/* * Copyright (c) 2014, Oculus VR, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * */ /// \file /// \brief Message filter plugin. Assigns systems to FilterSets. Each FilterSet limits what messages are allowed. This is a security related plugin. /// #include "NativeFeatureIncludes.hpp" #if _RAKNET_SUPPORT_MessageFilter==1 #ifndef __MESSAGE_FILTER_PLUGIN_H #define __MESSAGE_FILTER_PLUGIN_H #include "RakNetTypes.hpp" #include "PluginInterface2.hpp" #include "DS_OrderedList.hpp" #include "DS_Hash.hpp" #include "Export.hpp" /// MessageIdentifier (ID_*) values shoudln't go higher than this. Change it if you do. #define MESSAGE_FILTER_MAX_MESSAGE_ID 256 namespace RakNet { /// Forward declarations class RakPeerInterface; /// \internal Has to be public so some of the shittier compilers can use it. int RAK_DLL_EXPORT MessageFilterStrComp( char *const &key,char *const &data ); /// \internal Has to be public so some of the shittier compilers can use it. struct FilterSet { bool banOnFilterTimeExceed; bool kickOnDisallowedMessage; bool banOnDisallowedMessage; RakNet::TimeMS disallowedMessageBanTimeMS; RakNet::TimeMS timeExceedBanTimeMS; RakNet::TimeMS maxMemberTimeMS; void (*invalidMessageCallback)(RakPeerInterface *peer, AddressOrGUID systemAddress, int filterSetID, void *userData, unsigned char messageID); void *disallowedCallbackUserData; void (*timeoutCallback)(RakPeerInterface *peer, AddressOrGUID systemAddress, int filterSetID, void *userData); void *timeoutUserData; int filterSetID; bool allowedIDs[MESSAGE_FILTER_MAX_MESSAGE_ID]; DataStructures::OrderedList allowedRPC4; }; /// \internal Has to be public so some of the shittier compilers can use it. int RAK_DLL_EXPORT FilterSetComp( const int &key, FilterSet * const &data ); /// \internal Has to be public so some of the shittier compilers can use it. struct FilteredSystem { FilterSet *filter; RakNet::TimeMS timeEnteredThisSet; }; /// \defgroup MESSAGEFILTER_GROUP MessageFilter /// \brief Remote incoming packets from unauthorized systems /// \details /// \ingroup PLUGINS_GROUP /// \brief Assigns systems to FilterSets. Each FilterSet limits what kinds of messages are allowed. /// \details The MessageFilter plugin is used for security where you limit what systems can send what kind of messages.
/// You implicitly define FilterSets, and add allowed message IDs to these FilterSets.
/// You then add systems to these filters, such that those systems are limited to sending what the filters allows.
/// You can automatically assign systems to a filter.
/// You can automatically kick and possibly ban users that stay in a filter too long, or send the wrong message.
/// Each system is a member of either zero or one filters.
/// Add this plugin before any plugin you wish to filter (most likely just add this plugin before any other). /// \ingroup MESSAGEFILTER_GROUP class RAK_DLL_EXPORT MessageFilter : public PluginInterface2 { public: // GetInstance() and DestroyInstance(instance*) STATIC_FACTORY_DECLARATIONS(MessageFilter) MessageFilter(); virtual ~MessageFilter(); // -------------------------------------------------------------------------------------------- // User functions // -------------------------------------------------------------------------------------------- /// Automatically add all new systems to a particular filter /// Defaults to -1 /// \param[in] filterSetID Which filter to add new systems to. <0 for do not add. void SetAutoAddNewConnectionsToFilter(int filterSetID); /// Allow a range of message IDs /// Always allowed by default: ID_CONNECTION_REQUEST_ACCEPTED through ID_DOWNLOAD_PROGRESS /// Usually you specify a range to make it easier to add new enumerations without having to constantly refer back to this function. /// \param[in] allow True to allow this message ID, false to disallow. By default, all messageIDs except the noted types are disallowed. This includes messages from other plugins! /// \param[in] messageIDStart The first ID_* message to allow in the range. Inclusive. /// \param[in] messageIDEnd The last ID_* message to allow in the range. Inclusive. /// \param[in] filterSetID A user defined ID to represent a filter set. If no filter with this ID exists, one will be created with default settings. void SetAllowMessageID(bool allow, int messageIDStart, int messageIDEnd,int filterSetID); /// Allow a specific RPC4 call /// \pre MessageFilter must be attached before RPC4 /// \param[in] uniqueID Identifier passed to RegisterFunction() /// \param[in] filterSetID A user defined ID to represent a filter set. If no filter with this ID exists, one will be created with default settings. void SetAllowRPC4(bool allow, const char* uniqueID, int filterSetID); /// What action to take on a disallowed message. You can kick or not. You can add them to the ban list for some time /// By default no action is taken. The message is simply ignored. /// param[in] 0 for permanent ban, >0 for ban time in milliseconds. /// \param[in] kickOnDisallowed kick the system that sent a disallowed message. /// \param[in] banOnDisallowed ban the system that sent a disallowed message. See \a banTimeMS for the ban duration /// \param[in] banTimeMS Passed to the milliseconds parameter of RakPeer::AddToBanList. /// \param[in] filterSetID A user defined ID to represent a filter set. If no filter with this ID exists, one will be created with default settings. void SetActionOnDisallowedMessage(bool kickOnDisallowed, bool banOnDisallowed, RakNet::TimeMS banTimeMS, int filterSetID); /// Set a user callback to be called on an invalid message for a particular filterSet /// \param[in] filterSetID A user defined ID to represent a filter set. If no filter with this ID exists, one will be created with default settings. /// \param[in] userData A pointer passed with the callback /// \param[in] invalidMessageCallback A pointer to a C function to be called back with the specified parameters. void SetDisallowedMessageCallback(int filterSetID, void *userData, void (*invalidMessageCallback)(RakPeerInterface *peer, AddressOrGUID addressOrGUID, int filterSetID, void *userData, unsigned char messageID)); /// Set a user callback to be called when a user is disconnected due to SetFilterMaxTime /// \param[in] filterSetID A user defined ID to represent a filter set. If no filter with this ID exists, one will be created with default settings. /// \param[in] userData A pointer passed with the callback /// \param[in] invalidMessageCallback A pointer to a C function to be called back with the specified parameters. void SetTimeoutCallback(int filterSetID, void *userData, void (*invalidMessageCallback)(RakPeerInterface *peer, AddressOrGUID addressOrGUID, int filterSetID, void *userData)); /// Limit how long a connection can stay in a particular filterSetID. After this time, the connection is kicked and possibly banned. /// By default there is no limit to how long a connection can stay in a particular filter set. /// \param[in] allowedTimeMS How many milliseconds to allow a connection to stay in this filter set. /// \param[in] banOnExceed True or false to ban the system, or not, when \a allowedTimeMS is exceeded /// \param[in] banTimeMS Passed to the milliseconds parameter of RakPeer::AddToBanList. /// \param[in] filterSetID A user defined ID to represent a filter set. If no filter with this ID exists, one will be created with default settings. void SetFilterMaxTime(int allowedTimeMS, bool banOnExceed, RakNet::TimeMS banTimeMS, int filterSetID); /// Get the filterSetID a system is using. Returns -1 for none. /// \param[in] addressOrGUID The system we are referring to int GetSystemFilterSet(AddressOrGUID addressOrGUID); /// Assign a system to a filter set. /// Systems are automatically added to filter sets (or not) based on SetAutoAddNewConnectionsToFilter() /// This function is used to change the filter set a system is using, to add it to a new filter set, or to remove it from all existin filter sets. /// \param[in] addressOrGUID The system we are referring to /// \param[in] filterSetID A user defined ID to represent a filter set. If no filter with this ID exists, one will be created with default settings. If -1, the system will be removed from all filter sets. void SetSystemFilterSet(AddressOrGUID addressOrGUID, int filterSetID); /// Returns the number of systems subscribed to a particular filter set /// Using anything other than -1 for \a filterSetID is slow, so you should store the returned value. /// \param[in] filterSetID The filter set to limit to. Use -1 for none (just returns the total number of filter systems in that case). unsigned GetSystemCount(int filterSetID) const; /// Returns the total number of filter sets. /// \return The total number of filter sets. unsigned GetFilterSetCount(void) const; /// Returns the ID of a filter set, by index /// \param[in] An index between 0 and GetFilterSetCount()-1 inclusive int GetFilterSetIDByIndex(unsigned index); /// Delete a FilterSet. All systems formerly subscribed to this filter are now unrestricted. /// \param[in] filterSetID The ID of the filter set to delete. void DeleteFilterSet(int filterSetID); // -------------------------------------------------------------------------------------------- // Packet handling functions // -------------------------------------------------------------------------------------------- virtual void Update(void); virtual PluginReceiveResult OnReceive(Packet *packet); virtual void OnNewConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, bool isIncoming); virtual void OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason ); protected: void Clear(void); void DeallocateFilterSet(FilterSet *filterSet); FilterSet* GetFilterSetByID(int filterSetID); void OnInvalidMessage(FilterSet *filterSet, AddressOrGUID systemAddress, unsigned char messageID); DataStructures::OrderedList filterList; // Change to guid DataStructures::Hash systemList; int autoAddNewConnectionsToFilter; RakNet::Time whenLastTimeoutCheck; }; } // namespace RakNet #endif #endif // _RAKNET_SUPPORT_*