#ifndef PCAPP_FILTER #define PCAPP_FILTER #include #include #include #include "ProtocolType.h" #include #include "ArpLayer.h" #include "RawPacket.h" //Forward Declaration - used in GeneralFilter struct bpf_program; /** * @file * Most packet capture engines contain packet filtering capabilities. In order to set the filters there should be a known syntax user can use. * The most popular syntax is Berkeley Packet Filter (BPF) - see more in here: http://en.wikipedia.org/wiki/Berkeley_Packet_Filter. * Detailed explanation of the syntax can be found here: http://www.tcpdump.org/manpages/pcap-filter.7.html.
* The problem with BPF is that, for my opinion, the syntax is too complicated and too poorly documented. In addition the BPF filter compilers * may output syntax errors that are hard to understand. My experience with BPF was not good, so I decided to make the filters mechanism more * structured, easier to understand and less error-prone by creating classes that represent filters. Each possible filter phrase is represented * by a class. The filter, at the end, is that class.
* For example: the filter "src host 1.1.1.1" will be represented by IPFilter instance; "dst port 80" will be represented by PortFilter, and * so on.
* So what about complex filters that involve "and", "or"? There are also 2 classes: AndFilter and OrFilter that can store more filters (in a * composite idea) and connect them by "and" or "or". For example: "src host 1.1.1.1 and dst port 80" will be represented by an AndFilter that * h olds IPFilter and PortFilter inside it */ /** * \namespace pcpp * \brief The main namespace for the PcapPlusPlus lib */ namespace pcpp { //Forward Declaration - used in GeneralFilter class RawPacket; /** * An enum that contains direction (source or destination) */ typedef enum { /** Source */ SRC, /** Destination */ DST, /** Source or destination */ SRC_OR_DST } Direction; /** * Supported operators enum */ typedef enum { /** Equals */ EQUALS, /** Not equals */ NOT_EQUALS, /** Greater than */ GREATER_THAN, /** Greater or equal */ GREATER_OR_EQUAL, /** Less than */ LESS_THAN, /** Less or equal */ LESS_OR_EQUAL } FilterOperator; /** * @class BpfFilterWrapper * A wrapper class for BPF filtering. Enables setting a BPF filter and matching it against a packet */ class BpfFilterWrapper { private: std::string m_FilterStr; LinkLayerType m_LinkType; bpf_program* m_Program; void freeProgram(); public: /** * A c'tor for this class */ BpfFilterWrapper(); /** * A d'tor for this class. Makes sure to clear the bpf_program object if was previously set. */ ~BpfFilterWrapper(); /** * Set a filter. This method receives a filter in BPF syntax (https://biot.com/capstats/bpf.html) and an optional link type, * compiles them, and if compilation is successful it stores the filter. * @param[in] filter A filter in BPF syntax * @param[in] linkType An optional parameter to set the filter's link type. The default is LINKTYPE_ETHERNET * @return True if compilation is successful and filter is stored in side this object, false otherwise */ bool setFilter(const std::string& filter, LinkLayerType linkType = LINKTYPE_ETHERNET); /** * Match a packet with the filter stored in this object. If the filter is empty the method returns "true". * If the link type of the raw packet is different than the one set in setFilter(), the filter will be * re-compiled and stored in the object. * @param[in] rawPacket A pointer to a raw packet which the filter will be matched against * @return True if the filter matches (or if it's empty). False if the packet doesn't match or if the filter * could not be compiled */ bool matchPacketWithFilter(const RawPacket* rawPacket); /** * Match a packet data with the filter stored in this object. If the filter is empty the method returns "true". * If the link type provided is different than the one set in setFilter(), the filter will be re-compiled * and stored in the object. * @param[in] packetData A byte stream containing the packet data * @param[in] packetDataLength The length in [bytes] of the byte stream * @param[in] packetTimestamp The packet timestamp * @param[in] linkType The packet link type * @return True if the filter matches (or if it's empty). False if the packet doesn't match or if the filter * could not be compiled */ bool matchPacketWithFilter(const uint8_t* packetData, uint32_t packetDataLength, timespec packetTimestamp, uint16_t linkType); }; /** * @class GeneralFilter * The base class for all filter classes. This class is virtual and abstract, hence cannot be instantiated.
* For deeper understanding of the filter concept please refer to PcapFilter.h */ class GeneralFilter { protected: BpfFilterWrapper m_BpfWrapper; public: /** * A method that parses the class instance into BPF string format * @param[out] result An empty string that the parsing will be written into. If the string isn't empty, its content will be overridden */ virtual void parseToString(std::string& result) = 0; /** * Match a raw packet with a given BPF filter. * @param[in] rawPacket A pointer to the raw packet to match the BPF filter with * @return True if a raw packet matches the BPF filter or false otherwise */ bool matchPacketWithFilter(RawPacket* rawPacket); GeneralFilter() {} /** * Virtual destructor, frees the bpf program */ virtual ~GeneralFilter() {} }; /** * @class BPFStringFilter * This class can be loaded with a BPF filter string and then can be used to verify the string is valid.
*/ class BPFStringFilter : public GeneralFilter { private: const std::string m_FilterStr; public: explicit BPFStringFilter(const std::string& filterStr) : m_FilterStr(filterStr) {} virtual ~BPFStringFilter() {} /** * A method that parses the class instance into BPF string format * @param[out] result An empty string that the parsing will be written into. If the string isn't empty, its content will be overridden * If the filter is not valid the result will be an empty string */ virtual void parseToString(std::string& result); /** * Verify the filter is valid * @return True if the filter is valid or false otherwise */ bool verifyFilter(); }; /** * @class IFilterWithDirection * An abstract class that is the base class for all filters which contain a direction (source or destination). This class cannot be instantiated
* For deeper understanding of the filter concept please refer to PcapFilter.h */ class IFilterWithDirection : public GeneralFilter { private: Direction m_Dir; protected: void parseDirection(std::string& directionAsString); Direction getDir() const { return m_Dir; } explicit IFilterWithDirection(Direction dir) { m_Dir = dir; } public: /** * Set the direction for the filter (source or destination) * @param[in] dir The direction */ void setDirection(Direction dir) { m_Dir = dir; } }; /** * @class IFilterWithOperator * An abstract class that is the base class for all filters which contain an operator (e.g X equals Y; A is greater than B; Z1 not equals Z2, etc.). * This class cannot be instantiated
* For deeper understanding of the filter concept please refer to PcapFilter.h */ class IFilterWithOperator : public GeneralFilter { private: FilterOperator m_Operator; protected: std::string parseOperator(); FilterOperator getOperator() const { return m_Operator; } explicit IFilterWithOperator(FilterOperator op) { m_Operator = op; } public: /** * Set the operator for the filter * @param[in] op The operator to set */ void setOperator(FilterOperator op) { m_Operator = op; } }; /** * @class IPFilter * A class for representing IPv4 address filter, equivalent to "net src x.x.x.x" or "net dst x.x.x.x"
* For deeper understanding of the filter concept please refer to PcapFilter.h * @todo Add IPv6 filtering support */ class IPFilter : public IFilterWithDirection { private: std::string m_Address; std::string m_IPv4Mask; int m_Len; void convertToIPAddressWithMask(std::string& ipAddrmodified, std::string& mask) const; void convertToIPAddressWithLen(std::string& ipAddrmodified) const; public: /** * The basic constructor that creates the filter from an IPv4 address and direction (source or destination) * @param[in] ipAddress The IPv4 address to build the filter with. If this address is not a valid IPv4 address an error will be * written to log and parsing this filter will fail * @param[in] dir The address direction to filter (source or destination) */ IPFilter(const std::string& ipAddress, Direction dir) : IFilterWithDirection(dir), m_Address(ipAddress), m_IPv4Mask(""), m_Len(0) {} /** * A constructor that enable to filter only part of the address by using a mask (aka subnet). For example: "filter only IP addresses that matches * the subnet 10.0.0.x" * @param[in] ipAddress The IPv4 address to use. Only the part of the address that is not masked will be matched. For example: if the address * is "1.2.3.4" and the mask is "255.255.255.0" than the part of the address that will be matched is "1.2.3.X". If this address is not a * valid IPv4 address an error will be written to log and parsing this filter will fail * @param[in] dir The address direction to filter (source or destination) * @param[in] ipv4Mask The mask to use. Mask should also be in a valid IPv4 format (i.e x.x.x.x), otherwise parsing this filter will fail */ IPFilter(const std::string& ipAddress, Direction dir, const std::string& ipv4Mask) : IFilterWithDirection(dir), m_Address(ipAddress), m_IPv4Mask(ipv4Mask), m_Len(0) {} /** * A constructor that enables to filter by a subnet. For example: "filter only IP addresses that matches the subnet 10.0.0.3/24" which means * the part of the address that will be matched is "10.0.0.X" * @param[in] ipAddress The IPv4 address to use. Only the part of the address that is not masked will be matched. For example: if the address * is "1.2.3.4" and the subnet is "/24" than the part of the address that will be matched is "1.2.3.X". If this address is not a * valid IPv4 address an error will be written to log and parsing this filter will fail * @param[in] dir The address direction to filter (source or destination) * @param[in] len The subnet to use (e.g "/24") */ IPFilter(const std::string& ipAddress, Direction dir, int len) : IFilterWithDirection(dir), m_Address(ipAddress), m_IPv4Mask(""), m_Len(len) {} void parseToString(std::string& result); /** * Set the IPv4 address * @param[in] ipAddress The IPv4 address to build the filter with. If this address is not a valid IPv4 address an error will be * written to log and parsing this filter will fail */ void setAddr(const std::string& ipAddress) { m_Address = ipAddress; } /** * Set the IPv4 mask * @param[in] ipv4Mask The mask to use. Mask should also be in a valid IPv4 format (i.e x.x.x.x), otherwise parsing this filter will fail */ void setMask(const std::string& ipv4Mask) { m_IPv4Mask = ipv4Mask; m_Len = 0; } /** * Set the subnet * @param[in] len The subnet to use (e.g "/24") */ void setLen(int len) { m_IPv4Mask = ""; m_Len = len; } }; /** * @class IPv4IDFilter * A class for filtering IPv4 traffic by IP ID field of the IPv4 protocol, For example: * "filter only IPv4 traffic which IP ID is greater than 1234"
* For deeper understanding of the filter concept please refer to PcapFilter.h */ class IPv4IDFilter : public IFilterWithOperator { private: uint16_t m_IpID; public: /** * A constructor that gets the IP ID to filter and the operator and creates the filter out of them * @param[in] ipID The IP ID to filter * @param[in] op The operator to use (e.g "equal", "greater than", etc.) */ IPv4IDFilter(uint16_t ipID, FilterOperator op) : IFilterWithOperator(op), m_IpID(ipID) {} void parseToString(std::string& result); /** * Set the IP ID to filter * @param[in] ipID The IP ID to filter */ void setIpID(uint16_t ipID) { m_IpID = ipID; } }; /** * @class IPv4TotalLengthFilter * A class for filtering IPv4 traffic by "total length" field of the IPv4 protocol, For example: * "filter only IPv4 traffic which "total length" value is less than 60B"
* For deeper understanding of the filter concept please refer to PcapFilter.h */ class IPv4TotalLengthFilter : public IFilterWithOperator { private: uint16_t m_TotalLength; public: /** * A constructor that gets the total length to filter and the operator and creates the filter out of them * @param[in] totalLength The total length value to filter * @param[in] op The operator to use (e.g "equal", "greater than", etc.) */ IPv4TotalLengthFilter(uint16_t totalLength, FilterOperator op) : IFilterWithOperator(op), m_TotalLength(totalLength) {} void parseToString(std::string& result); /** * Set the total length value * @param[in] totalLength The total length value to filter */ void setTotalLength(uint16_t totalLength) { m_TotalLength = totalLength; } }; /** * @class PortFilter * A class for filtering TCP or UDP traffic by port, for example: "dst port 80" or "src port 12345"
* For deeper understanding of the filter concept please refer to PcapFilter.h */ class PortFilter : public IFilterWithDirection { private: std::string m_Port; void portToString(uint16_t portAsInt); public: /** * A constructor that gets the port and the direction and creates the filter * @param[in] port The port to create the filter with * @param[in] dir The port direction to filter (source or destination) */ PortFilter(uint16_t port, Direction dir); void parseToString(std::string& result); /** * Set the port * @param[in] port The port to create the filter with */ void setPort(uint16_t port) { portToString(port); } }; /** * @class PortRangeFilter * A class for filtering TCP or UDP port ranges, meaning match only packets which port is within this range, for example: "src portrange 1000-2000" * will match only TCP or UDP traffic which source port is in the range of 1000 - 2000
* For deeper understanding of the filter concept please refer to PcapFilter.h */ class PortRangeFilter : public IFilterWithDirection { private: uint16_t m_FromPort; uint16_t m_ToPort; public: /** * A constructor that gets the port range the the direction and creates the filter with them * @param[in] fromPort The lower end of the port range * @param[in] toPort The higher end of the port range * @param[in] dir The port range direction to filter (source or destination) */ PortRangeFilter(uint16_t fromPort, uint16_t toPort, Direction dir) : IFilterWithDirection(dir), m_FromPort(fromPort), m_ToPort(toPort) {} void parseToString(std::string& result); /** * Set the lower end of the port range * @param[in] fromPort The lower end of the port range */ void setFromPort(uint16_t fromPort) { m_FromPort = fromPort; } /** * Set the higher end of the port range * @param[in] toPort The higher end of the port range */ void setToPort(uint16_t toPort) { m_ToPort = toPort; } }; /** * @class MacAddressFilter * A class for filtering Ethernet traffic by MAC addresses, for example: "ether src 12:34:56:78:90:12" or "ether dst "10:29:38:47:56:10:29"
* For deeper understanding of the filter concept please refer to PcapFilter.h */ class MacAddressFilter : public IFilterWithDirection { private: MacAddress m_MacAddress; public: /** * A constructor that gets the MAC address and the direction and creates the filter with them * @param[in] address The MAC address to use for filtering * @param[in] dir The MAC address direction to filter (source or destination) */ MacAddressFilter(MacAddress address, Direction dir) : IFilterWithDirection(dir), m_MacAddress(address) {} void parseToString(std::string& result); /** * Set the MAC address * @param[in] address The MAC address to use for filtering */ void setMacAddress(MacAddress address) { m_MacAddress = address; } }; /** * @class EtherTypeFilter * A class for filtering by EtherType field of the Ethernet protocol. This enables to filter packets from certain protocols, such as ARP, IPv4, * IPv6, VLAN tags, etc.
* For deeper understanding of the filter concept please refer to PcapFilter.h */ class EtherTypeFilter : public GeneralFilter { private: uint16_t m_EtherType; public: /** * A constructor that gets the EtherType and creates the filter with it * @param[in] etherType The EtherType value to create the filter with */ explicit EtherTypeFilter(uint16_t etherType) : m_EtherType(etherType) {} void parseToString(std::string& result); /** * Set the EtherType value * @param[in] etherType The EtherType value to create the filter with */ void setEtherType(uint16_t etherType) { m_EtherType = etherType; } }; /** * @class AndFilter * A class for connecting several filters into one filter with logical "and" between them. For example: if the 2 filters are: "IPv4 address = * x.x.x.x" + "TCP port dst = 80", then the new filter will be: "IPv4 address = x.x.x.x _AND_ TCP port dst = 80"
* This class follows the composite design pattern
* For deeper understanding of the filter concept please refer to PcapFilter.h * @todo add some methods: "addFilter", "removeFilter", "clearAllFilter" */ class AndFilter : public GeneralFilter { private: std::vector m_FilterList; public: /** * An empty constructor for this class. Use addFilter() to add filters to the and condition */ AndFilter() {} /** * A constructor that gets a list of pointers to filters and creates one filter from all filters with logical "and" between them * @param[in] filters The list of pointers to filters */ explicit AndFilter(std::vector& filters); /** * Add filter to the and condition * @param[in] filter The filter to add */ void addFilter(GeneralFilter* filter) { m_FilterList.push_back(filter); } /** * Remove the current filters and set new ones * @param[in] filters The new filters to set. The previous ones will be removed */ void setFilters(std::vector& filters); void parseToString(std::string& result); }; /** * @class OrFilter * A class for connecting several filters into one filter with logical "or" between them. For example: if the 2 filters are: "IPv4 address = * x.x.x.x" + "TCP port dst = 80", then the new filter will be: "IPv4 address = x.x.x.x _OR_ TCP port dst = 80"
* This class follows the composite design pattern
* For deeper understanding of the filter concept please refer to PcapFilter.h * @todo add some methods: "addFilter", "removeFilter", "clearAllFilter" */ class OrFilter : public GeneralFilter { private: std::vector m_FilterList; public: /** * An empty constructor for this class. Use addFilter() to add filters to the or condition */ OrFilter() {} /** * A constructor that gets a list of pointers to filters and creates one filter from all filters with logical "or" between them * @param[in] filters The list of pointers to filters */ explicit OrFilter(std::vector& filters); /** * Add filter to the or condition * @param[in] filter The filter to add */ void addFilter(GeneralFilter* filter) { m_FilterList.push_back(filter); } void parseToString(std::string& result); }; /** * @class NotFilter * A class for creating a filter which is inverse to another filter
* For deeper understanding of the filter concept please refer to PcapFilter.h */ class NotFilter : public GeneralFilter { private: GeneralFilter* m_FilterToInverse; public: /** * A constructor that gets a pointer to a filter and create the inverse version of it * @param[in] filterToInverse A pointer to filter which the created filter be the inverse of */ explicit NotFilter(GeneralFilter* filterToInverse) { m_FilterToInverse = filterToInverse; } void parseToString(std::string& result); /** * Set a filter to create an inverse filter from * @param[in] filterToInverse A pointer to filter which the created filter be the inverse of */ void setFilter(GeneralFilter* filterToInverse) { m_FilterToInverse = filterToInverse; } }; /** * @class ProtoFilter * A class for filtering traffic by protocol. Notice not all protocols are supported, only the following are supported: * ::TCP, ::UDP, ::ICMP, ::VLAN, ::IPv4, ::IPv6, ::ARP, ::Ethernet, ::GRE (distinguish between ::GREv0 and ::GREv1 is not supported), * ::IGMP (distinguish between ::IGMPv1, ::IGMPv2 and ::IGMPv3 is not supported).
* For deeper understanding of the filter concept please refer to PcapFilter.h */ class ProtoFilter : public GeneralFilter { private: ProtocolType m_Proto; public: /** * A constructor that gets the protocol and creates the filter * @param[in] proto The protocol to filter, only packets matching this protocol will be received. Please note not all protocols are * supported. List of supported protocols is found in the class description */ explicit ProtoFilter(ProtocolType proto) : m_Proto(proto) {} void parseToString(std::string& result); /** * Set the protocol to filter with * @param[in] proto The protocol to filter, only packets matching this protocol will be received. Please note not all protocols are * supported. List of supported protocols is found in the class description */ void setProto(ProtocolType proto) { m_Proto = proto; } }; /** * @class ArpFilter * A class for filtering ARP packets according the ARP opcode. When using this filter only ARP packets with the relevant opcode will be * received
* For deeper understanding of the filter concept please refer to PcapFilter.h */ class ArpFilter : public GeneralFilter { private: ArpOpcode m_OpCode; public: /** * A constructor that get the ARP opcode and creates the filter * @param[in] opCode The ARP opcode: ::ARP_REQUEST or ::ARP_REPLY */ explicit ArpFilter(ArpOpcode opCode) : m_OpCode(opCode) {} void parseToString(std::string& result); /** * Set the ARP opcode * @param[in] opCode The ARP opcode: ::ARP_REQUEST or ::ARP_REPLY */ void setOpCode(ArpOpcode opCode) { m_OpCode = opCode; } }; /** * @class VlanFilter * A class for filtering VLAN tagged packets by VLAN ID. When using this filter only packets tagged with VLAN which has the specific VLAN ID * will be received
* For deeper understanding of the filter concept please refer to PcapFilter.h */ class VlanFilter : public GeneralFilter { private: uint16_t m_VlanID; public: /** * A constructor the gets the VLAN ID and creates the filter * @param[in] vlanId The VLAN ID to use for the filter */ explicit VlanFilter(uint16_t vlanId) : m_VlanID(vlanId) {} void parseToString(std::string& result); /** * Set the VLAN ID of the filter * @param[in] vlanId The VLAN ID to use for the filter */ void setVlanID(uint16_t vlanId) { m_VlanID = vlanId; } }; /** * @class TcpFlagsFilter * A class for filtering only TCP packets which certain TCP flags are set in them
* For deeper understanding of the filter concept please refer to PcapFilter.h */ class TcpFlagsFilter : public GeneralFilter { public: /** * An enum of all TCP flags that can be use in the filter */ enum TcpFlags { /** TCP FIN flag */ tcpFin = 1, /** TCP SYN flag */ tcpSyn = 2, /** TCP RST flag */ tcpRst = 4, /** TCP PSH flag */ tcpPush = 8, /** TCP ACK flag */ tcpAck = 16, /** TCP URG flag */ tcpUrg = 32 }; /** * An enum for representing 2 type of matches: match only packets that contain all flags defined in the filter or match packets that * contain at least one of the flags defined in the filter */ enum MatchOptions { /** Match only packets that contain all flags defined in the filter */ MatchAll, /** Match packets that contain at least one of the flags defined in the filter */ MatchOneAtLeast }; private: uint8_t m_TcpFlagsBitMask; MatchOptions m_MatchOption; public: /** * A constructor that gets a 1-byte bitmask containing all TCP flags participating in the filter and the match option, and * creates the filter * @param[in] tcpFlagBitMask A 1-byte bitmask containing all TCP flags participating in the filter. This parameter can contain the * following value for example: TcpFlagsFilter::tcpSyn | TcpFlagsFilter::tcpAck | TcpFlagsFilter::tcpUrg * @param[in] matchOption The match option: TcpFlagsFilter::MatchAll or TcpFlagsFilter::MatchOneAtLeast */ TcpFlagsFilter(uint8_t tcpFlagBitMask, MatchOptions matchOption) : m_TcpFlagsBitMask(tcpFlagBitMask), m_MatchOption(matchOption) {} /** * Set the TCP flags and the match option * @param[in] tcpFlagBitMask A 1-byte bitmask containing all TCP flags participating in the filter. This parameter can contain the * following value for example: TcpFlagsFilter::tcpSyn | TcpFlagsFilter::tcpAck | TcpFlagsFilter::tcpUrg * @param[in] matchOption The match option: TcpFlagsFilter::MatchAll or TcpFlagsFilter::MatchOneAtLeast */ void setTcpFlagsBitMask(uint8_t tcpFlagBitMask, MatchOptions matchOption) { m_TcpFlagsBitMask = tcpFlagBitMask; m_MatchOption = matchOption; } void parseToString(std::string& result); }; /** * @class TcpWindowSizeFilter * A class for filtering TCP packets that matches TCP window-size criteria
* For deeper understanding of the filter concept please refer to PcapFilter.h */ class TcpWindowSizeFilter : public IFilterWithOperator { private: uint16_t m_WindowSize; public: /** * A constructor that get the window-size and operator and creates the filter. For example: "filter all TCP packets with window-size * less than 1000" * @param[in] windowSize The window-size value that will be used in the filter * @param[in] op The operator to use (e.g "equal", "greater than", etc.) */ TcpWindowSizeFilter(uint16_t windowSize, FilterOperator op) : IFilterWithOperator(op), m_WindowSize(windowSize) {} void parseToString(std::string& result); /** * Set window-size value * @param[in] windowSize The window-size value that will be used in the filter */ void setWindowSize(uint16_t windowSize) { m_WindowSize = windowSize; } }; /** * @class UdpLengthFilter * A class for filtering UDP packets that matches UDP length criteria
* For deeper understanding of the filter concept please refer to PcapFilter.h */ class UdpLengthFilter : public IFilterWithOperator { private: uint16_t m_Length; public: /** * A constructor that get the UDP length and operator and creates the filter. For example: "filter all UDP packets with length * greater or equal to 500" * @param[in] length The length value that will be used in the filter * @param[in] op The operator to use (e.g "equal", "greater than", etc.) */ UdpLengthFilter(uint16_t length, FilterOperator op) : IFilterWithOperator(op), m_Length(length) {} void parseToString(std::string& result); /** * Set length value * @param[in] length The length value that will be used in the filter */ void setLength(uint16_t length) { m_Length = length; } }; } // namespace pcpp #endif