diff --git a/Common++/CMakeLists.txt b/Common++/CMakeLists.txt index 46ce5007bb..07ba2d5b38 100644 --- a/Common++/CMakeLists.txt +++ b/Common++/CMakeLists.txt @@ -12,20 +12,20 @@ add_library( src/TablePrinter.cpp) set(public_headers - header/DeprecationUtils.h - header/GeneralUtils.h - header/IpAddress.h - header/IpAddressUtils.h - header/IpUtils.h - header/Logger.h - header/LRUList.h - header/MacAddress.h - header/OUILookup.h - header/PcapPlusPlusVersion.h - header/PointerVector.h - header/SystemUtils.h - header/TablePrinter.h - header/TimespecTimeval.h) + header/pcapplusplus/DeprecationUtils.h + header/pcapplusplus/GeneralUtils.h + header/pcapplusplus/IpAddress.h + header/pcapplusplus/IpAddressUtils.h + header/pcapplusplus/IpUtils.h + header/pcapplusplus/Logger.h + header/pcapplusplus/LRUList.h + header/pcapplusplus/MacAddress.h + header/pcapplusplus/OUILookup.h + header/pcapplusplus/PcapPlusPlusVersion.h + header/pcapplusplus/PointerVector.h + header/pcapplusplus/SystemUtils.h + header/pcapplusplus/TablePrinter.h + header/pcapplusplus/TimespecTimeval.h) # Set the public header that will be installed set_property(TARGET Common++ PROPERTY PUBLIC_HEADER ${public_headers}) diff --git a/Common++/header/DeprecationUtils.h b/Common++/header/pcapPlusPlus/DeprecationUtils.h similarity index 100% rename from Common++/header/DeprecationUtils.h rename to Common++/header/pcapPlusPlus/DeprecationUtils.h diff --git a/Common++/header/GeneralUtils.h b/Common++/header/pcapPlusPlus/GeneralUtils.h similarity index 100% rename from Common++/header/GeneralUtils.h rename to Common++/header/pcapPlusPlus/GeneralUtils.h diff --git a/Common++/header/IpAddress.h b/Common++/header/pcapPlusPlus/IpAddress.h similarity index 100% rename from Common++/header/IpAddress.h rename to Common++/header/pcapPlusPlus/IpAddress.h diff --git a/Common++/header/IpAddressUtils.h b/Common++/header/pcapPlusPlus/IpAddressUtils.h similarity index 100% rename from Common++/header/IpAddressUtils.h rename to Common++/header/pcapPlusPlus/IpAddressUtils.h diff --git a/Common++/header/IpUtils.h b/Common++/header/pcapPlusPlus/IpUtils.h similarity index 100% rename from Common++/header/IpUtils.h rename to Common++/header/pcapPlusPlus/IpUtils.h diff --git a/Common++/header/LRUList.h b/Common++/header/pcapPlusPlus/LRUList.h similarity index 100% rename from Common++/header/LRUList.h rename to Common++/header/pcapPlusPlus/LRUList.h diff --git a/Common++/header/Logger.h b/Common++/header/pcapPlusPlus/Logger.h similarity index 100% rename from Common++/header/Logger.h rename to Common++/header/pcapPlusPlus/Logger.h diff --git a/Common++/header/MacAddress.h b/Common++/header/pcapPlusPlus/MacAddress.h similarity index 100% rename from Common++/header/MacAddress.h rename to Common++/header/pcapPlusPlus/MacAddress.h diff --git a/Common++/header/OUILookup.h b/Common++/header/pcapPlusPlus/OUILookup.h similarity index 100% rename from Common++/header/OUILookup.h rename to Common++/header/pcapPlusPlus/OUILookup.h diff --git a/Common++/header/PcapPlusPlusVersion.h b/Common++/header/pcapPlusPlus/PcapPlusPlusVersion.h similarity index 100% rename from Common++/header/PcapPlusPlusVersion.h rename to Common++/header/pcapPlusPlus/PcapPlusPlusVersion.h diff --git a/Common++/header/PointerVector.h b/Common++/header/pcapPlusPlus/PointerVector.h similarity index 100% rename from Common++/header/PointerVector.h rename to Common++/header/pcapPlusPlus/PointerVector.h diff --git a/Common++/header/SystemUtils.h b/Common++/header/pcapPlusPlus/SystemUtils.h similarity index 100% rename from Common++/header/SystemUtils.h rename to Common++/header/pcapPlusPlus/SystemUtils.h diff --git a/Common++/header/TablePrinter.h b/Common++/header/pcapPlusPlus/TablePrinter.h similarity index 100% rename from Common++/header/TablePrinter.h rename to Common++/header/pcapPlusPlus/TablePrinter.h diff --git a/Common++/header/TimespecTimeval.h b/Common++/header/pcapPlusPlus/TimespecTimeval.h similarity index 100% rename from Common++/header/TimespecTimeval.h rename to Common++/header/pcapPlusPlus/TimespecTimeval.h diff --git a/Common++/header/pcapplusplus/DeprecationUtils.h b/Common++/header/pcapplusplus/DeprecationUtils.h new file mode 100644 index 0000000000..2d600d88d6 --- /dev/null +++ b/Common++/header/pcapplusplus/DeprecationUtils.h @@ -0,0 +1,39 @@ +#pragma once + +/// @file + +#ifndef PCPP_DEPRECATED +# if defined(__GNUC__) || defined(__clang__) +# define PCPP_DEPRECATED(msg) __attribute__((deprecated(msg))) +# elif defined(_MSC_VER) +# define PCPP_DEPRECATED(msg) __declspec(deprecated(msg)) +# else +# pragma message("WARNING: DEPRECATED feature is not implemented for this compiler") +# define PCPP_DEPRECATED(msg) +# endif +#endif + +#if !defined(DISABLE_WARNING_PUSH) || !defined(DISABLE_WARNING_POP) +# if defined(_MSC_VER) +# define DISABLE_WARNING_PUSH __pragma(warning(push)) +# define DISABLE_WARNING_POP __pragma(warning(pop)) +# define DISABLE_WARNING(warningNumber) __pragma(warning(disable : warningNumber)) + +# define DISABLE_WARNING_DEPRECATED DISABLE_WARNING(4996) +# elif defined(__GNUC__) || defined(__clang__) +# define DO_PRAGMA(X) _Pragma(#X) +# define DISABLE_WARNING_PUSH DO_PRAGMA(GCC diagnostic push) +# define DISABLE_WARNING_POP DO_PRAGMA(GCC diagnostic pop) +# define DISABLE_WARNING(warningName) DO_PRAGMA(GCC diagnostic ignored #warningName) + +// clang-format off +# define DISABLE_WARNING_DEPRECATED DISABLE_WARNING(-Wdeprecated-declarations) +// clang-format on +# else +# pragma message("WARNING: Disabling of warnings is not implemented for this compiler") +# define DISABLE_WARNING_PUSH +# define DISABLE_WARNING_POP + +# define DISABLE_WARNING_DEPRECATED +# endif +#endif diff --git a/Common++/header/pcapplusplus/GeneralUtils.h b/Common++/header/pcapplusplus/GeneralUtils.h new file mode 100644 index 0000000000..acb4d93589 --- /dev/null +++ b/Common++/header/pcapplusplus/GeneralUtils.h @@ -0,0 +1,80 @@ +#pragma once + +#include +#include +#include + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + /** + * Convert a byte array into a string of hex characters. For example: for the array { 0xaa, 0x2b, 0x10 } the string + * "aa2b10" will be returned + * @param[in] byteArr A byte array + * @param[in] byteArrSize The size of the byte array [in bytes] + * @param[in] stringSizeLimit An optional parameter that enables to limit the returned string size. If set to a + * positive integer value the returned string size will be equal or less than this value. If the string + * representation of the whole array is longer than this size then only part of the array will be read. The default + * value is -1 which means no string size limitation + * @return A string of hex characters representing the byte array + */ + std::string byteArrayToHexString(const uint8_t* byteArr, size_t byteArrSize, int stringSizeLimit = -1); + + /** + * Convert a string of hex characters into a byte array. For example: for the string "aa2b10" an array of values + * { 0xaa, 0x2b, 0x10 } will be returned + * @param[in] hexString A string of hex characters + * @param[out] resultByteArr A pre-allocated byte array where the result will be written to + * @param[in] resultByteArrSize The size of the pre-allocated byte array + * @return The size of the result array. If the string represents an array that is longer than the pre-allocated + * size (resultByteArrSize) then the result array will contain only the part of the string that managed to fit into + * the array, and the returned size will be resultByteArrSize. However if the string represents an array that is + * shorter than the pre-allocated size then some of the cells will remain empty and contain zeros, and the returned + * size will be the part of the array that contain data. If the input is an illegal hex string 0 will be returned. + * Illegal hex string means odd number of characters or a string that contains non-hex characters + */ + size_t hexStringToByteArray(const std::string& hexString, uint8_t* resultByteArr, size_t resultByteArrSize); + + /** + * This is a cross platform version of memmem (https://man7.org/linux/man-pages/man3/memmem.3.html) which is not + * supported on all platforms. + * @param[in] haystack A pointer to the buffer to be searched + * @param[in] haystackLen Length of the haystack buffer + * @param[in] needle A pointer to a buffer that will be searched for + * @param[in] needleLen Length of the needle buffer + * @return A pointer to the beginning of the substring, or nullptr if the substring is not found + */ + char* cross_platform_memmem(const char* haystack, size_t haystackLen, const char* needle, size_t needleLen); + + /** + * Calculates alignment. + * @param[in] number Given number + * @return The aligned number + */ + template static int align(int number) + { + // Only works for alignment with power of 2 + constexpr bool isPowerOfTwo = alignment && ((alignment & (alignment - 1)) == 0); + static_assert(isPowerOfTwo, "Alignment must be a power of 2"); + int mask = alignment - 1; + return (number + mask) & ~mask; + } + + /** + * A template class to calculate enum class hash + * @tparam EnumClass + */ + template ::value, bool>::type = false> + struct EnumClassHash + { + size_t operator()(EnumClass value) const + { + return static_cast::type>(value); + } + }; +} // namespace pcpp diff --git a/Common++/header/pcapplusplus/IpAddress.h b/Common++/header/pcapplusplus/IpAddress.h new file mode 100644 index 0000000000..243dae0ef9 --- /dev/null +++ b/Common++/header/pcapplusplus/IpAddress.h @@ -0,0 +1,1121 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + // forward declarations + class IPv4Network; + class IPv6Network; + + // The implementation of the classes is based on document N4771 "Working Draft, C++ Extensions for Networking" + // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/n4771.pdf + + /** + * @class IPv4Address + * Represents an IPv4 address (of type XXX.XXX.XXX.XXX) + */ + class IPv4Address + { + public: + /** + * A default constructor that creates an instance of the class with the zero-initialized address + */ + IPv4Address() = default; + + /** + * A constructor that creates an instance of the class out of 4-byte integer value. + * @param[in] addrAsInt The address as 4-byte integer in network byte order + */ + IPv4Address(const uint32_t addrAsInt) + { + memcpy(m_Bytes.data(), &addrAsInt, sizeof(addrAsInt)); + } + + /** + * A constructor that creates an instance of the class out of 4-byte array. + * @param[in] bytes The address as 4-byte array in network byte order + */ + IPv4Address(const uint8_t bytes[4]) + { + memcpy(m_Bytes.data(), bytes, 4 * sizeof(uint8_t)); + } + + /** + * A constructor that creates an instance of the class out of a 4-byte standard array. + * @param[in] bytes The address as 4-byte standard array in network byte order + */ + IPv4Address(const std::array& bytes) : m_Bytes(bytes) + {} + + /** + * A constructor that creates an instance of the class out of std::string value. + * + * @param[in] addrAsString The std::string representation of the address + * @throws std::invalid_argument The provided string does not represent a valid IPv4 address. + */ + IPv4Address(const std::string& addrAsString); + + /** + * @return A 4-byte integer in network byte order representing the IPv4 address + */ + inline uint32_t toInt() const; + + /** + * @return A non-owning pointer to 4-byte C-style array representing the IPv4 address + */ + const uint8_t* toBytes() const + { + return m_Bytes.data(); + } + + /** + * @return A reference to a 4-byte standard array representing the IPv4 address + */ + const std::array& toByteArray() const + { + return m_Bytes; + } + + /** + * @return A string representation of the address + */ + std::string toString() const; + + /** + * @return True if an address is multicast, false otherwise. + */ + bool isMulticast() const; + + /** + * Overload of the equal-to operator + * @param[in] rhs The object to compare with + * @return True if the addresses are equal, false otherwise + */ + bool operator==(const IPv4Address& rhs) const + { + return toInt() == rhs.toInt(); + } + + /** + * Overload of the less-than operator + * @param[in] rhs The object to compare with + * @return True if the address value is lower than the other address value, false otherwise + */ + bool operator<(const IPv4Address& rhs) const + { + uint32_t intVal = toInt(); + std::reverse(reinterpret_cast(&intVal), reinterpret_cast(&intVal) + sizeof(intVal)); + + uint32_t rhsIntVal = rhs.toInt(); + std::reverse(reinterpret_cast(&rhsIntVal), + reinterpret_cast(&rhsIntVal) + sizeof(rhsIntVal)); + + return intVal < rhsIntVal; + } + + /** + * Overload of the not-equal-to operator + * @param[in] rhs The object to compare with + * @return True if the addresses are not equal, false otherwise + */ + bool operator!=(const IPv4Address& rhs) const + { + return !(*this == rhs); + } + + /** + * Checks whether the address matches a network. + * @param network An IPv4Network network + * @return True if the address matches the network or false otherwise + */ + bool matchNetwork(const IPv4Network& network) const; + + /** + * Checks whether the address matches a network. + * For example: this method will return true for address 10.1.1.9 and network which is one of: + * 10.1.1.1/24, 10.1.1.1/255.255.255.0 + * Another example: this method will return false for address 11.1.1.9 and network which is one of: + * 10.1.1.1/16, 10.1.1.1/255.255.0.0 + * @param[in] network A string in one of these formats: + * - X.X.X.X/Y where X.X.X.X is a valid IP address and Y is a number between 0 and 32 + * - X.X.X.X/Y.Y.Y.Y where X.X.X.X is a valid IP address and Y.Y.Y.Y is a valid netmask + * @return True if the address matches the network or false if it doesn't or if the network is invalid + */ + bool matchNetwork(const std::string& network) const; + + /** + * A static method that checks whether a string represents a valid IPv4 address + * @param[in] addrAsString The std::string representation of the address + * @return True if the address is valid, false otherwise + */ + static bool isValidIPv4Address(const std::string& addrAsString); + + /** + * A static value representing a zero value of IPv4 address, meaning address of value "0.0.0.0". + */ + static const IPv4Address Zero; + + /** + * A static values representing the lower and upper bound of IPv4 multicast ranges. The bounds are inclusive. + * MulticastRangeLowerBound is initialized to "224.0.0.0". + * MulticastRangeUpperBound is initialized to "239.255.255.255". + * In order to check whether the address is a multicast address the isMulticast method can be used. + */ + static const IPv4Address MulticastRangeLowerBound; + static const IPv4Address MulticastRangeUpperBound; + + private: + std::array m_Bytes = { 0 }; + }; // class IPv4Address + + // Implementation of inline methods + + uint32_t IPv4Address::toInt() const + { + uint32_t addr; + memcpy(&addr, m_Bytes.data(), m_Bytes.size() * sizeof(uint8_t)); + return addr; + } + + /** + * @class IPv6Address + * Represents an IPv6 address (of type xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx). + */ + class IPv6Address + { + public: + /** + * A default constructor that creates an instance of the class with the zero-initialized address. + */ + IPv6Address() = default; + + /** + * A constructor that creates an instance of the class out of 16-byte array. + * @param[in] bytes The address as 16-byte array in network byte order + */ + IPv6Address(const uint8_t bytes[16]) + { + memcpy(m_Bytes.data(), bytes, 16 * sizeof(uint8_t)); + } + + /** + * A constructor that creates an instance of the class out of a 16-byte standard array. + * @param[in] bytes The address as 16-byte standard array in network byte order + */ + IPv6Address(const std::array& bytes) : m_Bytes(bytes) + {} + + /** + * A constructor that creates an instance of the class out of std::string value. + * + * @param[in] addrAsString The std::string representation of the address + * @throws std::invalid_argument The provided string does not represent a valid IPv6 address. + */ + IPv6Address(const std::string& addrAsString); + + /** + * Returns a view of the IPv6 address as a 16-byte raw C-style array + * @return A non-owning pointer to 16-byte array representing the IPv6 address + */ + const uint8_t* toBytes() const + { + return m_Bytes.data(); + } + + /** + * Returns a view of the IPv6 address as a std::array of bytes + * @return A reference to a 16-byte standard array representing the IPv6 address + */ + const std::array& toByteArray() const + { + return m_Bytes; + } + + /** + * Returns a std::string representation of the address + * @return A string representation of the address + */ + std::string toString() const; + + /** + * Determine whether the address is a multicast address + * @return True if an address is multicast + */ + bool isMulticast() const; + + /** + * Overload of the equal-to operator + * @param[in] rhs The object to compare with + * @return True if the addresses are equal, false otherwise + */ + bool operator==(const IPv6Address& rhs) const + { + return memcmp(toBytes(), rhs.toBytes(), sizeof(m_Bytes)) == 0; + } + + /** + * Overload of the less-than operator + * @param[in] rhs The object to compare with + * @return True if the address value is lower than the other address value, false otherwise + */ + bool operator<(const IPv6Address& rhs) const + { + return memcmp(toBytes(), rhs.toBytes(), sizeof(m_Bytes)) < 0; + } + + /** + * Overload of the not-equal-to operator + * @param[in] rhs The object to compare with + * @return True if the addresses are not equal, false otherwise + */ + bool operator!=(const IPv6Address& rhs) const + { + return !(*this == rhs); + } + + /** + * Allocates a byte array and copies address value into it. Array deallocation is user responsibility + * @param[in] arr A pointer to where array will be allocated + * @param[out] length Returns the length in bytes of the array that was allocated + */ + void copyTo(uint8_t** arr, size_t& length) const; + + /** + * Gets a pointer to an already allocated byte array and copies the address value to it. + * This method assumes array allocated size is at least 16 (the size of an IPv6 address) + * @param[in] arr A pointer to the array which address will be copied to + */ + void copyTo(uint8_t* arr) const + { + memcpy(arr, m_Bytes.data(), m_Bytes.size() * sizeof(uint8_t)); + } + + /** + * Checks whether the address matches a network. + * @param network An IPv6Network network + * @return True if the address matches the network or false otherwise + */ + bool matchNetwork(const IPv6Network& network) const; + + /** + * Checks whether the address matches a network. + * For example: this method will return true for address d6e5:83dc:0c58:bc5d:1449:5898:: and network + * which is one of: + * d6e5:83dc:0c58:bc5d::/64, d6e5:83dc:0c58:bc5d::/ffff:ffff:ffff:ffff:: + * Another example: this method will return false for address d6e5:83dc:: and network which is one of: + * d6e5:83dc:0c58:bc5d::/64, d6e5:83dc:0c58:bc5d::/ffff:ffff:ffff:ffff:: + * @param[in] network A string in one of these formats: + * - IPV6_ADDRESS/Y where IPV6_ADDRESS is a valid IPv6 address and Y is a number between 0 and 128 + * - IPV6_ADDRESS/IPV6_NETMASK where IPV6_ADDRESS is a valid IPv6 address and IPV6_NETMASK is a valid + * IPv6 netmask + * @return True if the address matches the network or false if it doesn't or if the network is invalid + */ + bool matchNetwork(const std::string& network) const; + + /** + * A static method that checks whether a string represents a valid IPv6 address + * @param[in] addrAsString The std::string representation of the address + * @return True if the address is valid, false otherwise + */ + static bool isValidIPv6Address(const std::string& addrAsString); + + /** + * A static value representing a zero value of IPv6 address, meaning address of value + * "0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0". + */ + static const IPv6Address Zero; + + /** + * A static value representing the lower bound of IPv6 multicast ranges. The bound is inclusive. + * MulticastRangeLowerBound is initialized to "ff00:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0". + * In order to check whether the address is a multicast address the isMulticast method can be used. + */ + static const IPv6Address MulticastRangeLowerBound; + + private: + std::array m_Bytes = { 0 }; + }; // class IPv6Address + + /** + * @class IPAddress + * The class is a version-independent representation for an IP address + */ + class IPAddress + { + public: + /** + * An enum representing the address type: IPv4 or IPv6 + */ + enum AddressType + { + /** + * IPv4 address type + */ + IPv4AddressType, + /** + * IPv6 address type + */ + IPv6AddressType + }; + + /** + * A default constructor that creates an instance of the class with unspecified IPv4 address + */ + IPAddress() : m_Type(IPv4AddressType) + {} + + /** + * A constructor that creates an instance of the class out of IPv4Address. + * @param[in] addr A const reference to instance of IPv4Address + */ + IPAddress(const IPv4Address& addr) : m_Type(IPv4AddressType), m_IPv4(addr) + {} + + /** + * A constructor that creates an instance of the class out of IPv6Address. + * @param[in] addr A const reference to instance of IPv6Address + */ + IPAddress(const IPv6Address& addr) : m_Type(IPv6AddressType), m_IPv6(addr) + {} + + /** + * A constructor that creates an instance of the class out of std::string value + * + * @param[in] addrAsString The std::string representation of the address + * @throws std::invalid_argument The provided string does not represent a valid IPv4 or IPv6 address. + */ + IPAddress(const std::string& addrAsString); + + /** + * Overload of an assignment operator. + * @param[in] addr A const reference to instance of IPv4Address + * @return A reference to the assignee + */ + inline IPAddress& operator=(const IPv4Address& addr); + + /** + * Overload of an assignment operator. + * @param[in] addr A const reference to instance of IPv6Address + * @return A reference to the assignee + */ + inline IPAddress& operator=(const IPv6Address& addr); + + /** + * Gets the address type: IPv4 or IPv6 + * @return The address type + */ + AddressType getType() const + { + return static_cast(m_Type); + } + + /** + * Returns a std::string representation of the address + * @return A string representation of the address + */ + std::string toString() const + { + return (getType() == IPv4AddressType) ? m_IPv4.toString() : m_IPv6.toString(); + } + + /** + * @return Determine whether the object contains an IP version 4 address + */ + bool isIPv4() const + { + return getType() == IPv4AddressType; + } + + /** + * @return Determine whether the object contains an IP version 6 address + */ + bool isIPv6() const + { + return getType() == IPv6AddressType; + } + + /** + * Determine whether the address is a multicast address + * @return True if an address is multicast + */ + bool isMulticast() const + { + return (getType() == IPv4AddressType) ? m_IPv4.isMulticast() : m_IPv6.isMulticast(); + } + + /** + * Get a reference to IPv4 address instance + * @return The const reference to IPv4Address instance + */ + const IPv4Address& getIPv4() const + { + return m_IPv4; + } + + /** + * Get a reference to IPv6 address instance + * @return The const reference to IPv6Address instance + */ + const IPv6Address& getIPv6() const + { + return m_IPv6; + } + + /** + * @return True if the address is zero, false otherwise + */ + bool isZero() const + { + return (getType() == IPv4AddressType) ? m_IPv4 == IPv4Address::Zero : m_IPv6 == IPv6Address::Zero; + } + + /** + * Overload of the equal-to operator + * @param[in] rhs The object to compare with + * @return True if the addresses are equal, false otherwise + */ + inline bool operator==(const IPAddress& rhs) const; + + /** + * Overload of the less-than operator + * @param[in] rhs The object to compare with + * @return True if the address value is lower than the other address value, false otherwise + */ + inline bool operator<(const IPAddress& rhs) const; + + /** + * Overload of the not-equal-to operator + * @param[in] rhs The object to compare with + * @return True if the addresses are not equal, false otherwise + */ + bool operator!=(const IPAddress& rhs) const + { + return !(*this == rhs); + } + + private: + uint8_t m_Type; + IPv4Address m_IPv4; + IPv6Address m_IPv6; + }; + + // implementation of inline methods + + bool IPAddress::operator==(const IPAddress& rhs) const + { + if (isIPv4()) + return rhs.isIPv4() ? (m_IPv4 == rhs.m_IPv4) : false; + + return rhs.isIPv6() ? m_IPv6 == rhs.m_IPv6 : false; + } + + bool IPAddress::operator<(const IPAddress& rhs) const + { + if (isIPv4()) + { + // treat IPv4 as less than IPv6 + // If current obj is IPv4 and other is IPv6 return true + return rhs.isIPv4() ? (m_IPv4 < rhs.m_IPv4) : true; + } + return rhs.isIPv6() ? m_IPv6 < rhs.m_IPv6 : false; + } + + IPAddress& IPAddress::operator=(const IPv4Address& addr) + { + m_Type = IPv4AddressType; + m_IPv4 = addr; + return *this; + } + + IPAddress& IPAddress::operator=(const IPv6Address& addr) + { + m_Type = IPv6AddressType; + m_IPv6 = addr; + return *this; + } + + /** + * @class IPv4Network + * A class representing IPv4 network definition + */ + class IPv4Network + { + public: + /** + * A constructor that creates an instance of the class out of an address and a full prefix length, + * essentially making a network of consisting of only 1 address. + * + * @param address An address representing the network prefix. + */ + explicit IPv4Network(const IPv4Address& address) : IPv4Network(address, 32u) + {} + + /** + * A constructor that creates an instance of the class out of an address representing the network prefix + * and a prefix length + * @param address An address representing the network prefix. If the address is invalid std::invalid_argument + * exception is thrown + * @param prefixLen A number between 0 and 32 representing the prefix length. + * @throws std::invalid_argument Prefix length is out of acceptable range. + */ + IPv4Network(const IPv4Address& address, uint8_t prefixLen); + + /** + * A constructor that creates an instance of the class out of an address representing the network prefix + * and a netmask + * @param address An address representing the network prefix. If the address is invalid std::invalid_argument + * exception is thrown + * @param netmask A string representing a netmask in the format of X.X.X.X, for example: 255.255.0.0. + * Please notice that netmasks that start with zeros are invalid, for example: 0.0.255.255. The only netmask + * starting with zeros that is valid is 0.0.0.0. + * @throws std::invalid_argument The provided netmask is invalid. + */ + IPv4Network(const IPv4Address& address, const std::string& netmask); + + /** + * A constructor that creates an instance of the class out of a string representing the network prefix and + * a prefix length or a netmask + * @param addressAndNetmask A string in one of these formats: + * - X.X.X.X/Y where X.X.X.X is a valid IPv4 address representing the network prefix and Y is a number between + * 0 and 32 representing the network prefix + * - X.X.X.X/Y.Y.Y.Y where X.X.X.X is a valid IPv4 address representing the network prefix and Y.Y.Y.Y is + * a valid netmask + * @throws std::invalid_argument The provided string does not represent a valid address and netmask format. + */ + IPv4Network(const std::string& addressAndNetmask); + + /** + * @return The prefix length, for example: the prefix length of 10.10.10.10/255.0.0.0 is 8 + */ + uint8_t getPrefixLen() const; + + /** + * @return The netmask, for example: the netmask of 10.10.10.10/8 is 255.0.0.0 + */ + std::string getNetmask() const + { + return IPv4Address(m_Mask).toString(); + } + + /** + * @return The network prefix, for example: the network prefix of 10.10.10.10/16 is 10.10.0.0 + */ + IPv4Address getNetworkPrefix() const + { + return IPv4Address(m_NetworkPrefix); + } + + /** + * @return The lowest non-reserved IPv4 address in this network, for example: the lowest address + * in 10.10.10.10/16 is 10.10.0.1 + */ + IPv4Address getLowestAddress() const; + + /** + * @return The highest non-reserved IPv4 address in this network, for example: the highest address + * in 10.10.10.10/16 is 10.10.255.254 + */ + IPv4Address getHighestAddress() const; + + /** + * @return The number of addresses in this network including reserved addresses, for example: + * the number of addresses in 10.10.0.0/24 is 256 + */ + uint64_t getTotalAddressCount() const; + + /** + * @param address An IPv4 address + * @return True is the address belongs to the network, false otherwise or if the address isn't valid + */ + bool includes(const IPv4Address& address) const; + + /** + * @param network An IPv4 network + * @return True is the input network is completely included within this network, false otherwise, for example: + * 10.10.10.10/16 includes 10.10.10.10/24 but doesn't include 10.10.10.10/8 + */ + bool includes(const IPv4Network& network) const; + + /** + * @return A string representation of the network in a format of NETWORK_PREFIX/PREFIX_LEN, for example: + * 192.168.0.0/16 + */ + std::string toString() const; + + private: + uint32_t m_NetworkPrefix; + uint32_t m_Mask; + + bool isValidNetmask(const IPv4Address& netmaskAddress); + void initFromAddressAndPrefixLength(const IPv4Address& address, uint8_t prefixLen); + void initFromAddressAndNetmask(const IPv4Address& address, const IPv4Address& netmaskAddress); + }; + + /** + * @class IPv6Network + * A class representing IPv6 network definition + */ + class IPv6Network + { + public: + /** + * A constructor that creates an instance of the class out of an address and a full prefix length, + * essentially making a network of consisting of only 1 address. + * + * @param address An address representing the network prefix. + */ + explicit IPv6Network(const IPv6Address& address) : IPv6Network(address, 128u) + {} + + /** + * A constructor that creates an instance of the class out of an address representing the network prefix + * and a prefix length + * @param address An address representing the network prefix. If the address is invalid std::invalid_argument + * exception is thrown + * @param prefixLen A number between 0 and 128 representing the prefix length. + * @throws std::invalid_argument Prefix length is out of acceptable range. + */ + IPv6Network(const IPv6Address& address, uint8_t prefixLen); + + /** + * A constructor that creates an instance of the class out of an address representing the network prefix + * and a netmask + * @param address An address representing the network prefix. If the address is invalid std::invalid_argument + * exception is thrown + * @param netmask A string representing a netmask in valid IPv6 format, for example: ffff:ffff::. + * Please notice that netmasks that start with zeros are invalid, for example: 0:ffff::. The only netmask + * starting with zeros that is valid is all zeros (::). + * @throws std::invalid_argument The provided netmask is invalid. + */ + IPv6Network(const IPv6Address& address, const std::string& netmask); + + /** + * A constructor that creates an instance of the class out of a string representing the network prefix and + * a prefix length or a netmask + * @param addressAndNetmask A string in one of these formats: + * - IPV6_ADDRESS/Y where IPV6_ADDRESS is a valid IPv6 address representing the network prefix and Y is + * a number between 0 and 128 representing the network prefix + * - IPV6_ADDRESS/IPV6_NETMASK where IPV6_ADDRESS is a valid IPv6 address representing the network prefix + * and IPV6_NETMASK is a valid IPv6 netmask + * @throws std::invalid_argument The provided string does not represent a valid address and netmask format. + */ + IPv6Network(const std::string& addressAndNetmask); + + /** + * @return The prefix length, for example: the prefix length of 3546::/ffff:: is 16 + */ + uint8_t getPrefixLen() const; + + /** + * @return The netmask, for example: the netmask of 3546::/16 is ffff:: + */ + std::string getNetmask() const + { + return IPv6Address(m_Mask).toString(); + } + + /** + * @return The network prefix, for example: the network prefix of 3546:f321::/16 is 3546:: + */ + IPv6Address getNetworkPrefix() const + { + return IPv6Address(m_NetworkPrefix); + } + + /** + * @return The lowest non-reserved IPv6 address in this network, for example: the lowest address in 3546::/16 is + * 3546::1 + */ + IPv6Address getLowestAddress() const; + + /** + * @return The highest IPv6 address in this network, for example: the highest address in 3546::/16 is + * 3546:ffff:ffff:ffff:ffff:ffff:ffff:ffff + */ + IPv6Address getHighestAddress() const; + + /** + * @return The number of addresses in this network, for example: the number of addresses in 16ff::/120 is 256. + * If the number of addresses exceeds the size of uint64_t a std::out_of_range exception is thrown + */ + uint64_t getTotalAddressCount() const; + + /** + * @param address An IPv6 address + * @return True is the address belongs to the network, false otherwise or if the address isn't valid + */ + bool includes(const IPv6Address& address) const; + + /** + * @param network An IPv6 network + * @return True is the input network is completely included within this network, false otherwise, for example: + * 3546::/64 includes 3546::/120 but doesn't include 3546::/16 + */ + bool includes(const IPv6Network& network) const; + + /** + * @return A string representation of the network in a format of NETWORK_PREFIX/PREFIX_LEN, for example: + * fda7:9f81:6c23:275::/64 + */ + std::string toString() const; + + private: + uint8_t m_NetworkPrefix[16]; + uint8_t m_Mask[16]; + + bool isValidNetmask(const IPv6Address& netmaskAddress); + void initFromAddressAndPrefixLength(const IPv6Address& address, uint8_t prefixLen); + void initFromAddressAndNetmask(const IPv6Address& address, const IPv6Address& netmaskAddress); + }; + + /** + * @class IPNetwork + * A class representing version independent IP network definition, both IPv4 and IPv6 are included + */ + class IPNetwork + { + public: + /** + * A constructor that creates an instance of the class out of an IP address and a full prefix length, + * essentially making a network of consisting of only 1 address. + * + * @param address An address representing the network prefix. + */ + explicit IPNetwork(const IPAddress& address) : IPNetwork(address, address.isIPv4() ? 32u : 128u) + {} + + /** + * A constructor that creates an instance of the class out of an address representing the network prefix + * and a prefix length + * @param address An address representing the network prefix. If the address is invalid std::invalid_argument + * exception is thrown + * @param prefixLen A number representing the prefix length. Allowed ranges are 0 - 32 for IPv4 networks and 0 - + * 128 for IPv6 networks. + * @throws std::invalid_argument Prefix length is out of acceptable range. + */ + IPNetwork(const IPAddress& address, uint8_t prefixLen) + { + if (address.isIPv4()) + { + m_IPv4Network = std::unique_ptr(new IPv4Network(address.getIPv4(), prefixLen)); + } + else + { + m_IPv6Network = std::unique_ptr(new IPv6Network(address.getIPv6(), prefixLen)); + } + } + + /** + * A constructor that creates an instance of the class out of an address representing the network prefix + * and a netmask + * @param address An address representing the network prefix. If the address is invalid std::invalid_argument + * exception is thrown + * @param netmask A string representing a netmask in valid format, for example: ffff:ffff:: for IPv6 networks + * or 255.255.0.0 for IPv4 networks. + * Please notice that netmasks that start with zeros are invalid, for example: 0:ffff:: or 0.255.255.255. + * The only netmask starting with zeros that is valid is all zeros (:: or 0.0.0.0). + * @throws std::invalid_argument The provided netmask is invalid. + */ + IPNetwork(const IPAddress& address, const std::string& netmask) + { + if (address.isIPv4()) + { + m_IPv4Network = std::unique_ptr(new IPv4Network(address.getIPv4(), netmask)); + } + else + { + m_IPv6Network = std::unique_ptr(new IPv6Network(address.getIPv6(), netmask)); + } + } + + /** + * A constructor that creates an instance of the class out of a string representing the network prefix and + * a prefix length or a netmask + * @param addressAndNetmask A string in one of these formats: + * - IP_ADDRESS/Y where IP_ADDRESS is a valid IP address representing the network prefix and Y is + * a number representing the network prefix + * - IP_ADDRESS/NETMASK where IP_ADDRESS is a valid IP address representing the network prefix and NETMASK + * is a valid netmask for this type of network (IPv4 or IPv6 network) + * @throws std::invalid_argument The provided string does not represent a valid address and netmask format. + */ + IPNetwork(const std::string& addressAndNetmask) + { + try + { + m_IPv4Network = std::unique_ptr(new IPv4Network(addressAndNetmask)); + } + catch (const std::invalid_argument&) + { + m_IPv6Network = std::unique_ptr(new IPv6Network(addressAndNetmask)); + } + } + + /** + * A copy c'tor for this class + * @param other The instance to copy from + */ + IPNetwork(const IPNetwork& other) + { + if (other.m_IPv4Network) + { + m_IPv4Network = std::unique_ptr(new IPv4Network(*other.m_IPv4Network)); + } + + if (other.m_IPv6Network) + { + m_IPv6Network = std::unique_ptr(new IPv6Network(*other.m_IPv6Network)); + } + } + + /** + * Overload of an assignment operator. + * @param[in] other An instance of IPNetwork to assign + * @return A reference to the assignee + */ + IPNetwork& operator=(const IPNetwork& other) + { + if (other.isIPv4Network()) + { + return this->operator=(*other.m_IPv4Network); + } + else + { + return this->operator=(*other.m_IPv6Network); + } + } + + /** + * Overload of an assignment operator. + * @param[in] other An instance of IPv4Network to assign + * @return A reference to the assignee + */ + IPNetwork& operator=(const IPv4Network& other) + { + if (m_IPv4Network) + { + m_IPv4Network = nullptr; + } + + if (m_IPv6Network) + { + m_IPv6Network = nullptr; + } + + m_IPv4Network = std::unique_ptr(new IPv4Network(other)); + + return *this; + } + + /** + * Overload of an assignment operator. + * @param[in] other An instance of IPv6Network to assign + * @return A reference to the assignee + */ + IPNetwork& operator=(const IPv6Network& other) + { + if (m_IPv4Network) + { + m_IPv4Network = nullptr; + } + + if (m_IPv6Network) + { + m_IPv6Network = nullptr; + } + + m_IPv6Network = std::unique_ptr(new IPv6Network(other)); + + return *this; + } + + /** + * @return The prefix length, for example: the prefix length of 3546::/ffff:: is 16, the prefix length of + * 10.10.10.10/255.0.0.0 is 8 + */ + uint8_t getPrefixLen() const + { + return (m_IPv4Network != nullptr ? m_IPv4Network->getPrefixLen() : m_IPv6Network->getPrefixLen()); + } + + /** + * @return The netmask, for example: the netmask of 3546::/16 is ffff::, the netmask of 10.10.10.10/8 is + * 255.0.0.0 + */ + std::string getNetmask() const + { + return (m_IPv4Network != nullptr ? m_IPv4Network->getNetmask() : m_IPv6Network->getNetmask()); + } + + /** + * @return The network prefix, for example: the network prefix of 3546:f321::/16 is 3546::, the network prefix + * of 10.10.10.10/16 is 10.10.0.0 + */ + IPAddress getNetworkPrefix() const + { + return (m_IPv4Network != nullptr ? IPAddress(m_IPv4Network->getNetworkPrefix()) + : IPAddress(m_IPv6Network->getNetworkPrefix())); + } + + /** + * @return The lowest non-reserved IP address in this network, for example: the lowest address in 3546::/16 is + * 3546::1, the lowest address in 10.10.10.10/16 is 10.10.0.1 + */ + IPAddress getLowestAddress() const + { + return (m_IPv4Network != nullptr ? IPAddress(m_IPv4Network->getLowestAddress()) + : IPAddress(m_IPv6Network->getLowestAddress())); + } + + /** + * @return The highest non-reserved IP address in this network, for example: the highest address in 3546::/16 is + * 3546:ffff:ffff:ffff:ffff:ffff:ffff:ffff, the highest address in 10.10.10.10/16 is 10.10.255.254 + */ + IPAddress getHighestAddress() const + { + return (m_IPv4Network != nullptr ? IPAddress(m_IPv4Network->getHighestAddress()) + : IPAddress(m_IPv6Network->getHighestAddress())); + } + + /** + * @return The number of addresses in this network, for example: the number of addresses in 16ff::/120 is 256, + * the number of addresses in 10.10.0.0/24 is 256. If the number of addresses exceeds the size of uint64_t + * a std::out_of_range exception is thrown + */ + uint64_t getTotalAddressCount() const + { + return (m_IPv4Network != nullptr ? m_IPv4Network->getTotalAddressCount() + : m_IPv6Network->getTotalAddressCount()); + } + + /** + * @return True if this is an IPv4 network, false otherwise + */ + bool isIPv4Network() const + { + return m_IPv4Network != nullptr; + } + + /** + * @return True if this is an IPv6 network, false otherwise + */ + bool isIPv6Network() const + { + return m_IPv6Network != nullptr; + } + + /** + * @param address An IP address + * @return True is the address belongs to the network, false otherwise or if the address isn't valid + */ + bool includes(const IPAddress& address) const + { + if (m_IPv4Network != nullptr) + { + if (address.isIPv6()) + { + return false; + } + + return m_IPv4Network->includes(address.getIPv4()); + } + else + { + if (address.isIPv4()) + { + return false; + } + + return m_IPv6Network->includes(address.getIPv6()); + } + } + + /** + * @param network An IP network + * @return True is the input network is completely included within this network, false otherwise + */ + bool includes(const IPNetwork& network) const + { + if (m_IPv4Network != nullptr) + { + if (network.isIPv6Network()) + { + return false; + } + + return m_IPv4Network->includes(*network.m_IPv4Network); + } + else + { + if (network.isIPv4Network()) + { + return false; + } + + return m_IPv6Network->includes(*network.m_IPv6Network); + } + } + + /** + * @return A string representation of the network in a format of NETWORK_PREFIX/PREFIX_LEN, for example: + * fda7:9f81:6c23:275::/64 or 192.168.0.0/16 + */ + std::string toString() const + { + return (m_IPv4Network != nullptr ? m_IPv4Network->toString() : m_IPv6Network->toString()); + } + + private: + std::unique_ptr m_IPv4Network; + std::unique_ptr m_IPv6Network; + }; +} // namespace pcpp + +inline std::ostream& operator<<(std::ostream& os, const pcpp::IPv4Address& ipv4Address) +{ + os << ipv4Address.toString(); + return os; +} + +inline std::ostream& operator<<(std::ostream& os, const pcpp::IPv6Address& ipv6Address) +{ + os << ipv6Address.toString(); + return os; +} + +inline std::ostream& operator<<(std::ostream& os, const pcpp::IPAddress& ipAddress) +{ + os << ipAddress.toString(); + return os; +} + +inline std::ostream& operator<<(std::ostream& os, const pcpp::IPv4Network& network) +{ + os << network.toString(); + return os; +} + +inline std::ostream& operator<<(std::ostream& os, const pcpp::IPv6Network& network) +{ + os << network.toString(); + return os; +} + +inline std::ostream& operator<<(std::ostream& os, const pcpp::IPNetwork& network) +{ + os << network.toString(); + return os; +} diff --git a/Common++/header/pcapplusplus/IpAddressUtils.h b/Common++/header/pcapplusplus/IpAddressUtils.h new file mode 100644 index 0000000000..a7b6ac7041 --- /dev/null +++ b/Common++/header/pcapplusplus/IpAddressUtils.h @@ -0,0 +1,139 @@ +#pragma once + +/// @file + +// Forward declarations +struct in_addr; +struct in6_addr; + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + // Forward declarations + class IPv4Address; + class IPv6Address; + class IPAddress; + + /** + * Overload of the equal-to operator + * @return True if the addresses are equal, false otherwise + */ + bool operator==(const IPv4Address& lhs, const in_addr& rhs); + /** + * Overload of the not-equal-to operator + * @return True if the addresses differ, false otherwise + */ + inline bool operator!=(const IPv4Address& lhs, const in_addr& rhs) + { + return !(lhs == rhs); + } + /** + * Overload of the equal-to operator + * @return True if the addresses are equal, false otherwise + */ + inline bool operator==(const in_addr& lhs, const IPv4Address& rhs) + { + return rhs == lhs; + } + /** + * Overload of the not-equal-to operator + * @return True if the addresses differ, false otherwise + */ + inline bool operator!=(const in_addr& lhs, const IPv4Address& rhs) + { + return !(lhs == rhs); + } + + /** + * Overload of the equal-to operator + * @return True if the addresses are equal, false otherwise + */ + bool operator==(const IPv6Address& lhs, const in6_addr& rhs); + /** + * Overload of the not-equal-to operator + * @return True if the addresses differ, false otherwise + */ + inline bool operator!=(const IPv6Address& lhs, const in6_addr& rhs) + { + return !(lhs == rhs); + } + /** + * Overload of the equal-to operator + * @return True if the addresses are equal, false otherwise + */ + inline bool operator==(const in6_addr& lhs, const IPv6Address& rhs) + { + return rhs == lhs; + } + /** + * Overload of the not-equal-to operator + * @return True if the addresses differ, false otherwise + */ + inline bool operator!=(const in6_addr& lhs, const IPv6Address& rhs) + { + return !(lhs == rhs); + } + + /** + * Overload of the equal-to operator + * @return True if the addresses are equal, false otherwise + */ + bool operator==(const IPAddress& lhs, const in_addr& rhs); + /** + * Overload of the not-equal-to operator + * @return True if the addresses differ, false otherwise + */ + inline bool operator!=(const IPAddress& lhs, const in_addr& rhs) + { + return !(lhs == rhs); + } + /** + * Overload of the equal-to operator + * @return True if the addresses are equal, false otherwise + */ + inline bool operator==(const in_addr& lhs, const IPAddress& rhs) + { + return rhs == lhs; + } + /** + * Overload of the not-equal-to operator + * @return True if the addresses differ, false otherwise + */ + inline bool operator!=(const in_addr& lhs, const IPAddress& rhs) + { + return !(lhs == rhs); + } + + /** + * Overload of the equal-to operator + * @return True if the addresses are equal, false otherwise + */ + bool operator==(const IPAddress& lhs, const in6_addr& rhs); + /** + * Overload of the not-equal-to operator + * @return True if the addresses differ, false otherwise + */ + inline bool operator!=(const IPAddress& lhs, const in6_addr& rhs) + { + return !(lhs == rhs); + } + /** + * Overload of the equal-to operator + * @return True if the addresses are equal, false otherwise + */ + inline bool operator==(const in6_addr& lhs, const IPAddress& rhs) + { + return rhs == lhs; + } + /** + * Overload of the not-equal-to operator + * @return True if the addresses differ, false otherwise + */ + inline bool operator!=(const in6_addr& lhs, const IPAddress& rhs) + { + return !(lhs == rhs); + } +} // namespace pcpp diff --git a/Common++/header/pcapplusplus/IpUtils.h b/Common++/header/pcapplusplus/IpUtils.h new file mode 100644 index 0000000000..2cf9f7a00f --- /dev/null +++ b/Common++/header/pcapplusplus/IpUtils.h @@ -0,0 +1,107 @@ +#pragma once + +#include +#ifdef __linux__ +# include +# include +#endif +#if defined(__APPLE__) +# include +# include +#endif +#if defined(_WIN32) +# include +#endif +#if defined(__FreeBSD__) +# include +# include +# include +#endif + +/// @file + +// Both Visual C++ Compiler and MinGW-w64 define inet_ntop() and inet_pton() +// Add compatibility functions for old MinGW (aka MinGW32) +// We use "__MINGW64_VERSION_MAJOR" and not __MINGW64__ to detect MinGW-w64 compiler +// because the second one is not defined for MinGW-w64 in 32bits mode +#if defined(_WIN32) && !defined(_MSC_VER) && (!defined(__MINGW64_VERSION_MAJOR) || (__MINGW64_VERSION_MAJOR < 8)) +/** + * Convert a network format address to presentation format. + * @param[in] af Address family, can be either AF_INET (IPv4) or AF_INET6 (IPv6) + * @param[in] src Network address structure, can be either in_addr (IPv4) or in6_addr (IPv6) + * @param[out] dst Network address string representation + * @param[in] size 'dst' Maximum size + * @return pointer to presentation format address ('dst'), or nullptr (see errno). + */ +const char* inet_ntop(int af, const void* src, char* dst, size_t size); + +/** + * Convert from presentation format (which usually means ASCII printable) + * to network format (which is usually some kind of binary format). + * @param[in] af Address family, can be either AF_INET (IPv4) or AF_INET6 (IPv6) + * @param[in] src Network address string representation + * @param[out] dst Network address structure result, can be either in_addr (IPv4) or in6_addr (IPv6) + * @return + * 1 if the address was valid for the specified address family; + * 0 if the address wasn't valid ('dst' is untouched in this case); + * -1 if some other error occurred ('dst' is untouched in this case, too) + */ +int inet_pton(int af, const char* src, void* dst); +#endif + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + namespace internal + { + /** + * Extract IPv4 address from sockaddr + * @param[in] sa - input sockaddr + * @return Address in in_addr format + * @throws std::invalid_argument Sockaddr family is not AF_INET or sockaddr is nullptr. + */ + in_addr* sockaddr2in_addr(sockaddr* sa); + + /** + * Attempt to extract IPv4 address from sockaddr + * @param[in] sa - input sockaddr + * @return Pointer to address in in_addr format or nullptr if extraction fails. + */ + in_addr* try_sockaddr2in_addr(sockaddr* sa); + + /** + * Extract IPv6 address from sockaddr + * @param[in] sa - input sockaddr + * @return Address in in6_addr format + * @throws std::invalid_argument Sockaddr family is not AF_INET6 or sockaddr is nullptr. + */ + in6_addr* sockaddr2in6_addr(sockaddr* sa); + + /** + * Attempt to extract IPv6 address from sockaddr + * @param[in] sa - input sockaddr + * @return Pointer to address in in6_addr format or nullptr if extraction fails. + */ + in6_addr* try_sockaddr2in6_addr(sockaddr* sa); + + /** + * Converts a sockaddr format address to its string representation + * @param[in] sa Address in sockaddr format + * @param[out] resultString String representation of the address + * @param[in] resultBufLen Length of the result buffer. + * @throws std::invalid_argument Sockaddr family is not AF_INET or AF_INET6, sockaddr is nullptr or the result + * str buffer is insufficient. + */ + void sockaddr2string(sockaddr const* sa, char* resultString, size_t resultBufLen); + + /** + * Convert a in_addr format address to 32bit representation + * @param[in] inAddr Address in in_addr format + * @return Address in 32bit format + */ + uint32_t in_addr2int(in_addr inAddr); + } // namespace internal +} // namespace pcpp diff --git a/Common++/header/pcapplusplus/LRUList.h b/Common++/header/pcapplusplus/LRUList.h new file mode 100644 index 0000000000..a900c8413a --- /dev/null +++ b/Common++/header/pcapplusplus/LRUList.h @@ -0,0 +1,140 @@ +#pragma once + +#include +#include + +#if __cplusplus > 199711L || _MSC_VER >= 1800 +# include +#endif + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * @class LRUList + * A template class that implements a LRU cache with limited size. Each time the user puts an element it goes to + * head of the list as the most recently used element (if the element was already in the list it advances to the + * head of the list). The last element in the list is the one least recently used and will be pulled out of the list + * if it reaches its max size and a new element comes in. All actions on this LRU list are O(1) + */ + template class LRUList + { + public: + typedef typename std::list::iterator ListIterator; + typedef typename std::unordered_map::iterator MapIterator; + + /** + * A c'tor for this class + * @param[in] maxSize The max size this list can go + */ + explicit LRUList(size_t maxSize) + { + m_MaxSize = maxSize; + } + + /** + * Puts an element in the list. This element will be inserted (or advanced if it already exists) to the head of + * the list as the most recently used element. If the list already reached its max size and the element is new + * this method will remove the least recently used element and return a value in deletedValue. Method complexity + * is O(log(getSize())). This is a optimized version of the method T* put(const T&). + * @param[in] element The element to insert or to advance to the head of the list (if already exists) + * @param[out] deletedValue The value of deleted element if a pointer is not nullptr. This parameter is + * optional. + * @return 0 if the list didn't reach its max size, 1 otherwise. In case the list already reached its max size + * and deletedValue is not nullptr the value of deleted element is copied into the place the deletedValue points + * to. + */ + int put(const T& element, T* deletedValue = nullptr) + { + m_CacheItemsList.push_front(element); + + // Inserting a new element. If an element with an equivalent key already exists the method returns an + // iterator to the element that prevented the insertion + std::pair pair = + m_CacheItemsMap.insert(std::make_pair(element, m_CacheItemsList.begin())); + if (pair.second == false) // already exists + { + m_CacheItemsList.erase(pair.first->second); + pair.first->second = m_CacheItemsList.begin(); + } + + if (m_CacheItemsMap.size() > m_MaxSize) + { + ListIterator lruIter = m_CacheItemsList.end(); + --lruIter; + + if (deletedValue != nullptr) +#if __cplusplus > 199711L || _MSC_VER >= 1800 + *deletedValue = std::move(*lruIter); +#else + *deletedValue = *lruIter; +#endif + m_CacheItemsMap.erase(*lruIter); + m_CacheItemsList.erase(lruIter); + return 1; + } + + return 0; + } + + /** + * Get the most recently used element (the one at the beginning of the list) + * @return The most recently used element + */ + const T& getMRUElement() const + { + return m_CacheItemsList.front(); + } + + /** + * Get the least recently used element (the one at the end of the list) + * @return The least recently used element + */ + const T& getLRUElement() const + { + return m_CacheItemsList.back(); + } + + /** + * Erase an element from the list. If element isn't found in the list nothing happens + * @param[in] element The element to erase + */ + void eraseElement(const T& element) + { + MapIterator iter = m_CacheItemsMap.find(element); + if (iter == m_CacheItemsMap.end()) + return; + + m_CacheItemsList.erase(iter->second); + m_CacheItemsMap.erase(iter); + } + + /** + * @return The max size of this list as determined in the c'tor + */ + size_t getMaxSize() const + { + return m_MaxSize; + } + + /** + * @return The number of elements currently in this list + */ + size_t getSize() const + { + return m_CacheItemsMap.size(); + } + + private: + std::list m_CacheItemsList; + std::unordered_map m_CacheItemsMap; + size_t m_MaxSize; + }; + +} // namespace pcpp diff --git a/Common++/header/pcapplusplus/Logger.h b/Common++/header/pcapplusplus/Logger.h new file mode 100644 index 0000000000..6973cf530d --- /dev/null +++ b/Common++/header/pcapplusplus/Logger.h @@ -0,0 +1,299 @@ +#pragma once + +#include +#include +#include +#include +#include + +#ifndef LOG_MODULE +# define LOG_MODULE UndefinedLogModule +#endif + +// Use __FILE_NAME__ to avoid leaking complete full path +#ifdef __FILE_NAME__ +# define PCAPPP_FILENAME __FILE_NAME__ +#else +# define PCAPPP_FILENAME __FILE__ +#endif + +#define PCPP_LOG(level, message) \ + do \ + { \ + std::ostringstream* sstream = pcpp::Logger::getInstance().internalCreateLogStream(); \ + (*sstream) << message; \ + pcpp::Logger::getInstance().internalPrintLogMessage(sstream, level, PCAPPP_FILENAME, __FUNCTION__, __LINE__); \ + } while (0) + +#define PCPP_LOG_DEBUG(message) \ + do \ + { \ + if (pcpp::Logger::getInstance().logsEnabled() && pcpp::Logger::getInstance().isDebugEnabled(LOG_MODULE)) \ + { \ + PCPP_LOG(pcpp::Logger::Debug, message); \ + } \ + } while (0) + +#define PCPP_LOG_ERROR(message) \ + do \ + { \ + PCPP_LOG(pcpp::Logger::Error, message); \ + } while (0) + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * An enum representing all PcapPlusPlus modules + */ + enum LogModule + { + UndefinedLogModule, + CommonLogModuleIpUtils, ///< IP Utils module (Common++) + CommonLogModuleTablePrinter, ///< Table printer module (Common++) + CommonLogModuleGenericUtils, ///< Generic Utils (Common++) + PacketLogModuleRawPacket, ///< RawPacket module (Packet++) + PacketLogModulePacket, ///< Packet module (Packet++) + PacketLogModuleLayer, ///< Layer module (Packet++) + PacketLogModuleAsn1Codec, ///< Asn1Codec module (Packet++) + PacketLogModuleArpLayer, ///< ArpLayer module (Packet++) + PacketLogModuleEthLayer, ///< EthLayer module (Packet++) + PacketLogModuleIPv4Layer, ///< IPv4Layer module (Packet++) + PacketLogModuleIPv6Layer, ///< IPv6Layer module (Packet++) + PacketLogModulePayloadLayer, ///< PayloadLayer module (Packet++) + PacketLogModuleTcpLayer, ///< TcpLayer module (Packet++) + PacketLogModuleUdpLayer, ///< UdpLayer module (Packet++) + PacketLogModuleVlanLayer, ///< VlanLayer module (Packet++) + PacketLogModuleHttpLayer, ///< HttpLayer module (Packet++) + PacketLogModulePPPoELayer, ///< PPPoELayer module (Packet++) + PacketLogModuleDnsLayer, ///< DnsLayer module (Packet++) + PacketLogModuleMplsLayer, ///< MplsLayer module (Packet++) + PacketLogModuleIcmpLayer, ///< IcmpLayer module (Packet++) + PacketLogModuleIcmpV6Layer, ///< IcmpV6Layer module (Packet++) + PacketLogModuleGreLayer, ///< GreLayer module (Packet++) + PacketLogModuleSSLLayer, ///< SSLLayer module (Packet++) + PacketLogModuleSllLayer, ///< SllLayer module (Packet++) + PacketLogModuleNflogLayer, ///< NflogLayer module (Packet++) + PacketLogModuleDhcpLayer, ///< DhcpLayer module (Packet++) + PacketLogModuleDhcpV6Layer, ///< DhcpV6Layer module (Packet++) + PacketLogModuleIgmpLayer, ///< IgmpLayer module (Packet++) + PacketLogModuleSipLayer, ///< SipLayer module (Packet++) + PacketLogModuleSdpLayer, ///< SdpLayer module (Packet++) + PacketLogModuleRadiusLayer, ///< RadiusLayer module (Packet++) + PacketLogModuleGtpLayer, ///< GtpLayer module (Packet++) + PacketLogModuleBgpLayer, ///< GtpLayer module (Packet++) + PacketLogModuleSSHLayer, ///< SSHLayer module (Packet++) + PacketLogModuleVrrpLayer, ///< Vrrp Record module (Packet++) + PacketLogModuleTcpReassembly, ///< TcpReassembly module (Packet++) + PacketLogModuleIPReassembly, ///< IPReassembly module (Packet++) + PacketLogModuleIPSecLayer, ///< IPSecLayers module (Packet++) + PacketLogModuleNtpLayer, ///< NtpLayer module (Packet++) + PacketLogModuleTelnetLayer, ///< TelnetLayer module (Packet++) + PacketLogModuleStpLayer, ///< StpLayer module (Packet++) + PacketLogModuleLLCLayer, ///< LLCLayer module (Packet++) + PacketLogModuleNdpLayer, ///< NdpLayer module (Packet++) + PacketLogModuleFtpLayer, ///< FtpLayer module (Packet++) + PacketLogModuleSomeIpLayer, ///< SomeIpLayer module (Packet++) + PacketLogModuleSomeIpSdLayer, ///< SomeIpSdLayer module (Packet++) + PacketLogModuleWakeOnLanLayer, ///< WakeOnLanLayer module (Packet++) + PacketLogModuleSmtpLayer, ///< SmtpLayer module (Packet++) + PcapLogModuleWinPcapLiveDevice, ///< WinPcapLiveDevice module (Pcap++) + PcapLogModuleRemoteDevice, ///< WinPcapRemoteDevice module (Pcap++) + PcapLogModuleLiveDevice, ///< PcapLiveDevice module (Pcap++) + PcapLogModuleFileDevice, ///< FileDevice module (Pcap++) + PcapLogModulePfRingDevice, ///< PfRingDevice module (Pcap++) + PcapLogModuleMBufRawPacket, ///< MBufRawPacket module (Pcap++) + PcapLogModuleDpdkDevice, ///< DpdkDevice module (Pcap++) + PcapLogModuleKniDevice, ///< KniDevice module (Pcap++) + PcapLogModuleXdpDevice, ///< XdpDevice module (Pcap++) + NetworkUtils, ///< NetworkUtils module (Pcap++) + NumOfLogModules + }; + + /** + * @class Logger + * PcapPlusPlus logger manager. + * PcapPlusPlus uses this logger to output both error and debug logs. + * There are currently 3 log levels: Logger#Error, Logger#Info and Logger#Debug. + * + * PcapPlusPlus is divided into modules (described in #LogModule enum). The user can set the log level got each + * module or to all modules at once. The default is Logger#Info which outputs only error messages. Changing log + * level for modules can be done dynamically while the application is running. + * + * The logger also exposes a method to retrieve the last error log message. + * + * Logs are printed to console by default in a certain format. The user can set a different print function to change + * the format or to print to other media (such as files, etc.). + * + * PcapPlusPlus logger is a singleton which can be reached from anywhere in the code. + * + * Note: Logger#Info level logs are currently only used in DPDK devices to set DPDK log level to RTE_LOG_NOTICE. + */ + class Logger + { + public: + /** + * An enum representing the log level. Currently 3 log levels are supported: Error, Info and Debug. Info is the + * default log level + */ + enum LogLevel + { + Error, ///< Error log level + Info, ///< Info log level + Debug ///< Debug log level + }; + + /** + * @typedef LogPrinter + * Log printer callback. Used for printing the logs in a custom way. + * @param[in] logLevel The log level for this log message + * @param[in] logMessage The log message + * @param[in] file The source file in PcapPlusPlus code the log message is coming from + * @param[in] method The method in PcapPlusPlus code the log message is coming from + * @param[in] line The line in PcapPlusPlus code the log message is coming from + */ + typedef void (*LogPrinter)(LogLevel logLevel, const std::string& logMessage, const std::string& file, + const std::string& method, const int line); + + /** + * A static method for converting the log level enum to a string. + * @param[in] logLevel A log level enum + * @return The log level as a string + */ + static std::string logLevelAsString(LogLevel logLevel); + + /** + * Get the log level for a certain module + * @param[in] module PcapPlusPlus module + * @return The log level set for this module + */ + LogLevel getLogLevel(LogModule module) + { + return m_LogModulesArray[module]; + } + + /** + * Set the log level for a certain PcapPlusPlus module + * @param[in] module PcapPlusPlus module + * @param[in] level The log level to set the module to + */ + void setLogLevel(LogModule module, LogLevel level) + { + m_LogModulesArray[module] = level; + } + + /** + * Check whether a certain module is set to debug log level + * @param[in] module PcapPlusPlus module + * @return True if this module log level is "debug". False otherwise + */ + bool isDebugEnabled(LogModule module) const + { + return m_LogModulesArray[module] == Debug; + } + + /** + * Set all PcapPlusPlus modules to a certain log level + * @param[in] level The log level to set all modules to + */ + void setAllModulesToLogLevel(LogLevel level) + { + for (int i = 1; i < NumOfLogModules; i++) + m_LogModulesArray[i] = level; + } + + /** + * Set a custom log printer. + * @param[in] printer A log printer function that will be called for every log message + */ + void setLogPrinter(LogPrinter printer) + { + m_LogPrinter = printer; + } + + /** + * Set the log printer back to the default printer + */ + void resetLogPrinter() + { + m_LogPrinter = &defaultLogPrinter; + } + + /** + * @return Get the last error message + */ + std::string getLastError() + { + return m_LastError; + } + + /** + * Suppress logs in all PcapPlusPlus modules + */ + void suppressLogs() + { + m_LogsEnabled = false; + } + + /** + * Enable logs in all PcapPlusPlus modules + */ + void enableLogs() + { + m_LogsEnabled = true; + } + + /** + * Get an indication if logs are currently enabled. + * @return True if logs are currently enabled, false otherwise + */ + bool logsEnabled() const + { + return m_LogsEnabled; + } + + template Logger& operator<<(const T& msg) + { + (*m_LogStream) << msg; + return *this; + } + + std::ostringstream* internalCreateLogStream(); + + /** + * An internal method to print log messages. Shouldn't be used externally. + */ + void internalPrintLogMessage(std::ostringstream* logStream, Logger::LogLevel logLevel, const char* file, + const char* method, int line); + + /** + * Get access to Logger singleton + * @todo: make this singleton thread-safe/ + * @return a pointer to the Logger singleton + **/ + static Logger& getInstance() + { + static Logger instance; + return instance; + } + + private: + bool m_LogsEnabled; + Logger::LogLevel m_LogModulesArray[NumOfLogModules]; + LogPrinter m_LogPrinter; + std::string m_LastError; + std::ostringstream* m_LogStream; + + // private c'tor - this class is a singleton + Logger(); + + static void defaultLogPrinter(LogLevel logLevel, const std::string& logMessage, const std::string& file, + const std::string& method, const int line); + }; +} // namespace pcpp diff --git a/Common++/header/pcapplusplus/MacAddress.h b/Common++/header/pcapplusplus/MacAddress.h new file mode 100644 index 0000000000..29333aa02d --- /dev/null +++ b/Common++/header/pcapplusplus/MacAddress.h @@ -0,0 +1,182 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * @class MacAddress + * Represents L2 MAC addresses. Can be constructed from string or a series of 6 byte octets + */ + class MacAddress + { + public: + /** + * Default constructor for this class. + * Initializes the address as 00:00:00:00:00:00. + */ + MacAddress() = default; + + /** + * A constructor that creates an instance of the class out of a byte array. + * The byte array length should be 6 (as MAC address is 6-byte long), and the remaining bytes are ignored. + * If the byte array is invalid, the constructor throws an exception. + * @param[in] addr A pointer to the byte array containing 6 bytes representing the MAC address + */ + explicit MacAddress(const uint8_t* addr) + { + memcpy(m_Address, addr, sizeof(m_Address)); + } + + /** + * A constructor that creates an instance of the class out of a std::string. + * If the string doesn't represent a valid MAC address, the constructor throws an exception. + * @param[in] addr the string representing the MAC address in format "00:00:00:00:00:00" + */ + explicit MacAddress(const std::string& addr); + + /** + * A template constructor that creates an instance of the class out of a string convertible to std::string. + * If the string doesn't represent a valid MAC address, the constructor throws an exception. + * @param[in] addr the string representing the MAC address in format "00:00:00:00:00:00" + */ + template ::value>::type> + MacAddress(const T& addr) : MacAddress(static_cast(addr)) + {} + + /** + * A constructor that creates an instance of 6 bytes representing the MAC address + * @param[in] firstOctet Represent the first octet in the address + * @param[in] secondOctet Represent the second octet in the address + * @param[in] thirdOctet Represent the third octet in the address + * @param[in] fourthOctet Represent the fourth octet in the address + * @param[in] fifthOctet Represent the fifth octet in the address + * @param[in] sixthOctet Represent the sixth octet in the address + */ + inline MacAddress(uint8_t firstOctet, uint8_t secondOctet, uint8_t thirdOctet, uint8_t fourthOctet, + uint8_t fifthOctet, uint8_t sixthOctet) + { + m_Address[0] = firstOctet; + m_Address[1] = secondOctet; + m_Address[2] = thirdOctet; + m_Address[3] = fourthOctet; + m_Address[4] = fifthOctet; + m_Address[5] = sixthOctet; + } + + /** + * A constructor that creates an instance out of the initializer list. + * The byte list length should be 6 (as MAC address is 6-byte long). + * If the list is invalid, the constructor throws an exception. + * @param[in] octets An initializer list containing the values of type uint8_t representing the MAC address + */ + MacAddress(std::initializer_list octets) + { + if (octets.size() != sizeof(m_Address)) + { + throw std::invalid_argument("Invalid initializer list size, should be 6"); + } + std::copy(octets.begin(), octets.end(), std::begin(m_Address)); + } + + /** + * Overload of the comparison operator. + * @param[in] other The object to compare with + * @return True if addresses are equal, false otherwise + */ + bool operator==(const MacAddress& other) const + { + return memcmp(m_Address, other.m_Address, sizeof(m_Address)) == 0; + } + + /** + * Overload of the not-equal operator + * @param[in] other The object to compare with + * @return True if addresses are not equal, false otherwise + */ + bool operator!=(const MacAddress& other) const + { + return !operator==(other); + } + + /** + * Overload of the assignment operator. + * If the list is invalid, the constructor throws an exception. + * @param[in] octets An initializer list containing the values of type uint8_t representing the MAC address, the + * length of the list must be equal to 6 + */ + MacAddress& operator=(std::initializer_list octets) + { + if (octets.size() != sizeof(m_Address)) + { + throw std::invalid_argument("Invalid initializer list size, should be 6"); + } + + std::copy(octets.begin(), octets.end(), std::begin(m_Address)); + return *this; + } + + /** + * Returns the pointer to raw data + * @return The pointer to raw data + */ + const uint8_t* getRawData() const + { + return m_Address; + } + + /** + * Returns a std::string representation of the address + * @return A string representation of the address + */ + std::string toString() const; + + /** + * Allocates a byte array of length 6 and copies address value into it. Array deallocation is user + * responsibility + * @param[in] arr A pointer to where array will be allocated + */ + void copyTo(uint8_t** arr) const + { + *arr = new uint8_t[sizeof(m_Address)]; + memcpy(*arr, m_Address, sizeof(m_Address)); + } + + /** + * Gets a pointer to an already allocated byte array and copies the address value to it. + * This method assumes array allocated size is at least 6 (the size of a MAC address) + * @param[in] arr A pointer to the array which address will be copied to + */ + void copyTo(uint8_t* arr) const + { + memcpy(arr, m_Address, sizeof(m_Address)); + } + + /** + * A static value representing a zero value of MAC address, meaning address of value "00:00:00:00:00:00" + */ + static MacAddress Zero; + + private: + uint8_t m_Address[6] = { 0 }; + }; +} // namespace pcpp + +inline std::ostream& operator<<(std::ostream& os, const pcpp::MacAddress& macAddress) +{ + os << macAddress.toString(); + return os; +} diff --git a/Common++/header/pcapplusplus/OUILookup.h b/Common++/header/pcapplusplus/OUILookup.h new file mode 100644 index 0000000000..fb49ac236d --- /dev/null +++ b/Common++/header/pcapplusplus/OUILookup.h @@ -0,0 +1,71 @@ +#pragma once + +#include "MacAddress.h" + +#include +#include + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + /** + * @class OUILookup + * Provides vendor name matching functionality from MAC addresses. It uses an internal database to define name of + * the vendor. The class itself should be initialized by using initOUIDatabaseFromJson() otherwise all requests will + * return "Unknown" as vendor. The class itself currently does not support on-fly modifying the database but anyone + * who wants to add/modify/remove entries, should modify 3rdParty/OUILookup/PCPP_OUIDatabase.json file and call to + * initOUIDatabaseFromJson() function to renew the internal data. + */ + class OUILookup + { + private: + /** + * MAC addresses with mask values. For example for a MAC address "XX:XX:XX:XX:X0:00/36" the first element will + * be 36, and the second element will be unsigned integer equivalent of "XX:XX:XX:XX:X0:00" and vendor name. + */ + struct MaskedFilter + { + int mask; + std::unordered_map vendorMap; + }; + + /// Vendors for MAC addresses and mask filters if exists + struct VendorData + { + std::string vendorName; + std::vector maskedFilter; + }; + + /** + * MAC addresses with only first three octets. The first element is unsigned integer equivalent of "XX:XX:XX" + * formatted MAC address + */ + typedef std::unordered_map OUIVendorMap; + + /// Internal vendor list for MAC addresses + OUIVendorMap vendorMap; + + template int64_t internalParser(T& jsonData); + + public: + /** + * Initialise internal OUI database from a JSON file + * @param[in] path Path to OUI database. The database itself is located at + * 3rdParty/OUILookup/PCPP_OUIDatabase.json + * @return Returns the number of total vendors, negative on errors + */ + int64_t initOUIDatabaseFromJson(const std::string& path = ""); + + /** + * Returns the vendor of the MAC address. OUI database should be initialized with initOUIDatabaseFromJson() + * @param[in] addr MAC address to search + * @return Vendor name + */ + std::string getVendorName(const pcpp::MacAddress& addr); + }; +} // namespace pcpp diff --git a/Common++/header/pcapplusplus/PcapPlusPlusVersion.h b/Common++/header/pcapplusplus/PcapPlusPlusVersion.h new file mode 100644 index 0000000000..0e47016610 --- /dev/null +++ b/Common++/header/pcapplusplus/PcapPlusPlusVersion.h @@ -0,0 +1,68 @@ +#pragma once + +#include + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ +#define PCAPPLUSPLUS_VERSION "24.09+" +#define PCAPPLUSPLUS_VERSION_OFFICIAL "non-official release" + +#define PCAPPLUSPLUS_VERSION_FULL "v" PCAPPLUSPLUS_VERSION " (" PCAPPLUSPLUS_VERSION_OFFICIAL ")" + + /** + * @return PcapPlusPlus current version, e.g: 23.09. Notice that for non-official releases (which were pulled from + * GitHub) the version will end with a '+'. For example: '23.09+' means non-official release but '23.09' means + * official release + */ + inline std::string getPcapPlusPlusVersion() + { + return PCAPPLUSPLUS_VERSION; + } + + /** + * @return PcapPlusPlus long version string which includes the version and info whether it's an official or + * non-official release. For example: "v23.09+ (non-official release)" or "v23.09 (official release)" + */ + inline std::string getPcapPlusPlusVersionFull() + { + return PCAPPLUSPLUS_VERSION_FULL; + } + + /** + * @return The build date and time in a format of "Mmm dd yyyy hh:mm:ss" + */ +#ifdef PCAPPP_BUILD_REPRODUCIBLE + inline std::string getBuildDateTime() + { + return " "; + } +#else + inline std::string getBuildDateTime() + { + return std::string(__DATE__) + " " + std::string(__TIME__); + } +#endif + + /** + * @return The Git commit (revision) the binaries are built from + */ + std::string getGitCommit(); + + /** + * @return The Git branch the binaries are built from + */ + std::string getGitBranch(); + + /** + * @return Git branch and commit the binaries are built from. + * Aggregates data from getGitCommit() and getGitBranch() + */ + std::string getGitInfo(); + +} // namespace pcpp diff --git a/Common++/header/pcapplusplus/PointerVector.h b/Common++/header/pcapplusplus/PointerVector.h new file mode 100644 index 0000000000..342ad62e0b --- /dev/null +++ b/Common++/header/pcapplusplus/PointerVector.h @@ -0,0 +1,416 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "DeprecationUtils.h" + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + namespace internal + { + /** + * @brief A helper struct to facilitate the creation of a copy of an object. + * @tparam T The type of object to copy. + * @tparam Enable Helper parameter for SFINAE. + */ + template struct Copier + { + std::unique_ptr operator()(const T& obj) const + { + return std::unique_ptr(new T(obj)); + } + }; + + /** + * @brief A specialization of Copier to facilitate the safe copying of polymorphic objects via clone() method. + * @tparam T The type of object to copy. + */ + template struct Copier::value>::type> + { + std::unique_ptr operator()(const T& obj) const + { + // Clone can return unique_ptr or raw pointer. + return std::unique_ptr(std::move(obj.clone())); + } + }; + } // namespace internal + + /** + * @class PointerVector + * A template class for representing a std::vector of pointers. Once (a pointer to) an element is added to this + * vector, the element responsibility moves to the vector, meaning the PointerVector will free the object once it's + * removed from the vector This class wraps std::vector and adds the capability of freeing objects once they're + * removed from it + */ + template class PointerVector + { + public: + /** + * Iterator object that is used for iterating all elements in the vector + */ + using VectorIterator = typename std::vector::iterator; + + /** + * Const iterator object that is used for iterating all elements in a constant vector + */ + using ConstVectorIterator = typename std::vector::const_iterator; + + /** + * A constructor that create an empty instance of this object + */ + PointerVector() + {} + + /** + * Copies the vector along with all elements inside it. + * All elements inside the copied vector are duplicates and the originals remain unchanged. + * @param[in] other The vector to copy from. + * @remarks As the vector is copied via deep copy, all pointers obtained from the copied vector + * reference the duplicates and not the originals. + */ + PointerVector(const PointerVector& other) : m_Vector(deepCopyUnsafe(other.m_Vector)) + {} + + /** + * Move constructor. All elements along with their ownership is transferred to the new vector. + * @param[in] other The vector to move from. + */ + PointerVector(PointerVector&& other) noexcept : m_Vector(std::move(other.m_Vector)) + { + other.m_Vector.clear(); + } + + /** + * A destructor for this class. The destructor frees all elements that are binded to the vector + */ + ~PointerVector() + { + freeVectorUnsafe(m_Vector); + } + + /** + * A copy assignment operator. Replaces the contents with a copy of the contents of other. + * See copy constructor for more information on the specific copy procedure. + * @param[in] other The vector to copy from. + * @return A reference to the current object. + */ + PointerVector& operator=(const PointerVector& other) + { + // Saves a copy of the old pointer to defer cleanup. + auto oldValues = m_Vector; + try + { + m_Vector = deepCopyUnsafe(other.m_Vector); + } + // If an exception is thrown during the copy operation, restore old values and rethrow. + catch (const std::exception&) + { + m_Vector = std::move(oldValues); + throw; + } + // Free old values as the new ones have been successfully assigned. + freeVectorUnsafe(oldValues); + return *this; + } + + /** + * A move assignment operator. Replaces the contents with those of other via move semantics. + * The other vector is left empty. + * @param[in] other The vector to move from. + * @return A reference to the current object. + */ + PointerVector& operator=(PointerVector&& other) noexcept + { + // Releases all current elements. + clear(); + // Moves the elements of the other vector. + m_Vector = std::move(other.m_Vector); + // Explicitly clear the other vector as the standard only guarantees an unspecified valid state after move. + other.m_Vector.clear(); + return *this; + } + + /** + * Clears all elements of the vector while freeing them + */ + void clear() + { + freeVectorUnsafe(m_Vector); + m_Vector.clear(); + } + + /** + * Adding a nullptr to the vector is not allowed. + */ + void pushBack(std::nullptr_t element, bool freeElementOnError = true) = delete; + + /** + * Add a new (pointer to an) element to the vector + * @param[in] element A pointer to an element to assume ownership of. + * @param[in] freeElementOnError If set to true, the element is freed if an exception is thrown during the push. + * @throws std::invalid_argument The provided pointer is a nullptr. + */ + void pushBack(T* element, bool freeElementOnError = true) + { + if (element == nullptr) + { + throw std::invalid_argument("Element is nullptr"); + } + + try + { + m_Vector.push_back(element); + } + catch (const std::exception&) + { + if (freeElementOnError) + { + delete element; + } + throw; + } + } + + /** + * Add a new element to the vector that has been managed by an unique pointer. + * @param[in] element A unique pointer holding an element. + * @throws std::invalid_argument The provided pointer is a nullptr. + * @remarks If pushBack throws the element is freed immediately. + */ + void pushBack(std::unique_ptr element) + { + if (!element) + { + throw std::invalid_argument("Element is nullptr"); + } + + // Release is called after the raw pointer is already inserted into the vector to prevent + // a memory leak if push_back throws. + // cppcheck-suppress danglingLifetime + m_Vector.push_back(element.get()); + element.release(); + } + + /** + * Get the first element of the vector + * @return An iterator object pointing to the first element of the vector + */ + VectorIterator begin() + { + return m_Vector.begin(); + } + + /** + * Get the first element of a constant vector + * @return A const iterator object pointing to the first element of the vector + */ + ConstVectorIterator begin() const + { + return m_Vector.begin(); + } + + /** + * Get the last element of the vector + * @return An iterator object pointing to the last element of the vector + */ + VectorIterator end() + { + return m_Vector.end(); + } + + /** + * Get the last element of a constant vector + * @return A const iterator object pointing to the last element of the vector + */ + ConstVectorIterator end() const + { + return m_Vector.end(); + } + + /** + * Get number of elements in the vector + * @return The number of elements in the vector + */ + size_t size() const + { + return m_Vector.size(); + } + + /** + * @return A pointer of the first element in the vector + */ + T* front() + { + return m_Vector.front(); + } + + /** + * @return A pointer to the first element in the vector + */ + T const* front() const + { + return m_Vector.front(); + } + + /** + * @return A pointer to the last element in the vector + */ + T* back() + { + return m_Vector.back(); + } + + /* + * @return A pointer to the last element in the vector. + */ + T const* back() const + { + return m_Vector.back(); + } + + /** + * Removes from the vector a single element (position). Once the element is erased, it's also freed + * @param[in] position The position of the element to erase + * @return An iterator pointing to the new location of the element that followed the last element erased by the + * function call + */ + VectorIterator erase(VectorIterator position) + { + delete (*position); + return m_Vector.erase(position); + } + + /** + * Remove an element from the vector without freeing it + * @param[in, out] position The position of the element to remove from the vector. + * The iterator is shifted to the following element after the removal is completed. + * @return A pointer to the element which is no longer managed by the vector. It's user responsibility to free + * it + * @deprecated Deprecated in favor of 'getAndDetach' as that function provides memory safety. + */ + PCPP_DEPRECATED("Please use the memory safe 'getAndDetach' instead.") + T* getAndRemoveFromVector(VectorIterator& position) + { + T* result = *position; + position = m_Vector.erase(position); + return result; + } + + /** + * Removes an element from the vector and transfers ownership to the returned unique pointer. + * @param[in] index The index of the element to detach. + * @return An unique pointer that holds ownership of the detached element. + */ + std::unique_ptr getAndDetach(size_t index) + { + return getAndDetach(m_Vector.begin() + index); + } + + /** + * Removes an element from the vector and transfers ownership to the returned unique pointer. + * @param[in, out] position An iterator pointing to the element to detach. + * The iterator is shifted to the following element after the detach completes. + * @return An unique pointer that holds ownership of the detached element. + */ + std::unique_ptr getAndDetach(VectorIterator& position) + { + std::unique_ptr result(*position); + position = m_Vector.erase(position); + return result; + } + + /** + * Removes an element from the vector and transfers ownership to the returned unique pointer. + * @param[in] position An iterator pointing to the element to detach. + * @return An unique pointer that holds ownership of the detached element. + */ + std::unique_ptr getAndDetach(VectorIterator const& position) + { + std::unique_ptr result(*position); + m_Vector.erase(position); + return result; + } + + /** + * Return a pointer to the element in a certain index + * @param[in] index The index to retrieve the element from + * @return The element at the specified position in the vector + */ + T* at(int index) + { + return m_Vector.at(index); + } + + /** + * Return a const pointer to the element in a certain index + * @param[in] index The index to retrieve the element from + * @return The element at the specified position in the vector + */ + const T* at(int index) const + { + return m_Vector.at(index); + } + + private: + /** + * Performs a copy of the vector along with its elements. + * The caller is responsible of freeing the copied elements. + * @return A vector of pointers to the newly copied elements. + */ + static std::vector deepCopyUnsafe(std::vector const& origin) + { + std::vector copyVec; + // Allocate the vector initially to ensure no exceptions are thrown during push_back. + copyVec.reserve(origin.size()); + + try + { + for (const auto iter : origin) + { + std::unique_ptr objCopy = internal::Copier()(*iter); + // There shouldn't be a memory leak as the vector is reserved. + copyVec.push_back(objCopy.release()); + } + } + catch (const std::exception&) + { + for (auto obj : copyVec) + { + delete obj; + } + throw; + } + + return copyVec; + } + + /** + * Frees all elements inside the vector. + * Calling this function with non-heap allocated pointers is UB. + * @param[in] origin The vector of elements to free. + * @remarks The vector's contents are not cleared and will point to invalid locations in memory. + */ + static void freeVectorUnsafe(std::vector const& origin) + { + for (auto& obj : origin) + { + delete obj; + } + } + + std::vector m_Vector; + }; + +} // namespace pcpp diff --git a/Common++/header/pcapplusplus/SystemUtils.h b/Common++/header/pcapplusplus/SystemUtils.h new file mode 100644 index 0000000000..c68ab8f777 --- /dev/null +++ b/Common++/header/pcapplusplus/SystemUtils.h @@ -0,0 +1,400 @@ +#pragma once + +#include +#include +#include + +/// @file + +#define MAX_NUM_OF_CORES 32 + +#ifdef _MSC_VER +int gettimeofday(struct timeval* tp, struct timezone* tzp); +#endif + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * @struct SystemCore + * Represents data of 1 CPU core. Current implementation supports up to 32 cores + */ + struct SystemCore + { + /** + * Core position in a 32-bit mask. For each core this attribute holds a 4B integer where only 1 bit is set, + * according to the core ID. For example: + * - In core #0 the right-most bit will be set (meaning the number 0x01); + * - in core #5 the 5th right-most bit will be set (meaning the number 0x20) + */ + uint32_t Mask; + + /** + * Core ID - a value between 0 and 31 + */ + uint8_t Id; + + /** + * Overload of the comparison operator + * @return true if 2 addresses are equal. False otherwise + */ + bool operator==(const SystemCore& other) const + { + return Id == other.Id; + } + }; + + /** + * @struct SystemCores + * Contains static representation to all 32 cores and a static array to map core ID (integer) to a SystemCore struct + */ + struct SystemCores + { + /** + * Static representation of core #0 + */ + static const SystemCore Core0; + /** + * Static representation of core #1 + */ + static const SystemCore Core1; + /** + * Static representation of core #2 + */ + static const SystemCore Core2; + /** + * Static representation of core #3 + */ + static const SystemCore Core3; + /** + * Static representation of core #4 + */ + static const SystemCore Core4; + /** + * Static representation of core #5 + */ + static const SystemCore Core5; + /** + * Static representation of core #6 + */ + static const SystemCore Core6; + /** + * Static representation of core #7 + */ + static const SystemCore Core7; + /** + * Static representation of core #8 + */ + static const SystemCore Core8; + /** + * Static representation of core #9 + */ + static const SystemCore Core9; + /** + * Static representation of core #10 + */ + static const SystemCore Core10; + /** + * Static representation of core #11 + */ + static const SystemCore Core11; + /** + * Static representation of core #12 + */ + static const SystemCore Core12; + /** + * Static representation of core #13 + */ + static const SystemCore Core13; + /** + * Static representation of core #14 + */ + static const SystemCore Core14; + /** + * Static representation of core #15 + */ + static const SystemCore Core15; + /** + * Static representation of core #16 + */ + static const SystemCore Core16; + /** + * Static representation of core #17 + */ + static const SystemCore Core17; + /** + * Static representation of core #18 + */ + static const SystemCore Core18; + /** + * Static representation of core #19 + */ + static const SystemCore Core19; + /** + * Static representation of core #20 + */ + static const SystemCore Core20; + /** + * Static representation of core #21 + */ + static const SystemCore Core21; + /** + * Static representation of core #22 + */ + static const SystemCore Core22; + /** + * Static representation of core #23 + */ + static const SystemCore Core23; + /** + * Static representation of core #24 + */ + static const SystemCore Core24; + /** + * Static representation of core #25 + */ + static const SystemCore Core25; + /** + * Static representation of core #26 + */ + static const SystemCore Core26; + /** + * Static representation of core #27 + */ + static const SystemCore Core27; + /** + * Static representation of core #28 + */ + static const SystemCore Core28; + /** + * Static representation of core #29 + */ + static const SystemCore Core29; + /** + * Static representation of core #30 + */ + static const SystemCore Core30; + /** + * Static representation of core #31 + */ + static const SystemCore Core31; + + /** + * A static array for mapping core ID (integer) to the corresponding static SystemCore representation + */ + static const SystemCore IdToSystemCore[MAX_NUM_OF_CORES]; + }; + + typedef uint32_t CoreMask; + + /** + * Get total number of cores on device + * @return Total number of CPU cores on device + */ + int getNumOfCores(); + + /** + * Create a core mask for all cores available on machine + * @return A core mask for all cores available on machine + */ + CoreMask getCoreMaskForAllMachineCores(); + + /** + * Create a core mask from a vector of system cores + * @param[in] cores A vector of SystemCore instances + * @return A core mask representing these cores + */ + CoreMask createCoreMaskFromCoreVector(const std::vector& cores); + + /** + * Create a core mask from a vector of core IDs + * @param[in] coreIds A vector of core IDs + * @return A core mask representing these cores + */ + CoreMask createCoreMaskFromCoreIds(const std::vector& coreIds); + + /** + * Convert a core mask into a vector of its appropriate system cores + * @param[in] coreMask The input core mask + * @param[out] resultVec The vector that will contain the system cores + */ + void createCoreVectorFromCoreMask(CoreMask coreMask, std::vector& resultVec); + + /** + * Execute a shell command and return its output + * @param[in] command The command to run + * @return The output of the command (both stdout and stderr) + * @throws std::runtime_error Error executing the command. + */ + std::string executeShellCommand(const std::string& command); + + /** + * Check if a directory exists + * @param[in] dirPath Full path of the directory to search + * @return True if directory exists, false otherwise + */ + bool directoryExists(const std::string& dirPath); + + /** + * Retrieve a system-wide real-time accurate clock. It's actually a multi-platform version of clock_gettime() which + * is fully supported only on Linux + * @param[out] sec The second portion of the time + * @param[out] nsec The nanosecond portion of the time + * @return 0 for success, or -1 for failure + */ + int clockGetTime(long& sec, long& nsec); + + /** + * A multi-platform version of the popular sleep method. This method simply runs the right sleep method, according + * to the platform it is running on. + * @param[in] seconds Number of seconds to sleep + */ + void multiPlatformSleep(uint32_t seconds); + + /** + * A multi-platform version of sleep in milliseconds resolution. This method simply runs the right sleep method, + * according to the platform it is running on. + * @param[in] milliseconds Number of milliseconds to sleep + */ + void multiPlatformMSleep(uint32_t milliseconds); + + /** + * A multi-platform version of `htons` which convert host to network byte order + * @param[in] host Value in host byte order + * @return Value in network byte order + */ + uint16_t hostToNet16(uint16_t host); + + /** + * A multi-platform version of `ntohs` which convert network to host byte order + * @param[in] net Value in network byte order + * @return Value in host byte order + */ + uint16_t netToHost16(uint16_t net); + + /** + * A multi-platform version of `htonl` which convert host to network byte order + * @param[in] host Value in host byte order + * @return Value in network byte order + */ + uint32_t hostToNet32(uint32_t host); + + /** + * A multi-platform version of `ntohl` which convert network to host byte order + * @param[in] net Value in network byte order + * @return Value in host byte order + */ + uint32_t netToHost32(uint32_t net); + + /** + * @class AppName + * This class extracts the application name from the current running executable and stores it for usage of the + * application throughout its runtime. This class should be initialized once in the beginning of the main() method + * using AppName#init() and from then on the app name could be retrieved using AppName#get() + */ + class AppName + { + private: + static std::string m_AppName; + + public: + /** + * Static init method which should be called once at the beginning of the main method. + * @param[in] argc The argc param from main() + * @param[in] argv The argv param from main() + */ + // cppcheck-suppress constParameter + static void init(int argc, char* argv[]) + { + if (argc == 0) + { + m_AppName.clear(); + return; + } + + m_AppName = argv[0]; + + // remove Linux/Unix path + size_t lastPos = m_AppName.rfind('/'); + if (lastPos != std::string::npos) + { + m_AppName = m_AppName.substr(lastPos + 1); + } + + // remove Windows path + lastPos = m_AppName.rfind('\\'); + if (lastPos != std::string::npos) + { + m_AppName = m_AppName.substr(lastPos + 1); + } + + // remove file extension + lastPos = m_AppName.rfind('.'); + if (lastPos != std::string::npos) + { + m_AppName.resize(lastPos); + } + } + + /** + * @return The app name as extracted from the current running executable + */ + static const std::string& get() + { + return m_AppName; + } + }; + + /** + * @class ApplicationEventHandler + * A singleton class that provides callbacks for events that occur during application life-cycle such as ctrl+c + * pressed, application closed, killed, etc. + */ + class ApplicationEventHandler + { + public: + /** + * @typedef EventHandlerCallback + * The callback to be invoked when the event occurs + * @param[in] cookie A pointer the the cookie provided by the user in ApplicationEventHandler c'tor + */ + typedef void (*EventHandlerCallback)(void* cookie); + + /** + * As ApplicationEventHandler is a singleton, this is the static getter to retrieve its instance + * @return The singleton instance of ApplicationEventHandler + */ + static ApplicationEventHandler& getInstance() + { + static ApplicationEventHandler instance; + return instance; + } + + /** + * Register for an application-interrupted event, meaning ctrl+c was pressed + * @param[in] handler The callback to be activated when the event occurs + * @param[in] cookie A pointer to a user provided object. This object will be transferred to the + * EventHandlerCallback callback. This cookie is very useful for transferring objects that give context to the + * event callback + */ + void onApplicationInterrupted(EventHandlerCallback handler, void* cookie); + + private: + EventHandlerCallback m_ApplicationInterruptedHandler; + void* m_ApplicationInterruptedCookie; + + // private c'tor + ApplicationEventHandler(); + +#if defined(_WIN32) + static int handlerRoutine(unsigned long fdwCtrlType); +#else + static void handlerRoutine(int signum); +#endif + }; + +} // namespace pcpp diff --git a/Common++/header/pcapplusplus/TablePrinter.h b/Common++/header/pcapplusplus/TablePrinter.h new file mode 100644 index 0000000000..d34ec0df51 --- /dev/null +++ b/Common++/header/pcapplusplus/TablePrinter.h @@ -0,0 +1,73 @@ +#pragma once + +#include + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + /** + * A class for printing tables in command-line + */ + class TablePrinter + { + public: + /** + * C'tor - get column names and column widths + * @param[in] columnNames A vector of strings containing column names + * @param[in] columnWidths A vector of integers containing column widths + */ + TablePrinter(std::vector columnNames, std::vector columnWidths); + + /** + * A d'tor for this class. Closes the table if not closed + */ + virtual ~TablePrinter(); + + /** + * Print a single row by providing a single string containing all values delimited by a specified character. + * For example: if specified delimiter is '|' and there are 3 columns an example input can be: + * "value for column1|value for column2|value for column3" + * @param[in] values A string delimited by a specified delimiter that contains values for all columns + * @param[in] delimiter A delimiter that separates between values of different columns in the values string + * @return True if row was printed successfully or false otherwise (in any case of error an appropriate message + * will be printed to log) + */ + bool printRow(const std::string& values, char delimiter); + + /** + * Print a single row + * @param[in] values A vector of strings containing values for all columns + * @return True if row was printed successfully or false otherwise (in any case of error an appropriate message + * will be printed to log) + */ + bool printRow(std::vector values); + + /** + * Print a separator line + */ + void printSeparator(); + + /** + * Close the table - should be called after all rows were printed. Calling this method is not a must as it's + * called in the class d'tor + */ + void closeTable(); + + private: + std::vector m_ColumnNames; + std::vector m_ColumnWidths; + bool m_FirstRow; + bool m_TableClosed; + + /** + * Print the table headline + */ + void printHeadline(); + }; + +} // namespace pcpp diff --git a/Common++/header/pcapplusplus/TimespecTimeval.h b/Common++/header/pcapplusplus/TimespecTimeval.h new file mode 100644 index 0000000000..52c291778d --- /dev/null +++ b/Common++/header/pcapplusplus/TimespecTimeval.h @@ -0,0 +1,19 @@ +/// these conversion macros are not defined on some of the platforms, including +/// Windows +#pragma once + +#ifndef TIMEVAL_TO_TIMESPEC +# define TIMEVAL_TO_TIMESPEC(tv, ts) \ + { \ + (ts)->tv_sec = (tv)->tv_sec; \ + (ts)->tv_nsec = (tv)->tv_usec * 1000; \ + } +#endif + +#ifndef TIMESPEC_TO_TIMEVAL +# define TIMESPEC_TO_TIMEVAL(tv, ts) \ + { \ + (tv)->tv_sec = (ts)->tv_sec; \ + (tv)->tv_usec = (ts)->tv_nsec / 1000; \ + } +#endif diff --git a/Common++/src/GeneralUtils.cpp b/Common++/src/GeneralUtils.cpp index 51c6c50c07..ab13770a37 100644 --- a/Common++/src/GeneralUtils.cpp +++ b/Common++/src/GeneralUtils.cpp @@ -1,7 +1,7 @@ #define LOG_MODULE CommonLogModuleGenericUtils -#include "GeneralUtils.h" -#include "Logger.h" +#include "pcapplusplus/GeneralUtils.h" +#include "pcapplusplus/Logger.h" #include #include #include diff --git a/Common++/src/IpAddress.cpp b/Common++/src/IpAddress.cpp index 2c2f439361..1564b20f7e 100644 --- a/Common++/src/IpAddress.cpp +++ b/Common++/src/IpAddress.cpp @@ -7,9 +7,9 @@ #include #include #include -#include "Logger.h" -#include "IpUtils.h" -#include "IpAddress.h" +#include "pcapplusplus/Logger.h" +#include "pcapplusplus/IpUtils.h" +#include "pcapplusplus/IpAddress.h" #include "EndianPortable.h" // for AF_INET, AF_INET6 diff --git a/Common++/src/IpAddressUtils.cpp b/Common++/src/IpAddressUtils.cpp index a65941cbf5..f8eeebe58b 100644 --- a/Common++/src/IpAddressUtils.cpp +++ b/Common++/src/IpAddressUtils.cpp @@ -1,7 +1,7 @@ -#include "IpAddressUtils.h" +#include "pcapplusplus/IpAddressUtils.h" -#include "IpAddress.h" -#include "IpUtils.h" // Just needing in_addr and in6_addr. +#include "pcapplusplus/IpAddress.h" +#include "pcapplusplus/IpUtils.h" // Just needing in_addr and in6_addr. namespace pcpp { diff --git a/Common++/src/IpUtils.cpp b/Common++/src/IpUtils.cpp index bd8d8d7ad5..147e68e5ef 100644 --- a/Common++/src/IpUtils.cpp +++ b/Common++/src/IpUtils.cpp @@ -1,7 +1,7 @@ #define LOG_MODULE CommonLogModuleIpUtils -#include "IpUtils.h" -#include "Logger.h" +#include "pcapplusplus/IpUtils.h" +#include "pcapplusplus/Logger.h" #include #include #include diff --git a/Common++/src/Logger.cpp b/Common++/src/Logger.cpp index 7608911b6b..aa9846a21c 100644 --- a/Common++/src/Logger.cpp +++ b/Common++/src/Logger.cpp @@ -1,5 +1,5 @@ #include -#include "Logger.h" +#include "pcapplusplus/Logger.h" namespace pcpp { diff --git a/Common++/src/MacAddress.cpp b/Common++/src/MacAddress.cpp index f9fcc9bcc1..55ea3ee822 100644 --- a/Common++/src/MacAddress.cpp +++ b/Common++/src/MacAddress.cpp @@ -1,6 +1,6 @@ #include -#include "MacAddress.h" +#include "pcapplusplus/MacAddress.h" namespace pcpp { diff --git a/Common++/src/OUILookup.cpp b/Common++/src/OUILookup.cpp index d116ee8388..2280134135 100644 --- a/Common++/src/OUILookup.cpp +++ b/Common++/src/OUILookup.cpp @@ -1,7 +1,7 @@ -#include "OUILookup.h" -#include "Logger.h" +#include "pcapplusplus/OUILookup.h" +#include "pcapplusplus/Logger.h" -#include "json.hpp" +#include #include diff --git a/Common++/src/PcapPlusPlusVersion.cpp b/Common++/src/PcapPlusPlusVersion.cpp index 16f0ca3b95..11e435dd32 100644 --- a/Common++/src/PcapPlusPlusVersion.cpp +++ b/Common++/src/PcapPlusPlusVersion.cpp @@ -1,4 +1,4 @@ -#include "PcapPlusPlusVersion.h" +#include "pcapplusplus/PcapPlusPlusVersion.h" namespace pcpp { diff --git a/Common++/src/SystemUtils.cpp b/Common++/src/SystemUtils.cpp index 702d8b801a..017454e9c4 100644 --- a/Common++/src/SystemUtils.cpp +++ b/Common++/src/SystemUtils.cpp @@ -1,4 +1,4 @@ -#include "SystemUtils.h" +#include "pcapplusplus/SystemUtils.h" #include "EndianPortable.h" #ifndef _MSC_VER diff --git a/Common++/src/TablePrinter.cpp b/Common++/src/TablePrinter.cpp index 8c424cd000..355f97eade 100644 --- a/Common++/src/TablePrinter.cpp +++ b/Common++/src/TablePrinter.cpp @@ -6,8 +6,8 @@ #include #include #include -#include "TablePrinter.h" -#include "Logger.h" +#include "pcapplusplus/TablePrinter.h" +#include "pcapplusplus/Logger.h" namespace pcpp { diff --git a/Examples/ArpSpoofing/main.cpp b/Examples/ArpSpoofing/main.cpp index d25e1a6eb3..31face0a62 100644 --- a/Examples/ArpSpoofing/main.cpp +++ b/Examples/ArpSpoofing/main.cpp @@ -3,15 +3,17 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include #define EXIT_WITH_ERROR(reason) \ diff --git a/Examples/Arping/main.cpp b/Examples/Arping/main.cpp index 919e3d42f0..ec19d5393c 100644 --- a/Examples/Arping/main.cpp +++ b/Examples/Arping/main.cpp @@ -7,15 +7,15 @@ #include #include -#include -#include -#include -#include -#include -#include -#include #include -#include +#include +#include +#include +#include +#include +#include +#include +#include #define EXIT_WITH_ERROR(reason) \ do \ diff --git a/Examples/DNSResolver/main.cpp b/Examples/DNSResolver/main.cpp index f29f1e894d..805f834fce 100644 --- a/Examples/DNSResolver/main.cpp +++ b/Examples/DNSResolver/main.cpp @@ -1,11 +1,11 @@ #include #include -#include "PcapPlusPlusVersion.h" -#include "PcapLiveDevice.h" -#include "PcapLiveDeviceList.h" -#include "NetworkUtils.h" -#include "SystemUtils.h" -#include "Logger.h" +#include +#include +#include +#include +#include +#include #include #define EXIT_WITH_ERROR(reason) \ diff --git a/Examples/DnsSpoofing/main.cpp b/Examples/DnsSpoofing/main.cpp index 3e03c6833a..29ff606dd2 100644 --- a/Examples/DnsSpoofing/main.cpp +++ b/Examples/DnsSpoofing/main.cpp @@ -16,21 +16,21 @@ #if !defined(_WIN32) # include #endif -#include "IpAddress.h" -#include "RawPacket.h" -#include "ProtocolType.h" -#include "Packet.h" -#include "EthLayer.h" -#include "IPv4Layer.h" -#include "IPv6Layer.h" -#include "UdpLayer.h" -#include "DnsLayer.h" -#include "PcapFilter.h" -#include "PcapLiveDevice.h" -#include "PcapLiveDeviceList.h" -#include "TablePrinter.h" -#include "SystemUtils.h" -#include "PcapPlusPlusVersion.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #define EXIT_WITH_ERROR(reason) \ diff --git a/Examples/DpdkBridge/main.cpp b/Examples/DpdkBridge/main.cpp index ffebb0f48f..2eb3463710 100644 --- a/Examples/DpdkBridge/main.cpp +++ b/Examples/DpdkBridge/main.cpp @@ -23,13 +23,13 @@ #include "Common.h" #include "AppWorkerThread.h" -#include "DpdkDeviceList.h" -#include "IPv4Layer.h" -#include "TcpLayer.h" -#include "UdpLayer.h" -#include "SystemUtils.h" -#include "PcapPlusPlusVersion.h" -#include "TablePrinter.h" +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/Examples/DpdkExample-FilterTraffic/main.cpp b/Examples/DpdkExample-FilterTraffic/main.cpp index fceda082b9..0aa27ff335 100644 --- a/Examples/DpdkExample-FilterTraffic/main.cpp +++ b/Examples/DpdkExample-FilterTraffic/main.cpp @@ -24,12 +24,12 @@ #include "PacketMatchingEngine.h" #include "AppWorkerThread.h" -#include "DpdkDeviceList.h" -#include "TcpLayer.h" -#include "UdpLayer.h" -#include "SystemUtils.h" -#include "PcapPlusPlusVersion.h" -#include "TablePrinter.h" +#include +#include +#include +#include +#include +#include #include #include diff --git a/Examples/ExampleApp/main.cpp b/Examples/ExampleApp/main.cpp index 89f3bdf6d2..8cd6299a4f 100644 --- a/Examples/ExampleApp/main.cpp +++ b/Examples/ExampleApp/main.cpp @@ -1,7 +1,7 @@ #include -#include -#include -#include +#include +#include +#include int main(int argc, char* argv[]) { diff --git a/Examples/HttpAnalyzer/HttpStatsCollector.h b/Examples/HttpAnalyzer/HttpStatsCollector.h index 42cfa5c09c..e617134bbb 100644 --- a/Examples/HttpAnalyzer/HttpStatsCollector.h +++ b/Examples/HttpAnalyzer/HttpStatsCollector.h @@ -4,12 +4,12 @@ #include #include -#include "HttpLayer.h" -#include "TcpLayer.h" -#include "IPv4Layer.h" -#include "PayloadLayer.h" -#include "PacketUtils.h" -#include "SystemUtils.h" +#include "pcapplusplus/HttpLayer.h" +#include "pcapplusplus/TcpLayer.h" +#include "pcapplusplus/IPv4Layer.h" +#include "pcapplusplus/PayloadLayer.h" +#include "pcapplusplus/PacketUtils.h" +#include "pcapplusplus/SystemUtils.h" /** * An auxiliary struct for encapsulating rate stats diff --git a/Examples/HttpAnalyzer/main.cpp b/Examples/HttpAnalyzer/main.cpp index b1f6803177..266516668e 100644 --- a/Examples/HttpAnalyzer/main.cpp +++ b/Examples/HttpAnalyzer/main.cpp @@ -21,17 +21,18 @@ #include #include #include -#include "PcapLiveDeviceList.h" -#include "PcapFilter.h" -#include "PcapFileDevice.h" -#include "HttpStatsCollector.h" -#include "TablePrinter.h" -#include "SystemUtils.h" -#include "PcapPlusPlusVersion.h" +#include +#include +#include +#include +#include +#include #include #include #include +#include "HttpStatsCollector.h" + #define EXIT_WITH_ERROR(reason) \ do \ { \ diff --git a/Examples/IPDefragUtil/main.cpp b/Examples/IPDefragUtil/main.cpp index 394e87ddaf..659e1891a1 100644 --- a/Examples/IPDefragUtil/main.cpp +++ b/Examples/IPDefragUtil/main.cpp @@ -3,13 +3,13 @@ #include #include #include -#include "PcapPlusPlusVersion.h" -#include "IPv4Layer.h" -#include "IPv6Layer.h" -#include "IPReassembly.h" -#include "PcapFileDevice.h" -#include "SystemUtils.h" -#include "getopt.h" +#include +#include +#include +#include +#include +#include +#include #define EXIT_WITH_ERROR(reason) \ do \ diff --git a/Examples/IPFragUtil/main.cpp b/Examples/IPFragUtil/main.cpp index c6151ecd1c..d044cc7caf 100644 --- a/Examples/IPFragUtil/main.cpp +++ b/Examples/IPFragUtil/main.cpp @@ -4,13 +4,13 @@ #include #include #include -#include "PcapPlusPlusVersion.h" -#include "Packet.h" -#include "IPv4Layer.h" -#include "IPv6Layer.h" -#include "PayloadLayer.h" -#include "PcapFileDevice.h" -#include "SystemUtils.h" +#include "pcapplusplus/PcapPlusPlusVersion.h" +#include "pcapplusplus/Packet.h" +#include "pcapplusplus/IPv4Layer.h" +#include "pcapplusplus/IPv6Layer.h" +#include "pcapplusplus/PayloadLayer.h" +#include "pcapplusplus/PcapFileDevice.h" +#include "pcapplusplus/SystemUtils.h" #include "getopt.h" #define EXIT_WITH_ERROR(reason) \ diff --git a/Examples/IcmpFileTransfer/Common.cpp b/Examples/IcmpFileTransfer/Common.cpp index 80f080ce1d..75c9b502e8 100644 --- a/Examples/IcmpFileTransfer/Common.cpp +++ b/Examples/IcmpFileTransfer/Common.cpp @@ -3,12 +3,12 @@ #include #include #include -#include "EthLayer.h" -#include "IPv4Layer.h" -#include "IcmpLayer.h" -#include "PcapLiveDeviceList.h" -#include "SystemUtils.h" -#include "PcapPlusPlusVersion.h" +#include +#include +#include +#include +#include +#include #if defined(_WIN32) # define SEPARATOR '\\' diff --git a/Examples/IcmpFileTransfer/Common.h b/Examples/IcmpFileTransfer/Common.h index baf7c0d3e8..7631f734b5 100644 --- a/Examples/IcmpFileTransfer/Common.h +++ b/Examples/IcmpFileTransfer/Common.h @@ -1,8 +1,8 @@ #pragma once -#include "MacAddress.h" -#include "IpAddress.h" -#include "PcapLiveDevice.h" +#include "pcapplusplus/MacAddress.h" +#include "pcapplusplus/IpAddress.h" +#include "pcapplusplus/PcapLiveDevice.h" #define ICMP_FT_WAITING_FT_START 0x345a56c8e7f3cd67ULL #define ICMP_FT_START 0xd45ae6c2e7a3cd67ULL diff --git a/Examples/IcmpFileTransfer/IcmpFileTransfer-catcher.cpp b/Examples/IcmpFileTransfer/IcmpFileTransfer-catcher.cpp index a1ecd4703d..f1f5cb6c1b 100644 --- a/Examples/IcmpFileTransfer/IcmpFileTransfer-catcher.cpp +++ b/Examples/IcmpFileTransfer/IcmpFileTransfer-catcher.cpp @@ -9,14 +9,14 @@ #include #include #include -#include "EthLayer.h" -#include "IPv4Layer.h" -#include "IcmpLayer.h" -#include "Packet.h" -#include "PcapLiveDeviceList.h" -#include "PcapFilter.h" +#include "pcapplusplus/EthLayer.h" +#include "pcapplusplus/IPv4Layer.h" +#include "pcapplusplus/IcmpLayer.h" +#include "pcapplusplus/Packet.h" +#include "pcapplusplus/PcapLiveDeviceList.h" +#include "pcapplusplus/PcapFilter.h" #include "Common.h" -#include "SystemUtils.h" +#include "pcapplusplus/SystemUtils.h" /** * A struct used for starting a file transfer, mainly sending or getting the file name diff --git a/Examples/IcmpFileTransfer/IcmpFileTransfer-pitcher.cpp b/Examples/IcmpFileTransfer/IcmpFileTransfer-pitcher.cpp index 800e86d03b..066025617f 100644 --- a/Examples/IcmpFileTransfer/IcmpFileTransfer-pitcher.cpp +++ b/Examples/IcmpFileTransfer/IcmpFileTransfer-pitcher.cpp @@ -11,16 +11,16 @@ #include #include #ifndef _MSC_VER -# include "unistd.h" +# include #endif -#include "EthLayer.h" -#include "IPv4Layer.h" -#include "IcmpLayer.h" -#include "Packet.h" -#include "PcapLiveDeviceList.h" -#include "NetworkUtils.h" +#include "pcapplusplus/EthLayer.h" +#include "pcapplusplus/IPv4Layer.h" +#include "pcapplusplus/IcmpLayer.h" +#include "pcapplusplus/Packet.h" +#include "pcapplusplus/PcapLiveDeviceList.h" +#include "pcapplusplus/NetworkUtils.h" #include "Common.h" -#include "SystemUtils.h" +#include "pcapplusplus/SystemUtils.h" #define SEND_TIMEOUT_BEFORE_FT_START 3 diff --git a/Examples/KniPong/main.cpp b/Examples/KniPong/main.cpp index 9de1bb2d6f..d8daf6f51a 100644 --- a/Examples/KniPong/main.cpp +++ b/Examples/KniPong/main.cpp @@ -16,19 +16,19 @@ #include #include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include #define EXIT_WITH_ERROR(reason) \ do \ diff --git a/Examples/PcapPlusPlus-benchmark/benchmark.cpp b/Examples/PcapPlusPlus-benchmark/benchmark.cpp index 96c77ca63f..c28a8d0e1e 100644 --- a/Examples/PcapPlusPlus-benchmark/benchmark.cpp +++ b/Examples/PcapPlusPlus-benchmark/benchmark.cpp @@ -14,9 +14,9 @@ * `./benchmark.sh libpcap PcapPlusPlus libtins libcrafter` */ -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/Examples/PcapPrinter/main.cpp b/Examples/PcapPrinter/main.cpp index 76add37598..d28c92e4e9 100644 --- a/Examples/PcapPrinter/main.cpp +++ b/Examples/PcapPrinter/main.cpp @@ -14,11 +14,11 @@ #include #include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include static struct option PcapPrinterOptions[] = { diff --git a/Examples/PcapSearch/main.cpp b/Examples/PcapSearch/main.cpp index 397725837a..3d59431332 100644 --- a/Examples/PcapSearch/main.cpp +++ b/Examples/PcapSearch/main.cpp @@ -38,12 +38,12 @@ #include #include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include // clang-format off diff --git a/Examples/PcapSplitter/IPPortSplitters.h b/Examples/PcapSplitter/IPPortSplitters.h index 1493d7571b..13535d0a49 100644 --- a/Examples/PcapSplitter/IPPortSplitters.h +++ b/Examples/PcapSplitter/IPPortSplitters.h @@ -1,8 +1,8 @@ #pragma once #include "Splitters.h" -#include "PacketUtils.h" -#include "SystemUtils.h" +#include "pcapplusplus/PacketUtils.h" +#include "pcapplusplus/SystemUtils.h" /** * A virtual abstract class for all splitters that split files by IP address or TCP/UDP port. Inherits from diff --git a/Examples/PcapSplitter/SimpleSplitters.h b/Examples/PcapSplitter/SimpleSplitters.h index e05abcb575..9d42c8af5a 100644 --- a/Examples/PcapSplitter/SimpleSplitters.h +++ b/Examples/PcapSplitter/SimpleSplitters.h @@ -1,8 +1,8 @@ #pragma once #include "Splitters.h" -#include "PcapDevice.h" -#include "PcapFilter.h" +#include +#include /** * Splits a pcap file by number of packets diff --git a/Examples/PcapSplitter/Splitters.h b/Examples/PcapSplitter/Splitters.h index c6c43c30a0..591a640bbb 100644 --- a/Examples/PcapSplitter/Splitters.h +++ b/Examples/PcapSplitter/Splitters.h @@ -1,14 +1,14 @@ #pragma once -#include "LRUList.h" -#include "RawPacket.h" -#include "Packet.h" -#include "IPv4Layer.h" -#include "IPv6Layer.h" -#include "TcpLayer.h" -#include "UdpLayer.h" -#include "DnsLayer.h" -#include "PacketUtils.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/Examples/PcapSplitter/main.cpp b/Examples/PcapSplitter/main.cpp index 9607191db9..b19456496f 100644 --- a/Examples/PcapSplitter/main.cpp +++ b/Examples/PcapSplitter/main.cpp @@ -51,15 +51,15 @@ #include #include #include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include "SimpleSplitters.h" #include "IPPortSplitters.h" #include "ConnectionSplitters.h" -#include -#include -#include static struct option PcapSplitterOptions[] = { { "input-file", required_argument, nullptr, 'f' }, diff --git a/Examples/PfRingExample-FilterTraffic/Common.h b/Examples/PfRingExample-FilterTraffic/Common.h index 587c4916d7..7f630be050 100644 --- a/Examples/PfRingExample-FilterTraffic/Common.h +++ b/Examples/PfRingExample-FilterTraffic/Common.h @@ -1,9 +1,9 @@ #pragma once -#include -#include +#include +#include -#include +#include #include #include diff --git a/Examples/PfRingExample-FilterTraffic/PacketMatchingEngine.h b/Examples/PfRingExample-FilterTraffic/PacketMatchingEngine.h index 1a74629640..1b5141e564 100644 --- a/Examples/PfRingExample-FilterTraffic/PacketMatchingEngine.h +++ b/Examples/PfRingExample-FilterTraffic/PacketMatchingEngine.h @@ -1,10 +1,10 @@ #pragma once -#include "SystemUtils.h" -#include "Packet.h" -#include "IPv4Layer.h" -#include "TcpLayer.h" -#include "UdpLayer.h" +#include +#include +#include +#include +#include /** * Responsible for matching packets by match criteria received from the user. Current match criteria are a combination diff --git a/Examples/PfRingExample-FilterTraffic/main.cpp b/Examples/PfRingExample-FilterTraffic/main.cpp index 300ddd09c0..5001f7da66 100644 --- a/Examples/PfRingExample-FilterTraffic/main.cpp +++ b/Examples/PfRingExample-FilterTraffic/main.cpp @@ -32,13 +32,13 @@ #include "Common.h" #include "PacketMatchingEngine.h" -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/Examples/SSLAnalyzer/SSLStatsCollector.h b/Examples/SSLAnalyzer/SSLStatsCollector.h index bac5d0f050..7abee72ffb 100644 --- a/Examples/SSLAnalyzer/SSLStatsCollector.h +++ b/Examples/SSLAnalyzer/SSLStatsCollector.h @@ -2,12 +2,12 @@ #include #include -#include "TcpLayer.h" -#include "IPv4Layer.h" -#include "PayloadLayer.h" -#include "PacketUtils.h" -#include "SSLLayer.h" -#include "SystemUtils.h" +#include +#include +#include +#include +#include +#include /** * An auxiliary struct for encapsulating rate stats diff --git a/Examples/SSLAnalyzer/main.cpp b/Examples/SSLAnalyzer/main.cpp index bbc6941cbe..88ce5bba55 100644 --- a/Examples/SSLAnalyzer/main.cpp +++ b/Examples/SSLAnalyzer/main.cpp @@ -22,15 +22,16 @@ #include #include #include -#include "PcapLiveDeviceList.h" -#include "PcapFilter.h" -#include "PcapFileDevice.h" -#include "SSLStatsCollector.h" -#include "TablePrinter.h" -#include "SystemUtils.h" -#include "PcapPlusPlusVersion.h" +#include +#include +#include +#include +#include +#include #include +#include "SSLStatsCollector.h" + #define EXIT_WITH_ERROR(reason) \ do \ { \ diff --git a/Examples/TLSFingerprinting/main.cpp b/Examples/TLSFingerprinting/main.cpp index 87acfa5af0..e0d6a74486 100644 --- a/Examples/TLSFingerprinting/main.cpp +++ b/Examples/TLSFingerprinting/main.cpp @@ -15,15 +15,15 @@ #include #include #include -#include "SystemUtils.h" -#include "TablePrinter.h" -#include "IPLayer.h" -#include "TcpLayer.h" -#include "SSLLayer.h" -#include "SSLHandshake.h" -#include "PcapPlusPlusVersion.h" -#include "PcapLiveDeviceList.h" -#include "PcapFileDevice.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include #include static struct option TLSFingerprintingOptions[] = { diff --git a/Examples/TcpReassembly/main.cpp b/Examples/TcpReassembly/main.cpp index 8a19f86e60..eb41a4f1d1 100644 --- a/Examples/TcpReassembly/main.cpp +++ b/Examples/TcpReassembly/main.cpp @@ -28,12 +28,12 @@ #include #include #include -#include "TcpReassembly.h" -#include "PcapLiveDeviceList.h" -#include "PcapFileDevice.h" -#include "SystemUtils.h" -#include "PcapPlusPlusVersion.h" -#include "LRUList.h" +#include +#include +#include +#include +#include +#include #include #define EXIT_WITH_ERROR(reason) \ diff --git a/Examples/Tutorials/Tutorial-DpdkL2Fwd/WorkerThread.h b/Examples/Tutorials/Tutorial-DpdkL2Fwd/WorkerThread.h index aff9e96933..35ddc452a7 100644 --- a/Examples/Tutorials/Tutorial-DpdkL2Fwd/WorkerThread.h +++ b/Examples/Tutorials/Tutorial-DpdkL2Fwd/WorkerThread.h @@ -1,7 +1,7 @@ #pragma once -#include "DpdkDevice.h" -#include "DpdkDeviceList.h" +#include +#include class L2FwdWorkerThread : public pcpp::DpdkWorkerThread { diff --git a/Examples/Tutorials/Tutorial-DpdkL2Fwd/main.cpp b/Examples/Tutorials/Tutorial-DpdkL2Fwd/main.cpp index 59459614f6..0381aff5b7 100644 --- a/Examples/Tutorials/Tutorial-DpdkL2Fwd/main.cpp +++ b/Examples/Tutorials/Tutorial-DpdkL2Fwd/main.cpp @@ -1,9 +1,10 @@ #include #include #include -#include "SystemUtils.h" -#include "DpdkDeviceList.h" -#include "TablePrinter.h" +#include +#include +#include + #include "WorkerThread.h" #define MBUF_POOL_SIZE 16 * 1024 - 1 diff --git a/Examples/Tutorials/Tutorial-HelloWorld/main.cpp b/Examples/Tutorials/Tutorial-HelloWorld/main.cpp index 89f3bdf6d2..8cd6299a4f 100644 --- a/Examples/Tutorials/Tutorial-HelloWorld/main.cpp +++ b/Examples/Tutorials/Tutorial-HelloWorld/main.cpp @@ -1,7 +1,7 @@ #include -#include -#include -#include +#include +#include +#include int main(int argc, char* argv[]) { diff --git a/Examples/Tutorials/Tutorial-LiveTraffic/main.cpp b/Examples/Tutorials/Tutorial-LiveTraffic/main.cpp index 38d0d433da..9061e03154 100644 --- a/Examples/Tutorials/Tutorial-LiveTraffic/main.cpp +++ b/Examples/Tutorials/Tutorial-LiveTraffic/main.cpp @@ -1,8 +1,8 @@ #include #include -#include "stdlib.h" -#include "PcapLiveDeviceList.h" -#include "SystemUtils.h" +#include +#include +#include /** * A struct for collecting packet statistics */ diff --git a/Packet++/CMakeLists.txt b/Packet++/CMakeLists.txt index d493e01885..f154da73f4 100644 --- a/Packet++/CMakeLists.txt +++ b/Packet++/CMakeLists.txt @@ -68,72 +68,72 @@ add_library( ) set(public_headers - header/ArpLayer.h - header/Asn1Codec.h - header/BgpLayer.h - header/CotpLayer.h - header/DhcpLayer.h - header/DhcpV6Layer.h - header/DnsLayerEnums.h - header/DnsLayer.h - header/DnsResourceData.h - header/DnsResource.h - header/EthDot3Layer.h - header/EthLayer.h - header/FtpLayer.h - header/GreLayer.h - header/GtpLayer.h - header/HttpLayer.h - header/IcmpLayer.h - header/IcmpV6Layer.h - header/IgmpLayer.h - header/IPLayer.h - header/IPReassembly.h - header/IPSecLayer.h - header/IPv4Layer.h - header/IPv6Extensions.h - header/IPv6Layer.h - header/Layer.h - header/LdapLayer.h - header/LLCLayer.h - header/MplsLayer.h - header/NullLoopbackLayer.h - header/NdpLayer.h - header/NflogLayer.h - header/NtpLayer.h - header/Packet.h - header/PacketTrailerLayer.h - header/PacketUtils.h - header/PayloadLayer.h - header/PPPoELayer.h - header/ProtocolType.h - header/RadiusLayer.h - header/RawPacket.h - header/S7CommLayer.h - header/SdpLayer.h - header/SingleCommandTextProtocol.h - header/SipLayer.h - header/SllLayer.h - header/Sll2Layer.h - header/SmtpLayer.h - header/SomeIpLayer.h - header/SomeIpSdLayer.h - header/SSHLayer.h - header/SSLCommon.h - header/SSLHandshake.h - header/SSLLayer.h - header/StpLayer.h - header/TcpLayer.h - header/TcpReassembly.h - header/TelnetLayer.h - header/TextBasedProtocol.h - header/TLVData.h - header/TpktLayer.h - header/UdpLayer.h - header/VlanLayer.h - header/VrrpLayer.h - header/VxlanLayer.h - header/WakeOnLanLayer.h) + header/pcapplusplus/ArpLayer.h + header/pcapplusplus/Asn1Codec.h + header/pcapplusplus/BgpLayer.h + header/pcapplusplus/CotpLayer.h + header/pcapplusplus/DhcpLayer.h + header/pcapplusplus/DhcpV6Layer.h + header/pcapplusplus/DnsLayerEnums.h + header/pcapplusplus/DnsLayer.h + header/pcapplusplus/DnsResourceData.h + header/pcapplusplus/DnsResource.h + header/pcapplusplus/EthDot3Layer.h + header/pcapplusplus/EthLayer.h + header/pcapplusplus/FtpLayer.h + header/pcapplusplus/GreLayer.h + header/pcapplusplus/GtpLayer.h + header/pcapplusplus/HttpLayer.h + header/pcapplusplus/IcmpLayer.h + header/pcapplusplus/IcmpV6Layer.h + header/pcapplusplus/IgmpLayer.h + header/pcapplusplus/IPLayer.h + header/pcapplusplus/IPReassembly.h + header/pcapplusplus/IPSecLayer.h + header/pcapplusplus/IPv4Layer.h + header/pcapplusplus/IPv6Extensions.h + header/pcapplusplus/IPv6Layer.h + header/pcapplusplus/Layer.h + header/pcapplusplus/LdapLayer.h + header/pcapplusplus/LLCLayer.h + header/pcapplusplus/MplsLayer.h + header/pcapplusplus/NullLoopbackLayer.h + header/pcapplusplus/NdpLayer.h + header/pcapplusplus/NflogLayer.h + header/pcapplusplus/NtpLayer.h + header/pcapplusplus/Packet.h + header/pcapplusplus/PacketTrailerLayer.h + header/pcapplusplus/PacketUtils.h + header/pcapplusplus/PayloadLayer.h + header/pcapplusplus/PPPoELayer.h + header/pcapplusplus/ProtocolType.h + header/pcapplusplus/RadiusLayer.h + header/pcapplusplus/RawPacket.h + header/pcapplusplus/S7CommLayer.h + header/pcapplusplus/SdpLayer.h + header/pcapplusplus/SingleCommandTextProtocol.h + header/pcapplusplus/SipLayer.h + header/pcapplusplus/SllLayer.h + header/pcapplusplus/Sll2Layer.h + header/pcapplusplus/SmtpLayer.h + header/pcapplusplus/SomeIpLayer.h + header/pcapplusplus/SomeIpSdLayer.h + header/pcapplusplus/SSHLayer.h + header/pcapplusplus/SSLCommon.h + header/pcapplusplus/SSLHandshake.h + header/pcapplusplus/SSLLayer.h + header/pcapplusplus/StpLayer.h + header/pcapplusplus/TcpLayer.h + header/pcapplusplus/TcpReassembly.h + header/pcapplusplus/TelnetLayer.h + header/pcapplusplus/TextBasedProtocol.h + header/pcapplusplus/TLVData.h + header/pcapplusplus/TpktLayer.h + header/pcapplusplus/UdpLayer.h + header/pcapplusplus/VlanLayer.h + header/pcapplusplus/VrrpLayer.h + header/pcapplusplus/VxlanLayer.h + header/pcapplusplus/WakeOnLanLayer.h) # Don't use set_target_properties CMake limit to 50 elements set_property(TARGET Packet++ PROPERTY PUBLIC_HEADER ${public_headers}) diff --git a/Packet++/header/ArpLayer.h b/Packet++/header/pcapPlusPlus/ArpLayer.h similarity index 97% rename from Packet++/header/ArpLayer.h rename to Packet++/header/pcapPlusPlus/ArpLayer.h index a42db6270c..5634d0196c 100644 --- a/Packet++/header/ArpLayer.h +++ b/Packet++/header/pcapPlusPlus/ArpLayer.h @@ -1,8 +1,8 @@ #pragma once -#include "Layer.h" -#include "IpAddress.h" -#include "MacAddress.h" +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/IpAddress.h" +#include "pcapplusplus/MacAddress.h" /// @file diff --git a/Packet++/header/Asn1Codec.h b/Packet++/header/pcapPlusPlus/Asn1Codec.h similarity index 99% rename from Packet++/header/Asn1Codec.h rename to Packet++/header/pcapPlusPlus/Asn1Codec.h index 7b5bffef97..de7796739f 100644 --- a/Packet++/header/Asn1Codec.h +++ b/Packet++/header/pcapPlusPlus/Asn1Codec.h @@ -4,7 +4,7 @@ #include #include #include -#include "PointerVector.h" +#include "pcapplusplus/PointerVector.h" /// @file diff --git a/Packet++/header/BgpLayer.h b/Packet++/header/pcapPlusPlus/BgpLayer.h similarity index 99% rename from Packet++/header/BgpLayer.h rename to Packet++/header/pcapPlusPlus/BgpLayer.h index 979af7469a..b1e0e42a75 100644 --- a/Packet++/header/BgpLayer.h +++ b/Packet++/header/pcapPlusPlus/BgpLayer.h @@ -1,8 +1,8 @@ #pragma once #include -#include "Layer.h" -#include "IpAddress.h" +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/IpAddress.h" /** * @file diff --git a/Packet++/header/CotpLayer.h b/Packet++/header/pcapPlusPlus/CotpLayer.h similarity index 97% rename from Packet++/header/CotpLayer.h rename to Packet++/header/pcapPlusPlus/CotpLayer.h index 5412a2c312..810f7ec629 100644 --- a/Packet++/header/CotpLayer.h +++ b/Packet++/header/pcapPlusPlus/CotpLayer.h @@ -1,7 +1,7 @@ #pragma once -#include "EthLayer.h" -#include "Layer.h" +#include "pcapplusplus/EthLayer.h" +#include "pcapplusplus/Layer.h" namespace pcpp { diff --git a/Packet++/header/DhcpLayer.h b/Packet++/header/pcapPlusPlus/DhcpLayer.h similarity index 99% rename from Packet++/header/DhcpLayer.h rename to Packet++/header/pcapPlusPlus/DhcpLayer.h index 435becbdbc..98601f745a 100644 --- a/Packet++/header/DhcpLayer.h +++ b/Packet++/header/pcapPlusPlus/DhcpLayer.h @@ -1,9 +1,9 @@ #pragma once -#include "Layer.h" -#include "TLVData.h" -#include "IpAddress.h" -#include "MacAddress.h" +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/TLVData.h" +#include "pcapplusplus/IpAddress.h" +#include "pcapplusplus/MacAddress.h" #include /// @file diff --git a/Packet++/header/DhcpV6Layer.h b/Packet++/header/pcapPlusPlus/DhcpV6Layer.h similarity index 99% rename from Packet++/header/DhcpV6Layer.h rename to Packet++/header/pcapPlusPlus/DhcpV6Layer.h index 57e0edb5fc..7b2563b863 100644 --- a/Packet++/header/DhcpV6Layer.h +++ b/Packet++/header/pcapPlusPlus/DhcpV6Layer.h @@ -1,7 +1,7 @@ #pragma once -#include "Layer.h" -#include "TLVData.h" +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/TLVData.h" /// @file diff --git a/Packet++/header/DnsLayer.h b/Packet++/header/pcapPlusPlus/DnsLayer.h similarity index 99% rename from Packet++/header/DnsLayer.h rename to Packet++/header/pcapPlusPlus/DnsLayer.h index 06819a791a..1b5b28249e 100644 --- a/Packet++/header/DnsLayer.h +++ b/Packet++/header/pcapPlusPlus/DnsLayer.h @@ -1,9 +1,9 @@ #pragma once -#include "DnsLayerEnums.h" -#include "DnsResource.h" -#include "DnsResourceData.h" -#include "Layer.h" +#include "pcapplusplus/DnsLayerEnums.h" +#include "pcapplusplus/DnsResource.h" +#include "pcapplusplus/DnsResourceData.h" +#include "pcapplusplus/Layer.h" /// @file diff --git a/Packet++/header/DnsLayerEnums.h b/Packet++/header/pcapPlusPlus/DnsLayerEnums.h similarity index 100% rename from Packet++/header/DnsLayerEnums.h rename to Packet++/header/pcapPlusPlus/DnsLayerEnums.h diff --git a/Packet++/header/DnsResource.h b/Packet++/header/pcapPlusPlus/DnsResource.h similarity index 98% rename from Packet++/header/DnsResource.h rename to Packet++/header/pcapPlusPlus/DnsResource.h index af34fe621f..6c37fabddd 100644 --- a/Packet++/header/DnsResource.h +++ b/Packet++/header/pcapPlusPlus/DnsResource.h @@ -1,8 +1,8 @@ #pragma once -#include "DnsLayer.h" -#include "DnsLayerEnums.h" -#include "DnsResourceData.h" +#include "pcapplusplus/DnsLayer.h" +#include "pcapplusplus/DnsLayerEnums.h" +#include "pcapplusplus/DnsResourceData.h" #include #include #include diff --git a/Packet++/header/DnsResourceData.h b/Packet++/header/pcapPlusPlus/DnsResourceData.h similarity index 99% rename from Packet++/header/DnsResourceData.h rename to Packet++/header/pcapPlusPlus/DnsResourceData.h index 990990a29b..f4a8b96e6a 100644 --- a/Packet++/header/DnsResourceData.h +++ b/Packet++/header/pcapPlusPlus/DnsResourceData.h @@ -1,7 +1,7 @@ #pragma once -#include "DnsResource.h" -#include "IpAddress.h" +#include "pcapplusplus/DnsResource.h" +#include "pcapplusplus/IpAddress.h" #include #include #include diff --git a/Packet++/header/EthDot3Layer.h b/Packet++/header/pcapPlusPlus/EthDot3Layer.h similarity index 98% rename from Packet++/header/EthDot3Layer.h rename to Packet++/header/pcapPlusPlus/EthDot3Layer.h index 44a987accc..59b4ade1a7 100644 --- a/Packet++/header/EthDot3Layer.h +++ b/Packet++/header/pcapPlusPlus/EthDot3Layer.h @@ -1,7 +1,7 @@ #pragma once -#include "Layer.h" -#include "MacAddress.h" +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/MacAddress.h" /// @file diff --git a/Packet++/header/EthLayer.h b/Packet++/header/pcapPlusPlus/EthLayer.h similarity index 98% rename from Packet++/header/EthLayer.h rename to Packet++/header/pcapPlusPlus/EthLayer.h index 0192a5e44e..a3d6073a6a 100644 --- a/Packet++/header/EthLayer.h +++ b/Packet++/header/pcapPlusPlus/EthLayer.h @@ -1,7 +1,7 @@ #pragma once -#include "Layer.h" -#include "MacAddress.h" +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/MacAddress.h" /// @file diff --git a/Packet++/header/FtpLayer.h b/Packet++/header/pcapPlusPlus/FtpLayer.h similarity index 99% rename from Packet++/header/FtpLayer.h rename to Packet++/header/pcapPlusPlus/FtpLayer.h index fc5863861f..599f327b2c 100644 --- a/Packet++/header/FtpLayer.h +++ b/Packet++/header/pcapPlusPlus/FtpLayer.h @@ -1,7 +1,7 @@ #pragma once -#include "SingleCommandTextProtocol.h" -#include "PayloadLayer.h" +#include "pcapplusplus/SingleCommandTextProtocol.h" +#include "pcapplusplus/PayloadLayer.h" /// @file diff --git a/Packet++/header/GreLayer.h b/Packet++/header/pcapPlusPlus/GreLayer.h similarity index 99% rename from Packet++/header/GreLayer.h rename to Packet++/header/pcapPlusPlus/GreLayer.h index d6793cba3d..5ec057f418 100644 --- a/Packet++/header/GreLayer.h +++ b/Packet++/header/pcapPlusPlus/GreLayer.h @@ -1,6 +1,6 @@ #pragma once -#include "Layer.h" +#include "pcapplusplus/Layer.h" /// @file diff --git a/Packet++/header/GtpLayer.h b/Packet++/header/pcapPlusPlus/GtpLayer.h similarity index 99% rename from Packet++/header/GtpLayer.h rename to Packet++/header/pcapPlusPlus/GtpLayer.h index a860f1ecf4..019fde1079 100644 --- a/Packet++/header/GtpLayer.h +++ b/Packet++/header/pcapPlusPlus/GtpLayer.h @@ -1,6 +1,6 @@ #pragma once -#include "Layer.h" +#include "pcapplusplus/Layer.h" /// @file diff --git a/Packet++/header/HttpLayer.h b/Packet++/header/pcapPlusPlus/HttpLayer.h similarity index 99% rename from Packet++/header/HttpLayer.h rename to Packet++/header/pcapPlusPlus/HttpLayer.h index 3716c7b598..a9e5f61018 100644 --- a/Packet++/header/HttpLayer.h +++ b/Packet++/header/pcapPlusPlus/HttpLayer.h @@ -1,7 +1,7 @@ #pragma once -#include "DeprecationUtils.h" -#include "TextBasedProtocol.h" +#include "pcapplusplus/DeprecationUtils.h" +#include "pcapplusplus/TextBasedProtocol.h" #include #include diff --git a/Packet++/header/IPLayer.h b/Packet++/header/pcapPlusPlus/IPLayer.h similarity index 93% rename from Packet++/header/IPLayer.h rename to Packet++/header/pcapPlusPlus/IPLayer.h index b65f4217a7..67f18b84b6 100644 --- a/Packet++/header/IPLayer.h +++ b/Packet++/header/pcapPlusPlus/IPLayer.h @@ -1,7 +1,7 @@ #pragma once -#include "IpAddress.h" -#include "Layer.h" +#include "pcapplusplus/IpAddress.h" +#include "pcapplusplus/Layer.h" /// @file diff --git a/Packet++/header/IPReassembly.h b/Packet++/header/pcapPlusPlus/IPReassembly.h similarity index 99% rename from Packet++/header/IPReassembly.h rename to Packet++/header/pcapPlusPlus/IPReassembly.h index cf16724f3e..8e031cd2a7 100644 --- a/Packet++/header/IPReassembly.h +++ b/Packet++/header/pcapPlusPlus/IPReassembly.h @@ -1,9 +1,9 @@ #pragma once -#include "Packet.h" -#include "LRUList.h" -#include "IpAddress.h" -#include "PointerVector.h" +#include "pcapplusplus/Packet.h" +#include "pcapplusplus/LRUList.h" +#include "pcapplusplus/IpAddress.h" +#include "pcapplusplus/PointerVector.h" #include /** diff --git a/Packet++/header/IPSecLayer.h b/Packet++/header/pcapPlusPlus/IPSecLayer.h similarity index 99% rename from Packet++/header/IPSecLayer.h rename to Packet++/header/pcapPlusPlus/IPSecLayer.h index 5ba64819e2..d5945770fa 100644 --- a/Packet++/header/IPSecLayer.h +++ b/Packet++/header/pcapPlusPlus/IPSecLayer.h @@ -2,7 +2,7 @@ /// @file -#include "Layer.h" +#include "pcapplusplus/Layer.h" /** * \namespace pcpp diff --git a/Packet++/header/IPv4Layer.h b/Packet++/header/pcapPlusPlus/IPv4Layer.h similarity index 99% rename from Packet++/header/IPv4Layer.h rename to Packet++/header/pcapPlusPlus/IPv4Layer.h index d88133fd39..b0aafba34f 100644 --- a/Packet++/header/IPv4Layer.h +++ b/Packet++/header/pcapPlusPlus/IPv4Layer.h @@ -1,9 +1,9 @@ #pragma once -#include "Layer.h" -#include "TLVData.h" -#include "IpAddress.h" -#include "IPLayer.h" +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/TLVData.h" +#include "pcapplusplus/IpAddress.h" +#include "pcapplusplus/IPLayer.h" #include #include diff --git a/Packet++/header/IPv6Extensions.h b/Packet++/header/pcapPlusPlus/IPv6Extensions.h similarity index 99% rename from Packet++/header/IPv6Extensions.h rename to Packet++/header/pcapPlusPlus/IPv6Extensions.h index 92bd16740f..2979306752 100644 --- a/Packet++/header/IPv6Extensions.h +++ b/Packet++/header/pcapPlusPlus/IPv6Extensions.h @@ -1,9 +1,9 @@ #pragma once #include -#include "IpAddress.h" -#include "Layer.h" -#include "TLVData.h" +#include "pcapplusplus/IpAddress.h" +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/TLVData.h" /// @file diff --git a/Packet++/header/IPv6Layer.h b/Packet++/header/pcapPlusPlus/IPv6Layer.h similarity index 98% rename from Packet++/header/IPv6Layer.h rename to Packet++/header/pcapPlusPlus/IPv6Layer.h index d3c2096e23..b2fb8080ab 100644 --- a/Packet++/header/IPv6Layer.h +++ b/Packet++/header/pcapPlusPlus/IPv6Layer.h @@ -1,9 +1,9 @@ #pragma once -#include "Layer.h" -#include "IPLayer.h" -#include "IPv6Extensions.h" -#include "IpAddress.h" +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/IPLayer.h" +#include "pcapplusplus/IPv6Extensions.h" +#include "pcapplusplus/IpAddress.h" /// @file diff --git a/Packet++/header/IcmpLayer.h b/Packet++/header/pcapPlusPlus/IcmpLayer.h similarity index 99% rename from Packet++/header/IcmpLayer.h rename to Packet++/header/pcapPlusPlus/IcmpLayer.h index 18c8b85068..7bed759d6b 100644 --- a/Packet++/header/IcmpLayer.h +++ b/Packet++/header/pcapPlusPlus/IcmpLayer.h @@ -1,7 +1,7 @@ #pragma once -#include "Layer.h" -#include "IPv4Layer.h" +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/IPv4Layer.h" #ifdef _MSC_VER # include #else diff --git a/Packet++/header/IcmpV6Layer.h b/Packet++/header/pcapPlusPlus/IcmpV6Layer.h similarity index 99% rename from Packet++/header/IcmpV6Layer.h rename to Packet++/header/pcapPlusPlus/IcmpV6Layer.h index 3ea4843355..ffa8d6416c 100644 --- a/Packet++/header/IcmpV6Layer.h +++ b/Packet++/header/pcapPlusPlus/IcmpV6Layer.h @@ -1,6 +1,6 @@ #pragma once -#include "Layer.h" +#include "pcapplusplus/Layer.h" /// @file diff --git a/Packet++/header/IgmpLayer.h b/Packet++/header/pcapPlusPlus/IgmpLayer.h similarity index 99% rename from Packet++/header/IgmpLayer.h rename to Packet++/header/pcapPlusPlus/IgmpLayer.h index c16ecfee18..20f7c7bf52 100644 --- a/Packet++/header/IgmpLayer.h +++ b/Packet++/header/pcapPlusPlus/IgmpLayer.h @@ -1,7 +1,7 @@ #pragma once -#include "Layer.h" -#include "IpAddress.h" +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/IpAddress.h" #include /// @file diff --git a/Packet++/header/LLCLayer.h b/Packet++/header/pcapPlusPlus/LLCLayer.h similarity index 98% rename from Packet++/header/LLCLayer.h rename to Packet++/header/pcapPlusPlus/LLCLayer.h index 71f1815533..c758e4402c 100644 --- a/Packet++/header/LLCLayer.h +++ b/Packet++/header/pcapPlusPlus/LLCLayer.h @@ -1,6 +1,6 @@ #pragma once -#include "Layer.h" +#include "pcapplusplus/Layer.h" /// @file diff --git a/Packet++/header/Layer.h b/Packet++/header/pcapPlusPlus/Layer.h similarity index 99% rename from Packet++/header/Layer.h rename to Packet++/header/pcapPlusPlus/Layer.h index 53c49f83d1..a599613a75 100644 --- a/Packet++/header/Layer.h +++ b/Packet++/header/pcapPlusPlus/Layer.h @@ -2,7 +2,7 @@ #include #include -#include "ProtocolType.h" +#include "pcapplusplus/ProtocolType.h" #include /// @file diff --git a/Packet++/header/LdapLayer.h b/Packet++/header/pcapPlusPlus/LdapLayer.h similarity index 99% rename from Packet++/header/LdapLayer.h rename to Packet++/header/pcapPlusPlus/LdapLayer.h index c2d68a26e3..d0541af162 100644 --- a/Packet++/header/LdapLayer.h +++ b/Packet++/header/pcapPlusPlus/LdapLayer.h @@ -1,7 +1,7 @@ #pragma once -#include "Layer.h" -#include "Asn1Codec.h" +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/Asn1Codec.h" #include #include #include diff --git a/Packet++/header/MplsLayer.h b/Packet++/header/pcapPlusPlus/MplsLayer.h similarity index 99% rename from Packet++/header/MplsLayer.h rename to Packet++/header/pcapPlusPlus/MplsLayer.h index b5b6fef549..5498d0b3d9 100644 --- a/Packet++/header/MplsLayer.h +++ b/Packet++/header/pcapPlusPlus/MplsLayer.h @@ -1,6 +1,6 @@ #pragma once -#include "Layer.h" +#include "pcapplusplus/Layer.h" /// @file diff --git a/Packet++/header/NdpLayer.h b/Packet++/header/pcapPlusPlus/NdpLayer.h similarity index 98% rename from Packet++/header/NdpLayer.h rename to Packet++/header/pcapPlusPlus/NdpLayer.h index 518fb54fc1..e05cfbb26c 100644 --- a/Packet++/header/NdpLayer.h +++ b/Packet++/header/pcapPlusPlus/NdpLayer.h @@ -1,10 +1,10 @@ #pragma once -#include "IcmpV6Layer.h" -#include "IpAddress.h" -#include "Layer.h" -#include "MacAddress.h" -#include "TLVData.h" +#include "pcapplusplus/IcmpV6Layer.h" +#include "pcapplusplus/IpAddress.h" +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/MacAddress.h" +#include "pcapplusplus/TLVData.h" #include diff --git a/Packet++/header/NflogLayer.h b/Packet++/header/pcapPlusPlus/NflogLayer.h similarity index 98% rename from Packet++/header/NflogLayer.h rename to Packet++/header/pcapPlusPlus/NflogLayer.h index b49aaa997a..8c4fbb85c1 100644 --- a/Packet++/header/NflogLayer.h +++ b/Packet++/header/pcapPlusPlus/NflogLayer.h @@ -1,8 +1,8 @@ #pragma once -#include "Layer.h" -#include "TLVData.h" -#include "GeneralUtils.h" +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/TLVData.h" +#include "pcapplusplus/GeneralUtils.h" /// @file diff --git a/Packet++/header/NtpLayer.h b/Packet++/header/pcapPlusPlus/NtpLayer.h similarity index 99% rename from Packet++/header/NtpLayer.h rename to Packet++/header/pcapPlusPlus/NtpLayer.h index 822eca6b3c..b22845a9f9 100644 --- a/Packet++/header/NtpLayer.h +++ b/Packet++/header/pcapPlusPlus/NtpLayer.h @@ -1,8 +1,8 @@ #pragma once -#include "Logger.h" -#include "Layer.h" -#include "IpAddress.h" +#include "pcapplusplus/Logger.h" +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/IpAddress.h" /// @file diff --git a/Packet++/header/NullLoopbackLayer.h b/Packet++/header/pcapPlusPlus/NullLoopbackLayer.h similarity index 98% rename from Packet++/header/NullLoopbackLayer.h rename to Packet++/header/pcapPlusPlus/NullLoopbackLayer.h index 624696d648..85b2208dba 100644 --- a/Packet++/header/NullLoopbackLayer.h +++ b/Packet++/header/pcapPlusPlus/NullLoopbackLayer.h @@ -2,7 +2,7 @@ /// @file -#include "Layer.h" +#include "pcapplusplus/Layer.h" namespace pcpp { diff --git a/Packet++/header/PPPoELayer.h b/Packet++/header/pcapPlusPlus/PPPoELayer.h similarity index 99% rename from Packet++/header/PPPoELayer.h rename to Packet++/header/pcapPlusPlus/PPPoELayer.h index 242b165881..ec5a6a6b75 100644 --- a/Packet++/header/PPPoELayer.h +++ b/Packet++/header/pcapPlusPlus/PPPoELayer.h @@ -1,7 +1,7 @@ #pragma once -#include "Layer.h" -#include "TLVData.h" +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/TLVData.h" #include #include diff --git a/Packet++/header/Packet.h b/Packet++/header/pcapPlusPlus/Packet.h similarity index 99% rename from Packet++/header/Packet.h rename to Packet++/header/pcapPlusPlus/Packet.h index fac0a7203b..f1e0830258 100644 --- a/Packet++/header/Packet.h +++ b/Packet++/header/pcapPlusPlus/Packet.h @@ -1,7 +1,7 @@ #pragma once -#include "RawPacket.h" -#include "Layer.h" +#include "pcapplusplus/RawPacket.h" +#include "pcapplusplus/Layer.h" #include /// @file diff --git a/Packet++/header/PacketTrailerLayer.h b/Packet++/header/pcapPlusPlus/PacketTrailerLayer.h similarity index 98% rename from Packet++/header/PacketTrailerLayer.h rename to Packet++/header/pcapPlusPlus/PacketTrailerLayer.h index 14ce071e81..cd5c48f828 100644 --- a/Packet++/header/PacketTrailerLayer.h +++ b/Packet++/header/pcapPlusPlus/PacketTrailerLayer.h @@ -2,7 +2,7 @@ /// @file -#include "Layer.h" +#include "pcapplusplus/Layer.h" namespace pcpp { diff --git a/Packet++/header/PacketUtils.h b/Packet++/header/pcapPlusPlus/PacketUtils.h similarity index 97% rename from Packet++/header/PacketUtils.h rename to Packet++/header/pcapPlusPlus/PacketUtils.h index 1bf04c091a..e5ff52304e 100644 --- a/Packet++/header/PacketUtils.h +++ b/Packet++/header/pcapPlusPlus/PacketUtils.h @@ -1,7 +1,7 @@ #pragma once -#include "Packet.h" -#include "IpAddress.h" +#include "pcapplusplus/Packet.h" +#include "pcapplusplus/IpAddress.h" /// @file diff --git a/Packet++/header/PayloadLayer.h b/Packet++/header/pcapPlusPlus/PayloadLayer.h similarity index 98% rename from Packet++/header/PayloadLayer.h rename to Packet++/header/pcapPlusPlus/PayloadLayer.h index dc07279451..71560023cd 100644 --- a/Packet++/header/PayloadLayer.h +++ b/Packet++/header/pcapPlusPlus/PayloadLayer.h @@ -1,6 +1,6 @@ #pragma once -#include "Layer.h" +#include "pcapplusplus/Layer.h" /// @file diff --git a/Packet++/header/ProtocolType.h b/Packet++/header/pcapPlusPlus/ProtocolType.h similarity index 100% rename from Packet++/header/ProtocolType.h rename to Packet++/header/pcapPlusPlus/ProtocolType.h diff --git a/Packet++/header/RadiusLayer.h b/Packet++/header/pcapPlusPlus/RadiusLayer.h similarity index 99% rename from Packet++/header/RadiusLayer.h rename to Packet++/header/pcapPlusPlus/RadiusLayer.h index 9405551c21..7317257e9f 100644 --- a/Packet++/header/RadiusLayer.h +++ b/Packet++/header/pcapPlusPlus/RadiusLayer.h @@ -1,7 +1,7 @@ #pragma once -#include "Layer.h" -#include "TLVData.h" +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/TLVData.h" /// @file diff --git a/Packet++/header/RawPacket.h b/Packet++/header/pcapPlusPlus/RawPacket.h similarity index 100% rename from Packet++/header/RawPacket.h rename to Packet++/header/pcapPlusPlus/RawPacket.h diff --git a/Packet++/header/S7CommLayer.h b/Packet++/header/pcapPlusPlus/S7CommLayer.h similarity index 98% rename from Packet++/header/S7CommLayer.h rename to Packet++/header/pcapPlusPlus/S7CommLayer.h index 4cc5bc9235..7a6c02a66e 100644 --- a/Packet++/header/S7CommLayer.h +++ b/Packet++/header/pcapPlusPlus/S7CommLayer.h @@ -1,7 +1,7 @@ #pragma once -#include "EthLayer.h" -#include "Layer.h" +#include "pcapplusplus/EthLayer.h" +#include "pcapplusplus/Layer.h" namespace pcpp { diff --git a/Packet++/header/SSHLayer.h b/Packet++/header/pcapPlusPlus/SSHLayer.h similarity index 99% rename from Packet++/header/SSHLayer.h rename to Packet++/header/pcapPlusPlus/SSHLayer.h index d4e5b14562..0c4a638340 100644 --- a/Packet++/header/SSHLayer.h +++ b/Packet++/header/pcapPlusPlus/SSHLayer.h @@ -1,6 +1,6 @@ #pragma once -#include "Layer.h" +#include "pcapplusplus/Layer.h" /** * @file diff --git a/Packet++/header/SSLCommon.h b/Packet++/header/pcapPlusPlus/SSLCommon.h similarity index 100% rename from Packet++/header/SSLCommon.h rename to Packet++/header/pcapPlusPlus/SSLCommon.h diff --git a/Packet++/header/SSLHandshake.h b/Packet++/header/pcapPlusPlus/SSLHandshake.h similarity index 99% rename from Packet++/header/SSLHandshake.h rename to Packet++/header/pcapPlusPlus/SSLHandshake.h index 5f5f97e8bc..e15c83623f 100644 --- a/Packet++/header/SSLHandshake.h +++ b/Packet++/header/pcapPlusPlus/SSLHandshake.h @@ -1,9 +1,9 @@ #pragma once #include -#include "SSLCommon.h" -#include "PointerVector.h" -#include "Asn1Codec.h" +#include "pcapplusplus/SSLCommon.h" +#include "pcapplusplus/PointerVector.h" +#include "pcapplusplus/Asn1Codec.h" /** * @file diff --git a/Packet++/header/SSLLayer.h b/Packet++/header/pcapPlusPlus/SSLLayer.h similarity index 99% rename from Packet++/header/SSLLayer.h rename to Packet++/header/pcapPlusPlus/SSLLayer.h index fb7565f738..ce45e4a6fd 100644 --- a/Packet++/header/SSLLayer.h +++ b/Packet++/header/pcapPlusPlus/SSLLayer.h @@ -1,9 +1,9 @@ #pragma once -#include "PointerVector.h" -#include "Layer.h" -#include "SSLCommon.h" -#include "SSLHandshake.h" +#include "pcapplusplus/PointerVector.h" +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/SSLCommon.h" +#include "pcapplusplus/SSLHandshake.h" /** * @file diff --git a/Packet++/header/SdpLayer.h b/Packet++/header/pcapPlusPlus/SdpLayer.h similarity index 98% rename from Packet++/header/SdpLayer.h rename to Packet++/header/pcapPlusPlus/SdpLayer.h index 067f4d8feb..233f00498a 100644 --- a/Packet++/header/SdpLayer.h +++ b/Packet++/header/pcapPlusPlus/SdpLayer.h @@ -1,7 +1,7 @@ #pragma once -#include "IpAddress.h" -#include "TextBasedProtocol.h" +#include "pcapplusplus/IpAddress.h" +#include "pcapplusplus/TextBasedProtocol.h" #include /// @file diff --git a/Packet++/header/SingleCommandTextProtocol.h b/Packet++/header/pcapPlusPlus/SingleCommandTextProtocol.h similarity index 98% rename from Packet++/header/SingleCommandTextProtocol.h rename to Packet++/header/pcapPlusPlus/SingleCommandTextProtocol.h index cee3343f8f..d53aafac7f 100644 --- a/Packet++/header/SingleCommandTextProtocol.h +++ b/Packet++/header/pcapPlusPlus/SingleCommandTextProtocol.h @@ -1,7 +1,7 @@ #pragma once #include -#include "Layer.h" +#include "pcapplusplus/Layer.h" /// @file diff --git a/Packet++/header/SipLayer.h b/Packet++/header/pcapPlusPlus/SipLayer.h similarity index 99% rename from Packet++/header/SipLayer.h rename to Packet++/header/pcapPlusPlus/SipLayer.h index 2562f53ee4..f38f64f890 100644 --- a/Packet++/header/SipLayer.h +++ b/Packet++/header/pcapPlusPlus/SipLayer.h @@ -1,6 +1,6 @@ #pragma once -#include "TextBasedProtocol.h" +#include "pcapplusplus/TextBasedProtocol.h" /// @file diff --git a/Packet++/header/Sll2Layer.h b/Packet++/header/pcapPlusPlus/Sll2Layer.h similarity index 98% rename from Packet++/header/Sll2Layer.h rename to Packet++/header/pcapPlusPlus/Sll2Layer.h index 7b17682654..d717c4141d 100644 --- a/Packet++/header/Sll2Layer.h +++ b/Packet++/header/pcapPlusPlus/Sll2Layer.h @@ -1,7 +1,7 @@ #pragma once -#include "MacAddress.h" -#include "Layer.h" +#include "pcapplusplus/MacAddress.h" +#include "pcapplusplus/Layer.h" /// @file diff --git a/Packet++/header/SllLayer.h b/Packet++/header/pcapPlusPlus/SllLayer.h similarity index 98% rename from Packet++/header/SllLayer.h rename to Packet++/header/pcapPlusPlus/SllLayer.h index 6c6d19e888..c1b8d8f8f6 100644 --- a/Packet++/header/SllLayer.h +++ b/Packet++/header/pcapPlusPlus/SllLayer.h @@ -1,7 +1,7 @@ #pragma once -#include "MacAddress.h" -#include "Layer.h" +#include "pcapplusplus/MacAddress.h" +#include "pcapplusplus/Layer.h" /// @file diff --git a/Packet++/header/SmtpLayer.h b/Packet++/header/pcapPlusPlus/SmtpLayer.h similarity index 99% rename from Packet++/header/SmtpLayer.h rename to Packet++/header/pcapPlusPlus/SmtpLayer.h index 2c251b75d1..167221d03b 100644 --- a/Packet++/header/SmtpLayer.h +++ b/Packet++/header/pcapPlusPlus/SmtpLayer.h @@ -1,8 +1,8 @@ #ifndef PACKETPP_SMTP_LAYER #define PACKETPP_SMTP_LAYER -#include "PayloadLayer.h" -#include "SingleCommandTextProtocol.h" +#include "pcapplusplus/PayloadLayer.h" +#include "pcapplusplus/SingleCommandTextProtocol.h" /// @file diff --git a/Packet++/header/SomeIpLayer.h b/Packet++/header/pcapPlusPlus/SomeIpLayer.h similarity index 99% rename from Packet++/header/SomeIpLayer.h rename to Packet++/header/pcapPlusPlus/SomeIpLayer.h index 930869843c..6b9f9632c0 100644 --- a/Packet++/header/SomeIpLayer.h +++ b/Packet++/header/pcapPlusPlus/SomeIpLayer.h @@ -1,6 +1,6 @@ #pragma once -#include "Layer.h" +#include "pcapplusplus/Layer.h" #include /// @file diff --git a/Packet++/header/SomeIpSdLayer.h b/Packet++/header/pcapPlusPlus/SomeIpSdLayer.h similarity index 99% rename from Packet++/header/SomeIpSdLayer.h rename to Packet++/header/pcapPlusPlus/SomeIpSdLayer.h index b7c1bd9024..cb46ba777f 100644 --- a/Packet++/header/SomeIpSdLayer.h +++ b/Packet++/header/pcapPlusPlus/SomeIpSdLayer.h @@ -1,8 +1,8 @@ #pragma once -#include "IpAddress.h" -#include "Layer.h" -#include "SomeIpLayer.h" +#include "pcapplusplus/IpAddress.h" +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/SomeIpLayer.h" #include #include #include diff --git a/Packet++/header/StpLayer.h b/Packet++/header/pcapPlusPlus/StpLayer.h similarity index 99% rename from Packet++/header/StpLayer.h rename to Packet++/header/pcapPlusPlus/StpLayer.h index f59dc39910..6ec7a66ce3 100644 --- a/Packet++/header/StpLayer.h +++ b/Packet++/header/pcapPlusPlus/StpLayer.h @@ -1,7 +1,7 @@ #pragma once -#include "Layer.h" -#include "MacAddress.h" +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/MacAddress.h" /// @file diff --git a/Packet++/header/TLVData.h b/Packet++/header/pcapPlusPlus/TLVData.h similarity index 99% rename from Packet++/header/TLVData.h rename to Packet++/header/pcapPlusPlus/TLVData.h index 54787915b4..c96ee71ae0 100644 --- a/Packet++/header/TLVData.h +++ b/Packet++/header/pcapPlusPlus/TLVData.h @@ -1,7 +1,7 @@ #pragma once -#include "Layer.h" -#include "IpAddress.h" +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/IpAddress.h" #include /// @file diff --git a/Packet++/header/TcpLayer.h b/Packet++/header/pcapPlusPlus/TcpLayer.h similarity index 99% rename from Packet++/header/TcpLayer.h rename to Packet++/header/pcapPlusPlus/TcpLayer.h index fbe762f280..43d4542c44 100644 --- a/Packet++/header/TcpLayer.h +++ b/Packet++/header/pcapPlusPlus/TcpLayer.h @@ -1,7 +1,7 @@ #pragma once -#include "DeprecationUtils.h" -#include "Layer.h" +#include "pcapplusplus/DeprecationUtils.h" +#include "pcapplusplus/Layer.h" #include "TLVData.h" #include diff --git a/Packet++/header/TcpReassembly.h b/Packet++/header/pcapPlusPlus/TcpReassembly.h similarity index 99% rename from Packet++/header/TcpReassembly.h rename to Packet++/header/pcapPlusPlus/TcpReassembly.h index 129c2c9690..174b41faf7 100644 --- a/Packet++/header/TcpReassembly.h +++ b/Packet++/header/pcapPlusPlus/TcpReassembly.h @@ -1,8 +1,8 @@ #pragma once -#include "Packet.h" -#include "IpAddress.h" -#include "PointerVector.h" +#include "pcapplusplus/Packet.h" +#include "pcapplusplus/IpAddress.h" +#include "pcapplusplus/PointerVector.h" #include #include #include diff --git a/Packet++/header/TelnetLayer.h b/Packet++/header/pcapPlusPlus/TelnetLayer.h similarity index 99% rename from Packet++/header/TelnetLayer.h rename to Packet++/header/pcapPlusPlus/TelnetLayer.h index d57125f8f5..241c04f39a 100644 --- a/Packet++/header/TelnetLayer.h +++ b/Packet++/header/pcapPlusPlus/TelnetLayer.h @@ -1,6 +1,6 @@ #pragma once -#include "Layer.h" +#include "pcapplusplus/Layer.h" /// @file diff --git a/Packet++/header/TextBasedProtocol.h b/Packet++/header/pcapPlusPlus/TextBasedProtocol.h similarity index 99% rename from Packet++/header/TextBasedProtocol.h rename to Packet++/header/pcapPlusPlus/TextBasedProtocol.h index 054f1f3caa..c325fd8315 100644 --- a/Packet++/header/TextBasedProtocol.h +++ b/Packet++/header/pcapPlusPlus/TextBasedProtocol.h @@ -1,7 +1,7 @@ #pragma once #include -#include "Layer.h" +#include "pcapplusplus/Layer.h" /// @file diff --git a/Packet++/header/TpktLayer.h b/Packet++/header/pcapPlusPlus/TpktLayer.h similarity index 98% rename from Packet++/header/TpktLayer.h rename to Packet++/header/pcapPlusPlus/TpktLayer.h index 29bcba8aa2..c5d9ca9254 100644 --- a/Packet++/header/TpktLayer.h +++ b/Packet++/header/pcapPlusPlus/TpktLayer.h @@ -1,7 +1,7 @@ #pragma once -#include "EthLayer.h" -#include "Layer.h" +#include "pcapplusplus/EthLayer.h" +#include "pcapplusplus/Layer.h" /// @file diff --git a/Packet++/header/UdpLayer.h b/Packet++/header/pcapPlusPlus/UdpLayer.h similarity index 98% rename from Packet++/header/UdpLayer.h rename to Packet++/header/pcapPlusPlus/UdpLayer.h index 44c0f85bce..79639d8205 100644 --- a/Packet++/header/UdpLayer.h +++ b/Packet++/header/pcapPlusPlus/UdpLayer.h @@ -1,6 +1,6 @@ #pragma once -#include "Layer.h" +#include "pcapplusplus/Layer.h" /// @file diff --git a/Packet++/header/VlanLayer.h b/Packet++/header/pcapPlusPlus/VlanLayer.h similarity index 98% rename from Packet++/header/VlanLayer.h rename to Packet++/header/pcapPlusPlus/VlanLayer.h index a8ff158f59..f7f1bd2fe8 100644 --- a/Packet++/header/VlanLayer.h +++ b/Packet++/header/pcapPlusPlus/VlanLayer.h @@ -1,7 +1,7 @@ #pragma once -#include "Layer.h" -#include "EthLayer.h" +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/EthLayer.h" /// @file diff --git a/Packet++/header/VrrpLayer.h b/Packet++/header/pcapPlusPlus/VrrpLayer.h similarity index 99% rename from Packet++/header/VrrpLayer.h rename to Packet++/header/pcapPlusPlus/VrrpLayer.h index d6361521cc..5e9eaeb2fb 100644 --- a/Packet++/header/VrrpLayer.h +++ b/Packet++/header/pcapPlusPlus/VrrpLayer.h @@ -1,7 +1,7 @@ #pragma once -#include "Layer.h" -#include "IpAddress.h" +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/IpAddress.h" #include /// @file diff --git a/Packet++/header/VxlanLayer.h b/Packet++/header/pcapPlusPlus/VxlanLayer.h similarity index 99% rename from Packet++/header/VxlanLayer.h rename to Packet++/header/pcapPlusPlus/VxlanLayer.h index 87673d18ae..3cf83c1270 100644 --- a/Packet++/header/VxlanLayer.h +++ b/Packet++/header/pcapPlusPlus/VxlanLayer.h @@ -1,6 +1,6 @@ #pragma once -#include "Layer.h" +#include "pcapplusplus/Layer.h" /// @file diff --git a/Packet++/header/WakeOnLanLayer.h b/Packet++/header/pcapPlusPlus/WakeOnLanLayer.h similarity index 97% rename from Packet++/header/WakeOnLanLayer.h rename to Packet++/header/pcapPlusPlus/WakeOnLanLayer.h index 358bbb5a3d..1d23855865 100644 --- a/Packet++/header/WakeOnLanLayer.h +++ b/Packet++/header/pcapPlusPlus/WakeOnLanLayer.h @@ -1,8 +1,8 @@ #pragma once -#include "IpAddress.h" -#include "Layer.h" -#include "MacAddress.h" +#include "pcapplusplus/IpAddress.h" +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/MacAddress.h" /// @file diff --git a/Packet++/header/pcapplusplus/ArpLayer.h b/Packet++/header/pcapplusplus/ArpLayer.h new file mode 100644 index 0000000000..5634d0196c --- /dev/null +++ b/Packet++/header/pcapplusplus/ArpLayer.h @@ -0,0 +1,179 @@ +#pragma once + +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/IpAddress.h" +#include "pcapplusplus/MacAddress.h" + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * @struct arphdr + * Represents an ARP protocol header + */ +#pragma pack(push, 1) + struct arphdr + { + /** Hardware type (HTYPE) */ + uint16_t hardwareType; + /** Protocol type (PTYPE). The permitted PTYPE values share a numbering space with those for EtherType */ + uint16_t protocolType; + /** Hardware address length (HLEN). For IPv4, this has the value 0x0800 */ + uint8_t hardwareSize; + /** Protocol length (PLEN). Length (in octets) of addresses used in the upper layer protocol. (The upper layer + * protocol specified in PTYPE.) IPv4 address size is 4 */ + uint8_t protocolSize; + /** Specifies the operation that the sender is performing: 1 (::ARP_REQUEST) for request, 2 (::ARP_REPLY) for + * reply */ + uint16_t opcode; + /** Sender hardware address (SHA) */ + uint8_t senderMacAddr[6]; + /** Sender protocol address (SPA) */ + uint32_t senderIpAddr; + /** Target hardware address (THA) */ + uint8_t targetMacAddr[6]; + /** Target protocol address (TPA) */ + uint32_t targetIpAddr; + }; +#pragma pack(pop) + + /** + * An enum for ARP message type + */ + enum ArpOpcode + { + ARP_REQUEST = 0x0001, ///< ARP request + ARP_REPLY = 0x0002 ///< ARP reply (response) + }; + + /** + * @class ArpLayer + * Represents an ARP protocol layer. Currently only IPv4 ARP messages are supported + */ + class ArpLayer : public Layer + { + public: + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data (will be casted to @ref arphdr) + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + ArpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : Layer(data, dataLen, prevLayer, packet, ARP) + { + m_DataLen = sizeof(arphdr); + } + + /** + * A constructor that allocates a new ARP header + * @param[in] opCode ARP message type (ARP request or ARP reply) + * @param[in] senderMacAddr The sender MAC address (will be put in arphdr#senderMacAddr) + * @param[in] targetMacAddr The target MAC address (will be put in arphdr#targetMacAddr) + * @param[in] senderIpAddr The sender IP address (will be put in arphdr#senderIpAddr) + * @param[in] targetIpAddr The target IP address (will be put in arphdr#targetIpAddr) + */ + ArpLayer(ArpOpcode opCode, const MacAddress& senderMacAddr, const MacAddress& targetMacAddr, + const IPv4Address& senderIpAddr, const IPv4Address& targetIpAddr); + + ~ArpLayer() + {} + + /** + * Get a pointer to the ARP header. Notice this points directly to the data, so every change will change the + * actual packet data + * @return A pointer to the @ref arphdr + */ + inline arphdr* getArpHeader() const + { + return (arphdr*)m_Data; + } + + /** + * Get the sender hardware address (SHA) in the form of MacAddress + * @return A MacAddress containing the sender hardware address (SHA) + */ + inline MacAddress getSenderMacAddress() const + { + return MacAddress(getArpHeader()->senderMacAddr); + } + + /** + * Get the target hardware address (THA) in the form of MacAddress + * @return A MacAddress containing the target hardware address (THA) + */ + inline MacAddress getTargetMacAddress() const + { + return MacAddress(getArpHeader()->targetMacAddr); + } + + /** + * Get the sender protocol address (SPA) in the form of IPv4Address + * @return An IPv4Address containing the sender protocol address (SPA) + */ + inline IPv4Address getSenderIpAddr() const + { + return getArpHeader()->senderIpAddr; + } + + /** + * Get the target protocol address (TPA) in the form of IPv4Address + * @return An IPv4Address containing the target protocol address (TPA) + */ + inline IPv4Address getTargetIpAddr() const + { + return getArpHeader()->targetIpAddr; + } + + // implement abstract methods + + /** + * Does nothing for this layer (ArpLayer is always last) + */ + void parseNextLayer() + {} + + /** + * @return The size of @ref arphdr + */ + size_t getHeaderLen() const + { + return sizeof(arphdr); + } + + /** + * Calculate the following fields: + * - @ref arphdr#hardwareType = Ethernet (1) + * - @ref arphdr#hardwareSize = 6 + * - @ref arphdr#protocolType = ETHERTYPE_IP (assume IPv4 over ARP) + * - @ref arphdr#protocolSize = 4 (assume IPv4 over ARP) + * - if it's an ARP request: @ref arphdr#targetMacAddr = MacAddress("00:00:00:00:00:00") + */ + void computeCalculateFields(); + + /** + * Is this packet an ARP request? + */ + bool isRequest() const; + + /** + * Is this packet an ARP reply? + */ + bool isReply() const; + + std::string toString() const; + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelNetworkLayer; + } + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/Asn1Codec.h b/Packet++/header/pcapplusplus/Asn1Codec.h new file mode 100644 index 0000000000..de7796739f --- /dev/null +++ b/Packet++/header/pcapplusplus/Asn1Codec.h @@ -0,0 +1,582 @@ +#pragma once + +#include +#include +#include +#include +#include "pcapplusplus/PointerVector.h" + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + /** + * An enum for representing ASN.1 tag class + */ + enum class Asn1TagClass : uint8_t + { + /** The Universal tag class */ + Universal = 0, + /** The Application tag class */ + Application = 1, + /** The Context-Specific tag class */ + ContextSpecific = 2, + /** The Private tag class */ + Private = 3, + }; + + /** + * An enum for representing ASN.1 Universal tag types + */ + enum class Asn1UniversalTagType : uint8_t + { + /** The reserved identifier for the End-of-Contents marker in an indefinite length encoding */ + EndOfContent = 0, + /** The universal tag type for Boolean */ + Boolean = 1, + /** The universal tag type for Integer */ + Integer = 2, + /** The universal tag type for Bit String */ + BitString = 3, + /** The universal tag type for Octet String */ + OctetString = 4, + /** The universal tag type for Null */ + Null = 5, + /** The universal tag type for Object Identifier */ + ObjectIdentifier = 6, + /** The universal tag type for Object Descriptor */ + ObjectDescriptor = 7, + /** The universal tag type for External */ + External = 8, + /** The universal tag type for Real */ + Real = 9, + /** The universal tag type for Enumerated */ + Enumerated = 10, + /** The universal tag type for Embedded-PDV */ + EmbeddedPDV = 11, + /** The universal tag type for UTF8 String */ + UTF8String = 12, + /** The universal tag type for Relative Object Identifier */ + RelativeObjectIdentifier = 13, + /** The universal tag type for Time */ + Time = 14, + /** A reserved value */ + Reserved = 15, + /** The universal tag type Sequence */ + Sequence = 16, + /** The universal tag type for Set */ + Set = 17, + /** The universal tag type for Numeric String */ + NumericString = 18, + /** The universal tag type for Printable String */ + PrintableString = 19, + /** The universal tag type for T61String */ + T61String = 20, + /** The universal tag type for Videotex String */ + VideotexString = 21, + /** The universal tag type for IA5String */ + IA5String = 22, + /** The universal tag type for UTC time */ + UTCTime = 23, + /** The universal tag type for Generalized time */ + GeneralizedTime = 24, + /** The universal tag type for GraphicString */ + GraphicString = 25, + /** The universal tag type for VisibleString */ + VisibleString = 26, + /** The universal tag type for GeneralString */ + GeneralString = 27, + /** The universal tag type for UniversalString */ + UniversalString = 28, + /** The universal tag type for CharacterString */ + CharacterString = 29, + /** The universal tag type for BMPString */ + BMPString = 30, + /** The universal tag type for Date */ + Date = 31, + /** The universal tag type for Time of Day */ + TimeOfDay = 32, + /** The universal tag type for Date-Time */ + DateTime = 33, + /** The universal tag type for Duration */ + Duration = 34, + /** The universal tag type for Object Identifier Internationalized Resource Identifier (IRI) */ + ObjectIdentifierIRI = 35, + /** The universal tag type for Relative Object Identifier Internationalized Resource Identifier (IRI) */ + RelativeObjectIdentifierIRI = 36, + /** A non-applicable value */ + NotApplicable = 255 + }; + + /** + * @class Asn1Record + * Represents an ASN.1 record, as described in ITU-T Recommendation X.680: + * + * + * + */ + class Asn1Record + { + public: + /** + * A static method to decode a byte array into an Asn1Record + * @param data A byte array to decode + * @param dataLen The byte array length + * @param lazy Use lazy decoding, set to true by default. Lazy decoding entails delaying the decoding + * of the record value until it is accessed + * @return A smart pointer to the decoded ASN.1 record. If the byte stream is not a valid ASN.1 record + * an exception is thrown + */ + static std::unique_ptr decode(const uint8_t* data, size_t dataLen, bool lazy = true); + + /** + * Encode this record and convert it to a byte stream + * @return A vector of bytes representing the record + */ + std::vector encode(); + + /** + * @return The ASN.1 tag class + */ + Asn1TagClass getTagClass() const + { + return m_TagClass; + } + + /** + * @return True if it's a constructed record, or false if it's a primitive record + */ + bool isConstructed() const + { + return m_IsConstructed; + } + + /** + * @return The ASN.1 Universal tag type if the record is of class Universal, otherwise + * Asn1UniversalTagType#NotApplicable + */ + Asn1UniversalTagType getUniversalTagType() const; + + /** + * @return The ASN.1 tag type value + */ + uint8_t getTagType() const + { + return m_TagType; + } + + /** + * @return The length of the record value + */ + size_t getValueLength() const + { + return m_ValueLength; + } + + /** + * @return The total length of the record + */ + size_t getTotalLength() const + { + return m_TotalLength; + } + + /** + * @return A string representation of the record + */ + std::string toString(); + + /** + * A templated method that accepts a class derived from Asn1Record as its template argument and attempts + * to cast the current instance to that type + * @tparam Asn1RecordType The type to cast to + * @return A pointer to the type after casting + */ + template Asn1RecordType* castAs() + { + auto result = dynamic_cast(this); + if (result == nullptr) + { + throw std::bad_cast(); + } + return result; + } + + virtual ~Asn1Record() = default; + + protected: + Asn1TagClass m_TagClass = Asn1TagClass::Universal; + bool m_IsConstructed = false; + uint8_t m_TagType = 0; + + size_t m_ValueLength = 0; + size_t m_TotalLength = 0; + + uint8_t* m_EncodedValue = nullptr; + + Asn1Record() = default; + + static Asn1Record* decodeInternal(const uint8_t* data, size_t dataLen, bool lazy); + + virtual void decodeValue(uint8_t* data, bool lazy) = 0; + virtual std::vector encodeValue() const = 0; + + static Asn1Record* decodeTagAndCreateRecord(const uint8_t* data, size_t dataLen, int& tagLen); + int decodeLength(const uint8_t* data, size_t dataLen); + void decodeValueIfNeeded(); + + uint8_t encodeTag(); + std::vector encodeLength() const; + + virtual std::vector toStringList(); + + friend class Asn1ConstructedRecord; + }; + + /** + * @class Asn1GenericRecord + * Represents a generic ASN.1 record, either of an unknown type or of a known type that doesn't + * have a dedicated parser yet + */ + class Asn1GenericRecord : public Asn1Record + { + friend class Asn1Record; + + public: + /** + * A constructor to create a generic record + * @param tagClass The record tag class + * @param isConstructed A flag to indicate if the record is constructed or primitive + * @param tagType The record tag type value + * @param value A byte array of the tag value + * @param valueLen The length of the value byte array + */ + Asn1GenericRecord(Asn1TagClass tagClass, bool isConstructed, uint8_t tagType, const uint8_t* value, + size_t valueLen); + + /** + * A constructor to create a generic record + * @param tagClass The record tag class + * @param isConstructed A flag to indicate if the record is constructed or primitive + * @param tagType The record tag type value + * @param value A string representing the tag value + */ + Asn1GenericRecord(Asn1TagClass tagClass, bool isConstructed, uint8_t tagType, const std::string& value); + + ~Asn1GenericRecord() override; + + /** + * @return A pointer to the tag value + */ + const uint8_t* getValue() + { + decodeValueIfNeeded(); + return m_Value; + } + + protected: + Asn1GenericRecord() = default; + + void decodeValue(uint8_t* data, bool lazy) override; + std::vector encodeValue() const override; + + private: + uint8_t* m_Value = nullptr; + + void init(Asn1TagClass tagClass, bool isConstructed, uint8_t tagType, const uint8_t* value, size_t valueLen); + }; + + /** + * @class Asn1ConstructedRecord + * Represents a constructed ASN.1 record, which is a record that has sub-records + */ + class Asn1ConstructedRecord : public Asn1Record + { + friend class Asn1Record; + + public: + /** + * A constructor to create a constructed record + * @param tagClass The record tag class + * @param tagType The record tag type value + * @param subRecords A list of sub-records to assign as the record value + */ + explicit Asn1ConstructedRecord(Asn1TagClass tagClass, uint8_t tagType, + const std::vector& subRecords); + + /** + * A constructor to create a constructed record + * @param tagClass The record tag class + * @param tagType The record tag type value + * @param subRecords A PointerVector of sub-records to assign as the record value + */ + explicit Asn1ConstructedRecord(Asn1TagClass tagClass, uint8_t tagType, + const PointerVector& subRecords); + + /** + * @return A reference to the list of sub-records. It's important to note that any modifications made to + * this list will directly affect the internal structure + */ + PointerVector& getSubRecords() + { + decodeValueIfNeeded(); + return m_SubRecords; + }; + + protected: + Asn1ConstructedRecord() = default; + + void decodeValue(uint8_t* data, bool lazy) override; + std::vector encodeValue() const override; + + std::vector toStringList() override; + + template void init(Asn1TagClass tagClass, uint8_t tagType, Iterator begin, Iterator end) + { + m_TagType = tagType; + m_TagClass = tagClass; + m_IsConstructed = true; + + size_t recordValueLength = 0; + for (Iterator recordIter = begin; recordIter != end; ++recordIter) + { + auto encodedRecord = (*recordIter)->encode(); + auto copyRecord = Asn1Record::decode(encodedRecord.data(), encodedRecord.size(), false); + m_SubRecords.pushBack(std::move(copyRecord)); + recordValueLength += encodedRecord.size(); + } + + m_ValueLength = recordValueLength; + m_TotalLength = recordValueLength + 1 + (m_ValueLength < 128 ? 1 : 2); + } + + private: + PointerVector m_SubRecords; + }; + + /** + * @class Asn1SequenceRecord + * Represents an ASN.1 record with a value of type Sequence + */ + class Asn1SequenceRecord : public Asn1ConstructedRecord + { + friend class Asn1Record; + + public: + /** + * A constructor to create a record of type Sequence + * @param subRecords A list of sub-records to assign as the record value + */ + explicit Asn1SequenceRecord(const std::vector& subRecords); + + /** + * A constructor to create a record of type Sequence + * @param subRecords A PointerVector of sub-records to assign as the record value + */ + explicit Asn1SequenceRecord(const PointerVector& subRecords); + + private: + Asn1SequenceRecord() = default; + }; + + /** + * @class Asn1SetRecord + * Represents an ASN.1 record with a value of type Set + */ + class Asn1SetRecord : public Asn1ConstructedRecord + { + friend class Asn1Record; + + public: + /** + * A constructor to create a record of type Set + * @param subRecords A list of sub-records to assign as the record value + */ + explicit Asn1SetRecord(const std::vector& subRecords); + + /** + * A constructor to create a record of type Set + * @param subRecords A PointerVector of sub-records to assign as the record value + */ + explicit Asn1SetRecord(const PointerVector& subRecords); + + private: + Asn1SetRecord() = default; + }; + + /** + * @class Asn1PrimitiveRecord + * Represents a primitive ASN.1 record, meaning a record that doesn't have sub-records. + * This is an abstract class that cannot be instantiated + */ + class Asn1PrimitiveRecord : public Asn1Record + { + friend class Asn1Record; + + protected: + Asn1PrimitiveRecord() = default; + explicit Asn1PrimitiveRecord(Asn1UniversalTagType tagType); + }; + + /** + * @class Asn1IntegerRecord + * Represents an ASN.1 record with a value of type Integer + */ + class Asn1IntegerRecord : public Asn1PrimitiveRecord + { + friend class Asn1Record; + + public: + /** + * A constructor to create a record of type Integer + * @param value An integer to set as the record value + */ + explicit Asn1IntegerRecord(uint32_t value); + + /** + * @return The integer value of this record + */ + uint32_t getValue() + { + decodeValueIfNeeded(); + return m_Value; + } + + protected: + Asn1IntegerRecord() = default; + + void decodeValue(uint8_t* data, bool lazy) override; + std::vector encodeValue() const override; + + std::vector toStringList() override; + + private: + uint32_t m_Value = 0; + }; + + /** + * @class Asn1EnumeratedRecord + * Represents an ASN.1 record with a value of type Enumerated + */ + class Asn1EnumeratedRecord : public Asn1IntegerRecord + { + friend class Asn1Record; + + public: + /** + * A constructor to create a record of type Enumerated + * @param value An integer to set as the record value + */ + explicit Asn1EnumeratedRecord(uint32_t value); + + private: + Asn1EnumeratedRecord() = default; + }; + + /** + * @class Asn1OctetStringRecord + * Represents an ASN.1 record with a value of type Octet String + */ + class Asn1OctetStringRecord : public Asn1PrimitiveRecord + { + friend class Asn1Record; + + public: + /** + * A constructor to create a record of type Octet String from a printable value + * @param value A string to set as the record value + */ + explicit Asn1OctetStringRecord(const std::string& value); + + /** + * A constructor to create a record of type Octet String from a non-printable value + * @param value A byte array to set as the record value + * @param valueLength The length of the byte array + */ + explicit Asn1OctetStringRecord(const uint8_t* value, size_t valueLength); + + /** + * @return The string value of this record + */ + std::string getValue() + { + decodeValueIfNeeded(); + return m_Value; + }; + + protected: + void decodeValue(uint8_t* data, bool lazy) override; + std::vector encodeValue() const override; + + std::vector toStringList() override; + + private: + std::string m_Value; + bool m_IsPrintable = true; + + Asn1OctetStringRecord() = default; + }; + + /** + * @class Asn1BooleanRecord + * Represents an ASN.1 record with a value of type Boolean + */ + class Asn1BooleanRecord : public Asn1PrimitiveRecord + { + friend class Asn1Record; + + public: + /** + * A constructor to create a record of type Boolean + * @param value A boolean to set as the record value + */ + explicit Asn1BooleanRecord(bool value); + + /** + * @return The boolean value of this record + */ + bool getValue() + { + decodeValueIfNeeded(); + return m_Value; + }; + + protected: + void decodeValue(uint8_t* data, bool lazy) override; + std::vector encodeValue() const override; + + std::vector toStringList() override; + + private: + Asn1BooleanRecord() = default; + + bool m_Value = false; + }; + + /** + * @class Asn1NullRecord + * Represents an ASN.1 record with a value of type Null + */ + class Asn1NullRecord : public Asn1PrimitiveRecord + { + friend class Asn1Record; + + public: + /** + * A constructor to create a record of type Null + */ + Asn1NullRecord(); + + protected: + void decodeValue(uint8_t* data, bool lazy) override + {} + std::vector encodeValue() const override + { + return {}; + } + }; +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/BgpLayer.h b/Packet++/header/pcapplusplus/BgpLayer.h new file mode 100644 index 0000000000..b1e0e42a75 --- /dev/null +++ b/Packet++/header/pcapplusplus/BgpLayer.h @@ -0,0 +1,725 @@ +#pragma once + +#include +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/IpAddress.h" + +/** + * @file + * This file contains classes for parsing, creating and editing Border Gateway Protocol (BGP) version 4 packets. + * It contains an abstract class named BgpLayer which has common functionality and 5 inherited classes that + * represent the different BGP message types: OPEN, UPDATE, NOTIFICATION, KEEPALIVE and ROUTE-REFRESH. + * Each of these classes contains unique functionality for parsing. creating and editing of these message. + */ + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * @class BgpLayer + * Represents Border Gateway Protocol (BGP) v4 protocol layer. This is an abstract class that cannot be + * instantiated, and contains functionality which is common to all BGP message types. + */ + class BgpLayer : public Layer + { + public: + /** + * An enum representing BGP message types + */ + enum BgpMessageType + { + /** BGP OPEN message */ + Open = 1, + /** BGP UPDATE message */ + Update = 2, + /** BGP NOTIFICATION message */ + Notification = 3, + /** BGP KEEPALIVE message */ + Keepalive = 4, + /** BGP ROUTE-REFRESH message */ + RouteRefresh = 5, + }; + +#pragma pack(push, 1) + /** + * @struct bgp_common_header + * Represents the common fields of a BGP 4 message + */ + struct bgp_common_header + { + /** 16-octet marker */ + uint8_t marker[16]; + /** Total length of the message, including the header */ + uint16_t length; + /** BGP message type */ + uint8_t messageType; + }; +#pragma pack(pop) + + /** + * @return BGP message type + */ + virtual BgpMessageType getBgpMessageType() const = 0; + + /** + * @return BGP message type as string. Return value can be one of the following: + * "OPEN", "UPDATE", "NOTIFICATION", "KEEPALIVE", "ROUTE-REFRESH", "Unknown" + */ + std::string getMessageTypeAsString() const; + + /** + * A static method that checks whether a source or dest port match those associated with the BGP protocol + * @param[in] portSrc Source port number to check + * @param[in] portDst Dest port number to check + * @return True if the source or dest port match those associated with the BGP protocol + */ + static bool isBgpPort(uint16_t portSrc, uint16_t portDst) + { + return portSrc == 179 || portDst == 179; + } + + /** + * A method that creates a BGP layer from packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored + * @return A newly allocated BGP layer of one of the following types (according to the message type): + * BgpOpenMessageLayer, BgpUpdateMessageLayer, BgpNotificationMessageLayer, BgpKeepaliveMessageLayer, + * BgpRouteRefreshMessageLayer + */ + static BgpLayer* parseBgpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + // implement abstract methods + + /** + * @return The size of the BGP message + */ + size_t getHeaderLen() const; + + /** + * Multiple BGP messages can reside in a single packet, and the only layer that can come after a BGP message + * is another BGP message. This method checks for remaining data and parses it as another BGP layer + */ + void parseNextLayer(); + + std::string toString() const; + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelApplicationLayer; + } + + /** + * Calculates the basic BGP fields: + * - Set marker to all ones + * - Set message type value + * - Set message length + */ + void computeCalculateFields(); + + protected: + // protected c'tors, this class cannot be instantiated by users + BgpLayer() + {} + BgpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : Layer(data, dataLen, prevLayer, packet, BGP) + {} + + bgp_common_header* getBasicHeader() const + { + return (bgp_common_header*)m_Data; + } + + void setBgpFields(size_t messageLen = 0); + }; + + /** + * @class BgpOpenMessageLayer + * Represents a BGP v4 OPEN message + */ + class BgpOpenMessageLayer : public BgpLayer + { + public: +#pragma pack(push, 1) + /** + * @struct bgp_open_message + * BGP OPEN message structure + */ + typedef struct bgp_open_message : bgp_common_header + { + /** BGP version number */ + uint8_t version; + /** Autonomous System number of the sender */ + uint16_t myAutonomousSystem; + /** The number of seconds the sender proposes for the value of the Hold Timer */ + uint16_t holdTime; + /** BGP Identifier of the sender */ + uint32_t bgpId; + /** The total length of the Optional Parameters field */ + uint8_t optionalParameterLength; + } bgp_open_message; +#pragma pack(pop) + + /** + * @struct optional_parameter + * A structure that represents BGP OPEN message optional parameters + */ + struct optional_parameter + { + /** Parameter type */ + uint8_t type; + /** Parameter length */ + uint8_t length; + /** Parameter data */ + uint8_t value[32]; + + /** + * A default c'tor that zeroes all data + */ + optional_parameter() + {} + + /** + * A c'tor that initializes the values of the struct + * @param[in] typeVal Parameter type value + * @param[in] valueAsHexString Parameter data as hex string. The length field will be set accordingly. + * If this parameter is not a valid hex string the data will remain zeroed and length will be also zero + */ + optional_parameter(uint8_t typeVal, const std::string& valueAsHexString); + }; + + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + BgpOpenMessageLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : BgpLayer(data, dataLen, prevLayer, packet) + {} + + /** + * A c'tor that creates a new BGP OPEN message + * @param[in] myAutonomousSystem The Autonomous System number of the sender + * @param[in] holdTime The number of seconds the sender proposes for the value of the Hold Timer + * @param[in] bgpId The BGP Identifier of the sender + * @param[in] optionalParams A vector of optional parameters. This parameter is optional and if not provided no + * parameters will be set on the message + */ + BgpOpenMessageLayer(uint16_t myAutonomousSystem, uint16_t holdTime, const IPv4Address& bgpId, + const std::vector& optionalParams = std::vector()); + + /** + * Get a pointer to the open message data. Notice this points directly to the data, so any change will modify + * the actual packet data + * @return A pointer to a bgp_open_message structure containing the data + */ + bgp_open_message* getOpenMsgHeader() const + { + return (bgp_open_message*)m_Data; + } + + /** + * @return The BGP identifier as IPv4Address object + */ + IPv4Address getBgpId() const + { + return IPv4Address(getOpenMsgHeader()->bgpId); + } + + /** + * Set the BGP identifier + * @param[in] newBgpId BGP identifier to set. If value is not a valid IPv4 address it won't be set + */ + void setBgpId(const IPv4Address& newBgpId); + + /** + * Get a vector of the optional parameters in the message + * @param[out] optionalParameters The vector where the optional parameters will be written to. This method + * doesn't remove any existing data on this vector before pushing data to it + */ + void getOptionalParameters(std::vector& optionalParameters); + + /** + * @return The length in [bytes] of the optional parameters data in the message + */ + size_t getOptionalParametersLength(); + + /** + * Set optional parameters in the message. This method will override all existing optional parameters currently + * in the message. If the input is an empty vector all optional parameters will be cleared. This method + * automatically sets the bgp_common_header#length and the bgp_open_message#optionalParameterLength fields on + * the message + * @param[in] optionalParameters A vector of new optional parameters to set in the message + * @return True if all optional parameters were set successfully or false otherwise. In case of an error an + * appropriate message will be printed to log + */ + bool setOptionalParameters(const std::vector& optionalParameters); + + /** + * Clear all optional parameters currently in the message. This is equivalent to calling setOptionalParameters() + * with an empty vector as a parameter + * @return True if all optional parameters were successfully cleared or false otherwise. In case of an error an + * appropriate message will be printed to log + */ + bool clearOptionalParameters(); + + // implement abstract methods + + BgpMessageType getBgpMessageType() const + { + return BgpLayer::Open; + } + + private: + size_t optionalParamsToByteArray(const std::vector& optionalParams, uint8_t* resultByteArr, + size_t maxByteArrSize); + }; + + /** + * @class BgpUpdateMessageLayer + * Represents a BGP v4 UPDATE message + */ + class BgpUpdateMessageLayer : public BgpLayer + { + public: + /** + * @struct prefix_and_ip + * A structure that contains IPv4 address and IP address mask (prefix) information. + * It's used to represent BGP Withdrawn Routes and Network Layer Reachability Information (NLRI) + */ + struct prefix_and_ip + { + /** IPv4 address mask, must contain one of the values: 8, 16, 24, 32 */ + uint8_t prefix; + /** IPv4 address */ + IPv4Address ipAddr; + + /** + * A default c'tor that zeroes all data + */ + prefix_and_ip() : prefix(0), ipAddr(IPv4Address::Zero) + {} + + /** + * A c'tor that initializes the values of the struct + * @param[in] prefixVal IPv4 address mask value + * @param[in] ipAddrVal IPv4 address + */ + prefix_and_ip(uint8_t prefixVal, const std::string& ipAddrVal) : prefix(prefixVal), ipAddr(ipAddrVal) + {} + }; + + /** + * @struct path_attribute + * A structure that represents BGP OPEN message Path Attributes information + */ + struct path_attribute + { + /** Path attribute flags */ + uint8_t flags; + /** Path attribute type */ + uint8_t type; + /** Path attribute length */ + uint8_t length; + /** Path attribute data. Max supported data length is 32 bytes */ + uint8_t data[32]; + + /** + * A default c'tor that zeroes all data + */ + path_attribute() + {} + + /** + * A c'tor that initializes the values of the struct + * @param[in] flagsVal Path attribute flags value + * @param[in] typeVal Path attribute type value + * @param[in] dataAsHexString Path attribute data as hex string. The path_attribute#length field will be set + * accordingly. If this parameter is not a valid hex string the data will remain zeroed and length will be + * also set to zero + */ + path_attribute(uint8_t flagsVal, uint8_t typeVal, const std::string& dataAsHexString); + }; + + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + BgpUpdateMessageLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : BgpLayer(data, dataLen, prevLayer, packet) + {} + + /** + * A static method that takes a byte array and detects whether it is a BgpUpdateMessage + * @param[in] data A byte array + * @param[in] dataSize The byte array size (in bytes) + * @return True if the data looks like a valid BgpUpdateMessage layer + */ + static bool isDataValid(const uint8_t* data, size_t dataSize); + + /** + * A c'tor that creates a new BGP UPDATE message + * @param[in] withdrawnRoutes A vector of withdrawn routes data. If left empty (which is the default value) no + * withdrawn route information will be written to the message + * @param[in] pathAttributes A vector of path attributes data. If left empty (which is the default value) no + * path attribute information will be written to the message + * @param[in] nlri A vector of network layer reachability data. If left empty (which is the default value) no + * reachability information will be written to the message + */ + explicit BgpUpdateMessageLayer( + const std::vector& withdrawnRoutes = std::vector(), + const std::vector& pathAttributes = std::vector(), + const std::vector& nlri = std::vector()); + + /** + * Get a pointer to the basic BGP message data. Notice this points directly to the data, so any change will + * modify the actual packet data + * @return A pointer to a bgp_common_header structure containing the data + */ + bgp_common_header* getBasicMsgHeader() const + { + return (bgp_common_header*)m_Data; + } + + /** + * @return The size in [bytes] of the Withdrawn Routes data + */ + size_t getWithdrawnRoutesLength() const; + + /** + * Get a vector of the Withdrawn Routes currently in the message + * @param[out] withdrawnRoutes A reference to a vector the Withdrawn Routes data will be written to + */ + void getWithdrawnRoutes(std::vector& withdrawnRoutes); + + /** + * Set Withdrawn Routes in this message. This method will override any existing Withdrawn Routes in the message. + * If the input is an empty vector all Withdrawn Routes will be removed. This method automatically sets the + * bgp_common_header#length and the Withdrawn Routes length fields in the message + * @param[in] withdrawnRoutes New Withdrawn Routes to set in the message + * @return True if all Withdrawn Routes were set successfully or false otherwise. In case of an error an + * appropriate message will be printed to log + */ + bool setWithdrawnRoutes(const std::vector& withdrawnRoutes); + + /** + * Clear all Withdrawn Routes data currently in the message. This is equivalent to calling setWithdrawnRoutes() + * with an empty vector as a parameter + * @return True if all Withdrawn Routes were successfully cleared or false otherwise. In case of an error an + * appropriate message will be printed to log + */ + bool clearWithdrawnRoutes(); + + /** + * @return The size in [bytes] of the Path Attributes data + */ + size_t getPathAttributesLength() const; + + /** + * Get a vector of the Path Attributes currently in the message + * @param[out] pathAttributes A reference to a vector the Path Attributes data will be written to + */ + void getPathAttributes(std::vector& pathAttributes); + + /** + * Set Path Attributes in this message. This method will override any existing Path Attributes in the message. + * If the input is an empty vector all Path Attributes will be removed. This method automatically sets the + * bgp_common_header#length and the Path Attributes length fields in the message + * @param[in] pathAttributes New Path Attributes to set in the message + * @return True if all Path Attributes were set successfully or false otherwise. In case of an error an + * appropriate message will be printed to log + */ + bool setPathAttributes(const std::vector& pathAttributes); + + /** + * Clear all Path Attributes data currently in the message. This is equivalent to calling setPathAttributes() + * with an empty vector as a parameter + * @return True if all Path Attributes were successfully cleared or false otherwise. In case of an error an + * appropriate message will be printed to log + */ + bool clearPathAttributes(); + + /** + * @return The size in [bytes] of the Network Layer Reachability Info + */ + size_t getNetworkLayerReachabilityInfoLength() const; + + /** + * Get a vector of the Network Layer Reachability Info currently in the message + * @param[out] nlri A reference to a vector the NLRI data will be written to + */ + void getNetworkLayerReachabilityInfo(std::vector& nlri); + + /** + * Set NLRI data in this message. This method will override any existing NLRI data in the message. + * If the input is an empty vector all NLRI data will be removed. This method automatically sets the + * bgp_common_header#length field in the message + * @param[in] nlri New NLRI data to set in the message + * @return True if all NLRI data was set successfully or false otherwise. In case of an error an appropriate + * message will be printed to log + */ + bool setNetworkLayerReachabilityInfo(const std::vector& nlri); + + /** + * Clear all NLRI data currently in the message. This is equivalent to calling setNetworkLayerReachabilityInfo() + * with an empty vector as a parameter + * @return True if all NLRI were successfully cleared or false otherwise. In case of an error an appropriate + * message will be printed to log + */ + bool clearNetworkLayerReachabilityInfo(); + + // implement abstract methods + + BgpMessageType getBgpMessageType() const + { + return BgpLayer::Update; + } + + private: + void parsePrefixAndIPData(uint8_t* dataPtr, size_t dataLen, std::vector& result); + + size_t prefixAndIPDataToByteArray(const std::vector& prefixAndIpData, uint8_t* resultByteArr, + size_t maxByteArrSize); + + size_t pathAttributesToByteArray(const std::vector& pathAttributes, uint8_t* resultByteArr, + size_t maxByteArrSize); + }; + + /** + * @class BgpNotificationMessageLayer + * Represents a BGP v4 NOTIFICATION message + */ + class BgpNotificationMessageLayer : public BgpLayer + { + public: +#pragma pack(push, 1) + /** + * @struct bgp_notification_message + * BGP NOTIFICATION message structure + */ + typedef struct bgp_notification_message : bgp_common_header + { + /** BGP notification error code */ + uint8_t errorCode; + /** BGP notification error sub-code */ + uint8_t errorSubCode; + } bgp_notification_message; +#pragma pack(pop) + + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + BgpNotificationMessageLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : BgpLayer(data, dataLen, prevLayer, packet) + {} + + /** + * A c'tor that creates a new BGP NOTIFICATION message + * @param[in] errorCode BGP notification error code + * @param[in] errorSubCode BGP notification error sub code + */ + BgpNotificationMessageLayer(uint8_t errorCode, uint8_t errorSubCode); + + /** + * A c'tor that creates a new BGP Notification message + * @param[in] errorCode BGP notification error code + * @param[in] errorSubCode BGP notification error sub code + * @param[in] notificationData A byte array that contains the notification data + * @param[in] notificationDataLen The size of the byte array that contains the notification data + */ + BgpNotificationMessageLayer(uint8_t errorCode, uint8_t errorSubCode, const uint8_t* notificationData, + size_t notificationDataLen); + + /** + * A c'tor that creates a new BGP Notification message + * @param[in] errorCode BGP notification error code + * @param[in] errorSubCode BGP notification error sub code + * @param[in] notificationData A hex string that contains the notification data. This string will be converted + * to a byte array that will be added to the message. If the input isn't a valid hex string notification data + * will remain empty and an error will be printed to log + */ + BgpNotificationMessageLayer(uint8_t errorCode, uint8_t errorSubCode, const std::string& notificationData); + + /** + * Get a pointer to the notification message data. Notice this points directly to the data, so any change will + * modify the actual packet data + * @return A pointer to a bgp_notification_message structure containing the data + */ + bgp_notification_message* getNotificationMsgHeader() const + { + return (bgp_notification_message*)m_Data; + } + + /** + * @return The size in [bytes] of the notification data. Notification data is a variable-length field used to + * diagnose the reason for the BGP NOTIFICATION + */ + size_t getNotificationDataLen() const; + + /** + * @return A pointer to the notification data. Notification data is a variable-length field used to diagnose the + * reason for the BGP NOTIFICATION + */ + uint8_t* getNotificationData() const; + + /** + * @return A hex string which represents the notification data. Notification data is a variable-length field + * used to diagnose the reason for the BGP NOTIFICATION + */ + std::string getNotificationDataAsHexString() const; + + /** + * Set the notification data. This method will extend or shorten the existing layer to include the new + * notification data. If newNotificationData is nullptr or newNotificationDataLen is zero then notification data + * will be set to none. + * @param[in] newNotificationData A byte array containing the new notification data + * @param[in] newNotificationDataLen The size of the byte array + * @return True if notification data was set successfully or false if any error occurred. In case of an error an + * appropriate error message will be printed to log + */ + bool setNotificationData(const uint8_t* newNotificationData, size_t newNotificationDataLen); + + /** + * Set the notification data. This method will extend or shorten the existing layer to include the new + * notification data. If newNotificationDataAsHexString is an empty string then notification data will be set to + * none. + * @param[in] newNotificationDataAsHexString A hex string representing the new notification data. If the string + * is not a valid hex string no data will be changed and an error will be returned + * @return True if notification data was set successfully or false if any error occurred or if the string is not + * a valid hex string. In case of an error an appropriate error message will be printed to log + */ + bool setNotificationData(const std::string& newNotificationDataAsHexString); + + // implement abstract methods + + BgpMessageType getBgpMessageType() const + { + return BgpLayer::Notification; + } + + private: + void initMessageData(uint8_t errorCode, uint8_t errorSubCode, const uint8_t* notificationData, + size_t notificationDataLen); + }; + + /** + * @class BgpKeepaliveMessageLayer + * Represents a BGP v4 KEEPALIVE message + */ + class BgpKeepaliveMessageLayer : public BgpLayer + { + public: + /** + * @typedef bgp_keepalive_message + * BGP KEEPALIVE message structure + */ + typedef bgp_common_header bgp_keepalive_message; + + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + BgpKeepaliveMessageLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : BgpLayer(data, dataLen, prevLayer, packet) + {} + + /** + * A c'tor that creates a new BGP KEEPALIVE message + */ + BgpKeepaliveMessageLayer(); + + /** + * Get a pointer to the KeepAlive message data. Notice this points directly to the data, so any change will + * modify the actual packet data + * @return A pointer to a bgp_keepalive_message structure containing the data + */ + bgp_keepalive_message* getKeepaliveHeader() const + { + return (bgp_keepalive_message*)getBasicHeader(); + } + + // implement abstract methods + + BgpMessageType getBgpMessageType() const + { + return BgpLayer::Keepalive; + } + }; + + /** + * @class BgpRouteRefreshMessageLayer + * Represents a BGP v4 ROUTE-REFRESH message + */ + class BgpRouteRefreshMessageLayer : public BgpLayer + { + public: +#pragma pack(push, 1) + /** + * @struct bgp_route_refresh_message + * BGP ROUTE-REFRESH message structure + */ + typedef struct bgp_route_refresh_message : bgp_common_header + { + /** Address Family Identifier */ + uint16_t afi; + /** Reserved field */ + uint8_t reserved; + /** Subsequent Address Family Identifier */ + uint8_t safi; + } bgp_route_refresh_message; +#pragma pack(pop) + + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + BgpRouteRefreshMessageLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : BgpLayer(data, dataLen, prevLayer, packet) + {} + + /** + * A c'tor that creates a new BGP ROUTE-REFRESH message + * @param[in] afi The Address Family Identifier (AFI) value to set in the message + * @param[in] safi The Subsequent Address Family Identifier (SAFI) value to set in the message + */ + BgpRouteRefreshMessageLayer(uint16_t afi, uint8_t safi); + + /** + * Get a pointer to the ROUTE-REFRESH message data. Notice this points directly to the data, so any change will + * modify the actual packet data + * @return A pointer to a bgp_route_refresh_message structure containing the data + */ + bgp_route_refresh_message* getRouteRefreshHeader() const + { + return (bgp_route_refresh_message*)getBasicHeader(); + } + + // implement abstract methods + + BgpMessageType getBgpMessageType() const + { + return BgpLayer::RouteRefresh; + } + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/CotpLayer.h b/Packet++/header/pcapplusplus/CotpLayer.h new file mode 100644 index 0000000000..810f7ec629 --- /dev/null +++ b/Packet++/header/pcapplusplus/CotpLayer.h @@ -0,0 +1,126 @@ +#pragma once + +#include "pcapplusplus/EthLayer.h" +#include "pcapplusplus/Layer.h" + +namespace pcpp +{ + +/** + * @struct cotphdr + * Represents a COTP protocol header + */ +#pragma pack(push, 1) + typedef struct + { + /** length */ + uint8_t length; + /** PDU type identifier */ + uint8_t pduType; + /** TPDU number sequence*/ + uint8_t tpduNumber; + } cotphdr; +#pragma pack(pop) + + /** + * @class CotpLayer + * Represents a COTP (Connection Oriented Transport Protocol) + */ + class CotpLayer : public Layer + { + public: + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data (will be casted to @ref cotphdr) + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + CotpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : Layer(data, dataLen, prevLayer, packet, COTP) + {} + + /** + * A constructor that allocates a new COTP header + * @param[in] tpduNumber Protocol TPDU number + */ + explicit CotpLayer(uint8_t tpduNumber); + + virtual ~CotpLayer() + {} + + /** + * @return COTP length + */ + uint8_t getLength() const; + + /** + * @return COTP PDU type + */ + uint8_t getPduType() const; + + /** + * @return COTP TPDU number + */ + uint8_t getTpduNumber() const; + + /** + * @return Size of @ref cotphdr + */ + size_t getHeaderLen() const override + { + return sizeof(cotphdr); + } + + /** + * Set the value of the length + * @param[in] length The value of the length + */ + void setLength(uint8_t length) const; + + /** + * Set the value of the version + * @param[in] pduType The number of the PDU type + */ + void setPduType(uint8_t pduType) const; + + /** + * Set the value of the version + * @param[in] tpduNumber The value of the TPDU number + */ + void setTpduNumber(uint8_t tpduNumber) const; + + /** + * Does nothing for this layer + */ + void computeCalculateFields() override + {} + + /** + * Currently parses the rest of the packet as a S7COMM or generic payload (PayloadLayer) + */ + void parseNextLayer() override; + + /** + * A static method that takes a byte array and detects whether it is a COTP + * @param[in] data A byte array + * @param[in] dataSize The byte array size (in bytes) + * @return True if the data looks like a valid COTP layer + */ + static bool isDataValid(const uint8_t* data, size_t dataSize); + + std::string toString() const override; + + OsiModelLayer getOsiModelLayer() const override + { + return OsiModelTransportLayer; + } + + private: + cotphdr* getCotpHeader() const + { + return (cotphdr*)m_Data; + } + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/DhcpLayer.h b/Packet++/header/pcapplusplus/DhcpLayer.h new file mode 100644 index 0000000000..98601f745a --- /dev/null +++ b/Packet++/header/pcapplusplus/DhcpLayer.h @@ -0,0 +1,888 @@ +#pragma once + +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/TLVData.h" +#include "pcapplusplus/IpAddress.h" +#include "pcapplusplus/MacAddress.h" +#include + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + +/** + * @struct dhcp_header + * Represents a DHCP protocol header + */ +#pragma pack(push, 1) + struct dhcp_header + { + /** BootP opcode */ + uint8_t opCode; + /** Hardware type, set to 1 (Ethernet) by default */ + uint8_t hardwareType; + /** Hardware address length, set to 6 (MAC address length) by default */ + uint8_t hardwareAddressLength; + /** Hop count */ + uint8_t hops; + /** DHCP/BootP transaction ID */ + uint32_t transactionID; + /** The elapsed time, in seconds since the client sent its first BOOTREQUEST message */ + uint16_t secondsElapsed; + /** BootP flags */ + uint16_t flags; + /** Client IPv4 address */ + uint32_t clientIpAddress; + /** Your IPv4 address */ + uint32_t yourIpAddress; + /** Server IPv4 address */ + uint32_t serverIpAddress; + /** Gateway IPv4 address */ + uint32_t gatewayIpAddress; + /** Client hardware address, by default contains the MAC address (only 6 first bytes are used) */ + uint8_t clientHardwareAddress[16]; + /** BootP server name */ + uint8_t serverName[64]; + /** BootP boot file name */ + uint8_t bootFilename[128]; + /** DHCP magic number (set to the default value of 0x63538263) */ + uint32_t magicNumber; + }; +#pragma pack(pop) + + /** + * BootP opcodes + */ + enum BootpOpCodes + { + /** BootP request */ + DHCP_BOOTREQUEST = 1, + /** BootP reply */ + DHCP_BOOTREPLY = 2 + }; + + /** + * DHCP message types + */ + enum DhcpMessageType + { + /** Unknown message type */ + DHCP_UNKNOWN_MSG_TYPE = 0, + /** Discover message type */ + DHCP_DISCOVER = 1, + /** Offer message type */ + DHCP_OFFER = 2, + /** Request message type */ + DHCP_REQUEST = 3, + /** Decline message type */ + DHCP_DECLINE = 4, + /** Acknowledge message type */ + DHCP_ACK = 5, + /** Non-acknowledge message type */ + DHCP_NAK = 6, + /** Release message type */ + DHCP_RELEASE = 7, + /** Inform message type */ + DHCP_INFORM = 8 + }; + + /** + * DHCP option types. + */ + enum DhcpOptionTypes + { + /** Unknown option type */ + DHCPOPT_UNKNOWN = -1, + /** Pad */ + DHCPOPT_PAD = 0, + /** Subnet Mask Value */ + DHCPOPT_SUBNET_MASK = 1, + /** Time Offset in Seconds from UTC */ + DHCPOPT_TIME_OFFSET = 2, + /** N/4 Router addresses */ + DHCPOPT_ROUTERS = 3, + /** N/4 Timeserver addresses */ + DHCPOPT_TIME_SERVERS = 4, + /** N/4 IEN-116 Server addresses */ + DHCPOPT_NAME_SERVERS = 5, + /** N/4 DNS Server addresses */ + DHCPOPT_DOMAIN_NAME_SERVERS = 6, + /** N/4 Logging Server addresses */ + DHCPOPT_LOG_SERVERS = 7, + /** N/4 Quotes Server addresses */ + DHCPOPT_QUOTES_SERVERS = 8, + /** N/4 Quotes Server addresses */ + DHCPOPT_LPR_SERVERS = 9, + /** N/4 Quotes Server addresses */ + DHCPOPT_IMPRESS_SERVERS = 10, + /** N/4 RLP Server addresses */ + DHCPOPT_RESOURCE_LOCATION_SERVERS = 11, + /** Hostname string */ + DHCPOPT_HOST_NAME = 12, + /** Size of boot file in 512 byte chunks */ + DHCPOPT_BOOT_SIZE = 13, + /** Client to dump and name the file to dump it to */ + DHCPOPT_MERIT_DUMP = 14, + /** The DNS domain name of the client */ + DHCPOPT_DOMAIN_NAME = 15, + /** Swap Server address */ + DHCPOPT_SWAP_SERVER = 16, + /** Path name for root disk */ + DHCPOPT_ROOT_PATH = 17, + /** Path name for more BOOTP info */ + DHCPOPT_EXTENSIONS_PATH = 18, + /** Enable/Disable IP Forwarding */ + DHCPOPT_IP_FORWARDING = 19, + /** Enable/Disable Source Routing */ + DHCPOPT_NON_LOCAL_SOURCE_ROUTING = 20, + /** Routing Policy Filters */ + DHCPOPT_POLICY_FILTER = 21, + /** Max Datagram Reassembly Size */ + DHCPOPT_MAX_DGRAM_REASSEMBLY = 22, + /** Default IP Time to Live */ + DEFAULT_IP_TTL = 23, + /** Path MTU Aging Timeout */ + DHCPOPT_PATH_MTU_AGING_TIMEOUT = 24, + /** Path MTU Plateau Table */ + PATH_MTU_PLATEAU_TABLE = 25, + /** Interface MTU Size */ + DHCPOPT_INTERFACE_MTU = 26, + /** All Subnets are Local */ + DHCPOPT_ALL_SUBNETS_LOCAL = 27, + /** Broadcast Address */ + DHCPOPT_BROADCAST_ADDRESS = 28, + /** Perform Mask Discovery */ + DHCPOPT_PERFORM_MASK_DISCOVERY = 29, + /** Provide Mask to Others */ + DHCPOPT_MASK_SUPPLIER = 30, + /** Perform Router Discovery */ + DHCPOPT_ROUTER_DISCOVERY = 31, + /** Router Solicitation Address */ + DHCPOPT_ROUTER_SOLICITATION_ADDRESS = 32, + /** Static Routing Table */ + DHCPOPT_STATIC_ROUTES = 33, + /** Trailer Encapsulation */ + DHCPOPT_TRAILER_ENCAPSULATION = 34, + /** ARP Cache Timeout */ + DHCPOPT_ARP_CACHE_TIMEOUT = 35, + /** IEEE802.3 Encapsulation */ + DHCPOPT_IEEE802_3_ENCAPSULATION = 36, + /** Default TCP Time to Live */ + DHCPOPT_DEFAULT_TCP_TTL = 37, + /** TCP Keepalive Interval */ + DHCPOPT_TCP_KEEPALIVE_INTERVAL = 38, + /** TCP Keepalive Garbage */ + DHCPOPT_TCP_KEEPALIVE_GARBAGE = 39, + /** NIS Domain Name */ + DHCPOPT_NIS_DOMAIN = 40, + /** NIS Server Addresses */ + DHCPOPT_NIS_SERVERS = 41, + /** NTP Server Addresses */ + DHCPOPT_NTP_SERVERS = 42, + /** Vendor Specific Information */ + DHCPOPT_VENDOR_ENCAPSULATED_OPTIONS = 43, + /** NETBIOS Name Servers */ + DHCPOPT_NETBIOS_NAME_SERVERS = 44, + /** NETBIOS Datagram Distribution */ + DHCPOPT_NETBIOS_DD_SERVER = 45, + /** NETBIOS Node Type */ + DHCPOPT_NETBIOS_NODE_TYPE = 46, + /** NETBIOS Scope */ + DHCPOPT_NETBIOS_SCOPE = 47, + /** X Window Font Server */ + DHCPOPT_FONT_SERVERS = 48, + /** X Window Display Manager */ + DHCPOPT_X_DISPLAY_MANAGER = 49, + /** Requested IP Address */ + DHCPOPT_DHCP_REQUESTED_ADDRESS = 50, + /** IP Address Lease Time */ + DHCPOPT_DHCP_LEASE_TIME = 51, + /** Overload "sname" or "file" */ + DHCPOPT_DHCP_OPTION_OVERLOAD = 52, + /** DHCP Message Type */ + DHCPOPT_DHCP_MESSAGE_TYPE = 53, + /** DHCP Server Identification */ + DHCPOPT_DHCP_SERVER_IDENTIFIER = 54, + /** Parameter Request List */ + DHCPOPT_DHCP_PARAMETER_REQUEST_LIST = 55, + /** DHCP Error Message */ + DHCPOPT_DHCP_MESSAGE = 56, + /** DHCP Maximum Message Size */ + DHCPOPT_DHCP_MAX_MESSAGE_SIZE = 57, + /** DHCP Renewal (T1) Time */ + DHCPOPT_DHCP_RENEWAL_TIME = 58, + /** DHCP Rebinding (T2) Time */ + DHCPOPT_DHCP_REBINDING_TIME = 59, + /** Class Identifier */ + DHCPOPT_VENDOR_CLASS_IDENTIFIER = 60, + /** Class Identifier */ + DHCPOPT_DHCP_CLIENT_IDENTIFIER = 61, + /** NetWare/IP Domain Name */ + DHCPOPT_NWIP_DOMAIN_NAME = 62, + /** NetWare/IP sub Options */ + DHCPOPT_NWIP_SUBOPTIONS = 63, + /** NIS+ v3 Client Domain Name */ + DHCPOPT_NIS_DOMAIN_NAME = 64, + /** NIS+ v3 Server Addresses */ + DHCPOPT_NIS_SERVER_ADDRESS = 65, + /** TFTP Server Name */ + DHCPOPT_TFTP_SERVER_NAME = 66, + /** Boot File Name */ + DHCPOPT_BOOTFILE_NAME = 67, + /** Home Agent Addresses */ + DHCPOPT_HOME_AGENT_ADDRESS = 68, + /** Simple Mail Server (SMTP) Addresses */ + DHCPOPT_SMTP_SERVER = 69, + /** Post Office (POP3) Server Addresses */ + DHCPOPT_POP3_SERVER = 70, + /** Network News (NNTP) Server Addresses */ + DHCPOPT_NNTP_SERVER = 71, + /** WWW Server Addresses */ + DHCPOPT_WWW_SERVER = 72, + /** Finger Server Addresses */ + DHCPOPT_FINGER_SERVER = 73, + /** Chat (IRC) Server Addresses */ + DHCPOPT_IRC_SERVER = 74, + /** StreetTalk Server Addresses */ + DHCPOPT_STREETTALK_SERVER = 75, + /** ST Directory Assist. Addresses */ + DHCPOPT_STDA_SERVER = 76, + /** User Class Information */ + DHCPOPT_USER_CLASS = 77, + /** Directory Agent Information */ + DHCPOPT_DIRECTORY_AGENT = 78, + /** Service Location Agent Scope */ + DHCPOPT_SERVICE_SCOPE = 79, + /** Rapid Commit */ + DHCPOPT_RAPID_COMMIT = 80, + /** Fully Qualified Domain Name */ + DHCPOPT_FQDN = 81, + /** Relay Agent Information */ + DHCPOPT_DHCP_AGENT_OPTIONS = 82, + /** Internet Storage Name Service */ + DHCPOPT_ISNS = 83, + /** Novell Directory Services */ + DHCPOPT_NDS_SERVERS = 85, + /** Novell Directory Services */ + DHCPOPT_NDS_TREE_NAME = 86, + /** Novell Directory Services */ + DHCPOPT_NDS_CONTEXT = 87, + /** BCMCS Controller Domain Name list */ + DHCPOPT_BCMCS_CONTROLLER_DOMAIN_NAME_LIST = 88, + /** BCMCS Controller IPv4 address option */ + DHCPOPT_BCMCS_CONTROLLER_IPV4_ADDRESS = 89, + /** Authentication */ + DHCPOPT_AUTHENTICATION = 90, + /** Client Last Transaction Time */ + DHCPOPT_CLIENT_LAST_TXN_TIME = 91, + /** Associated IP */ + DHCPOPT_ASSOCIATED_IP = 92, + /** Client System Architecture */ + DHCPOPT_CLIENT_SYSTEM = 93, + /** Client Network Device Interface */ + DHCPOPT_CLIENT_NDI = 94, + /** Lightweight Directory Access Protocol [ */ + DHCPOPT_LDAP = 95, + /** UUID/GUID-based Client Identifier */ + DHCPOPT_UUID_GUID = 97, + /** Open Group's User Authentication */ + DHCPOPT_USER_AUTH = 98, + /** GEOCONF_CIVIC */ + DHCPOPT_GEOCONF_CIVIC = 99, + /** IEEE 1003.1 TZ String */ + DHCPOPT_PCODE = 100, + /** Reference to the TZ Database */ + DHCPOPT_TCODE = 101, + /** NetInfo Parent Server Address */ + DHCPOPT_NETINFO_ADDRESS = 112, + /** NetInfo Parent Server Tag */ + DHCPOPT_NETINFO_TAG = 113, + /** URL */ + DHCPOPT_URL = 114, + /** DHCP Auto-Configuration */ + DHCPOPT_AUTO_CONFIG = 116, + /** Name Service Search */ + DHCPOPT_NAME_SERVICE_SEARCH = 117, + /** Subnet Selection Option */ + DHCPOPT_SUBNET_SELECTION = 118, + /** DNS Domain Search List */ + DHCPOPT_DOMAIN_SEARCH = 119, + /** SIP Servers DHCP Option */ + DHCPOPT_SIP_SERVERS = 120, + /** Classless Static Route Option */ + DHCPOPT_CLASSLESS_STATIC_ROUTE = 121, + /** CableLabs Client Configuration */ + DHCPOPT_CCC = 122, + /** GeoConf Option */ + DHCPOPT_GEOCONF = 123, + /** Vendor-Identifying Vendor Class */ + DHCPOPT_V_I_VENDOR_CLASS = 124, + /** Vendor-Identifying Vendor-Specific Information */ + DHCPOPT_V_I_VENDOR_OPTS = 125, + /** OPTION_PANA_AGENT */ + DHCPOPT_OPTION_PANA_AGENT = 136, + /** OPTION_V4_LOST */ + DHCPOPT_OPTION_V4_LOST = 137, + /** CAPWAP Access Controller addresses */ + DHCPOPT_OPTION_CAPWAP_AC_V4 = 138, + /** A Series Of Suboptions */ + DHCPOPT_OPTION_IPV4_ADDRESS_MOS = 139, + /** A Series Of Suboptions */ + DHCPOPT_OPTION_IPV4_FQDN_MOS = 140, + /** List of domain names to search for SIP User Agent Configuration */ + DHCPOPT_SIP_UA_CONFIG = 141, + /** ANDSF IPv4 Address Option for DHCPv4 */ + DHCPOPT_OPTION_IPV4_ADDRESS_ANDSF = 142, + /** Geospatial Location with Uncertainty [RF */ + DHCPOPT_GEOLOC = 144, + /** Forcerenew Nonce Capable */ + DHCPOPT_FORCERENEW_NONCE_CAPABLE = 145, + /** Information for selecting RDNSS */ + DHCPOPT_RDNSS_SELECTION = 146, + /** Status code and optional N byte text message describing status */ + DHCPOPT_STATUS_CODE = 151, + /** Absolute time (seconds since Jan 1, 1970) message was sent */ + DHCPOPT_BASE_TIME = 152, + /** Number of seconds in the past when client entered current state */ + DHCPOPT_START_TIME_OF_STATE = 153, + /** Absolute time (seconds since Jan 1, 1970) for beginning of query */ + DHCPOPT_QUERY_START_TIME = 154, + /** Absolute time (seconds since Jan 1, 1970) for end of query */ + DHCPOPT_QUERY_END_TIME = 155, + /** State of IP address */ + DHCPOPT_DHCP_STATE = 156, + /** Indicates information came from local or remote server */ + DHCPOPT_DATA_SOURCE = 157, + /** Includes one or multiple lists of PCP server IP addresses; each list is treated as a separate PCP server */ + DHCPOPT_OPTION_V4_PCP_SERVER = 158, + /** This option is used to configure a set of ports bound to a shared IPv4 address */ + DHCPOPT_OPTION_V4_PORTPARAMS = 159, + /** DHCP Captive-Portal */ + DHCPOPT_CAPTIVE_PORTAL = 160, + /** Manufacturer Usage Descriptions */ + DHCPOPT_OPTION_MUD_URL_V4 = 161, + /** Etherboot */ + DHCPOPT_ETHERBOOT = 175, + /** IP Telephone */ + DHCPOPT_IP_TELEPHONE = 176, + /** Magic string = F1:00:74:7E */ + DHCPOPT_PXELINUX_MAGIC = 208, + /** Configuration file */ + DHCPOPT_CONFIGURATION_FILE = 209, + /** Path Prefix Option */ + DHCPOPT_PATH_PREFIX = 210, + /** Reboot Time */ + DHCPOPT_REBOOT_TIME = 211, + /** OPTION_6RD with N/4 6rd BR addresses */ + DHCPOPT_OPTION_6RD = 212, + /** Access Network Domain Name */ + DHCPOPT_OPTION_V4_ACCESS_DOMAIN = 213, + /** Subnet Allocation Option */ + DHCPOPT_SUBNET_ALLOCATION = 220, + /** Virtual Subnet Selection (VSS) Option */ + DHCPOPT_VIRTUAL_SUBNET_SELECTION = 221, + /** End (last option) */ + DHCPOPT_END = 255 + }; + + /** + * @class DhcpOption + * A wrapper class for DHCP options. This class does not create or modify DHCP option records, but rather + * serves as a wrapper and provides useful methods for setting and retrieving data to/from them + */ + class DhcpOption : public TLVRecord + { + public: + /** + * A c'tor for this class that gets a pointer to the option raw data (byte array) + * @param[in] optionRawData A pointer to the option raw data + */ + explicit DhcpOption(uint8_t* optionRawData) : TLVRecord(optionRawData) + {} + + /** + * A d'tor for this class, currently does nothing + */ + virtual ~DhcpOption() + {} + + /** + * Retrieve DHCP option data as IPv4 address. Relevant only if option value is indeed an IPv4 address + * @return DHCP option data as IPv4 address + */ + IPv4Address getValueAsIpAddr() const + { + return getValueAs(); + } + + /** + * Set DHCP option data as IPv4 address. This method copies the 4 bytes of the IP address to the option value + * @param[in] addr The IPv4 address to set + * @param[in] valueOffset An optional parameter that specifies where to start set the option data (default set + * to 0). For example: if option data is 20 bytes long and you want to set the IP address in the 4 last bytes + * then use this method like this: setValueIpAddr(your_addr, 16) + */ + void setValueIpAddr(const IPv4Address& addr, int valueOffset = 0) + { + setValue(addr.toInt(), valueOffset); + } + + /** + * Retrieve DHCP option data as string. Relevant only if option value is indeed a string + * @param[in] valueOffset An optional parameter that specifies where to start copy the DHCP option data. For + * example: when retrieving Client FQDN option, you may ignore the flags and RCODE fields using this method like + * this: getValueAsString(3). The default is 0 - start copying from the beginning of option data + * @return DHCP option data as string + */ + std::string getValueAsString(int valueOffset = 0) const + { + if (m_Data == nullptr || m_Data->recordLen - valueOffset < 1) + return ""; + + return std::string((const char*)m_Data->recordValue + valueOffset, (int)m_Data->recordLen - valueOffset); + } + + /** + * Set DHCP option data as string. This method copies the string to the option value. If the string is longer + * than option length the string is trimmed so it will fit the option length + * @param[in] stringValue The string to set + * @param[in] valueOffset An optional parameter that specifies where to start set the option data (default set + * to 0). For example: if option data is 20 bytes long and you want to set a 6 char-long string in the 6 last + * bytes then use this method like this: setValueString("string", 14) + */ + void setValueString(const std::string& stringValue, int valueOffset = 0) + { + // calculate the maximum length of the destination buffer + size_t len = (size_t)m_Data->recordLen - (size_t)valueOffset; + + // use the length of input string if a buffer is large enough for whole string + if (stringValue.length() < len) + len = stringValue.length(); + + memcpy(m_Data->recordValue + valueOffset, stringValue.data(), len); + } + + /** + * Check if a pointer can be assigned to the TLV record data + * @param[in] recordRawData A pointer to the TLV record raw data + * @param[in] tlvDataLen The size of the TLV record raw data + * @return True if data is valid and can be assigned + */ + static bool canAssign(const uint8_t* recordRawData, size_t tlvDataLen) + { + auto data = (TLVRawData*)recordRawData; + if (data == nullptr) + return false; + + if (tlvDataLen < sizeof(TLVRawData::recordType)) + return false; + + if (data->recordType == (uint8_t)DHCPOPT_END || data->recordType == (uint8_t)DHCPOPT_PAD) + return true; + + return TLVRecord::canAssign(recordRawData, tlvDataLen); + } + + // implement abstract methods + + size_t getTotalSize() const + { + if (m_Data == nullptr) + return 0; + + if (m_Data->recordType == (uint8_t)DHCPOPT_END || m_Data->recordType == (uint8_t)DHCPOPT_PAD) + return sizeof(uint8_t); + + return sizeof(uint8_t) * 2 + (size_t)m_Data->recordLen; + } + + size_t getDataSize() const + { + if (m_Data == nullptr) + return 0; + + if (m_Data->recordType == (uint8_t)DHCPOPT_END || m_Data->recordType == (uint8_t)DHCPOPT_PAD) + return 0; + + return m_Data->recordLen; + } + }; + + /** + * @class DhcpOptionBuilder + * A class for building DHCP options. This builder receives the option parameters in its c'tor, + * builds the DHCP option raw buffer and provides a build() method to get a DhcpOption object out of it + */ + class DhcpOptionBuilder : public TLVRecordBuilder + { + public: + /** + * A c'tor for building DHCP options which their value is a byte array. The DhcpOption object can later + * be retrieved by calling build() + * @param[in] optionType DHCP option type + * @param[in] optionValue A buffer containing the option value. This buffer is read-only and isn't modified in + * any way + * @param[in] optionValueLen DHCP option value length in bytes + */ + DhcpOptionBuilder(DhcpOptionTypes optionType, const uint8_t* optionValue, uint8_t optionValueLen) + : TLVRecordBuilder((uint8_t)optionType, optionValue, optionValueLen) + {} + + /** + * A c'tor for building DHCP options which have a 1-byte value. The DhcpOption object can later be retrieved + * by calling build() + * @param[in] optionType DHCP option type + * @param[in] optionValue A 1-byte option value + */ + DhcpOptionBuilder(DhcpOptionTypes optionType, uint8_t optionValue) + : TLVRecordBuilder((uint8_t)optionType, optionValue) + {} + + /** + * A c'tor for building DHCP options which have a 2-byte value. The DhcpOption object can later be retrieved + * by calling build() + * @param[in] optionType DHCP option type + * @param[in] optionValue A 2-byte option value + */ + DhcpOptionBuilder(DhcpOptionTypes optionType, uint16_t optionValue) + : TLVRecordBuilder((uint8_t)optionType, optionValue) + {} + + /** + * A c'tor for building DHCP options which have a 4-byte value. The DhcpOption object can later be retrieved + * by calling build() + * @param[in] optionType DHCP option type + * @param[in] optionValue A 4-byte option value + */ + DhcpOptionBuilder(DhcpOptionTypes optionType, uint32_t optionValue) + : TLVRecordBuilder((uint8_t)optionType, optionValue) + {} + + /** + * A c'tor for building DHCP options which have an IPv4Address value. The DhcpOption object can later be + * retrieved by calling build() + * @param[in] optionType DHCP option type + * @param[in] optionValue The IPv4 address option value + */ + DhcpOptionBuilder(DhcpOptionTypes optionType, const IPv4Address& optionValue) + : TLVRecordBuilder((uint8_t)optionType, optionValue) + {} + + /** + * A c'tor for building DHCP options which have a string value. The DhcpOption object can later be retrieved + * by calling build() + * @param[in] optionType DHCP option type + * @param[in] optionValue The string option value + */ + DhcpOptionBuilder(DhcpOptionTypes optionType, const std::string& optionValue) + : TLVRecordBuilder((uint8_t)optionType, optionValue) + {} + + /** + * A copy c'tor which copies all the data from another instance of DhcpOptionBuilder + * @param[in] other The instance to copy from + */ + DhcpOptionBuilder(const DhcpOptionBuilder& other) : TLVRecordBuilder(other) + {} + + /** + * Assignment operator that copies all data from another instance of DhcpOptionBuilder + * @param[in] other The instance to assign from + * @return A reference to the assignee + */ + DhcpOptionBuilder& operator=(const DhcpOptionBuilder& other) + { + TLVRecordBuilder::operator=(other); + return *this; + } + + /** + * Build the DhcpOption object out of the parameters defined in the c'tor + * @return The DhcpOption object + */ + DhcpOption build() const; + }; + + /** + * @class DhcpLayer + * Represents a DHCP (Dynamic Host Configuration Protocol) protocol layer + */ + class DhcpLayer : public Layer + { + public: + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + DhcpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + /** + * A constructor that creates the layer from scratch. Adds a ::DHCPOPT_DHCP_MESSAGE_TYPE and a ::DHCPOPT_END + * options + * @param[in] msgType A DHCP message type to be set + * @param[in] clientMacAddr A client MAC address to set in dhcp_header#clientHardwareAddress field + */ + DhcpLayer(DhcpMessageType msgType, const MacAddress& clientMacAddr); + + /** + * A constructor that creates the layer from scratch with clean data + */ + DhcpLayer(); + + /** + * A destructor for this layer + */ + virtual ~DhcpLayer() + {} + + /** + * Get a pointer to the DHCP header. Notice this points directly to the data, so every change will change the + * actual packet data + * @return A pointer to the @ref dhcp_header + */ + dhcp_header* getDhcpHeader() const + { + return (dhcp_header*)m_Data; + } + + /** + * @return The BootP opcode of this message + */ + BootpOpCodes getOpCode() const + { + return (BootpOpCodes)getDhcpHeader()->opCode; + } + + /** + * @return The client IPv4 address (as extracted from dhcp_header#clientIpAddress converted to IPv4Address + * object) + */ + IPv4Address getClientIpAddress() const + { + return getDhcpHeader()->clientIpAddress; + } + + /** + * Set the client IPv4 address in dhcp_header#clientIpAddress + * @param[in] addr The IPv4 address to set + */ + void setClientIpAddress(const IPv4Address& addr) + { + getDhcpHeader()->clientIpAddress = addr.toInt(); + } + + /** + * @return The server IPv4 address (as extracted from dhcp_header#serverIpAddress converted to IPv4Address + * object) + */ + IPv4Address getServerIpAddress() const + { + return getDhcpHeader()->serverIpAddress; + } + + /** + * Set the server IPv4 address in dhcp_header#serverIpAddress + * @param[in] addr The IPv4 address to set + */ + void setServerIpAddress(const IPv4Address& addr) + { + getDhcpHeader()->serverIpAddress = addr.toInt(); + } + + /** + * @return Your IPv4 address (as extracted from dhcp_header#yourIpAddress converted to IPv4Address object) + */ + IPv4Address getYourIpAddress() const + { + return getDhcpHeader()->yourIpAddress; + } + + /** + * Set your IPv4 address in dhcp_header#yourIpAddress + * @param[in] addr The IPv4 address to set + */ + void setYourIpAddress(const IPv4Address& addr) + { + getDhcpHeader()->yourIpAddress = addr.toInt(); + } + + /** + * @return Gateway IPv4 address (as extracted from dhcp_header#gatewayIpAddress converted to IPv4Address object) + */ + IPv4Address getGatewayIpAddress() const + { + return getDhcpHeader()->gatewayIpAddress; + } + + /** + * Set the gateway IPv4 address in dhcp_header#gatewayIpAddress + * @param[in] addr The IPv4 address to set + */ + void setGatewayIpAddress(const IPv4Address& addr) + { + getDhcpHeader()->gatewayIpAddress = addr.toInt(); + } + + /** + * @return The client MAC address as extracted from dhcp_header#clientHardwareAddress, assuming + * dhcp_header#hardwareType is 1 (Ethernet) and dhcp_header#hardwareAddressLength is 6 (MAC address length). + * Otherwise returns MacAddress#Zero + */ + MacAddress getClientHardwareAddress() const; + + /** + * Set a MAC address into the first 6 bytes of dhcp_header#clientHardwareAddress. This method also sets + * dhcp_header#hardwareType to 1 (Ethernet) and dhcp_header#hardwareAddressLength to 6 (MAC address length) + * @param[in] addr The MAC address to set + */ + void setClientHardwareAddress(const MacAddress& addr); + + /** + * @return DHCP message type as extracted from ::DHCPOPT_DHCP_MESSAGE_TYPE option. If this option doesn't exist + * the value of + * ::DHCP_UNKNOWN_MSG_TYPE is returned + */ + DhcpMessageType getMessageType() const; + + /** + * Set DHCP message type. This method searches for existing ::DHCPOPT_DHCP_MESSAGE_TYPE option. If found, it + * sets the requested message type as its value. If not, it creates a ::DHCPOPT_DHCP_MESSAGE_TYPE option and + * sets the requested message type as its value + * @param[in] msgType Message type to set + * @return True if message type was set successfully or false if msgType is ::DHCP_UNKNOWN_MSG_TYPE or if failed + * to add + * ::DHCPOPT_DHCP_MESSAGE_TYPE option + */ + bool setMessageType(DhcpMessageType msgType); + + /** + * @return The first DHCP option in the packet. If there are no DHCP options the returned value will contain + * a logical null (DhcpOption#isNull() == true) + */ + DhcpOption getFirstOptionData() const; + + /** + * Get the DHCP option that comes after a given option. If the given option was the last one, the + * returned value will contain a logical null (DhcpOption#isNull() == true) + * @param[in] dhcpOption A given DHCP option + * @return A DhcpOption object containing the option data that comes next, or logical null if the given DHCP + * option: (1) was the last one; (2) contains a logical null or (3) doesn't belong to this packet + */ + DhcpOption getNextOptionData(DhcpOption dhcpOption) const; + + /** + * Get a DHCP option by type + * @param[in] option DHCP option type + * @return A DhcpOption object containing the first DHCP option data that matches this type, or logical null + * (DhcpOption#isNull() == true) if no such option found + */ + DhcpOption getOptionData(DhcpOptionTypes option) const; + + /** + * @return The number of DHCP options in this layer + */ + size_t getOptionsCount() const; + + /** + * Add a new DHCP option at the end of the layer + * @param[in] optionBuilder A DhcpOptionBuilder object that contains the requested DHCP option data to add + * @return A DhcpOption object containing the newly added DHCP option data or logical null + * (DhcpOption#isNull() == true) if addition failed + */ + DhcpOption addOption(const DhcpOptionBuilder& optionBuilder); + + /** + * Add a new DHCP option after an existing one + * @param[in] optionBuilder A DhcpOptionBuilder object that contains the requested DHCP option data to add + * @param[in] prevOption The DHCP option type which the newly added option will come after + * @return A DhcpOption object containing the newly added DHCP option data or logical null + * (DhcpOption#isNull() == true) if addition failed + */ + DhcpOption addOptionAfter(const DhcpOptionBuilder& optionBuilder, DhcpOptionTypes prevOption); + + /** + * Remove an existing DHCP option from the layer + * @param[in] optionType The DHCP option type to remove + * @return True if DHCP option was successfully removed or false if type wasn't found or if removal failed + */ + bool removeOption(DhcpOptionTypes optionType); + + /** + * Remove all DHCP options in this layer + * @return True if all DHCP options were successfully removed or false if removal failed for some reason + */ + bool removeAllOptions(); + + /** + * A static method that checks whether a pair of ports are considered DHCP ports + * @param[in] portSrc The source port number to check + * @param[in] portDst The destination port number to check + * @return True if these are DHCP port numbers, false otherwise + */ + static inline bool isDhcpPorts(uint16_t portSrc, uint16_t portDst); + + // implement abstract methods + + /** + * Does nothing for this layer (DhcpLayer is always last) + */ + void parseNextLayer() + {} + + /** + * @return The size of @ref dhcp_header + size of options + */ + size_t getHeaderLen() const + { + return m_DataLen; + } + + /** + * Calculate the following fields: + * - @ref dhcp_header#magicNumber = DHCP magic number (0x63538263) + * - @ref dhcp_header#opCode = ::DHCP_BOOTREQUEST for message types: ::DHCP_DISCOVER, ::DHCP_REQUEST, + * ::DHCP_DECLINE, ::DHCP_RELEASE, + * ::DHCP_INFORM, ::DHCP_UNKNOWN_MSG_TYPE + * ::DHCP_BOOTREPLY for message types: ::DHCP_OFFER, ::DHCP_ACK, ::DHCP_NAK + * - @ref dhcp_header#hardwareType = 1 (Ethernet) + * - @ref dhcp_header#hardwareAddressLength = 6 (MAC address length) + */ + void computeCalculateFields(); + + std::string toString() const; + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelApplicationLayer; + } + + private: + uint8_t* getOptionsBasePtr() const + { + return m_Data + sizeof(dhcp_header); + } + + TLVRecordReader m_OptionReader; + + void initDhcpLayer(size_t numOfBytesToAllocate); + + DhcpOption addOptionAt(const DhcpOptionBuilder& optionBuilder, int offset); + }; + + // implementation of inline methods + + bool DhcpLayer::isDhcpPorts(uint16_t portSrc, uint16_t portDst) + { + return ((portSrc == 68 && portDst == 67) || (portSrc == 67 && portDst == 68) || + (portSrc == 67 && portDst == 67)); + } + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/DhcpV6Layer.h b/Packet++/header/pcapplusplus/DhcpV6Layer.h new file mode 100644 index 0000000000..7b2563b863 --- /dev/null +++ b/Packet++/header/pcapplusplus/DhcpV6Layer.h @@ -0,0 +1,468 @@ +#pragma once + +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/TLVData.h" + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + /** + * DHCPv6 message types + */ + enum DhcpV6MessageType + { + /** Unknown message type */ + DHCPV6_UNKNOWN_MSG_TYPE = 0, + /** Solicit message type (Client to Server) */ + DHCPV6_SOLICIT = 1, + /** Advertise message type (Server to Client) */ + DHCPV6_ADVERTISE = 2, + /** Request message type (Client to Server) */ + DHCPV6_REQUEST = 3, + /** Confirm message type (Client to Server) */ + DHCPV6_CONFIRM = 4, + /** Renew message type (Client to Server) */ + DHCPV6_RENEW = 5, + /** Rebind message type (Client to Server) */ + DHCPV6_REBIND = 6, + /** Reply message type (Server to Client) */ + DHCPV6_REPLY = 7, + /** Release message type (Client to Server) */ + DHCPV6_RELEASE = 8, + /** Decline message type (Client to Server) */ + DHCPV6_DECLINE = 9, + /** Reconfigure message type (Server to Client) */ + DHCPV6_RECONFIGURE = 10, + /** Information-Request message type (Client to Server) */ + DHCPV6_INFORMATION_REQUEST = 11, + /** Relay-Forward message type (Relay agent to Server) */ + DHCPV6_RELAY_FORWARD = 12, + /** Relay-Reply message type (Server to Relay agent) */ + DHCPV6_RELAY_REPLY = 13 + }; + + /** + * DHCPv6 option types. + * Resources for more information: + * - https://onlinelibrary.wiley.com/doi/pdf/10.1002/9781118073810.app2 + * - https://datatracker.ietf.org/doc/html/rfc5970 + * - https://datatracker.ietf.org/doc/html/rfc6607 + * - https://datatracker.ietf.org/doc/html/rfc8520 + */ + enum DhcpV6OptionType + { + /** Unknown option type */ + DHCPV6_OPT_UNKNOWN = 0, + /** Client Identifier (DUID of client) */ + DHCPV6_OPT_CLIENTID = 1, + /** Server Identifier (DUID of server) */ + DHCPV6_OPT_SERVERID = 2, + /** Identity Association for Non-temporary addresses */ + DHCPV6_OPT_IA_NA = 3, + /** Identity Association for Temporary addresses */ + DHCPV6_OPT_IA_TA = 4, + /** IA Address option */ + DHCPV6_OPT_IAADDR = 5, + /** Option Request Option */ + DHCPV6_OPT_ORO = 6, + /** Preference setting */ + DHCPV6_OPT_PREFERENCE = 7, + /** The amount of time since the client began the current DHCP transaction */ + DHCPV6_OPT_ELAPSED_TIME = 8, + /** The DHCP message being relayed by a relay agent */ + DHCPV6_OPT_RELAY_MSG = 9, + /** Authentication information */ + DHCPV6_OPT_AUTH = 11, + /** Server unicast */ + DHCPV6_OPT_UNICAST = 12, + /** Status code */ + DHCPV6_OPT_STATUS_CODE = 13, + /** Rapid commit */ + DHCPV6_OPT_RAPID_COMMIT = 14, + /** User class */ + DHCPV6_OPT_USER_CLASS = 15, + /** Vendor class */ + DHCPV6_OPT_VENDOR_CLASS = 16, + /** Vendor specific information */ + DHCPV6_OPT_VENDOR_OPTS = 17, + /** Interface ID */ + DHCPV6_OPT_INTERFACE_ID = 18, + /** Reconfigure Message */ + DHCPV6_OPT_RECONF_MSG = 19, + /** Reconfigure Accept */ + DHCPV6_OPT_RECONF_ACCEPT = 20, + /** SIP Servers Domain Name */ + DHCPV6_OPT_SIP_SERVERS_D = 21, + /** SIP Servers IPv6 Address List */ + DHCPV6_OPT_SIP_SERVERS_A = 22, + /** DNS Recursive Name Server */ + DHCPV6_OPT_DNS_SERVERS = 23, + /** Domain Search List */ + DHCPV6_OPT_DOMAIN_LIST = 24, + /** Identity Association for Prefix Delegation */ + DHCPV6_OPT_IA_PD = 25, + /** IA_PD Prefix */ + DHCPV6_OPT_IAPREFIX = 26, + /** Network Information Service (NIS) Servers */ + DHCPV6_OPT_NIS_SERVERS = 27, + /** Network Information Service v2 (NIS+) Servers */ + DHCPV6_OPT_NISP_SERVERS = 28, + /** Network Information Service (NIS) domain name */ + DHCPV6_OPT_NIS_DOMAIN_NAME = 29, + /** Network Information Service v2 (NIS+) domain name */ + DHCPV6_OPT_NISP_DOMAIN_NAME = 30, + /** Simple Network Time Protocol (SNTP) servers */ + DHCPV6_OPT_SNTP_SERVERS = 31, + /** Information Refresh */ + DHCPV6_OPT_INFORMATION_REFRESH_TIME = 32, + /** Broadcast and Multicast Service (BCMCS) Domain Name List */ + DHCPV6_OPT_BCMCS_SERVER_D = 33, + /** Broadcast and Multicast Service (BCMCS) IPv6 Address List */ + DHCPV6_OPT_BCMCS_SERVER_A = 34, + /** Geographical location in civic (e.g., postal) format */ + DHCPV6_OPT_GEOCONF_CIVIC = 36, + /** Relay Agent Remote ID */ + DHCPV6_OPT_REMOTE_ID = 37, + /** Relay Agent Subscriber ID */ + DHCPV6_OPT_SUBSCRIBER_ID = 38, + /** FQDN */ + DHCPV6_OPT_CLIENT_FQDN = 39, + /** One or more IPv6 addresses associated with PANA (Protocol for carrying Authentication for Network Access) + * Authentication Agents */ + DHCPV6_OPT_PANA_AGENT = 40, + /** Time zone to be used by the client in IEEE 1003.1 format */ + DHCPV6_OPT_NEW_POSIX_TIMEZONE = 41, + /** Time zone (TZ) database entry referred to by entry name */ + DHCPV6_OPT_NEW_TZDB_TIMEZONE = 42, + /** Relay Agent Echo Request */ + DHCPV6_OPT_ERO = 43, + /** Query option */ + DHCPV6_OPT_LQ_QUERY = 44, + /** Client Data */ + DHCPV6_OPT_CLIENT_DATA = 45, + /** Client Last Transaction Time */ + DHCPV6_OPT_CLT_TIME = 46, + /** Relay data */ + DHCPV6_OPT_LQ_RELAY_DATA = 47, + /** Client link */ + DHCPV6_OPT_LQ_CLIENT_LINK = 48, + /** Mobile IPv6 Home Network Information */ + DHCPV6_OPT_MIP6_HNINF = 49, + /** Mobile IPv6 Relay Agent */ + DHCPV6_OPT_MIP6_RELAY = 50, + /** Location to Service Translation (LoST) server domain name */ + DHCPV6_OPT_V6_LOST = 51, + /** Access Points (CAPWAP) Access Controller IPv6 addresses */ + DHCPV6_OPT_CAPWAP_AC_V6 = 52, + /** DHCPv6 Bulk LeaseQuery */ + DHCPV6_OPT_RELAY_ID = 53, + /** List of IPv6 addresses for servers providing particular types of IEEE 802.21 Mobility Service (MoS) */ + DHCPV6_OPT_IPH6_ADDRESS_MOS = 54, + /** List of FQDNs for servers providing particular types of IEEE 802.21 Mobility Service (MoS) */ + DHCPV6_OPT_IPV6_FQDN_MOS = 55, + /** Network Time Protocol (NTP) or Simple NTP (SNTP) Server Location */ + DHCPV6_OPT_NTP_SERVER = 56, + /** Boot File Uniform Resource Locator (URL) */ + DHCPV6_OPT_BOOTFILE_URL = 59, + /** Boot File Parameters */ + DHCPV6_OPT_BOOTFILE_PARAM = 60, + /** Client System Architecture Type */ + DHCPV6_OPT_CLIENT_ARCH_TYPE = 61, + /** Client Network Interface Identifier */ + DHCPV6_OPT_NII = 62, + /** ERP Local Domain Name */ + DHCPV6_OPT_ERP_LOCAL_DOMAIN_NAME = 65, + /** Relay supplied options */ + DHCPV6_OPT_RELAY_SUPPLIED_OPTIONS = 66, + /** Virtual Subnet Selection */ + DHCPV6_OPT_VSS = 68, + /** Client link layer */ + DHCPV6_OPT_CLIENT_LINKLAYER_ADDR = 79, + /** Manufacturer Usage Description */ + DHCPV6_OPT_MUD_URL = 112 + }; + + /** + * @class DhcpV6Option + * A wrapper class for DHCPv6 options. This class does not create or modify DHCP option records, but rather + * serves as a wrapper and provides useful methods for setting and retrieving data to/from them + */ + class DhcpV6Option : public TLVRecord + { + public: + /** + * A c'tor for this class that gets a pointer to the option raw data (byte array) + * @param[in] optionRawData A pointer to the option raw data + */ + explicit DhcpV6Option(uint8_t* optionRawData) : TLVRecord(optionRawData) + {} + + /** + * A d'tor for this class, currently does nothing + */ + virtual ~DhcpV6Option() + {} + + /** + * @return The option type converted to ::DhcpV6OptionType enum + */ + DhcpV6OptionType getType() const; + + /** + * @return The raw option value (byte array) as a hex string + */ + std::string getValueAsHexString() const; + + // implement abstract methods + + size_t getTotalSize() const; + size_t getDataSize() const; + }; + + /** + * @class DhcpV6OptionBuilder + * A class for building DHCPv6 options. This builder receives the option parameters in its c'tor, + * builds the DHCPv6 option raw buffer and provides a build() method to get a DhcpV6Option object out of it + */ + class DhcpV6OptionBuilder : public TLVRecordBuilder + { + public: + /** + * A c'tor for building DHCPv6 options from a string representing the hex stream of the raw byte value. + * The DhcpV6Option object can later be retrieved by calling build() + * @param[in] optionType DHCPv6 option type + * @param[in] optionValueAsHexStream The value as a hex stream string + */ + DhcpV6OptionBuilder(DhcpV6OptionType optionType, const std::string& optionValueAsHexStream) + : TLVRecordBuilder(static_cast(optionType), optionValueAsHexStream, true) + {} + + /** + * A c'tor for building DHCPv6 options from a byte array representing their value. The DhcpV6Option object can + * be later retrieved by calling build() + * @param[in] optionType DHCPv6 option type + * @param[in] optionValue A buffer containing the option value. This buffer is read-only and isn't modified in + * any way. + * @param[in] optionValueLen Option value length in bytes + */ + DhcpV6OptionBuilder(DhcpV6OptionType optionType, const uint8_t* optionValue, uint8_t optionValueLen) + : TLVRecordBuilder(static_cast(optionType), optionValue, optionValueLen) + {} + + /** + * Build the DhcpV6Option object out of the parameters defined in the c'tor + * @return The DhcpV6Option object + */ + DhcpV6Option build() const; + }; + + /** + * @struct dhcpv6_header + * Represents the basic DHCPv6 protocol header + */ + struct dhcpv6_header + { + /** DHCPv6 message type */ + uint8_t messageType; + /** DHCPv6 transaction ID (first byte) */ + uint8_t transactionId1; + /** DHCPv6 transaction ID (second byte) */ + uint8_t transactionId2; + /** DHCPv6 transaction ID (last byte) */ + uint8_t transactionId3; + }; + + /** + * @class DhcpV6Layer + * Represents a DHCPv6 (Dynamic Host Configuration Protocol version 6) protocol layer + */ + class DhcpV6Layer : public Layer + { + public: + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + DhcpV6Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + /** + * A constructor that creates the layer from scratch + * @param[in] messageType A DHCPv6 message type to be set + * @param[in] transactionId The transaction ID to be set. Notice the transaction ID is 3-byte long so the value + * shouldn't exceed 0xFFFFFF + */ + DhcpV6Layer(DhcpV6MessageType messageType, uint32_t transactionId); + + /** + * @return The message type of this DHCPv6 message + */ + DhcpV6MessageType getMessageType() const; + + /** + * @return The string value of the message type of this DHCPv6 message + */ + std::string getMessageTypeAsString() const; + + /** + * Set the message type for this layer + * @param[in] messageType The message type to set + */ + void setMessageType(DhcpV6MessageType messageType); + + /** + * @return The transaction ID of this DHCPv6 message + */ + uint32_t getTransactionID() const; + + /** + * Set the transaction ID for this DHCPv6 message + * @param[in] transactionId The transaction ID value to set + */ + void setTransactionID(uint32_t transactionId) const; + + /** + * @return The first DHCPv6 option in the packet. If there are no DHCPv6 options the returned value will contain + * a logical null (DhcpV6Option#isNull() == true) + */ + DhcpV6Option getFirstOptionData() const; + + /** + * Get the DHCPv6 option that comes after a given option. If the given option was the last one, the + * returned value will contain a logical null (DhcpV6Option#isNull() == true) + * @param[in] dhcpv6Option A given DHCPv6 option + * @return A DhcpV6Option object containing the option data that comes next, or logical null if the given + * DHCPv6 option: (1) was the last one; (2) contains a logical null or (3) doesn't belong to this packet + */ + DhcpV6Option getNextOptionData(DhcpV6Option dhcpv6Option) const; + + /** + * Get a DHCPv6 option by type + * @param[in] option DHCPv6 option type + * @return A DhcpV6OptionType object containing the first DHCP option data that matches this type, or logical + * null (DhcpV6Option#isNull() == true) if no such option found + */ + DhcpV6Option getOptionData(DhcpV6OptionType option) const; + + /** + * @return The number of DHCPv6 options in this layer + */ + size_t getOptionCount() const; + + /** + * Add a new DHCPv6 option at the end of the layer + * @param[in] optionBuilder A DhcpV6OptionBuilder object that contains the requested DHCPv6 option data to add + * @return A DhcpV6Option object containing the newly added DHCP option data or logical null + * (DhcpV6Option#isNull() == true) if addition failed + */ + DhcpV6Option addOption(const DhcpV6OptionBuilder& optionBuilder); + + /** + * Add a new DHCPv6 option after an existing one + * @param[in] optionBuilder A DhcpV6OptionBuilder object that contains the requested DHCPv6 option data to add + * @param[in] optionType The DHCPv6 option type which the newly added option will come after + * @return A DhcpV6Option object containing the newly added DHCPv6 option data or logical null + * (DhcpV6Option#isNull() == true) if addition failed + */ + DhcpV6Option addOptionAfter(const DhcpV6OptionBuilder& optionBuilder, DhcpV6OptionType optionType); + + /** + * Add a new DHCPv6 option before an existing one + * @param[in] optionBuilder A DhcpV6OptionBuilder object that contains the requested DHCPv6 option data to add + * @param[in] optionType The DHCPv6 option type which the newly added option will come before + * @return A DhcpV6Option object containing the newly added DHCPv6 option data or logical null + * (DhcpV6Option#isNull() == true) if addition failed + */ + DhcpV6Option addOptionBefore(const DhcpV6OptionBuilder& optionBuilder, DhcpV6OptionType optionType); + + /** + * Remove an existing DHCPv6 option from the layer + * @param[in] optionType The DHCPv6 option type to remove + * @return True if DHCPv6 option was successfully removed or false if type wasn't found or if removal failed + */ + bool removeOption(DhcpV6OptionType optionType); + + /** + * Remove all DHCPv6 options in this layer + * @return True if all DHCPv6 options were successfully removed or false if removal failed for some reason + */ + bool removeAllOptions(); + + /** + * A static method that checks whether a port is considered as a DHCPv6 port + * @param[in] port The port number to check + * @return True if this is a DHCPv6 port number, false otherwise + */ + static inline bool isDhcpV6Port(uint16_t port); + + /** + * A static method that validates the input data + * @param[in] data The pointer to the beginning of a byte stream of an DHCPv6 layer + * @param[in] dataLen The length of the byte stream + * @return True if the data is valid and can represent an DHCPv6 layer + */ + static inline bool isDataValid(const uint8_t* data, size_t dataLen); + + // implement abstract methods + + /** + * Does nothing for this layer (DhcpV6Layer is always last) + */ + void parseNextLayer() + {} + + /** + * @return The size of @ref dhcpv6_header + size of options + */ + size_t getHeaderLen() const + { + return m_DataLen; + } + + /** + * Does nothing for this layer + */ + void computeCalculateFields() + {} + + std::string toString() const; + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelApplicationLayer; + } + + private: + uint8_t* getOptionsBasePtr() const + { + return m_Data + sizeof(dhcpv6_header); + } + dhcpv6_header* getDhcpHeader() const + { + return (dhcpv6_header*)m_Data; + } + DhcpV6Option addOptionAt(const DhcpV6OptionBuilder& optionBuilder, int offset); + + TLVRecordReader m_OptionReader; + }; + + // implementation of inline methods + + bool DhcpV6Layer::isDhcpV6Port(uint16_t port) + { + return (port == 546) || (port == 547); + } + + bool DhcpV6Layer::isDataValid(const uint8_t* data, size_t dataLen) + { + return data && dataLen >= sizeof(dhcpv6_header); + } + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/DnsLayer.h b/Packet++/header/pcapplusplus/DnsLayer.h new file mode 100644 index 0000000000..1b5b28249e --- /dev/null +++ b/Packet++/header/pcapplusplus/DnsLayer.h @@ -0,0 +1,593 @@ +#pragma once + +#include "pcapplusplus/DnsLayerEnums.h" +#include "pcapplusplus/DnsResource.h" +#include "pcapplusplus/DnsResourceData.h" +#include "pcapplusplus/Layer.h" + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * @struct dnshdr + * Represents the fixed part of the DNS header, meaning the part that doesn't include the DNS data (queries, + * answers, authorities and additional records) + */ +#pragma pack(push, 1) + struct dnshdr + { + /** DNS query identification */ + uint16_t transactionID; +#if (BYTE_ORDER == LITTLE_ENDIAN) + uint16_t + /** Recursion desired flag */ + recursionDesired : 1, + /** Truncated flag */ + truncation : 1, + /** Authoritative answer flag */ + authoritativeAnswer : 1, + /** Operation Code */ + opcode : 4, + /** Query/Response flag */ + queryOrResponse : 1, + /** Return Code */ + responseCode : 4, + /** Checking disabled flag */ + checkingDisabled : 1, + /** Authenticated data flag */ + authenticData : 1, + /** Zero flag (Reserved) */ + zero : 1, + /** Recursion available flag */ + recursionAvailable : 1; +#elif (BYTE_ORDER == BIG_ENDIAN) + uint16_t + /** Query/Response flag */ + queryOrResponse : 1, + /** Operation Code */ + opcode : 4, + /** Authoritative answer flag */ + authoritativeAnswer : 1, + /** Truncated flag */ + truncation : 1, + /** Recursion desired flag */ + recursionDesired : 1, + /** Recursion available flag */ + recursionAvailable : 1, + /** Zero flag (Reserved) */ + zero : 1, + /** Authenticated data flag */ + authenticData : 1, + /** Checking disabled flag */ + checkingDisabled : 1, + /** Return Code */ + responseCode : 4; +#endif + /** Number of DNS query records in packet */ + uint16_t numberOfQuestions; + /** Number of DNS answer records in packet */ + uint16_t numberOfAnswers; + /** Number of authority records in packet */ + uint16_t numberOfAuthority; + /** Number of additional records in packet */ + uint16_t numberOfAdditional; + }; +#pragma pack(pop) + + // forward declarations + class DnsQuery; + class IDnsResource; + class DnsResource; + class IDnsResourceData; + + /** + * @class DnsLayer + * Represents the DNS protocol layer + */ + class DnsLayer : public Layer + { + friend class IDnsResource; + friend class DnsQuery; + friend class DnsResource; + + public: + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + DnsLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + /** + * A constructor that creates an empty DNS layer: all members of dnshdr are set to 0 and layer will contain no + * records + */ + DnsLayer(); + + /** + * A copy constructor for this layer + * @param[in] other The DNS layer to copy from + */ + DnsLayer(const DnsLayer& other); + + /** + * An assignment operator for this layer + * @param[in] other The DNS layer to assign + * @return A reference to the assignee + */ + DnsLayer& operator=(const DnsLayer& other); + + virtual ~DnsLayer(); + + /** + * Get a pointer to the DNS header (as opposed to the DNS data which is the queries, answers, etc. Data can be + * retrieved through the other methods of this layer. Notice the return value points directly to the data, so + * every change will change the actual packet data + * @return A pointer to the @ref dnshdr + */ + dnshdr* getDnsHeader() const; + + /** + * Searches for a DNS query by its name field. Notice this method returns only a query which its name equals to + * the requested name. If several queries match the requested name, the first one will be returned. If no + * queries match the requested name, nullptr will be returned + * @param[in] name The name of the query to search + * @param[in] exactMatch Indicate whether to match the whole name or just a part of it + * @return The first matching DNS query or nullptr if no queries were found + */ + DnsQuery* getQuery(const std::string& name, bool exactMatch) const; + + /** + * @return The first DNS query in the packet or nullptr if packet doesn't contain any queries + */ + DnsQuery* getFirstQuery() const; + + /** + * Get the DNS query following a certain query + * @param[in] query A pointer to a DNS query that exist in the packet + * @return The DNS query following 'query'. If 'query' is nullptr or 'query' is the last query in the packet + * nullptr will be returned + */ + DnsQuery* getNextQuery(DnsQuery* query) const; + + /** + * @return The number of DNS queries in the packet + */ + size_t getQueryCount() const; + + /** + * Add a new DNS query to the layer + * @param[in] name The value that shall be set in the name field of the query + * @param[in] dnsType The value that shall be set in the DNS type field of the query + * @param[in] dnsClass The value that shall be set in the DNS class field of the query + * @return A pointer to the newly created DNS query or nullptr if query could not be created (an appropriate + * error log message will be printed in this case) + */ + DnsQuery* addQuery(const std::string& name, DnsType dnsType, DnsClass dnsClass); + + /** + * Add a new DNS query similar to an already existing DNS query. All query fields will be copied from the + * existing query + * @param[in] copyQuery The record to create the new record from. copyQuery won't be changed in any way + * @return A pointer to the newly created DNS query or nullptr if query could not be created (an appropriate + * error log message will be printed in this case) + */ + DnsQuery* addQuery(DnsQuery* const copyQuery); + + /** + * Remove an existing query by name. If several queries matches the name, the first match will be removed + * @param[in] queryNameToRemove The name of the query to remove + * @param[in] exactMatch Indicate whether to match the whole name or just a part of it + * @return True if query was found and successfully removed or false if query was not found or couldn't be + * removed + */ + bool removeQuery(const std::string& queryNameToRemove, bool exactMatch); + + /** + * Remove an existing query + * @param[in] queryToRemove A pointer to the query to remove + * @return True if query was found and successfully removed or false if query was not found or couldn't be + * removed + */ + bool removeQuery(DnsQuery* queryToRemove); + + /** + * Searches for a DNS answer by its name field. Notice this method returns only an answer which its name equals + * to the requested name. If several answers match the requested name, the first one will be returned. If no + * answers match the requested name, nullptr will be returned + * @param[in] name The name of the answer to search + * @param[in] exactMatch Indicate whether to match the whole name or just a part of it + * @return The first matching DNS answer or nullptr if no answers were found + */ + DnsResource* getAnswer(const std::string& name, bool exactMatch) const; + + /** + * @return The first DNS answer in the packet or nullptr if packet doesn't contain any answers + */ + DnsResource* getFirstAnswer() const; + + /** + * Get the DNS answer following a certain answer + * @param[in] answer A pointer to a DNS answer that exist in the packet + * @return The DNS answer following 'answer'. If 'answer' is nullptr or 'answer' is the last answer in the + * packet nullptr will be returned + */ + DnsResource* getNextAnswer(DnsResource* answer) const; + + /** + * @return The number of DNS answers in the packet + */ + size_t getAnswerCount() const; + + /** + * Add a new DNS answer to the layer + * @param[in] name The value that shall be set in the name field of the answer + * @param[in] dnsType The value that shall be set in the DNS type field of the answer + * @param[in] dnsClass The value that shall be set in the DNS class field of the answer + * @param[in] ttl The value that shall be set in the 'time-to-leave' field of the answer + * @param[in] data The answer data to be set. The type of the data should match the type of the DNS record + * (for example: DNS record of type A should have data of type IPv4DnsResourceData. Please see + * DnsResource#setData() for more info on this + * @return A pointer to the newly created DNS answer or nullptr if answer could not be created (an appropriate + * error log message will be printed in this case) + */ + DnsResource* addAnswer(const std::string& name, DnsType dnsType, DnsClass dnsClass, uint32_t ttl, + IDnsResourceData* data); + + /** + * Add a new DNS answer similar to an already existing DNS answer. All answer fields will be copied from the + * existing answer + * @param[in] copyAnswer The record to create the new record from. copyAnswer won't be changed in any way + * @return A pointer to the newly created DNS answer or nullptr if query could not be created (an appropriate + * error log message will be printed in this case) + */ + DnsResource* addAnswer(DnsResource* const copyAnswer); + + /** + * Remove an existing answer by name. If several answers matches the name, the first match will be removed + * @param[in] answerNameToRemove The name of the answer to remove + * @param[in] exactMatch Indicate whether to match the whole name or just a part of it + * @return True if answer was found and successfully removed or false if answer was not found or couldn't be + * removed + */ + bool removeAnswer(const std::string& answerNameToRemove, bool exactMatch); + + /** + * Remove an existing answer + * @param[in] answerToRemove A pointer to the answer to remove + * @return True if answer was found and successfully removed or false if answer was not found or couldn't be + * removed + */ + bool removeAnswer(DnsResource* answerToRemove); + + /** + * Searches for a DNS authority by its name field. Notice this method returns only an authority which its name + * equals to the requested name. If several authorities match the requested name, the first one will be + * returned. If no authorities match the requested name, nullptr will be returned + * @param[in] name The name of the authority to search + * @param[in] exactMatch Indicate whether to match the whole name or just a part of it + * @return The first matching DNS authority or nullptr if no authorities were found + */ + DnsResource* getAuthority(const std::string& name, bool exactMatch) const; + + /** + * @return The first DNS authority in the packet or nullptr if packet doesn't contain any authorities + */ + DnsResource* getFirstAuthority() const; + + /** + * Get the DNS authority following a certain authority + * @param[in] authority A pointer to a DNS authority that exist in the packet + * @return The DNS authority following 'authority'. If 'authority' is nullptr or 'authority' is the last + * authority in the packet nullptr will be returned + */ + DnsResource* getNextAuthority(DnsResource* authority) const; + + /** + * @return The number of DNS authorities in the packet + */ + size_t getAuthorityCount() const; + + /** + * Add a new DNS authority to the layer + * @param[in] name The value that shall be set in the name field of the authority + * @param[in] dnsType The value that shall be set in the DNS type field of the authority + * @param[in] dnsClass The value that shall be set in the DNS class field of the authority + * @param[in] ttl The value that shall be set in the 'time-to-leave' field of the authority + * @param[in] data The authority data to be set. The type of the data should match the type of the DNS record + * (for example: DNS record of type A should have data of type IPv4DnsResourceData. Please see + * DnsResource#setData() for more info on this + * @return A pointer to the newly created DNS authority or nullptr if authority could not be created (an + * appropriate error log message will be printed in this case) + */ + DnsResource* addAuthority(const std::string& name, DnsType dnsType, DnsClass dnsClass, uint32_t ttl, + IDnsResourceData* data); + + /** + * Add a new DNS authority similar to an already existing DNS authority. All authority fields will be copied + * from the existing authority + * @param[in] copyAuthority The record to create the new record from. copyAuthority won't be changed in any way + * @return A pointer to the newly created DNS authority or nullptr if query could not be created (an appropriate + * error log message will be printed in this case) + */ + DnsResource* addAuthority(DnsResource* const copyAuthority); + + /** + * Remove an existing authority by name. If several authorities matches the name, the first match will be + * removed + * @param[in] authorityNameToRemove The name of the authority to remove + * @param[in] exactMatch Indicate whether to match the whole name or just a part of it + * @return True if authority was found and successfully removed or false if authority was not found or couldn't + * be removed + */ + bool removeAuthority(const std::string& authorityNameToRemove, bool exactMatch); + + /** + * Remove an existing authority + * @param[in] authorityToRemove A pointer to the authority to remove + * @return True if authority was found and successfully removed or false if authority was not found or couldn't + * be removed + */ + bool removeAuthority(DnsResource* authorityToRemove); + + /** + * Searches for a DNS additional record by its name field. Notice this method returns only an additional record + * which its name equals to the requested name. If several additional records match the requested name, the + * first one will be returned. If no additional records match the requested name, nullptr will be returned + * @param[in] name The name of the additional record to search + * @param[in] exactMatch Indicate whether to match the whole name or just a part of it + * @return The first matching DNS additional record or nullptr if no additional records were found + */ + DnsResource* getAdditionalRecord(const std::string& name, bool exactMatch) const; + + /** + * @return The first DNS additional record in the packet or nullptr if packet doesn't contain any additional + * records + */ + DnsResource* getFirstAdditionalRecord() const; + + /** + * Get the DNS additional record following a certain additional record + * @param[in] additionalRecord A pointer to a DNS additional record that exist in the packet + * @return The DNS additional record following 'additionalRecord'. If 'additionalRecord' is nullptr or + * 'additionalRecord' is the last additional record in the packet nullptr will be returned + */ + DnsResource* getNextAdditionalRecord(DnsResource* additionalRecord) const; + + /** + * @return The number of DNS additional records in the packet + */ + size_t getAdditionalRecordCount() const; + + /** + * Add a new DNS additional record to the layer + * @param[in] name The value that shall be set in the name field of the additional record + * @param[in] dnsType The value that shall be set in the DNS type field of the additional record + * @param[in] dnsClass The value that shall be set in the DNS class field of the additional record + * @param[in] ttl The value that shall be set in the 'time-to-leave' field of the additional record + * @param[in] data The additional record data to be set. The type of the data should match the type of the DNS + * record (for example: DNS record of type A should have data of type IPv4DnsResourceData. Please see + * DnsResource#setData() for more info on this + * @return A pointer to the newly created DNS additional record or nullptr if additional record could not be + * created (an appropriate error log message will be printed in this case) + */ + DnsResource* addAdditionalRecord(const std::string& name, DnsType dnsType, DnsClass dnsClass, uint32_t ttl, + IDnsResourceData* data); + + /** + * Add a new DNS additional record to the layer that doesn't have DNS class and TTL. Instead these bytes may + * contains some arbitrary data. In the future I may add support for these kinds of additional data records. For + * now, these bytes are set as raw + * @param[in] name The value that shall be set in the name field of the additional record + * @param[in] dnsType The value that shall be set in the DNS type field of the additional record + * @param[in] customData1 Two bytes of the arbitrary data that will be set in the offset usually used for the + * DNS class + * @param[in] customData2 Four bytes of the arbitrary data that will be set in the offset usually used for the + * TTL + * @param[in] data The additional record data to be set. The type of the data should match the type of the DNS + * record. (for example: DNS record of type A should have data of type IPv4DnsResourceData. Please see + * DnsResource#setData() for more info on this + * @return A pointer to the newly created DNS additional record or nullptr if additional record could not be + * created (an appropriate error log message will be printed in this case) + */ + DnsResource* addAdditionalRecord(const std::string& name, DnsType dnsType, uint16_t customData1, + uint32_t customData2, IDnsResourceData* data); + + /** + * Add a new DNS additional record similar to an already existing DNS additional record. All additional record + * fields will be copied from the existing additional record + * @param[in] copyAdditionalRecord The record to create the new record from. copyAdditionalRecord won't be + * changed in any way + * @return A pointer to the newly created DNS additional record or nullptr if query could not be created (an + * appropriate error log message will be printed in this case) + */ + DnsResource* addAdditionalRecord(DnsResource* const copyAdditionalRecord); + + /** + * Remove an existing additional record by name. If several additional records matches the name, the first match + * will be removed + * @param[in] additionalRecordNameToRemove The name of the additional record to remove + * @param[in] exactMatch Indicate whether to match the whole name or just a part of it + * @return True if additional record was found and successfully removed or false if additional record was not + * found or couldn't be removed + */ + bool removeAdditionalRecord(const std::string& additionalRecordNameToRemove, bool exactMatch); + + /** + * Remove an existing additional record + * @param[in] additionalRecordToRemove A pointer to the additional record to remove + * @return True if additional record was found and successfully removed or false if additional record was not + * found or couldn't be removed + */ + bool removeAdditionalRecord(DnsResource* additionalRecordToRemove); + + // implement abstract methods + + /** + * Does nothing for this layer (DnsLayer is always last) + */ + void parseNextLayer() + {} + + /** + * @return The size of the DNS data in the packet including he DNS header and size of all queries, answers, + * authorities and additional records + */ + size_t getHeaderLen() const + { + return m_DataLen; + } // No layer above DNS + + /** + * Does nothing for this layer + */ + virtual void computeCalculateFields() + {} + + std::string toString() const; + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelApplicationLayer; + } + + /** + * A static method that checks whether the port is considered as DNS + * @param[in] port The port number to be checked + * @return True if the port is associated with the DNS protocol + */ + static inline bool isDnsPort(uint16_t port); + + /** + * A static method that validates the input data + * @param[in] data The pointer to the beginning of a byte stream of a DNS packet + * @param[in] dataLen The length of the byte stream + * @param[in] dnsOverTcp Should be set to "true" if this is DNS is over TCP, otherwise set to "false" + * (which is also the default value) + * @return True if the data is valid and can represent a DNS packet + */ + static inline bool isDataValid(const uint8_t* data, size_t dataLen, bool dnsOverTcp = false); + + protected: + DnsLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, size_t offsetAdjustment); + explicit DnsLayer(size_t offsetAdjustment); + + private: + IDnsResource* m_ResourceList; + DnsQuery* m_FirstQuery; + DnsResource* m_FirstAnswer; + DnsResource* m_FirstAuthority; + DnsResource* m_FirstAdditional; + uint16_t m_OffsetAdjustment; + + size_t getBasicHeaderSize(); + void init(size_t offsetAdjustment, bool callParseResource); + void initNewLayer(size_t offsetAdjustment); + + IDnsResource* getFirstResource(DnsResourceType resType) const; + void setFirstResource(DnsResourceType resType, IDnsResource* resource); + + using Layer::extendLayer; + bool extendLayer(int offsetInLayer, size_t numOfBytesToExtend, IDnsResource* resource); + + using Layer::shortenLayer; + bool shortenLayer(int offsetInLayer, size_t numOfBytesToShorten, IDnsResource* resource); + + IDnsResource* getResourceByName(IDnsResource* startFrom, size_t resourceCount, const std::string& name, + bool exactMatch) const; + + void parseResources(); + + DnsResource* addResource(DnsResourceType resType, const std::string& name, DnsType dnsType, DnsClass dnsClass, + uint32_t ttl, IDnsResourceData* data); + + bool removeResource(IDnsResource* resourceToRemove); + }; + + /** + * @class DnsOverTcpLayer + * Represents the DNS over TCP layer. + * DNS over TCP is described here: https://tools.ietf.org/html/rfc7766 . + * It is very similar to DNS over UDP, except for one field: TCP message length which is added in the beginning of + * the message before the other DNS data properties. The rest of the data is similar. + * + * Note: DNS over TCP can spread over more than one packet, but this implementation doesn't support this use-case + * and assumes the whole message fits in a single packet. + */ + class DnsOverTcpLayer : public DnsLayer + { + public: + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + DnsOverTcpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : DnsLayer(data, dataLen, prevLayer, packet, sizeof(uint16_t)) + {} + + /** + * A constructor that creates an empty DNS layer: all members of dnshdr are set to 0 and layer will contain no + * records + */ + DnsOverTcpLayer() : DnsLayer(sizeof(uint16_t)) + {} + + /** + * A copy constructor for this layer + * @param[in] other The DNS over TCP layer to copy from + */ + DnsOverTcpLayer(const DnsOverTcpLayer& other) : DnsLayer(other) + {} + + /** + * @return The value of the TCP message length as described in https://tools.ietf.org/html/rfc7766#section-8 + */ + uint16_t getTcpMessageLength(); + + /** + * Set the TCP message length value as described in https://tools.ietf.org/html/rfc7766#section-8 + * @param[in] value The value to set + */ + void setTcpMessageLength(uint16_t value); + + // overridden methods + + /** + * Calculate the TCP message length field + */ + void computeCalculateFields(); + }; + + // implementation of inline methods + + bool DnsLayer::isDnsPort(uint16_t port) + { + switch (port) + { + case 53: + case 5353: + case 5355: + return true; + default: + return false; + } + } + + bool DnsLayer::isDataValid(const uint8_t* data, size_t dataLen, bool dnsOverTcp) + { + size_t minSize = sizeof(dnshdr) + (dnsOverTcp ? sizeof(uint16_t) : 0); + return data && dataLen >= minSize; + } + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/DnsLayerEnums.h b/Packet++/header/pcapplusplus/DnsLayerEnums.h new file mode 100644 index 0000000000..9c986fb9cf --- /dev/null +++ b/Packet++/header/pcapplusplus/DnsLayerEnums.h @@ -0,0 +1,154 @@ +#pragma once + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + /** + * An enum for all possible DNS record types + */ + enum DnsType + { + /** IPv4 address record */ + DNS_TYPE_A = 1, + /** Name Server record */ + DNS_TYPE_NS, + /** Obsolete, replaced by MX */ + DNS_TYPE_MD, + /** Obsolete, replaced by MX */ + DNS_TYPE_MF, + /** Canonical name record */ + DNS_TYPE_CNAME, + /** Start of Authority record */ + DNS_TYPE_SOA, + /** mailbox domain name record */ + DNS_TYPE_MB, + /** mail group member record */ + DNS_TYPE_MG, + /** mail rename domain name record */ + DNS_TYPE_MR, + /** Null record */ + DNS_TYPE_NULL_R, + /** well known service description record */ + DNS_TYPE_WKS, + /** Pointer record */ + DNS_TYPE_PTR, + /** Host information record */ + DNS_TYPE_HINFO, + /** mailbox or mail list information record */ + DNS_TYPE_MINFO, + /** Mail exchanger record */ + DNS_TYPE_MX, + /** Text record */ + DNS_TYPE_TXT, + /** Responsible person record */ + DNS_TYPE_RP, + /** AFS database record */ + DNS_TYPE_AFSDB, + /** DNS X25 resource record */ + DNS_TYPE_X25, + /** Integrated Services Digital Network record */ + DNS_TYPE_ISDN, + /** Route Through record */ + DNS_TYPE_RT, + /** network service access point address record */ + DNS_TYPE_NSAP, + /** network service access point address pointer record */ + DNS_TYPE_NSAP_PTR, + /** Signature record */ + DNS_TYPE_SIG, + /** Key record */ + DNS_TYPE_KEY, + /** Mail Mapping Information record */ + DNS_TYPE_PX, + /** DNS Geographical Position record */ + DNS_TYPE_GPOS, + /** IPv6 address record */ + DNS_TYPE_AAAA, + /** Location record */ + DNS_TYPE_LOC, + /** Obsolete record */ + DNS_TYPE_NXT, + /** DNS Endpoint Identifier record */ + DNS_TYPE_EID, + /** DNS Nimrod Locator record */ + DNS_TYPE_NIMLOC, + /** Service locator record */ + DNS_TYPE_SRV, + /** Asynchronous Transfer Mode address record */ + DNS_TYPE_ATMA, + /** Naming Authority Pointer record */ + DNS_TYPE_NAPTR, + /** Key eXchanger record */ + DNS_TYPE_KX, + /** Certificate record */ + DNS_TYPE_CERT, + /** Obsolete, replaced by AAAA type */ + DNS_TYPE_A6, + /** Delegation Name record */ + DNS_TYPE_DNAM, + /** Kitchen sink record */ + DNS_TYPE_SINK, + /** Option record */ + DNS_TYPE_OPT, + /** Address Prefix List record */ + DNS_TYPE_APL, + /** Delegation signer record */ + DNS_TYPE_DS, + /** SSH Public Key Fingerprint record */ + DNS_TYPE_SSHFP, + /** IPsec Key record */ + DNS_TYPE_IPSECKEY, + /** DNSSEC signature record */ + DNS_TYPE_RRSIG, + /** Next-Secure record */ + DNS_TYPE_NSEC, + /** DNS Key record */ + DNS_TYPE_DNSKEY, + /** DHCP identifier record */ + DNS_TYPE_DHCID, + /** NSEC record version 3 */ + DNS_TYPE_NSEC3, + /** NSEC3 parameters */ + DNS_TYPE_NSEC3PARAM, + /** All cached records */ + DNS_TYPE_ALL = 255 + }; + + /** + * An enum for all possible DNS classes + */ + enum DnsClass + { + /** Internet class */ + DNS_CLASS_IN = 1, + /** Internet class with QU flag set to True */ + DNS_CLASS_IN_QU = 32769, + /** Chaos class */ + DNS_CLASS_CH = 3, + /** Hesiod class */ + DNS_CLASS_HS = 4, + /** ANY class */ + DNS_CLASS_ANY = 255 + }; + + /** + * An enum for representing the 4 types of possible DNS records + */ + enum DnsResourceType + { + /** DNS query record */ + DnsQueryType = 0, + /** DNS answer record */ + DnsAnswerType = 1, + /** DNS authority record */ + DnsAuthorityType = 2, + /** DNS additional record */ + DnsAdditionalType = 3 + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/DnsResource.h b/Packet++/header/pcapplusplus/DnsResource.h new file mode 100644 index 0000000000..6c37fabddd --- /dev/null +++ b/Packet++/header/pcapplusplus/DnsResource.h @@ -0,0 +1,273 @@ +#pragma once + +#include "pcapplusplus/DnsLayer.h" +#include "pcapplusplus/DnsLayerEnums.h" +#include "pcapplusplus/DnsResourceData.h" +#include +#include +#include + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + // forward declarations + class DnsLayer; + class IDnsResourceData; + class DnsResourceDataPtr; + + /** + * @class IDnsResource + * An abstract class for representing all types of DNS records. This class gives access to all available record data + * such as DNS type, class, name, type of record, etc. The DnsLayer holds an instance of (inherited type of) this + * class for each DNS record in the DNS packet + */ + class IDnsResource + { + protected: + friend class DnsLayer; + friend class IDnsResourceData; + + protected: + DnsLayer* m_DnsLayer; + size_t m_OffsetInLayer; + IDnsResource* m_NextResource; + std::string m_DecodedName; + size_t m_NameLength; + uint8_t* m_ExternalRawData; + + IDnsResource(DnsLayer* dnsLayer, size_t offsetInLayer); + + IDnsResource(uint8_t* emptyRawData); + + size_t decodeName(const char* encodedName, char* result, int iteration = 1); + void encodeName(const std::string& decodedName, char* result, size_t& resultLen); + + IDnsResource* getNextResource() const + { + return m_NextResource; + } + void setNextResource(IDnsResource* next) + { + m_NextResource = next; + } + + uint8_t* getRawData() const; + + void setDnsLayer(DnsLayer* dnsLayer, size_t offsetInLayer); + + public: + virtual ~IDnsResource() + {} + + /** + * @return The DNS type of this record + */ + DnsType getDnsType() const; + + /** + * Set DNS type for this record + * @param[in] newType The type to set + */ + void setDnsType(DnsType newType); + + /** + * @return The DNS class of this record + */ + DnsClass getDnsClass() const; + + /** + * Set DNS class for this record + * @param[in] newClass The class to set + */ + void setDnsClass(DnsClass newClass); + + /** + * @return The name of this record + */ + const std::string& getName() const + { + return m_DecodedName; + } + + /** + * @return The record name's offset in the packet + */ + size_t getNameOffset() const + { + return m_OffsetInLayer; + } + + /** + * Set the name of this record. The input name can be a standard hostname (e.g 'google.com'), or it may contain + * a pointer to another string in the packet (as explained here: http://www.zytrax.com/books/dns/ch15/#name). + * The pointer is used to reduce the DNS packet size and avoid unnecessary duplications. In case you + * want to use a pointer in your string you should use the following format: 'some.domain.#{offset}' where + * '#{offset}' is a the offset from the start of the layer. For example: if the string 'yahoo.com' already + * appears in offset 12 in the packet and you want to set the name of the current record to + * 'my.subdomain.yahoo.com' you may use the following string: 'my.subdomain.#12'. This will result in writing + * 'my.subdomain' and a pointer to offset 12.
Please notice the new name can be shorter or longer of the old + * name, so this method can cause the packet to be shorten or extended + * @param[in] newName The name to set + * @return True if name was set successfully or false if input string is malformed or if an error occurred + */ + bool setName(const std::string& newName); + + // abstract methods + + /** + * @return The total size in bytes of this record + */ + virtual size_t getSize() const = 0; + + /** + * @return The type of this record (query, answer, authority, additional) + */ + virtual DnsResourceType getType() const = 0; + }; + + /** + * @class DnsQuery + * Representing a DNS query record + */ + class DnsQuery : public IDnsResource + { + friend class DnsLayer; + + private: + DnsQuery(DnsLayer* dnsLayer, size_t offsetInLayer) : IDnsResource(dnsLayer, offsetInLayer) + {} + + explicit DnsQuery(uint8_t* emptyRawData) : IDnsResource(emptyRawData) + {} + + public: + virtual ~DnsQuery() + {} + + // implementation of abstract methods + virtual size_t getSize() const + { + return m_NameLength + 2 * sizeof(uint16_t); + } + virtual DnsResourceType getType() const + { + return DnsQueryType; + } + }; + + /** + * @class DnsResource + * Representing DNS record other than DNS query + */ + class DnsResource : public IDnsResource + { + friend class DnsLayer; + + private: + DnsResourceType m_ResourceType; + + DnsResource(DnsLayer* dnsLayer, size_t offsetInLayer, DnsResourceType resourceType) + : IDnsResource(dnsLayer, offsetInLayer) + { + m_ResourceType = resourceType; + } + + DnsResource(uint8_t* emptyRawData, DnsResourceType resType) + : IDnsResource(emptyRawData), m_ResourceType(resType) + {} + + public: + virtual ~DnsResource() + {} + + /** + * @return The time-to-leave value for this record + */ + uint32_t getTTL() const; + + /** + * Set time-to-leave value for this record + * @param[in] newTTL The new TTL value to set + */ + void setTTL(uint32_t newTTL); + + /** + * @return The data length value for this record (taken from the "data length" field of the record) + */ + size_t getDataLength() const; + + /** + * @return A smart pointer to an IDnsResourceData object that contains the DNS resource data. It is guaranteed + * that the smart pointer will always point to an object and never to nullptr. The specific object type depends + * on the DNS type of this record:
+ * - For type A (::DNS_TYPE_A): the return value is a smart pointer to IPv4DnsResourceData object that contains + * the IPv4 address
+ * - For type AAAA (::DNS_TYPE_AAAA): the return value is a smart pointer to IPv6DnsResourceData object that + * contains the IPv6 address
+ * - For types NS, CNAME, DNAME, PTR (::DNS_TYPE_NS, ::DNS_TYPE_CNAME, ::DNS_TYPE_DNAM, ::DNS_TYPE_PTR): the + * return value is a smart pointer to StringDnsResourceData object that contains the name
+ * - For type MX (::DNS_TYPE_MX): the return value is a smart pointer to MxDnsResourceData object that contains + * the MX data (preference and mail exchange name)
+ * - For all other types: the return value is a smart pointer to GenericDnsResourceData which contains a byte + * array of the data + */ + DnsResourceDataPtr getData() const; + + /** + * @return The offset of data in the DNS layer + */ + size_t getDataOffset() const; + + /** + * Set resource data. The given IDnsResourceData input object is validated against the DNS type of the resource. + * For example: if DNS type is A and data isn't of type IPv4DnsResourceData (which contains the IPv4 address) a + * log error will be printed and the method will return false. This method currently supports the following DNS + * types:
+ * - ::DNS_TYPE_A (IPv4 address) - data is expected to be a pointer to IPv4DnsResourceData with a valid IPv4 + * address + * - ::DNS_TYPE_AAAA (IPv6 address) - data is expected to be a pointer to IPv6DnsResourceData with a valid IPv6 + * address + * - ::DNS_TYPE_NS, ::DNS_TYPE_CNAME, ::DNS_TYPE_DNAM, ::DNS_TYPE_PTR (name data) - data is expected to be a + * pointer to StringDnsResourceData object that contains a host name, e.g: 'www.google.com' + * - ::DNS_TYPE_MX (MX data) - data is expected to be a pointer to MxDnsResourceData object that contains the MX + * data + * - else: data is expected to be a pointer to GenericDnsResourceData object that contains a valid hex string + * (valid hex string means a string which has an even number of characters representing a valid hex data. e.g: + * '0d0a45569a9b') + * @param[in] data The pointer to the data object, as described above + * @return True if data was properly set or false if data is illegal or method couldn't extend or shorted the + * packet (appropriate error log is printed in all cases) + */ + bool setData(IDnsResourceData* data); + + /** + * Some records don't have a DNS class and the bytes used for storing the DNS class are used for other purpose. + * This method enables the user to receive these bytes + * @return The value stored in this place + */ + uint16_t getCustomDnsClass() const; + + /** + * Some records don't have a DNS class and the bytes used for storing the DNS class are used for other purpose. + * This method enables the user to set these bytes + * @param[in] customValue The value to set + */ + void setCustomDnsClass(uint16_t customValue); + + // implementation of abstract methods + virtual size_t getSize() const + { + return m_NameLength + 3 * sizeof(uint16_t) + sizeof(uint32_t) + getDataLength(); + } + virtual DnsResourceType getType() const + { + return m_ResourceType; + } + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/DnsResourceData.h b/Packet++/header/pcapplusplus/DnsResourceData.h new file mode 100644 index 0000000000..f4a8b96e6a --- /dev/null +++ b/Packet++/header/pcapplusplus/DnsResourceData.h @@ -0,0 +1,415 @@ +#pragma once + +#include "pcapplusplus/DnsResource.h" +#include "pcapplusplus/IpAddress.h" +#include +#include +#include + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + // forward declarations + class IDnsResource; + + /** + * @class IDnsResourceData + * A wrapper class for storing DNS RR (resource record) data. This is the base class which introduces several + * abstract methods for derived classes to implement for setting and retrieving the stored data. Each derived class + * will store different type of DNS RR data and implement these methods accordingly (for example: IPv4/IPv6 + * addresses, MX data, hostnames, raw byte data etc.) + */ + class IDnsResourceData + { + protected: + // unimplemented private copy c'tor + IDnsResourceData(const IDnsResourceData& other); + IDnsResourceData() + {} + + size_t decodeName(const char* encodedName, char* result, IDnsResource* dnsResource) const; + void encodeName(const std::string& decodedName, char* result, size_t& resultLen, + IDnsResource* dnsResource) const; + + public: + /** + * A virtual d'tor, does nothing + */ + virtual ~IDnsResourceData() + {} + + /** + * A templated method which takes a class that derives from IDnsResourceData as the template argument and + * checks whether this instance is of this type + * @return True if this instance is of the requested type, false otherwise + */ + template bool isTypeOf() const + { + return dynamic_cast(this) != nullptr; + } + + /** + * A templated method which take a class that derives from IDnsResourceData as the template argument and tries + * to cast the current instance as that type + * @return A pointer to the current instance casted as the requested type or nullptr if this instance isn't of + * this type + */ + template IDnsResourceDataType* castAs() + { + return dynamic_cast(this); + } + + /** + * @return A string that represents the current DNS RR data + */ + virtual std::string toString() const = 0; + + /** + * Convert the DNS RR data into a byte array + * @param[out] arr A pointer to a pre-allocated byte array where the result will be written to + * @param[out] arrLength A reference to a 2-byte number where the result array length will be written to + * @param[in] dnsResource A pointer to a DNS resource object where this DNS RR data will be stored + * @return True if the DNS RR data was successfully converted into a byte array and written to the given array + * or false if stored DNS RR data is invalid or if it could not be written to the given array + */ + virtual bool toByteArr(uint8_t* arr, size_t& arrLength, IDnsResource* dnsResource) const = 0; + }; + + /** + * @class DnsResourceDataPtr + * A smart pointer class that holds pointers of type IDnsResourceData. This object is used in DnsResource#getData() + */ + class DnsResourceDataPtr : public std::unique_ptr + { + public: + /** + * A c'tor to this class + * @param[in] ptr A pointer to IDnsResourceData + */ + explicit DnsResourceDataPtr(IDnsResourceData* ptr) : std::unique_ptr(ptr) + {} + + /** + * A templated method which takes a class that derives from IDnsResourceData as the template argument and + * checks whether the pointer stored in this object is of this type + * @return True if the stored pointer is of the requested type, false otherwise + */ + template bool isTypeOf() const + { + return get()->isTypeOf(); + } + + /** + * A templated method which take a class that derives from IDnsResourceData as the template argument and tries + * to cast the pointer stored in this object as that type + * @return A pointer to the stored pointer casted as the requested type or nullptr if it isn't of this type + */ + template IDnsResourceDataType* castAs() + { + return get()->castAs(); + } + }; + + /** + * @class StringDnsResourceData + * A class that represents DNS RR string data, mainly used in DNS RRs that store hostnames (like CNAME, DNAME, NS, + * etc.) + */ + class StringDnsResourceData : public IDnsResourceData + { + private: + std::string m_Data; + + public: + /** + * A c'tor for this class + * @param[in] data The string data to store in this object. If this string represents a hostname it's possible + * to include a pointer to another string in the DNS layer (as explained here: + * http://www.zytrax.com/books/dns/ch15/#name). These pointers are often used to reduce the DNS packet size and + * avoid unnecessary duplications. The way to include pointers in a hostname string is to use the following + * format: 'some.domain.#{offset}' where '#{offset}' is the offset from the start of the DNS layer. For example: + * if the string 'yahoo.com' already appears in offset 12 in the packet and you want to set the DNS RR data as + * 'my.subdomain.yahoo.com' you may use the following string: 'my.subdomain.#12'. This will result in writing + * 'my.subdomain' and a pointer to offset 12 + */ + explicit StringDnsResourceData(const std::string& data) : m_Data(data) + {} + + StringDnsResourceData(const uint8_t* dataPtr, size_t dataLen, IDnsResource* dnsResource); + + ~StringDnsResourceData() + {} + + /** + * Equality operator overload for this class that compares the strings stored in each object + * @param[in] other The object to compare with + * @return True if the string data is the same in both objects, false otherwise + */ + bool operator==(const StringDnsResourceData& other) const + { + return m_Data == other.m_Data; + } + + // implement abstract methods + + std::string toString() const + { + return m_Data; + } + bool toByteArr(uint8_t* arr, size_t& arrLength, IDnsResource* dnsResource) const; + }; + + /** + * @class IPv4DnsResourceData + * A class that represents DNS RR IPv4 data, mainly used in DNS RRs of type ::DNS_TYPE_A + */ + class IPv4DnsResourceData : public IDnsResourceData + { + private: + IPv4Address m_Data; + + public: + /** + * A c'tor for this class + * @param[in] dataPtr A byte array of size 4 that contains an IPv4 address (each byte represents 1 octet) + * @param[in] dataLen The byte array size, expected to be 4 + */ + IPv4DnsResourceData(const uint8_t* dataPtr, size_t dataLen); + + /** + * A c'tor for this class + * @param[in] addr The IPv4 address to store in this object + */ + explicit IPv4DnsResourceData(const IPv4Address& addr) : m_Data(addr) + {} + + /** + * A c'tor for this class + * @param[in] addrAsString A string representation of an IPv4 address to store in this object + */ + explicit IPv4DnsResourceData(const std::string& addrAsString) : m_Data(addrAsString) + {} + + /** + * Equality operator overload for this class that compares the IPv4 addresses stored in each object + * @param[in] other The object to compare with + * @return True if IPv4 addresses are the same in both objects, false otherwise + */ + bool operator==(const IPv4DnsResourceData& other) const + { + return m_Data == other.m_Data; + } + + /** + * @return The IPv4 address stored in this object + */ + IPv4Address getIpAddress() const + { + return m_Data; + } + + // implement abstract methods + + std::string toString() const + { + return m_Data.toString(); + } + bool toByteArr(uint8_t* arr, size_t& arrLength, IDnsResource* dnsResource) const; + }; + + /** + * @class IPv6DnsResourceData + * A class that represents DNS RR IPv6 data, mainly used in DNS RRs of type ::DNS_TYPE_AAAA + */ + class IPv6DnsResourceData : public IDnsResourceData + { + private: + IPv6Address m_Data; + + public: + /** + * A c'tor for this class + * @param[in] dataPtr A byte array of size 16 that contains an IPv6 address (each byte represents 1 octet) + * @param[in] dataLen The byte array size, expected to be 16 + */ + IPv6DnsResourceData(const uint8_t* dataPtr, size_t dataLen); + + /** + * A c'tor for this class + * @param[in] addr The IPv6 address to store in this object + */ + explicit IPv6DnsResourceData(const IPv6Address& addr) : m_Data(addr) + {} + + /** + * A c'tor for this class + * @param[in] addrAsString A string representation of an IPv6 address to store in this object + */ + explicit IPv6DnsResourceData(const std::string& addrAsString) : m_Data(addrAsString) + {} + + /** + * Equality operator overload for this class that compares the IPv6 addresses stored in each object + * @param[in] other The object to compare with + * @return True if IPv6 addresses are the same in both objects, false otherwise + */ + bool operator==(const IPv6DnsResourceData& other) const + { + return m_Data == other.m_Data; + } + + /** + * @return The IPv6 address stored in this object + */ + IPv6Address getIpAddress() const + { + return m_Data; + } + + // implement abstract methods + + std::string toString() const + { + return m_Data.toString(); + } + bool toByteArr(uint8_t* arr, size_t& arrLength, IDnsResource* dnsResource) const; + }; + + /** + * @class MxDnsResourceData + * A class that represents DNS RR mail exchange (MX) data, used in DNS RRs of type ::DNS_TYPE_MX + */ + class MxDnsResourceData : public IDnsResourceData + { + public: + /** + * A struct that represents mail exchange (MX) data + */ + struct MxData + { + /** Preference value */ + uint16_t preference; + /** Mail exchange hostname */ + std::string mailExchange; + }; + + /** + * A c'tor for this class + * @param[in] dataPtr A byte array that contains the raw MX data (as written in the DNS packet) + * @param[in] dataLen The byte array size + * @param[in] dnsResource A pointer to a DNS resource object where this DNS RR data will be stored + */ + MxDnsResourceData(uint8_t* dataPtr, size_t dataLen, IDnsResource* dnsResource); + + /** + * A c'tor for this class + * @param[in] preference The MX preference value to store in this object + * @param[in] mailExchange The MX hostname value to store in this object. It's possible to include a pointer to + * another string in the DNS layer (as explained here: http://www.zytrax.com/books/dns/ch15/#name). These + * pointers are often used to reduce the DNS packet size and avoid unnecessary duplications. The way to include + * pointers in the hostname string is to use the following format: 'some.domain.#{offset}' where '#{offset}' is + * the offset from the start of the DNS layer. For example: if the string 'yahoo.com' already appears in offset + * 12 in the packet and you want to set the DNS RR data as 'my.subdomain.yahoo.com' you may use the following + * string: 'my.subdomain.#12'. This will result in writing 'my.subdomain' and a pointer to offset 12 + */ + MxDnsResourceData(const uint16_t& preference, const std::string& mailExchange); + + ~MxDnsResourceData() + {} + + /** + * Equality operator overload for this class that compares the MX data stored in each object + * @param[in] other The object to compare with + * @return True if MX data is the same in both objects, meaning both preference and MX hostname are the same, + * false otherwise + */ + bool operator==(const MxDnsResourceData& other) const; + + /** + * @return The MX data stored in this object + */ + MxData getMxData() const + { + return m_Data; + } + + /** + * Set the MX data stored in this object + * @param[in] preference The MX preference value to store in this object + * @param[in] mailExchange The MX hostname value to store in this object + */ + void setMxData(uint16_t preference, std::string mailExchange); + + // implement abstract methods + + /** + * A string representation of the MX data stored in this object. The string format is as follows: + * 'pref: {preference_value}; mx: {mail_exchange_hostname_value}' + */ + std::string toString() const; + + bool toByteArr(uint8_t* arr, size_t& arrLength, IDnsResource* dnsResource) const; + + private: + MxData m_Data; + }; + + /** + * @class GenericDnsResourceData + * A class that represents generic DNS RR data which cannot be represented in any of the other classes. It stores + * the DNS RR data as byte array + */ + class GenericDnsResourceData : public IDnsResourceData + { + private: + uint8_t* m_Data; + size_t m_DataLen; + + public: + /** + * A c'tor for this class + * @param[in] dataPtr A byte array that contains the raw data (as it written in the DNS packet). The data will + * be copied from this byte array to the object + * @param[in] dataLen The byte array size + */ + GenericDnsResourceData(const uint8_t* dataPtr, size_t dataLen); + + /** + * A c'tor for this class + * @param[in] dataAsHexString A hex string that represents the DNS RR data + */ + explicit GenericDnsResourceData(const std::string& dataAsHexString); + + /** + * A copy c'tor for this class + * @param[in] other The instance to copy from + */ + GenericDnsResourceData(const GenericDnsResourceData& other); + + ~GenericDnsResourceData() + { + if (m_Data != nullptr) + delete[] m_Data; + } + + GenericDnsResourceData& operator=(const GenericDnsResourceData& other); + + /** + * Equality operator overload for this class that compares the raw data stored in each object + * @param[in] other The object to compare with + * @return True if data is the same in both objects, meaning byte streams are equal, false otherwise + */ + bool operator==(const GenericDnsResourceData& other) const; + + // implement abstract methods + + std::string toString() const; + bool toByteArr(uint8_t* arr, size_t& arrLength, IDnsResource* dnsResource) const; + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/EthDot3Layer.h b/Packet++/header/pcapplusplus/EthDot3Layer.h new file mode 100644 index 0000000000..59b4ade1a7 --- /dev/null +++ b/Packet++/header/pcapplusplus/EthDot3Layer.h @@ -0,0 +1,153 @@ +#pragma once + +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/MacAddress.h" + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * @struct ether_dot3_header + * Represents an IEEE 802.3 Ethernet header + */ +#pragma pack(push, 1) + struct ether_dot3_header + { + /** Destination MAC */ + uint8_t dstMac[6]; + /** Source MAC */ + uint8_t srcMac[6]; + /** EtherType */ + uint16_t length; + }; +#pragma pack(pop) + + /** + * @class EthDot3Layer + * Represents an IEEE 802.3 Ethernet protocol layer + */ + class EthDot3Layer : public Layer + { + public: + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data (will be casted to ether_dot3_header) + * @param[in] dataLen Size of the data in bytes + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + EthDot3Layer(uint8_t* data, size_t dataLen, Packet* packet) + : Layer(data, dataLen, nullptr, packet, EthernetDot3) + {} + + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data (will be casted to ether_header) + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + EthDot3Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : Layer(data, dataLen, prevLayer, packet, EthernetDot3) + {} + + /** + * A constructor that creates a new IEEE 802.3 Ethernet header and allocates the data + * @param[in] sourceMac The source MAC address + * @param[in] destMac The destination MAC address + * @param[in] length The frame length + */ + EthDot3Layer(const MacAddress& sourceMac, const MacAddress& destMac, uint16_t length); + + ~EthDot3Layer() + {} + + /** + * Get a pointer to the Ethernet header. Notice this points directly to the data, so every change will change + * the actual packet data + * @return A pointer to the ether_header + */ + ether_dot3_header* getEthHeader() const + { + return (ether_dot3_header*)m_Data; + } + + /** + * Get the source MAC address + * @return The source MAC address + */ + MacAddress getSourceMac() const + { + return MacAddress(getEthHeader()->srcMac); + } + + /** + * Set source MAC address + * @param sourceMac Source MAC to set + */ + void setSourceMac(const MacAddress& sourceMac) + { + sourceMac.copyTo(getEthHeader()->srcMac); + } + + /** + * Get the destination MAC address + * @return The destination MAC address + */ + MacAddress getDestMac() const + { + return MacAddress(getEthHeader()->dstMac); + } + + /** + * Set destination MAC address + * @param destMac Destination MAC to set + */ + void setDestMac(const MacAddress& destMac) + { + destMac.copyTo(getEthHeader()->dstMac); + } + + // implement abstract methods + + /** + * Parses next layer + */ + void parseNextLayer(); + + /** + * @return Size of ether_dot3_header + */ + size_t getHeaderLen() const + { + return sizeof(ether_dot3_header); + } + + /** + * Does nothing for this layer + */ + void computeCalculateFields() + {} + + std::string toString() const; + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelDataLinkLayer; + } + + /** + * A static method that validates the input data + * @param[in] data The pointer to the beginning of a byte stream of an IEEE 802.3 Eth packet + * @param[in] dataLen The length of the byte stream + * @return True if the data is valid and can represent an IEEE 802.3 Eth packet + */ + static bool isDataValid(const uint8_t* data, size_t dataLen); + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/EthLayer.h b/Packet++/header/pcapplusplus/EthLayer.h new file mode 100644 index 0000000000..a3d6073a6a --- /dev/null +++ b/Packet++/header/pcapplusplus/EthLayer.h @@ -0,0 +1,190 @@ +#pragma once + +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/MacAddress.h" + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * @struct ether_header + * Represents an Ethernet II header + */ +#pragma pack(push, 1) + struct ether_header + { + /** Destination MAC */ + uint8_t dstMac[6]; + /** Source MAC */ + uint8_t srcMac[6]; + /** EtherType */ + uint16_t etherType; + }; +#pragma pack(pop) + + /* Ethernet protocol ID's */ + + /** IP */ +#define PCPP_ETHERTYPE_IP 0x0800 + /** Address resolution */ +#define PCPP_ETHERTYPE_ARP 0x0806 + /** Transparent Ethernet Bridging */ +#define PCPP_ETHERTYPE_ETHBRIDGE 0x6558 + /** Reverse ARP */ +#define PCPP_ETHERTYPE_REVARP 0x8035 + /** AppleTalk protocol */ +#define PCPP_ETHERTYPE_AT 0x809B + /** AppleTalk ARP */ +#define PCPP_ETHERTYPE_AARP 0x80F3 + /** IEEE 802.1Q VLAN tagging */ +#define PCPP_ETHERTYPE_VLAN 0x8100 + /** IPX */ +#define PCPP_ETHERTYPE_IPX 0x8137 + /** IP protocol version 6 */ +#define PCPP_ETHERTYPE_IPV6 0x86dd + /** used to test interfaces */ +#define PCPP_ETHERTYPE_LOOPBACK 0x9000 + /** PPPoE discovery */ +#define PCPP_ETHERTYPE_PPPOED 0x8863 + /** PPPoE session */ +#define PCPP_ETHERTYPE_PPPOES 0x8864 + /** MPLS */ +#define PCPP_ETHERTYPE_MPLS 0x8847 + /** Point-to-point protocol (PPP) */ +#define PCPP_ETHERTYPE_PPP 0x880B + /** RDMA over Converged Ethernet (RoCEv1) */ +#define PCPP_ETHERTYPE_ROCEV1 0x8915 + /** IEEE 802.1ad Provider Bridge, Q-in-Q */ +#define PCPP_ETHERTYPE_IEEE_802_1AD 0x88A8 + /** Wake on LAN */ +#define PCPP_ETHERTYPE_WAKE_ON_LAN 0x0842 + + /** + * @class EthLayer + * Represents an Ethernet II protocol layer + */ + class EthLayer : public Layer + { + public: + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data (will be casted to ether_header) + * @param[in] dataLen Size of the data in bytes + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + EthLayer(uint8_t* data, size_t dataLen, Packet* packet) : Layer(data, dataLen, nullptr, packet, Ethernet) + {} + + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data (will be casted to ether_header) + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + EthLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : Layer(data, dataLen, prevLayer, packet, Ethernet) + {} + + /** + * A constructor that creates a new Ethernet header and allocates the data + * @param[in] sourceMac The source MAC address + * @param[in] destMac The destination MAC address + * @param[in] etherType The EtherType to be used. It's an optional parameter, a value of 0 will be set if not + * provided + */ + EthLayer(const MacAddress& sourceMac, const MacAddress& destMac, uint16_t etherType = 0); + + ~EthLayer() + {} + + /** + * Get a pointer to the Ethernet header. Notice this points directly to the data, so every change will change + * the actual packet data + * @return A pointer to the ether_header + */ + inline ether_header* getEthHeader() const + { + return (ether_header*)m_Data; + } + + /** + * Get the source MAC address + * @return The source MAC address + */ + inline MacAddress getSourceMac() const + { + return MacAddress(getEthHeader()->srcMac); + } + + /** + * Set source MAC address + * @param sourceMac Source MAC to set + */ + inline void setSourceMac(const MacAddress& sourceMac) + { + sourceMac.copyTo(getEthHeader()->srcMac); + } + + /** + * Get the destination MAC address + * @return The destination MAC address + */ + inline MacAddress getDestMac() const + { + return MacAddress(getEthHeader()->dstMac); + } + + /** + * Set destination MAC address + * @param destMac Destination MAC to set + */ + inline void setDestMac(const MacAddress& destMac) + { + destMac.copyTo(getEthHeader()->dstMac); + } + + // implement abstract methods + + /** + * Currently identifies the following next layers: IPv4Layer, IPv6Layer, ArpLayer, VlanLayer, PPPoESessionLayer, + * PPPoEDiscoveryLayer, MplsLayer. Otherwise sets PayloadLayer + */ + void parseNextLayer(); + + /** + * @return Size of ether_header + */ + size_t getHeaderLen() const + { + return sizeof(ether_header); + } + + /** + * Calculate ether_header#etherType for known protocols: IPv4, IPv6, ARP, VLAN + */ + void computeCalculateFields(); + + std::string toString() const; + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelDataLinkLayer; + } + + /** + * A static method that validates the input data + * @param[in] data The pointer to the beginning of a byte stream of an Ethernet II packet + * @param[in] dataLen The length of the byte stream + * @return True if the data is valid and can represent an Ethernet II packet + */ + static bool isDataValid(const uint8_t* data, size_t dataLen); + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/FtpLayer.h b/Packet++/header/pcapplusplus/FtpLayer.h new file mode 100644 index 0000000000..599f327b2c --- /dev/null +++ b/Packet++/header/pcapplusplus/FtpLayer.h @@ -0,0 +1,518 @@ +#pragma once + +#include "pcapplusplus/SingleCommandTextProtocol.h" +#include "pcapplusplus/PayloadLayer.h" + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * Class for general FTP message + */ + class FtpLayer : public SingleCommandTextProtocol + { + protected: + FtpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : SingleCommandTextProtocol(data, dataLen, prevLayer, packet, FTP) {}; + FtpLayer(const std::string& command, const std::string& option) + : SingleCommandTextProtocol(command, option, FTP) {}; + + public: + /** + * A static method that checks whether the port is considered as FTP control + * @param[in] port The port number to be checked + */ + static bool isFtpPort(uint16_t port) + { + return port == 21; + } + + /** + * A static method that checks whether the port is considered as FTP data + * @param[in] port The port number to be checked + */ + static bool isFtpDataPort(uint16_t port) + { + return port == 20; + } + + // overridden methods + + /// FTP is the always last so does nothing for this layer + void parseNextLayer() + {} + + /** + * @return Get the size of the layer + */ + size_t getHeaderLen() const + { + return m_DataLen; + } + + /// Does nothing for this layer + void computeCalculateFields() + {} + + /** + * @return The OSI layer level of FTP (Application Layer). + */ + OsiModelLayer getOsiModelLayer() const + { + return OsiModelApplicationLayer; + } + }; + + /** + * Class for representing the request messages of FTP Layer + */ + class FtpRequestLayer : public FtpLayer + { + public: + /** + * Enum for FTP command codes + */ + enum class FtpCommand : int + { + /// Unknown command + UNK, + /// Abort an active file transfer. + ABOR = ('A') | ('B' << 8) | ('O' << 16) | ('R' << 24), + /// Account information. + ACCT = ('A') | ('C' << 8) | ('C' << 16) | ('T' << 24), + /// Authentication/Security Data + ADAT = ('A') | ('D' << 8) | ('A' << 16) | ('T' << 24), + /// Allocate sufficient disk space to receive a file. + ALLO = ('A') | ('L' << 8) | ('L' << 16) | ('O' << 24), + /// Append (with create) + APPE = ('A') | ('P' << 8) | ('P' << 16) | ('E' << 24), + /// Authentication/Security Mechanism + AUTH = ('A') | ('U' << 8) | ('T' << 16) | ('H' << 24), + /// Get the available space + AVBL = ('A') | ('V' << 8) | ('B' << 16) | ('L' << 24), + /// Clear Command Channel + CCC = ('C') | ('C' << 8) | ('C' << 16), + /// Change to Parent Directory. + CDUP = ('C') | ('D' << 8) | ('U' << 16) | ('P' << 24), + /// Confidentiality Protection Command + CONF = ('C') | ('O' << 8) | ('N' << 16) | ('F' << 24), + /// Client / Server Identification + CSID = ('C') | ('S' << 8) | ('I' << 16) | ('D' << 24), + /// Change working directory. + CWD = ('C') | ('W' << 8) | ('D' << 16), + /// Delete file. + DELE = ('D') | ('E' << 8) | ('L' << 16) | ('E' << 24), + /// Get the directory size + DSIZ = ('D') | ('S' << 8) | ('I' << 16) | ('Z' << 24), + /// Privacy Protected Channel + ENC = ('E') | ('N' << 8) | ('C' << 16), + /// Specifies an extended address and port to which the server should connect. + EPRT = ('E') | ('P' << 8) | ('R' << 16) | ('T' << 24), + /// Enter extended passive mode. + EPSV = ('E') | ('P' << 8) | ('S' << 16) | ('V' << 24), + /// Get the feature list implemented by the server. + FEAT = ('F') | ('E' << 8) | ('A' << 16) | ('T' << 24), + /// Returns usage documentation on a command if specified, else a general help document is returned. + HELP = ('H') | ('E' << 8) | ('L' << 16) | ('P' << 24), + /// Identify desired virtual host on server, by name. + HOST = ('H') | ('O' << 8) | ('S' << 16) | ('T' << 24), + /// Language Negotiation + LANG = ('L') | ('A' << 8) | ('N' << 16) | ('G' << 24), + /// Returns information of a file or directory if specified, else information of the current working + /// directory is returned. + LIST = ('L') | ('I' << 8) | ('S' << 16) | ('T' << 24), + /// Specifies a long address and port to which the server should connect. + LPRT = ('L') | ('P' << 8) | ('R' << 16) | ('T' << 24), + /// Enter long passive mode. + LPSV = ('L') | ('P' << 8) | ('S' << 16) | ('V' << 24), + /// Return the last-modified time of a specified file. + MDTM = ('M') | ('D' << 8) | ('T' << 16) | ('M' << 24), + /// Modify the creation time of a file. + MFCT = ('M') | ('F' << 8) | ('C' << 16) | ('T' << 24), + /// Modify fact (the last modification time, creation time, UNIX group/owner/mode of a file). + MFF = ('M') | ('F' << 8) | ('F' << 16), + /// Modify the last modification time of a file. + MFMT = ('M') | ('F' << 8) | ('M' << 16) | ('T' << 24), + /// Integrity Protected Command + MIC = ('M') | ('I' << 8) | ('C' << 16), + /// Make directory. + MKD = ('M') | ('K' << 8) | ('D' << 16), + /// Lists the contents of a directory in a standardized machine-readable format. + MLSD = ('M') | ('L' << 8) | ('S' << 16) | ('D' << 24), + /// Provides data about exactly the object named on its command line in a standardized machine-readable + /// format. + MLST = ('M') | ('L' << 8) | ('S' << 16) | ('T' << 24), + /// Sets the transfer mode (Stream, Block, or Compressed). + MODE = ('M') | ('O' << 8) | ('D' << 16) | ('E' << 24), + /// Returns a list of file names in a specified directory. + NLST = ('N') | ('L' << 8) | ('S' << 16) | ('T' << 24), + /// No operation (dummy packet; used mostly on keepalives). + NOOP = ('N') | ('O' << 8) | ('O' << 16) | ('P' << 24), + /// Select options for a feature (for example OPTS UTF8 ON). + OPTS = ('O') | ('P' << 8) | ('T' << 16) | ('S' << 24), + /// Authentication password. + PASS = ('P') | ('A' << 8) | ('S' << 16) | ('S' << 24), + /// Enter passive mode. + PASV = ('P') | ('A' << 8) | ('S' << 16) | ('V' << 24), + /// Protection Buffer Size + PBSZ = ('P') | ('B' << 8) | ('S' << 16) | ('Z' << 24), + /// Specifies an address and port to which the server should connect. + PORT = ('P') | ('O' << 8) | ('R' << 16) | ('T' << 24), + /// Data Channel Protection Level. + PROT = ('P') | ('R' << 8) | ('O' << 16) | ('T' << 24), + /// Print working directory. Returns the current directory of the host. + PWD = ('P') | ('W' << 8) | ('D' << 16), + /// Disconnect. + QUIT = ('Q') | ('U' << 8) | ('I' << 16) | ('T' << 24), + /// Re initializes the connection. + REIN = ('R') | ('E' << 8) | ('I' << 16) | ('N' << 24), + /// Restart transfer from the specified point. + REST = ('R') | ('E' << 8) | ('S' << 16) | ('T' << 24), + /// Retrieve a copy of the file + RETR = ('R') | ('E' << 8) | ('T' << 16) | ('R' << 24), + /// Remove a directory. + RMD = ('R') | ('M' << 8) | ('D' << 16), + /// Remove a directory tree + RMDA = ('R') | ('M' << 8) | ('D' << 16) | ('A' << 24), + /// Rename from. + RNFR = ('R') | ('N' << 8) | ('F' << 16) | ('R' << 24), + /// Rename to. + RNTO = ('R') | ('N' << 8) | ('T' << 16) | ('O' << 24), + /// Sends site specific commands to remote server (like SITE IDLE 60 or SITE UMASK 002). Inspect SITE HELP + /// output for complete list of supported commands. + SITE = ('S') | ('I' << 8) | ('T' << 16) | ('E' << 24), + /// Return the size of a file. + SIZE = ('S') | ('I' << 8) | ('Z' << 16) | ('E' << 24), + /// Mount file structure. + SMNT = ('S') | ('M' << 8) | ('N' << 16) | ('T' << 24), + /// Use single port passive mode (only one TCP port number for both control connections and passive-mode + /// data connections) + SPSV = ('S') | ('P' << 8) | ('S' << 16) | ('V' << 24), + /// Returns information on the server status, including the status of the current connection + STAT = ('S') | ('T' << 8) | ('A' << 16) | ('T' << 24), + /// Accept the data and to store the data as a file at the server site + STOR = ('S') | ('T' << 8) | ('O' << 16) | ('R' << 24), + /// Store file uniquely. + STOU = ('S') | ('T' << 8) | ('O' << 16) | ('U' << 24), + /// Set file transfer structure. + STRU = ('S') | ('T' << 8) | ('R' << 16) | ('U' << 24), + /// Return system type. + SYST = ('S') | ('Y' << 8) | ('S' << 16) | ('T' << 24), + /// Get a thumbnail of a remote image file + THMB = ('T') | ('H' << 8) | ('M' << 16) | ('B' << 24), + /// Sets the transfer mode (ASCII/Binary). + TYPE = ('T') | ('Y' << 8) | ('P' << 16) | ('E' << 24), + /// Authentication username. + USER = ('U') | ('S' << 8) | ('E' << 16) | ('R' << 24), + /// Change to the parent of the current working directory + XCUP = ('X') | ('C' << 8) | ('U' << 16) | ('P' << 24), + /// Make a directory + XMKD = ('X') | ('M' << 8) | ('K' << 16) | ('D' << 24), + /// Print the current working directory + XPWD = ('X') | ('P' << 8) | ('W' << 16) | ('D' << 24), + /// + XRCP = ('X') | ('R' << 8) | ('C' << 16) | ('P' << 24), + /// Remove the directory + XRMD = ('X') | ('R' << 8) | ('M' << 16) | ('D' << 24), + /// + XRSQ = ('X') | ('R' << 8) | ('S' << 16) | ('Q' << 24), + /// Send, mail if cannot + XSEM = ('X') | ('S' << 8) | ('E' << 16) | ('M' << 24), + /// Send to terminal + XSEN = ('X') | ('S' << 8) | ('E' << 16) | ('N' << 24) + }; + + /** A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + FtpRequestLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : FtpLayer(data, dataLen, prevLayer, packet) {}; + + /** + * A constructor that creates layer with provided input values + * @param[in] command FTP command + * @param[in] option Argument of the command + */ + explicit FtpRequestLayer(const FtpCommand& command, const std::string& option = "") + : FtpLayer(getCommandAsString(command), option) {}; + + /** + * Set the command of request message + * @param[in] code Value to set command + * @return True if the operation is successful, false otherwise + */ + bool setCommand(FtpCommand code); + + /** + * Get the command of request message + * @return FtpCommand Value of the command + */ + FtpCommand getCommand() const; + + /** + * Get the command of request message as string + * @return std::string Value of the command as string + */ + std::string getCommandString() const; + + /** + * Set the command argument of request message + * @param[in] value Value to set command argument + * @return True if the operation is successful, false otherwise + */ + bool setCommandOption(const std::string& value); + + /** + * Get the command argument of request message + * @param[in] removeEscapeCharacters Whether non-alphanumerical characters should be removed or not + * @return std::string Value of command argument + */ + std::string getCommandOption(bool removeEscapeCharacters = true) const; + + /** + * Convert the command info to readable string + * @param[in] code Command code to convert + * @return std::string Returns the command info as readable string + */ + static std::string getCommandInfo(FtpCommand code); + + /** + * Convert the command to readable string + * @param[in] code Command code to convert + * @return std::string Returns the command as readable string + */ + static std::string getCommandAsString(FtpCommand code); + + // overridden methods + + /** + * @return Returns the protocol info as readable string + */ + std::string toString() const; + }; + + /** + * Class for representing the response messages of FTP Layer + */ + class FtpResponseLayer : public FtpLayer + { + public: + /** + * Enum for FTP response codes + */ + enum class FtpStatusCode : int + { + /// Unknown status code + UNKNOWN, + /// Restart marker reply + RESTART_MARKER = 110, + /// Service ready in nnn minutes + SERVICE_READY_IN_MIN = 120, + /// Data connection already open; transfer starting + DATA_ALREADY_OPEN_START_TRANSFER = 125, + /// File status okay; about to open data connection + FILE_OK = 150, + /// Command okay + COMMAND_OK = 200, + /// Command not implemented, superfluous at this site + COMMAND_NOT_IMPLEMENTED_SUPERFLUOUS = 202, + /// System status, or system help reply + SYSTEM_STATUS = 211, + /// Directory status + DIR_STATUS = 212, + /// File status + FILE_STATUS = 213, + /// Help message + HELP_MESSAGE = 214, + /// NAME system type + NAME_SYSTEM_TYPE = 215, + /// Service ready for new user + SERVICE_READY_FOR_USER = 220, + /// Service closing control connection + SERVICE_CLOSING_CONTROL = 221, + /// Data connection open; no transfer in progress + DATA_OPEN_NO_TRANSFER = 225, + /// Closing data connection + CLOSING_DATA = 226, + /// Entering Passive Mode + ENTERING_PASSIVE = 227, + /// Entering Extended Passive Mode + ENTERING_EXTENDED_PASSIVE = 229, + /// User logged in, proceed + USER_LOG_IN_PROCEED = 230, + /// User logged in, authorized by security data exchange + USER_LOG_IN_AUTHORIZED = 232, + /// Security data exchange complete + SEC_DATA_EXCHANGE_COMPLETE = 234, + /// Security data exchange completed successfully + SEC_DATA_EXCHANGE_COMPLETE_SUCCESS = 235, + /// Requested file action okay, completed + REQ_FILE_OK_COMPLETE = 250, + /// PATHNAME created + PATHNAME_CREATED = 257, + /// User name okay, need password + USER_OK_NEED_PASSWORD = 331, + /// Need account for login + NEED_ACCOUNT = 332, + /// Requested security mechanism is ok + REQ_SEC_MECHANISM_OK = 334, + /// Security data is acceptable, more is required + SEC_IS_ACCEPTABLE = 335, + /// Username okay, need password. Challenge is ... + USER_OK_NEED_PASS_CHALLENGE = 336, + /// Requested file action pending further information + FILE_PENDING_ACTION = 350, + /// Service not available, closing control connection + SERVICE_NOT_AVAILABLE = 421, + /// Can't open data connection + CANT_OPEN_DATA_CONNECTION = 425, + /// Connection closed; transfer aborted + CONNECTION_CLOSED = 426, + /// Need some unavailable resource to process security + NEED_UNAVAILABLE_RESOURCE_TO_SEC = 431, + /// Requested file action not taken + REQ_FILE_ACTION_NOT_TAKEN = 450, + /// Requested action aborted: local error in processing + REQ_ACTION_ABORTED = 451, + /// Requested action not taken. Insufficient storage space in system + REQ_ACTION_NOT_TAKEN = 452, + /// Syntax error, command unrecognized + SYNTAX_ERROR_COMMAND_UNRECOGNIZED = 500, + /// Syntax error in parameters or arguments + SYNTAX_ERROR_PARAMETER_OR_ARGUMENT = 501, + /// Command not implemented + COMMAND_NOT_IMPLEMENTED = 502, + /// Bad sequence of commands + BAD_SEQUENCE_COMMANDS = 503, + /// Command not implemented for that parameter + COMMAND_NOT_IMPLEMENTED_FOR_PARAMETER = 504, + /// Network protocol not supported + NETWORK_PROTOCOL_NOT_SUPPORTED = 522, + /// Not logged in + NOT_LOGGED_IN = 530, + /// Need account for storing files + NEED_ACCOUNT_FOR_STORE_FILE = 532, + /// Command protection level denied for policy reasons + COMMAND_PROTECTION_DENIED = 533, + /// Request denied for policy reasons + REQUEST_DENIED = 534, + /// Failed security check (hash, sequence, etc) + FAILED_SEC_CHECK = 535, + /// Requested PROT level not supported by mechanism + REQ_PROT_LEVEL_NOT_SUPPORTED = 536, + /// Command protection level not supported by security mechanism + COMMAND_PROTECTION_LEVEL_NOT_SUPPORTED = 537, + /// Requested action not taken: File unavailable + FILE_UNAVAILABLE = 550, + /// Requested action aborted: page type unknown + PAGE_TYPE_UNKNOWN = 551, + /// Requested file action aborted: Exceeded storage allocation + EXCEED_STORAGE_ALLOCATION = 552, + /// Requested action not taken: File name not allowed + FILENAME_NOT_ALLOWED = 553, + /// Integrity protected reply + INTEGRITY_PROTECTED = 631, + /// Confidentiality and integrity protected reply + CONFIDENTIALITY_AND_INTEGRITY_PROTECTED = 632, + /// Confidentiality protected reply + CONFIDENTIALITY_PROTECTED = 633 + }; + + /** A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + FtpResponseLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : FtpLayer(data, dataLen, prevLayer, packet) {}; + + /** + * A constructor that creates layer with provided input values + * @param[in] code Status code + * @param[in] option Argument of the status code + */ + explicit FtpResponseLayer(const FtpStatusCode& code, const std::string& option = "") + : FtpLayer(std::to_string(int(code)), option) {}; + + /** + * Set the status code of response message + * @param[in] code Value to set status code + * @return True if the operation is successful, false otherwise + */ + bool setStatusCode(FtpStatusCode code); + + /** + * Get the status code of response message + * @return FtpStatusCode Value of the status code + */ + FtpStatusCode getStatusCode() const; + + /** + * Get the status code of response message as string + * @return std::string Value of the status code as string + */ + std::string getStatusCodeString() const; + + /** + * Set the argument of response message + * @param[in] value Value to set argument + * @return True if the operation is successful, false otherwise + */ + bool setStatusOption(const std::string& value); + + /** + * Get the argument of response message + * @param[in] removeEscapeCharacters Whether non-alphanumerical characters should be removed or not + * @return std::string Value of argument + */ + std::string getStatusOption(bool removeEscapeCharacters = true) const; + + /** + * Convert the status code to readable string + * @param[in] code Status code to convert + * @return std::string Returns the status info as readable string + */ + static std::string getStatusCodeAsString(FtpStatusCode code); + + // overridden methods + + /** + * @return Returns the protocol info as readable string + */ + std::string toString() const; + }; + + /** + * Class for representing the data of FTP Layer + */ + class FtpDataLayer : public PayloadLayer + { + public: + /** A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + FtpDataLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : PayloadLayer(data, dataLen, prevLayer, packet) + { + m_Protocol = FTP; + }; + + /** + * @return Returns the protocol info as readable string + */ + std::string toString() const; + }; +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/GreLayer.h b/Packet++/header/pcapplusplus/GreLayer.h new file mode 100644 index 0000000000..5ec057f418 --- /dev/null +++ b/Packet++/header/pcapplusplus/GreLayer.h @@ -0,0 +1,468 @@ +#pragma once + +#include "pcapplusplus/Layer.h" + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * @struct gre_basic_header + * Represents GRE basic protocol header (common for GREv0 and GREv1) + */ +#pragma pack(push, 1) + struct gre_basic_header + { +#if (BYTE_ORDER == LITTLE_ENDIAN) + /** Number of additional encapsulations which are permitted. 0 is the default value */ + uint8_t recursionControl : 3, + /** Strict source routing bit (GRE v0 only) */ + strictSourceRouteBit : 1, + /** Set if sequence number exists */ + sequenceNumBit : 1, + /** Set if key exists */ + keyBit : 1, + /** Set if routing exists (GRE v0 only) */ + routingBit : 1, + /** Set if checksum exists (GRE v0 only) */ + checksumBit : 1; +#else + /** Set if checksum exists (GRE v0 only) */ + uint8_t checksumBit : 1, + /** Set if routing exists (GRE v0 only) */ + routingBit : 1, + /** Set if key exists */ + keyBit : 1, + /** Set if sequence number exists */ + sequenceNumBit : 1, + /** Strict source routing bit (GRE v0 only) */ + strictSourceRouteBit : 1, + /** Number of additional encapsulations which are permitted. 0 is the default value */ + recursionControl : 3; +#endif +#if (BYTE_ORDER == LITTLE_ENDIAN) + /** GRE version - can be 0 or 1 */ + uint8_t version : 3, + /** Reserved */ + flags : 4, + /** Set if acknowledgment number is set (GRE v1 only) */ + ackSequenceNumBit : 1; +#else + /** Set if acknowledgment number is set (GRE v1 only) */ + uint8_t ackSequenceNumBit : 1, + /** Reserved */ + flags : 4, + /** GRE version - can be 0 or 1 */ + version : 3; +#endif + + /** Protocol type of the next layer */ + uint16_t protocol; + }; +#pragma pack(pop) + + /** + * @struct gre1_header + * Represents GREv1 protocol header + */ +#pragma pack(push, 1) + struct gre1_header : gre_basic_header + { + /** Size of the payload not including the GRE header */ + uint16_t payloadLength; + /** Contains the Peer's Call ID for the session to which this packet belongs */ + uint16_t callID; + }; +#pragma pack(pop) + + /** + * @struct ppp_pptp_header + * Represents PPP layer that comes after GREv1 as part of PPTP protocol + */ +#pragma pack(push, 1) + struct ppp_pptp_header + { + /** Broadcast address */ + uint8_t address; + /** Control byte */ + uint8_t control; + /** Protocol type of the next layer (see PPP_* macros at PPPoELayer.h) */ + uint16_t protocol; + }; +#pragma pack(pop) + + /** + * @class GreLayer + * Abstract base class for GRE layers (GREv0Layer and GREv1Layer). Cannot be instantiated and contains common logic + * for derived classes + */ + class GreLayer : public Layer + { + public: + virtual ~GreLayer() + {} + + /** + * A static method that determines the GRE version of GRE layer raw data by looking at the + * gre_basic_header#version field + * @param[in] greData GRE layer raw data + * @param[in] greDataLen Size of raw data + * @return ::GREv0 or ::GREv1 values if raw data is GREv0 or GREv1 (accordingly) or ::UnknownProtocol otherwise + */ + static ProtocolType getGREVersion(uint8_t* greData, size_t greDataLen); + + /** + * Get sequence number value if field exists in layer + * @param[out] seqNumber The returned sequence number value if exists in layer. Else remain unchanged + * @return True if sequence number field exists in layer. In this case seqNumber will be filled with the value. + * Or false if sequence number field doesn't exist in layer + */ + bool getSequenceNumber(uint32_t& seqNumber) const; + + /** + * Set sequence number value. If field already exists (gre_basic_header#sequenceNumBit is set) then only the new + * value is set. If field doesn't exist it will be added to the layer, gre_basic_header#sequenceNumBit will be + * set and the new value will be set + * @param[in] seqNumber The sequence number value to set + * @return True if managed to set the value successfully, or false otherwise (if couldn't extend the layer) + */ + bool setSequenceNumber(uint32_t seqNumber); + + /** + * Unset sequence number and remove it from the layer + * @return True if managed to unset successfully or false (and error log) if sequence number wasn't set in the + * first place or if didn't manage to remove it from the layer + */ + bool unsetSequenceNumber(); + + // implement abstract methods + + /** + * Currently identifies the following next layers: + * IPv4Layer, IPv6Layer, VlanLayer, MplsLayer, PPP_PPTPLayer, EthLayer, EthDot3Layer + * Otherwise sets PayloadLayer + */ + void parseNextLayer(); + + /** + * @return Size of GRE header (may change if optional fields are added or removed) + */ + size_t getHeaderLen() const; + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelNetworkLayer; + } + + protected: + GreLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, ProtocolType protocol) + : Layer(data, dataLen, prevLayer, packet, protocol) + {} + + GreLayer() + {} + + enum GreField + { + GreChecksumOrRouting = 0, + GreKey = 1, + GreSeq = 2, + GreAck = 3 + }; + + uint8_t* getFieldValue(GreField field, bool returnOffsetEvenIfFieldMissing) const; + + void computeCalculateFieldsInner(); + }; + + /** + * @class GREv0Layer + * Represents a GRE version 0 protocol. Limitation: currently this layer doesn't support GRE routing information + * parsing and editing. So if a GREv0 packet includes routing information it won't be parse correctly. I didn't add + * it because of lack of time, but if you need it please tell me and I'll add it + */ + class GREv0Layer : public GreLayer + { + public: + /** A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + GREv0Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : GreLayer(data, dataLen, prevLayer, packet, GREv0) + {} + + /** + * A constructor that creates a new GREv0 header and allocates the data + */ + GREv0Layer(); + + virtual ~GREv0Layer() + {} + + /** + * Get a pointer to the basic GRE header containing only non-optional fields. Notice this points directly to the + * data, so every change will change the actual packet data. Also please notice that changing the set bits + * (gre_basic_header#strictSourceRouteBit, gre_basic_header#sequenceNumBit, gre_basic_header#keyBit, + * gre_basic_header#routingBit, gre_basic_header#checksumBit, gre_basic_header#ackSequenceNumBit) without using + * the proper set or unset methods (such as setChecksum(), unsetChecksum(), etc.) may result to wrong + * calculation of header length and really weird bugs. Please avoid doing so + * @return A pointer to the gre_basic_header + */ + gre_basic_header* getGreHeader() const + { + return (gre_basic_header*)m_Data; + } + + /** + * Get checksum value if field exists in layer + * @param[out] checksum The returned checksum value if exists in layer. Else remain unchanged + * @return True if checksum field exists in layer. In this case checksum parameter will be filled with the + * value. Or false if checksum field doesn't exist in layer + */ + bool getChecksum(uint16_t& checksum); + + /** + * Set checksum value. If checksum or offset fields already exist (gre_basic_header#checksumBit or + * gre_basic_header#routingBit are set) then only the new value is set. If both fields don't exist a new 4-byte + * value will be added to the layer, gre_basic_header#checksumBit will be set (gre_basic_header#routingBit will + * remain unset), the new checksum value will be set and offset value will be set to 0. The reason both fields + * are added is that GREv0 protocol states both of them or none of them should exist on packet (even if only one + * of the bits are set) + * @param[in] checksum The checksum value to set + * @return True if managed to set the value/s successfully, or false otherwise (if couldn't extend the layer) + */ + bool setChecksum(uint16_t checksum); + + /** + * Unset checksum and possibly remove it from the layer. It will be removed from the layer only if + * gre_basic_header#routingBit is not set as well. Otherwise checksum field will remain on packet with value of + * 0 + * @return True if managed to unset successfully or false (and error log) if checksum wasn't set in the first + * place or if didn't manage to remove it from the layer + */ + bool unsetChecksum(); + + /** + * Get offset value if field exists in layer. Notice there is no setOffset() method as GRE routing information + * isn't supported yet (see comment on class description) + * @param[out] offset The returned offset value if exists in layer. Else remain unchanged + * @return True if offset field exists in layer. In this case offset parameter will be filled with the value. + * Or false if offset field doesn't exist in layer + */ + bool getOffset(uint16_t& offset) const; + + /** + * Get key value if field exists in layer + * @param[out] key The returned key value if exists in layer. Else remain unchanged + * @return True if key field exists in layer. In this case key parameter will be filled with the value. + * Or false if key field doesn't exist in layer + */ + bool getKey(uint32_t& key) const; + + /** + * Set key value. If field already exists (gre_basic_header#keyBit is set) then only the new value is set. + * If field doesn't exist it will be added to the layer, gre_basic_header#keyBit will be set + * and the new value will be set + * @param[in] key The key value to set + * @return True if managed to set the value successfully, or false otherwise (if couldn't extend the layer) + */ + bool setKey(uint32_t key); + + /** + * Unset key and remove it from the layer + * @return True if managed to unset successfully or false (and error log) if key wasn't set in the first + * place or if didn't manage to remove it from the layer + */ + bool unsetKey(); + + /** + * A static method that validates the input data + * @param[in] data The pointer to the beginning of a byte stream of an GREv0 layer + * @param[in] dataLen The length of the byte stream + * @return True if the data is valid and can represent an GREv0 layer + */ + static inline bool isDataValid(const uint8_t* data, size_t dataLen) + { + return data && dataLen >= sizeof(gre_basic_header); + } + + // implement abstract methods + + /** + * Calculate the following fields: + * - gre_basic_header#protocol + * - GRE checksum field (if exists in packet) + */ + void computeCalculateFields(); + + std::string toString() const; + }; + + /** + * @class GREv1Layer + * Represents a GRE version 1 protocol + */ + class GREv1Layer : public GreLayer + { + public: + /** A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + GREv1Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : GreLayer(data, dataLen, prevLayer, packet, GREv1) + {} + + /** + * A constructor that creates a new GREv1 header and allocates the data + * @param[in] callID The call ID to set + */ + explicit GREv1Layer(uint16_t callID); + + virtual ~GREv1Layer() + {} + + /** + * Get a pointer to the basic GREv1 header containing all non-optional fields. Notice this points directly to + * the data, so every change will change the actual packet data. Also please notice that changing the set bits + * (gre_basic_header#strictSourceRouteBit, gre_basic_header#sequenceNumBit, gre_basic_header#keyBit, + * gre_basic_header#routingBit, gre_basic_header#checksumBit, gre_basic_header#ackSequenceNumBit) without using + * the proper set or unset methods (such as setAcknowledgmentNum(), unsetSequenceNumber(), etc.) may result to + * wrong calculation of header length or illegal GREv1 packet and to some really weird bugs. Please avoid doing + * so + * @return A pointer to the gre1_header + */ + gre1_header* getGreHeader() const + { + return (gre1_header*)m_Data; + } + + /** + * Get acknowledgment (ack) number value if field exists in layer + * @param[out] ackNum The returned ack number value if exists in layer. Else remain unchanged + * @return True if ack number field exists in layer. In this case ackNum will be filled with the value. + * Or false if ack number field doesn't exist in layer + */ + bool getAcknowledgmentNum(uint32_t& ackNum) const; + + /** + * Set acknowledgment (ack) number value. If field already exists (gre_basic_header#ackSequenceNumBit is set) + * then only the new value is set. If field doesn't exist it will be added to the layer, + * gre_basic_header#ackSequenceNumBit will be set and the new value will be set + * @param[in] ackNum The ack number value to set + * @return True if managed to set the value successfully, or false otherwise (if couldn't extend the layer) + */ + bool setAcknowledgmentNum(uint32_t ackNum); + + /** + * Unset acknowledgment (ack) number and remove it from the layer + * @return True if managed to unset successfully or false (and error log) if ack number wasn't set in the first + * place or if didn't manage to remove it from the layer + */ + bool unsetAcknowledgmentNum(); + + /** + * A static method that validates the input data + * @param[in] data The pointer to the beginning of a byte stream of an GREv1 layer + * @param[in] dataLen The length of the byte stream + * @return True if the data is valid and can represent an GREv1 layer + */ + static inline bool isDataValid(const uint8_t* data, size_t dataLen) + { + return data && dataLen >= sizeof(gre1_header); + } + + // implement abstract methods + + /** + * Calculate the following fields: + * - gre1_header#payloadLength + * - gre_basic_header#protocol + */ + void computeCalculateFields(); + + std::string toString() const; + }; + + /** + * @class PPP_PPTPLayer + * Represent a PPP (point-to-point) protocol header that comes after GREv1 header, as part of PPTP - Point-to-Point + * Tunneling Protocol + */ + class PPP_PPTPLayer : public Layer + { + public: + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data (will be casted to @ref ppp_pptp_header) + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + PPP_PPTPLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : Layer(data, dataLen, prevLayer, packet, PPP_PPTP) + {} + + /** + * A constructor that allocates a new PPP-PPTP header + * @param[in] address Address field + * @param[in] control Control field + */ + PPP_PPTPLayer(uint8_t address, uint8_t control); + + ~PPP_PPTPLayer() + {} + + /** + * Get a pointer to the PPP-PPTP header. Notice this points directly to the data, so every change will change + * the actual packet data + * @return A pointer to the @ref ppp_pptp_header + */ + ppp_pptp_header* getPPP_PPTPHeader() const + { + return (ppp_pptp_header*)m_Data; + } + + // implement abstract methods + + /** + * Currently identifies the following next layers: IPv4Layer, IPv6Layer. Otherwise sets PayloadLayer + */ + void parseNextLayer(); + + /** + * @return The size of @ref ppp_pptp_header + */ + size_t getHeaderLen() const + { + return sizeof(ppp_pptp_header); + } + + /** + * Calculate the following fields: + * - ppp_pptp_header#protocol + */ + void computeCalculateFields(); + + std::string toString() const + { + return "PPP for PPTP Layer"; + } + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelSesionLayer; + } + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/GtpLayer.h b/Packet++/header/pcapplusplus/GtpLayer.h new file mode 100644 index 0000000000..019fde1079 --- /dev/null +++ b/Packet++/header/pcapplusplus/GtpLayer.h @@ -0,0 +1,480 @@ +#pragma once + +#include "pcapplusplus/Layer.h" + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + +#pragma pack(push, 1) + /** + * @struct gtpv1_header + * GTP v1 common message header + */ + struct gtpv1_header + { +#if (BYTE_ORDER == LITTLE_ENDIAN) + /** A 1-bit value that states whether there is a N-PDU number optional field */ + uint8_t npduNumberFlag : 1, + /** A 1-bit value that states whether there is a Sequence Number optional field */ + sequenceNumberFlag : 1, + /** A 1-bit value that states whether there is an extension header optional field */ + extensionHeaderFlag : 1, + /** Reserved bit */ + reserved : 1, + /** A 1-bit value that differentiates GTP (value 1) from GTP' (value 0) */ + protocolType : 1, + /** GTP version */ + version : 3; +#else + /** GTP version */ + uint8_t version : 3, + /** A 1-bit value that differentiates GTP (value 1) from GTP' (value 0) */ + protocolType : 1, + /** Reserved bit */ + reserved : 1, + /** A 1-bit value that states whether there is an extension header optional field */ + extensionHeaderFlag : 1, + /** A 1-bit value that states whether there is a Sequence Number optional field */ + sequenceNumberFlag : 1, + /** A 1-bit value that states whether there is a N-PDU number optional field */ + npduNumberFlag : 1; +#endif + /** An 8-bit field that indicates the type of GTP message */ + uint8_t messageType; + + /** A 16-bit field that indicates the length of the payload in bytes (rest of the packet following the mandatory + * 8-byte GTP header). Includes the optional fields */ + uint16_t messageLength; + + /** Tunnel endpoint identifier - A 32-bit(4-octet) field used to multiplex different connections in the same GTP + * tunnel */ + uint32_t teid; + }; + +#pragma pack(pop) + + /** + * An enum representing the possible GTP v1 message types. + * All of the message types except for #GtpV1_GPDU are considered GTP-C messages. #GtpV1_GPDU is considered a GTP-U + * message + */ + enum GtpV1MessageType + { + /** GTPv1 Message Type Unknown */ + GtpV1_MessageTypeUnknown = 0, + /** Echo Request */ + GtpV1_EchoRequest = 1, + /** Echo Response */ + GtpV1_EchoResponse = 2, + /** Version Not Supported */ + GtpV1_VersionNotSupported = 3, + /** Node Alive Request */ + GtpV1_NodeAliveRequest = 4, + /** Node Alive Response */ + GtpV1_NodeAliveResponse = 5, + /** Redirection Request */ + GtpV1_RedirectionRequest = 6, + /** Create PDP Context Request */ + GtpV1_CreatePDPContextRequest = 7, + /** Create PDP Context Response */ + GtpV1_CreatePDPContextResponse = 16, + /** Update PDP Context Request */ + GtpV1_UpdatePDPContextRequest = 17, + /** Update PDP Context Response */ + GtpV1_UpdatePDPContextResponse = 18, + /** Delete PDP Context Request */ + GtpV1_DeletePDPContextRequest = 19, + /** Delete PDP Context Response */ + GtpV1_DeletePDPContextResponse = 20, + /** Initiate PDP Context Activation Request */ + GtpV1_InitiatePDPContextActivationRequest = 22, + /** Initiate PDP Context Activation Response */ + GtpV1_InitiatePDPContextActivationResponse = 23, + /** Error Indication */ + GtpV1_ErrorIndication = 26, + /** PDU Notification Request */ + GtpV1_PDUNotificationRequest = 27, + /** PDU Notification Response */ + GtpV1_PDUNotificationResponse = 28, + /** PDU Notification Reject Request */ + GtpV1_PDUNotificationRejectRequest = 29, + /** PDU Notification Reject Response */ + GtpV1_PDUNotificationRejectResponse = 30, + /** Supported Extensions Header Notification */ + GtpV1_SupportedExtensionsHeaderNotification = 31, + /** Send Routing for GPRS Request */ + GtpV1_SendRoutingforGPRSRequest = 32, + /** Send Routing for GPRS Response */ + GtpV1_SendRoutingforGPRSResponse = 33, + /** Failure Report Request */ + GtpV1_FailureReportRequest = 34, + /** Failure Report Response */ + GtpV1_FailureReportResponse = 35, + /** Note MS Present Request */ + GtpV1_NoteMSPresentRequest = 36, + /** Note MS Present Response */ + GtpV1_NoteMSPresentResponse = 37, + /** Identification Request */ + GtpV1_IdentificationRequest = 38, + /** Identification Response */ + GtpV1_IdentificationResponse = 39, + /** SGSN Context Request */ + GtpV1_SGSNContextRequest = 50, + /** SGSN Context Response */ + GtpV1_SGSNContextResponse = 51, + /** SGSN Context Acknowledge */ + GtpV1_SGSNContextAcknowledge = 52, + /** Forward Relocation Request */ + GtpV1_ForwardRelocationRequest = 53, + /** Forward Relocation Response */ + GtpV1_ForwardRelocationResponse = 54, + /** Forward Relocation Complete */ + GtpV1_ForwardRelocationComplete = 55, + /** Relocation Cancel Request */ + GtpV1_RelocationCancelRequest = 56, + /** Relocation Cancel Response */ + GtpV1_RelocationCancelResponse = 57, + /** Forward SRNS Context */ + GtpV1_ForwardSRNSContext = 58, + /** Forward Relocation Complete Acknowledge */ + GtpV1_ForwardRelocationCompleteAcknowledge = 59, + /** Forward SRNS Context Acknowledge */ + GtpV1_ForwardSRNSContextAcknowledge = 60, + /** UE Registration Request */ + GtpV1_UERegistrationRequest = 61, + /** UE Registration Response */ + GtpV1_UERegistrationResponse = 62, + /** RAN Information Relay */ + GtpV1_RANInformationRelay = 70, + /** MBMS Notification Request */ + GtpV1_MBMSNotificationRequest = 96, + /** MBMS Notification Response */ + GtpV1_MBMSNotificationResponse = 97, + /** MBMS Notification Reject Request */ + GtpV1_MBMSNotificationRejectRequest = 98, + /** MBMS Notification Reject Response */ + GtpV1_MBMSNotificationRejectResponse = 99, + /** Create MBMS Notification Request */ + GtpV1_CreateMBMSNotificationRequest = 100, + /** Create MBMS Notification Response */ + GtpV1_CreateMBMSNotificationResponse = 101, + /** Update MBMS Notification Request */ + GtpV1_UpdateMBMSNotificationRequest = 102, + /** Update MBMS Notification Response */ + GtpV1_UpdateMBMSNotificationResponse = 103, + /** Delete MBMS Notification Request */ + GtpV1_DeleteMBMSNotificationRequest = 104, + /** Delete MBMS Notification Response */ + GtpV1_DeleteMBMSNotificationResponse = 105, + /** MBMS Registration Request */ + GtpV1_MBMSRegistrationRequest = 112, + /** MBMS Registration Response */ + GtpV1_MBMSRegistrationResponse = 113, + /** MBMS De-Registration Request */ + GtpV1_MBMSDeRegistrationRequest = 114, + /** MBMS De-Registration Response */ + GtpV1_MBMSDeRegistrationResponse = 115, + /** MBMS Session Start Request */ + GtpV1_MBMSSessionStartRequest = 116, + /** MBMS Session Start Response */ + GtpV1_MBMSSessionStartResponse = 117, + /** MBMS Session Stop Request */ + GtpV1_MBMSSessionStopRequest = 118, + /** MBMS Session Stop Response */ + GtpV1_MBMSSessionStopResponse = 119, + /** MBMS Session Update Request */ + GtpV1_MBMSSessionUpdateRequest = 120, + /** MBMS Session Update Response */ + GtpV1_MBMSSessionUpdateResponse = 121, + /** MS Info Change Request */ + GtpV1_MSInfoChangeRequest = 128, + /** MS Info Change Response */ + GtpV1_MSInfoChangeResponse = 129, + /** Data Record Transfer Request */ + GtpV1_DataRecordTransferRequest = 240, + /** Data Record Transfer Response */ + GtpV1_DataRecordTransferResponse = 241, + /** End Marker */ + GtpV1_EndMarker = 254, + /** G-PDU */ + GtpV1_GPDU = 255 + }; + + /** + * @class GtpV1Layer + * A class representing the [GTP v1](https://en.wikipedia.org/wiki/GPRS_Tunnelling_Protocol) protocol. + */ + class GtpV1Layer : public Layer + { + private: + struct gtpv1_header_extra + { + uint16_t sequenceNumber; + uint8_t npduNumber; + uint8_t nextExtensionHeader; + }; + + gtpv1_header_extra* getHeaderExtra() const; + + void init(GtpV1MessageType messageType, uint32_t teid, bool setSeqNum, uint16_t seqNum, bool setNpduNum, + uint8_t npduNum); + + public: + /** + * @class GtpExtension + * A class that represents [GTP header extensions](https://en.wikipedia.org/wiki/GPRS_Tunnelling_Protocol) + */ + class GtpExtension + { + friend class GtpV1Layer; + + private: + uint8_t* m_Data; + size_t m_DataLen; + uint8_t m_ExtType; + + GtpExtension(uint8_t* data, size_t dataLen, uint8_t type); + + void setNextHeaderType(uint8_t nextHeaderType); + + static GtpExtension createGtpExtension(uint8_t* data, size_t dataLen, uint8_t extType, uint16_t content); + + public: + /** + * An empty c'tor that creates an empty object, meaning one that isNull() returns "true") + */ + GtpExtension(); + + /** + * A copy c'tor for this class + * @param[in] other The GTP extension to copy from + */ + GtpExtension(const GtpExtension& other); + + /** + * An assignment operator for this class + * @param[in] other The extension to assign from + * @return A reference to the assignee + */ + GtpExtension& operator=(const GtpExtension& other); + + /** + * @return Instances of this class may be initialized as empty, meaning they don't contain any data. In + * these cases this method returns true + */ + bool isNull() const; + + /** + * @return The extension type. If the object is empty a value of zero is returned + */ + uint8_t getExtensionType() const; + + /** + * @return The total length of the extension including the length and next extension type fields. + * If the object is empty a value of zero is returned + */ + size_t getTotalLength() const; + + /** + * @return The length of the extension's content, excluding the extension length and next extension type + * fields. If the object is empty a value of zero is returned + */ + size_t getContentLength() const; + + /** + * @return A byte array that includes the extension's content. The length of this array can be determined by + * getContentLength(). If the object is empty a null value is returned + */ + uint8_t* getContent() const; + + /** + * @return The extension type of the next header. If there are no more header extensions or if this object + * is empty a value of zero is returned + */ + uint8_t getNextExtensionHeaderType() const; + + /** + * @return An instance of this class representing the next extension header, if exists in the message. If + * there are no more header extensions or if this object is empty an empty instance of GtpExtension is + * returned, meaning one that GtpExtension#isNull() returns "true" + */ + GtpExtension getNextExtension() const; + }; // GtpExtension + + virtual ~GtpV1Layer() + {} + + /** A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + GtpV1Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : Layer(data, dataLen, prevLayer, packet, GTPv1) + {} + + /** + * A constructor that creates a new GTPv1 layer and sets the message type and the TEID value + * @param[in] messageType The GTPv1 message type to be set in the newly created layer + * @param[in] teid The TEID value to be set in the newly created layer + */ + GtpV1Layer(GtpV1MessageType messageType, uint32_t teid); + + /** + * A constructor that creates a new GTPv1 layer and sets various parameters + * @param[in] messageType The GTPv1 message type to be set in the newly created layer + * @param[in] teid The TEID value to be set in the newly created layer + * @param[in] setSeqNum A flag indicating whether to set a sequence number. If set to "false" then the parameter + * "seqNum" will be ignored + * @param[in] seqNum The sequence number to be set in the newly created later. If "setSeqNum" is set to false + * this parameter will be ignored + * @param[in] setNpduNum A flag indicating whether to set the N-PDU number. If set to "false" then the parameter + * "npduNum" will be ignored + * @param[in] npduNum The N-PDU number to be set in the newly created later. If "setNpduNum" is set to false + * this parameter will be ignored + */ + GtpV1Layer(GtpV1MessageType messageType, uint32_t teid, bool setSeqNum, uint16_t seqNum, bool setNpduNum, + uint8_t npduNum); + + /** + * A static method that takes a byte array and detects whether it is a GTP v1 message + * @param[in] data A byte array + * @param[in] dataSize The byte array size (in bytes) + * @return True if the data is identified as GTP v1 message (GTP-C or GTP-U) + */ + static bool isGTPv1(const uint8_t* data, size_t dataSize); + + /** + * @return The GTP v1 common header structure. Notice this points directly to the data, so every change will + * change the actual packet data + */ + gtpv1_header* getHeader() const + { + return (gtpv1_header*)m_Data; + } + + /** + * Get the sequence number if exists on the message (sequence number is an optional field in GTP messages) + * @param[out] seqNumber Set with the sequence number value if exists in the layer. Otherwise remains unchanged + * @return True if the sequence number field exists in layer, in which case seqNumber is set with the value. + * Or false otherwise + */ + bool getSequenceNumber(uint16_t& seqNumber) const; + + /** + * Set a sequence number + * @param[in] seqNumber The sequence number to set + * @return True if the value was set successfully, false otherwise. In case of failure a corresponding error + * message will be written to log + */ + bool setSequenceNumber(const uint16_t seqNumber); + + /** + * Get the N-PDU number if exists on the message (N-PDU number is an optional field in GTP messages) + * @param[out] npduNum Set with the N-PDU number value if exists in the layer. Otherwise remains unchanged + * @return True if the N-PDU number field exists in layer, in which case npduNum is set with the value. + * Or false otherwise + */ + bool getNpduNumber(uint8_t& npduNum) const; + + /** + * Set an N-PDU number + * @param[in] npduNum The N-PDU number to set + * @return True if the value was set successfully, false otherwise. In case of failure a corresponding error + * message will be written to log + */ + bool setNpduNumber(const uint8_t npduNum); + + /** + * Get the type of the next header extension if exists on the message (extensions are optional in GTP messages) + * @param[out] nextExtType Set with the next header extension type if exists in layer. Otherwise remains + * unchanged + * @return True if the message contains header extensions, in which case nextExtType is set to the next + * header extension type. If there are no header extensions false is returned and nextExtType remains unchanged + */ + bool getNextExtensionHeaderType(uint8_t& nextExtType) const; + + /** + * @return An object that represents the next extension header, if exists in the message. If there are no + * extensions an empty object is returned, meaning an object which GtpExtension#isNull() returns "true" + */ + GtpExtension getNextExtension() const; + + /** + * Add a GTPv1 header extension. It is assumed that the extension is 4 bytes in length and its content is 2 + * bytes in length. If you need a different content size please reach out to me. This method takes care of + * extending the layer to make room for the new extension and also sets the relevant flags and fields + * @param[in] extensionType The type of the new extension + * @param[in] extensionContent A 2-byte long content + * @return An object representing the newly added extension. If there was an error adding the extension a null + * object will be returned (meaning GtpExtension#isNull() will return "true") and a corresponding error message + * will be written to log + */ + GtpExtension addExtension(uint8_t extensionType, uint16_t extensionContent); + + /** + * @return The message type of this GTP packet + */ + GtpV1MessageType getMessageType() const; + + /** + * @return A string representation of the packet's message type + */ + std::string getMessageTypeAsString() const; + + /** + * @return True if this is a GTP-U message, false otherwise + */ + bool isGTPUMessage() const; + + /** + * @return True if this is a GTP-C message, false otherwise + */ + bool isGTPCMessage() const; + + /** + * A static method that checks whether the port is considered as GTPv1 + * @param[in] port The port number to be checked + * @return True if the port matches those associated with the BGP protocol + */ + static bool isGTPv1Port(uint16_t port) + { + return port == 2152 /* GTP-U */ || port == 2123 /* GTP-C */; + } + + // implement abstract methods + + /** + * Identifies the following next layers for GTP-U packets: IPv4Layer, IPv6Layer. Otherwise sets PayloadLayer + */ + void parseNextLayer(); + + /** + * @return The size of the GTP header. For GTP-C packets the size is determined by the value of + * gtpv1_header#messageLength and for GTP-U the size only includes the GTP header itself (meaning + * the size of gtpv1_header plus the size of the optional fields such as sequence number, N-PDU + * or extensions if exist) + */ + size_t getHeaderLen() const; + + /** + * Calculate the following fields: + * - gtpv1_header#messageLength + */ + void computeCalculateFields(); + + std::string toString() const; + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelTransportLayer; + } + }; +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/HttpLayer.h b/Packet++/header/pcapplusplus/HttpLayer.h new file mode 100644 index 0000000000..a9e5f61018 --- /dev/null +++ b/Packet++/header/pcapplusplus/HttpLayer.h @@ -0,0 +1,888 @@ +#pragma once + +#include "pcapplusplus/DeprecationUtils.h" +#include "pcapplusplus/TextBasedProtocol.h" +#include +#include + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * An enum for HTTP version + */ + enum HttpVersion + { + /** HTTP/0.9 */ + ZeroDotNine, + /** HTTP/1.0 */ + OneDotZero, + /** HTTP/1.1 */ + OneDotOne, + /** Unknown HTTP version */ + HttpVersionUnknown + }; + + // some popular HTTP fields + + /** Host field */ +#define PCPP_HTTP_HOST_FIELD "Host" + /** Connection field */ +#define PCPP_HTTP_CONNECTION_FIELD "Connection" + /** User-Agent field */ +#define PCPP_HTTP_USER_AGENT_FIELD "User-Agent" + /** Referer field */ +#define PCPP_HTTP_REFERER_FIELD "Referer" + /** Accept field */ +#define PCPP_HTTP_ACCEPT_FIELD "Accept" + /** Accept-Encoding field */ +#define PCPP_HTTP_ACCEPT_ENCODING_FIELD "Accept-Encoding" + /** Accept-Language field */ +#define PCPP_HTTP_ACCEPT_LANGUAGE_FIELD "Accept-Language" + /** Cookie field */ +#define PCPP_HTTP_COOKIE_FIELD "Cookie" + /** Content-Length field */ +#define PCPP_HTTP_CONTENT_LENGTH_FIELD "Content-Length" + /** Content-Encoding field */ +#define PCPP_HTTP_CONTENT_ENCODING_FIELD "Content-Encoding" + /** Content-Type field */ +#define PCPP_HTTP_CONTENT_TYPE_FIELD "Content-Type" + /** Transfer-Encoding field */ +#define PCPP_HTTP_TRANSFER_ENCODING_FIELD "Transfer-Encoding" + /** Server field */ +#define PCPP_HTTP_SERVER_FIELD "Server" + + // -------- classes to be defined later ----------------- + + class HttpRequestFirstLine; + class HttpResponseFirstLine; + + // -------- Class HttpMessage ----------------- + + /** + * @class HttpMessage + * Represents a general HTTP message. It's an abstract class and cannot be instantiated. It's inherited by + * HttpRequestLayer and HttpResponseLayer + */ + class HttpMessage : public TextBasedProtocolMessage + { + public: + virtual ~HttpMessage() + {} + + /** + * A static method that checks whether the port is considered as HTTP + * @param[in] port The port number to be checked + * @return True if the port matches those associated with the HTTP protocol + */ + static bool isHttpPort(uint16_t port) + { + return port == 80 || port == 8080; + } + + // overridden methods + + virtual HeaderField* addField(const std::string& fieldName, const std::string& fieldValue); + virtual HeaderField* addField(const HeaderField& newField); + virtual HeaderField* insertField(HeaderField* prevField, const std::string& fieldName, + const std::string& fieldValue); + virtual HeaderField* insertField(HeaderField* prevField, const HeaderField& newField); + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelApplicationLayer; + } + + protected: + HttpMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, ProtocolType protocol) + : TextBasedProtocolMessage(data, dataLen, prevLayer, packet, protocol) + {} + HttpMessage() : TextBasedProtocolMessage() + {} + HttpMessage(const HttpMessage& other) : TextBasedProtocolMessage(other) + {} + HttpMessage& operator=(const HttpMessage& other) + { + TextBasedProtocolMessage::operator=(other); + return *this; + } + + // implementation of abstract methods + char getHeaderFieldNameValueSeparator() const + { + return ':'; + } + bool spacesAllowedBetweenHeaderFieldNameAndValue() const + { + return true; + } + }; + + // -------- Class HttpRequestLayer ----------------- + + /** + * @class HttpRequestLayer + * Represents an HTTP request header and inherits all basic functionality of HttpMessage and + * TextBasedProtocolMessage. The functionality that is added for this class is the HTTP first line concept. An HTTP + * request has the following first line: GET /bla/blabla.asp HTTP/1.1 Since it's not an "ordinary" HTTP + * field, it requires a special treatment and gets a class of it's own: HttpRequestFirstLine. Unlike most L2-4 + * protocols, an HTTP request header can spread over more than 1 packet. PcapPlusPlus currently doesn't support a + * header that is spread over more than 1 packet so in such cases: 1) only the first packet will be parsed as + * HttpRequestLayer (the other packets won't be recognized as HttpRequestLayer) and 2) the HTTP header for the first + * packet won't be complete (as it continues in the following packets), this why PcapPlusPlus can indicate that HTTP + * request header is complete or not(doesn't end with "\r\n\r\n" or "\n\n") using HttpMessage#isHeaderComplete() + */ + class HttpRequestLayer : public HttpMessage + { + friend class HttpRequestFirstLine; + + public: + /** + * HTTP request methods + */ + enum HttpMethod + { + /** GET */ + HttpGET, + /** HEAD */ + HttpHEAD, + /** POST */ + HttpPOST, + /** PUT */ + HttpPUT, + /** DELETE */ + HttpDELETE, + /** TRACE */ + HttpTRACE, + /** OPTIONS */ + HttpOPTIONS, + /** CONNECT */ + HttpCONNECT, + /** PATCH */ + HttpPATCH, + /** Unknown HTTP method */ + HttpMethodUnknown + }; + + /** A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + HttpRequestLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + /** + * A constructor that allocates a new HTTP request header with only the first line filled. Object will be + * created without further fields. The user can then add fields using addField() methods + * @param[in] method The HTTP method used in this HTTP request + * @param[in] uri The URI of the first line + * @param[in] version HTTP version to be used in this request + */ + HttpRequestLayer(HttpMethod method, const std::string& uri, HttpVersion version); + + virtual ~HttpRequestLayer(); + + /** + * A copy constructor for this layer. This copy constructor inherits base copy constructor + * HttpMessage#HttpMessage() and add the functionality of copying the first line as well + * @param[in] other The instance to copy from + */ + HttpRequestLayer(const HttpRequestLayer& other); + + /** + * An assignment operator overload for this layer. This method inherits base assignment operator + * HttpMessage#operator=() and add the functionality of copying the first line as well + * @param[in] other The instance to copy from + * @return A reference to the assignee + */ + HttpRequestLayer& operator=(const HttpRequestLayer& other); + + /** + * @return A pointer to the first line instance for this message + */ + HttpRequestFirstLine* getFirstLine() const + { + return m_FirstLine; + } + + /** + * The URL is hostname+uri. So given the following URL, for example: "www.cnn.com/main.html", the hostname is + * "www.cnn.com" and the URI is "/.main.html". URI and hostname are split to 2 different places inside the HTTP + * request packet: URI is in the first line and hostname is in "HOST" field. This methods concatenates the + * hostname and URI to the full URL + * @return The URL of the HTTP request message + */ + std::string getUrl() const; + + // implement Layer's abstract methods + std::string toString() const; + + private: + HttpRequestFirstLine* m_FirstLine; + }; + + // -------- Class HttpResponseStatusCode ----------------- + + /** + * @struct HttpResponseStatusCode + * @brief The enum wrapper class of HTTP response status codes + */ + class HttpResponseStatusCode + { + public: + /** + * @brief Define enum types and the corresponding int values + */ + enum Value : int + { + /** 100 Continue*/ + Http100Continue = 100, + /** 101 Switching Protocols*/ + Http101SwitchingProtocols = 101, + /** 102 Processing */ + Http102Processing = 102, + /** 103 Early Hints */ + Http103EarlyHints = 103, + /** 104-199 Unassigned */ + + /** 200 OK */ + Http200OK = 200, + /** 201 Created */ + Http201Created = 201, + /** 202 Accepted */ + Http202Accepted = 202, + /** 203 Non-Authoritative Information */ + Http203NonAuthoritativeInformation = 203, + /** 204 No Content*/ + Http204NoContent = 204, + /** 205 Reset Content*/ + Http205ResetContent = 205, + /** 206 Partial Content */ + Http206PartialContent = 206, + /** 207 Multi-Status */ + Http207MultiStatus = 207, + /** 208 Already Reported */ + Http208AlreadyReported = 208, + /** 209-225 Unassigned */ + /** 226 IM Used */ + Http226IMUsed = 226, + /** 227-299 Unassigned */ + + /** 300 Multiple Choices */ + Http300MultipleChoices = 300, + /** 301 Moved Permanently */ + Http301MovedPermanently = 301, + /** 302 (various messages) */ + Http302 = 302, + /** 303 See Other */ + Http303SeeOther = 303, + /** 304 Not Modified */ + Http304NotModified = 304, + /** 305 Use Proxy */ + Http305UseProxy = 305, + /** 306 Switch Proxy */ + Http306SwitchProxy = 306, + /** 307 Temporary Redirect */ + Http307TemporaryRedirect = 307, + /** 308 Permanent Redirect, */ + Http308PermanentRedirect = 308, + /** 309-399 Unassigned */ + + /** 400 Bad Request */ + Http400BadRequest = 400, + /** 401 Unauthorized */ + Http401Unauthorized = 401, + /** 402 Payment Required */ + Http402PaymentRequired = 402, + /** 403 Forbidden */ + Http403Forbidden = 403, + /** 404 Not Found */ + Http404NotFound = 404, + /** 405 Method Not Allowed */ + Http405MethodNotAllowed = 405, + /** 406 Not Acceptable */ + Http406NotAcceptable = 406, + /** 407 Proxy Authentication Required */ + Http407ProxyAuthenticationRequired = 407, + /** 408 Request Timeout */ + Http408RequestTimeout = 408, + /** 409 Conflict */ + Http409Conflict = 409, + /** 410 Gone */ + Http410Gone = 410, + /** 411 Length Required */ + Http411LengthRequired = 411, + /** 412 Precondition Failed */ + Http412PreconditionFailed = 412, + /** 413 RequestEntity Too Large */ + Http413RequestEntityTooLarge = 413, + /** 414 Request-URI Too Long */ + Http414RequestURITooLong = 414, + /** 415 Unsupported Media Type */ + Http415UnsupportedMediaType = 415, + /** 416 Requested Range Not Satisfiable */ + Http416RequestedRangeNotSatisfiable = 416, + /** 417 Expectation Failed */ + Http417ExpectationFailed = 417, + /** 418 I'm a teapot */ + Http418ImATeapot = 418, + /** 419 Authentication Timeout */ + Http419AuthenticationTimeout = 419, + /** 420 (various messages) */ + Http420 = 420, + /** 421 Misdirected Request */ + Http421MisdirectedRequest = 421, + /** 422 Unprocessable Entity */ + Http422UnprocessableEntity = 422, + /** 423 Locked */ + Http423Locked = 423, + /** 424 Failed Dependency */ + Http424FailedDependency = 424, + /** 425 Too Early */ + Http425TooEarly = 425, + /** 426 Upgrade Required */ + Http426UpgradeRequired = 426, + /** 427 Unassigned */ + /** 428 Precondition Required */ + Http428PreconditionRequired = 428, + /** 429 Too Many Requests */ + Http429TooManyRequests = 429, + /** 430 Unassigned */ + /** 431 Request Header Fields Too Large */ + Http431RequestHeaderFieldsTooLarge = 431, + /** 432-439 unassigned */ + /** 440 Login Timeout */ + Http440LoginTimeout = 440, + /** 441-443 unassigned */ + /** 444 No Response */ + Http444NoResponse = 444, + /** 445-448 unassigned */ + /** 449 Retry With */ + Http449RetryWith = 449, + /** 450 Blocked by Windows Parental Controls */ + Http450BlockedByWindowsParentalControls = 450, + /** 451 (various messages) */ + Http451 = 451, + /** 452-493 unassigned */ + /** 494 Request Header Too Large */ + Http494RequestHeaderTooLarge = 494, + /** 495 Cert Error */ + Http495CertError = 495, + /** 496 No Cert */ + Http496NoCert = 496, + /** 497 HTTP to HTTPS */ + Http497HTTPtoHTTPS = 497, + /** 498 Token expired/invalid */ + Http498TokenExpiredInvalid = 498, + /** 499 (various messages) */ + Http499 = 499, + + /** 500 Internal Server Error */ + Http500InternalServerError = 500, + /** 501 Not Implemented */ + Http501NotImplemented = 501, + /** 502 Bad Gateway */ + Http502BadGateway = 502, + /** 503 Service Unavailable */ + Http503ServiceUnavailable = 503, + /** 504 Gateway Timeout */ + Http504GatewayTimeout = 504, + /** 505 HTTP Version Not Supported */ + Http505HTTPVersionNotSupported = 505, + /** 506 Variant Also Negotiates */ + Http506VariantAlsoNegotiates = 506, + /** 507 Insufficient Storage */ + Http507InsufficientStorage = 507, + /** 508 Loop Detected */ + Http508LoopDetected = 508, + /** 509 Bandwidth Limit Exceeded */ + Http509BandwidthLimitExceeded = 509, + /** 510 Not Extended */ + Http510NotExtended = 510, + /** 511 Network Authentication Required */ + Http511NetworkAuthenticationRequired = 511, + /** 512-519 unassigned */ + /** 520 Origin Error */ + Http520OriginError = 520, + /** 521 Web server is down */ + Http521WebServerIsDown = 521, + /** 522 Connection timed out */ + Http522ConnectionTimedOut = 522, + /** 523 Proxy Declined Request */ + Http523ProxyDeclinedRequest = 523, + /** 524 A timeout occurred */ + Http524aTimeoutOccurred = 524, + /** 525-597 unassigned */ + /** 598 Network read timeout error */ + Http598NetworkReadTimeoutError = 598, + /** 599 Network connect timeout error */ + Http599NetworkConnectTimeoutError = 599, + + // clang-format off + /** Unknown status code */ + HttpStatus1xxCodeUnknown = 900001, // 1xx: Informational - Request received, continuing process + HttpStatus2xxCodeUnknown = 900002, // 2xx: Success - The action was successfully received, understood, and accepted + HttpStatus3xxCodeUnknown = 900003, // 3xx: Redirection - Further action must be taken in order to complete the request + HttpStatus4xxCodeUnknown = 900004, // 4xx: Client Error - The request contains bad syntax or cannot be fulfilled + HttpStatus5xxCodeUnknown = 900005, // 5xx: Server Error - The server failed to fulfill an apparently valid request + HttpStatusCodeUnknown = 999999, // other arbitrary number + // clang-format on + }; + + HttpResponseStatusCode() = default; + + // cppcheck-suppress noExplicitConstructor + /** + * @brief Construct HttpResponseStatusCode from Value enum + * @param[in] statusCode the status code enum + */ + HttpResponseStatusCode(Value statusCode) : m_Value(statusCode) + {} + + /** + * @brief Construct HttpResponseStatusCode from the code number and the customized message + * @param[in] statusCodeNumber the status code in number, e.g. 200, 404 + * @param[in] statusMessage the status message, optional, leave empty to use a default message + */ + explicit HttpResponseStatusCode(const int& statusCodeNumber, const std::string& statusMessage = ""); + + /** + * @brief Construct HttpResponseStatusCode from Value enum and the customized message + * @param[in] statusCode the status code enum + * @param[in] statusMessage the customized status message, optional + */ + explicit HttpResponseStatusCode(const Value& statusCode, const std::string& statusMessage); + + // Allow switch and comparisons. + operator Value() const + { + return m_Value; + } + // Prevent usage: if(httpResponseStatusCode) + explicit operator bool() const = delete; + + /** + * @brief get status code number as string + */ + std::string toString() const + { + return std::to_string(m_Value); + } + + /** + * @brief get status code number as int + */ + int toInt() const + { + return static_cast(m_Value); + } + + /** + * @brief get status code message, e.g. "OK", "Not Found" + */ + std::string getMessage() const; + /** + * @return If this HttpResponseStatusCode a valid code + * @note Any unknown or error code has an extreme large enum value + */ + bool isUnsupportedCode() const + { + return m_Value > 599; + } + + private: + Value m_Value = HttpStatusCodeUnknown; + std::string m_CustomizedMessage; + }; + + // -------- Class HttpResponseLayer ----------------- + + /** + * @class HttpResponseLayer + * Represents an HTTP response header and inherits all basic functionality of HttpMessage and + * TextBasedProtocolMessage. The functionality that is added for this class is the HTTP first line concept. An HTTP + * response has the following first line: 200 OK HTTP/1.1 Since it's not an "ordinary" HTTP field, it + * requires a special treatment and gets a class of it's own: HttpResponseFirstLine. Unlike most L2-4 protocols, an + * HTTP response header can spread over more than 1 packet. PcapPlusPlus currently doesn't support a header that is + * spread over more than 1 packet so in such cases: 1) only the first packet will be parsed as HttpResponseLayer + * (the other packets won't be recognized as HttpResponseLayer) and 2) the HTTP header for the first packet won't be + * complete (as it continues in the following packets), this why PcapPlusPlus can indicate that HTTP response header + * is complete or not (doesn't end with "\r\n\r\n" or "\n\n") using HttpMessage#isHeaderComplete() + */ + class HttpResponseLayer : public HttpMessage + { + friend class HttpResponseFirstLine; + + public: + // backward compatibility + using HttpResponseStatusCode = pcpp::HttpResponseStatusCode; + + /** A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + HttpResponseLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + /** + * A constructor that allocates a new HTTP response header with only the first line filled. Object will be + * created without further fields. The user can then add fields using addField() methods + * @param[in] version HTTP version to be used + * @param[in] statusCode Status code to be used + * @param[in] statusCodeString Most status codes have their default string, e.g 200 is usually "OK", 404 is + * usually "Not Found", etc. But the user can set a non-default status code string and it will be written in the + * header first line. Empty string ("") means using the default status code string + * @deprecated Use other constructors instead. + */ + PCPP_DEPRECATED("Use other constructors instead") + explicit HttpResponseLayer(HttpVersion version, const HttpResponseStatusCode& statusCode, + const std::string& statusCodeString); + + /** + * A constructor that allocates a new HTTP response header with only the first line filled. Object will be + * created without further fields. The user can then add fields using addField() methods + * @param[in] version HTTP version to be used + * @param[in] statusCode Status code to be used + */ + explicit HttpResponseLayer(HttpVersion version, const HttpResponseStatusCode& statusCode); + + virtual ~HttpResponseLayer(); + + /** + * A copy constructor for this layer. This copy constructor inherits base copy constructor + * HttpMessage#HttpMessage() and adds the functionality of copying the first line as well + * @param[in] other The instance to copy from + */ + HttpResponseLayer(const HttpResponseLayer& other); + + /** + * An assignment operator overload for this layer. This method inherits base assignment operator + * HttpMessage#operator=() and adds the functionality of copying the first line as well + * @param[in] other The instance to copy from + * @return A reference to the assignee + */ + HttpResponseLayer& operator=(const HttpResponseLayer& other); + + /** + * @return A pointer to the first line instance for this message + */ + HttpResponseFirstLine* getFirstLine() const + { + return m_FirstLine; + } + + /** + * The length of the body of many HTTP response messages is determined by a HTTP header field called + * "Content-Length". This method sets The content-length field value. The method supports several cases: + * - If the "Content-Length" field exists - the method will only replace the existing value with the new value + * - If the "Content-Length" field doesn't exist - the method will create this field and put the value in it. + * Here are also 2 cases: + * - If prevFieldName is specified - the new "Content-Length" field will be created after it + * - If prevFieldName isn't specified or doesn't exist - the new "Content-Length" field will be created as the + * last field before end-of-header field + * + * @param[in] contentLength The content length value to set + * @param[in] prevFieldName Optional field, if specified and "Content-Length" field doesn't exist, it will be + * created after it + * @return A pointer to the "Content-Length" field, or nullptr if creation failed for some reason + */ + HeaderField* setContentLength(int contentLength, const std::string& prevFieldName = ""); + + /** + * The length of the body of many HTTP response messages is determined by a HTTP header field called + * "Content-Length". This method parses this field, extracts its value and return it. If this field doesn't + * exist the method will return 0 + * @return HTTP response body length determined by "Content-Length" field + */ + int getContentLength() const; + + // implement Layer's abstract methods + + std::string toString() const; + + private: + HttpResponseFirstLine* m_FirstLine; + }; + + // -------- Class HttpRequestFirstLine ----------------- + + /** + * @class HttpRequestFirstLine + * Represents an HTTP request header first line. The first line includes 3 parameters: HTTP method (e.g GET, POST, + * etc.), URI (e.g /main/index.html) and HTTP version (e.g HTTP/1.1). All these parameters are included in this + * class, and the user can retrieve or set them. This class cannot be instantiated by users, it's created inside + * HttpRequestLayer and user can get a pointer to an instance of it. All "get" methods of this class will retrieve + * the actual data of the HTTP request and the "set" methods will change the packet data. Since HTTP is a textual + * protocol, most fields aren't of fixed size and this also applies to the first line parameters. So most "set" + * methods of this class need in most cases to shorten or extend the data in HttpRequestLayer. These methods will + * return a false value if this action failed + */ + class HttpRequestFirstLine + { + friend class HttpRequestLayer; + + public: + /** + * @return The HTTP method + */ + HttpRequestLayer::HttpMethod getMethod() const + { + return m_Method; + } + + /** + * Set the HTTP method + * @param[in] newMethod The method to set + * @return False if newMethod is HttpRequestLayer#HttpMethodUnknown or if shortening/extending the + * HttpRequestLayer data failed. True otherwise + */ + bool setMethod(HttpRequestLayer::HttpMethod newMethod); + + /** + * @return A copied version of the URI (notice changing the return value won't change the actual data of the + * packet) + */ + std::string getUri() const; + + /** + * Set the URI + * @param[in] newUri The URI to set + * @return False if shortening/extending the HttpRequestLayer data failed. True otherwise + */ + bool setUri(std::string newUri); + + /** + * @return The HTTP version + */ + HttpVersion getVersion() const + { + return m_Version; + } + + /** + * Set the HTTP version. This method doesn't return a value since all supported HTTP versions are of the same + * size (HTTP/0.9, HTTP/1.0, HTTP/1.1) + * @param[in] newVersion The HTTP version to set + */ + void setVersion(HttpVersion newVersion); + + /** + * A static method for parsing the HTTP method out of raw data + * @param[in] data The raw data + * @param[in] dataLen The raw data length + * @return The parsed HTTP method + */ + static HttpRequestLayer::HttpMethod parseMethod(const char* data, size_t dataLen); + + /** + * @return The size in bytes of the HTTP first line + */ + int getSize() const + { + return m_FirstLineEndOffset; + } + + /** + * As explained in HttpRequestLayer, an HTTP header can spread over more than 1 packet, so when looking at a + * single packet the header can be partial. Same goes for the first line - it can spread over more than 1 + * packet. This method returns an indication whether the first line is partial + * @return False if the first line is partial, true if it's complete + */ + bool isComplete() const + { + return m_IsComplete; + } + + /** + * @class HttpRequestFirstLineException + * This exception can be thrown while constructing HttpRequestFirstLine (the constructor is private, so the + * construction happens only in HttpRequestLayer). This kind of exception will be thrown if trying to construct + * with HTTP method of HttpRequestLayer#HttpMethodUnknown or with undefined HTTP version ::HttpVersionUnknown + */ + class HttpRequestFirstLineException : public std::exception + { + public: + ~HttpRequestFirstLineException() noexcept + {} + void setMessage(const std::string& message) + { + m_Message = message; + } + virtual const char* what() const noexcept + { + return m_Message.c_str(); + } + + private: + std::string m_Message; + }; + + private: + HttpRequestFirstLine(HttpRequestLayer* httpRequest); + HttpRequestFirstLine(HttpRequestLayer* httpRequest, HttpRequestLayer::HttpMethod method, HttpVersion version, + const std::string& uri = "/"); + + void parseVersion(); + + HttpRequestLayer* m_HttpRequest; + HttpRequestLayer::HttpMethod m_Method; + HttpVersion m_Version; + int m_VersionOffset; + int m_UriOffset; + int m_FirstLineEndOffset; + bool m_IsComplete; + HttpRequestFirstLineException m_Exception; + }; + + // -------- Class HttpResponseFirstLine ----------------- + + /** + * @class HttpResponseFirstLine + * Represents an HTTP response header first line. The first line includes 2 parameters: status code (e.g 200 OK, 404 + * Not Found, etc.), and HTTP version (e.g HTTP/1.1). These 2 parameters are included in this class, and the user + * can retrieve or set them. This class cannot be instantiated by users, it's created inside HttpResponseLayer and + * user can get a pointer to an instance of it. The "get" methods of this class will retrieve the actual data of the + * HTTP response and the "set" methods will change the packet data. Since HTTP is a textual protocol, most fields + * aren't of fixed size and this also applies to the first line parameters. So most "set" methods of this class need + * in most cases to shorten or extend the data in HttpResponseLayer. These methods will return a false value if this + * action failed + */ + class HttpResponseFirstLine + { + friend class HttpResponseLayer; + + public: + /** + * @return The status code as HttpResponseStatusCode enum + */ + HttpResponseStatusCode getStatusCode() const + { + return m_StatusCode; + } + + /** + * @return The status code number as integer (e.g 200, 404, etc.) + */ + int getStatusCodeAsInt() const; + + /** + * @return The status code message (e.g "OK", "Not Found", etc.) + */ + std::string getStatusCodeString() const; + + /** + * Set the status code + * @param[in] newStatusCode The new status code to set + * @param[in] statusCodeString An optional parameter: set a non-default status code message (e.g "Bla Bla" + * instead of "Not Found"). If this parameter isn't supplied or supplied as empty string (""), the default + * message for the status code will be set + * @return True if setting the status code was completed successfully, false otherwise + * @deprecated Use the other overload instead. + */ + PCPP_DEPRECATED("Use the other overload instead") + bool setStatusCode(const HttpResponseStatusCode& newStatusCode, const std::string& statusCodeString); + + /** + * Set the status code + * @param[in] newStatusCode The new status code to set + * @return True if setting the status code was completed successfully, false otherwise + */ + bool setStatusCode(const HttpResponseStatusCode& newStatusCode); + + /** + * @return The HTTP version + */ + HttpVersion getVersion() const + { + return m_Version; + } + + /** + * Set the HTTP version. This method doesn't return a value since all supported HTTP versions are of the same + * size (HTTP/0.9, HTTP/1.0, HTTP/1.1) + * @param[in] newVersion The HTTP version to set + */ + void setVersion(HttpVersion newVersion); + + /** + * A static method for parsing the HTTP status code out of raw data + * @param[in] data The raw data + * @param[in] dataLen The raw data length + * @return The parsed HTTP status code as enum + */ + static HttpResponseStatusCode parseStatusCode(const char* data, size_t dataLen); + + /** + * A static method for parsing the HTTP version out of raw first line data (e.g "HTTP/x.y") + * @param[in] data The raw data + * @param[in] dataLen The raw data length + * @return The parsed HTTP status code as enum + */ + static HttpVersion parseVersion(const char* data, size_t dataLen); + + /** + * @return The size in bytes of the HTTP first line + */ + int getSize() const + { + return m_FirstLineEndOffset; + } + + /** + * As explained in HttpResponseLayer, an HTTP header can spread over more than 1 packet, so when looking at a + * single packet the header can be partial. Same goes for the first line - it can spread over more than 1 + * packet. This method returns an indication whether the first line is partial + * @return False if the first line is partial, true if it's complete + */ + bool isComplete() const + { + return m_IsComplete; + } + + /** + * @class HttpResponseFirstLineException + * This exception can be thrown while constructing HttpResponseFirstLine (the constructor is private, so the + * construction happens only in HttpResponseLayer). This kind of exception will be thrown if trying to construct + * with a HTTP status code that is not in HttpResponseStatusCode or with undefined HTTP version + * ::HttpVersionUnknown + */ + class HttpResponseFirstLineException : public std::exception + { + public: + ~HttpResponseFirstLineException() noexcept + {} + void setMessage(const std::string& message) + { + m_Message = message; + } + virtual const char* what() const noexcept + { + return m_Message.c_str(); + } + + private: + std::string m_Message; + }; + + private: + HttpResponseFirstLine(HttpResponseLayer* httpResponse); + HttpResponseFirstLine(HttpResponseLayer* httpResponse, HttpVersion version, + const HttpResponseStatusCode& statusCode); + + HttpResponseLayer* m_HttpResponse; + HttpVersion m_Version; + HttpResponseStatusCode m_StatusCode; + int m_FirstLineEndOffset; + bool m_IsComplete; + HttpResponseFirstLineException m_Exception; + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/IPLayer.h b/Packet++/header/pcapplusplus/IPLayer.h new file mode 100644 index 0000000000..67f18b84b6 --- /dev/null +++ b/Packet++/header/pcapplusplus/IPLayer.h @@ -0,0 +1,46 @@ +#pragma once + +#include "pcapplusplus/IpAddress.h" +#include "pcapplusplus/Layer.h" + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + /** + * @class IPLayer + * This is an interface (abstract class) implemented in the IP layers (IPv4Layer and IPv6Layer). + * It provides methods to fetch the source and destination IP addresses in an abdtract way + * that hides the IP type (IPv4 or IPv6). This is useful for use-cases in which the IP type doesn't matter. + * For example: if you're only interested in printing the IP address the IP type shouldn't matter. + */ + class IPLayer + { + protected: + IPLayer() + {} + + public: + /** + * An abstract method to get the source IP address + * @return An IPAddress object containing the source address + */ + virtual IPAddress getSrcIPAddress() const = 0; + + /** + * An abstract method to get the destination IP address + * @return An IPAddress object containing the destination address + */ + virtual IPAddress getDstIPAddress() const = 0; + + /** + * An empty destructor + */ + virtual ~IPLayer() + {} + }; +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/IPReassembly.h b/Packet++/header/pcapplusplus/IPReassembly.h new file mode 100644 index 0000000000..8e031cd2a7 --- /dev/null +++ b/Packet++/header/pcapplusplus/IPReassembly.h @@ -0,0 +1,569 @@ +#pragma once + +#include "pcapplusplus/Packet.h" +#include "pcapplusplus/LRUList.h" +#include "pcapplusplus/IpAddress.h" +#include "pcapplusplus/PointerVector.h" +#include + +/** + * @file + * This file includes an implementation of IP reassembly mechanism (a.k.a IP de-fragmentation), which is the mechanism + * of assembling IPv4 or IPv6 fragments back into one whole packet. As the previous sentence imply, this module supports + * both IPv4 and IPv6 reassembly which means the same pcpp#IPReassembly instance can reassemble both IPv4 and IPv6 + * fragments. You can read more about IP fragmentation here: https://en.wikipedia.org/wiki/IP_fragmentation.
The API + * is rather simple and contains one main method: pcpp#IPReassembly#processPacket() which gets a fragment packet as a + * parameter, does the reassembly and returns a fully reassembled packet when done.
+ * + * The logic works as follows: + * - There is an internal map that stores the reassembly data for each packet. The key to this map, meaning the way to + * uniquely associate a fragment to a (reassembled) packet is the triplet of source IP, destination IP and IP ID (for + * IPv4) or Fragment ID (for IPv6) + * - When the first fragment arrives a new record is created in the map and the fragment data is copied + * - With each fragment arriving the fragment data is copied right after the previous fragment and the reassembled + * packet is gradually being built + * - When the last fragment arrives the packet is fully reassembled and returned to the user. Since all fragment data is + * copied, the packet pointer returned to the user has to be freed by the user when done using it + * - The logic supports out-of-order fragments, meaning that a fragment which arrives out-of-order, its data will be + * copied to a list of out-of-order fragments where it waits for its turn. This list is observed each time a new + * fragment arrives to see if the next fragment(s) wait(s) in this list + * - If a non-IP packet arrives it's returned as is to the user + * - If a non-fragment packet arrives it's returned as is to the user + * + * In order to limit the amount of memory used by this mechanism there is a limit to the number of concurrent packets + * being reassembled. The default limit is #PCPP_IP_REASSEMBLY_DEFAULT_MAX_PACKETS_TO_STORE but the user can set any + * value (determined in pcpp#IPReassembly c'tor). Once capacity (the number of concurrent reassembled packets) exceeds + * this number, the packet that was least recently used will be dropped from the map along with all the data that was + * reassembled so far. This means that if the next fragment from this packet suddenly appears it will be treated as a + * new reassembled packet (which will create another record in the map). The user can be notified when reassembled + * packets are removed from the map by registering to the pcpp#IPReassembly#OnFragmentsClean callback in + * pcpp#IPReassembly c'tor + */ + +/** + * @namespace pcpp + * @brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + +/** IP reassembly mechanism default capacity. If concurrent packet volume exceeds this numbers, packets will start to be + * dropped in a LRU manner + */ +#define PCPP_IP_REASSEMBLY_DEFAULT_MAX_PACKETS_TO_STORE 500000 + + /** + * @class IPReassembly + * Contains the IP reassembly (a.k.a IP de-fragmentation) mechanism. Encapsulates both IPv4 and IPv6 reassembly. + * Please refer to the documentation at the top of IPReassembly.h + * to understand how this mechanism works. The main APIs are: + * - IPReassembly#processPacket() - process a fragment. This is the main method which should be called whenever a + * new fragment arrives. This method processes the fragment, runs the reassembly logic and returns the result + * packet when it's fully reassembled + * - IPReassembly#getCurrentPacket() - get the reassembled data that is currently available, even if reassembly + * process is not yet completed + * - IPReassembly#removePacket() - remove all data that is currently stored for a packet, including the reassembled + * data that was gathered so far + */ + class IPReassembly + { + public: + /** + * @class PacketKey + * An abstract class that represents a key that can uniquely identify an IP packet. This class cannot be + * instantiated or copied, only its derived classes can + */ + class PacketKey + { + public: + /** + * A default virtual d'tor + */ + virtual ~PacketKey() = default; + + /** + * @return A 4-byte hash value of the packet key + */ + virtual uint32_t getHashValue() const = 0; + + /** + * @return The IP protocol this key represents (pcpp#IPv4 or pcpp#IPv6) + */ + virtual ProtocolType getProtocolType() const = 0; + + /** + * @return A pointer to a new instance which is a clone of the current instance + */ + virtual PacketKey* clone() const = 0; + + protected: + // private c'tor + PacketKey() = default; + + // private copy c'tor + PacketKey(const PacketKey& other) = default; + }; + + /** + * @class IPv4PacketKey + * Represents a key that can uniquely identify IPv4 packets. The key comprises of source IPv4 address, dest IPv4 + * address and IP ID + */ + class IPv4PacketKey : public PacketKey + { + public: + /** + * A default c'tor which zeros all members + */ + IPv4PacketKey() : m_IpID(0), m_SrcIP(IPv4Address::Zero), m_DstIP(IPv4Address::Zero) + {} + + /** + * A c'tor that sets values in each one of the members + * @param[in] ipid IP ID value + * @param[in] srcip Source IPv4 address + * @param[in] dstip Dest IPv4 address + */ + IPv4PacketKey(uint16_t ipid, IPv4Address srcip, IPv4Address dstip) + : m_IpID(ipid), m_SrcIP(srcip), m_DstIP(dstip) + {} + + /** + * A copy c'tor for this class + * @param[in] other The instance to copy from + */ + IPv4PacketKey(const IPv4PacketKey& other) + : PacketKey(other), m_IpID(other.m_IpID), m_SrcIP(other.m_SrcIP), m_DstIP(other.m_DstIP) + {} + + /** + * Assignment operator for this class + * @param[in] other The instance to assign from + */ + IPv4PacketKey& operator=(const IPv4PacketKey& other) + { + m_IpID = other.m_IpID; + m_SrcIP = other.m_SrcIP; + m_DstIP = other.m_DstIP; + return *this; + } + + /** + * @return IP ID value + */ + uint16_t getIpID() const + { + return m_IpID; + } + + /** + * @return Source IP address + */ + IPv4Address getSrcIP() const + { + return m_SrcIP; + } + + /** + * @return Dest IP address + */ + IPv4Address getDstIP() const + { + return m_DstIP; + } + + /** + * Set IP ID + * @param[in] ipID IP ID value to set + */ + void setIpID(uint16_t ipID) + { + m_IpID = ipID; + } + + /** + * Set source IPv4 address + * @param[in] srcIP Source IP to set + */ + void setSrcIP(const IPv4Address& srcIP) + { + m_SrcIP = srcIP; + } + + /** + * Set dest IPv4 address + * @param[in] dstIP Dest IP to set + */ + void setDstIP(const IPv4Address& dstIP) + { + m_DstIP = dstIP; + } + + // implement abstract methods + + uint32_t getHashValue() const; + + /** + * @return pcpp#IPv4 protocol + */ + ProtocolType getProtocolType() const + { + return IPv4; + } + + PacketKey* clone() const + { + return new IPv4PacketKey(*this); + } + + private: + uint16_t m_IpID; + IPv4Address m_SrcIP; + IPv4Address m_DstIP; + }; + + /** + * @class IPv6PacketKey + * Represents a key that can uniquely identify IPv6 fragment packets. The key comprises of source IPv6 address, + * dest IPv6 address and fragment ID (which resides in the IPv6 fragmentation extension) + */ + class IPv6PacketKey : public PacketKey + { + public: + /** + * A default c'tor which zeros all members + */ + IPv6PacketKey() : m_FragmentID(0), m_SrcIP(IPv6Address::Zero), m_DstIP(IPv6Address::Zero) + {} + + /** + * A c'tor that sets values in each one of the members + * @param[in] fragmentID Fragment ID value + * @param[in] srcip Source IPv6 address + * @param[in] dstip Dest IPv6 address + */ + IPv6PacketKey(uint32_t fragmentID, IPv6Address srcip, IPv6Address dstip) + : m_FragmentID(fragmentID), m_SrcIP(srcip), m_DstIP(dstip) + {} + + /** + * A copy c'tor for this class + * @param[in] other The instance to copy from + */ + IPv6PacketKey(const IPv6PacketKey& other) + : PacketKey(other), m_FragmentID(other.m_FragmentID), m_SrcIP(other.m_SrcIP), m_DstIP(other.m_DstIP) + {} + + /** + * Assignment operator for this class + * @param[in] other The instance to assign from + */ + IPv6PacketKey& operator=(const IPv6PacketKey& other) + { + m_FragmentID = other.m_FragmentID; + m_SrcIP = other.m_SrcIP; + m_DstIP = other.m_DstIP; + return *this; + } + + /** + * @return Fragment ID value + */ + uint32_t getFragmentID() const + { + return m_FragmentID; + } + + /** + * @return Source IP address + */ + IPv6Address getSrcIP() const + { + return m_SrcIP; + } + + /** + * @return Dest IP address + */ + IPv6Address getDstIP() const + { + return m_DstIP; + } + + /** + * Set fragment ID + * @param[in] fragID Fragment ID value to set + */ + void setFragmentID(uint32_t fragID) + { + m_FragmentID = fragID; + } + + /** + * Set source IPv6 address + * @param[in] srcIP Source IP to set + */ + void setSrcIP(const IPv6Address& srcIP) + { + m_SrcIP = srcIP; + } + + /** + * Set dest IPv6 address + * @param[in] dstIP Dest IP to set + */ + void setDstIP(const IPv6Address& dstIP) + { + m_DstIP = dstIP; + } + + // implement abstract methods + + uint32_t getHashValue() const; + + /** + * @return pcpp#IPv6 protocol + */ + ProtocolType getProtocolType() const + { + return IPv6; + } + + PacketKey* clone() const + { + return new IPv6PacketKey(*this); + } + + private: + uint32_t m_FragmentID; + IPv6Address m_SrcIP; + IPv6Address m_DstIP; + }; + + /** + * @typedef OnFragmentsClean + * The IP reassembly mechanism has a certain capacity of concurrent packets it can handle. This capacity is + * determined in its c'tor (default value is #PCPP_IP_REASSEMBLY_DEFAULT_MAX_PACKETS_TO_STORE). When traffic + * volume exceeds this capacity the mechanism starts dropping packets in a LRU manner (least recently used are + * dropped first). Whenever a packet is dropped this callback is fired + * @param[in] key A pointer to the identifier of the packet that is being dropped + * @param[in] userCookie A pointer to the cookie provided by the user in IPReassemby c'tor (or nullptr if no + * cookie provided) + */ + typedef void (*OnFragmentsClean)(const PacketKey* key, void* userCookie); + + /** + * An enum representing the status returned from processing a fragment + */ + enum ReassemblyStatus + { + /** The processed packet isn't of type IPv4 or IPv6 */ + NON_IP_PACKET = 0x00, + /** The processed packet isn't a fragment */ + NON_FRAGMENT = 0x01, + /** The processed fragment is the first fragment */ + FIRST_FRAGMENT = 0x02, + /** The processed fragment is a fragment (but not the first one) */ + FRAGMENT = 0x04, + /** The processed fragment is not the fragment that was expected at this time */ + OUT_OF_ORDER_FRAGMENT = 0x08, + /** The processed fragment is malformed, meaning a fragment which has offset of zero but isn't the first + * fragment */ + MALFORMED_FRAGMENT = 0x10, + /** Packet is now fully reassembled */ + REASSEMBLED = 0x20 + }; + + /** + * A c'tor for this class. + * @param[in] onFragmentsCleanCallback The callback to be called when packets are dropped due to capacity limit. + * Please read more about capacity limit in IPReassembly.h file description. This parameter is optional, default + * value is nullptr (no callback) + * @param[in] callbackUserCookie A pointer to an object provided by the user. This pointer will be returned when + * invoking the onFragmentsCleanCallback. This parameter is optional, default cookie is nullptr + * @param[in] maxPacketsToStore Set the capacity limit of the IP reassembly mechanism. Default capacity is + * #PCPP_IP_REASSEMBLY_DEFAULT_MAX_PACKETS_TO_STORE + */ + explicit IPReassembly(OnFragmentsClean onFragmentsCleanCallback = nullptr, void* callbackUserCookie = nullptr, + size_t maxPacketsToStore = PCPP_IP_REASSEMBLY_DEFAULT_MAX_PACKETS_TO_STORE) + : m_PacketLRU(maxPacketsToStore), m_OnFragmentsCleanCallback(onFragmentsCleanCallback), + m_CallbackUserCookie(callbackUserCookie) + {} + + /** + * A d'tor for this class + */ + ~IPReassembly(); + + /** + * The main API that drives IPReassembly. This method should be called whenever a fragment arrives. This method + * finds the relevant packet this fragment belongs to and runs the IP reassembly logic that is described in + * IPReassembly.h. + * @param[in] fragment The fragment to process (IPv4 or IPv6). Please notice that the reassembly logic doesn't + * change or manipulate this object in any way. All of its data is copied to internal structures and manipulated + * there + * @param[out] status An indication of the packet reassembly status following the processing of this fragment. + * Possible values are: + * - The input fragment is not a IPv4 or IPv6 packet + * - The input fragment is not a IPv4 or IPv6 fragment packet + * - The input fragment is the first fragment of the packet + * - The input fragment is not the first or last fragment + * - The input fragment came out-of-order, meaning that wasn't the fragment that was currently expected (it's + * data is copied to the out-of-order fragment list) + * - The input fragment is malformed and will be ignored + * - The input fragment is the last one and the packet is now fully reassembled. In this case the return value + * will contain a pointer to the reassembled packet + * @param[in] parseUntil Optional parameter. Parse the reassembled packet until you reach a certain protocol + * (inclusive). Can be useful for cases when you need to parse only up to a certain layer and want to avoid the + * performance impact and memory consumption of parsing the whole packet. Note that setting this to a protocol + * which doesn't include the IP-Layer will result in IPReassembly not finding the IP-Layer and thus failing to + * work properly. Default value is ::UnknownProtocol which means don't take this parameter into account + * @param[in] parseUntilLayer Optional parameter. Parse the reassembled packet until you reach a certain layer + * in the OSI model (inclusive). Can be useful for cases when you need to parse only up to a certain OSI layer + * (for example transport layer) and want to avoid the performance impact and memory consumption of parsing the + * whole packet. Note that setting this value to OsiModelPhysicalLayer will result in IPReassembly not finding + * the IP-layer and thus failing to work properly. Default value is ::OsiModelLayerUnknown which means don't + * take this parameter into account + * @return + * - If the input fragment isn't an IPv4/IPv6 packet or if it isn't an IPv4/IPv6 fragment, the return value is a + * pointer to the input fragment + * - If the input fragment is the last one and the reassembled packet is ready - a pointer to the reassembled + * packet is returned. Notice it's the user's responsibility to free this pointer when done using it + * - If the reassembled packet isn't ready then nullptr is returned + */ + Packet* processPacket(Packet* fragment, ReassemblyStatus& status, ProtocolType parseUntil = UnknownProtocol, + OsiModelLayer parseUntilLayer = OsiModelLayerUnknown); + + /** + * The main API that drives IPReassembly. This method should be called whenever a fragment arrives. This method + * finds the relevant packet this fragment belongs to and runs the IPv4 reassembly logic that is described in + * IPReassembly.h. + * @param[in] fragment The fragment to process (IPv4 or IPv6). Please notice that the reassembly logic doesn't + * change or manipulate this object in any way. All of its data is copied to internal structures and manipulated + * there + * @param[out] status An indication of the packet reassembly status following the processing of this fragment. + * Possible values are: + * - The input fragment is not a IPv4 or IPv6 packet + * - The input fragment is not a IPv4 or IPv6 fragment packet + * - The input fragment is the first fragment of the packet + * - The input fragment is not the first or last fragment + * - The input fragment came out-of-order, meaning that wasn't the fragment that was currently expected (it's + * data is copied to the out-of-order fragment list) + * - The input fragment is malformed and will be ignored + * - The input fragment is the last one and the packet is now fully reassembled. In this case the return value + * will contain a pointer to the reassembled packet + * @param[in] parseUntil Optional parameter. Parse the raw and reassembled packets until you reach a certain + * protocol (inclusive). Can be useful for cases when you need to parse only up to a certain layer and want to + * avoid the performance impact and memory consumption of parsing the whole packet. Note that setting this to a + * protocol which doesn't include the IP-Layer will result in IPReassembly not finding the IP-Layer and thus + * failing to work properly. Default value is ::UnknownProtocol which means don't take this parameter into + * account + * @param[in] parseUntilLayer Optional parameter. Parse the raw and reassembled packets until you reach a + * certain layer in the OSI model (inclusive). Can be useful for cases when you need to parse only up to a + * certain OSI layer (for example transport layer) and want to avoid the performance impact and memory + * consumption of parsing the whole packet. Note that setting this value to OsiModelPhysicalLayer will result in + * IPReassembly not finding the IP-layer and thus failing to work properly. Default value is ::UnknownProtocol + * which means don't take this parameter into account Default value is ::OsiModelLayerUnknown which means don't + * take this parameter into account + * @return + * - If the input fragment isn't an IPv4/IPv6 packet or if it isn't an IPv4/IPv6 fragment, the return value is a + * pointer to a Packet object wrapping the input fragment RawPacket object. It's the user responsibility to + * free this instance + * - If the input fragment is the last one and the reassembled packet is ready - a pointer to the reassembled + * packet is returned. Notice it's the user's responsibility to free this pointer when done using it + * - If the reassembled packet isn't ready then nullptr is returned + */ + Packet* processPacket(RawPacket* fragment, ReassemblyStatus& status, ProtocolType parseUntil = UnknownProtocol, + OsiModelLayer parseUntilLayer = OsiModelLayerUnknown); + + /** + * Get a partially reassembled packet. This method returns all the reassembled data that was gathered so far + * which is obviously not a fully reassembled packet (otherwise it would have returned by processPacket()). + * Notice all data is being copied so the user is responsible to free the returned Packet object when done using + * it. Notice#2 - calling this method doesn't interfere with the reassembly of this packet - all internal + * structures and data remain + * @param[in] key The identifiers of the packet to return + * @return A pointer to a Packet object containing the partially reassembled packet. Notice the user is + * responsible to free this object when done using it + */ + Packet* getCurrentPacket(const PacketKey& key); + + /** + * Remove a partially reassembled packet from all internal structures. That means that if another fragment of + * this packet appears it will be treated as a new packet + * @param[in] key The identifiers of the packet to remove + */ + void removePacket(const PacketKey& key); + + /** + * Get the maximum capacity as determined in the c'tor + */ + size_t getMaxCapacity() const + { + return m_PacketLRU.getMaxSize(); + } + + /** + * Get the current number of packets being processed + */ + size_t getCurrentCapacity() const + { + return m_FragmentMap.size(); + } + + private: + struct IPFragment + { + uint16_t fragmentOffset; + bool lastFragment; + uint8_t* fragmentData; + size_t fragmentDataLen; + IPFragment() + { + fragmentOffset = 0; + lastFragment = false; + fragmentData = nullptr; + fragmentDataLen = 0; + } + ~IPFragment() + { + delete[] fragmentData; + } + }; + + struct IPFragmentData + { + uint16_t currentOffset; + RawPacket* data; + bool deleteData; + uint32_t fragmentID; + PacketKey* packetKey; + PointerVector outOfOrderFragments; + IPFragmentData(PacketKey* pktKey, uint32_t fragId) + { + currentOffset = 0; + data = nullptr; + deleteData = true; + fragmentID = fragId; + packetKey = pktKey; + } + ~IPFragmentData() + { + delete packetKey; + if (deleteData && data != nullptr) + { + delete data; + } + } + }; + + LRUList m_PacketLRU; + std::unordered_map m_FragmentMap; + OnFragmentsClean m_OnFragmentsCleanCallback; + void* m_CallbackUserCookie; + + void addNewFragment(uint32_t hash, IPFragmentData* fragData); + bool matchOutOfOrderFragments(IPFragmentData* fragData); + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/IPSecLayer.h b/Packet++/header/pcapplusplus/IPSecLayer.h new file mode 100644 index 0000000000..d5945770fa --- /dev/null +++ b/Packet++/header/pcapplusplus/IPSecLayer.h @@ -0,0 +1,234 @@ +#pragma once + +/// @file + +#include "pcapplusplus/Layer.h" + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + /** + * @struct ipsec_authentication_header + * Represents IPSec AuthenticationHeader (AH) structure + */ +#pragma pack(push, 1) + struct ipsec_authentication_header + { + /** Type of the next header */ + uint8_t nextHeader; + /** The length of the Authentication Header in 4-octet units, minus 2 */ + uint8_t payloadLen; + /** Reserved */ + uint16_t reserved; + /** Security Parameters Index */ + uint32_t spi; + /** Sequence Number */ + uint32_t sequenceNumber; + }; +#pragma pack(pop) + + /** + * @struct ipsec_esp + * Represents IPSec Encapsulating Security Payload (ESP) structure + */ +#pragma pack(push, 1) + struct ipsec_esp + { + /** Security Parameters Index */ + uint32_t spi; + /** Sequence Number */ + uint32_t sequenceNumber; + }; +#pragma pack(pop) + + /** + * @class AuthenticationHeaderLayer + * Represents an IPSec AuthenticationHeader (AH) layer + */ + class AuthenticationHeaderLayer : public Layer + { + public: + /** A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + AuthenticationHeaderLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : Layer(data, dataLen, prevLayer, packet, AuthenticationHeader) + {} + + /** + * Get a pointer to the raw AH header. Notice this points directly to the data, so every change will change the + * actual packet data + * @return A pointer to the ipsec_authentication_header + */ + ipsec_authentication_header* getAHHeader() const + { + return (ipsec_authentication_header*)m_Data; + } + + /** + * @return The Security Parameters Index (SPI) field value + */ + uint32_t getSPI() const; + + /** + * @return The sequence number value + */ + uint32_t getSequenceNumber() const; + + /** + * @return The size of the Integrity Check Value (ICV) + */ + size_t getICVLength() const; + + /** + * @return A pointer to the raw data of the Integrity Check Value (ICV) + */ + uint8_t* getICVBytes() const; + + /** + * @return The value of the Integrity Check Value (ICV) as a hex string + */ + std::string getICVHexStream() const; + + /** + * A static method that validates the input data + * @param[in] data The pointer to the beginning of a byte stream of a AuthenticationHeader layer + * @param[in] dataLen The length of byte stream + * @return True if the data is valid and can represent an AuthenticationHeader layer + */ + static inline bool isDataValid(const uint8_t* data, size_t dataLen); + + // implement abstract methods + + /** + * @return The size of the AH header + */ + size_t getHeaderLen() const + { + return 4 * (getAHHeader()->payloadLen + 2); + } + + /** + * Currently identifies the following next layers: UdpLayer, TcpLayer, IPv4Layer, IPv6Layer and ESPLayer. + * Otherwise sets PayloadLayer + */ + void parseNextLayer(); + + /** + * Does nothing for this layer + */ + void computeCalculateFields() + {} + + std::string toString() const; + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelNetworkLayer; + } + + private: + // this layer supports parsing only + AuthenticationHeaderLayer() + {} + }; + + /** + * @class ESPLayer + * Represents an IPSec Encapsulating Security Payload (ESP) layer + */ + class ESPLayer : public Layer + { + public: + /** A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + ESPLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : Layer(data, dataLen, prevLayer, packet, ESP) + {} + + ipsec_esp* getESPHeader() const + { + return reinterpret_cast(m_Data); + } + + /** + * @return The Security Parameters Index (SPI) field value + */ + uint32_t getSPI() const; + + /** + * @return The sequence number value + */ + uint32_t getSequenceNumber() const; + + /** + * A static method that validates the input data + * @param[in] data The pointer to the beginning of a byte stream of a ESP layer + * @param[in] dataLen The length of byte stream + * @return True if the data is valid and can represent an ESP layer + */ + static inline bool isDataValid(const uint8_t* data, size_t dataLen); + + // implement abstract methods + + /** + * @return The size of the ESP header (8 bytes) + */ + size_t getHeaderLen() const + { + return sizeof(ipsec_esp); + } + + /** + * The payload of an ESP layer is encrypted, hence the next layer is always a generic payload (PayloadLayer) + */ + void parseNextLayer(); + + /** + * Does nothing for this layer + */ + void computeCalculateFields() + {} + + std::string toString() const; + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelTransportLayer; + } + + private: + // this layer supports parsing only + ESPLayer() + {} + }; + + // implementation of inline methods + + bool AuthenticationHeaderLayer::isDataValid(const uint8_t* data, size_t dataLen) + { + if (dataLen < sizeof(ipsec_authentication_header)) + return false; + + size_t payloadLen = 4 * (data[1] + 2); + if (payloadLen < sizeof(ipsec_authentication_header) || payloadLen > dataLen) + return false; + + return true; + } + + bool ESPLayer::isDataValid(const uint8_t* data, size_t dataLen) + { + return data && dataLen >= sizeof(ipsec_esp); + } +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/IPv4Layer.h b/Packet++/header/pcapplusplus/IPv4Layer.h new file mode 100644 index 0000000000..b0aafba34f --- /dev/null +++ b/Packet++/header/pcapplusplus/IPv4Layer.h @@ -0,0 +1,736 @@ +#pragma once + +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/TLVData.h" +#include "pcapplusplus/IpAddress.h" +#include "pcapplusplus/IPLayer.h" +#include +#include + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * @struct iphdr + * Represents an IPv4 protocol header + */ +#pragma pack(push, 1) + struct iphdr + { +#if (BYTE_ORDER == LITTLE_ENDIAN) + /** IP header length, has the value of 5 for IPv4 */ + uint8_t internetHeaderLength : 4, + /** IP version number, has the value of 4 for IPv4 */ + ipVersion : 4; +#else + /** IP version number, has the value of 4 for IPv4 */ + uint8_t ipVersion : 4, + /** IP header length, has the value of 5 for IPv4 */ + internetHeaderLength : 4; +#endif + /** type of service, same as Differentiated Services Code Point (DSCP)*/ + uint8_t typeOfService; + /** Entire packet (fragment) size, including header and data, in bytes */ + uint16_t totalLength; + /** Identification field. Primarily used for uniquely identifying the group of fragments of a single IP + * datagram*/ + uint16_t ipId; + /** Fragment offset field, measured in units of eight-byte blocks (64 bits) */ + uint16_t fragmentOffset; + /** An eight-bit time to live field helps prevent datagrams from persisting (e.g. going in circles) on an + * internet. In practice, the field has become a hop count */ + uint8_t timeToLive; + /** Defines the protocol used in the data portion of the IP datagram. Must be one of ::IPProtocolTypes */ + uint8_t protocol; + /** Error-checking of the header */ + uint16_t headerChecksum; + /** IPv4 address of the sender of the packet */ + uint32_t ipSrc; + /** IPv4 address of the receiver of the packet */ + uint32_t ipDst; + /*The options start here. */ + }; +#pragma pack(pop) + + /** + * An enum for all possible IPv4 and IPv6 protocol types + */ + enum IPProtocolTypes + { + /** Dummy protocol for TCP */ + PACKETPP_IPPROTO_IP = 0, + /** IPv6 Hop-by-Hop options */ + PACKETPP_IPPROTO_HOPOPTS = 0, + /** Internet Control Message Protocol */ + PACKETPP_IPPROTO_ICMP = 1, + /** Internet Gateway Management Protocol */ + PACKETPP_IPPROTO_IGMP = 2, + /** IPIP tunnels (older KA9Q tunnels use 94) */ + PACKETPP_IPPROTO_IPIP = 4, + /** Transmission Control Protocol */ + PACKETPP_IPPROTO_TCP = 6, + /** Exterior Gateway Protocol */ + PACKETPP_IPPROTO_EGP = 8, + /** PUP protocol */ + PACKETPP_IPPROTO_PUP = 12, + /** User Datagram Protocol */ + PACKETPP_IPPROTO_UDP = 17, + /** XNS IDP protocol */ + PACKETPP_IPPROTO_IDP = 22, + /** IPv6 header */ + PACKETPP_IPPROTO_IPV6 = 41, + /** IPv6 Routing header */ + PACKETPP_IPPROTO_ROUTING = 43, + /** IPv6 fragmentation header */ + PACKETPP_IPPROTO_FRAGMENT = 44, + /** GRE protocol */ + PACKETPP_IPPROTO_GRE = 47, + /** encapsulating security payload */ + PACKETPP_IPPROTO_ESP = 50, + /** authentication header */ + PACKETPP_IPPROTO_AH = 51, + /** ICMPv6 */ + PACKETPP_IPPROTO_ICMPV6 = 58, + /** IPv6 no next header */ + PACKETPP_IPPROTO_NONE = 59, + /** IPv6 Destination options */ + PACKETPP_IPPROTO_DSTOPTS = 60, + /** VRRP protocol */ + PACKETPP_IPPROTO_VRRP = 112, + /** Raw IP packets */ + PACKETPP_IPPROTO_RAW = 255, + /** Maximum value */ + PACKETPP_IPPROTO_MAX + }; + + /** + * An enum for supported IPv4 option types + */ + enum IPv4OptionTypes + { + /** End of Options List */ + IPV4OPT_EndOfOptionsList = 0, + /** No Operation */ + IPV4OPT_NOP = 1, + /** Record Route */ + IPV4OPT_RecordRoute = 7, + /** MTU Probe */ + IPV4OPT_MTUProbe = 11, + /** MTU Reply */ + IPV4OPT_MTUReply = 12, + /** Quick-Start */ + IPV4OPT_QuickStart = 25, + /** Timestamp */ + IPV4OPT_Timestamp = 68, + /** Traceroute */ + IPV4OPT_Traceroute = 82, + /** Security */ + IPV4OPT_Security = 130, + /** Loose Source Route */ + IPV4OPT_LooseSourceRoute = 131, + /** Extended Security */ + IPV4OPT_ExtendedSecurity = 133, + /** Commercial Security */ + IPV4OPT_CommercialSecurity = 134, + /** Stream ID */ + IPV4OPT_StreamID = 136, + /** Strict Source Route */ + IPV4OPT_StrictSourceRoute = 137, + /** Extended Internet Protocol */ + IPV4OPT_ExtendedInternetProtocol = 145, + /** Address Extension */ + IPV4OPT_AddressExtension = 147, + /** Router Alert */ + IPV4OPT_RouterAlert = 148, + /** Selective Directed Broadcast */ + IPV4OPT_SelectiveDirectedBroadcast = 149, + /** Dynamic Packet State */ + IPV4OPT_DynamicPacketState = 151, + /** Upstream Multicast Pkt. */ + IPV4OPT_UpstreamMulticastPkt = 152, + /** Unknown IPv4 option */ + IPV4OPT_Unknown + }; + +#define PCPP_IP_DONT_FRAGMENT 0x40 +#define PCPP_IP_MORE_FRAGMENTS 0x20 + + /** + * @struct IPv4TimestampOptionValue + * A struct representing a parsed value of the IPv4 timestamp option. This struct is used returned in + * IPv4OptionData#getTimestampOptionValue() method + */ + struct IPv4TimestampOptionValue + { + /** + * An enum for IPv4 timestamp option types + */ + enum TimestampType + { + /** Value containing only timestamps */ + TimestampOnly = 0, + /** Value containing both timestamps and IPv4 addresses */ + TimestampAndIP = 1, + /** The IPv4 addresses are prespecified */ + TimestampsForPrespecifiedIPs = 2, + /** Invalid or unknown value type */ + Unknown = 3 + }; + + /** The timestamp value type */ + TimestampType type; + + /** A list of timestamps parsed from the IPv4 timestamp option value */ + std::vector timestamps; + + /** A list of IPv4 addresses parsed from the IPv4 timestamp option value */ + std::vector ipAddresses; + + /** The default constructor */ + IPv4TimestampOptionValue() : type(IPv4TimestampOptionValue::Unknown) + {} + + /** + * Clear the structure. Clean the timestamps and IP addresses vectors and set the type as + * IPv4TimestampOptionValue#Unknown + */ + void clear() + { + type = IPv4TimestampOptionValue::Unknown; + timestamps.clear(); + ipAddresses.clear(); + } + }; + + /** + * @class IPv4Option + * A wrapper class for IPv4 options. This class does not create or modify IPv4 option records, but rather + * serves as a wrapper and provides useful methods for retrieving data from them + */ + class IPv4Option : public TLVRecord + { + public: + /** + * A c'tor for this class that gets a pointer to the option raw data (byte array) + * @param[in] optionRawData A pointer to the IPv4 option raw data + */ + explicit IPv4Option(uint8_t* optionRawData) : TLVRecord(optionRawData) + {} + + /** + * A d'tor for this class, currently does nothing + */ + ~IPv4Option() + {} + + /** + * A method for parsing the IPv4 option value as a list of IPv4 addresses. This method is relevant only for + * certain types of IPv4 options which their value is a list of IPv4 addresses such as ::IPV4OPT_RecordRoute, + * ::IPV4OPT_StrictSourceRoute, ::IPV4OPT_LooseSourceRoute, etc. This method returns a vector of the IPv4 + * addresses. Blank IP addresses (meaning zeroed addresses - 0.0.0.0) will not be added to the returned list. If + * some error occurs during the parsing or the value is invalid an empty vector is returned + * @return A vector of IPv4 addresses parsed from the IPv4 option value + */ + std::vector getValueAsIpList() const + { + std::vector res; + + if (m_Data == nullptr) + return res; + + size_t dataSize = getDataSize(); + if (dataSize < 2) + return res; + + uint8_t valueOffset = static_cast(1); + + while (static_cast(valueOffset) < dataSize) + { + uint32_t curValue; + memcpy(&curValue, m_Data->recordValue + valueOffset, sizeof(uint32_t)); + if (curValue == 0) + break; + + res.push_back(IPv4Address(curValue)); + + valueOffset += static_cast(4); + } + + return res; + } + + /** + * A method for parsing the IPv4 timestamp option value. This method is relevant only for IPv4 timestamp option. + * For other option types an empty result will be returned. The returned structure contains the timestamp value + * type (timestamp only, timestamp + IP addresses, etc.) as well as 2 vectors containing the list of timestamps + * and the list of IP addresses (if applicable for the timestamp value type). Blank timestamps or IP addresses + * (meaning zeroed values - timestamp=0 or IP address=0.0.0.0) will not be added to the lists. If some error + * occurs during the parsing or the value is invalid an empty result is returned + * @return A structured containing the IPv4 timestamp value + */ + IPv4TimestampOptionValue getTimestampOptionValue() const + { + IPv4TimestampOptionValue res; + res.clear(); + + if (m_Data == nullptr) + return res; + + if (getIPv4OptionType() != IPV4OPT_Timestamp) + return res; + + size_t dataSize = getDataSize(); + if (dataSize < 2) + return res; + + res.type = static_cast(m_Data->recordValue[1]); + + uint8_t valueOffset = static_cast(2); + bool readIPAddr = (res.type == IPv4TimestampOptionValue::TimestampAndIP); + + while (static_cast(valueOffset) < dataSize) + { + uint32_t curValue; + memcpy(&curValue, m_Data->recordValue + valueOffset, sizeof(uint32_t)); + if (curValue == 0) + break; + + if (readIPAddr) + res.ipAddresses.push_back(IPv4Address(curValue)); + else + res.timestamps.push_back(curValue); + + if (res.type == IPv4TimestampOptionValue::TimestampAndIP) + readIPAddr = !readIPAddr; + + valueOffset += static_cast(4); + } + + return res; + } + + /** + * @return IPv4 option type casted as pcpp::IPv4OptionTypes enum + */ + IPv4OptionTypes getIPv4OptionType() const + { + return getIPv4OptionType(m_Data); + } + + /** + * Check if a pointer can be assigned to the TLV record data + * @param[in] recordRawData A pointer to the TLV record raw data + * @param[in] tlvDataLen The size of the TLV record raw data + * @return True if data is valid and can be assigned + */ + static bool canAssign(const uint8_t* recordRawData, size_t tlvDataLen) + { + auto data = reinterpret_cast(recordRawData); + if (data == nullptr) + return false; + + if (tlvDataLen < sizeof(TLVRawData::recordType)) + return false; + + if (getIPv4OptionType(data) == static_cast(IPV4OPT_EndOfOptionsList) || + data->recordType == static_cast(IPV4OPT_NOP)) + return true; + + return TLVRecord::canAssign(recordRawData, tlvDataLen); + } + + // implement abstract methods + + size_t getTotalSize() const + { + if (m_Data == nullptr) + return 0; + + if (getIPv4OptionType() == static_cast(IPV4OPT_EndOfOptionsList) || + m_Data->recordType == static_cast(IPV4OPT_NOP)) + return sizeof(uint8_t); + + return static_cast(m_Data->recordLen); + } + + size_t getDataSize() const + { + if (m_Data == nullptr) + return 0; + + if (getIPv4OptionType() == static_cast(IPV4OPT_EndOfOptionsList) || + m_Data->recordType == static_cast(IPV4OPT_NOP)) + return 0; + + return static_cast(m_Data->recordLen) - (2 * sizeof(uint8_t)); + } + + private: + /** + * @return IPv4 option type casted as pcpp::IPv4OptionTypes enum + */ + static IPv4OptionTypes getIPv4OptionType(const TLVRawData* data) + { + if (data == nullptr) + return IPV4OPT_Unknown; + + return static_cast(data->recordType); + } + }; + + /** + * @class IPv4OptionBuilder + * A class for building IPv4 option records. This builder receives the IPv4 option parameters in its c'tor, + * builds the IPv4 option raw buffer and provides a build() method to get a IPv4Option object out of it + */ + class IPv4OptionBuilder : public TLVRecordBuilder + { + private: + bool m_BuilderParamsValid; + + public: + /** + * A c'tor for building IPv4 options which their value is a byte array. The IPv4Option object can be later + * retrieved by calling build() + * @param[in] optionType IPv4 option type + * @param[in] optionValue A buffer containing the option value. This buffer is read-only and isn't modified in + * any way. For option types ::IPV4OPT_NOP and ::IPV4OPT_EndOfOptionsList this parameter is ignored (expected to + * be nullptr) as these option types don't contain any data + * @param[in] optionValueLen Option value length in bytes + */ + IPv4OptionBuilder(IPv4OptionTypes optionType, const uint8_t* optionValue, uint8_t optionValueLen) + : TLVRecordBuilder((uint8_t)optionType, optionValue, optionValueLen) + { + m_BuilderParamsValid = true; + } + + /** + * A c'tor for building IPv4 options which have a 2-byte value. The IPv4Option object can be later retrieved + * by calling build() + * @param[in] optionType IPv4 option type + * @param[in] optionValue A 2-byte option value + */ + IPv4OptionBuilder(IPv4OptionTypes optionType, uint16_t optionValue) + : TLVRecordBuilder((uint8_t)optionType, optionValue) + { + m_BuilderParamsValid = true; + } + + /** + * A c'tor for building IPv4 options which their value is a list of IPv4 addresses, for example: + * ::IPV4OPT_RecordRoute, ::IPV4OPT_StrictSourceRoute, ::IPV4OPT_LooseSourceRoute. The IPv4Option object can be + * later retrieved by calling build() + * @param[in] optionType IPv4 option type + * @param[in] ipList A vector of IPv4 addresses that will be used as the option value + */ + IPv4OptionBuilder(IPv4OptionTypes optionType, const std::vector& ipList); + + /** + * A c'tor for building IPv4 timestamp option (::IPV4OPT_Timestamp). The IPv4Option object can be later + * retrieved by calling build() + * @param[in] timestampValue The timestamp value to build the IPv4 option with + */ + explicit IPv4OptionBuilder(const IPv4TimestampOptionValue& timestampValue); + + /** + * Build the IPv4Option object out of the parameters defined in the c'tor + * @return The IPv4Option object + */ + IPv4Option build() const; + }; + + /** + * @class IPv4Layer + * Represents an IPv4 protocol layer + */ + class IPv4Layer : public Layer, public IPLayer + { + public: + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data (will be casted to @ref iphdr) + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + IPv4Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data (will be casted to @ref iphdr) + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + * @param[in] setTotalLenAsDataLen When setting this value to "true" or when using the other c'tor, the layer + * data length is calculated from iphdr#totalLength field. When setting to "false" the data length is set as the + * value of dataLen parameter. Please notice that if iphdr#totalLength is equal to zero (which can happen in TCP + * Segmentation Offloading), this flag is ignored and the layer data length is calculated by the actual data + * captured on the wire + */ + IPv4Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, bool setTotalLenAsDataLen); + + /** + * A constructor that allocates a new IPv4 header with empty fields + */ + IPv4Layer(); + + /** + * A constructor that allocates a new IPv4 header with source and destination IPv4 addresses + * @param[in] srcIP Source IPv4 address + * @param[in] dstIP Destination IPv4 address + */ + IPv4Layer(const IPv4Address& srcIP, const IPv4Address& dstIP); + + /** + * A copy constructor that copy the entire header from the other IPv4Layer (including IPv4 options) + */ + IPv4Layer(const IPv4Layer& other); + + /** + * An assignment operator that first delete all data from current layer and then copy the entire header from the + * other IPv4Layer (including IPv4 options) + */ + IPv4Layer& operator=(const IPv4Layer& other); + + /** + * Get a pointer to the IPv4 header. Notice this points directly to the data, so every change will change the + * actual packet data + * @return A pointer to the @ref iphdr + */ + iphdr* getIPv4Header() const + { + return (iphdr*)m_Data; + } + + /** + * Get the source IP address in the form of IPAddress. This method is very similar to getSrcIPv4Address(), + * but adds a level of abstraction because IPAddress can be used for both IPv4 and IPv6 addresses + * @return An IPAddress containing the source address + */ + IPAddress getSrcIPAddress() const + { + return getSrcIPv4Address(); + } + + /** + * Get the source IP address in the form of IPv4Address + * @return An IPv4Address containing the source address + */ + IPv4Address getSrcIPv4Address() const + { + return getIPv4Header()->ipSrc; + } + + /** + * Set the source IP address + * @param[in] ipAddr The IP address to set + */ + void setSrcIPv4Address(const IPv4Address& ipAddr) + { + getIPv4Header()->ipSrc = ipAddr.toInt(); + } + + /** + * Get the destination IP address in the form of IPAddress. This method is very similar to getDstIPv4Address(), + * but adds a level of abstraction because IPAddress can be used for both IPv4 and IPv6 addresses + * @return An IPAddress containing the destination address + */ + IPAddress getDstIPAddress() const + { + return getDstIPv4Address(); + } + + /** + * Get the destination IP address in the form of IPv4Address + * @return An IPv4Address containing the destination address + */ + IPv4Address getDstIPv4Address() const + { + return getIPv4Header()->ipDst; + } + + /** + * Set the dest IP address + * @param[in] ipAddr The IP address to set + */ + void setDstIPv4Address(const IPv4Address& ipAddr) + { + getIPv4Header()->ipDst = ipAddr.toInt(); + } + + /** + * @return True if this packet is a fragment (in sense of IP fragmentation), false otherwise + */ + bool isFragment() const; + + /** + * @return True if this packet is a fragment (in sense of IP fragmentation) and is the first fragment + * (which usually contains the L4 header). Return false otherwise (not a fragment or not the first fragment) + */ + bool isFirstFragment() const; + + /** + * @return True if this packet is a fragment (in sense of IP fragmentation) and is the last fragment. + * Return false otherwise (not a fragment or not the last fragment) + */ + bool isLastFragment() const; + + /** + * @return A bitmask containing the fragmentation flags (e.g IP_DONT_FRAGMENT or IP_MORE_FRAGMENTS) + */ + uint8_t getFragmentFlags() const; + + /** + * @return The fragment offset in case this packet is a fragment, 0 otherwise + */ + uint16_t getFragmentOffset() const; + + /** + * Get an IPv4 option by type. + * @param[in] option IPv4 option type + * @return An IPv4Option object that contains the first option that matches this type, or logical null + * (IPv4Option#isNull() == true) if no such option found + */ + IPv4Option getOption(IPv4OptionTypes option) const; + + /** + * @return The first IPv4 option in the packet. If the current layer contains no options the returned value will + * contain a logical null (IPv4Option#isNull() == true) + */ + IPv4Option getFirstOption() const; + + /** + * Get the IPv4 option that comes after a given option. If the given option was the last one, the + * returned value will contain a logical null (IPv4Option#isNull() == true) + * @param[in] option An IPv4 option object that exists in the current layer + * @return A IPv4Option object that contains the IPv4 option data that comes next, or logical null if the + * given IPv4 option: (1) was the last one; or (2) contains a logical null; or (3) doesn't belong to this + * packet + */ + IPv4Option getNextOption(IPv4Option& option) const; + + /** + * @return The number of IPv4 options in this layer + */ + size_t getOptionCount() const; + + /** + * Add a new IPv4 option at the end of the layer (after the last IPv4 option) + * @param[in] optionBuilder An IPv4OptionBuilder object that contains the IPv4 option data to be added + * @return A IPv4Option object that contains the newly added IPv4 option data or logical null + * (IPv4Option#isNull() == true) if addition failed. In case of a failure a corresponding error message will be + * printed to log + */ + IPv4Option addOption(const IPv4OptionBuilder& optionBuilder); + + /** + * Add a new IPv4 option after an existing one + * @param[in] optionBuilder An IPv4OptionBuilder object that contains the requested IPv4 option data to be added + * @param[in] prevOptionType The IPv4 option which the newly added option should come after. This is an optional + * parameter which gets a default value of ::IPV4OPT_Unknown if omitted, which means the new option will be + * added as the first option in the layer + * @return A IPv4Option object containing the newly added IPv4 option data or logical null + * (IPv4Option#isNull() == true) if addition failed. In case of a failure a corresponding error message will be + * printed to log + */ + IPv4Option addOptionAfter(const IPv4OptionBuilder& optionBuilder, + IPv4OptionTypes prevOptionType = IPV4OPT_Unknown); + + /** + * Remove an IPv4 option + * @param[in] option The option type to remove + * @return True if option was removed successfully or false if option type wasn't found or failed to shorten the + * layer. If an option appears twice in the layer, its first instance will be removed + */ + bool removeOption(IPv4OptionTypes option); + + /** + * Remove all IPv4 options from the layer + * @return True if options removed successfully or false if some error occurred (an appropriate error message + * will be printed to log) + */ + bool removeAllOptions(); + + // implement abstract methods + + /** + * Currently identifies the following next layers: + * - UdpLayer + * - TcpLayer + * - IcmpLayer + * - IPv4Layer (IP-in-IP) + * - IPv6Layer (IP-in-IP) + * - GreLayer + * - IgmpLayer + * - AuthenticationHeaderLayer (IPSec) + * - ESPLayer (IPSec) + * + * Otherwise sets PayloadLayer + */ + void parseNextLayer(); + + /** + * @return Size of IPv4 header (including IPv4 options if exist) + */ + size_t getHeaderLen() const + { + return static_cast(static_cast(getIPv4Header()->internetHeaderLength) * 4) + + m_TempHeaderExtension; + } + + /** + * Calculate the following fields: + * - iphdr#ipVersion = 4; + * - iphdr#totalLength = total packet length + * - iphdr#headerChecksum = calculated + * - iphdr#protocol = calculated if next layer is known: ::PACKETPP_IPPROTO_TCP for TCP, ::PACKETPP_IPPROTO_UDP + * for UDP, ::PACKETPP_IPPROTO_ICMP for ICMP + */ + void computeCalculateFields(); + + std::string toString() const; + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelNetworkLayer; + } + + /** + * A static method that validates the input data + * @param[in] data The pointer to the beginning of a byte stream of IP packet + * @param[in] dataLen The length of the byte stream + * @return True if the data is valid and can represent an IPv4 packet + */ + static inline bool isDataValid(const uint8_t* data, size_t dataLen); + + private: + int m_NumOfTrailingBytes; + int m_TempHeaderExtension; + TLVRecordReader m_OptionReader; + + void copyLayerData(const IPv4Layer& other); + uint8_t* getOptionsBasePtr() const + { + return m_Data + sizeof(iphdr); + } + IPv4Option addOptionAt(const IPv4OptionBuilder& optionBuilder, int offset); + void adjustOptionsTrailer(size_t totalOptSize); + void initLayer(); + void initLayerInPacket(bool setTotalLenAsDataLen); + }; + + // implementation of inline methods + + bool IPv4Layer::isDataValid(const uint8_t* data, size_t dataLen) + { + const iphdr* hdr = reinterpret_cast(data); + return dataLen >= sizeof(iphdr) && hdr->ipVersion == 4 && hdr->internetHeaderLength >= 5; + } + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/IPv6Extensions.h b/Packet++/header/pcapplusplus/IPv6Extensions.h new file mode 100644 index 0000000000..2979306752 --- /dev/null +++ b/Packet++/header/pcapplusplus/IPv6Extensions.h @@ -0,0 +1,591 @@ +#pragma once + +#include +#include "pcapplusplus/IpAddress.h" +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/TLVData.h" + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * @class IPv6Extension + * A base class for all supported IPv6 extensions. This class is abstract, meaning it cannot be instantiated or + * copied (has private c'tor and copy c'tor) + */ + class IPv6Extension + { + friend class IPv6Layer; + + public: + /** + * An enum representing all supported IPv6 extension types + */ + enum IPv6ExtensionType + { + /** Hop-By-Hop extension type */ + IPv6HopByHop = 0, + /** Routing extension type */ + IPv6Routing = 43, + /** IPv6 fragmentation extension type */ + IPv6Fragmentation = 44, + /** Authentication Header extension type */ + IPv6AuthenticationHdr = 51, + /** Destination extension type */ + IPv6Destination = 60, + /** Unknown or unsupported extension type */ + IPv6ExtensionUnknown = 255 + }; + + /** + * @return The size of extension in bytes, meaning (for most extensions): 8 * ([headerLen field] + 1) + */ + virtual size_t getExtensionLen() const + { + return 8 * (getBaseHeader()->headerLen + 1); + } + + /** + * @return The type of the extension + */ + IPv6ExtensionType getExtensionType() const + { + return m_ExtType; + } + + /** + * A destructor for this class + */ + virtual ~IPv6Extension(); + + /** + * @return A pointer to the next header or nullptr if the extension is the last one + */ + IPv6Extension* getNextHeader() const + { + return m_NextHeader; + } + + protected: + struct ipv6_ext_base_header + { + uint8_t nextHeader; + uint8_t headerLen; + }; + + // protected c'tor + IPv6Extension(IDataContainer* dataContainer, size_t offset) + : m_NextHeader(nullptr), m_ExtType(IPv6ExtensionUnknown), m_DataContainer(dataContainer), m_Offset(offset), + m_ShadowData(nullptr) + {} + + // protected empty c'tor + IPv6Extension() + : m_NextHeader(nullptr), m_ExtType(IPv6ExtensionUnknown), m_DataContainer(nullptr), m_Offset(0), + m_ShadowData(nullptr) + {} + + // protected assignment operator + IPv6Extension& operator=(const IPv6Extension& other); + + uint8_t* getDataPtr() const; + + void initShadowPtr(size_t size); + + ipv6_ext_base_header* getBaseHeader() const + { + return (ipv6_ext_base_header*)getDataPtr(); + } + + void setNextHeader(IPv6Extension* nextHeader) + { + m_NextHeader = nextHeader; + } + + IPv6Extension* m_NextHeader; + IPv6ExtensionType m_ExtType; + + private: + IDataContainer* m_DataContainer; + size_t m_Offset; + uint8_t* m_ShadowData; + }; + + /** + * @class IPv6FragmentationHeader + * Represents an IPv6 fragmentation extension header and allows easy access to all fragmentation parameters + */ + class IPv6FragmentationHeader : public IPv6Extension + { + friend class IPv6Layer; + + public: + /** + * @struct ipv6_frag_header + * A struct representing IPv6 fragmentation header + */ + struct ipv6_frag_header + { + /** Next header type */ + uint8_t nextHeader; + /** Fragmentation header size is fixed 8 bytes, so len is always zero */ + uint8_t headerLen; + /** Offset, in 8-octet units, relative to the start of the fragmentable part of the original packet + * plus 1-bit indicating if more fragments will follow */ + uint16_t fragOffsetAndFlags; + /** packet identification value. Needed for reassembly of the original packet */ + uint32_t id; + }; + + /** + * A c'tor for creating a new IPv6 fragmentation extension object not bounded to a packet. Useful for adding new + * extensions to an IPv6 layer with IPv6Layer#addExtension() + * @param[in] fragId Fragmentation ID + * @param[in] fragOffset Fragmentation offset + * @param[in] lastFragment Indicates whether this fragment is the last one + */ + IPv6FragmentationHeader(uint32_t fragId, uint16_t fragOffset, bool lastFragment); + + /** + * Get a pointer to the fragmentation header. Notice the returned pointer points directly to the data, so every + * change will modify the actual packet data + * @return A pointer to the @ref ipv6_frag_header + */ + ipv6_frag_header* getFragHeader() const + { + return (ipv6_frag_header*)getDataPtr(); + } + + /** + * @return True if this is the first fragment (which usually contains the L4 header), false otherwise + */ + bool isFirstFragment() const; + + /** + * @return True if this is the last fragment, false otherwise + */ + bool isLastFragment() const; + + /** + * @return True if the "more fragments" bit is set, meaning more fragments are expected to follow this fragment + */ + bool isMoreFragments() const; + + /** + * @return The fragment offset + */ + uint16_t getFragmentOffset() const; + + private: + IPv6FragmentationHeader(IDataContainer* dataContainer, size_t offset) : IPv6Extension(dataContainer, offset) + { + m_ExtType = IPv6Fragmentation; + } + }; + + /** + * An abstract base class for Hop-By-Hop and Destination IPv6 extensions which their structure contains + * Type-Length-Value (TLV) options. This class provides access to these options and their data as well as methods to + * create new options. Notice this class is abstract and cannot be instantiated + */ + class IPv6TLVOptionHeader : public IPv6Extension + { + friend class IPv6Layer; + + public: + /** + * @class IPv6Option + * A class representing a Type-Length-Value (TLV) options that are used inside Hop-By-Hop and Destinations IPv6 + * extensions. This class does not create or modify IPv6 option records, but rather serves as a wrapper and + * provides useful methods for retrieving data from them + */ + class IPv6Option : public TLVRecord + { + public: + static const uint8_t Pad0OptionType = 0; + static const uint8_t PadNOptionType = 1; + + /** + * A c'tor for this class that gets a pointer to the option raw data (byte array) + * @param[in] optionRawData A pointer to the attribute raw data + */ + explicit IPv6Option(uint8_t* optionRawData) : TLVRecord(optionRawData) + {} + + /** + * A d'tor for this class, currently does nothing + */ + ~IPv6Option() + {} + + /** + * Check if a pointer can be assigned to the TLV record data + * @param[in] recordRawData A pointer to the TLV record raw data + * @param[in] tlvDataLen The size of the TLV record raw data + * @return True if data is valid and can be assigned + */ + static bool canAssign(const uint8_t* recordRawData, size_t tlvDataLen) + { + auto data = (TLVRawData*)recordRawData; + if (data == nullptr) + return false; + + if (tlvDataLen < sizeof(TLVRawData::recordType)) + return false; + + if (data->recordType == Pad0OptionType) + return true; + + return TLVRecord::canAssign(recordRawData, tlvDataLen); + } + + // implement abstract methods + + size_t getTotalSize() const + { + if (m_Data == nullptr) + return 0; + + if (m_Data->recordType == Pad0OptionType) + return sizeof(uint8_t); + + return (size_t)(m_Data->recordLen + sizeof(uint16_t)); + } + + size_t getDataSize() const + { + if (m_Data == nullptr || m_Data->recordType == Pad0OptionType) + return 0; + + return (size_t)m_Data->recordLen; + } + }; + + /** + * @class IPv6TLVOptionBuilder + * A class for building IPv6 Type-Length-Value (TLV) options. This builder receives the option parameters in its + * c'tor, builds the option raw buffer and provides a method to build a IPv6Option object out of it + */ + class IPv6TLVOptionBuilder : public TLVRecordBuilder + { + public: + /** + * A c'tor for building IPv6 TLV options which their value is a byte array. The IPv6Option object can later + * be retrieved by calling build() + * @param[in] optType IPv6 option type + * @param[in] optValue A buffer containing the option value. This buffer is read-only and isn't modified in + * any way + * @param[in] optValueLen Option value length in bytes + */ + IPv6TLVOptionBuilder(uint8_t optType, const uint8_t* optValue, uint8_t optValueLen) + : TLVRecordBuilder(optType, optValue, optValueLen) + {} + + /** + * A c'tor for building IPv6 TLV options which have a 1-byte value. The IPv6Option object can later be + * retrieved by calling build() + * @param[in] optType IPv6 option type + * @param[in] optValue A 1-byte option value + */ + IPv6TLVOptionBuilder(uint8_t optType, uint8_t optValue) : TLVRecordBuilder(optType, optValue) + {} + + /** + * A c'tor for building IPv6 TLV options which have a 2-byte value. The IPv6Option object can later be + * retrieved by calling build() + * @param[in] optType IPv6 option type + * @param[in] optValue A 2-byte option value + */ + IPv6TLVOptionBuilder(uint8_t optType, uint16_t optValue) : TLVRecordBuilder(optType, optValue) + {} + + /** + * A copy c'tor that creates an instance of this class out of another instance and copies all the data from + * it + * @param[in] other The instance to copy data from + */ + IPv6TLVOptionBuilder(const IPv6TLVOptionBuilder& other) : TLVRecordBuilder(other) + {} + + /** + * Assignment operator that copies all data from another instance of IPv6TLVOptionBuilder + * @param[in] other The instance to assign from + */ + IPv6TLVOptionBuilder& operator=(const IPv6TLVOptionBuilder& other) + { + TLVRecordBuilder::operator=(other); + return *this; + } + + /** + * Build the IPv6Option object out of the parameters defined in the c'tor + * @return The IPv6Option object + */ + IPv6Option build() const; + }; + + /** + * Retrieve an option by its type + * @param[in] optionType Option type + * @return An IPv6Option object that wraps the option data. If option isn't found a logical null is returned + * (IPv6Option#isNull() == true) + */ + IPv6Option getOption(uint8_t optionType) const; + + /** + * @return An IPv6Option that wraps the first option data or logical null (IPv6Option#isNull() == true) if no + * options exist + */ + IPv6Option getFirstOption() const; + + /** + * Returns a pointer to the option that comes after the option given as the parameter + * @param[in] option A pointer to an option instance + * @return An IPv6Option object that wraps the option data. In the following cases logical null + * (IPv6Option#isNull() == true) is returned: (1) input parameter is out-of-bounds for this extension or (2) the + * next option doesn't exist or (3) the input option is nullptr + */ + IPv6Option getNextOption(IPv6Option& option) const; + + /** + * @returns The number of options this IPv6 extension contains + */ + size_t getOptionCount() const; + + protected: + /** A private c'tor to keep this object from being constructed */ + explicit IPv6TLVOptionHeader(const std::vector& options); + + IPv6TLVOptionHeader(IDataContainer* dataContainer, size_t offset); + + private: + TLVRecordReader m_OptionReader; + }; + + /** + * @class IPv6HopByHopHeader + * Represents IPv6 Hop-By-Hop extension header and allows easy access to all of its data including the TLV options + * stored + */ + class IPv6HopByHopHeader : public IPv6TLVOptionHeader + { + friend class IPv6Layer; + + public: + /** + * A c'tor for creating a new IPv6 Hop-By-Hop extension object not bounded to a packet. Useful for adding new + * extensions to an IPv6 layer with IPv6Layer#addExtension() + * @param[in] options A vector of IPv6TLVOptionHeader#TLVOptionBuilder instances which define the options that + * will be stored in the extension data. Notice this vector is read-only and its content won't be modified + */ + explicit IPv6HopByHopHeader(const std::vector& options) : IPv6TLVOptionHeader(options) + { + m_ExtType = IPv6HopByHop; + } + + private: + IPv6HopByHopHeader(IDataContainer* dataContainer, size_t offset) : IPv6TLVOptionHeader(dataContainer, offset) + { + m_ExtType = IPv6HopByHop; + } + }; + + /** + * @class IPv6DestinationHeader + * Represents IPv6 destination extension header and allows easy access to all of its data including the TLV options + * stored in it + */ + class IPv6DestinationHeader : public IPv6TLVOptionHeader + { + friend class IPv6Layer; + + public: + /** + * A c'tor for creating a new IPv6 destination extension object not bounded to a packet. Useful for adding new + * extensions to an IPv6 layer with IPv6Layer#addExtension() + * @param[in] options A vector of IPv6TLVOptionHeader#TLVOptionBuilder instances which define the options that + * will be stored in the extension data. Notice this vector is read-only and its content won't be modified + */ + explicit IPv6DestinationHeader(const std::vector& options) : IPv6TLVOptionHeader(options) + { + m_ExtType = IPv6Destination; + } + + private: + IPv6DestinationHeader(IDataContainer* dataContainer, size_t offset) : IPv6TLVOptionHeader(dataContainer, offset) + { + m_ExtType = IPv6Destination; + } + }; + + /** + * @class IPv6RoutingHeader + * Represents IPv6 routing extension header and allows easy access to all of its data + */ + class IPv6RoutingHeader : public IPv6Extension + { + friend class IPv6Layer; + + public: + /** + * @struct ipv6_routing_header + * A struct representing the fixed part of the IPv6 routing extension header + */ + struct ipv6_routing_header + { + /** Next header type */ + uint8_t nextHeader; + /** The length of this header, in multiples of 8 octets, not including the first 8 octets */ + uint8_t headerLen; + /** A value representing the routing type */ + uint8_t routingType; + /** Number of nodes this packet still has to visit before reaching its final destination */ + uint8_t segmentsLeft; + }; + + /** + * A c'tor for creating a new IPv6 routing extension object not bounded to a packet. Useful for adding new + * extensions to an IPv6 layer with IPv6Layer#addExtension() + * @param[in] routingType Routing type value (will be written to ipv6_routing_header#routingType field) + * @param[in] segmentsLeft Segments left value (will be written to ipv6_routing_header#segmentsLeft field) + * @param[in] additionalRoutingData A pointer to a buffer containing the additional routing data for this + * extension. Notice this buffer is read-only and its content isn't modified + * @param[in] additionalRoutingDataLen The length of the additional routing data buffer + */ + IPv6RoutingHeader(uint8_t routingType, uint8_t segmentsLeft, const uint8_t* additionalRoutingData, + size_t additionalRoutingDataLen); + + /** + * Get a pointer to the fixed part of the routing header. Notice the return pointer points directly to the data, + * so every change will modify the actual packet data + * @return A pointer to the @ref ipv6_routing_header + */ + ipv6_routing_header* getRoutingHeader() const + { + return (ipv6_routing_header*)getDataPtr(); + } + + /** + * @return A pointer to the buffer containing the additional routing data for this extension. Notice that any + * change in this buffer will lead to a change in the extension data + */ + uint8_t* getRoutingAdditionalData() const; + + /** + * @return The length of the additional routing parameters buffer + */ + size_t getRoutingAdditionalDataLength() const; + + /** + * In many cases the additional routing data is actually IPv6 address(es). This method converts the raw buffer + * data into an IPv6 address + * @param[in] offset An offset in the additional routing buffer pointing to where the IPv6 address begins. In + * some cases there are multiple IPv6 addresses in the additional routing data buffer so this offset points to + * where the request IPv6 address begins. Also, even if there is only one IPv6 address in this buffer, sometimes + * it isn't written in the beginning of the buffer, so the offset points to where the IPv6 address begins. This + * is an optional parameter and the default offset is 0 + * @return The IPv6 address stored in the additional routing data buffer from the offset defined by the user. If + * offset is out-of-bounds of the extension of doesn't have 16 bytes (== the length of IPv6 address) until the + * end of the buffer - IPv6Address#Zero is returned + */ + IPv6Address getRoutingAdditionalDataAsIPv6Address(size_t offset = 0) const; + + private: + IPv6RoutingHeader(IDataContainer* dataContainer, size_t offset) : IPv6Extension(dataContainer, offset) + { + m_ExtType = IPv6Routing; + } + }; + + /** + * @class IPv6AuthenticationHeader + * Represents IPv6 authentication header extension (used in IPSec protocol) and allows easy access to all of its + * data + */ + class IPv6AuthenticationHeader : public IPv6Extension + { + friend class IPv6Layer; + + public: + /** + * @struct ipv6_authentication_header + * A struct representing the fixed part of the IPv6 authentication header extension + */ + struct ipv6_authentication_header + { + /** Next header type */ + uint8_t nextHeader; + /** The length of this Authentication Header in 4-octet units, minus 2. For example, an AH value of 4 + * equals: [ 3×(32-bit fixed-length AH fields) + 3×(32-bit ICV fields) − 2 ] and thus an AH value of 4 means + * 24 octets */ + uint8_t headerLen; + /** Reserved bytes, all zeros */ + uint16_t reserved; + /** Arbitrary value which is used (together with the destination IP address) to identify the security + * association of the receiving party */ + uint32_t securityParametersIndex; + /** A monotonic strictly increasing sequence number (incremented by 1 for every packet sent) */ + uint32_t sequenceNumber; + }; + + /** + * A c'tor for creating a new IPv6 authentication header extension object not bounded to a packet. Useful for + * adding new extensions to an IPv6 layer with IPv6Layer#addExtension() + * @param[in] securityParametersIndex Security Parameters Index (SPI) value (will be written to + * ipv6_authentication_header#securityParametersIndex field) + * @param[in] sequenceNumber Sequence number value (will be written to ipv6_authentication_header#sequenceNumber + * field) + * @param[in] integrityCheckValue A pointer to a buffer containing the integrity check value (ICV) data for this + * extension. Notice this pointer is read-only and its content isn't modified in any way + * @param[in] integrityCheckValueLen The length of the integrity check value (ICV) buffer + */ + IPv6AuthenticationHeader(uint32_t securityParametersIndex, uint32_t sequenceNumber, + const uint8_t* integrityCheckValue, size_t integrityCheckValueLen); + + /** + * Get a pointer to the fixed part of the authentication header. Notice the return pointer points directly to + * the data, so every change will modify the actual packet data + * @return A pointer to the @ref ipv6_authentication_header + */ + ipv6_authentication_header* getAuthHeader() const + { + return (ipv6_authentication_header*)getDataPtr(); + } + + /** + * @return A pointer to the buffer containing the integrity check value (ICV) for this extension. Notice that + * any change in this buffer will lead to a change in the extension data + */ + uint8_t* getIntegrityCheckValue() const; + + /** + * @return The length of the integrity check value (ICV) buffer + */ + size_t getIntegrityCheckValueLength() const; + + // overridden methods + + /** + * In the authentication header the extension length is calculated in a different way than other extensions. The + * calculation is: [ 4 * (ipv6_authentication_header#headerLen + 2) ] + * @return The length of this extension + */ + size_t getExtensionLen() const + { + return 4 * (getBaseHeader()->headerLen + 2); + } + + private: + IPv6AuthenticationHeader(IDataContainer* dataContainer, size_t offset) : IPv6Extension(dataContainer, offset) + { + m_ExtType = IPv6AuthenticationHdr; + } + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/IPv6Layer.h b/Packet++/header/pcapplusplus/IPv6Layer.h new file mode 100644 index 0000000000..b2fb8080ab --- /dev/null +++ b/Packet++/header/pcapplusplus/IPv6Layer.h @@ -0,0 +1,299 @@ +#pragma once + +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/IPLayer.h" +#include "pcapplusplus/IPv6Extensions.h" +#include "pcapplusplus/IpAddress.h" + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * @struct ip6_hdr + * Represents IPv6 protocol header + */ +#pragma pack(push, 1) + struct ip6_hdr + { +#if (BYTE_ORDER == LITTLE_ENDIAN) + /** Traffic class */ + uint8_t trafficClass : 4, + /** IP version number, has the value of 6 for IPv6 */ + ipVersion : 4; +#else + /** IP version number, has the value of 6 for IPv6 */ + uint8_t ipVersion : 4, + /** Traffic class */ + trafficClass : 4; +#endif + /** Flow label */ + uint8_t flowLabel[3]; + /** The size of the payload in octets, including any extension headers */ + uint16_t payloadLength; + /** Specifies the type of the next header (protocol). Must be one of ::IPProtocolTypes */ + uint8_t nextHeader; + /** Replaces the time to live field of IPv4 */ + uint8_t hopLimit; + /** Source address */ + uint8_t ipSrc[16]; + /** Destination address */ + uint8_t ipDst[16]; + }; +#pragma pack(pop) + + /** + * @class IPv6Layer + * Represents an IPv6 protocol layer + */ + class IPv6Layer : public Layer, public IPLayer + { + public: + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data (will be casted to @ref ip6_hdr) + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + IPv6Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + /** + * A constructor that allocates a new IPv6 header with empty fields + */ + IPv6Layer(); + + /** + * A constructor that allocates a new IPv6 header with source and destination IPv6 addresses + * @param[in] srcIP Source IPv6 address + * @param[in] dstIP Destination IPv6 address + */ + IPv6Layer(const IPv6Address& srcIP, const IPv6Address& dstIP); + + /** + * A copy constructor that copies the entire header from the other IPv6Layer (including IPv6 extensions) + */ + IPv6Layer(const IPv6Layer& other); + + /** + * A destructor for this layer + */ + ~IPv6Layer(); + + /** + * An assignment operator that first delete all data from current layer and then copy the entire header from the + * other IPv6Layer (including IPv6 extensions) + */ + IPv6Layer& operator=(const IPv6Layer& other); + + /** + * Get a pointer to the IPv6 header. Notice this points directly to the data, so every change will change the + * actual packet data + * @return A pointer to the @ref ip6_hdr + */ + ip6_hdr* getIPv6Header() const + { + return (ip6_hdr*)m_Data; + } + + /** + * Get the source IP address in the form of IPAddress. This method is very similar to getSrcIPv6Address(), + * but adds a level of abstraction because IPAddress can be used for both IPv4 and IPv6 addresses + * @return An IPAddress containing the source address + */ + IPAddress getSrcIPAddress() const + { + return getSrcIPv6Address(); + } + + /** + * Get the source IP address in the form of IPv6Address + * @return An IPv6Address containing the source address + */ + IPv6Address getSrcIPv6Address() const + { + return getIPv6Header()->ipSrc; + } + + /** + * Set the source IP address + * @param[in] ipAddr The IP address to set + */ + void setSrcIPv6Address(const IPv6Address& ipAddr) + { + ipAddr.copyTo(getIPv6Header()->ipSrc); + } + + /** + * Set the dest IP address + * @param[in] ipAddr The IP address to set + */ + void setDstIPv6Address(const IPv6Address& ipAddr) + { + ipAddr.copyTo(getIPv6Header()->ipDst); + } + + /** + * Get the destination IP address in the form of IPAddress. This method is very similar to getDstIPv6Address(), + * but adds a level of abstraction because IPAddress can be used for both IPv4 and IPv6 addresses + * @return An IPAddress containing the destination address + */ + IPAddress getDstIPAddress() const + { + return getDstIPv6Address(); + } + + /** + * Get the destination IP address in the form of IPv6Address + * @return An IPv6Address containing the destination address + */ + IPv6Address getDstIPv6Address() const + { + return getIPv6Header()->ipDst; + } + + /** + * @return Number of IPv6 extensions in this layer + */ + size_t getExtensionCount() const; + + /** + * A templated getter for an IPv6 extension of a type TIPv6Extension. TIPv6Extension has to be one of the + * supported IPv6 extensions, meaning a class that inherits IPv6Extension. If the requested extension type isn't + * found nullptr is returned + * @return A pointer to the extension instance or nullptr if the requested extension type isn't found + */ + template TIPv6Extension* getExtensionOfType() const; + + /** + * Add a new extension of type TIPv6Extension to the layer. This is a templated method and TIPv6Extension has to + * be one of the supported IPv6 extensions, meaning a class that inherits IPv6Extension. If the extension is + * added successfully a pointer to the newly added extension object is returned, otherwise nullptr is returned + * @param[in] extensionHeader The extension object to add. Notice the object passed here is read-only, meaning + * its data is copied but the object itself isn't modified + * @return If the extension is added successfully a pointer to the newly added extension object is returned. + * Otherwise nullptr is returned + */ + template TIPv6Extension* addExtension(const TIPv6Extension& extensionHeader); + + /** + * Remove all IPv6 extensions in this layer + */ + void removeAllExtensions(); + + /** + * @return True if this packet is an IPv6 fragment, meaning if it has an IPv6FragmentationHeader extension + */ + bool isFragment() const; + + /** + * The static method makes validation of input data + * @param[in] data The pointer to the beginning of byte stream of IP packet + * @param[in] dataLen The length of byte stream + * @return True if the data is valid and can represent the IPv6 packet + */ + static inline bool isDataValid(const uint8_t* data, size_t dataLen); + + // implement abstract methods + + /** + * Currently identifies the following next layers: + * - UdpLayer + * - TcpLayer + * - IPv4Layer (IP-in-IP) + * - IPv6Layer (IP-in-IP) + * - GreLayer + * - AuthenticationHeaderLayer (IPSec) + * - ESPLayer (IPSec) + * + * Otherwise sets PayloadLayer + */ + void parseNextLayer(); + + /** + * @return Size of @ref ip6_hdr + */ + size_t getHeaderLen() const + { + return sizeof(ip6_hdr) + m_ExtensionsLen; + } + + /** + * Calculate the following fields: + * - ip6_hdr#payloadLength = size of payload (all data minus header size) + * - ip6_hdr#ipVersion = 6 + * - ip6_hdr#nextHeader = calculated if next layer is known: ::PACKETPP_IPPROTO_TCP for TCP, + * ::PACKETPP_IPPROTO_UDP for UDP, ::PACKETPP_IPPROTO_ICMP for ICMP + */ + void computeCalculateFields(); + + std::string toString() const; + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelNetworkLayer; + } + + private: + void initLayer(); + void parseExtensions(); + void deleteExtensions(); + + IPv6Extension* m_FirstExtension; + IPv6Extension* m_LastExtension; + size_t m_ExtensionsLen; + }; + + template TIPv6Extension* IPv6Layer::getExtensionOfType() const + { + IPv6Extension* curExt = m_FirstExtension; + while (curExt != nullptr && dynamic_cast(curExt) == nullptr) + curExt = curExt->getNextHeader(); + + return static_cast(curExt); + } + + template TIPv6Extension* IPv6Layer::addExtension(const TIPv6Extension& extensionHeader) + { + int offsetToAddHeader = static_cast(getHeaderLen()); + if (!extendLayer(offsetToAddHeader, extensionHeader.getExtensionLen())) + { + return nullptr; + } + + TIPv6Extension* newHeader = new TIPv6Extension(this, static_cast(offsetToAddHeader)); + (*newHeader) = extensionHeader; + + if (m_FirstExtension != nullptr) + { + newHeader->getBaseHeader()->nextHeader = m_LastExtension->getBaseHeader()->nextHeader; + m_LastExtension->getBaseHeader()->nextHeader = newHeader->getExtensionType(); + m_LastExtension->setNextHeader(newHeader); + m_LastExtension = newHeader; + } + else + { + m_FirstExtension = newHeader; + m_LastExtension = newHeader; + newHeader->getBaseHeader()->nextHeader = getIPv6Header()->nextHeader; + getIPv6Header()->nextHeader = newHeader->getExtensionType(); + } + + m_ExtensionsLen += newHeader->getExtensionLen(); + + return newHeader; + } + + // implementation of inline methods + + bool IPv6Layer::isDataValid(const uint8_t* data, size_t dataLen) + { + return data && dataLen >= sizeof(ip6_hdr); + } + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/IcmpLayer.h b/Packet++/header/pcapplusplus/IcmpLayer.h new file mode 100644 index 0000000000..7bed759d6b --- /dev/null +++ b/Packet++/header/pcapplusplus/IcmpLayer.h @@ -0,0 +1,775 @@ +#pragma once + +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/IPv4Layer.h" +#ifdef _MSC_VER +# include +#else +# include +#endif +#include + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * @struct icmphdr + * Represents ICMP basic protocol header (common for all ICMP message types) + */ +#pragma pack(push, 1) + typedef struct icmphdr + { + /** message type */ + uint8_t type; + /** message code */ + uint8_t code; + /** message checksum */ + uint16_t checksum; + } icmphdr; +#pragma pack(pop) + + /** + * An enum of all supported ICMP message types + */ + enum IcmpMessageType + { + /** ICMP echo (ping) reply message */ + ICMP_ECHO_REPLY = 0, + /** ICMP destination unreachable message */ + ICMP_DEST_UNREACHABLE = 3, + /** ICMP source quench message */ + ICMP_SOURCE_QUENCH = 4, + /** ICMP redirect message */ + ICMP_REDIRECT = 5, + /** ICMP echo (ping) request message */ + ICMP_ECHO_REQUEST = 8, + /** ICMP router advertisement message */ + ICMP_ROUTER_ADV = 9, + /** ICMP router soliciatation message */ + ICMP_ROUTER_SOL = 10, + /** ICMP time-to-live excceded message */ + ICMP_TIME_EXCEEDED = 11, + /** ICMP parameter problem message */ + ICMP_PARAM_PROBLEM = 12, + /** ICMP timestamp request message */ + ICMP_TIMESTAMP_REQUEST = 13, + /** ICMP timestamp reply message */ + ICMP_TIMESTAMP_REPLY = 14, + /** ICMP information request message */ + ICMP_INFO_REQUEST = 15, + /** ICMP information reply message */ + ICMP_INFO_REPLY = 16, + /** ICMP address mask request message */ + ICMP_ADDRESS_MASK_REQUEST = 17, + /** ICMP address mask reply message */ + ICMP_ADDRESS_MASK_REPLY = 18, + /** ICMP message type unsupported by PcapPlusPlus */ + ICMP_UNSUPPORTED = 255 + }; + + /** + * An enum for all possible codes for a destination unreachable message type + * Documentation is taken from Wikipedia: https://en.wikipedia.org/wiki/Internet_Control_Message_Protocol + */ + enum IcmpDestUnreachableCodes + { + /** Network unreachable error */ + IcmpNetworkUnreachable = 0, + /** Host unreachable error */ + IcmpHostUnreachable = 1, + /** Protocol unreachable error (the designated transport protocol is not supported) */ + IcmpProtocolUnreachable = 2, + /** Port unreachable error (the designated protocol is unable to inform the host of the incoming message) */ + IcmpPortUnreachable = 3, + /** The datagram is too big. Packet fragmentation is required but the 'don't fragment' (DF) flag is on */ + IcmpDatagramTooBig = 4, + /** Source route failed error */ + IcmpSourceRouteFailed = 5, + /** Destination network unknown error */ + IcmpDestinationNetworkUnknown = 6, + /** Destination host unknown error */ + IcmpDestinationHostUnknown = 7, + /** Source host isolated error */ + IcmpSourceHostIsolated = 8, + /** The destination network is administratively prohibited */ + IcmpDestinationNetworkProhibited = 9, + /** The destination host is administratively prohibited */ + IcmpDestinationHostProhibited = 10, + /** The network is unreachable for Type Of Service */ + IcmpNetworkUnreachableForTypeOfService = 11, + /** The host is unreachable for Type Of Service */ + IcmpHostUnreachableForTypeOfService = 12, + /** Communication administratively prohibited (administrative filtering prevents + * packet from being forwarded) + */ + IcmpCommunicationProhibited = 13, + /** Host precedence violation (indicates the requested precedence is not permitted for + * the combination of host or network and port) + */ + IcmpHostPrecedenceViolation = 14, + /** Precedence cutoff in effect (precedence of datagram is below the level set by + * the network administrators) + */ + IcmpPrecedenceCutoff = 15 + }; + + /** + * @struct icmp_echo_hdr + * ICMP echo (ping) request/reply message structure + */ +#pragma pack(push, 1) + typedef struct icmp_echo_hdr : icmphdr + { + /** the echo (ping) request identifier */ + uint16_t id; + /** the echo (ping) request sequence number */ + uint16_t sequence; + /** a timestamp of when the message was sent */ + uint64_t timestamp; + } icmp_echo_hdr; +#pragma pack(pop) + + /** + * @struct icmp_echo_request + * ICMP echo (ping) request/reply message structure + */ + typedef struct icmp_echo_request + { + /** a pointer to the header data */ + icmp_echo_hdr* header; + /** most echo requests/replies contain some payload data. This is the data length */ + size_t dataLength; + /** most echo requests/replies contain some payload data. This is a pointer to this data */ + uint8_t* data; + } icmp_echo_request; + + /** + * @typedef icmp_echo_reply + * ICMP echo (ping) reply message structure, same as icmp_echo_request + */ + typedef icmp_echo_request icmp_echo_reply; + + /** + * @struct icmp_timestamp_request + * ICMP timestamp request message structure + */ +#pragma pack(push, 1) + typedef struct icmp_timestamp_request : icmphdr + { + /** the timestamp request identifier */ + uint16_t id; + /** the timestamp request sequence number */ + uint16_t sequence; + /** the time (in milliseconds since midnight) the sender last touched the packet */ + uint32_t originateTimestamp; + /** relevant for timestamp reply only - the time the echoer first touched it on receipt */ + uint32_t receiveTimestamp; + /** relevant for timestamp reply only - the time the echoer last touched the message on sending it */ + uint32_t transmitTimestamp; + } icmp_timestamp_request; +#pragma pack(pop) + + /** + * @typedef icmp_timestamp_reply + * ICMP timestamp reply message structure, same as icmp_timestamp_request + */ + typedef icmp_timestamp_request icmp_timestamp_reply; + + /** + * @struct icmp_destination_unreachable + * ICMP destination unreachable message structure + */ +#pragma pack(push, 1) + typedef struct icmp_destination_unreachable : icmphdr + { + /** unused 2 bytes */ + uint16_t unused; + /** contains the MTU of the next-hop network if a code 4 error occurs */ + uint16_t nextHopMTU; + } icmp_destination_unreachable; +#pragma pack(pop) + + /** + * @struct icmp_time_exceeded + * ICMP time-to-live exceeded message structure + */ +#pragma pack(push, 1) + typedef struct icmp_time_exceeded : icmphdr + { + /** unused 4 bytes */ + uint32_t unused; + } icmp_time_exceeded; +#pragma pack(pop) + + /** + * @typedef icmp_source_quench + * ICMP source quence message structure, same as icmp_time_exceeded + */ + typedef icmp_time_exceeded icmp_source_quench; + + /** + * @struct icmp_param_problem + * ICMP parameter problem message structure + */ +#pragma pack(push, 1) + typedef struct icmp_param_problem : icmphdr + { + /** in the case of an invalid IP header (Code 0), this field indicates the byte offset of the error in the + * header */ + uint8_t pointer; + /** unused 1 byte */ + uint8_t unused1; + /** unused 2 bytes */ + uint16_t unused2; + } icmp_param_problem; +#pragma pack(pop) + + /** + * @typedef icmp_router_solicitation + * ICMP router solicitation message structure, same as icmphdr + */ + typedef icmphdr icmp_router_solicitation; + + /** + * @struct icmp_redirect + * ICMP redirect message structure + */ +#pragma pack(push, 1) + typedef struct icmp_redirect : icmphdr + { + /** an IPv4 address of the gateway to which the redirection should be sent */ + uint32_t gatewayAddress; + } icmp_redirect; +#pragma pack(pop) + + /** + * @struct icmp_router_address_structure + * Router address structure, relevant for ICMP router advertisement message type (icmp_router_advertisement) + */ +#pragma pack(push, 1) + struct icmp_router_address_structure + { + /** the IPv4 address of the advertised router */ + uint32_t routerAddress; + /** The preferability of the router address as a default router address, relative to other router addresses + * on the same subnet. This is a twos-complement value where higher values indicate that the route is + * more preferable */ + uint32_t preferenceLevel; + + /** + * Set router address structure from a given IPv4 address and preference level + * @param[in] addr IPv4 address to set + * @param[in] preference Preference level to set + */ + void setRouterAddress(IPv4Address addr, uint32_t preference); + + /** + * @return The IPv4 address extracted from icmp_router_address_structure#routerAddress field + */ + IPv4Address getAddress() const + { + return routerAddress; + } + }; +#pragma pack(pop) + + /** + * @struct icmp_router_advertisement_hdr + * ICMP router advertisement message structure + */ +#pragma pack(push, 1) + typedef struct icmp_router_advertisement_hdr : icmphdr + { + /** the number of router advertisements in this message. Each advertisement contains one router + * address/preference level pair */ + uint8_t advertisementCount; + /** the number of 32-bit words of information for each router address entry in the list. The value is normally + * set to 2 (router address + preference level) */ + uint8_t addressEntrySize; + /** the maximum number of seconds that the router addresses in this list may be considered valid */ + uint16_t lifetime; + } icmp_router_advertisement_hdr; +#pragma pack(pop) + + /** + * @struct icmp_router_advertisement + * ICMP router advertisement message structure + */ + struct icmp_router_advertisement + { + /** a pointer to the header data on the packet */ + icmp_router_advertisement_hdr* header; + + /** + * Extract router advertisement at a given index + * @param[in] index The index of the router advertisement + * @return A pointer to the router advertisement on the packet or null if index is out of range (less than zero + * or greater than the number of router advertisement records on this message, determined by advertisementCount + * field) + */ + icmp_router_address_structure* getRouterAddress(int index) const; + }; + + /** + * @struct icmp_address_mask_request + * ICMP address mask request message structure + */ +#pragma pack(push, 1) + typedef struct icmp_address_mask_request : icmphdr + { + /** the address mask request identifier */ + uint16_t id; + /** the address mask request sequence */ + uint16_t sequence; + /** the subnet mask of the requesting host */ + uint32_t addressMask; + } icmp_address_mask_request; +#pragma pack(pop) + + /** + * @typedef icmp_address_mask_reply + * ICMP address mask reply message structure, same as icmp_address_mask_request + */ + typedef icmp_address_mask_request icmp_address_mask_reply; + + /** + * @struct icmp_info_request + * ICMP information request message structure + */ +#pragma pack(push, 1) + typedef struct icmp_info_request : icmphdr + { + /** the information request identifier */ + uint16_t id; + /** the information request sequence */ + uint16_t sequence; + } icmp_info_request; +#pragma pack(pop) + + /** + * @typedef icmp_info_reply + * ICMP information reply message structure, same as icmp_info_request + */ + typedef icmp_info_request icmp_info_reply; + + /** + * @class IcmpLayer + * Represents an ICMP protocol layer (for IPv4 only) + */ + class IcmpLayer : public Layer + { + private: + icmp_echo_request m_EchoData; + mutable icmp_router_advertisement m_RouterAdvData; + + bool cleanIcmpLayer(); + + bool setEchoData(IcmpMessageType echoType, uint16_t id, uint16_t sequence, uint64_t timestamp, + const uint8_t* data, size_t dataLen); + + bool setIpAndL4Layers(IPv4Layer* ipLayer, Layer* l4Layer); + + public: + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data (will be casted to @ref arphdr) + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + // cppcheck-suppress uninitMemberVar + IcmpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : Layer(data, dataLen, prevLayer, packet, ICMP) + {} + + /** + * An empty constructor that creates a new layer with an empty ICMP header without setting the ICMP type or ICMP + * data. Call the set*Data() methods to set ICMP type and data + */ + IcmpLayer(); + + virtual ~IcmpLayer() + {} + + /** + * Get a pointer to the basic ICMP header. Notice this points directly to the data, so every change will change + * the actual packet data + * @return A pointer to the @ref icmphdr + */ + icmphdr* getIcmpHeader() const + { + return (icmphdr*)m_Data; + } + + /** + * @return The ICMP message type + */ + IcmpMessageType getMessageType() const; + + /** + * @param[in] type Type to check + * @return True if the layer if of the given type, false otherwise + */ + bool isMessageOfType(IcmpMessageType type) const + { + return getMessageType() == type; + } + + /** + * @return ICMP echo (ping) request data. If the layer isn't of type ICMP echo request nullptr is returned + */ + icmp_echo_request* getEchoRequestData(); + + /** + * Set echo (ping) request message data + * @param[in] id Echo (ping) request identifier + * @param[in] sequence Echo (ping) request sequence + * @param[in] timestamp Echo (ping) request timestamp + * @param[in] data A pointer to echo (ping) request payload to set + * @param[in] dataLen The length of the echo (ping) request payload + * @return A pointer to the echo (ping) request data that have been set or nullptr if something went wrong + * (an appropriate error log is printed in such cases) + */ + icmp_echo_request* setEchoRequestData(uint16_t id, uint16_t sequence, uint64_t timestamp, const uint8_t* data, + size_t dataLen); + + /** + * @return ICMP echo reply data. If the layer isn't of type ICMP echo reply nullptr is returned + */ + icmp_echo_reply* getEchoReplyData(); + + /** + * Set echo (ping) reply message data + * @param[in] id Echo (ping) reply identifier + * @param[in] sequence Echo (ping) reply sequence + * @param[in] timestamp Echo (ping) reply timestamp + * @param[in] data A pointer to echo (ping) reply payload to set + * @param[in] dataLen The length of the echo (ping) reply payload + * @return A pointer to the echo (ping) reply data that have been set or nullptr if something went wrong + * (an appropriate error log is printed in such cases) + */ + icmp_echo_reply* setEchoReplyData(uint16_t id, uint16_t sequence, uint64_t timestamp, const uint8_t* data, + size_t dataLen); + + /** + * @return ICMP timestamp request data. If the layer isn't of type ICMP timestamp request nullptr is returned + */ + icmp_timestamp_request* getTimestampRequestData(); + + /** + * Set timestamp request message data + * @param[in] id Timestamp request identifier + * @param[in] sequence Timestamp request sequence + * @param[in] originateTimestamp Time (in milliseconds since midnight) the sender last touched the packet + * @return A pointer to the timestamp request data that have been set or nullptr if something went wrong + * (an appropriate error log is printed in such cases) + */ + icmp_timestamp_request* setTimestampRequestData(uint16_t id, uint16_t sequence, timeval originateTimestamp); + + /** + * @return ICMP timestamp reply data. If the layer isn't of type ICMP timestamp reply nullptr is returned + */ + icmp_timestamp_reply* getTimestampReplyData(); + + /** + * Set timestamp reply message data + * @param[in] id Timestamp reply identifier + * @param[in] sequence Timestamp reply sequence + * @param[in] originateTimestamp Time (in milliseconds since midnight) the sender last touched the packet + * @param[in] receiveTimestamp The time the echoer first touched it on receipt + * @param[in] transmitTimestamp The time the echoer last touched the message on sending it + * @return A pointer to the timestamp reply data that have been set or nullptr if something went wrong + * (an appropriate error log is printed in such cases) + */ + icmp_timestamp_reply* setTimestampReplyData(uint16_t id, uint16_t sequence, timeval originateTimestamp, + timeval receiveTimestamp, timeval transmitTimestamp); + + /** + * @return ICMP destination unreachable data. If the layer isn't of type ICMP destination unreachable nullptr is + * returned. The IP and L4 (ICMP/TCP/UDP) headers of the destination unreachable data are parsed as separate + * layers and can be retrieved via this->getNextLayer() + */ + icmp_destination_unreachable* getDestUnreachableData(); + + /** + * Set destination unreachable message data. This method only works if IcmpLayer is already part of a packet + * (not a standalone layer). The reason is the Internet and L4 headers given as parameters are added as separate + * layers and need a packet to be added to + * @param[in] code Destination unreachable code + * @param[in] nextHopMTU The MTU of the next-hop network if a code 4 error occurs + * @param[in] ipHeader The Internet header of the original data. This layer is added as a separate layer on the + * packet + * @param[in] l4Header The L4 header of the original data. This layer is added as a separate layer on the packet + * @return A pointer to the destination unreachable data that have been set or nullptr if something went wrong + * (an appropriate error log is printed in such cases) + */ + icmp_destination_unreachable* setDestUnreachableData(IcmpDestUnreachableCodes code, uint16_t nextHopMTU, + IPv4Layer* ipHeader, Layer* l4Header); + + /** + * @return ICMP source quench data. If the layer isn't of type ICMP source quench nullptr is returned. + * The IP and L4 (ICMP/TCP/UDP) headers of the source quench data are parsed as separate layers and can be + * retrieved via this->getNextLayer() + */ + icmp_source_quench* getSourceQuenchdata(); + + /** + * Set source quench message data. This method only works if IcmpLayer is already part of a packet (not + * a standalone layer). The reason is the Internet and L4 headers given as parameters are added as separate + * layers and need a packet to be added to + * @param[in] ipHeader The Internet header of the original data. This layer is added as a separate layer on the + * packet + * @param[in] l4Header The L4 header of the original data. This layer is added as a separate layer on the packet + * @return A pointer to the source quench data that have been set or nullptr if something went wrong + * (an appropriate error log is printed in such cases) + */ + icmp_source_quench* setSourceQuenchdata(IPv4Layer* ipHeader, Layer* l4Header); + + /** + * @return ICMP redirect data. If the layer isn't of type ICMP redirect nullptr is returned. + * The IP and L4 (ICMP/TCP/UDP) headers of the redirect data are parsed as separate layers and can be + * retrieved via this->getNextLayer() + */ + icmp_redirect* getRedirectData(); + + /** + * Set redirect message data. This method only works if IcmpLayer is already part of a packet (not + * a standalone layer). The reason is the Internet and L4 headers given as parameters are added as separate + * layers and need a packet to be added to + * @param[in] code The redirect message code. Only values between 0 and 3 are legal, the rest will cause the + * method to fail + * @param[in] gatewayAddress An IPv4 address of the gateway to which the redirection should be sent + * @param[in] ipHeader The Internet header of the original data. This layer is added as a separate layer on the + * packet + * @param[in] l4Header The L4 header of the original data. This layer is added as a separate layer on the packet + * @return A pointer to the redirect data that have been set or nullptr if something went wrong + * (an appropriate error log is printed in such cases) + */ + icmp_redirect* setRedirectData(uint8_t code, IPv4Address gatewayAddress, IPv4Layer* ipHeader, Layer* l4Header); + + /** + * @return ICMP router advertisement data. If the layer isn't of type ICMP router advertisement nullptr is + * returned + */ + icmp_router_advertisement* getRouterAdvertisementData() const; + + /** + * Set router advertisement message data + * @param[in] code The router advertisement message code. Only codes 0 or 16 are legal, the rest will fail the + * method + * @param[in] lifetimeInSeconds The maximum number of seconds that the router addresses in this list may be + * considered valid + * @param[in] routerAddresses A vector of router advertisements to set + * @return A pointer to the router advertisement data that have been set or nullptr if something went wrong + * (an appropriate error log is printed in such cases) + */ + icmp_router_advertisement* setRouterAdvertisementData( + uint8_t code, uint16_t lifetimeInSeconds, + const std::vector& routerAddresses); + + /** + * @return ICMP router solicitation data. If the layer isn't of type ICMP router solicitation nullptr is + * returned + */ + icmp_router_solicitation* getRouterSolicitationData(); + + /** + * Set router solicitation message data. This message accepts no parameters as there are no parameters to this + * type of message (code is always zero) + * @return A pointer to the router solicitation data that have been set or nullptr if something went wrong + * (an appropriate error log is printed in such cases) + */ + icmp_router_solicitation* setRouterSolicitationData(); + + /** + * @return ICMP time-to-live exceeded data. If the layer isn't of type ICMP time-to-live exceeded nullptr is + * returned. The IP and L4 (ICMP/TCP/UDP) headers of the time exceeded data are parsed as separate layers and + * can be retrieved via this->getNextLayer() + */ + icmp_time_exceeded* getTimeExceededData(); + + /** + * Set time-to-live exceeded message data. This method only works if IcmpLayer is already part of a packet (not + * a standalone layer). The reason is the Internet and L4 headers given as parameters are added as separate + * layers and need a packet to be added to + * @param[in] code Time-to-live exceeded message code. Only codes 0 or 1 are legal, the rest will fail the + * method + * @param[in] ipHeader The Internet header of the original data. This layer is added as a separate layer on the + * packet + * @param[in] l4Header The L4 header of the original data. This layer is added as a separate layer on the packet + * @return A pointer to the time-to-live exceeded data that have been set or nullptr if something went wrong + * (an appropriate error log is printed in such cases) + */ + icmp_time_exceeded* setTimeExceededData(uint8_t code, IPv4Layer* ipHeader, Layer* l4Header); + + /** + * @return ICMP parameter problem data. If the layer isn't of type ICMP parameter problem nullptr is returned + */ + icmp_param_problem* getParamProblemData(); + + /** + * Set parameter problem message data. This method only works if IcmpLayer is already part of a packet (not + * a standalone layer). The reason is the Internet and L4 headers given as parameters are added as separate + * layers and need a packet to be added to + * @param[in] code Parameter problem message code. Only code between 0 and 2 are legal, the rest will fail the + * method + * @param[in] errorOctetPointer In the case of an invalid IP header (Code 0), indicate the byte offset of the + * error in the header + * @param[in] ipHeader The Internet header of the original data. This layer is added as a separate layer on the + * packet + * @param[in] l4Header The L4 header of the original data. This layer is added as a separate layer on the packet + * @return A pointer to the parameter problem data that have been set or nullptr if something went wrong + * (an appropriate error log is printed in such cases) + */ + icmp_param_problem* setParamProblemData(uint8_t code, uint8_t errorOctetPointer, IPv4Layer* ipHeader, + Layer* l4Header); + + /** + * @return ICMP address mask request data. If the layer isn't of type ICMP address mask request nullptr is + * returned + */ + icmp_address_mask_request* getAddressMaskRequestData(); + + /** + * Set address mask request message data + * @param[in] id Address mask request identifier + * @param[in] sequence Address mask request sequence + * @param[in] mask The subnet mask of the requesting host + * @return A pointer to the address mask request data that have been set or nullptr if something went wrong + * (an appropriate error log is printed in such cases) + */ + icmp_address_mask_request* setAddressMaskRequestData(uint16_t id, uint16_t sequence, IPv4Address mask); + + /** + * @return ICMP address mask reply data. If the layer isn't of type ICMP address mask reply nullptr is returned + */ + icmp_address_mask_reply* getAddressMaskReplyData(); + + /** + * Set address mask reply message data + * @param[in] id Address mask reply identifier + * @param[in] sequence Address mask reply sequence + * @param[in] mask The subnet mask of the requesting host + * @return A pointer to the address mask reply data that have been set or nullptr if something went wrong + * (an appropriate error log is printed in such cases) + */ + icmp_address_mask_reply* setAddressMaskReplyData(uint16_t id, uint16_t sequence, IPv4Address mask); + + /** + * @return ICMP address information request data. If the layer isn't of type ICMP information request nullptr is + * returned + */ + icmp_info_request* getInfoRequestData(); + + /** + * Set information request message data + * @param[in] id Information request identifier + * @param[in] sequence Information request sequence + * @return A pointer to the information request data that have been set or nullptr if something went wrong + * (an appropriate error log is printed in such cases) + */ + icmp_info_request* setInfoRequestData(uint16_t id, uint16_t sequence); + + /** + * @return ICMP address information reply data. If the layer isn't of type ICMP information reply nullptr is + * returned + */ + icmp_info_reply* getInfoReplyData(); + + /** + * Set information reply message data + * @param[in] id Information reply identifier + * @param[in] sequence Information reply sequence + * @return A pointer to the information reply data that have been set or nullptr if something went wrong + * (an appropriate error log is printed in such cases) + */ + icmp_info_reply* setInfoReplyData(uint16_t id, uint16_t sequence); + + /** + * The static method makes validation of input data + * @param[in] data The pointer to the beginning of byte stream of ICMP packet + * @param[in] dataLen The length of byte stream + * @return True if the data is valid and can represent an ICMP packet + */ + static inline bool isDataValid(const uint8_t* data, size_t dataLen); + + // implement abstract methods + + /** + * ICMP messages of types: ICMP_DEST_UNREACHABLE, ICMP_SOURCE_QUENCH, ICMP_TIME_EXCEEDED, ICMP_REDIRECT, + * ICMP_PARAM_PROBLEM have data that contains IPv4 header and some L4 header (TCP/UDP/ICMP). This method parses + * these headers as separate layers on top of the ICMP layer + */ + void parseNextLayer(); + + /** + * @return The ICMP header length. This length varies according to the ICMP message type. This length doesn't + * include IPv4 and L4 headers in case ICMP message type are: ICMP_DEST_UNREACHABLE, ICMP_SOURCE_QUENCH, + * ICMP_TIME_EXCEEDED, ICMP_REDIRECT, ICMP_PARAM_PROBLEM + */ + size_t getHeaderLen() const; + + /** + * Calculate ICMP checksum field + */ + void computeCalculateFields(); + + std::string toString() const; + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelNetworkLayer; + } + }; + + // implementation of inline methods + + bool IcmpLayer::isDataValid(const uint8_t* data, size_t dataLen) + { + if (dataLen < sizeof(icmphdr)) + return false; + + uint8_t type = data[0]; + + // ICMP_ECHO_REQUEST, ICMP_ECHO_REPLY, ICMP_ROUTER_SOL, ICMP_INFO_REQUEST, ICMP_INFO_REPLY + if (type == 8 || type == 0 || type == 10 || type == 15 || type == 16) + return true; + + // ICMP_TIMESTAMP_REQUEST, ICMP_TIMESTAMP_REPLY + if (type == 13 || type == 14) + return dataLen >= sizeof(icmp_timestamp_request); + + // ICMP_ADDRESS_MASK_REPLY, ICMP_ADDRESS_MASK_REQUEST + if (type == 17 || type == 18) + return dataLen >= sizeof(icmp_address_mask_request); + + // ICMP_DEST_UNREACHABLE + if (type == 3) + return dataLen >= sizeof(icmp_destination_unreachable); + + // ICMP_REDIRECT + if (type == 5) + return dataLen >= sizeof(icmp_redirect); + + // ICMP_TIME_EXCEEDED, ICMP_SOURCE_QUENCH + if (type == 4 || type == 11) + return dataLen >= sizeof(icmp_time_exceeded); + + // ICMP_PARAM_PROBLEM + if (type == 12) + return dataLen >= sizeof(icmp_param_problem); + + // ICMP_ROUTER_ADV + if (type == 9) + return dataLen >= sizeof(icmp_router_advertisement_hdr); + + return false; + } + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/IcmpV6Layer.h b/Packet++/header/pcapplusplus/IcmpV6Layer.h new file mode 100644 index 0000000000..ffa8d6416c --- /dev/null +++ b/Packet++/header/pcapplusplus/IcmpV6Layer.h @@ -0,0 +1,306 @@ +#pragma once + +#include "pcapplusplus/Layer.h" + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * An enum representing the available ICMPv6 message types + */ + enum class ICMPv6MessageType : int + { + /** Unknown ICMPv6 message */ + ICMPv6_UNKNOWN_MESSAGE = 0, + /** Destination Unreachable Message */ + ICMPv6_DESTINATION_UNREACHABLE = 1, + /** Packet Too Big Message */ + ICMPv6_PACKET_TOO_BIG = 2, + /** Time Exceeded Message */ + ICMPv6_TIME_EXCEEDED = 3, + /** Parameter Problem Message */ + ICMPv6_PARAMETER_PROBLEM = 4, + /** Private Experimentation Message */ + ICMPv6_PRIVATE_EXPERIMENTATION1 = 100, + /** Private Experimentation Message */ + ICMPv6_PRIVATE_EXPERIMENTATION2 = 101, + /** Reserved for expansion of ICMPv6 error messages */ + ICMPv6_RESERVED_EXPANSION_ERROR = 127, + /** Echo Request Message */ + ICMPv6_ECHO_REQUEST = 128, + /** Echo Reply Message */ + ICMPv6_ECHO_REPLY = 129, + /** Multicast Listener Query Message */ + ICMPv6_MULTICAST_LISTENER_QUERY = 130, + /** Multicast Listener Report Message */ + ICMPv6_MULTICAST_LISTENER_REPORT = 131, + /** Multicast Listener Done Message */ + ICMPv6_MULTICAST_LISTENER_DONE = 132, + /** Router Solicitation Message */ + ICMPv6_ROUTER_SOLICITATION = 133, + /** Router Advertisement Message */ + ICMPv6_ROUTER_ADVERTISEMENT = 134, + /** Neighbor Solicitation Message */ + ICMPv6_NEIGHBOR_SOLICITATION = 135, + /** Neighbor Advertisement Message */ + ICMPv6_NEIGHBOR_ADVERTISEMENT = 136, + /** Redirect Message */ + ICMPv6_REDIRECT_MESSAGE = 137, + /** Router Renumbering Message */ + ICMPv6_ROUTER_RENUMBERING = 138, + /** Node Information Query Message */ + ICMPv6_ICMP_NODE_INFORMATION_QUERY = 139, + /** Node Information Reply Message*/ + ICMPv6_ICMP_NODE_INFORMATION_RESPONSE = 140, + /** Inverse Neighbor Discovery Solicitation Message */ + ICMPv6_INVERSE_NEIGHBOR_DISCOVERY_SOLICITATION_MESSAGE = 141, + /** Inverse Neighbor Discovery Advertisement Message */ + ICMPv6_INVERSE_NEIGHBOR_DISCOVERY_ADVERTISEMENT_MESSAGE = 142, + /** Multicast Listener Report Message */ + ICMPv6_MULTICAST_LISTENER_DISCOVERY_REPORTS = 143, + /** Home Agent Address Discovery Request Message */ + ICMPv6_HOME_AGENT_ADDRESS_DISCOVERY_REQUEST_MESSAGE = 144, + /** Home Agent Address Discovery Reply Message */ + ICMPv6_HOME_AGENT_ADDRESS_DISCOVERY_REPLY_MESSAGE = 145, + /** Mobile Prefix Solicitation Message */ + ICMPv6_MOBILE_PREFIX_SOLICITATION = 146, + /** Mobile Prefix Advertisement Message */ + ICMPv6_MOBILE_PREFIX_ADVERTISEMENT = 147, + /** Certification Path Solicitation Message */ + ICMPv6_CERTIFICATION_PATH_SOLICITATION = 148, + /** Certification Path Advertisement Message */ + ICMPv6_CERTIFICATION_PATH_ADVERTISEMENT = 149, + /** ICMP Experimental Mobility Subtype Format and Registry Message */ + ICMPv6_EXPERIMENTAL_MOBILITY = 150, + /** Multicast Router Advertisement Message */ + ICMPv6_MULTICAST_ROUTER_ADVERTISEMENT = 151, + /** Multicast Router Solicitation Message */ + ICMPv6_MULTICAST_ROUTER_SOLICITATION = 152, + /** Multicast Router Termination Message*/ + ICMPv6_MULTICAST_ROUTER_TERMINATION = 153, + /** RPL Control Message */ + ICMPv6_RPL_CONTROL_MESSAGE = 155, + /** Private Experimentation Message */ + ICMPv6_PRIVATE_EXPERIMENTATION3 = 200, + /** Private Experimentation Message */ + ICMPv6_PRIVATE_EXPERIMENTATION4 = 201, + /** Reserved for expansion of ICMPv6 informational messages */ + ICMPv6_RESERVED_EXPANSION_INFORMATIONAL = 255 + }; + +/** + * @struct icmpv6hdr + * Represents an ICMPv6 protocol header + */ +#pragma pack(push, 1) + struct icmpv6hdr + { + /** Type of the message. Values in the range from 0 to 127 (high-order bit is 0) indicate an error message, + while values in the range from 128 to 255 (high-order bit is 1) indicate an information message. */ + uint8_t type; + /** The code field value depends on the message type and provides an additional level of message granularity */ + uint8_t code; + /** The checksum field provides a minimal level of integrity verification for the ICMP message */ + uint16_t checksum; + }; +#pragma pack(pop) + +/** + * @struct icmpv6_echo_hdr + * ICMP echo request/reply message structure + */ +#pragma pack(push, 1) + typedef struct icmpv6_echo_hdr : icmpv6hdr + { + /** the echo request identifier */ + uint16_t id; + /** the echo request sequence number */ + uint16_t sequence; + } icmpv6_echo_hdr; +#pragma pack(pop) + + /** + * @class IcmpV6Layer + * Base class for ICMPv6 protocol layers which provides common logic for ICMPv6 messages. + */ + class IcmpV6Layer : public Layer + { + public: + /** + * A constructor that creates the layer from an existing packet raw data + * @param data A pointer to the raw data + * @param dataLen Size of the data in bytes + * @param prevLayer A pointer to the previous layer + * @param packet A pointer to the Packet instance where layer will be stored in + */ + IcmpV6Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : Layer(data, dataLen, prevLayer, packet, ICMPv6) + {} + + /** + * A constructor that allocates a new ICMPv6 layer with type, code and data + * @param[in] msgType Message type of the ICMPv6 layer + * @param[in] code Code field of the ICMPv6 layer + * @param[in] data A pointer to the payload to set + * @param[in] dataLen The length of the payload + */ + IcmpV6Layer(ICMPv6MessageType msgType, uint8_t code, const uint8_t* data, size_t dataLen); + + virtual ~IcmpV6Layer() + {} + + /** + * A static method that creates an ICMPv6 layer from packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored + * @return Layer* A newly allocated ICMPv6 layer + */ + static Layer* parseIcmpV6Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + /** + * @param[in] type Type to check + * @return True if the layer if of the given type, false otherwise + */ + bool isMessageOfType(ICMPv6MessageType type) const + { + return getMessageType() == type; + } + + /** + * @return Get the ICMPv6 Message Type + */ + ICMPv6MessageType getMessageType() const; + + /** + * @return Get the code header field + */ + uint8_t getCode() const; + + /** + * @return Get the checksum header field in host representation + */ + uint16_t getChecksum() const; + + /** + * Does nothing for this layer. ICMPv6 is the last layer. + */ + void parseNextLayer() + {} + + /** + * @return The size of the ICMPv6 message + */ + size_t getHeaderLen() const + { + return m_DataLen; + } + + /** + * Calculate ICMPv6 checksum field + */ + void computeCalculateFields(); + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelNetworkLayer; + } + + std::string toString() const; + + protected: + IcmpV6Layer() = default; + + private: + void calculateChecksum(); + icmpv6hdr* getIcmpv6Header() const + { + return (icmpv6hdr*)m_Data; + } + }; + + /** + * @class ICMPv6EchoLayer + * Represents an ICMPv6 echo request/reply protocol layer + */ + class ICMPv6EchoLayer : public IcmpV6Layer + { + public: + /** + * An enum representing ICMPv6 echo message types + */ + enum ICMPv6EchoType + { + /** Echo Request Type */ + REQUEST, + /** Echo Reply Type */ + REPLY + }; + + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + ICMPv6EchoLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : IcmpV6Layer(data, dataLen, prevLayer, packet) + {} + + /** + * A constructor for a new echo request/reply layer + * @param[in] echoType The type of the echo message + * @param[in] id Echo request identifier + * @param[in] sequence Echo request sequence number + * @param[in] data A pointer to echo request payload to set + * @param[in] dataLen The length of the echo request payload + */ + ICMPv6EchoLayer(ICMPv6EchoType echoType, uint16_t id, uint16_t sequence, const uint8_t* data, size_t dataLen); + + virtual ~ICMPv6EchoLayer() + {} + + /** + * @return Identifier in host representation + */ + uint16_t getIdentifier() const; + + /** + * @return Sequence number in host representation + */ + uint16_t getSequenceNr() const; + + /** + * @return Size of the data in bytes + */ + size_t getEchoDataLen() const + { + return m_DataLen - sizeof(icmpv6_echo_hdr); + } + + /** + * @return Pointer to the beginning of the data + */ + uint8_t* getEchoDataPtr() const + { + return m_Data + sizeof(icmpv6_echo_hdr); + } + + std::string toString() const; + + private: + icmpv6_echo_hdr* getEchoHeader() const + { + return (icmpv6_echo_hdr*)m_Data; + } + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/IgmpLayer.h b/Packet++/header/pcapplusplus/IgmpLayer.h new file mode 100644 index 0000000000..20f7c7bf52 --- /dev/null +++ b/Packet++/header/pcapplusplus/IgmpLayer.h @@ -0,0 +1,554 @@ +#pragma once + +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/IpAddress.h" +#include + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * @struct igmp_header + * IGMPv1 and IGMPv2 basic protocol header + */ + struct igmp_header + { + /** Indicates the message type. The enum for message type is pcpp::IgmpType */ + uint8_t type; + /** Specifies the time limit for the corresponding report. The field has a resolution of 100 milliseconds */ + uint8_t maxResponseTime; + /** This is the 16-bit one's complement of the one's complement sum of the entire IGMP message */ + uint16_t checksum; + /** This is the multicast address being queried when sending a Group-Specific or Group-and-Source-Specific Query + */ + uint32_t groupAddress; + }; + + /** + * @struct igmpv3_query_header + * IGMPv3 membership query basic header + */ + struct igmpv3_query_header + { + /** IGMP message type. Should always have value of membership query (::IgmpType_MembershipQuery) */ + uint8_t type; + /** This field specifies the maximum time (in 1/10 second) allowed before sending a responding report */ + uint8_t maxResponseTime; + /** This is the 16-bit one's complement of the one's complement sum of the entire IGMP message */ + uint16_t checksum; + /** This is the multicast address being queried when sending a Group-Specific or Group-and-Source-Specific Query + */ + uint32_t groupAddress; + /** Suppress Router-side Processing Flag + Querier's Robustness Variable */ + uint8_t s_qrv; + /** Querier's Query Interval Code */ + uint8_t qqic; + /** This field specifies the number of source addresses present in the Query */ + uint16_t numOfSources; + }; + + /** + * @struct igmpv3_report_header + * IGMPv3 membership report basic header + */ + struct igmpv3_report_header + { + /** IGMP message type. Should always have value of IGMPv3 membership report (::IgmpType_MembershipReportV3) */ + uint8_t type; + /** Unused byte */ + uint8_t reserved1; + /** This is the 16-bit one's complement of the one's complement sum of the entire IGMP message */ + uint16_t checksum; + /** Unused bytes */ + uint16_t reserved2; + /** This field specifies the number of group records present in the Report */ + uint16_t numOfGroupRecords; + }; + + /** + * @struct igmpv3_group_record + * A block of fields containing information pertaining to the sender's membership in a single multicast group on the + * interface from which the Report is sent. Relevant only for IGMPv3 membership report messages + */ + struct igmpv3_group_record + { + /** Group record type */ + uint8_t recordType; + /** Contains the length of the Auxiliary Data field in this Group Record. A value other than 0 isn't supported + */ + uint8_t auxDataLen; + /** Specifies how many source addresses are present in this Group Record */ + uint16_t numOfSources; + /** Contains the IP multicast address to which this Group Record pertains */ + uint32_t multicastAddress; + /** A vector of n IP unicast addresses, where n is the value in this record's Number of Sources field */ + uint8_t sourceAddresses[]; + + /** + * @return The multicast address in igmpv3_group_record#multicastAddress as IPv4Address instance + */ + IPv4Address getMulticastAddress() const + { + return multicastAddress; + } + + /** + * @return The number of source addresses in this group record + */ + uint16_t getSourceAddressCount() const; + + /** + * Get the source address at a certain index + * @param[in] index The index of the source address in the group record + * @return The source address in the requested index. If index is negative or higher than the number of source + * addresses in this group record the value if IPv4Address#Zero is returned + */ + IPv4Address getSourceAddressAtIndex(int index) const; + + /** + * @return The total size in bytes of the group record + */ + size_t getRecordLen() const; + }; + + /** + * IGMP message types + */ + enum IgmpType + { + /** Unknown message type */ + IgmpType_Unknown = 0, + /** IGMP Membership Query */ + IgmpType_MembershipQuery = 0x11, + /** IGMPv1 Membership Report */ + IgmpType_MembershipReportV1 = 0x12, + /** DVMRP */ + IgmpType_DVMRP = 0x13, + /** PIM version 1 */ + IgmpType_P1Mv1 = 0x14, + /** Cisco Trace Messages */ + IgmpType_CiscoTrace = 0x15, + /** IGMPv2 Membership Report */ + IgmpType_MembershipReportV2 = 0x16, + /** IGMPv2 Leave Group */ + IgmpType_LeaveGroup = 0x17, + /** Multicast Traceroute Response */ + IgmpType_MulticastTracerouteResponse = 0x1e, + /** Multicast Traceroute */ + IgmpType_MulticastTraceroute = 0x1f, + /** IGMPv3 Membership Report */ + IgmpType_MembershipReportV3 = 0x22, + /** MRD, Multicast Router Advertisement */ + IgmpType_MulticastRouterAdvertisement = 0x30, + /** MRD, Multicast Router Solicitation */ + IgmpType_MulticastRouterSolicitation = 0x31, + /** MRD, Multicast Router Termination */ + IgmpType_MulticastRouterTermination = 0x32, + }; + + /** + * @class IgmpLayer + * A base class for all IGMP (Internet Group Management Protocol) protocol classes. This is an abstract class and + * cannot be instantiated, only its child classes can be instantiated. The inherited classes represent the different + * versions of the protocol: IGMPv1, IGMPv2 and IGMPv3 + */ + class IgmpLayer : public Layer + { + protected: + IgmpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, ProtocolType igmpVer) + : Layer(data, dataLen, prevLayer, packet, igmpVer) + {} + + IgmpLayer(IgmpType type, const IPv4Address& groupAddr, uint8_t maxResponseTime, ProtocolType igmpVer); + + uint16_t calculateChecksum(); + + size_t getHeaderSizeByVerAndType(ProtocolType igmpVer, IgmpType igmpType) const; + + public: + virtual ~IgmpLayer() + {} + + /** + * Get a pointer to the raw IGMPv1/IGMPv2 header. Notice this points directly to the data, so every change will + * change the actual packet data + * @return A pointer to the @ref igmp_header + */ + igmp_header* getIgmpHeader() const + { + return (igmp_header*)m_Data; + } + + /** + * @return The IPv4 multicast address stored igmp_header#groupAddress + */ + IPv4Address getGroupAddress() const + { + return getIgmpHeader()->groupAddress; + } + + /** + * Set the IPv4 multicast address + * @param[in] groupAddr The IPv4 address to set + */ + void setGroupAddress(const IPv4Address& groupAddr); + + /** + * @return IGMP type set in igmp_header#type as ::IgmpType enum. Notice that if igmp_header#type contains a + * value that doesn't appear in the ::IgmpType enum, ::IgmpType_Unknown will be returned + */ + IgmpType getType() const; + + /** + * Set IGMP type (will be written to igmp_header#type field) + * @param[in] type The type to set + */ + void setType(IgmpType type); + + /** + * A static method that gets raw IGMP data (byte stream) and returns the IGMP version of this IGMP message + * @param[in] data The IGMP raw data (byte stream) + * @param[in] dataLen Raw data length + * @param[out] isQuery Return true if IGMP message type is ::IgmpType_MembershipQuery and false otherwise + * @return One of the values ::IGMPv1, ::IGMPv2, ::IGMPv3 according to detected IGMP version or + * ::UnknownProtocol if couldn't detect IGMP version + */ + static ProtocolType getIGMPVerFromData(uint8_t* data, size_t dataLen, bool& isQuery); + + // implement abstract methods + + /** + * Does nothing for this layer (IGMP layer is always last) + */ + void parseNextLayer() + {} + + /** + * @return Size of IGMP header = 8B + */ + size_t getHeaderLen() const + { + return sizeof(igmp_header); + } + + std::string toString() const; + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelNetworkLayer; + } + }; + + /** + * @class IgmpV1Layer + * Represents IGMPv1 (Internet Group Management Protocol ver 1) layer. This class represents all the different + * messages of IGMPv1 + */ + class IgmpV1Layer : public IgmpLayer + { + public: + /** A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + IgmpV1Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : IgmpLayer(data, dataLen, prevLayer, packet, IGMPv1) + {} + + /** + * A constructor that allocates a new IGMPv1 header + * @param[in] type The message type to set + * @param[in] groupAddr The multicast address to set. This is an optional parameter and has a default value of + * IPv4Address#Zero if not provided + */ + explicit IgmpV1Layer(IgmpType type, const IPv4Address& groupAddr = IPv4Address()) + : IgmpLayer(type, groupAddr, 0, IGMPv1) + {} + + /** + * A destructor for this layer (does nothing) + */ + ~IgmpV1Layer() + {} + + // implement abstract methods + + /** + * Calculate the IGMP checksum and set igmp_header#maxResponseTime to 0 (this field is unused in IGMPv1) + */ + void computeCalculateFields(); + }; + + /** + * @class IgmpV2Layer + * Represents IGMPv2 (Internet Group Management Protocol ver 2) layer. This class represents all the different + * messages of IGMPv2 + */ + class IgmpV2Layer : public IgmpLayer + { + public: + /** A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + IgmpV2Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : IgmpLayer(data, dataLen, prevLayer, packet, IGMPv2) + {} + + /** + * A constructor that allocates a new IGMPv2 header + * @param[in] type The message type to set + * @param[in] groupAddr The multicast address to set. This is an optional parameter and has a default value of + * unspecified/zero IPv4 address + * @param[in] maxResponseTime The max response time to set. This is an optional parameter and has a default + * value of 0 if not provided + */ + explicit IgmpV2Layer(IgmpType type, const IPv4Address& groupAddr = IPv4Address(), uint8_t maxResponseTime = 0) + : IgmpLayer(type, groupAddr, maxResponseTime, IGMPv2) + {} + + /** + * A destructor for this layer (does nothing) + */ + ~IgmpV2Layer() + {} + + // implement abstract methods + + /** + * Calculate the IGMP checksum + */ + void computeCalculateFields(); + }; + + /** + * @class IgmpV3QueryLayer + * Represents an IGMPv3 (Internet Group Management Protocol ver 3) membership query message + */ + class IgmpV3QueryLayer : public IgmpLayer + { + public: + /** A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + IgmpV3QueryLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + /** + * A constructor that allocates a new IGMPv3 membership query + * @param[in] multicastAddr The multicast address to set. This is an optional parameter and has a default value + * of unspecified/zero IPv4 address if not provided + * @param[in] maxResponseTime The max response time to set. This is an optional parameter and has a default + * value of 0 if not provided + * @param[in] s_qrv A 1-byte value representing the value in Suppress Router-side Processing Flag + Querier's + * Robustness Variable (igmpv3_query_header#s_qrv field). This is an optional parameter and has a default value + * of 0 if not provided + */ + explicit IgmpV3QueryLayer(const IPv4Address& multicastAddr = IPv4Address(), uint8_t maxResponseTime = 0, + uint8_t s_qrv = 0); + + /** + * Get a pointer to the raw IGMPv3 membership query header. Notice this points directly to the data, so every + * change will change the actual packet data + * @return A pointer to the @ref igmpv3_query_header + */ + igmpv3_query_header* getIgmpV3QueryHeader() const + { + return (igmpv3_query_header*)m_Data; + } + + /** + * @return The number of source addresses in this message (as extracted from the + * igmpv3_query_header#numOfSources field) + */ + uint16_t getSourceAddressCount() const; + + /** + * Get the IPV4 source address in a certain index + * @param[in] index The requested index of the source address + * @return The IPv4 source address, or IPv4Address#Zero if index is out of bounds (of the message or of the + * layer) + */ + IPv4Address getSourceAddressAtIndex(int index) const; + + /** + * Add a new source address at the end of the source address list. The igmpv3_query_header#numOfSources field + * will be incremented accordingly + * @param[in] addr The IPv4 source address to add + * @return True if source address was added successfully or false otherwise. If false is returned an appropriate + * error message will be printed to log + */ + bool addSourceAddress(const IPv4Address& addr); + + /** + * Add a new source address at a certain index of the source address list. The igmpv3_query_header#numOfSources + * field will be incremented accordingly + * @param[in] addr The IPv4 source address to add + * @param[in] index The index to add the new source address at + * @return True if source address was added successfully or false otherwise. If false is returned an appropriate + * error message will be printed to log + */ + bool addSourceAddressAtIndex(const IPv4Address& addr, int index); + + /** + * Remove a source address at a certain index. The igmpv3_query_header#numOfSources field will be decremented + * accordingly + * @param[in] index The index of the source address to be removed + * @return True if source address was removed successfully or false otherwise. If false is returned an + * appropriate error message will be printed to log + */ + bool removeSourceAddressAtIndex(int index); + + /** + * Remove all source addresses in the message. The igmpv3_query_header#numOfSources field will be set to 0 + * @return True if all source addresses were cleared successfully or false otherwise. If false is returned an + * appropriate error message will be printed to log + */ + bool removeAllSourceAddresses(); + + // implement abstract methods + + /** + * Calculate the IGMP checksum + */ + void computeCalculateFields(); + + /** + * @return The message size in bytes which include the size of the basic header + the size of the source address + * list + */ + size_t getHeaderLen() const; + }; + + /** + * @class IgmpV3ReportLayer + * Represents an IGMPv3 (Internet Group Management Protocol ver 3) membership report message + */ + class IgmpV3ReportLayer : public IgmpLayer + { + private: + igmpv3_group_record* addGroupRecordAt(uint8_t recordType, const IPv4Address& multicastAddress, + const std::vector& sourceAddresses, int offset); + + public: + /** A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + IgmpV3ReportLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : IgmpLayer(data, dataLen, prevLayer, packet, IGMPv3) + {} + + /** + * A constructor that allocates a new IGMPv3 membership report with 0 group addresses + */ + IgmpV3ReportLayer() : IgmpLayer(IgmpType_MembershipReportV3, IPv4Address(), 0, IGMPv3) + {} + + /** + * Get a pointer to the raw IGMPv3 membership report header. Notice this points directly to the data, so every + * change will change the actual packet data + * @return A pointer to the @ref igmpv3_report_header + */ + igmpv3_report_header* getReportHeader() const + { + return (igmpv3_report_header*)m_Data; + } + + /** + * @return The number of group records in this message (as extracted from the + * igmpv3_report_header#numOfGroupRecords field) + */ + uint16_t getGroupRecordCount() const; + + /** + * @return A pointer to the first group record or nullptr if no group records exist. Notice the return value is + * a pointer to the real data, so changes in the return value will affect the packet data + */ + igmpv3_group_record* getFirstGroupRecord() const; + + /** + * Get the group record that comes next to a given group record. If "groupRecord" is nullptr then nullptr will + * be returned. If "groupRecord" is the last group record or if it is out of layer bounds nullptr will be + * returned also. Notice the return value is a pointer to the real data casted to igmpv3_group_record type (as + * opposed to a copy of the option data). So changes in the return value will affect the packet data + * @param[in] groupRecord The group record to start searching from + * @return The next group record or nullptr if "groupRecord" is nullptr, last or out of layer bounds + */ + igmpv3_group_record* getNextGroupRecord(igmpv3_group_record* groupRecord) const; + + /** + * Add a new group record at a the end of the group record list. The igmpv3_report_header#numOfGroupRecords + * field will be incremented accordingly + * @param[in] recordType The type of the new group record + * @param[in] multicastAddress The multicast address of the new group record + * @param[in] sourceAddresses A vector containing all the source addresses of the new group record + * @return The method constructs a new group record, adds it to the end of the group record list of IGMPv3 + * report message and returns a pointer to the new message. If something went wrong in creating or adding the + * new group record a nullptr value is returned and an appropriate error message is printed to log + */ + igmpv3_group_record* addGroupRecord(uint8_t recordType, const IPv4Address& multicastAddress, + const std::vector& sourceAddresses); + + /** + * Add a new group record at a certain index of the group record list. The + * igmpv3_report_header#numOfGroupRecords field will be incremented accordingly + * @param[in] recordType The type of the new group record + * @param[in] multicastAddress The multicast address of the new group record + * @param[in] sourceAddresses A vector containing all the source addresses of the new group record + * @param[in] index The index to add the new group address at + * @return The method constructs a new group record, adds it to the IGMPv3 report message and returns a pointer + * to the new message. If something went wrong in creating or adding the new group record a nullptr value is + * returned and an appropriate error message is printed to log + */ + igmpv3_group_record* addGroupRecordAtIndex(uint8_t recordType, const IPv4Address& multicastAddress, + const std::vector& sourceAddresses, int index); + + /** + * Remove a group record at a certain index. The igmpv3_report_header#numOfGroupRecords field will be + * decremented accordingly + * @param[in] index The index of the group record to be removed + * @return True if group record was removed successfully or false otherwise. If false is returned an appropriate + * error message will be printed to log + */ + bool removeGroupRecordAtIndex(int index); + + /** + * Remove all group records in the message. The igmpv3_report_header#numOfGroupRecords field will be set to 0 + * @return True if all group records were cleared successfully or false otherwise. If false is returned an + * appropriate error message will be printed to log + */ + bool removeAllGroupRecords(); + + // implement abstract methods + + /** + * Calculate the IGMP checksum + */ + void computeCalculateFields(); + + /** + * @return The message size in bytes which include the size of the basic header + the size of the group record + * list + */ + size_t getHeaderLen() const + { + return m_DataLen; + } + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/LLCLayer.h b/Packet++/header/pcapplusplus/LLCLayer.h new file mode 100644 index 0000000000..c758e4402c --- /dev/null +++ b/Packet++/header/pcapplusplus/LLCLayer.h @@ -0,0 +1,103 @@ +#pragma once + +#include "pcapplusplus/Layer.h" + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ +#pragma pack(push, 1) + /** + * @struct llc_header + * Logical Link Control (LLC) header + */ + struct llc_header + { + /// Destination Service Access Point + uint8_t dsap, + /// Source Service Access Point + ssap, + /// Control Field + control; + }; +#pragma pack(pop) + + /** + * @class LLCLayer + * Represents Logical Link Control layer messages + */ + class LLCLayer : public Layer + { + public: + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data (will be casted to llc_header) + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + LLCLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : Layer(data, dataLen, prevLayer, packet, LLC) + {} + + /** + * A constructor that creates the LLC layer from provided values + * @param[in] dsap Destination Service Access Point + * @param[in] ssap Source Service Access Point + * @param[in] control Control Field + */ + LLCLayer(uint8_t dsap, uint8_t ssap, uint8_t control); + + /** + * Get a pointer to Logical Link Control (LLC) layer header + * @return Pointer to LLC header + */ + inline llc_header* getLlcHeader() const + { + return (llc_header*)m_Data; + }; + + // overridden methods + + /// Parses the next layer. Currently only STP supported as next layer + void parseNextLayer(); + + /// Does nothing for this layer + void computeCalculateFields() + {} + + /** + * @return Get the size of the LLC header + */ + size_t getHeaderLen() const + { + return sizeof(llc_header); + } + + /** + * @return Returns the protocol info as readable string + */ + std::string toString() const; + + /** + * @return The OSI layer level of LLC (Data Link Layer). + */ + OsiModelLayer getOsiModelLayer() const + { + return OsiModelDataLinkLayer; + } + + /** + * A static method that validates the input data + * @param[in] data The pointer to the beginning of a byte stream of an LLC packet + * @param[in] dataLen The length of the byte stream + * @return True if the data is valid and can represent an LLC packet + */ + static bool isDataValid(const uint8_t* data, size_t dataLen); + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/Layer.h b/Packet++/header/pcapplusplus/Layer.h new file mode 100644 index 0000000000..a599613a75 --- /dev/null +++ b/Packet++/header/pcapplusplus/Layer.h @@ -0,0 +1,242 @@ +#pragma once + +#include +#include +#include "pcapplusplus/ProtocolType.h" +#include + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * @class IDataContainer + * An interface (virtual abstract class) that indicates an object that holds a pointer to a buffer data. The Layer + * class is an example of such object, hence it inherits this interface + */ + class IDataContainer + { + public: + /** + * Get a pointer to the data + * @param[in] offset Get a pointer in a certain offset. Default is 0 - get a pointer to start of data + * @return A pointer to the data + */ + virtual uint8_t* getDataPtr(size_t offset = 0) const = 0; + + virtual ~IDataContainer() + {} + }; + + class Packet; + + /** + * @class Layer + * Layer is the base class for all protocol layers. Each protocol supported in PcapPlusPlus has a class that + * inherits Layer. + * The protocol layer class expose all properties and methods relevant for viewing and editing protocol fields. + * For example: a pointer to a structured header (e.g tcphdr, iphdr, etc.), protocol header size, payload size, + * compute fields that can be automatically computed, print protocol data to string, etc. + * Each protocol instance is obviously part of a protocol stack (which construct a packet). This protocol stack is + * represented in PcapPlusPlus in a linked list, and each layer is an element in this list. That's why each layer + * has properties to the next and previous layer in the protocol stack. The Layer class, as a base class, is + * abstract and the user can't create an instance of it (it has a private constructor). Each layer holds a pointer + * to the relevant place in the packet. The layer sees all the data from this pointer forward until the end of the + * packet. Here is an example packet showing this concept: + * + * @verbatim + * ==================================================== + * |Eth |IPv4 |TCP |Packet | + * |Header |Header |Header |Payload | + * ==================================================== + * + * |--------------------------------------------------| + * EthLayer data + * |---------------------------------------| + * IPv4Layer data + * |---------------------------| + * TcpLayer data + * |----------------| + * PayloadLayer data + * @endverbatim + * + */ + class Layer : public IDataContainer + { + friend class Packet; + + public: + /** + * A destructor for this class. Frees the data if it was allocated by the layer constructor (see + * isAllocatedToPacket() for more info) + */ + virtual ~Layer(); + + /** + * @return A pointer to the next layer in the protocol stack or nullptr if the layer is the last one + */ + Layer* getNextLayer() const + { + return m_NextLayer; + } + + /** + * @return A pointer to the previous layer in the protocol stack or nullptr if the layer is the first one + */ + Layer* getPrevLayer() const + { + return m_PrevLayer; + } + + /** + * @return The protocol enum + */ + ProtocolType getProtocol() const + { + return m_Protocol; + } + + /** + * Check if the layer's protocol matches a protocol family + * @param protocolTypeFamily The protocol family to check + * @return True if the layer's protocol matches the protocol family, false otherwise + */ + bool isMemberOfProtocolFamily(ProtocolTypeFamily protocolTypeFamily) const; + + /** + * @return A pointer to the layer raw data. In most cases it'll be a pointer to the first byte of the header + */ + uint8_t* getData() const + { + return m_Data; + } + + /** + * @return The length in bytes of the data from the first byte of the header until the end of the packet + */ + size_t getDataLen() const + { + return m_DataLen; + } + + /** + * @return A pointer for the layer payload, meaning the first byte after the header + */ + uint8_t* getLayerPayload() const + { + return m_Data + getHeaderLen(); + } + + /** + * @return The size in bytes of the payload + */ + size_t getLayerPayloadSize() const + { + return m_DataLen - getHeaderLen(); + } + + /** + * Raw data in layers can come from one of sources: + * 1. from an existing packet - this is the case when parsing packets received from files or the network. In + * this case the data was already allocated by someone else, and layer only holds the pointer to the relevant + * place inside this data + * 2. when creating packets, data is allocated when layer is created. In this case the layer is responsible for + * freeing it as well + * + * @return Returns true if the data was allocated by an external source (a packet) or false if it was allocated + * by the layer itself + */ + bool isAllocatedToPacket() const + { + return m_Packet != nullptr; + } + + /** + * Copy the raw data of this layer to another array + * @param[out] toArr The destination byte array + */ + void copyData(uint8_t* toArr) const; + + // implement abstract methods + + uint8_t* getDataPtr(size_t offset = 0) const + { + return (uint8_t*)(m_Data + offset); + } + + // abstract methods + + /** + * Each layer is responsible for parsing the next layer + */ + virtual void parseNextLayer() = 0; + + /** + * @return The header length in bytes + */ + virtual size_t getHeaderLen() const = 0; + + /** + * Each layer can compute field values automatically using this method. This is an abstract method + */ + virtual void computeCalculateFields() = 0; + + /** + * @return A string representation of the layer most important data (should look like the layer description in + * Wireshark) + */ + virtual std::string toString() const = 0; + + /** + * @return The OSI Model layer this protocol belongs to + */ + virtual OsiModelLayer getOsiModelLayer() const = 0; + + protected: + uint8_t* m_Data; + size_t m_DataLen; + Packet* m_Packet; + ProtocolType m_Protocol; + Layer* m_NextLayer; + Layer* m_PrevLayer; + bool m_IsAllocatedInPacket; + + Layer() + : m_Data(nullptr), m_DataLen(0), m_Packet(nullptr), m_Protocol(UnknownProtocol), m_NextLayer(nullptr), + m_PrevLayer(nullptr), m_IsAllocatedInPacket(false) + {} + + Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, ProtocolType protocol = UnknownProtocol) + : m_Data(data), m_DataLen(dataLen), m_Packet(packet), m_Protocol(protocol), m_NextLayer(nullptr), + m_PrevLayer(prevLayer), m_IsAllocatedInPacket(false) + {} + + // Copy c'tor + Layer(const Layer& other); + Layer& operator=(const Layer& other); + + void setNextLayer(Layer* nextLayer) + { + m_NextLayer = nextLayer; + } + void setPrevLayer(Layer* prevLayer) + { + m_PrevLayer = prevLayer; + } + + virtual bool extendLayer(int offsetInLayer, size_t numOfBytesToExtend); + virtual bool shortenLayer(int offsetInLayer, size_t numOfBytesToShorten); + }; + +} // namespace pcpp + +inline std::ostream& operator<<(std::ostream& os, const pcpp::Layer& layer) +{ + os << layer.toString(); + return os; +} diff --git a/Packet++/header/pcapplusplus/LdapLayer.h b/Packet++/header/pcapplusplus/LdapLayer.h new file mode 100644 index 0000000000..d0541af162 --- /dev/null +++ b/Packet++/header/pcapplusplus/LdapLayer.h @@ -0,0 +1,1367 @@ +#pragma once + +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/Asn1Codec.h" +#include +#include +#include + +/// @file + +/** + * @namespace pcpp + * @brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + /** + * @class LdapOperationType + * @brief An enum wrapper class for LDAP operation types + */ + class LdapOperationType + { + public: + /** + * Define enum types and the corresponding int values + */ + enum Value : uint8_t + { + /// Bind Request + BindRequest = 0, + /// Bind Response + BindResponse = 1, + /// Unbind Request + UnbindRequest = 2, + /// Search Request + SearchRequest = 3, + /// Search Result Entry + SearchResultEntry = 4, + /// Search Result Done + SearchResultDone = 5, + /// Modify Request + ModifyRequest = 6, + /// Modify Response + ModifyResponse = 7, + /// Add Request + AddRequest = 8, + /// Add Response + AddResponse = 9, + /// Delete Request + DeleteRequest = 10, + /// Delete Response + DeleteResponse = 11, + /// Modify DN (Distinguished Name) Request + ModifyDNRequest = 12, + /// Modify DN (Distinguished Name) Response + ModifyDNResponse = 13, + /// Compare Request + CompareRequest = 14, + /// Compare Response + CompareResponse = 15, + /// Abandon Request + AbandonRequest = 16, + /// Search Result Reference + SearchResultReference = 19, + /// Extended Request + ExtendedRequest = 23, + /// Extended Response + ExtendedResponse = 24, + /// Intermediate Response + IntermediateResponse = 25, + /// Unknown operation type + Unknown = 255 + }; + + LdapOperationType() = default; + + // cppcheck-suppress noExplicitConstructor + /** + * Construct LdapOperationType from Value enum + * @param[in] value the opetation type enum value + */ + constexpr LdapOperationType(Value value) : m_Value(value) + {} + + /** + * @return A string representation of the operation type + */ + std::string toString() const; + + /** + * A static method that creates LdapOperationType from an integer value + * @param[in] value The operation type integer value + * @return The operation type that corresponds to the integer value. If the integer value + * doesn't corresponds to any operation type, LdapOperationType::Unknown is returned + */ + static LdapOperationType fromUintValue(uint8_t value); + + // Allow switch and comparisons. + constexpr operator Value() const + { + return m_Value; + } + + // Prevent usage: if(LdapOperationType) + explicit operator bool() const = delete; + + private: + Value m_Value = LdapOperationType::Unknown; + }; + + /** + * @class LdapResultCode + * @brief An enum wrapper class for LDAP result codes + */ + class LdapResultCode + { + public: + /** + * Define enum types and the corresponding int values + */ + enum Value : uint8_t + { + /** + * Indicates that the associated operation completed successfully + */ + Success = 0, + /** + * Indicates that there was a problem with the client’s use of the LDAP protocol + */ + OperationsError = 1, + /** + * Indicates that there was a problem with the client’s use of the LDAP protocol + */ + ProtocolError = 2, + /** + * Indicates that the associated operation failed because it hadn’t completed by the time + * a maximum processing time limit had been reached + */ + TimeLimitExceeded = 3, + /** + * Indicates that the associated search operation failed because the server has determined + * that the number of entries that would be returned in response to the search would exceed + * the upper bound for that operation + */ + SizeLimitExceeded = 4, + /** + * Indicates that the associated compare request targeted an entry that exists and that contains + * the targeted attribute, but does not have any value that matches the provided assertion value + */ + CompareFalse = 5, + /** + * Indicates that the associated compare request targeted an entry that exists and that contains + * the targeted attribute with a value that matches the provided assertion value + */ + CompareTrue = 6, + /** + * Indicates that the associated bind operation failed because the client attempted to authenticate + * with a mechanism that the server does not support or that it does not allow the client to use + */ + AuthMethodNotSupported = 7, + /** + * Indicates that the server requires the client to authenticate with a stronger form of authentication + */ + StrongerAuthRequired = 8, + /** + * Indicates that the request cannot be processed exactly as issued, but that it might succeed + * if re-issued to a different server, or is updated to target a different location in the DIT + */ + Referral = 10, + /** + * Indicates that some administrative limit within the server was exceeded while processing the request + */ + AdminLimitExceeded = 11, + /** + * Indicates that the request includes a control with a criticality of true, + * but that control could not be honored for some reason + */ + UnavailableCriticalExtension = 12, + /** + * Indicates that the server is only willing to process the requested operation if it is received + * over a secure connection that does not allow an eavesdropper to decipher or alter the contents + * of the request or response + */ + ConfidentialityRequired = 13, + /** + * Indicates that the server has completed a portion of the processing for the provided SASL + * bind request, but that it needs additional information from the client to complete the authentication + */ + SaslBindInProgress = 14, + /** + * Indicates that the request targeted an attribute that does not exist in the specified entry + */ + NoSuchAttribute = 16, + /** + * Indicates that the request attempted to provide one or more values for an attribute type + * that is not defined in the server schema + */ + UndefinedAttributeType = 17, + /** + * Indicates that the search request tried to perform some type of matching that is not + * supported for the target attribute type + */ + InappropriateMatching = 18, + /** + * Indicates that the requested operation would have resulted in an entry that violates + * some constraint defined within the server + */ + ConstraintViolation = 19, + /** + * Indicates that the requested operation would have resulted in an attribute in which + * the same value appeared more than once + */ + AttributeOrValueExists = 20, + /** + * Indicates that the requested add or modify operation would have resulted in an entry + * that had at least one attribute value that does not conform to the constraints of the + * associated attribute syntax + */ + InvalidAttributeSyntax = 21, + /** + * Indicates that the requested operation targeted an entry that does not exist within the DIT + */ + NoSuchObject = 32, + /** + * Indicates that a problem occurred while attempting to dereference an alias during search processing + */ + AliasProblem = 33, + /** + * Indicates that the request included a malformed entry DN + */ + InvalidDNSyntax = 34, + /** + * Indicates that the server encountered an alias while processing the request and that there + * was some problem related to that alias + */ + AliasDereferencingProblem = 36, + /** + * Indicates that the client attempted to bind in an inappropriate manner that is inappropriate + * for the target account + */ + InappropriateAuthentication = 48, + /** + * Indicates that the client attempted to bind with a set of credentials that cannot + * be used to authenticate + */ + InvalidCredentials = 49, + /** + * Indicates that the client requested an operation for which it does not have the necessary + * access control permissions + */ + InsufficientAccessRights = 50, + /** + * Indicates that the requested operation cannot be processed because the server is currently too busy + */ + Busy = 51, + /** + * Indicates that the server is currently not available to process the requested operation + */ + Unavailable = 52, + /** + * Indicates that the server is not willing to process the requested operation for some reason + */ + UnwillingToPerform = 53, + /** + * Indicates that the server detected some kind of circular reference in the course + * of processing an operation + */ + LoopDetect = 54, + /** + * Indicates that the requested add or modify DN operation would have resulted in an entry + * that violates some naming constraint within the server + */ + NamingViolation = 64, + /** + * Indicates that the requested operation would have resulted in an entry that has + * an inappropriate set of object classes, or whose attributes violate the constraints + * associated with its set of object classes + */ + ObjectClassViolation = 65, + /** + * Indicates that the requested operation is only supported for leaf entries, + * but the targeted entry has one or more subordinates + */ + NotAllowedOnNonLeaf = 66, + /** + * Indicates that the requested modify operation would have resulted in an entry that + * does not include all of the attributes used in its RDN + */ + NotAllowedOnRDN = 67, + /** + * Indicates that the requested operation would have resulted in an entry with the same + * DN as an entry that already exists in the server + */ + EntryAlreadyExists = 68, + /** + * Indicates that the requested modify operation would have altered the target entry’s + * set of object classes in a way that is not supported + */ + ObjectClassModsProhibited = 69, + /** + * Indicates that the requested operation would have required manipulating information + * in multiple servers in a way that is not supported + */ + AffectsMultipleDSAs = 71, + /** + * Used when a problem occurs for which none of the other result codes is more appropriate + */ + Other = 80, + /** + * Unknown result code + */ + Unknown = 255 + }; + + LdapResultCode() = default; + + // cppcheck-suppress noExplicitConstructor + /** + * Construct LdapResultCode from Value enum + * @param[in] value the result code enum value + */ + constexpr LdapResultCode(Value value) : m_Value(value) + {} + + /** + * @return A string representation of the result code + */ + std::string toString() const; + + /** + * A static method that creates LdapResultCode from an integer value + * @param[in] value The result code integer value + * @return The result code that corresponds to the integer value. If the integer value + * doesn't corresponds to any operation type, LdapResultCode::Unknown is returned + */ + static LdapResultCode fromUintValue(uint8_t value); + + // Allow switch and comparisons + constexpr operator Value() const + { + return m_Value; + } + + // Prevent usage: if(LdapResultCode) + explicit operator bool() const = delete; + + private: + Value m_Value = LdapResultCode::Unknown; + }; + + /** + * @struct LdapControl + * A struct that represents an LDAP Control + */ + struct LdapControl + { + /// LDAP control type + std::string controlType; + /// LDAP control value + std::string controlValue; + + /** + * Equality operator overload for this struct + * @param[in] other The value to compare with + * @return True if both values are equal, false otherwise + */ + bool operator==(const LdapControl& other) const + { + return controlType == other.controlType && controlValue == other.controlValue; + } + }; + + /** + * @struct LdapAttribute + * A struct that represents an LDAP attribute + */ + struct LdapAttribute + { + /// Attribute description + std::string type; + /// A list of attribute values (zero or more) + std::vector values; + + /** + * Equality operator overload for this struct + * @param[in] other The value to compare with + * @return True if both values are equal, false otherwise + */ + bool operator==(const LdapAttribute& other) const + { + return type == other.type && values == other.values; + } + }; + + /** + * @class LdapLayer + * Represents an LDAP message + */ + class LdapLayer : public Layer + { + public: + /** + * A constructor to create a new LDAP message + * @param[in] messageId The LDAP message ID + * @param[in] operationType The LDAP operation type + * @param[in] messageRecords A vector of ASN.1 records that comprise the LDAP message + * @param[in] controls A vector of LDAP controls. This is an optional parameter, if not provided the message + * will be created without LDAP controls + */ + LdapLayer(uint16_t messageId, LdapOperationType operationType, const std::vector& messageRecords, + const std::vector& controls = std::vector()); + + ~LdapLayer() + {} + + /** + * @return The root ASN.1 record of the LDAP message. All of the message data will be under this record. + * If the Root ASN.1 record is malformed, an exception is thrown + */ + Asn1SequenceRecord* getRootAsn1Record() const; + + /** + * @return The ASN.1 record of the specific LDAP operation in this LDAP message. Each operation has a specific + * structure. If the Operation ASN.1 record is malformed, an exception is thrown + */ + Asn1ConstructedRecord* getLdapOperationAsn1Record() const; + + /** + * @return The LDAP message ID. If the ASN.1 record is malformed, an exception is thrown + */ + uint16_t getMessageID() const; + + /** + * @return A vector of LDAP controls in this message. If the message contains no controls then an empty + * vector is returned. If the Controls ASN.1 record is malformed, an exception is thrown + */ + std::vector getControls() const; + + /** + * @return The LDAP operation of this message. If the Operation ASN.1 record is malformed, an exception is + * thrown + */ + virtual LdapOperationType getLdapOperationType() const; + + /** + * Most getter methods in this class throw an exception if the corresponding ASN.1 record is invalid. + * This is a wrapper method that allows calling these getters without adding a `try...catch` clause. + * It accepts the getter method and an out variable. It tries to call the getter and if no exception + * is thrown, the out variable will contain the result. + * + * Here is an example: + * @code + * uint16_t messageId; + * ldapLayer->tryGet(&pcpp::LdapLayer::getMessageID, messageId)); + * @endcode + * + * We call getMessageID(), if no exception is thrown the variable messageId will hold the result + * + * @tparam Method The class method type + * @tparam ResultType The expected result type (for example: uint8_t, std::string, etc.) + * @param[in] method The class method to call + * @param[out] result An outvariable to contain the result if no exception is thrown + * @return True if no exception was thrown or false otherwise + */ + template bool tryGet(Method method, ResultType& result) + { + return internalTryGet(this, method, result); + } + + /** + * A static method that checks whether a source or dest port match those associated with the LDAP protocol + * @param[in] port The port number to check + * @return True if this is an LDAP port, false otherwise + */ + static bool isLdapPort(uint16_t port) + { + return port == 389; + } + + /** + * A static message to parse an LDAP message from raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + * @return An instance of LdapLayer if this is indeed an LDAP message, nullptr otherwise + */ + static LdapLayer* parseLdapMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + // implement abstract methods + + /** + * Tries to identify more LDAP messages in this packet if exist + */ + void parseNextLayer() override; + + /** + * @return The size of the LDAP message + */ + size_t getHeaderLen() const override + { + return m_Asn1Record->getTotalLength(); + } + + void computeCalculateFields() override + {} + + OsiModelLayer getOsiModelLayer() const override + { + return OsiModelApplicationLayer; + } + + std::string toString() const override; + + protected: + std::unique_ptr m_Asn1Record; + + LdapLayer(std::unique_ptr asn1Record, uint8_t* data, size_t dataLen, Layer* prevLayer, + Packet* packet); + LdapLayer() = default; + void init(uint16_t messageId, LdapOperationType operationType, const std::vector& messageRecords, + const std::vector& controls); + virtual std::string getExtendedInfoString() const + { + return ""; + } + + static constexpr int messageIdIndex = 0; + static constexpr int operationTypeIndex = 1; + static constexpr int controlsIndex = 2; + + static constexpr int controlTypeIndex = 0; + static constexpr int controlValueIndex = 1; + + template + bool internalTryGet(LdapClass* thisPtr, Method method, ResultType& result) + { + try + { + result = std::mem_fn(method)(thisPtr); + return true; + } + catch (...) + { + return false; + } + } + }; + + /** + * @class LdapResponseLayer + * An abstract class for representing an LDAP response message. It's the parent class + * for all response message layers + */ + class LdapResponseLayer : public LdapLayer + { + public: + /** + * @return LDAP result code + */ + LdapResultCode getResultCode() const; + + /** + * @return An optional distinguished name (DN) that may be included in the response to a request + * targeting an entry that does not exist + */ + std::string getMatchedDN() const; + + /** + * @return An optional string that can provide additional information about the processing that + * was performed + */ + std::string getDiagnosticMessage() const; + + /** + * @return An optional list of one or more URIs that the client may use to re-try the operation + * somewhere else. If referral doesn't exist on the message, and empty vector is returned + */ + std::vector getReferral() const; + + protected: + static constexpr int resultCodeIndex = 0; + static constexpr int matchedDNIndex = 1; + static constexpr int diagnotsticsMessageIndex = 2; + static constexpr int referralIndex = 3; + + static constexpr uint8_t referralTagType = 3; + + LdapResponseLayer() = default; + LdapResponseLayer(std::unique_ptr asn1Record, uint8_t* data, size_t dataLen, Layer* prevLayer, + Packet* packet) + : LdapLayer(std::move(asn1Record), data, dataLen, prevLayer, packet) + {} + + LdapResponseLayer(uint16_t messageId, LdapOperationType operationType, LdapResultCode resultCode, + const std::string& matchedDN, const std::string& diagnosticMessage, + const std::vector& referral = std::vector(), + const std::vector& controls = std::vector()); + + void init(uint16_t messageId, LdapOperationType operationType, LdapResultCode resultCode, + const std::string& matchedDN, const std::string& diagnosticMessage, + const std::vector& referral = std::vector(), + const std::vector& additionalRecords = std::vector(), + const std::vector& controls = std::vector()); + + std::string getExtendedInfoString() const override; + }; + + /** + * @class LdapBindRequestLayer + * Represents LDAP bind request operation + */ + class LdapBindRequestLayer : public LdapLayer + { + public: + /** + * An enum to represent the bind request authentication type + */ + enum class AuthenticationType : uint8_t + { + /// Simple authentication + Simple = 0, + /// SASL authentication + Sasl = 3, + /// Unknown / not application authentication type + NotApplicable = 255 + }; + + /** + * @struct SaslAuthentication + * A struct to represent SASL authentication + */ + struct SaslAuthentication + { + /// The SASL mechanism + std::string mechanism; + /// Encoded SASL credentials + std::vector credentials; + + /** + * Equality operator overload for this struct + * @param[in] other The value to compare with + * @return True if both values are equal, false otherwise + */ + bool operator==(const SaslAuthentication& other) const + { + return mechanism == other.mechanism && credentials == other.credentials; + } + + /** + * Inequality operator overload for this struct + * @param[in] other The value to compare with + * @return False if both values are equal, true otherwise + */ + bool operator!=(const SaslAuthentication& other) const + { + return !operator==(other); + } + }; + + /** + * A constructor to create a new LDAP bind request message with simple authentication + * @param[in] messageId The LDAP message ID + * @param[in] version The LDAP protocol version that the client wants to use + * @param[in] name The DN of the user to authenticate + * @param[in] simpleAuthentication Simple authentication to use in this message + * @param[in] controls A vector of LDAP controls. This is an optional parameter, if not provided the message + * will be created without LDAP controls + */ + LdapBindRequestLayer(uint16_t messageId, uint8_t version, const std::string& name, + const std::string& simpleAuthentication, + const std::vector& controls = std::vector()); + + /** + * A constructor to create a new LDAP bind request message with SASL authentication + * @param[in] messageId The LDAP message ID + * @param[in] version The LDAP protocol version that the client wants to use + * @param[in] name The DN of the user to authenticate + * @param[in] saslAuthentication SASL authentication to use in this message + * @param[in] controls A vector of LDAP controls. This is an optional parameter, if not provided the message + * will be created without LDAP controls + */ + LdapBindRequestLayer(uint16_t messageId, uint8_t version, const std::string& name, + const SaslAuthentication& saslAuthentication, + const std::vector& controls = std::vector()); + + /** + * @return The LDAP protocol version that the client wants to use + */ + uint32_t getVersion() const; + + /** + * @return The DN of the user to authenticate + */ + std::string getName() const; + + /** + * @return The authentication type included in this message + */ + AuthenticationType getAuthenticationType() const; + + /** + * @return The simple authentication included in this message + * @throws std::invalid_argument if the message doesn't include simple authentication + */ + std::string getSimpleAuthentication() const; + + /** + * @return The SASL authentication included in this message + * @throws std::invalid_argument if the message doesn't include SASL authentication + */ + SaslAuthentication getSaslAuthentication() const; + + template bool tryGet(Method method, ResultType& result) + { + return internalTryGet(this, method, result); + } + + protected: + friend LdapLayer* LdapLayer::parseLdapMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + LdapBindRequestLayer(std::unique_ptr asn1Record, uint8_t* data, size_t dataLen, Layer* prevLayer, + Packet* packet) + : LdapLayer(std::move(asn1Record), data, dataLen, prevLayer, packet) + {} + + std::string getExtendedInfoString() const override; + + private: + static constexpr int versionIndex = 0; + static constexpr int nameIndex = 1; + static constexpr int credentialIndex = 2; + + static constexpr int saslMechanismIndex = 0; + static constexpr int saslCredentialsIndex = 1; + }; + + /** + * @class LdapBindResponseLayer + * Represents LDAP bind response operation + */ + class LdapBindResponseLayer : public LdapResponseLayer + { + public: + /** + * A constructor to create a new LDAP bind response message + * @param[in] messageId The LDAP message ID + * @param[in] resultCode The LDAP result code + * @param[in] matchedDN The distinguished name (DN) to set on the message. If not applicable + * pass an empty string + * @param[in] diagnosticMessage The additional information to set on the message. If not applicable + * pass an empty string + * @param[in] referral A list of URIs to re-try the operation somewhere else. This is an optional + * parameter. If not provided then referral won't be added to the message + * @param[in] serverSaslCredentials Encoded server SASL credentials for use in subsequent processing + * @param[in] controls A vector of LDAP controls. This is an optional parameter, if not provided the message + * will be created without LDAP controls + */ + LdapBindResponseLayer(uint16_t messageId, LdapResultCode resultCode, const std::string& matchedDN, + const std::string& diagnosticMessage, + const std::vector& referral = std::vector(), + const std::vector& serverSaslCredentials = std::vector(), + const std::vector& controls = std::vector()); + + /** + * @return Encoded server SASL credentials for use in subsequent processing + */ + std::vector getServerSaslCredentials() const; + + protected: + friend LdapLayer* LdapLayer::parseLdapMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + static constexpr int serverSaslCredentialsTagType = 7; + + LdapBindResponseLayer(std::unique_ptr asn1Record, uint8_t* data, size_t dataLen, Layer* prevLayer, + Packet* packet) + : LdapResponseLayer(std::move(asn1Record), data, dataLen, prevLayer, packet) + {} + }; + + /** + * @class LdapUnbindRequestLayer + * Represents LDAP unbind operation + */ + class LdapUnbindRequestLayer : public LdapLayer + { + public: + /** + * A constructor to create a new LDAP unbind message + * @param[in] messageId The LDAP message ID + * @param[in] controls A vector of LDAP controls. This is an optional parameter, if not provided the message + * will be created without LDAP controls + */ + explicit LdapUnbindRequestLayer(uint16_t messageId, + const std::vector& controls = std::vector()); + + // Unbind request has no operation record + Asn1ConstructedRecord* getLdapOperationAsn1Record() const = delete; + + LdapOperationType getLdapOperationType() const override + { + return LdapOperationType::UnbindRequest; + } + + template bool tryGet(Method method, ResultType& result) + { + return internalTryGet(this, method, result); + } + + protected: + friend LdapLayer* LdapLayer::parseLdapMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + LdapUnbindRequestLayer(std::unique_ptr asn1Record, uint8_t* data, size_t dataLen, Layer* prevLayer, + Packet* packet) + : LdapLayer(std::move(asn1Record), data, dataLen, prevLayer, packet) + {} + }; + + /** + * @class LdapSearchRequestLayer + * Represents LDAP search request operation + */ + class LdapSearchRequestLayer : public LdapLayer + { + public: + /** + * @class SearchRequestScope + * An enum wrapper class for LDAP search request scope + */ + class SearchRequestScope + { + public: + /** + * Define enum types and the corresponding int values + */ + enum Value : uint8_t + { + /** + * The search operation should only be performed against the entry specified as the search base DN + */ + BaseObject = 0, + /** + * The search operation should only be performed against entries that are immediate subordinates + * of the entry specified as the search base DN + */ + SingleLevel = 1, + /** + * The search operation should be performed against the entry specified as the search base + * and all of its subordinates to any depth + */ + WholeSubtree = 2, + /** + * The search operation should be performed against any subordinate entries (to any depth) below the + * entry specified by the base DN should be considered, but the base entry itself + * should not be considered + */ + subordinateSubtree = 3, + /** + * Unknown or unsupported scope + */ + Unknown = 255 + }; + + SearchRequestScope() = default; + + // cppcheck-suppress noExplicitConstructor + /** + * Construct SearchRequestScope from Value enum + * @param[in] value the scope enum value + */ + constexpr SearchRequestScope(Value value) : m_Value(value) + {} + + /** + * @return A string representation of the scope value + */ + std::string toString() const; + + /** + * A static method that creates SearchRequestScope from an integer value + * @param[in] value The scope integer value + * @return The scope that corresponds to the integer value. If the integer value + * doesn't corresponds to any enum value, SearchRequestScope::Unknown is returned + */ + static SearchRequestScope fromUintValue(uint8_t value); + + // Allow switch and comparisons. + constexpr operator Value() const + { + return m_Value; + } + + // Prevent usage: if(LdapOperationType) + explicit operator bool() const = delete; + + private: + Value m_Value = SearchRequestScope::Unknown; + }; + + /** + * @class DerefAliases + * An enum wrapper class for LDAP search request dereferencing aliases + */ + class DerefAliases + { + public: + /** + * Define enum types and the corresponding int values + */ + enum Value : uint8_t + { + /// Never dereferences aliases + NeverDerefAliases = 0, + /// Dereferences aliases only after name resolution + DerefInSearching = 1, + /// Dereferences aliases only during name resolution + DerefFindingBaseObj = 2, + /// Always dereference aliases + DerefAlways = 3, + /// Unknown value + Unknown = 255 + }; + + DerefAliases() = default; + + // cppcheck-suppress noExplicitConstructor + /** + * Construct DerefAliases from Value enum + * @param[in] value the dereference alias enum value + */ + constexpr DerefAliases(Value value) : m_Value(value) + {} + + /** + * @return A string representation of the dereference alias value + */ + std::string toString() const; + + /** + * A static method that creates DerefAliases from an integer value + * @param[in] value The dereference alias integer value + * @return The dereference alias that corresponds to the integer value. If the integer value + * doesn't corresponds to any enum value, DerefAliases::Unknown is returned + */ + static DerefAliases fromUintValue(uint8_t value); + + // Allow switch and comparisons. + constexpr operator Value() const + { + return m_Value; + } + + // Prevent usage: if(LdapOperationType) + explicit operator bool() const = delete; + + private: + Value m_Value = DerefAliases::Unknown; + }; + + /** + * A constructor to create a new LDAP search request message + * @param[in] messageId The LDAP message ID + * @param[in] baseObject The base object for the LDAP search request entry + * @param[in] scope The portion of the target subtree that should be considered + * @param[in] derefAliases The alias dereferencing behavior, which indicates how the server should treat + * any aliases encountered while processing the search + * @param[in] sizeLimit The maximum number of entries that should be returned from the search + * @param[in] timeLimit The time limit for the search in seconds + * @param[in] typesOnly If this is given a value of true, then it indicates that entries that match the + * search criteria should be returned containing only the attribute descriptions for the attributes + * contained in that entry but should not include the values for those attributes. + * If this is given a value of false, then it indicates that the attribute values should be included + * in the entries that are returned + * @param[in] filterRecord The filter for the search. Please note that parsing for the search filter + * doesn't exist yet. Therefore, the expected input value should be a plain ASN.1 record + * @param[in] attributes A set of attributes to request for inclusion in entries that match the search + * criteria and are returned to the client + * @param[in] controls A vector of LDAP controls. This is an optional parameter, if not provided the message + * will be created without LDAP controls + */ + LdapSearchRequestLayer(uint16_t messageId, const std::string& baseObject, SearchRequestScope scope, + DerefAliases derefAliases, uint8_t sizeLimit, uint8_t timeLimit, bool typesOnly, + Asn1Record* filterRecord, const std::vector& attributes, + const std::vector& controls = std::vector()); + + /** + * @return The base object for the LDAP search request entry + */ + std::string getBaseObject() const; + + /** + * @return The portion of the target subtree that should be considered + */ + SearchRequestScope getScope() const; + + /** + * @return The alias dereferencing behavior + */ + DerefAliases getDerefAlias() const; + + /** + * @return The maximum number of entries that should be returned from the search + */ + uint8_t getSizeLimit() const; + + /** + * @return The time limit for the search in seconds + */ + uint8_t getTimeLimit() const; + + /** + * @return If this flag is true, then it indicates that entries that match the search criteria should be + * returned containing only the attribute descriptions for the attributes contained in that entry but + * should not include the values for those attributes. If this flag is false, then it indicates that the + * attribute values should be included in the entries that are returned + */ + bool getTypesOnly() const; + + /** + * @return The filter for the search. Please note that parsing for the search filter doesn't exist yet. + * Therefore, the return value is a plain ASN.1 record + */ + Asn1Record* getFilter() const; + + /** + * @return A list of search request attributes + */ + std::vector getAttributes() const; + + template bool tryGet(Method method, ResultType& result) + { + return internalTryGet(this, method, result); + } + + protected: + friend LdapLayer* LdapLayer::parseLdapMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + static constexpr int baseObjectIndex = 0; + static constexpr int scopeIndex = 1; + static constexpr int derefAliasIndex = 2; + static constexpr int sizeLimitIndex = 3; + static constexpr int timeLimitIndex = 4; + static constexpr int typesOnlyIndex = 5; + static constexpr int filterIndex = 6; + static constexpr int attributesIndex = 7; + + LdapSearchRequestLayer(std::unique_ptr asn1Record, uint8_t* data, size_t dataLen, Layer* prevLayer, + Packet* packet) + : LdapLayer(std::move(asn1Record), data, dataLen, prevLayer, packet) + {} + + std::string getExtendedInfoString() const override; + }; + + /** + * @class LdapSearchResultEntryLayer + * Represents LDAP search result entry message + */ + class LdapSearchResultEntryLayer : public LdapLayer + { + public: + /** + * A constructor to create a new LDAP search result entry message + * @param[in] messageId The LDAP message ID + * @param[in] objectName The entry's DN + * @param[in] attributes The entry's attributes + * @param[in] controls A vector of LDAP controls. This is an optional parameter, if not provided the message + * will be created without LDAP controls + */ + LdapSearchResultEntryLayer(uint16_t messageId, const std::string& objectName, + const std::vector& attributes, + const std::vector& controls = std::vector()); + + /** + * @return The entry's DN + */ + std::string getObjectName() const; + + /** + * @return The entry's attributes + */ + std::vector getAttributes() const; + + template bool tryGet(Method method, ResultType& result) + { + return internalTryGet(this, method, result); + } + + protected: + friend LdapLayer* LdapLayer::parseLdapMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + static constexpr int objectNameIndex = 0; + static constexpr int attributesIndex = 1; + static constexpr int attributeTypeIndex = 0; + static constexpr int attributeValueIndex = 1; + + LdapSearchResultEntryLayer(std::unique_ptr asn1Record, uint8_t* data, size_t dataLen, + Layer* prevLayer, Packet* packet) + : LdapLayer(std::move(asn1Record), data, dataLen, prevLayer, packet) + {} + }; + + /** + * @class LdapSearchResultDoneLayer + * Represents LDAP search result done message + */ + class LdapSearchResultDoneLayer : public LdapResponseLayer + { + public: + /** + * A constructor to create a new LDAP search result done message + * @param[in] messageId The LDAP message ID + * @param[in] resultCode The LDAP result code + * @param[in] matchedDN The distinguished name (DN) to set on the message. If not applicable + * pass an empty string + * @param[in] diagnosticMessage The additional information to set on the message. If not applicable + * pass an empty string + * @param[in] referral A list of URIs to re-try the operation somewhere else. This is an optional + * parameter. If not provided then referral won't be added to the message + * @param[in] controls A vector of LDAP controls. This is an optional parameter, if not provided the message + * will be created without LDAP controls + */ + LdapSearchResultDoneLayer(uint16_t messageId, LdapResultCode resultCode, const std::string& matchedDN, + const std::string& diagnosticMessage, + const std::vector& referral = std::vector(), + const std::vector& controls = std::vector()) + : LdapResponseLayer(messageId, LdapOperationType::SearchResultDone, resultCode, matchedDN, + diagnosticMessage, referral, controls) + {} + + protected: + friend LdapLayer* LdapLayer::parseLdapMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + LdapSearchResultDoneLayer(std::unique_ptr asn1Record, uint8_t* data, size_t dataLen, + Layer* prevLayer, Packet* packet) + : LdapResponseLayer(std::move(asn1Record), data, dataLen, prevLayer, packet) + {} + }; + + /** + * @class LdapModifyResponseLayer + * Represents LDAP modify response message + */ + class LdapModifyResponseLayer : public LdapResponseLayer + { + public: + /** + * A constructor to create a new LDAP modify response message + * @param[in] messageId The LDAP message ID + * @param[in] resultCode The LDAP result code + * @param[in] matchedDN The distinguished name (DN) to set on the message. If not applicable + * pass an empty string + * @param[in] diagnosticMessage The additional information to set on the message. If not applicable + * pass an empty string + * @param[in] referral A list of URIs to re-try the operation somewhere else. This is an optional + * parameter. If not provided then referral won't be added to the message + * @param[in] controls A vector of LDAP controls. This is an optional parameter, if not provided the message + * will be created without LDAP controls + */ + LdapModifyResponseLayer(uint16_t messageId, LdapResultCode resultCode, const std::string& matchedDN, + const std::string& diagnosticMessage, + const std::vector& referral = std::vector(), + const std::vector& controls = std::vector()) + : LdapResponseLayer(messageId, LdapOperationType::ModifyResponse, resultCode, matchedDN, diagnosticMessage, + referral, controls) + {} + + protected: + friend LdapLayer* LdapLayer::parseLdapMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + LdapModifyResponseLayer(std::unique_ptr asn1Record, uint8_t* data, size_t dataLen, Layer* prevLayer, + Packet* packet) + : LdapResponseLayer(std::move(asn1Record), data, dataLen, prevLayer, packet) + {} + }; + + /** + * @class LdapAddResponseLayer + * Represents LDAP add response message + */ + class LdapAddResponseLayer : public LdapResponseLayer + { + public: + /** + * A constructor to create a new LDAP add response message + * @param[in] messageId The LDAP message ID + * @param[in] resultCode The LDAP result code + * @param[in] matchedDN The distinguished name (DN) to set on the message. If not applicable + * pass an empty string + * @param[in] diagnosticMessage The additional information to set on the message. If not applicable + * pass an empty string + * @param[in] referral A list of URIs to re-try the operation somewhere else. This is an optional + * parameter. If not provided then referral won't be added to the message + * @param[in] controls A vector of LDAP controls. This is an optional parameter, if not provided the message + * will be created without LDAP controls + */ + LdapAddResponseLayer(uint16_t messageId, LdapResultCode resultCode, const std::string& matchedDN, + const std::string& diagnosticMessage, + const std::vector& referral = std::vector(), + const std::vector& controls = std::vector()) + : LdapResponseLayer(messageId, LdapOperationType::AddResponse, resultCode, matchedDN, diagnosticMessage, + referral, controls) + {} + + protected: + friend LdapLayer* LdapLayer::parseLdapMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + LdapAddResponseLayer(std::unique_ptr asn1Record, uint8_t* data, size_t dataLen, Layer* prevLayer, + Packet* packet) + : LdapResponseLayer(std::move(asn1Record), data, dataLen, prevLayer, packet) + {} + }; + + /** + * @class LdapDeleteResponseLayer + * Represents LDAP delete response message + */ + class LdapDeleteResponseLayer : public LdapResponseLayer + { + public: + /** + * A constructor to create a new LDAP delete response message + * @param[in] messageId The LDAP message ID + * @param[in] resultCode The LDAP result code + * @param[in] matchedDN The distinguished name (DN) to set on the message. If not applicable + * pass an empty string + * @param[in] diagnosticMessage The additional information to set on the message. If not applicable + * pass an empty string + * @param[in] referral A list of URIs to re-try the operation somewhere else. This is an optional + * parameter. If not provided then referral won't be added to the message + * @param[in] controls A vector of LDAP controls. This is an optional parameter, if not provided the message + * will be created without LDAP controls + */ + LdapDeleteResponseLayer(uint16_t messageId, LdapResultCode resultCode, const std::string& matchedDN, + const std::string& diagnosticMessage, + const std::vector& referral = std::vector(), + const std::vector& controls = std::vector()) + : LdapResponseLayer(messageId, LdapOperationType::DeleteResponse, resultCode, matchedDN, diagnosticMessage, + referral, controls) + {} + + protected: + friend LdapLayer* LdapLayer::parseLdapMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + LdapDeleteResponseLayer(std::unique_ptr asn1Record, uint8_t* data, size_t dataLen, Layer* prevLayer, + Packet* packet) + : LdapResponseLayer(std::move(asn1Record), data, dataLen, prevLayer, packet) + {} + }; + + /** + * @class LdapModifyDNResponseLayer + * Represents LDAP modify DN response message + */ + class LdapModifyDNResponseLayer : public LdapResponseLayer + { + public: + /** + * A constructor to create a new LDAP modify DN response message + * @param[in] messageId The LDAP message ID + * @param[in] resultCode The LDAP result code + * @param[in] matchedDN The distinguished name (DN) to set on the message. If not applicable + * pass an empty string + * @param[in] diagnosticMessage The additional information to set on the message. If not applicable + * pass an empty string + * @param[in] referral A list of URIs to re-try the operation somewhere else. This is an optional + * parameter. If not provided then referral won't be added to the message + * @param[in] controls A vector of LDAP controls. This is an optional parameter, if not provided the message + * will be created without LDAP controls + */ + LdapModifyDNResponseLayer(uint16_t messageId, LdapResultCode resultCode, const std::string& matchedDN, + const std::string& diagnosticMessage, + const std::vector& referral = std::vector(), + const std::vector& controls = std::vector()) + : LdapResponseLayer(messageId, LdapOperationType::ModifyDNResponse, resultCode, matchedDN, + diagnosticMessage, referral, controls) + {} + + protected: + friend LdapLayer* LdapLayer::parseLdapMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + LdapModifyDNResponseLayer(std::unique_ptr asn1Record, uint8_t* data, size_t dataLen, + Layer* prevLayer, Packet* packet) + : LdapResponseLayer(std::move(asn1Record), data, dataLen, prevLayer, packet) + {} + }; + + /** + * @class LdapCompareResponseLayer + * Represents LDAP compare response message + */ + class LdapCompareResponseLayer : public LdapResponseLayer + { + public: + /** + * A constructor to create a new LDAP compare response message + * @param[in] messageId The LDAP message ID + * @param[in] resultCode The LDAP result code + * @param[in] matchedDN The distinguished name (DN) to set on the message. If not applicable + * pass an empty string + * @param[in] diagnosticMessage The additional information to set on the message. If not applicable + * pass an empty string + * @param[in] referral A list of URIs to re-try the operation somewhere else. This is an optional + * parameter. If not provided then referral won't be added to the message + * @param[in] controls A vector of LDAP controls. This is an optional parameter, if not provided the message + * will be created without LDAP controls + */ + LdapCompareResponseLayer(uint16_t messageId, LdapResultCode resultCode, const std::string& matchedDN, + const std::string& diagnosticMessage, + const std::vector& referral = std::vector(), + const std::vector& controls = std::vector()) + : LdapResponseLayer(messageId, LdapOperationType::CompareResponse, resultCode, matchedDN, diagnosticMessage, + referral, controls) + {} + + protected: + friend LdapLayer* LdapLayer::parseLdapMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + LdapCompareResponseLayer(std::unique_ptr asn1Record, uint8_t* data, size_t dataLen, + Layer* prevLayer, Packet* packet) + : LdapResponseLayer(std::move(asn1Record), data, dataLen, prevLayer, packet) + {} + }; +} // namespace pcpp + +inline std::ostream& operator<<(std::ostream& os, const pcpp::LdapControl& control) +{ + os << "{" << control.controlType << ", " << control.controlValue << "}"; + return os; +} + +inline std::ostream& operator<<(std::ostream& os, const pcpp::LdapAttribute& attr) +{ + os << "{" << attr.type << ", {"; + + std::string separator; + for (const auto& value : attr.values) + { + os << separator << value; + if (separator.empty()) + { + separator = ", "; + } + } + + os << "}}"; + return os; +} + +inline std::ostream& operator<<(std::ostream& os, + const pcpp::LdapBindRequestLayer::SaslAuthentication& saslAuthentication) +{ + os << "{" << saslAuthentication.mechanism << ", {"; + + std::string separator; + for (const auto& value : saslAuthentication.credentials) + { + os << separator << "0x" << std::hex << static_cast(value) << std::dec; + if (separator.empty()) + { + separator = ", "; + } + } + + os << "}}"; + return os; +} diff --git a/Packet++/header/pcapplusplus/MplsLayer.h b/Packet++/header/pcapplusplus/MplsLayer.h new file mode 100644 index 0000000000..5498d0b3d9 --- /dev/null +++ b/Packet++/header/pcapplusplus/MplsLayer.h @@ -0,0 +1,141 @@ +#pragma once + +#include "pcapplusplus/Layer.h" + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * @class MplsLayer + * Represents a MPLS (Multi-Protocol Label Switching) layer + */ + class MplsLayer : public Layer + { + private: +#pragma pack(push, 1) + struct mpls_header + { + uint16_t hiLabel; + uint8_t misc; + uint8_t ttl; + }; +#pragma pack(pop) + + mpls_header* getMplsHeader() const + { + return (mpls_header*)m_Data; + } + + public: + /** A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + MplsLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : Layer(data, dataLen, prevLayer, packet, MPLS) + {} + + /** + * A constructor that allocates a new MPLS header + * @param[in] mplsLabel MPLS label + * @param[in] ttl Time-to-leave value + * @param[in] experimentalUseValue Experimental use value + * @param[in] bottomOfStack Bottom-of-stack value which indicate whether the next layer will also be a MPLS + * label or not + */ + MplsLayer(uint32_t mplsLabel, uint8_t ttl, uint8_t experimentalUseValue, bool bottomOfStack); + + virtual ~MplsLayer() + {} + + /** + * @return TTL value of the MPLS header + */ + uint8_t getTTL() const + { + return getMplsHeader()->ttl; + } + + /** + * Set the TTL value + * @param[in] ttl The TTL value to set + */ + void setTTL(uint8_t ttl) + { + getMplsHeader()->ttl = ttl; + } + + /** + * Get an indication whether the next layer is also be a MPLS label or not + * @return True if it's the last MPLS layer, false otherwise + */ + bool isBottomOfStack() const; + + /** + * Set the bottom-of-stack bit in the MPLS label + * @param[in] val Set or unset the bit + */ + void setBottomOfStack(bool val); + + /** + * @return The exp value (3 bits) of the MPLS label + */ + uint8_t getExperimentalUseValue() const; + + /** + * Set the exp value (3 bits) of the MPLS label + * @param[in] val The exp value to set. val must be a valid number meaning between 0 and 7 (inclusive) + * @return True if exp value was set successfully or false if val has invalid value + */ + bool setExperimentalUseValue(uint8_t val); + + /** + * @return The MPLS label value (20 bits) + */ + uint32_t getMplsLabel() const; + + /** + * Set the MPLS label (20 bits) + * @param[in] label The label to set. label must be a valid number meaning between 0 and 0xFFFFF (inclusive) + * @return True if label was set successfully or false if label has invalid value + */ + bool setMplsLabel(uint32_t label); + + // implement abstract methods + + /** + * Currently identifies the following next layers: IPv4Layer, IPv6Layer, MplsLayer. Otherwise sets PayloadLayer + */ + void parseNextLayer(); + + /** + * @return Size of MPLS header (4 bytes) + */ + size_t getHeaderLen() const + { + return sizeof(mpls_header); + } + + /** + * Set/unset the bottom-of-stack bit according to next layer: if it's a MPLS layer then bottom-of-stack will be + * unset. If it's not a MPLS layer this bit will be set + */ + void computeCalculateFields(); + + std::string toString() const; + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelNetworkLayer; + } + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/NdpLayer.h b/Packet++/header/pcapplusplus/NdpLayer.h new file mode 100644 index 0000000000..e05cfbb26c --- /dev/null +++ b/Packet++/header/pcapplusplus/NdpLayer.h @@ -0,0 +1,411 @@ +#pragma once + +#include "pcapplusplus/IcmpV6Layer.h" +#include "pcapplusplus/IpAddress.h" +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/MacAddress.h" +#include "pcapplusplus/TLVData.h" + +#include + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * An enum representing the available option types for Neighbor Discovery in IPv6 (see RFC 4861) + */ + enum class NDPNeighborOptionTypes : int + { + NDP_OPTION_SOURCE_LINK_LAYER = 1, + NDP_OPTION_TARGET_LINK_LAYER = 2, + NDP_OPTION_PREFIX_INFORMATION = 3, + NDP_OPTION_REDIRECTED_HEADER = 4, + NDP_OPTION_MTU = 5, + NDP_OPTION_UNKNOWN = 255 + }; + + /** + * @class NdpOption + * A wrapper class for NDP options. This class does not create or modify NDP option records, but rather + * serves as a wrapper and provides useful methods for retrieving data from them + */ + class NdpOption : public TLVRecord + { + public: + /** + * A c'tor for this class that gets a pointer to the option raw data (byte array) + * @param[in] optionRawData A pointer to the NDP option raw data + */ + explicit NdpOption(uint8_t* optionRawData) : TLVRecord(optionRawData) + {} + + /** + * A d'tor for this class, currently does nothing + */ + ~NdpOption() + {} + + /** + * @return NDP option type casted as pcpp::NDPNeighborOptionTypes enum. If the data is null a value + * of NDP_OPTION_UNKNOWN is returned + */ + NDPNeighborOptionTypes getNdpOptionType() const + { + if (m_Data == nullptr) + return NDPNeighborOptionTypes::NDP_OPTION_UNKNOWN; + + return static_cast(m_Data->recordType); + } + + // implement abstract methods + + size_t getTotalSize() const + { + if (m_Data == nullptr) + return (size_t)0; + + return (size_t)m_Data->recordLen * 8; + } + + size_t getDataSize() const + { + if (m_Data == nullptr) + { + return 0; + } + + // length value is stored in units of 8 octets + return (size_t)m_Data->recordLen * 8 - (2 * sizeof(uint8_t)); + } + }; + + /** + * @class NdpOptionBuilder + * A class for building NDP option records. This builder receives the NDP option parameters in its c'tor, + * builds the NDP option raw buffer and provides a build() method to get a NdpOption object out of it + */ + class NdpOptionBuilder : public TLVRecordBuilder + { + public: + /** + * A c'tor for building NDP options which their value is a byte array. The NdpOption object can be later + * retrieved by calling build(). Each option is padded to have a 64-bit boundary. + * @param[in] optionType NDP option type + * @param[in] optionValue A buffer containing the option value. This buffer is read-only and isn't modified in + * any way. + * @param[in] optionValueLen Option value length in bytes + */ + NdpOptionBuilder(NDPNeighborOptionTypes optionType, const uint8_t* optionValue, uint8_t optionValueLen) + : TLVRecordBuilder((uint8_t)optionType, optionValue, optionValueLen) + {} + + /** + * Build the NdpOption object out of the parameters defined in the c'tor. Padding bytes are added to the + * option for option length with 64-bit boundaries. + * @return The NdpOption object + */ + NdpOption build() const; + }; + + /** + * @class NDPLayerBase + * Represents a base for NDP packet types + */ + class NDPLayerBase : public IcmpV6Layer + { + public: + virtual ~NDPLayerBase() + {} + + /** + * @return The number of NDP options in this layer + */ + size_t getNdpOptionCount() const; + + /** + * Get a NDP option by type. + * @param[in] option NDP option type + * @return An NdpOption object that contains the first option that matches this type, or logical null + * (NdpOption#isNull() == true) if no such option found + */ + NdpOption getNdpOption(NDPNeighborOptionTypes option) const; + + /** + * @return The first NDP option in the packet. If the current layer contains no options the returned value will + * contain a logical null (NdpOption#isNull() == true) + */ + NdpOption getFirstNdpOption() const; + + /** + * Get the NDP option that comes after a given option. If the given option was the last one, the + * returned value will contain a logical null (IdpOption#isNull() == true) + * @param[in] option An NDP option object that exists in the current layer + * @return A NdpOption object that contains the NDP option data that comes next, or logical null if the given + * NDP option: (1) was the last one; or (2) contains a logical null; or (3) doesn't belong to this packet + */ + NdpOption getNextNdpOption(NdpOption& option) const; + + /** + * Add a new NDP option at the end of the layer (after the last NDP option) + * @param[in] optionBuilder An NdpOptionBuilder object that contains the NDP option data to be added + * @return A NdpOption object that contains the newly added NDP option data or logical null + * (NdpOption#isNull() == true) if addition failed. In case of a failure a corresponding error message will be + * printed to log + */ + NdpOption addNdpOption(const NdpOptionBuilder& optionBuilder); + + /** + * Remove all NDP options from the layer + * @return True if options removed successfully or false if some error occurred (an appropriate error message + * will be printed to log) + */ + bool removeAllNdpOptions(); + + protected: + NDPLayerBase() = default; + + NDPLayerBase(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : IcmpV6Layer(data, dataLen, prevLayer, packet) + {} + + private: + TLVRecordReader m_OptionReader; + + virtual size_t getNdpHeaderLen() const = 0; + virtual uint8_t* getNdpOptionsBasePtr() const + { + return m_Data + getNdpHeaderLen(); + }; + NdpOption addNdpOptionAt(const NdpOptionBuilder& optionBuilder, int offset); + }; + + /** + * @class NDPNeighborSolicitationLayer + * Represents a NDP Neighbor Solicitation protocol layer + */ + class NDPNeighborSolicitationLayer : public NDPLayerBase + { + public: + /** + * @struct ndpneighborsolicitationhdr + * Represents neighbor solicitation message format + */ +#pragma pack(push, 1) + struct ndpneighborsolicitationhdr : icmpv6hdr + { + /** Reserved */ + uint32_t reserved; + /** Target address - Target address of solicitation message */ + uint8_t targetIP[16]; + }; +#pragma pack(pop) + + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + NDPNeighborSolicitationLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : NDPLayerBase(data, dataLen, prevLayer, packet) + {} + + /** + * A constructor for a new NDPNeighborSolicitationLayer object + * @param[in] code Code field + * @param[in] targetIP Target IP address for which the solicitation shall be created + */ + NDPNeighborSolicitationLayer(uint8_t code, const IPv6Address& targetIP); + + /** + * A constructor for a new NDPNeighborSolicitationLayer object + * @param[in] code Code field + * @param[in] targetIP Target IP address for which the solicitation shall be created + * @param[in] srcMac Mac address which shall be put in the linklayer option + */ + NDPNeighborSolicitationLayer(uint8_t code, const IPv6Address& targetIP, const MacAddress& srcMac); + + virtual ~NDPNeighborSolicitationLayer() + {} + + /** + * @return Get the IP address specified as the target IP address in the solicitation message + */ + IPv6Address getTargetIP() const + { + return IPv6Address(getNdpHeader()->targetIP); + }; + + /** + * Checks if the layer has a link layer address option set + * @return true if link layer address option is available, false otherwise + */ + bool hasLinkLayerAddress() const; + + /** + * Get the Link Layer Address + * @return Mac address which is specified in the link layer address option + */ + MacAddress getLinkLayerAddress() const; + + std::string toString() const; + + private: + void initLayer(uint8_t code, const IPv6Address& targetIP); + ndpneighborsolicitationhdr* getNdpHeader() const + { + return (ndpneighborsolicitationhdr*)m_Data; + } + size_t getNdpHeaderLen() const + { + return sizeof(ndpneighborsolicitationhdr); + }; + }; + + /** + * @class NDPNeighborAdvertisementLayer + * Represents a NDP Neighbor Advertisement protocol layer + */ + class NDPNeighborAdvertisementLayer : public NDPLayerBase + { + public: + /** + * @struct ndpneighboradvertisementhdr + * Represents neighbor advertisement message format + */ +#pragma pack(push, 1) + struct ndpneighboradvertisementhdr : icmpv6hdr + { +#if (BYTE_ORDER == LITTLE_ENDIAN) + uint32_t + /** Unused field */ + reserved : 5, + /** Flag indicating that this entry should override the old one */ + override : 1, + /** Flag indicating that the advertisement was sent in response to a Neighbor Solicitation from the + Destination address */ + solicited : 1, + /** Flag indicating that the advertisement is sent by a router */ + router : 1, + /** Unused field */ + reserved2 : 24; +#else + uint32_t + /** Flag indicating that the advertisement is sent by a router */ + router : 1, + /** Flag indicating that the advertisement was sent in response to a Neighbor Solicitation from the + Destination address */ + solicited : 1, + /** Flag indicating that this entry should override the old one */ + override : 1, + /** Unused field */ + reserved : 29; +#endif + /** Target address - Either source address of advertisement or address for requested MAC */ + uint8_t targetIP[16]; + }; +#pragma pack(pop) + + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + NDPNeighborAdvertisementLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : NDPLayerBase(data, dataLen, prevLayer, packet) + {} + + /** + * A constructor that allocates a new NDP Advertisement Layer with target link-layer address option + * @param[in] code Code field + * @param[in] targetIP The target IP address from the Neighbor Solicitation message (solicited advertisements) + * or the address whose link-layer address has changed (unsolicited advertisement) + * @param[in] targetMac Adds the target link-layer address into the option field of the layer + * @param[in] routerFlag The router flag + * @param[in] unicastFlag The solicited flag + * @param[in] overrideFlag The override flag + */ + NDPNeighborAdvertisementLayer(uint8_t code, const IPv6Address& targetIP, const MacAddress& targetMac, + bool routerFlag, bool unicastFlag, bool overrideFlag); + + /** + * A constructor that allocates a new NDP Advertisement Layer + * @param code Code field + * @param targetIP The target IP address from the Neighbor Solicitation message (solicited advertisements) or + * the address whose link-layer address has changed (unsolicited advertisement) + * @param routerFlag The router flag + * @param unicastFlag The solicited flag + * @param overrideFlag The override flag + */ + NDPNeighborAdvertisementLayer(uint8_t code, const IPv6Address& targetIP, bool routerFlag, bool unicastFlag, + bool overrideFlag); + + virtual ~NDPNeighborAdvertisementLayer() + {} + + /** + * @return Get the target MAC address + */ + MacAddress getTargetMac() const; + + /** + * @return Get the target IP address + */ + IPv6Address getTargetIP() const + { + return IPv6Address(getNdpHeader()->targetIP); + } + + /** + * @return Get information if the target link-layer address was added in the option field of the header + */ + bool hasTargetMacInfo() const; + + /** + * @return Get the router flag + */ + bool getRouterFlag() const + { + return getNdpHeader()->router; + } + + /** + * @return Get the unicast flag + */ + bool getUnicastFlag() const + { + return getNdpHeader()->solicited; + } + + /** + * @return Get the override flag + */ + bool getOverrideFlag() const + { + return getNdpHeader()->override; + } + + std::string toString() const; + + private: + void initLayer(uint8_t code, const IPv6Address& targetIP, bool routerFlag, bool unicastFlag, bool overrideFlag); + ndpneighboradvertisementhdr* getNdpHeader() const + { + return (ndpneighboradvertisementhdr*)m_Data; + } + size_t getNdpHeaderLen() const + { + return sizeof(ndpneighboradvertisementhdr); + }; + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/NflogLayer.h b/Packet++/header/pcapplusplus/NflogLayer.h new file mode 100644 index 0000000000..8c4fbb85c1 --- /dev/null +++ b/Packet++/header/pcapplusplus/NflogLayer.h @@ -0,0 +1,263 @@ +#pragma once + +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/TLVData.h" +#include "pcapplusplus/GeneralUtils.h" + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + /** + * @struct nflog_header + * Represents Nflog header + */ +#pragma pack(push, 1) + struct nflog_header + { + /** A Linux AF_ value, so it's 2 for IPv4 and 10 for IPv6 */ + uint8_t addressFamily; + /** The version field is 0 for the current version of the pseudo-header */ + uint8_t version; + /** The network byte order (big-endian) */ + uint16_t resourceId; + }; +#pragma pack(pop) + + /** + * @enum NflogTlvType + * Represents TLV types of NFLOG packets + */ + enum class NflogTlvType + { + /** the packet header structure */ + NFULA_PACKET_HDR = 1, + /** packet mark from skbuff */ + NFULA_MARK = 2, + /** nflog_timestamp_t for skbuff's time stamp */ + NFULA_TIMESTAMP = 3, + /** ifindex of device on which packet received (possibly bridge group) */ + NFULA_IFINDEX_INDEV = 4, + /** ifindex of device on which packet transmitted (possibly bridge group) */ + NFULA_IFINDEX_OUTDEV = 5, + /** ifindex of physical device on which packet received (not bridge group) */ + NFULA_IFINDEX_PHYSINDEV = 6, + /** ifindex of physical device on which packet transmitted (not bridge group) */ + NFULA_IFINDEX_PHYSOUTDEV = 7, + /** nflog_hwaddr_t for hardware address */ + NFULA_HWADDR = 8, + /** packet payload */ + NFULA_PAYLOAD = 9, + /** text string - null-terminated, count includes NUL */ + NFULA_PREFIX = 10, + /** UID owning socket on which packet was sent/received */ + NFULA_UID = 11, + /** sequence number of packets on this NFLOG socket */ + NFULA_SEQ = 12, + /** sequence number of packets on all NFLOG sockets */ + NFULA_SEQ_GLOBAL = 13, + /** GID owning socket on which packet was sent/received */ + NFULA_GID = 14, + /** ARPHRD_ type of skbuff's device */ + NFULA_HWTYPE = 15, + /** skbuff's MAC-layer header */ + NFULA_HWHEADER = 16, + /** length of skbuff's MAC-layer header */ + NFULA_HWLEN = 17, + }; + + /** + * @class NflogTlv + * A wrapper class for NFLOG TLV fields. This class does not create or modify TLVs related to NFLOG, but rather + * serves as a wrapper and provides useful methods for setting and retrieving data to/from them + */ + class NflogTlv + { + private: + struct NflogTLVRawData + { + /** Record length in bytes */ + uint16_t recordLen; + /** Record type */ + uint16_t recordType; + /** Record value (variable size) */ + uint8_t recordValue[]; + }; + NflogTLVRawData* m_Data; + + public: + /** + * A c'tor for this class that gets a pointer to the option raw data (byte array) + * @param[in] recordRawData A pointer to the option raw data + */ + explicit NflogTlv(uint8_t* recordRawData) + { + assign(recordRawData); + } + + /** + * @return recordLen attribute in NflogTLVRawData + */ + size_t getTotalSize() const + { + // as in + // https://github.com/the-tcpdump-group/libpcap/blob/766b607d60d8038087b49fc4cf433dac3dcdb49c/pcap-util.c#L371-L374 + return align<4>(m_Data->recordLen); + } + + /** + * Assign a pointer to the TLV record raw data (byte array) + * @param[in] recordRawData A pointer to the TLV record raw data + */ + void assign(uint8_t* recordRawData) + { + m_Data = (NflogTLVRawData*)recordRawData; + } + + /** + * Check if a pointer can be assigned to the TLV record data + * @param[in] recordRawData A pointer to the TLV record raw data + * @param[in] tlvDataLen The size of the TLV record raw data + * * @return True if data is valid and can be assigned + */ + static bool canAssign(const uint8_t* recordRawData, size_t tlvDataLen) + { + return recordRawData != nullptr && tlvDataLen >= sizeof(NflogTLVRawData::recordLen); + } + + /** + * @return True if the TLV record raw data is nullptr, false otherwise + */ + bool isNull() const + { + return (m_Data == nullptr); + } + + /** + * @return The type field of the record (the 'T' in __Type__-Length-Value) + */ + uint16_t getType() const + { + return m_Data->recordType; + } + + /** + * @return A pointer to the TLV record raw data byte stream + */ + uint8_t* getRecordBasePtr() const + { + return (uint8_t*)m_Data; + } + + /** + * @return A pointer to the value of the record as byte array (the 'V' in Type-Length- __Value__) + */ + uint8_t* getValue() const + { + return m_Data->recordValue; + } + }; + + /** + * @class NflogLayer + * Represents an NFLOG protocol layer + */ + class NflogLayer : public Layer + { + public: + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data (will be casted to ether_header) + * @param[in] dataLen Size of the data in bytes + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + NflogLayer(uint8_t* data, size_t dataLen, Packet* packet) : Layer(data, dataLen, nullptr, packet, NFLOG) + {} + + ~NflogLayer() + {} + + /** + * Get a pointer to the Nflog header. + * @return A pointer to the nflog_header + */ + nflog_header* getNflogHeader() const + { + return (nflog_header*)m_Data; + } + + /** + * Get address family of the packet. e.g. 2 for ipv4 and 10 for ipv6 + * @return an unsigned char of address family + */ + uint8_t getFamily(); + + /** + * Get Version number inside packet header + * The version field is 0 for the current version of the pseudo-header + * @return an unsigned char for version + */ + uint8_t getVersion(); + + /** + * Get Resource Id in packet header + * On one netlink socket it's possible to listen to several nflog groups; the resource ID is the nflog group for + * the packet + */ + uint16_t getResourceId(); + + /** + * Get a TLV object found with the input type. if no tlv is found, the internal value of the object will set to + * nullptr + * @param[in] type type of tlv by using enum class defined as NflogTlvType + * @return NflogTlv obtained by type + */ + NflogTlv getTlvByType(NflogTlvType type) const; + + // implement abstract methods + + /** + * Currently identifies the following next layers: IPv4Layer, IPv6Layer using address family + * Otherwise sets PayloadLayer + */ + void parseNextLayer(); + + /** + * @return Size of nflog_header + */ + size_t getHeaderLen() const; + + /** + * Does nothing for this layer + */ + void computeCalculateFields() {}; + + std::string toString() const; + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelDataLinkLayer; + } + + /** + * A static method that validates the input data + * @param[in] data The pointer to the beginning of a byte stream of an NFLOG packet + * @param[in] dataLen The length of the byte stream + * @return True if the data is valid and can represent an NFLOG packet + */ + static bool isDataValid(const uint8_t* data, size_t dataLen); + + private: + uint8_t* getTlvsBasePtr() const + { + return m_Data + sizeof(nflog_header); + } + + TLVRecordReader m_TlvReader; + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/NtpLayer.h b/Packet++/header/pcapplusplus/NtpLayer.h new file mode 100644 index 0000000000..b22845a9f9 --- /dev/null +++ b/Packet++/header/pcapplusplus/NtpLayer.h @@ -0,0 +1,701 @@ +#pragma once + +#include "pcapplusplus/Logger.h" +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/IpAddress.h" + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + /** + * @class NtpLayer + * Represents a NTP (Network Time Protocol) layer + * + * @brief The NTP packet consists of an integral number of 32-bit (4 octet) words in network byte order. + * The packet format consists of three components: the header itself, one or more optional extension fields (for + * v4), and an optional message authentication code (MAC). Currently the extension fields are not supported. The NTP + * header is: + * + * @verbatim + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |LI | VN |Mode | Stratum | Poll | Precision | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Root Delay | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Root Dispersion | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Reference ID | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + + Reference Timestamp (64) + + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + + Origin Timestamp (64) + + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + + Receive Timestamp (64) + + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + + Transmit Timestamp (64) + + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + . . + . Extension Field 1 (variable, only v4) . + . . + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + . . + . Extension Field 1 (variable, only v4) . + . . + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Key Identifier | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + | dgst (128 for v4, 64 for v3) | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + @endverbatim + * + */ + class NtpLayer : public Layer + { + private: +#pragma pack(push, 1) + struct ntp_header + { +#if (BYTE_ORDER == LITTLE_ENDIAN) + /// 3-bit integer representing the mode + uint8_t mode : 3, + /// 3-bit integer representing the NTP version number + version : 3, + /// LI Leap Indicator (leap): 2-bit integer warning of an impending leap second to be inserted or + /// deleted in the last minute of the current month + leapIndicator : 2; +#else + /// LI Leap Indicator (leap): 2-bit integer warning of an impending leap second to be inserted or deleted in + /// the last minute of the current month + uint8_t leapIndicator : 2, + /// 3-bit integer representing the NTP version number + version : 3, + /// 3-bit integer representing the mode + mode : 3; +#endif + /// 8-bit integer representing the stratum + uint8_t stratum; + /// Total round-trip delay to the reference clock, in log2 seconds. + int8_t pollInterval, + /// 8-bit signed integer representing the precision of the system clock, in log2 seconds. + precision; + /// Total round-trip delay to the reference clock, in NTP short format. + uint32_t rootDelay, + /// Total dispersion to the reference clock, in NTP short format. + rootDispersion, + /// 32-bit code identifying the particular server or reference clock. The interpretation depends on the + /// value in the stratum field. + referenceIdentifier; + /// Time when the system clock was last set or corrected, in NTP timestamp format. + uint64_t referenceTimestamp, + /// Time at the client when the request departed for the server, in NTP timestamp format. + originTimestamp, + /// Time at the client when the request departed for the server, in NTP timestamp format. + receiveTimestamp, + /// Time at the server when the response left for the client, in NTP timestamp format. + transmitTimestamp; + }; +#pragma pack(pop) + +#pragma pack(push, 1) + struct ntp_v3_auth + { + /// An integer identifying the cryptographic key used to generate the message-authentication code + uint32_t keyID; + /// This is an integer identifying the cryptographic key used to generate the message-authentication code. + uint8_t dgst[8]; // 64 bit DES based + }; +#pragma pack(pop) + +#pragma pack(push, 1) + struct ntp_v4_auth_md5 + { + /// 32-bit unsigned integer used by the client and server to designate a secret 128-bit MD5 key. + uint32_t keyID; + /// 128-bit MD5 hash + uint8_t dgst[16]; + }; +#pragma pack(pop) + +#pragma pack(push, 1) + struct ntp_v4_auth_sha1 + { + /// 32-bit unsigned integer used by the client and server to designate a secret 160-bit SHA1 key. + uint32_t keyID; + /// 160-bit SHA1 hash + uint8_t dgst[20]; + }; +#pragma pack(pop) + + ntp_header* getNtpHeader() const + { + return (ntp_header*)m_Data; + } + + public: + /** + * Warning of an impending leap second to be inserted or deleted in the last minute of the current month + */ + enum LeapIndicator + { + /// Normal, no leap second + NoWarning = 0, + /// Last minute of the day has 61 seconds + Last61Secs, + /// Last minute of the day has 59 seconds + Last59Secs, + /// Unknown (clock unsynchronized) + Unknown + }; + + /** + * Representing the NTP association modes + */ + enum Mode + { + /// Reserved variable + Reserved = 0, + /// Symmetrically active + SymActive, + /// Symmetrically passive + SymPassive, + /// Client mode + Client, + /// Server mode + Server, + /// Broadcasting mode + Broadcast, + /// NTP control messages + Control, + /// Reserved for private use + PrivateUse + }; + + /** + * 32-bit code identifying the particular server or reference clock. + * The interpretation depends on the value in the stratum field. + */ + enum class ClockSource : uint32_t + { + // NTPv4 + + /// Geosynchronous Orbit Environment Satellite + GOES = ('G') | ('O' << 8) | ('E' << 16) | ('S' << 24), + /// Global Position System + GPS = ('G') | ('P' << 8) | ('S' << 16), + /// Galileo Positioning System + GAL = ('G') | ('A' << 8) | ('L' << 16), + /// Generic pulse-per-second + PPS = ('P') | ('P' << 8) | ('S' << 16), + /// Inter-Range Instrumentation Group + IRIG = ('I') | ('R' << 8) | ('I' << 16) | ('G' << 24), + /// LF Radio WWVB Ft. Collins, CO 60 kHz + WWVB = ('W') | ('W' << 8) | ('V' << 16) | ('B' << 24), + /// LF Radio DCF77 Mainflingen, DE 77.5 kHz + DCF = ('D') | ('C' << 8) | ('F' << 16), + /// LF Radio HBG Prangins, HB 75 kHz + HBG = ('H') | ('B' << 8) | ('G' << 16), + /// LF Radio MSF Anthorn, UK 60 kHz + MSF = ('M') | ('S' << 8) | ('F' << 16), + /// LF Radio JJY Fukushima, JP 40 kHz, Saga, JP 60 kHz + JJY = ('J') | ('J' << 8) | ('Y' << 16), + /// MF Radio LORAN C station, 100 kHz + LORC = ('L') | ('O' << 8) | ('R' << 16) | ('C' << 24), + /// MF Radio Allouis, FR 162 kHz + TDF = ('T') | ('D' << 8) | ('F' << 16), + /// HF Radio CHU Ottawa, Ontario + CHU = ('C') | ('H' << 8) | ('U' << 16), + /// HF Radio WWV Ft. Collins, CO + WWV = ('W') | ('W' << 8) | ('V' << 16), + /// HF Radio WWVH Kauai, HI + WWVH = ('W') | ('W' << 8) | ('V' << 16) | ('H' << 24), + /// NIST telephone modem + NIST = ('N') | ('I' << 8) | ('S' << 16) | ('T' << 24), + /// NIST telephone modem + ACTS = ('A') | ('C' << 8) | ('T' << 16) | ('S' << 24), + /// USNO telephone modem + USNO = ('U') | ('S' << 8) | ('N' << 16) | ('O' << 24), + /// European telephone modem + PTB = ('P') | ('T' << 8) | ('B' << 16), + /// Multi Reference Sources + MRS = ('M') | ('R' << 8) | ('S' << 16), + /// Inter Face Association Changed + XFAC = ('X') | ('F' << 8) | ('A' << 16) | ('C' << 24), + /// Step time change + STEP = ('S') | ('T' << 8) | ('E' << 16) | ('P' << 24), + /// Google Refid used by Google NTP servers as time4.google.com + GOOG = ('G') | ('O' << 8) | ('O' << 16) | ('G' << 24), + /// Meinberg DCF77 with amplitude modulation (Ref: + /// https://www.meinbergglobal.com/english/info/ntp-refid.htm) + DCFa = ('D') | ('C' << 8) | ('F' << 16) | ('a' << 24), + /// Meinberg DCF77 with phase modulation)/pseudo random phase modulation (Ref: + /// https://www.meinbergglobal.com/english/info/ntp-refid.htm) + DCFp = ('D') | ('C' << 8) | ('F' << 16) | ('p' << 24), + /// Meinberg GPS (with shared memory access) (Ref: + /// https://www.meinbergglobal.com/english/info/ntp-refid.htm) + GPSs = ('G') | ('P' << 8) | ('S' << 16) | ('s' << 24), + /// Meinberg GPS (with interrupt based access) (Ref: + /// https://www.meinbergglobal.com/english/info/ntp-refid.htm) + GPSi = ('G') | ('P' << 8) | ('S' << 16) | ('i' << 24), + /// Meinberg GPS/GLONASS (with shared memory access) (Ref: + /// https://www.meinbergglobal.com/english/info/ntp-refid.htm) + GLNs = ('G') | ('L' << 8) | ('N' << 16) | ('s' << 24), + /// Meinberg GPS/GLONASS (with interrupt based access) (Ref: + /// https://www.meinbergglobal.com/english/info/ntp-refid.htm) + GLNi = ('G') | ('L' << 8) | ('N' << 16) | ('i' << 24), + /// Meinberg Undisciplined local clock (Ref: https://www.meinbergglobal.com/english/info/ntp-refid.htm) + LCL = ('L') | ('C' << 8) | ('L' << 16), + /// Meinberg Undisciplined local clock (Ref: https://www.meinbergglobal.com/english/info/ntp-refid.htm) + LOCL = ('L') | ('O' << 8) | ('C' << 16) | ('L' << 24), + + // NTPv3 + + /// DCN routing protocol + DCN = ('D') | ('C' << 8) | ('N' << 16), + /// TSP time protocol + TSP = ('T') | ('S' << 8) | ('P' << 16), + /// Digital Time Service + DTS = ('D') | ('T' << 8) | ('S' << 16), + /// Atomic clock (calibrated) + ATOM = ('A') | ('T' << 8) | ('O' << 16) | ('M' << 24), + /// VLF radio (OMEGA, etc.) + VLF = ('V') | ('L' << 8) | ('F' << 16) + }; + + /** + * 32-bit Kiss of Death (KoD) codes + */ + enum class KissODeath : uint32_t + { + /// The association belongs to a anycast server + ACST = ('A') | ('C' << 8) | ('S' << 16) | ('T' << 24), + /// Server authentication failed + AUTH = ('A') | ('U' << 8) | ('T' << 16) | ('H' << 24), + /// Autokey sequence failed + AUTO = ('A') | ('U' << 8) | ('T' << 16) | ('O' << 24), + /// The association belongs to a broadcast server + BCST = ('B') | ('C' << 8) | ('S' << 16) | ('T' << 24), + /// Cryptographic authentication or identification failed + CRYP = ('C') | ('R' << 8) | ('Y' << 16) | ('P' << 24), + /// Access denied by remote server + DENY = ('D') | ('E' << 8) | ('N' << 16) | ('Y' << 24), + /// Lost peer in symmetric mode + DROP = ('D') | ('R' << 8) | ('O' << 16) | ('P' << 24), + /// Access denied due to local policy + RSTR = ('R') | ('S' << 8) | ('T' << 16) | ('R' << 24), + /// The association has not yet synchronized for the first time + INIT = ('I') | ('N' << 8) | ('I' << 16) | ('T' << 24), + /// The association belongs to a manycast server + MCST = ('M') | ('C' << 8) | ('S' << 16) | ('T' << 24), + /// No key found. Either the key was never installed or is not trusted + NKEY = ('N') | ('K' << 8) | ('E' << 16) | ('Y' << 24), + /// Rate exceeded. The server has temporarily denied access because the client exceeded the rate threshold + RATE = ('R') | ('A' << 8) | ('T' << 16) | ('E' << 24), + /// Somebody is tinkering with the association from a remote host running ntpdc. Not to worry unless some + /// rascal has stolen your keys + RMOT = ('R') | ('M' << 8) | ('O' << 16) | ('T' << 24), + /// A step change in system time has occurred, but the association has not yet resynchronized + STEP = ('S') | ('T' << 8) | ('E' << 16) | ('P' << 24), + }; + + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + NtpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : Layer(data, dataLen, prevLayer, packet, NTP) + {} + + /** + * Empty c'tor + */ + NtpLayer(); + + /** + * @return The leap indicator + */ + LeapIndicator getLeapIndicator() const; + + /** + * Set the leap indicator + */ + void setLeapIndicator(LeapIndicator val); + + /** + * @return The version of NTP + */ + uint8_t getVersion() const; + + /** + * Set the version of NTP + */ + void setVersion(uint8_t val); + + /** + * @return The mode value + */ + Mode getMode() const; + + /** + * @return The mode as string + */ + std::string getModeString() const; + + /** + * Set the mode + */ + void setMode(Mode val); + + /** + * @return The value of stratum + */ + uint8_t getStratum() const; + + /** + * Set the value of stratum + */ + void setStratum(uint8_t val); + + /** + * @return The value of poll interval in log2 seconds + */ + int8_t getPollInterval() const; + + /** + * Set the value of poll interval + * @param[in] val Poll interval in log2 seconds + */ + void setPollInterval(int8_t val); + + /** + * @return The value of poll interval in seconds + */ + double getPollIntervalInSecs() const; + + /** + * @return The value of precision in log2 seconds + */ + int8_t getPrecision() const; + + /** + * Set the value of precision + * @param[in] val Precision in log2 seconds + */ + void setPrecision(int8_t val); + + /** + * @return The value of precision in seconds + */ + double getPrecisionInSecs() const; + + /** + * @return The value of root delay in NTP short format + */ + uint32_t getRootDelay() const; + + /** + * Set the value of root delay + * @param[in] val Root delay in NTP short format + */ + void setRootDelay(uint32_t val); + + /** + * @return The value of root delay in seconds + */ + double getRootDelayInSecs() const; + + /** + * Set the value of root delay + * @param[in] val Root delay in seconds + */ + void setRootDelayInSecs(double val); + + /** + * @return The value of root dispersion in NTP short format + */ + uint32_t getRootDispersion() const; + + /** + * Set the value of root delay + * @param[in] val Root dispersion in NTP short format + */ + void setRootDispersion(uint32_t val); + + /** + * @return The value of root dispersion in seconds + */ + double getRootDispersionInSecs() const; + + /** + * Set the value of root dispersion + * @param[in] val Root dispersion in seconds + */ + void setRootDispersionInSecs(double val); + + /** + * @return The value of reference identifier + */ + uint32_t getReferenceIdentifier() const; + + /** + * Set the value of reference identifier + * @param[in] val Value of the reference identifier as IPv4 address + */ + void setReferenceIdentifier(IPv4Address val); + + /** + * Set the value of reference identifier + * @param[in] val Value of the reference identifier as ClockSource + */ + void setReferenceIdentifier(ClockSource val); + + /** + * Set the value of reference identifier + * @param[in] val Value of the reference identifier as Kiss-O-Death code + */ + void setReferenceIdentifier(KissODeath val); + + /** + * @return The value of reference identifier as a string. String representation of NTP clock source if stratum + * is 1, IPv4 address or MD5 hash of first four octets of IPv6 + */ + std::string getReferenceIdentifierString() const; + + /** + * @return The value of reference timestamp in NTP timestamp format + */ + uint64_t getReferenceTimestamp() const; + + /** + * Set the value of reference timestamp + * @param[in] val Timestamp in NTP timestamp format + */ + void setReferenceTimestamp(uint64_t val); + + /** + * @return The value of reference timestamp in seconds from Unix Epoch (1 Jan 1970) + */ + double getReferenceTimestampInSecs() const; + + /** + * Set the value of reference timestamp + * @param[in] val Value in seconds from Unix Epoch (1 Jan 1970) + */ + void setReferenceTimestampInSecs(double val); + + /** + * @return The reference timestamp value as readable string in ISO8601 format + */ + std::string getReferenceTimestampAsString(); + + /** + * @return The value of origin timestamp in NTP timestamp format + */ + uint64_t getOriginTimestamp() const; + + /** + * Set the value of origin timestamp + * @param[in] val Value in NTP timestamp format + */ + void setOriginTimestamp(uint64_t val); + + /** + * @return The value of origin timestamp in seconds from Unix Epoch (1 Jan 1970) + */ + double getOriginTimestampInSecs() const; + + /** + * Set the value of origin timestamp + * @param[in] val Value in seconds from Unix Epoch (1 Jan 1970) + */ + void setOriginTimestampInSecs(double val); + + /** + * @return the origin timestamp value as readable string in ISO8601 format + */ + std::string getOriginTimestampAsString(); + + /** + * @return The value of receive timestamp in NTP timestamp format + */ + uint64_t getReceiveTimestamp() const; + + /** + * Set the value of receive timestamp + * @param[in] val Value in NTP timestamp format + */ + void setReceiveTimestamp(uint64_t val); + + /** + * @return The value of receive timestampin seconds from Unix Epoch (1 Jan 1970) + */ + double getReceiveTimestampInSecs() const; + + /** + * Set the value of receive timestamp + * @param[in] val Value in seconds from Unix Epoch (1 Jan 1970) + */ + void setReceiveTimestampInSecs(double val); + + /** + * @return The receive timestamp value as readable string in ISO8601 format + */ + std::string getReceiveTimestampAsString(); + + /** + * @return The value of transmit timestamp in NTP timestamp format + */ + uint64_t getTransmitTimestamp() const; + + /** + * Set the value of transmit timestamp + * @param[in] val Value in NTP timestamp format + */ + void setTransmitTimestamp(uint64_t val); + + /** + * @return The value of transmit timestamp in seconds from Unix Epoch (1 Jan 1970) + */ + double getTransmitTimestampInSecs() const; + + /** + * Set the value of transmit timestamp + * @param[in] val Value in seconds from Unix Epoch (1 Jan 1970) + */ + void setTransmitTimestampInSecs(double val); + + /** + * @return The transmit timestamp value as readable string in ISO8601 format + */ + std::string getTransmitTimestampAsString(); + + /** + * @return Returns the key identifier if exists, returns 0 on unsupported NTP version or key identifier not + * found + */ + uint32_t getKeyID() const; + + /** + * @return Get the digest value as hexadecimal string, empty string on unsupported version + */ + std::string getDigest() const; + + /** + * Convert NTP short format to seconds from the Unix Epoch + * + * @param[in] val Value in NTP short format + * @return Value in seconds from Unix Epoch (1 Jan 1970) + */ + static double convertFromShortFormat(const uint32_t val); + + /** + * Convert NTP timestamp format to seconds from the Unix Epoch + * + * @param[in] val Value in NTP timestamp format + * @return Value in seconds from Unix Epoch (1 Jan 1970) + */ + static double convertFromTimestampFormat(const uint64_t val); + + /** + * Convert seconds from the Unix Epoch to NTP short format + * + * @param[in] val Value in seconds from Unix Epoch (1 Jan 1970) + * @return Value in NTP short format + */ + static uint32_t convertToShortFormat(const double val); + + /** + * Convert seconds from the Unix Epoch to NTP timestamp format + * + * @param[in] val Value in seconds from Unix Epoch (1 Jan 1970) + * @return Value in NTP timestamp format + */ + static uint64_t convertToTimestampFormat(const double val); + + /** + * A static method to convert timestamp value to ISO8601 date time format + * @param[in] timestamp Value in seconds from the Unix Epoch + * @return std::string ISO8601 formatted string + */ + static std::string convertToIsoFormat(const double timestamp); + + /** + * A static method to convert timestamp value to ISO8601 date time format + * @param[in] timestampInNTPformat Value in NTP timestamp format + * @return std::string ISO8601 formatted string + */ + static std::string convertToIsoFormat(const uint64_t timestampInNTPformat); + + /** + * A static method that takes a byte array and detects whether it is a NTP message + * @param[in] data A byte array + * @param[in] dataSize The byte array size (in bytes) + * @return True if the data is identified as NTP message + */ + static bool isDataValid(const uint8_t* data, size_t dataSize); + + /** + * A static method that checks whether the port is considered as NTP + * @param[in] port The port number to be checked + */ + static bool isNTPPort(uint16_t port) + { + return port == 123; + } + + // overridden methods + + /// Parses the next layer. NTP is the always last so does nothing for this layer + void parseNextLayer() + {} + + /** + * @return Get the size of the layer (Including the extension and authentication fields if exists) + */ + size_t getHeaderLen() const + { + return m_DataLen; + } + + /// Does nothing for this layer + void computeCalculateFields() + {} + + /** + * @return The OSI layer level of NTP (Application Layer). + */ + OsiModelLayer getOsiModelLayer() const + { + return OsiModelApplicationLayer; + } + + /** + * @return Returns the protocol info as readable string + */ + std::string toString() const; + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/NullLoopbackLayer.h b/Packet++/header/pcapplusplus/NullLoopbackLayer.h new file mode 100644 index 0000000000..85b2208dba --- /dev/null +++ b/Packet++/header/pcapplusplus/NullLoopbackLayer.h @@ -0,0 +1,99 @@ +#pragma once + +/// @file + +#include "pcapplusplus/Layer.h" + +namespace pcpp +{ + +/** IPv4 protocol **/ +#define PCPP_BSD_AF_INET 2 +/** XEROX NS protocols */ +#define PCPP_BSD_AF_NS 6 +/** ISO */ +#define PCPP_BSD_AF_ISO 7 +/** AppleTalk */ +#define PCPP_BSD_AF_APPLETALK 16 +/** IPX */ +#define PCPP_BSD_AF_IPX 23 +/** OpenBSD (and probably NetBSD), BSD/OS IPv6 */ +#define PCPP_BSD_AF_INET6_BSD 24 +/** FreeBSD IPv6 */ +#define PCPP_BSD_AF_INET6_FREEBSD 28 +/** Darwin IPv6 */ +#define PCPP_BSD_AF_INET6_DARWIN 30 + + /** + * @class NullLoopbackLayer + * Represents a Null/Loopback layer + */ + class NullLoopbackLayer : public Layer + { + public: + /** A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + NullLoopbackLayer(uint8_t* data, size_t dataLen, Packet* packet) + : Layer(data, dataLen, nullptr, packet, NULL_LOOPBACK) + {} + + /** + * A constructor that allocates a new Null/Loopback header + * @param[in] family The family protocol to set + */ + explicit NullLoopbackLayer(uint32_t family); + + /** + * A destructor for this layer (does nothing) + */ + ~NullLoopbackLayer() + {} + + /** + * @return The protocol family in this layer + */ + uint32_t getFamily() const; + + /** + * Set a protocol family + * @param[in] family The family protocol to set + */ + void setFamily(uint32_t family); + + // implement abstract methods + + /** + * Identifies the next layers by family: + * - for ::PCPP_BSD_AF_INET the next layer is IPv4Layer + * - for ::PCPP_BSD_AF_INET6_BSD, ::PCPP_BSD_AF_INET6_FREEBSD, ::PCPP_BSD_AF_INET6_DARWIN the next layer is + * IPv6Layer + * - for other values the next layer in PayloadLayer (unknown protocol) + */ + void parseNextLayer(); + + /** + * @return Size of Null/Loopback header = 4B + */ + size_t getHeaderLen() const + { + return sizeof(uint32_t); + } + + /** + * Does nothing for this layer + */ + void computeCalculateFields() + {} + + std::string toString() const; + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelDataLinkLayer; + } + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/PPPoELayer.h b/Packet++/header/pcapplusplus/PPPoELayer.h new file mode 100644 index 0000000000..ec5a6a6b75 --- /dev/null +++ b/Packet++/header/pcapplusplus/PPPoELayer.h @@ -0,0 +1,739 @@ +#pragma once + +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/TLVData.h" +#include +#include + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * @struct pppoe_header + * Represents an PPPoE protocol header + */ +#pragma pack(push, 1) + struct pppoe_header + { +#if (BYTE_ORDER == LITTLE_ENDIAN) + /** PPPoE version */ + uint8_t version : 4; + /** PPPoE type */ + uint8_t type : 4; + /** PPPoE code */ + uint8_t code; +#else + /** PPPoE version */ + uint16_t version : 4; + /** PPPoE type */ + uint16_t type : 4; + /** PPPoE code */ + uint16_t code : 8; +#endif + /** PPPoE session ID (relevant for PPPoE session packets only) */ + uint16_t sessionId; + /** Length (in bytes) of payload, not including the PPPoE header */ + uint16_t payloadLength; + }; +#pragma pack(pop) + + /** + * @class PPPoELayer + * An abstract class that describes the PPPoE protocol. Contains common data and logic of the two types of PPPoE + * packets: PPPoE session and PPPoE discovery + */ + class PPPoELayer : public Layer + { + public: + /** + * PPPoE possible codes + */ + enum PPPoECode + { + /** PPPoE session code */ + PPPOE_CODE_SESSION = 0x00, + /** PPPoE discovery PADO */ + PPPOE_CODE_PADO = 0x07, + /** PPPoE discovery PADI */ + PPPOE_CODE_PADI = 0x09, + /** PPPoE discovery PADG */ + PPPOE_CODE_PADG = 0x0a, + /** PPPoE discovery PADC */ + PPPOE_CODE_PADC = 0x0b, + /** PPPoE discovery PADQ */ + PPPOE_CODE_PADQ = 0x0c, + /** PPPoE discovery PADR */ + PPPOE_CODE_PADR = 0x19, + /** PPPoE discovery PADS */ + PPPOE_CODE_PADS = 0x65, + /** PPPoE discovery PADT */ + PPPOE_CODE_PADT = 0xa7, + /** PPPoE discovery PADM */ + PPPOE_CODE_PADM = 0xd3, + /** PPPoE discovery PADN */ + PPPOE_CODE_PADN = 0xd4 + }; + + ~PPPoELayer() + {} + + /** + * Get a pointer to the PPPoE header. Notice this points directly to the data, so every change will change the + * actual packet data + * @return A pointer to the pppoe_header + */ + pppoe_header* getPPPoEHeader() const + { + return (pppoe_header*)m_Data; + } + + // abstract methods implementation + + /** + * Calculate @ref pppoe_header#payloadLength field + */ + virtual void computeCalculateFields(); + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelDataLinkLayer; + } + + protected: + // protected c'tor as this class shouldn't be instantiated + PPPoELayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, ProtocolType protocol) + : Layer(data, dataLen, prevLayer, packet, protocol) + {} + + // protected c'tor as this class shouldn't be instantiated + PPPoELayer(uint8_t version, uint8_t type, PPPoELayer::PPPoECode code, uint16_t sessionId, + size_t additionalBytesToAllocate = 0); + }; + + /** + * @class PPPoESessionLayer + * Describes the PPPoE session protocol + */ + class PPPoESessionLayer : public PPPoELayer + { + public: + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data (will be casted to @ref pppoe_header) + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + PPPoESessionLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : PPPoELayer(data, dataLen, prevLayer, packet, PPPoESession) + {} + + /** + * A constructor that allocates a new PPPoE Session header with version, type and session ID + * @param[in] version PPPoE version + * @param[in] type PPPoE type + * @param[in] sessionId PPPoE session ID + * @param[in] pppNextProtocol The next protocol to come after the PPPoE session header. Should be one of the + * PPP_* macros listed below + */ + PPPoESessionLayer(uint8_t version, uint8_t type, uint16_t sessionId, uint16_t pppNextProtocol) + : PPPoELayer(version, type, PPPoELayer::PPPOE_CODE_SESSION, sessionId, sizeof(uint16_t)) + { + setPPPNextProtocol(pppNextProtocol); + } + + virtual ~PPPoESessionLayer() + {} + + /** + * @return The protocol after the PPPoE session header. The return value is one of the PPP_* macros listed + * below. This method is also used when parsing a packet (this way we know which layer comes after the PPPoE + * session) + */ + uint16_t getPPPNextProtocol() const; + + /** + * Set the field that describes which header comes after the PPPoE session header + * @param[in] nextProtocol The protocol value. Should be one of the PPP_* macros listed below + */ + void setPPPNextProtocol(uint16_t nextProtocol); + + /** + * A static method that validates the input data + * @param[in] data The pointer to the beginning of byte stream of a packet + * @param[in] dataLen The length of the byte stream + * @return True if the data is valid and can represent a PPPoES packet + */ + static inline bool isDataValid(const uint8_t* data, size_t dataLen); + + // abstract methods implementation + + /** + * Currently identifies the following next layers: IPv4Layer, IPv6Layer. Otherwise sets PayloadLayer + */ + virtual void parseNextLayer(); + + /** + * @return Size of @ref pppoe_header + */ + virtual size_t getHeaderLen() const + { + return sizeof(pppoe_header) + sizeof(uint16_t); + } + + virtual std::string toString() const; + }; + + /** + * @class PPPoEDiscoveryLayer + * Describes the PPPoE discovery protocol + */ + class PPPoEDiscoveryLayer : public PPPoELayer + { + public: + /** + * PPPoE tag types + */ + enum PPPoETagTypes + { + /** End-Of-List tag type*/ + PPPOE_TAG_EOL = 0x0000, + /** Service-Name tag type*/ + PPPOE_TAG_SVC_NAME = 0x0101, + /** AC-Name tag type*/ + PPPOE_TAG_AC_NAME = 0x0102, + /** Host-Uniq tag type*/ + PPPOE_TAG_HOST_UNIQ = 0x0103, + /** AC-Cookie tag type*/ + PPPOE_TAG_AC_COOKIE = 0x0104, + /** Vendor-Specific tag type*/ + PPPOE_TAG_VENDOR = 0x0105, + /** Credits tag type*/ + PPPOE_TAG_CREDITS = 0x0106, + /** Metrics tag type*/ + PPPOE_TAG_METRICS = 0x0107, + /** Sequence Number tag type */ + PPPOE_TAG_SEQ_NUM = 0x0108, + /** Credit Scale Factor tag type */ + PPPOE_TAG_CRED_SCALE = 0x0109, + /** Relay-Session-Id tag type */ + PPPOE_TAG_RELAY_ID = 0x0110, + /** HURL tag type */ + PPPOE_TAG_HURL = 0x0111, + /** MOTM tag type */ + PPPOE_TAG_MOTM = 0x0112, + /** PPP-Max-Payload tag type */ + PPPOE_TAG_MAX_PAYLD = 0x0120, + /** IP_Route_Add tag type */ + PPPOE_TAG_IP_RT_ADD = 0x0121, + /** Service-Name-Error tag type */ + PPPOE_TAG_SVC_ERR = 0x0201, + /** AC-System-Error tag type */ + PPPOE_TAG_AC_ERR = 0x0202, + /** Generic-Error tag type */ + PPPOE_TAG_GENERIC_ERR = 0x0203 + }; + + /** + * @class PPPoETag + * Represents a PPPoE tag and its data + */ + class PPPoETag : public TLVRecord + { + public: + /** + * A c'tor that gets a pointer to the tag raw data (byte array) + * @param[in] tagRawData A pointer to the tag raw data + */ + explicit PPPoETag(uint8_t* tagRawData) : TLVRecord(tagRawData) + {} + + /** + * A d'tor for this class, currently does nothing + */ + virtual ~PPPoETag() + {} + + /** + * @return The tag type converted to PPPoEDiscoveryLayer#PPPoETagTypes enum + */ + PPPoEDiscoveryLayer::PPPoETagTypes getType() const; + + /** + * Retrieve the tag data as string. Relevant only if the tag value is indeed a string + * @return The tag data as string + */ + std::string getValueAsString() const + { + size_t dataSize = getDataSize(); + if (dataSize < 1) + return ""; + + return std::string((const char*)m_Data->recordValue, dataSize); + } + + // implement abstract methods + + size_t getTotalSize() const; + + size_t getDataSize() const; + }; + + /** + * @class PPPoETagBuilder + * A class for building PPPoE Tags. This builder receives the tag parameters in its c'tor, + * builds the PPPoE Tag raw buffer and provides a build() method to get a PPPoETag object out of it + */ + class PPPoETagBuilder : public TLVRecordBuilder + { + public: + /** + * A c'tor for building a PPPoE Tag which has no value (tag len is zero). The PPPoETag object can later + * be retrieved by calling build() + * @param[in] tagType Tag type + */ + explicit PPPoETagBuilder(PPPoETagTypes tagType) + : TLVRecordBuilder(static_cast(tagType), nullptr, 0) + {} + + /** + * A c'tor for building a PPPoE Tag which has a 4-byte value. The PPPoETag object can later + * be retrieved by calling build() + * @param[in] tagType Tag type + * @param[in] tagValue The tag's 4-byte value + */ + PPPoETagBuilder(PPPoETagTypes tagType, uint32_t tagValue) + : TLVRecordBuilder(static_cast(tagType), tagValue) + {} + + /** + * A c'tor for building a PPPoE Tag which has some arbitrary value. The PPPoETag object can later + * be retrieved by calling build() + * @param[in] tagType Tag type + * @param[in] tagValue A byte array that contains the tag data + * @param[in] tagValueLen The length of the value byte array + */ + PPPoETagBuilder(PPPoETagTypes tagType, uint8_t* tagValue, uint8_t tagValueLen) + : TLVRecordBuilder(static_cast(tagType), tagValue, tagValueLen) + {} + + /** + * Build the PPPoETag object out of the parameters defined in the c'tor + * @return The PPPoETag object + */ + PPPoETag build() const; + }; + + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data (will be casted to @ref pppoe_header) + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + PPPoEDiscoveryLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : PPPoELayer(data, dataLen, prevLayer, packet, PPPoEDiscovery) + { + m_DataLen = getHeaderLen(); + } + + /** + * A constructor that allocates a new PPPoE Discovery header with version, type, PPPoE code and session ID + * @param[in] version PPPoE version + * @param[in] type PPPoE type + * @param[in] code PPPoE code enum + * @param[in] sessionId PPPoE session ID + */ + PPPoEDiscoveryLayer(uint8_t version, uint8_t type, PPPoELayer::PPPoECode code, uint16_t sessionId) + : PPPoELayer(version, type, code, sessionId) + { + m_Protocol = PPPoEDiscovery; + } + + /** + * Get a PPPoE Tag by tag type. + * @param[in] tagType The type of the tag to search + * @return A PPPoETag object that contains the first tag that matches this type, or logical null + * (PPPoETag#isNull() == true) if no such tag found + */ + PPPoETag getTag(PPPoEDiscoveryLayer::PPPoETagTypes tagType) const; + + /** + * @return The first tag in the PPPoE discovery layer. If the current layer contains no tags the returned value + * will contain a logical null (PPPoETag#isNull() == true) + */ + PPPoETag getFirstTag() const; + + /** + * Get the tag that comes right after the "tag" parameter. If the given tag is the last one, the returned value + * will contain a logical null (PPPoETag#isNull() == true) + * @param[in] tag A given tag + * @return A PPPoETag object containing the tag that comes next, or logical null if the given + * tag: (1) was the last one; (2) contains a logical null or (3) doesn't belong to this packet + */ + PPPoETag getNextTag(const PPPoETag& tag) const; + + /** + * @return The number of tags in this layer + */ + int getTagCount() const; + + /** + * Add a new PPPoE Tag at the end of the layer + * @param[in] tagBuilder A PPPoETagBuilder object that contains the requested tag data to add + * @return A PPPoETag object containing the newly added PPPoE Tag data or logical null + * (PPPoETag#isNull() == true) if addition failed + */ + PPPoETag addTag(const PPPoETagBuilder& tagBuilder); + + /** + * Add a new PPPoE Tag after an existing one + * @param[in] tagBuilder A PPPoETagBuilder object that contains the requested tag data to add + * @param[in] prevTagType The PPPoE Tag which the newly added tag will come after + * @return A PPPoETag object containing the newly added PPPoE Tag data or logical null + * (PPPoETag#isNull() == true) if addition failed + */ + PPPoETag addTagAfter(const PPPoETagBuilder& tagBuilder, PPPoETagTypes prevTagType); + + /** + * Remove an existing tag. Tag will be found by the tag type + * @param[in] tagType The tag type to remove + * @return True if tag was removed or false if tag wasn't found or if tag removal failed (in each case a proper + * error will be written to log) + */ + bool removeTag(PPPoEDiscoveryLayer::PPPoETagTypes tagType); + + /** + * Remove all tags in this layer + * @return True if all tags were successfully or false if removal failed for some reason (a proper error will be + * written to log) + */ + bool removeAllTags(); + + /** + * A static method that validates the input data + * @param[in] data The pointer to the beginning of byte stream of a packet + * @param[in] dataLen The length of the byte stream + * @return True if the data is valid and can represent a PPPoED packet + */ + static inline bool isDataValid(const uint8_t* data, size_t dataLen); + + // abstract methods implementation + + /** + * Does nothing for this layer (PPPoE discovery is always the last layer) + */ + virtual void parseNextLayer() + {} + + /** + * @return The header length which is size of strcut pppoe_header plus the total size of tags + */ + virtual size_t getHeaderLen() const; + + virtual std::string toString() const + { + return "PPP-over-Ethernet Discovery (" + codeToString((PPPoELayer::PPPoECode)getPPPoEHeader()->code) + ")"; + } + + private: + TLVRecordReader m_TagReader; + + PPPoETag addTagAt(const PPPoETagBuilder& tagBuilder, int offset); + + uint8_t* getTagBasePtr() const + { + return m_Data + sizeof(pppoe_header); + } + + std::string codeToString(PPPoECode code) const; + }; + + // implementation of inline methods + + bool PPPoESessionLayer::isDataValid(const uint8_t* data, size_t dataLen) + { + return data && dataLen >= sizeof(pppoe_header) + sizeof(uint16_t); + } + + bool PPPoEDiscoveryLayer::isDataValid(const uint8_t* data, size_t dataLen) + { + return data && dataLen >= sizeof(pppoe_header); + } + + // Copied from Wireshark: ppptypes.h + + /** Padding Protocol */ +#define PCPP_PPP_PADDING 0x1 + /** ROHC small-CID */ +#define PCPP_PPP_ROHC_SCID 0x3 + /** ROHC large-CID */ +#define PCPP_PPP_ROHC_LCID 0x5 + /** Internet Protocol version 4 */ +#define PCPP_PPP_IP 0x21 + /** OSI Network Layer */ +#define PCPP_PPP_OSI 0x23 + /** Xerox NS IDP */ +#define PCPP_PPP_XNSIDP 0x25 + /** DECnet Phase IV */ +#define PCPP_PPP_DEC4 0x27 + /** AppleTalk */ +#define PCPP_PPP_AT 0x29 + /** Novell IPX */ +#define PCPP_PPP_IPX 0x2b + /** Van Jacobson Compressed TCP/IP */ +#define PCPP_PPP_VJC_COMP 0x2d + /** Van Jacobson Uncompressed TCP/IP */ +#define PCPP_PPP_VJC_UNCOMP 0x2f + /** Bridging PDU */ +#define PCPP_PPP_BCP 0x31 + /** Stream Protocol (ST-II) */ +#define PCPP_PPP_ST 0x33 + /** Banyan Vines */ +#define PCPP_PPP_VINES 0x35 + /** AppleTalk EDDP */ +#define PCPP_PPP_AT_EDDP 0x39 + /** AppleTalk SmartBuffered */ +#define PCPP_PPP_AT_SB 0x3b + /** Multi-Link */ +#define PCPP_PPP_MP 0x3d + /** NETBIOS Framing */ +#define PCPP_PPP_NB 0x3f + /** Cisco Systems */ +#define PCPP_PPP_CISCO 0x41 + /** Ascom Timeplex */ +#define PCPP_PPP_ASCOM 0x43 + /** Fujitsu Link Backup and Load Balancing */ +#define PCPP_PPP_LBLB 0x45 + /** DCA Remote Lan */ +#define PCPP_PPP_RL 0x47 + /** Serial Data Transport Protocol */ +#define PCPP_PPP_SDTP 0x49 + /** SNA over 802.2 */ +#define PCPP_PPP_LLC 0x4b + /** SNA */ +#define PCPP_PPP_SNA 0x4d + /** IPv6 Header Compression */ +#define PCPP_PPP_IPV6HC 0x4f + /** KNX Bridging Data */ +#define PCPP_PPP_KNX 0x51 + /** Encryption */ +#define PCPP_PPP_ENCRYPT 0x53 + /** Individual Link Encryption */ +#define PCPP_PPP_ILE 0x55 + /** Internet Protocol version 6 */ +#define PCPP_PPP_IPV6 0x57 + /** PPP Muxing */ +#define PCPP_PPP_MUX 0x59 + /** Vendor-Specific Network Protocol (VSNP) */ +#define PCPP_PPP_VSNP 0x5b + /** TRILL Network Protocol (TNP) */ +#define PCPP_PPP_TNP 0x5d + /** RTP IPHC Full Header */ +#define PCPP_PPP_RTP_FH 0x61 + /** RTP IPHC Compressed TCP */ +#define PCPP_PPP_RTP_CTCP 0x63 + /** RTP IPHC Compressed Non TCP */ +#define PCPP_PPP_RTP_CNTCP 0x65 + /** RTP IPHC Compressed UDP 8 */ +#define PCPP_PPP_RTP_CUDP8 0x67 + /** RTP IPHC Compressed RTP 8 */ +#define PCPP_PPP_RTP_CRTP8 0x69 + /** Stampede Bridging */ +#define PCPP_PPP_STAMPEDE 0x6f + /** MP+ Protocol */ +#define PCPP_PPP_MPPLUS 0x73 + /** NTCITS IPI */ +#define PCPP_PPP_NTCITS_IPI 0xc1 + /** Single link compression in multilink */ +#define PCPP_PPP_ML_SLCOMP 0xfb + /** Compressed datagram */ +#define PCPP_PPP_COMP 0xfd + /** 802.1d Hello Packets */ +#define PCPP_PPP_STP_HELLO 0x0201 + /** IBM Source Routing BPDU */ +#define PCPP_PPP_IBM_SR 0x0203 + /** DEC LANBridge100 Spanning Tree */ +#define PCPP_PPP_DEC_LB 0x0205 + /** Cisco Discovery Protocol */ +#define PCPP_PPP_CDP 0x0207 + /** Netcs Twin Routing */ +#define PCPP_PPP_NETCS 0x0209 + /** STP - Scheduled Transfer Protocol */ +#define PCPP_PPP_STP 0x020b + /** EDP - Extreme Discovery Protocol */ +#define PCPP_PPP_EDP 0x020d + /** Optical Supervisory Channel Protocol */ +#define PCPP_PPP_OSCP 0x0211 + /** Optical Supervisory Channel Protocol */ +#define PCPP_PPP_OSCP2 0x0213 + /** Luxcom */ +#define PCPP_PPP_LUXCOM 0x0231 + /** Sigma Network Systems */ +#define PCPP_PPP_SIGMA 0x0233 + /** Apple Client Server Protocol */ +#define PCPP_PPP_ACSP 0x0235 + /** MPLS Unicast */ +#define PCPP_PPP_MPLS_UNI 0x0281 + /** MPLS Multicast */ +#define PCPP_PPP_MPLS_MULTI 0x0283 + /** IEEE p1284.4 standard - data packets */ +#define PCPP_PPP_P12844 0x0285 + /** ETSI TETRA Network Protocol Type 1 */ +#define PCPP_PPP_TETRA 0x0287 + /** Multichannel Flow Treatment Protocol */ +#define PCPP_PPP_MFTP 0x0289 + /** RTP IPHC Compressed TCP No Delta */ +#define PCPP_PPP_RTP_CTCPND 0x2063 + /** RTP IPHC Context State */ +#define PCPP_PPP_RTP_CS 0x2065 + /** RTP IPHC Compressed UDP 16 */ +#define PCPP_PPP_RTP_CUDP16 0x2067 + /** RTP IPHC Compressed RTP 16 */ +#define PCPP_PPP_RTP_CRDP16 0x2069 + /** Cray Communications Control Protocol */ +#define PCPP_PPP_CCCP 0x4001 + /** CDPD Mobile Network Registration Protocol */ +#define PCPP_PPP_CDPD_MNRP 0x4003 + /** Expand accelerator protocol */ +#define PCPP_PPP_EXPANDAP 0x4005 + /** ODSICP NCP */ +#define PCPP_PPP_ODSICP 0x4007 + /** DOCSIS DLL */ +#define PCPP_PPP_DOCSIS 0x4009 + /** Cetacean Network Detection Protocol */ +#define PCPP_PPP_CETACEANNDP 0x400b + /** Stacker LZS */ +#define PCPP_PPP_LZS 0x4021 + /** RefTek Protocol */ +#define PCPP_PPP_REFTEK 0x4023 + /** Fibre Channel */ +#define PCPP_PPP_FC 0x4025 + /** EMIT Protocols */ +#define PCPP_PPP_EMIT 0x4027 + /** Vendor-Specific Protocol (VSP) */ +#define PCPP_PPP_VSP 0x405b + /** TRILL Link State Protocol (TLSP) */ +#define PCPP_PPP_TLSP 0x405d + /** Internet Protocol Control Protocol */ +#define PCPP_PPP_IPCP 0x8021 + /** OSI Network Layer Control Protocol */ +#define PCPP_PPP_OSINLCP 0x8023 + /** Xerox NS IDP Control Protocol */ +#define PCPP_PPP_XNSIDPCP 0x8025 + /** DECnet Phase IV Control Protocol */ +#define PCPP_PPP_DECNETCP 0x8027 + /** AppleTalk Control Protocol */ +#define PCPP_PPP_ATCP 0x8029 + /** Novell IPX Control Protocol */ +#define PCPP_PPP_IPXCP 0x802b + /** Bridging NCP */ +#define PCPP_PPP_BRIDGENCP 0x8031 + /** Stream Protocol Control Protocol */ +#define PCPP_PPP_SPCP 0x8033 + /** Banyan Vines Control Protocol */ +#define PCPP_PPP_BVCP 0x8035 + /** Multi-Link Control Protocol */ +#define PCPP_PPP_MLCP 0x803d + /** NETBIOS Framing Control Protocol */ +#define PCPP_PPP_NBCP 0x803f + /** Cisco Systems Control Protocol */ +#define PCPP_PPP_CISCOCP 0x8041 + /** Ascom Timeplex Control Protocol (?) */ +#define PCPP_PPP_ASCOMCP 0x8043 + /** Fujitsu LBLB Control Protocol */ +#define PCPP_PPP_LBLBCP 0x8045 + /** DCA Remote Lan Network Control Protocol */ +#define PCPP_PPP_RLNCP 0x8047 + /** Serial Data Control Protocol */ +#define PCPP_PPP_SDCP 0x8049 + /** SNA over 802.2 Control Protocol */ +#define PCPP_PPP_LLCCP 0x804b + /** SNA Control Protocol */ +#define PCPP_PPP_SNACP 0x804d + /** IP6 Header Compression Control Protocol */ +#define PCPP_PPP_IP6HCCP 0x804f + /** KNX Bridging Control Protocol */ +#define PCPP_PPP_KNXCP 0x8051 + /** Encryption Control Protocol */ +#define PCPP_PPP_ECP 0x8053 + /** Individual Link Encryption Control Protocol */ +#define PCPP_PPP_ILECP 0x8055 + /** IPv6 Control Protocol */ +#define PCPP_PPP_IPV6CP 0x8057 + /** PPP Muxing Control Protocol */ +#define PCPP_PPP_MUXCP 0x8059 + /** Vendor-Specific Network Control Protocol (VSNCP) [RFC3772] */ +#define PCPP_PPP_VSNCP 0x805b + /** TRILL Network Control Protocol (TNCP) */ +#define PCPP_PPP_TNCP 0x805d + /** Stampede Bridging Control Protocol */ +#define PCPP_PPP_STAMPEDECP 0x806f + /** MP+ Contorol Protocol */ +#define PCPP_PPP_MPPCP 0x8073 + /** NTCITS IPI Control Protocol */ +#define PCPP_PPP_IPICP 0x80c1 + /** Single link compression in multilink control */ +#define PCPP_PPP_SLCC 0x80fb + /** Compression Control Protocol */ +#define PCPP_PPP_CCP 0x80fd + /** Cisco Discovery Protocol Control Protocol */ +#define PCPP_PPP_CDPCP 0x8207 + /** Netcs Twin Routing */ +#define PCPP_PPP_NETCSCP 0x8209 + /** STP - Control Protocol */ +#define PCPP_PPP_STPCP 0x820b + /** EDPCP - Extreme Discovery Protocol Control Protocol */ +#define PCPP_PPP_EDPCP 0x820d + /** Apple Client Server Protocol Control */ +#define PCPP_PPP_ACSPC 0x8235 + /** MPLS Control Protocol */ +#define PCPP_PPP_MPLSCP 0x8281 + /** IEEE p1284.4 standard - Protocol Control */ +#define PCPP_PPP_P12844CP 0x8285 + /** ETSI TETRA TNP1 Control Protocol */ +#define PCPP_PPP_TETRACP 0x8287 + /** Multichannel Flow Treatment Protocol */ +#define PCPP_PPP_MFTPCP 0x8289 + /** Link Control Protocol */ +#define PCPP_PPP_LCP 0xc021 + /** Password Authentication Protocol */ +#define PCPP_PPP_PAP 0xc023 + /** Link Quality Report */ +#define PCPP_PPP_LQR 0xc025 + /** Shiva Password Authentication Protocol */ +#define PCPP_PPP_SPAP 0xc027 + /** CallBack Control Protocol (CBCP) */ +#define PCPP_PPP_CBCP 0xc029 + /** BACP Bandwidth Allocation Control Protocol */ +#define PCPP_PPP_BACP 0xc02b + /** BAP Bandwidth Allocation Protocol */ +#define PCPP_PPP_BAP 0xc02d + /** Vendor-Specific Authentication Protocol (VSAP) */ +#define PCPP_PPP_VSAP 0xc05b + /** Container Control Protocol */ +#define PCPP_PPP_CONTCP 0xc081 + /** Challenge Handshake Authentication Protocol */ +#define PCPP_PPP_CHAP 0xc223 + /** RSA Authentication Protocol */ +#define PCPP_PPP_RSAAP 0xc225 + /** Extensible Authentication Protocol */ +#define PCPP_PPP_EAP 0xc227 + /** Mitsubishi Security Information Exchange Protocol (SIEP) */ +#define PCPP_PPP_SIEP 0xc229 + /** Stampede Bridging Authorization Protocol */ +#define PCPP_PPP_SBAP 0xc26f + /** Proprietary Authentication Protocol */ +#define PCPP_PPP_PRPAP 0xc281 + /** Proprietary Authentication Protocol */ +#define PCPP_PPP_PRPAP2 0xc283 + /** Proprietary Node ID Authentication Protocol */ +#define PCPP_PPP_PRPNIAP 0xc481 + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/Packet.h b/Packet++/header/pcapplusplus/Packet.h new file mode 100644 index 0000000000..f1e0830258 --- /dev/null +++ b/Packet++/header/pcapplusplus/Packet.h @@ -0,0 +1,454 @@ +#pragma once + +#include "pcapplusplus/RawPacket.h" +#include "pcapplusplus/Layer.h" +#include + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * @class Packet + * This class represents a parsed packet. It contains the raw data (RawPacket instance), and a linked list of + * layers, each layer is a parsed protocol that this packet contains. The layers linked list is ordered where the + * first layer is the lowest in the packet (currently it's always Ethernet protocol as PcapPlusPlus supports only + * Ethernet packets), the next layer will be L2.5 or L3 (e.g VLAN, IPv4, IPv6, etc.), and so on. etc.), etc. The + * last layer in the linked list will be the highest in the packet. For example: for a standard HTTP request packet + * the layer will look like this: EthLayer -> IPv4Layer -> TcpLayer -> HttpRequestLayer
Packet instance isn't + * read only. The user can add or remove layers, update current layer, etc. + */ + class Packet + { + friend class Layer; + + private: + RawPacket* m_RawPacket; + Layer* m_FirstLayer; + Layer* m_LastLayer; + size_t m_MaxPacketLen; + bool m_FreeRawPacket; + bool m_CanReallocateData; + + public: + /** + * A constructor for creating a new packet (with no layers). + * When using this constructor an empty raw buffer is allocated (with the size of maxPacketLen) and a new + * RawPacket is created + * @param[in] maxPacketLen The expected packet length in bytes + */ + explicit Packet(size_t maxPacketLen = 1); + + /** + * A constructor for creating a new packet with a buffer that is pre-allocated by the user. + * The packet is created empty (with no layers), which means the constructor doesn't parse the data in the + * buffer. Instead, all of the raw data of this packet it written to this buffer: whenever a layer is added, + * it's data is written to this buffer. The buffer isn't freed and it's content isn't erased when the packet + * object is deleted. This constructor is useful when you already have a memory buffer and you want to create + * packet data in it. + * @param[in] buffer A pointer to a pre-allocated memory buffer + * @param[in] bufferSize The size of the buffer + */ + Packet(uint8_t* buffer, size_t bufferSize); + + /** + * A constructor for creating a packet out of already allocated RawPacket. Very useful when parsing packets that + * came from the network. When using this constructor a pointer to the RawPacket is saved (data isn't copied) + * and the RawPacket is parsed, meaning all layers are created and linked to each other in the right order. In + * this overload of the constructor the user can specify whether to free the instance of raw packet when the + * Packet is free or not + * @param[in] rawPacket A pointer to the raw packet + * @param[in] freeRawPacket Optional parameter. A flag indicating if the destructor should also call the raw + * packet destructor or not. Default value is false + * @param[in] parseUntil Optional parameter. Parse the packet until you reach a certain protocol (inclusive). + * Can be useful for cases when you need to parse only up to a certain layer and want to avoid the performance + * impact and memory consumption of parsing the whole packet. Default value is ::UnknownProtocol which means + * don't take this parameter into account + * @param[in] parseUntilLayer Optional parameter. Parse the packet until you reach a certain layer in the OSI + * model (inclusive). Can be useful for cases when you need to parse only up to a certain OSI layer (for example + * transport layer) and want to avoid the performance impact and memory consumption of parsing the whole packet. + * Default value is ::OsiModelLayerUnknown which means don't take this parameter into account + */ + explicit Packet(RawPacket* rawPacket, bool freeRawPacket = false, ProtocolType parseUntil = UnknownProtocol, + OsiModelLayer parseUntilLayer = OsiModelLayerUnknown); + + /** + * A constructor for creating a packet out of already allocated RawPacket. Very useful when parsing packets that + * came from the network. When using this constructor a pointer to the RawPacket is saved (data isn't copied) + * and the RawPacket is parsed, meaning all layers are created and linked to each other in the right order. In + * this overload of the constructor the user can specify whether to free the instance of raw packet when the + * Packet is free or not. This constructor should be used to parse the packet up to a certain layer + * @param[in] rawPacket A pointer to the raw packet + * @param[in] parseUntil Parse the packet until you reach a certain protocol (inclusive). Can be useful for + * cases when you need to parse only up to a certain layer and want to avoid the performance impact and memory + * consumption of parsing the whole packet + */ + explicit Packet(RawPacket* rawPacket, ProtocolType parseUntil); + + /** + * A constructor for creating a packet out of already allocated RawPacket. Very useful when parsing packets that + * came from the network. When using this constructor a pointer to the RawPacket is saved (data isn't copied) + * and the RawPacket is parsed, meaning all layers are created and linked to each other in the right order. In + * this overload of the constructor the user can specify whether to free the instance of raw packet when the + * Packet is free or not. This constructor should be used to parse the packet up to a certain layer + * @param[in] rawPacket A pointer to the raw packet + * @param[in] parseUntilFamily Parse the packet until you reach a certain protocol family (inclusive). Can be + * useful for cases when you need to parse only up to a certain layer and want to avoid the performance impact + * and memory consumption of parsing the whole packet + */ + explicit Packet(RawPacket* rawPacket, ProtocolTypeFamily parseUntilFamily); + + /** + * A constructor for creating a packet out of already allocated RawPacket. Very useful when parsing packets that + * came from the network. When using this constructor a pointer to the RawPacket is saved (data isn't copied) + * and the RawPacket is parsed, meaning all layers are created and linked to each other in the right order. In + * this overload of the constructor the user can specify whether to free the instance of raw packet when the + * Packet is free or not. This constructor should be used to parse the packet up to a certain layer in the OSI + * model + * @param[in] rawPacket A pointer to the raw packet + * @param[in] parseUntilLayer Optional parameter. Parse the packet until you reach a certain layer in the OSI + * model (inclusive). Can be useful for cases when you need to parse only up to a certain OSI layer (for example + * transport layer) and want to avoid the performance impact and memory consumption of parsing the whole packet + */ + explicit Packet(RawPacket* rawPacket, OsiModelLayer parseUntilLayer); + + /** + * A destructor for this class. Frees all layers allocated by this instance (Notice: it doesn't free layers that + * weren't allocated by this class, for example layers that were added by addLayer() or insertLayer() ). In + * addition it frees the raw packet if it was allocated by this instance (meaning if it was allocated by this + * instance constructor) + */ + virtual ~Packet() + { + destructPacketData(); + } + + /** + * A copy constructor for this class. This copy constructor copies all the raw data and re-create all layers. So + * when the original Packet is being freed, no data will be lost in the copied instance + * @param[in] other The instance to copy from + */ + Packet(const Packet& other) + { + copyDataFrom(other); + } + + /** + * Assignment operator overloading. It first frees all layers allocated by this instance (Notice: it doesn't + * free layers that weren't allocated by this class, for example layers that were added by addLayer() or + * insertLayer() ). In addition it frees the raw packet if it was allocated by this instance (meaning if it was + * allocated by this instance constructor). Afterwards it copies the data from the other packet in the same way + * used in the copy constructor. + * @param[in] other The instance to copy from + */ + Packet& operator=(const Packet& other); + + /** + * Get a pointer to the Packet's RawPacket + * @return A pointer to the Packet's RawPacket + */ + RawPacket* getRawPacket() const + { + return m_RawPacket; + } + + /** + * Set a RawPacket and re-construct all packet layers + * @param[in] rawPacket Raw packet to set + * @param[in] freeRawPacket A flag indicating if the destructor should also call the raw packet destructor or + * not + * @param[in] parseUntil Parse the packet until it reaches this protocol. Can be useful for cases when you need + * to parse only up to a certain layer and want to avoid the performance impact and memory consumption of + * parsing the whole packet. Default value is ::UnknownProtocol which means don't take this parameter into + * account + * @param[in] parseUntilLayer Parse the packet until certain layer in OSI model. Can be useful for cases when + * you need to parse only up to a certain layer and want to avoid the performance impact and memory consumption + * of parsing the whole packet. Default value is ::OsiModelLayerUnknown which means don't take this parameter + * into account + */ + void setRawPacket(RawPacket* rawPacket, bool freeRawPacket, ProtocolTypeFamily parseUntil = UnknownProtocol, + OsiModelLayer parseUntilLayer = OsiModelLayerUnknown); + + /** + * Get a pointer to the Packet's RawPacket in a read-only manner + * @return A pointer to the Packet's RawPacket + */ + RawPacket* getRawPacketReadOnly() const + { + return m_RawPacket; + } + + /** + * Get a pointer to the first (lowest) layer in the packet + * @return A pointer to the first (lowest) layer in the packet + */ + Layer* getFirstLayer() const + { + return m_FirstLayer; + } + + /** + * Get a pointer to the last (highest) layer in the packet + * @return A pointer to the last (highest) layer in the packet + */ + Layer* getLastLayer() const + { + return m_LastLayer; + } + + /** + * Add a new layer as the last layer in the packet. This method gets a pointer to the new layer as a parameter + * and attaches it to the packet. Notice after calling this method the input layer is attached to the packet so + * every change you make in it affect the packet; Also it cannot be attached to other packets + * @param[in] newLayer A pointer to the new layer to be added to the packet + * @param[in] ownInPacket If true, Packet fully owns newLayer, including memory deletion upon destruct. Default + * is false. + * @return True if everything went well or false otherwise (an appropriate error log message will be printed in + * such cases) + */ + bool addLayer(Layer* newLayer, bool ownInPacket = false) + { + return insertLayer(m_LastLayer, newLayer, ownInPacket); + } + + /** + * Insert a new layer after an existing layer in the packet. This method gets a pointer to the new layer as a + * parameter and attaches it to the packet. Notice after calling this method the input layer is attached to the + * packet so every change you make in it affect the packet; Also it cannot be attached to other packets + * @param[in] prevLayer A pointer to an existing layer in the packet which the new layer should followed by. If + * this layer isn't attached to a packet and error will be printed to log and false will be returned + * @param[in] newLayer A pointer to the new layer to be added to the packet + * @param[in] ownInPacket If true, Packet fully owns newLayer, including memory deletion upon destruct. Default + * is false. + * @return True if everything went well or false otherwise (an appropriate error log message will be printed in + * such cases) + */ + bool insertLayer(Layer* prevLayer, Layer* newLayer, bool ownInPacket = false); + + /** + * Remove an existing layer from the packet. The layer to removed is identified by its type (protocol). If the + * packet has multiple layers of the same type in the packet the user may specify the index of the layer to + * remove (the default index is 0 - remove the first layer of this type). If the layer was allocated during + * packet creation it will be deleted and any pointer to it will get invalid. However if the layer was allocated + * by the user and manually added to the packet it will simply get detached from the packet, meaning the pointer + * to it will stay valid and its data (that was removed from the packet) will be copied back to the layer. In + * that case it's the user's responsibility to delete the layer instance + * @param[in] layerType The layer type (protocol) to remove + * @param[in] index If there are multiple layers of the same type, indicate which instance to remove. The + * default value is 0, meaning remove the first layer of this type + * @return True if everything went well or false otherwise (an appropriate error log message will be printed in + * such cases) + */ + bool removeLayer(ProtocolType layerType, int index = 0); + + /** + * Remove the first layer in the packet. The layer will be deleted if it was allocated during packet creation, + * or detached if was allocated outside of the packet. Please refer to removeLayer() to get more info + * @return True if layer removed successfully, or false if removing the layer failed or if there are no layers + * in the packet. In any case of failure an appropriate error log message will be printed + */ + bool removeFirstLayer(); + + /** + * Remove the last layer in the packet. The layer will be deleted if it was allocated during packet creation, or + * detached if was allocated outside of the packet. Please refer to removeLayer() to get more info + * @return True if layer removed successfully, or false if removing the layer failed or if there are no layers + * in the packet. In any case of failure an appropriate error log message will be printed + */ + bool removeLastLayer(); + + /** + * Remove all layers that come after a certain layer. All layers removed will be deleted if they were allocated + * during packet creation or detached if were allocated outside of the packet, please refer to removeLayer() to + * get more info + * @param[in] layer A pointer to the layer to begin removing from. Please note this layer will not be removed, + * only the layers that come after it will be removed. Also, if removal of one layer failed, the method will + * return immediately and the following layers won't be deleted + * @return True if all layers were removed successfully, or false if failed to remove at least one layer. In any + * case of failure an appropriate error log message will be printed + */ + bool removeAllLayersAfter(Layer* layer); + + /** + * Detach a layer from the packet. Detaching means the layer instance will not be deleted, but rather separated + * from the packet - e.g it will be removed from the layer chain of the packet and its data will be copied from + * the packet buffer into an internal layer buffer. After a layer is detached, it can be added into another + * packet (but it's impossible to attach a layer to multiple packets in the same time). After layer is detached, + * it's the user's responsibility to delete it when it's not needed anymore + * @param[in] layerType The layer type (protocol) to detach from the packet + * @param[in] index If there are multiple layers of the same type, indicate which instance to detach. The + * default value is 0, meaning detach the first layer of this type + * @return A pointer to the detached layer or nullptr if detaching process failed. In any case of failure an + * appropriate error log message will be printed + */ + Layer* detachLayer(ProtocolType layerType, int index = 0); + + /** + * Detach a layer from the packet. Detaching means the layer instance will not be deleted, but rather separated + * from the packet - e.g it will be removed from the layer chain of the packet and its data will be copied from + * the packet buffer into an internal layer buffer. After a layer is detached, it can be added into another + * packet (but it's impossible to attach a layer to multiple packets at the same time). After layer is detached, + * it's the user's responsibility to delete it when it's not needed anymore + * @param[in] layer A pointer to the layer to detach + * @return True if the layer was detached successfully, or false if something went wrong. In any case of failure + * an appropriate error log message will be printed + */ + bool detachLayer(Layer* layer) + { + return removeLayer(layer, false); + } + + /** + * Get a pointer to the layer of a certain type (protocol). This method goes through the layers and returns a + * layer that matches the give protocol type + * @param[in] layerType The layer type (protocol) to fetch + * @param[in] index If there are multiple layers of the same type, indicate which instance to fetch. The default + * value is 0, meaning fetch the first layer of this type + * @return A pointer to the layer or nullptr if no such layer was found + */ + Layer* getLayerOfType(ProtocolType layerType, int index = 0) const; + + /** + * A templated method to get a layer of a certain type (protocol). If no layer of such type is found, nullptr is + * returned + * @param[in] reverseOrder The optional parameter that indicates that the lookup should run in reverse order, + * the default value is false + * @return A pointer to the layer of the requested type, nullptr if not found + */ + template TLayer* getLayerOfType(bool reverseOrder = false) const; + + /** + * A templated method to get the first layer of a certain type (protocol), start searching from a certain layer. + * For example: if a packet looks like: EthLayer -> VlanLayer(1) -> VlanLayer(2) -> VlanLayer(3) -> IPv4Layer + * and the user put VlanLayer(2) as a parameter and wishes to search for a VlanLayer, VlanLayer(3) will be + * returned If no layer of such type is found, nullptr is returned + * @param[in] startLayer A pointer to the layer to start search from + * @return A pointer to the layer of the requested type, nullptr if not found + */ + template TLayer* getNextLayerOfType(Layer* startLayer) const; + + /** + * A templated method to get the first layer of a certain type (protocol), start searching from a certain layer. + * For example: if a packet looks like: EthLayer -> VlanLayer(1) -> VlanLayer(2) -> VlanLayer(3) -> IPv4Layer + * and the user put VlanLayer(2) as a parameter and wishes to search for a VlanLayer, VlanLayer(1) will be + * returned If no layer of such type is found, nullptr is returned + * @param[in] startLayer A pointer to the layer to start search from + * @return A pointer to the layer of the requested type, nullptr if not found + */ + template TLayer* getPrevLayerOfType(Layer* startLayer) const; + + /** + * Check whether the packet contains a layer of a certain protocol + * @param[in] protocolType The protocol type to search + * @return True if the packet contains a layer of a certain protocol, false otherwise + */ + bool isPacketOfType(ProtocolType protocolType) const; + + /** + * Check whether the packet contains a layer of a certain protocol family + * @param[in] protocolTypeFamily The protocol type family to search + * @return True if the packet contains a layer of a certain protocol family, false otherwise + */ + bool isPacketOfType(ProtocolTypeFamily protocolTypeFamily) const; + + /** + * Each layer can have fields that can be calculate automatically from other fields using + * Layer#computeCalculateFields(). This method forces all layers to calculate these fields values + */ + void computeCalculateFields(); + + /** + * Each layer can print a string representation of the layer most important data using Layer#toString(). This + * method aggregates this string from all layers and print it to a complete string containing all packet's + * relevant data + * @param[in] timeAsLocalTime Print time as local time or GMT. Default (true value) is local time, for GMT set + * to false + * @return A string containing most relevant data from all layers (looks like the packet description in + * Wireshark) + */ + std::string toString(bool timeAsLocalTime = true) const; + + /** + * Similar to toString(), but instead of one string it outputs a list of strings, one string for every layer + * @param[out] result A string vector that will contain all strings + * @param[in] timeAsLocalTime Print time as local time or GMT. Default (true value) is local time, for GMT set + * to false + */ + void toStringList(std::vector& result, bool timeAsLocalTime = true) const; + + private: + void copyDataFrom(const Packet& other); + + void destructPacketData(); + + bool extendLayer(Layer* layer, int offsetInLayer, size_t numOfBytesToExtend); + bool shortenLayer(Layer* layer, int offsetInLayer, size_t numOfBytesToShorten); + + void reallocateRawData(size_t newSize); + + bool removeLayer(Layer* layer, bool tryToDelete); + + std::string printPacketInfo(bool timeAsLocalTime) const; + + Layer* createFirstLayer(LinkLayerType linkType); + }; // class Packet + + // implementation of inline methods + + template TLayer* Packet::getLayerOfType(bool reverse) const + { + if (!reverse) + { + if (dynamic_cast(getFirstLayer()) != nullptr) + return dynamic_cast(getFirstLayer()); + + return getNextLayerOfType(getFirstLayer()); + } + + // lookup in reverse order + if (dynamic_cast(getLastLayer()) != nullptr) + return dynamic_cast(getLastLayer()); + + return getPrevLayerOfType(getLastLayer()); + } + + template TLayer* Packet::getNextLayerOfType(Layer* curLayer) const + { + if (curLayer == nullptr) + return nullptr; + + curLayer = curLayer->getNextLayer(); + while ((curLayer != nullptr) && (dynamic_cast(curLayer) == nullptr)) + { + curLayer = curLayer->getNextLayer(); + } + + return dynamic_cast(curLayer); + } + + template TLayer* Packet::getPrevLayerOfType(Layer* curLayer) const + { + if (curLayer == nullptr) + return nullptr; + + curLayer = curLayer->getPrevLayer(); + while (curLayer != nullptr && dynamic_cast(curLayer) == nullptr) + { + curLayer = curLayer->getPrevLayer(); + } + + return dynamic_cast(curLayer); + } + +} // namespace pcpp + +inline std::ostream& operator<<(std::ostream& os, const pcpp::Packet& packet) +{ + os << packet.toString(); + return os; +} diff --git a/Packet++/header/pcapplusplus/PacketTrailerLayer.h b/Packet++/header/pcapplusplus/PacketTrailerLayer.h new file mode 100644 index 0000000000..cd5c48f828 --- /dev/null +++ b/Packet++/header/pcapplusplus/PacketTrailerLayer.h @@ -0,0 +1,100 @@ +#pragma once + +/// @file + +#include "pcapplusplus/Layer.h" + +namespace pcpp +{ + /** + * @class PacketTrailerLayer + * A class for representing packet tailer (a.k.a footer or padding) which refers to supplemental data placed at the + * end of a block of data being stored or transmitted, which may contain information for the handling of the data + * block, or just mark its end (taken from Wikipedia: https://en.wikipedia.org/wiki/Trailer_(computing) ) + * + * There are various reasons for adding a packet trailer, one of the most famous is FCS (Frame check sequence) which + * refers to the extra error-detecting code added to a frame. Another usage is padding which means adding data to + * reach a minimum required packet length. + * + * Although this layer inherits from the Layer class, it is not a standard layer in the sense that it can't be + * constructed by the user. This layer may be only be constructed in the Packet class, in the process of parsing the + * packet and creating the layers; if at the end of the parsing process there is data left that is not allocated to + * any layer, it's assumed to be the packet trailer and an instance of this class is created. This means this layer + * can only exist as the last layer in a packet, if a packet trailer indeed exists. + * + * No layer can be added by the user after this layer (trying to do that will result with an error). + * + * This layer can be removed by the user or extended/shortened, as any layer. + * + * It also contains method to extract the trailer data + */ + class PacketTrailerLayer : public Layer + { + public: + /** A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + PacketTrailerLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : Layer(data, dataLen, prevLayer, packet, PacketTrailer) + {} + + ~PacketTrailerLayer() + {} + + /** + * Get a pointer to the trailer data + * @return A pointer to the trailer data + */ + uint8_t* getTrailerData() const + { + return m_Data; + } + + /** + * @return Trailer data as hex string + */ + std::string getTrailerDataAsHexString() const; + + /** + * Get the trailer data length + * @return The trailer data length in bytes + */ + size_t getTrailerLen() const + { + return m_DataLen; + } + + // implement abstract methods + + /** + * Does nothing for this layer (PacketTrailerLayer is always last) + */ + void parseNextLayer() + {} + + /** + * @return trailer data length in bytes + */ + size_t getHeaderLen() const + { + return m_DataLen; + } + + /** + * Does nothing for this layer + */ + void computeCalculateFields() + {} + + std::string toString() const; + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelDataLinkLayer; + } + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/PacketUtils.h b/Packet++/header/pcapplusplus/PacketUtils.h new file mode 100644 index 0000000000..e5ff52304e --- /dev/null +++ b/Packet++/header/pcapplusplus/PacketUtils.h @@ -0,0 +1,86 @@ +#pragma once + +#include "pcapplusplus/Packet.h" +#include "pcapplusplus/IpAddress.h" + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + /** + * A struct that represent a single buffer + */ + template struct ScalarBuffer + { + /** + * The pointer to the buffer + */ + T* buffer; + + /** + * Buffer length + */ + size_t len; + }; + + /** + * Computes the checksum for a vector of buffers + * @param[in] vec The vector of buffers + * @param[in] vecSize Number of ScalarBuffers in vector + * @return The checksum result + */ + uint16_t computeChecksum(ScalarBuffer vec[], size_t vecSize); + + /** + * Computes the checksum for Pseudo header + * @param[in] dataPtr Data pointer + * @param[in] dataLen Data length + * @param[in] ipAddrType IP address type(IPv4/IPv6) type @ref IPAddress::AddressType + * @param[in] protocolType Current protocol type @ref IPProtocolTypes + * @param[in] srcIPAddress Source IP Address + * @param[in] dstIPAddress Destination IP Address + * @return The checksum result + */ + uint16_t computePseudoHdrChecksum(uint8_t* dataPtr, size_t dataLen, IPAddress::AddressType ipAddrType, + uint8_t protocolType, IPAddress srcIPAddress, IPAddress dstIPAddress); + + /** + * Computes Fowler-Noll-Vo (FNV-1) 32bit hash function on an array of byte buffers. The hash is calculated on each + * byte in each byte buffer, as if all byte buffers were one long byte buffer + * @param[in] vec An array of byte buffers (ScalarBuffer of type uint8_t) + * @param[in] vecSize The length of vec + * @return The 32bit hash value + */ + uint32_t fnvHash(ScalarBuffer vec[], size_t vecSize); + + /** + * Computes Fowler-Noll-Vo (FNV-1) 32bit hash function on a byte buffer + * @param[in] buffer The byte buffer + * @param[in] bufSize The size of the byte buffer + * @return The 32bit hash value + */ + uint32_t fnvHash(uint8_t* buffer, size_t bufSize); + + /** + * A method that is given a packet and calculates a hash value by the packet's 5-tuple. Supports IPv4, IPv6, + * TCP and UDP. For packets which doesn't have 5-tuple (for example: packets which aren't IPv4/6 or aren't + * TCP/UDP) the value of 0 will be returned + * @param[in] packet The packet to calculate hash for + * @param[in] directionUnique Make hash value unique for each direction + * @return The hash value calculated for this packet or 0 if the packet doesn't contain 5-tuple + */ + uint32_t hash5Tuple(Packet* packet, bool const& directionUnique = false); + + /** + * A method that is given a packet and calculates a hash value by the packet's 2-tuple (IP src + IP dst). Supports + * IPv4 and IPv6. For packets which aren't IPv4/6 the value of 0 will be returned + * @param[in] packet The packet to calculate hash for + * @return The hash value calculated for this packet or 0 if the packet isn't IPv4/6 + */ + uint32_t hash2Tuple(Packet* packet); + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/PayloadLayer.h b/Packet++/header/pcapplusplus/PayloadLayer.h new file mode 100644 index 0000000000..71560023cd --- /dev/null +++ b/Packet++/header/pcapplusplus/PayloadLayer.h @@ -0,0 +1,107 @@ +#pragma once + +#include "pcapplusplus/Layer.h" + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * @class PayloadLayer + * Represents a generic or unknown layer or a packet payload + */ + class PayloadLayer : public Layer + { + public: + /** A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + PayloadLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : Layer(data, dataLen, prevLayer, packet, GenericPayload) + {} + + /** + * A constructor that allocates a new payload + * @param[in] data A raw buffer that will be used as a payload. This data will be copied to the layer + * @param[in] dataLen The raw buffer length + */ + PayloadLayer(const uint8_t* data, size_t dataLen); + + /** + * A constructor that allocates a new payload from an hex stream + * @param[in] payloadAsHexStream A string that represents an hex stream of the payload. For example: + * 0001080006040002842b2b774c56c0a80078000000000000c0a8. In order for the hex stream to be valid it has to + * contain valid hex chars only (which means, for example, that it can't begin with "0x") and it also has to + * have an even number of chars (each char represents one nibble). If the string is not a valid hex stream an + * error will be printed to log and the payload layer will be empty (no data) + */ + explicit PayloadLayer(const std::string& payloadAsHexStream); + + ~PayloadLayer() + {} + + /** + * Get a pointer to the payload data + * @return A pointer to the payload data + */ + uint8_t* getPayload() const + { + return m_Data; + } + + /** + * Get the payload data length + * @return The payload data length in bytes + */ + size_t getPayloadLen() const + { + return m_DataLen; + } + + // implement abstract methods + + /** + * Does nothing for this layer (PayloadLayer is always last) + */ + void parseNextLayer() + {} + + /** + * @return Payload data length in bytes + */ + size_t getHeaderLen() const + { + return m_DataLen; + } + + /** + * Does nothing for this layer + */ + void computeCalculateFields() + {} + + /** + * Sets the payload of the PayloadLayer to the given pointer. This will resize (extend/shorten) the underlying + * packet respectively if there is one. + * @param[in] newPayload New payload that shall be set + * @param[in] newPayloadLength New length of payload + */ + void setPayload(const uint8_t* newPayload, size_t newPayloadLength); + + std::string toString() const; + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelApplicationLayer; + } + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/ProtocolType.h b/Packet++/header/pcapplusplus/ProtocolType.h new file mode 100644 index 0000000000..ada6950c5e --- /dev/null +++ b/Packet++/header/pcapplusplus/ProtocolType.h @@ -0,0 +1,373 @@ +#pragma once + +#include + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + /** + * @typedef ProtocolType + * Representing all protocols supported by PcapPlusPlus + */ + typedef uint8_t ProtocolType; + + /** + * @typedef ProtocolTypeFamily + * Representing a family of protocols + */ + typedef uint32_t ProtocolTypeFamily; + + /** + * Unknown protocol (or unsupported by PcapPlusPlus) + */ + const ProtocolType UnknownProtocol = 0; + + /** + * Ethernet protocol + */ + const ProtocolType Ethernet = 1; + + /** + * IPv4 protocol + */ + const ProtocolType IPv4 = 2; + + /** + * IPv6 protocol + */ + const ProtocolType IPv6 = 3; + + /** + * IP protocol family (IPv4 and IPv6 protocols) + */ + const ProtocolTypeFamily IP = 0x203; + + /** + * TCP protocol + */ + const ProtocolType TCP = 4; + + /** + * UDP protocol + */ + const ProtocolType UDP = 5; + + /** + * HTTP request protocol + */ + const ProtocolType HTTPRequest = 6; + + /** + * HTTP response protocol + */ + const ProtocolType HTTPResponse = 7; + + /** + * HTTP protocol family (HTTP request and HTTP response protocols) + */ + const ProtocolTypeFamily HTTP = 0x607; + + /** + * ARP protocol + */ + const ProtocolType ARP = 8; + + /** + * VLAN protocol + */ + const ProtocolType VLAN = 9; + + /** + * ICMP protocol + */ + const ProtocolType ICMP = 10; + + /** + * PPPoE session protocol + */ + const ProtocolType PPPoESession = 11; + + /** + * PPPoE discovery protocol + */ + const ProtocolType PPPoEDiscovery = 12; + + /** + * PPPoE protocol family (PPPoESession and PPPoEDiscovery protocols) + */ + const ProtocolTypeFamily PPPoE = 0xb0c; + + /** + * DNS protocol + */ + const ProtocolType DNS = 13; + + /** + * MPLS protocol + */ + const ProtocolType MPLS = 14; + + /** + * GRE version 0 protocol + */ + const ProtocolType GREv0 = 15; + + /** + * GRE version 1 protocol + */ + const ProtocolType GREv1 = 16; + + /** + * GRE protocol family (GREv0 and GREv1 protocols) + */ + const ProtocolTypeFamily GRE = 0xf10; + + /** + * PPP for PPTP protocol + */ + const ProtocolType PPP_PPTP = 17; + + /** + * SSL/TLS protocol + */ + const ProtocolType SSL = 18; + + /** + * SLL (Linux cooked capture) protocol + */ + const ProtocolType SLL = 19; + + /** + * DHCP/BOOTP protocol + */ + const ProtocolType DHCP = 20; + + /** + * Null/Loopback protocol + */ + const ProtocolType NULL_LOOPBACK = 21; + + /** + * IGMPv1 protocol + */ + const ProtocolType IGMPv1 = 22; + + /** + * IGMPv2 protocol + */ + const ProtocolType IGMPv2 = 23; + + /** + * IGMPv3 protocol + */ + const ProtocolType IGMPv3 = 24; + + /** + * IGMP protocol family (IGMPv1, IGMPv2, IGMPv3) + */ + const ProtocolTypeFamily IGMP = 0x161718; + + /** + * Generic payload (no specific protocol) + */ + const ProtocolType GenericPayload = 25; + + /** + * VXLAN protocol + */ + const ProtocolType VXLAN = 26; + + /** + * SIP request protocol + */ + const ProtocolType SIPRequest = 27; + + /** + * SIP response protocol + */ + const ProtocolType SIPResponse = 28; + + /** + * SIP protocol family (SIPRequest and SIPResponse protocols) + */ + const ProtocolTypeFamily SIP = 0x1b1c; + + /** + * SDP protocol + */ + const ProtocolType SDP = 29; + + /** + * Packet trailer + */ + const ProtocolType PacketTrailer = 30; + + /** + * RADIUS protocol + */ + const ProtocolType Radius = 31; + + /** + * GTPv1 protocol + */ + const ProtocolType GTPv1 = 32; + + /** + * GTP protocol family (currently only GTPv1) + */ + const ProtocolTypeFamily GTP = 0x20; + + /** + * IEEE 802.3 Ethernet protocol + */ + const ProtocolType EthernetDot3 = 33; + + /** + * Border Gateway Protocol (BGP) version 4 protocol + */ + const ProtocolType BGP = 34; + + /** + * SSH version 2 protocol + */ + const ProtocolType SSH = 35; + + /** + * IPSec Authentication Header (AH) protocol + */ + const ProtocolType AuthenticationHeader = 36; + + /** + * IPSec Encapsulating Security Payload (ESP) protocol + */ + const ProtocolType ESP = 37; + + /** + * IPSec protocol family (AH and ESP protocols) + */ + const ProtocolTypeFamily IPSec = 0x2425; + + /** + * Dynamic Host Configuration Protocol version 6 (DHCPv6) protocol + */ + const ProtocolType DHCPv6 = 38; + + /** + * Network Time (NTP) Protocol + */ + const ProtocolType NTP = 39; + + /** + * Telnet Protocol + */ + const ProtocolType Telnet = 40; + + /** + * File Transfer (FTP) Protocol + */ + const ProtocolType FTP = 41; + + /** + * ICMPv6 protocol + */ + const ProtocolType ICMPv6 = 42; + + /** + * Spanning Tree Protocol + */ + const ProtocolType STP = 43; + + /** + * Logical Link Control (LLC) + */ + const ProtocolType LLC = 44; + + /** + * SOME/IP Base protocol + */ + const ProtocolType SomeIP = 45; + + /** + * Wake On LAN (WOL) Protocol + */ + const ProtocolType WakeOnLan = 46; + + /** + * NFLOG (Linux Netfilter NFLOG) Protocol + */ + const ProtocolType NFLOG = 47; + + /** + * TPKT protocol + */ + const ProtocolType TPKT = 48; + + /** + * VRRP version 2 protocol + */ + const ProtocolType VRRPv2 = 49; + + /** + * VRRP version 3 protocol + */ + const ProtocolType VRRPv3 = 50; + + /** + * VRRP protocol family (VRRPv2 and VRRPv3 protocols) + */ + const ProtocolTypeFamily VRRP = 0x3132; + + /** + * COTP protocol + */ + const ProtocolType COTP = 51; + + /** + * SLL2 protocol + */ + const ProtocolType SLL2 = 52; + + /** + * S7COMM protocol + */ + const ProtocolType S7COMM = 53; + + /* + * SMTP protocol + */ + const ProtocolType SMTP = 54; + + /* + * LDAP protocol + */ + const ProtocolType LDAP = 55; + + /** + * An enum representing OSI model layers + */ + enum OsiModelLayer + { + /** Physical layer (layer 1) */ + OsiModelPhysicalLayer = 1, + /** Data link layer (layer 2) */ + OsiModelDataLinkLayer = 2, + /** Network layer (layer 3) */ + OsiModelNetworkLayer = 3, + /** Transport layer (layer 4) */ + OsiModelTransportLayer = 4, + /** Session layer (layer 5) */ + OsiModelSesionLayer = 5, + /** Presentation layer (layer 6) */ + OsiModelPresentationLayer = 6, + /** Application layer (layer 7) */ + OsiModelApplicationLayer = 7, + /** Unknown / null layer */ + OsiModelLayerUnknown = 8 + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/RadiusLayer.h b/Packet++/header/pcapplusplus/RadiusLayer.h new file mode 100644 index 0000000000..7317257e9f --- /dev/null +++ b/Packet++/header/pcapplusplus/RadiusLayer.h @@ -0,0 +1,362 @@ +#pragma once + +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/TLVData.h" + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * @struct radius_header + * Represents a RADIUS protocol header + */ +#pragma pack(push, 1) + struct radius_header + { + /** RADIUS message code */ + uint8_t code; + /** RADIUS message ID */ + uint8_t id; + /** RADIUS message length */ + uint16_t length; + /** Used to authenticate the reply from the RADIUS server and to encrypt passwords */ + uint8_t authenticator[16]; + }; +#pragma pack(pop) + + /** + * @class RadiusAttribute + * A wrapper class for RADIUS attributes. This class does not create or modify RADIUS attribute records, but rather + * serves as a wrapper and provides useful methods for retrieving data from them + */ + class RadiusAttribute : public TLVRecord + { + public: + /** + * A c'tor for this class that gets a pointer to the attribute raw data (byte array) + * @param[in] attrRawData A pointer to the attribute raw data + */ + explicit RadiusAttribute(uint8_t* attrRawData) : TLVRecord(attrRawData) + {} + + /** + * A d'tor for this class, currently does nothing + */ + virtual ~RadiusAttribute() + {} + + // implement abstract methods + + size_t getTotalSize() const + { + if (m_Data == nullptr) + return 0; + + return (size_t)m_Data->recordLen; + } + + size_t getDataSize() const + { + if (m_Data == nullptr) + return 0; + + return (size_t)m_Data->recordLen - 2 * sizeof(uint8_t); + } + }; + + /** + * @class RadiusAttributeBuilder + * A class for building RADIUS attributes. This builder receives the attribute parameters in its c'tor, + * builds the RADIUS attribute raw buffer and provides a build() method to get a RadiusAttribute object out of it + */ + class RadiusAttributeBuilder : public TLVRecordBuilder + { + public: + /** + * A c'tor for building RADIUS attributes which their value is a byte array. The RadiusAttribute object can + * later be retrieved by calling build() + * @param[in] attrType RADIUS attribute type + * @param[in] attrValue A buffer containing the attribute value. This buffer is read-only and isn't modified in + * any way + * @param[in] attrValueLen Attribute value length in bytes + */ + RadiusAttributeBuilder(uint8_t attrType, const uint8_t* attrValue, uint8_t attrValueLen) + : TLVRecordBuilder(attrType, attrValue, attrValueLen) + {} + + /** + * A c'tor for building RADIUS attributes which have a 1-byte value. The RadiusAttribute object can later be + * retrieved by calling build() + * @param[in] attrType RADIUS attribute type + * @param[in] attrValue A 1-byte attribute value + */ + RadiusAttributeBuilder(uint8_t attrType, uint8_t attrValue) : TLVRecordBuilder(attrType, attrValue) + {} + + /** + * A c'tor for building RADIUS attributes which have a 2-byte value. The RadiusAttribute object can later be + * retrieved by calling build() + * @param[in] attrType RADIUS attribute type + * @param[in] attrValue A 2-byte attribute value + */ + RadiusAttributeBuilder(uint8_t attrType, uint16_t attrValue) : TLVRecordBuilder(attrType, attrValue) + {} + + /** + * A c'tor for building RADIUS attributes which have a 4-byte value. The RadiusAttribute object can later be + * retrieved by calling build() + * @param[in] attrType RADIUS attribute type + * @param[in] attrValue A 4-byte attribute value + */ + RadiusAttributeBuilder(uint8_t attrType, uint32_t attrValue) : TLVRecordBuilder(attrType, attrValue) + {} + + /** + * A c'tor for building RADIUS attributes which have an IPv4Address value. The RadiusAttribute object can later + * be retrieved by calling build() + * @param[in] attrType RADIUS attribute type + * @param[in] attrValue The IPv4 address attribute value + */ + RadiusAttributeBuilder(uint8_t attrType, const IPv4Address& attrValue) : TLVRecordBuilder(attrType, attrValue) + {} + + /** + * A c'tor for building RADIUS attributes which have a string value. The RadiusAttribute object can later be + * retrieved by calling build() + * @param[in] attrType RADIUS attribute type + * @param[in] attrValue The string attribute value + */ + RadiusAttributeBuilder(uint8_t attrType, const std::string& attrValue) : TLVRecordBuilder(attrType, attrValue) + {} + + /** + * A copy c'tor which copies all the data from another instance of RadiusAttributeBuilder + * @param[in] other The instance to copy from + */ + RadiusAttributeBuilder(const RadiusAttributeBuilder& other) : TLVRecordBuilder(other) + {} + + /** + * Assignment operator that copies all data from another instance of RadiusAttributeBuilder + * @param[in] other The instance to assign from + */ + RadiusAttributeBuilder& operator=(const RadiusAttributeBuilder& other) + { + TLVRecordBuilder::operator=(other); + return *this; + } + + /** + * Build the RadiusAttribute object out of the parameters defined in the c'tor + * @return The RadiusAttribute object + */ + RadiusAttribute build() const; + }; + + /** + * @class RadiusLayer + * Represents a RADIUS (Remote Authentication Dial-In User Service) protocol layer + */ + class RadiusLayer : public Layer + { + private: + TLVRecordReader m_AttributeReader; + + uint8_t* getAttributesBasePtr() const + { + return m_Data + sizeof(radius_header); + } + + RadiusAttribute addAttrAt(const RadiusAttributeBuilder& attrBuilder, int offset); + + public: + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + RadiusLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : Layer(data, dataLen, prevLayer, packet, Radius) + {} + + /** + * A constructor that creates a new layer from scratch + * @param[in] code The RADIUS message code + * @param[in] id The RADIUS message ID + * @param[in] authenticator A pointer to a byte array containing the authenticator value + * @param[in] authenticatorArrSize The authenticator byte array size. A valid size of the authenticator field is + * 16 bytes. If the provided size is less than that then the byte array will be copied to the packet but the + * missing bytes will stay zero. If the size is more than 16 bytes, only the first 16 bytes will be copied to + * the packet + */ + RadiusLayer(uint8_t code, uint8_t id, const uint8_t* authenticator, uint8_t authenticatorArrSize); + + /** + * A constructor that creates a new layer from scratch + * @param[in] code The RADIUS message code + * @param[in] id The RADIUS message ID + * @param[in] authenticator A hex string representing the authenticator value. A valid size of the authenticator + * field is 16 bytes. If the hex string represents an array that is smaller than this then the missing bytes in + * the packet's authenticator field will stay zero. If the hex string represents an array that is larger than 16 + * bytes, only the first 16 bytes will be copied to the packet + */ + RadiusLayer(uint8_t code, uint8_t id, const std::string& authenticator); + + /** + * A d'tor for this layer, currently does nothing + */ + ~RadiusLayer() + {} + + /** + * Get a pointer to the RADIUS header. Notice this points directly to the data, so every change will change the + * actual packet data + * @return A pointer to the radius_header object + */ + radius_header* getRadiusHeader() const + { + return (radius_header*)m_Data; + } + + /** + * @return A hex string representation of the radius_header#authenticator byte array value + */ + std::string getAuthenticatorValue() const; + + /** + * Setter for radius_header#authenticator + * @param[in] authValue A hex string representing the requested authenticator value + */ + void setAuthenticatorValue(const std::string& authValue); + + /** + * A static method that returns the RADIUS message string for a give message code. For example: the string + * "Access-Request" will be returned for code 1 + * @param[in] radiusMessageCode RADIUS message code + * @return RADIUS message string + */ + static std::string getRadiusMessageString(uint8_t radiusMessageCode); + + /** + * @return The first RADIUS attribute in the packet. If there are no attributes the returned value will contain + * a logical null (RadiusAttribute#isNull() == true) + */ + RadiusAttribute getFirstAttribute() const; + + /** + * Get the RADIUS attribute that comes after a given attribute. If the given attribute was the last one, the + * returned value will contain a logical null (RadiusAttribute#isNull() == true) + * @param[in] attr A given attribute + * @return A RadiusAttribute object containing the attribute data that comes next, or logical null if the + * given attribute: (1) was the last one; (2) contains a logical null or (3) doesn't belong to this packet + */ + RadiusAttribute getNextAttribute(RadiusAttribute& attr) const; + + /** + * Get a RADIUS attribute by attribute type + * @param[in] attrType RADIUS attribute type + * @return A RadiusAttribute object containing the first attribute data that matches this type, or logical + * null (RadiusAttribute#isNull() == true) if no such attribute found + */ + RadiusAttribute getAttribute(uint8_t attrType) const; + + /** + * @return The number of RADIUS attributes in the packet + */ + size_t getAttributeCount() const; + + /** + * Add a new RADIUS attribute at the end of the layer + * @param[in] attrBuilder A RadiusAttributeBuilder object that contains the requested attribute data to add + * @return A RadiusAttribute object containing the newly added RADIUS attribute data or logical null + * (RadiusAttribute#isNull() == true) if addition failed + */ + RadiusAttribute addAttribute(const RadiusAttributeBuilder& attrBuilder); + + /** + * Add a new RADIUS attribute after an existing one + * @param[in] attrBuilder A RadiusAttributeBuilder object that contains the requested attribute data to add + * @param[in] prevAttrType The RADIUS attribute which the newly added attribute will come after + * @return A RadiusAttribute object containing the newly added RADIUS attribute data or logical null + * (RadiusAttribute#isNull() == true) if addition failed + */ + RadiusAttribute addAttributeAfter(const RadiusAttributeBuilder& attrBuilder, uint8_t prevAttrType); + + /** + * Remove an existing RADIUS attribute from the layer + * @param[in] attrType The RADIUS attribute type to remove + * @return True if the RADIUS attribute was successfully removed or false if type wasn't found or if removal + * failed + */ + bool removeAttribute(uint8_t attrType); + + /** + * Remove all RADIUS attributes in this layer + * @return True if all attributes were successfully removed or false if removal failed for some reason + */ + bool removeAllAttributes(); + + /** + * The static method makes validation of UDP data + * @param[in] udpData The pointer to the UDP payload data. It points to the first byte of RADIUS header. + * @param[in] udpDataLen The payload data size + * @return True if the data is valid and can represent the RADIUS packet + */ + static bool isDataValid(const uint8_t* udpData, size_t udpDataLen); + + /** + * A static method that checks whether the port is considered as RADIUS + * @param[in] port The port number to be checked + */ + static inline bool isRadiusPort(uint16_t port); + + // implement abstract methods + + /** + * @return The size written in radius_header#length + */ + size_t getHeaderLen() const; + + /** + * Does nothing for this layer, RADIUS is always last + */ + void parseNextLayer() + {} + + /** + * Calculate and store the value of radius_header#length according to the layer size + */ + void computeCalculateFields(); + + std::string toString() const; + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelApplicationLayer; + } + }; + + // implementation of inline methods + + bool RadiusLayer::isRadiusPort(uint16_t port) + { + switch (port) + { + case 1812: + case 1813: + case 3799: + return true; + default: + return false; + } + } // isRadiusPort + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/RawPacket.h b/Packet++/header/pcapplusplus/RawPacket.h new file mode 100644 index 0000000000..d3136ed9c8 --- /dev/null +++ b/Packet++/header/pcapplusplus/RawPacket.h @@ -0,0 +1,526 @@ +#pragma once + +#include +#ifdef _MSC_VER +# include +# include +#else +# include +#endif +#include + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * An enum describing all known link layer type. Taken from: http://www.tcpdump.org/linktypes.html . + */ + enum LinkLayerType + { + /** BSD loopback encapsulation */ + LINKTYPE_NULL = 0, + /** IEEE 802.3 Ethernet */ + LINKTYPE_ETHERNET = 1, + /** AX.25 packet */ + LINKTYPE_AX25 = 3, + /** IEEE 802.5 Token Ring */ + LINKTYPE_IEEE802_5 = 6, + /** ARCNET Data Packets */ + LINKTYPE_ARCNET_BSD = 7, + /** SLIP, encapsulated with a LINKTYPE_SLIP header */ + LINKTYPE_SLIP = 8, + /** PPP, as per RFC 1661 and RFC 1662 */ + LINKTYPE_PPP = 9, + /** FDDI, as specified by ANSI INCITS 239-1994 */ + LINKTYPE_FDDI = 10, + /** Raw IP */ + LINKTYPE_DLT_RAW1 = 12, + /** Raw IP (OpenBSD) */ + LINKTYPE_DLT_RAW2 = 14, + /** PPP in HDLC-like framing, as per RFC 1662, or Cisco PPP with HDLC framing, as per section 4.3.1 of RFC 1547 + */ + LINKTYPE_PPP_HDLC = 50, + /** PPPoE */ + LINKTYPE_PPP_ETHER = 51, + /** RFC 1483 LLC/SNAP-encapsulated ATM */ + LINKTYPE_ATM_RFC1483 = 100, + /** Raw IP */ + LINKTYPE_RAW = 101, + /** Cisco PPP with HDLC framing */ + LINKTYPE_C_HDLC = 104, + /** IEEE 802.11 wireless LAN */ + LINKTYPE_IEEE802_11 = 105, + /** Frame Relay */ + LINKTYPE_FRELAY = 107, + /** OpenBSD loopback encapsulation */ + LINKTYPE_LOOP = 108, + /** Linux "cooked" capture encapsulation */ + LINKTYPE_LINUX_SLL = 113, + /** Apple LocalTalk */ + LINKTYPE_LTALK = 114, + /** OpenBSD pflog */ + LINKTYPE_PFLOG = 117, + /** Prism monitor mode information followed by an 802.11 header */ + LINKTYPE_IEEE802_11_PRISM = 119, + /** RFC 2625 IP-over-Fibre Channel */ + LINKTYPE_IP_OVER_FC = 122, + /** ATM traffic, encapsulated as per the scheme used by SunATM devices */ + LINKTYPE_SUNATM = 123, + /** Radiotap link-layer information followed by an 802.11 header */ + LINKTYPE_IEEE802_11_RADIOTAP = 127, + /** ARCNET Data Packets, as described by the ARCNET Trade Association standard ATA 878.1-1999 */ + LINKTYPE_ARCNET_LINUX = 129, + /** Apple IP-over-IEEE 1394 cooked header */ + LINKTYPE_APPLE_IP_OVER_IEEE1394 = 138, + /** Signaling System 7 Message Transfer Part Level 2 */ + LINKTYPE_MTP2_WITH_PHDR = 139, + /** Signaling System 7 Message Transfer Part Level 2 */ + LINKTYPE_MTP2 = 140, + /** Signaling System 7 Message Transfer Part Level 3 */ + LINKTYPE_MTP3 = 141, + /** Signaling System 7 Signalling Connection Control Part */ + LINKTYPE_SCCP = 142, + /** Signaling System 7 Signalling Connection Control Part */ + LINKTYPE_DOCSIS = 143, + /** Linux-IrDA packets */ + LINKTYPE_LINUX_IRDA = 144, + /** Reserved for private use */ + LINKTYPE_USER0 = 147, + /** Reserved for private use */ + LINKTYPE_USER1 = 148, + /** Reserved for private use */ + LINKTYPE_USER2 = 149, + /** Reserved for private use */ + LINKTYPE_USER3 = 150, + /** Reserved for private use */ + LINKTYPE_USER4 = 151, + /** Reserved for private use */ + LINKTYPE_USER5 = 152, + /** Reserved for private use */ + LINKTYPE_USER6 = 153, + /** Reserved for private use */ + LINKTYPE_USER7 = 154, + /** Reserved for private use */ + LINKTYPE_USER8 = 155, + /** Reserved for private use */ + LINKTYPE_USER9 = 156, + /** Reserved for private use */ + LINKTYPE_USER10 = 157, + /** Reserved for private use */ + LINKTYPE_USER11 = 158, + /** Reserved for private use */ + LINKTYPE_USER12 = 159, + /** Reserved for private use */ + LINKTYPE_USER13 = 160, + /** Reserved for private use */ + LINKTYPE_USER14 = 161, + /** Reserved for private use */ + LINKTYPE_USER15 = 162, + /** AVS monitor mode information followed by an 802.11 header */ + LINKTYPE_IEEE802_11_AVS = 163, + /** BACnet MS/TP frames */ + LINKTYPE_BACNET_MS_TP = 165, + /** PPP in HDLC-like encapsulation, like LINKTYPE_PPP_HDLC, but with the 0xff address byte replaced by a + * direction indication - 0x00 for incoming and 0x01 for outgoing */ + LINKTYPE_PPP_PPPD = 166, + /** General Packet Radio Service Logical Link Control */ + LINKTYPE_GPRS_LLC = 169, + /** Transparent-mapped generic framing procedure */ + LINKTYPE_GPF_T = 170, + /** Frame-mapped generic framing procedure */ + LINKTYPE_GPF_F = 171, + /** Link Access Procedures on the D Channel (LAPD) frames */ + LINKTYPE_LINUX_LAPD = 177, + /** Bluetooth HCI UART transport layer */ + LINKTYPE_BLUETOOTH_HCI_H4 = 187, + /** USB packets, beginning with a Linux USB header */ + LINKTYPE_USB_LINUX = 189, + /** Per-Packet Information information */ + LINKTYPE_PPI = 192, + /** IEEE 802.15.4 wireless Personal Area Network */ + LINKTYPE_IEEE802_15_4 = 195, + /** Various link-layer types, with a pseudo-header, for SITA */ + LINKTYPE_SITA = 196, + /** Various link-layer types, with a pseudo-header, for Endace DAG cards; encapsulates Endace ERF record */ + LINKTYPE_ERF = 197, + /** Bluetooth HCI UART transport layer */ + LINKTYPE_BLUETOOTH_HCI_H4_WITH_PHDR = 201, + /** AX.25 packet, with a 1-byte KISS header containing a type indicator */ + LINKTYPE_AX25_KISS = 202, + /** Link Access Procedures on the D Channel (LAPD) frames */ + LINKTYPE_LAPD = 203, + /** PPP, as per RFC 1661 and RFC 1662, preceded with a one-byte pseudo-header with a zero value meaning + * "received by this host" and a non-zero value meaning "sent by this host" */ + LINKTYPE_PPP_WITH_DIR = 204, + /** Cisco PPP with HDLC framing */ + LINKTYPE_C_HDLC_WITH_DIR = 205, + /** Frame Relay */ + LINKTYPE_FRELAY_WITH_DIR = 206, + /** IPMB over an I2C circuit */ + LINKTYPE_IPMB_LINUX = 209, + /** IEEE 802.15.4 wireless Personal Area Network */ + LINKTYPE_IEEE802_15_4_NONASK_PHY = 215, + /** USB packets, beginning with a Linux USB header */ + LINKTYPE_USB_LINUX_MMAPPED = 220, + /** Fibre Channel FC-2 frames, beginning with a Frame_Header */ + LINKTYPE_FC_2 = 224, + /** Fibre Channel FC-2 frames */ + LINKTYPE_FC_2_WITH_FRAME_DELIMS = 225, + /** Solaris ipnet pseudo-header */ + LINKTYPE_IPNET = 226, + /** CAN (Controller Area Network) frames, with a pseudo-header as supplied by Linux SocketCAN */ + LINKTYPE_CAN_SOCKETCAN = 227, + /** Raw IPv4; the packet begins with an IPv4 header */ + LINKTYPE_IPV4 = 228, + /** Raw IPv6; the packet begins with an IPv6 header */ + LINKTYPE_IPV6 = 229, + /** IEEE 802.15.4 wireless Personal Area Network, without the FCS at the end of the frame */ + LINKTYPE_IEEE802_15_4_NOFCS = 230, + /** Raw D-Bus messages, starting with the endianness flag, followed by the message type, etc., but without the + * authentication handshake before the message sequence */ + LINKTYPE_DBUS = 231, + /** DVB-CI (DVB Common Interface for communication between a PC Card module and a DVB receiver), with the + * message format specified by the PCAP format for DVB-CI specification */ + LINKTYPE_DVB_CI = 235, + /** Variant of 3GPP TS 27.010 multiplexing protocol (similar to, but not the same as, 27.010) */ + LINKTYPE_MUX27010 = 236, + /** D_PDUs as described by NATO standard STANAG 5066, starting with the synchronization sequence, and including + * both header and data CRCs */ + LINKTYPE_STANAG_5066_D_PDU = 237, + /** Linux netlink NETLINK NFLOG socket log messages */ + LINKTYPE_NFLOG = 239, + /** Pseudo-header for Hilscher Gesellschaft für Systemautomation mbH netANALYZER devices, followed by an + * Ethernet frame, beginning with the MAC header and ending with the FCS */ + LINKTYPE_NETANALYZER = 240, + /** Pseudo-header for Hilscher Gesellschaft für Systemautomation mbH netANALYZER devices, followed by an + * Ethernet frame, beginning with the preamble, SFD, and MAC header, and ending with the FCS */ + LINKTYPE_NETANALYZER_TRANSPARENT = 241, + /** IP-over-InfiniBand, as specified by RFC 4391 section 6 */ + LINKTYPE_IPOIB = 242, + /** MPEG-2 Transport Stream transport packets, as specified by ISO 13818-1/ITU-T Recommendation H.222.0 */ + LINKTYPE_MPEG_2_TS = 243, + /** Pseudo-header for ng4T GmbH's UMTS Iub/Iur-over-ATM and Iub/Iur-over-IP format as used by their ng40 + * protocol tester */ + LINKTYPE_NG40 = 244, + /** Pseudo-header for NFC LLCP packet captures, followed by frame data for the LLCP Protocol as specified by + * NFCForum-TS-LLCP_1.1 */ + LINKTYPE_NFC_LLCP = 245, + /** Raw InfiniBand frames, starting with the Local Routing Header */ + LINKTYPE_INFINIBAND = 247, + /** SCTP packets, as defined by RFC 4960, with no lower-level protocols such as IPv4 or IPv6 */ + LINKTYPE_SCTP = 248, + /** USB packets, beginning with a USBPcap header */ + LINKTYPE_USBPCAP = 249, + /** Serial-line packet header for the Schweitzer Engineering Laboratories "RTAC" product */ + LINKTYPE_RTAC_SERIAL = 250, + /** Bluetooth Low Energy air interface Link Layer packets */ + LINKTYPE_BLUETOOTH_LE_LL = 251, + /** Linux Netlink capture encapsulation */ + LINKTYPE_NETLINK = 253, + /** Bluetooth Linux Monitor encapsulation of traffic for the BlueZ stack */ + LINKTYPE_BLUETOOTH_LINUX_MONITOR = 254, + /** Bluetooth Basic Rate and Enhanced Data Rate baseband packets */ + LINKTYPE_BLUETOOTH_BREDR_BB = 255, + /** Bluetooth Low Energy link-layer packets */ + LINKTYPE_BLUETOOTH_LE_LL_WITH_PHDR = 256, + /** PROFIBUS data link layer packets, as specified by IEC standard 61158-6-3 */ + LINKTYPE_PROFIBUS_DL = 257, + /** Apple PKTAP capture encapsulation */ + LINKTYPE_PKTAP = 258, + /** Ethernet-over-passive-optical-network packets */ + LINKTYPE_EPON = 259, + /** IPMI trace packets, as specified by Table 3-20 "Trace Data Block Format" in the PICMG HPM.2 specification */ + LINKTYPE_IPMI_HPM_2 = 260, + /** Per Joshua Wright , formats for Z-Wave RF profiles R1 and R2 captures */ + LINKTYPE_ZWAVE_R1_R2 = 261, + /** Per Joshua Wright , formats for Z-Wave RF profile R3 captures */ + LINKTYPE_ZWAVE_R3 = 262, + /** Formats for WattStopper Digital Lighting Management (DLM) and Legrand Nitoo Open protocol common packet + * structure captures */ + LINKTYPE_WATTSTOPPER_DLM = 263, + /** Messages between ISO 14443 contactless smartcards (Proximity Integrated Circuit Card, PICC) and card readers + * (Proximity Coupling Device, PCD), with the message format specified by the PCAP format for ISO14443 + * specification */ + LINKTYPE_ISO_14443 = 264, + /** Linux "cooked" capture encapsulation v2 */ + LINKTYPE_LINUX_SLL2 = 276, + /** Set if interface ID for a packet of a pcapng file is too high */ + LINKTYPE_INVALID = 0xFFFF + }; + + /** + * Max packet size supported + */ +#define PCPP_MAX_PACKET_SIZE 65536 + + /** + * @class RawPacket + * This class holds the packet as raw (not parsed) data. The data is held as byte array. In addition to the data + * itself every instance also holds a timestamp representing the time the packet was received by the NIC. RawPacket + * instance isn't read only. The user can change the packet data, add or remove data, etc. + */ + class RawPacket + { + protected: + uint8_t* m_RawData; + int m_RawDataLen; + int m_FrameLength; + timespec m_TimeStamp; + bool m_DeleteRawDataAtDestructor; + bool m_RawPacketSet; + LinkLayerType m_LinkLayerType; + void init(bool deleteRawDataAtDestructor = true); + void copyDataFrom(const RawPacket& other, bool allocateData = true); + + public: + /** + * A constructor that receives a pointer to the raw data (allocated elsewhere). This constructor is usually used + * when packet is captured using a packet capturing engine (like libPcap. WinPcap, Npcap, PF_RING, etc.). The + * capturing engine allocates the raw data memory and give the user a pointer to it + a timestamp it has arrived + * to the device + * @param[in] pRawData A pointer to the raw data + * @param[in] rawDataLen The raw data length in bytes + * @param[in] timestamp The timestamp packet was received by the NIC (in usec precision) + * @param[in] deleteRawDataAtDestructor An indicator whether raw data pointer should be freed when the instance + * is freed or not. If set to 'true' than pRawData will be freed when instanced is being freed + * @param[in] layerType The link layer type of this raw packet. The default is Ethernet + */ + RawPacket(const uint8_t* pRawData, int rawDataLen, timeval timestamp, bool deleteRawDataAtDestructor, + LinkLayerType layerType = LINKTYPE_ETHERNET); + + /** + * A constructor that receives a pointer to the raw data (allocated elsewhere). This constructor is usually used + * when packet is captured using a packet capturing engine (like libPcap. WinPcap, Npcap, PF_RING, etc.). The + * capturing engine allocates the raw data memory and give the user a pointer to it + a timestamp it has arrived + * to the device + * @param[in] pRawData A pointer to the raw data + * @param[in] rawDataLen The raw data length in bytes + * @param[in] timestamp The timestamp packet was received by the NIC (in nsec precision) + * @param[in] deleteRawDataAtDestructor An indicator whether raw data pointer should be freed when the instance + * is freed or not. If set to 'true' than pRawData will be freed when instanced is being freed + * @param[in] layerType The link layer type of this raw packet. The default is Ethernet + */ + RawPacket(const uint8_t* pRawData, int rawDataLen, timespec timestamp, bool deleteRawDataAtDestructor, + LinkLayerType layerType = LINKTYPE_ETHERNET); + + /** + * A default constructor that initializes class'es attributes to default value: + * - data pointer is set to nullptr + * - data length is set to 0 + * - deleteRawDataAtDestructor is set to 'true' + * @todo timestamp isn't set here to a default value + */ + RawPacket(); + + /** + * A destructor for this class. Frees the raw data if deleteRawDataAtDestructor was set to 'true' + */ + virtual ~RawPacket(); + + /** + * A copy constructor that copies all data from another instance. Notice all raw data is copied (using memcpy), + * so when the original or the other instance are freed, the other won't be affected + * @param[in] other The instance to copy from + */ + RawPacket(const RawPacket& other); + + /** + * Assignment operator overload for this class. When using this operator on an already initialized RawPacket + * instance, the original raw data is freed first. Then the other instance is copied to this instance, the same + * way the copy constructor works + * @todo free raw data only if deleteRawDataAtDestructor was set to 'true' + * @param[in] other The instance to copy from + */ + RawPacket& operator=(const RawPacket& other); + + /** + * @brief Clones the current packet. Caller is responsible for deallocation of the memory. + * @return A pointer to the new RawPacket object which is a clone of this object + */ + virtual RawPacket* clone() const; + + /** + * @return RawPacket object type. Each derived class should return a different value + */ + virtual uint8_t getObjectType() const + { + return 0; + } + + /** + * Set a raw data. If data was already set and deleteRawDataAtDestructor was set to 'true' the old data will be + * freed first + * @param[in] pRawData A pointer to the new raw data + * @param[in] rawDataLen The new raw data length in bytes + * @param[in] timestamp The timestamp packet was received by the NIC (in usec precision) + * @param[in] layerType The link layer type for this raw data + * @param[in] frameLength When reading from pcap files, sometimes the captured length is different from the + * actual packet length. This parameter represents the packet length. This parameter is optional, if not set or + * set to -1 it is assumed both lengths are equal + * @return True if raw data was set successfully, false otherwise + */ + virtual bool setRawData(const uint8_t* pRawData, int rawDataLen, timeval timestamp, + LinkLayerType layerType = LINKTYPE_ETHERNET, int frameLength = -1); + + /** + * Set a raw data. If data was already set and deleteRawDataAtDestructor was set to 'true' the old data will be + * freed first + * @param[in] pRawData A pointer to the new raw data + * @param[in] rawDataLen The new raw data length in bytes + * @param[in] timestamp The timestamp packet was received by the NIC (in nsec precision) + * @param[in] layerType The link layer type for this raw data + * @param[in] frameLength When reading from pcap files, sometimes the captured length is different from the + * actual packet length. This parameter represents the packet length. This parameter is optional, if not set or + * set to -1 it is assumed both lengths are equal + * @return True if raw data was set successfully, false otherwise + */ + virtual bool setRawData(const uint8_t* pRawData, int rawDataLen, timespec timestamp, + LinkLayerType layerType = LINKTYPE_ETHERNET, int frameLength = -1); + + /** + * Initialize a raw packet with data. The main difference between this method and setRawData() is that + * setRawData() is meant for replacing the data in an existing raw packet, whereas this method is meant to be + * used right after constructing a raw packet using the default c'tor, before setting any data + * @param pRawData A pointer to the new raw data + * @param rawDataLen The new raw data length in bytes + * @param timestamp The timestamp packet was received by the NIC (in nsec precision) + * @param layerType The link layer type for this raw data + * @return True if raw data was set successfully, false otherwise + */ + bool initWithRawData(const uint8_t* pRawData, int rawDataLen, timespec timestamp, + LinkLayerType layerType = LINKTYPE_ETHERNET); + + /** + * Get raw data pointer + * @return A read-only pointer to the raw data + */ + const uint8_t* getRawData() const + { + return m_RawData; + } + + /** + * Get the link layer type + * @return the type of the link layer + */ + LinkLayerType getLinkLayerType() const + { + return m_LinkLayerType; + } + + /** + * This static method validates whether a link type integer value is valid + * @param[in] linkTypeValue Link type integer value + * @return True if the link type value is valid and can be casted into LinkLayerType enum, false otherwise + */ + static bool isLinkTypeValid(int linkTypeValue); + + /** + * Get raw data length in bytes + * @return Raw data length in bytes + */ + int getRawDataLen() const + { + return m_RawDataLen; + } + + /** + * Get frame length in bytes + * @return frame length in bytes + */ + int getFrameLength() const + { + return m_FrameLength; + } + /** + * Get raw data timestamp + * @return Raw data timestamp + */ + timespec getPacketTimeStamp() const + { + return m_TimeStamp; + } + + /** + * Set raw packet timestamp with usec precision + * @param[in] timestamp The timestamp to set (with usec precision) + * @return True if timestamp was set successfully, false otherwise + */ + virtual bool setPacketTimeStamp(timeval timestamp); + + /** + * Set raw packet timestamp with nsec precision + * @param[in] timestamp The timestamp to set (with nsec precision) + * @return True if timestamp was set successfully, false otherwise + */ + virtual bool setPacketTimeStamp(timespec timestamp); + + /** + * Get an indication whether raw data was already set for this instance. + * @return True if raw data was set for this instance. Raw data can be set using the non-default constructor, + * using setRawData(), using the copy constructor or using the assignment operator. Returns false otherwise, for + * example: if the instance was created using the default constructor or clear() was called + */ + bool isPacketSet() const + { + return m_RawPacketSet; + } + + /** + * Clears all members of this instance, meaning setting raw data to nullptr, raw data length to 0, etc. + * Currently raw data is always freed, even if deleteRawDataAtDestructor was set to 'false' + * @todo deleteRawDataAtDestructor was set to 'true', don't free the raw data + * @todo set timestamp to a default value as well + */ + virtual void clear(); + + /** + * Append data to the end of current data. This method works without allocating more memory, it just uses + * memcpy() to copy dataToAppend at the end of the current data. This means that the method assumes this memory + * was already allocated by the user. If it isn't the case then this method will cause memory corruption + * @param[in] dataToAppend A pointer to the data to append to current raw data + * @param[in] dataToAppendLen Length in bytes of dataToAppend + */ + virtual void appendData(const uint8_t* dataToAppend, size_t dataToAppendLen); + + /** + * Insert new data at some index of the current data and shift the remaining old data to the end. This method + * works without allocating more memory, it just copies dataToAppend at the relevant index and shifts the + * remaining data to the end. This means that the method assumes this memory was already allocated by the user. + * If it isn't the case then this method will cause memory corruption + * @param[in] atIndex The index to insert the new data to + * @param[in] dataToInsert A pointer to the new data to insert + * @param[in] dataToInsertLen Length in bytes of dataToInsert + */ + virtual void insertData(int atIndex, const uint8_t* dataToInsert, size_t dataToInsertLen); + + /** + * Remove certain number of bytes from current raw data buffer. All data after the removed bytes will be shifted + * back + * @param[in] atIndex The index to start removing bytes from + * @param[in] numOfBytesToRemove Number of bytes to remove + * @return True if all bytes were removed successfully, or false if atIndex+numOfBytesToRemove is out-of-bounds + * of the raw data buffer + */ + virtual bool removeData(int atIndex, size_t numOfBytesToRemove); + + /** + * Re-allocate raw packet buffer meaning add size to it without losing the current packet data. This method + * allocates the required buffer size as instructed by the use and then copies the raw data from the current + * allocated buffer to the new one. This method can become useful if the user wants to insert or append data to + * the raw data, and the previous allocated buffer is too small, so the user wants to allocate a larger buffer + * and get RawPacket instance to point to it + * @param[in] newBufferLength The new buffer length as required by the user. The method is responsible to + * allocate the memory + * @return True if data was reallocated successfully, false otherwise + */ + virtual bool reallocateData(size_t newBufferLength); + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/S7CommLayer.h b/Packet++/header/pcapplusplus/S7CommLayer.h new file mode 100644 index 0000000000..7a6c02a66e --- /dev/null +++ b/Packet++/header/pcapplusplus/S7CommLayer.h @@ -0,0 +1,236 @@ +#pragma once + +#include "pcapplusplus/EthLayer.h" +#include "pcapplusplus/Layer.h" + +namespace pcpp +{ +/** + * @struct s7commhdr + * Represents a S7COMM protocol header + */ +#pragma pack(push, 1) + typedef struct + { + /** protocol id */ + uint8_t protocolId; + /** message type */ + uint8_t msgType; + /** redundancy identification (reserved) */ + uint16_t reserved; + /** protocol data unit reference */ + uint16_t pduRef; + /** parameter length */ + uint16_t paramLength; + /** data length */ + uint16_t dataLength; + } s7commhdr; +#pragma pack(pop) + +/** + * @struct s7comm_ack_data_hdr + * Represents a S7COMM protocol header with Ack-Data header + */ +#pragma pack(push, 1) + struct s7comm_ack_data_hdr : s7commhdr + { + /** error class */ + uint8_t errorClass; + /** error code */ + uint8_t errorCode; + }; +#pragma pack(pop) + + /** + * @class S7CommParameter + * Represents a S7COMM (S7 Communication) protocol Parameter + */ + class S7CommParameter + { + friend class S7CommLayer; + + public: + S7CommParameter() + {} + + virtual ~S7CommParameter() + {} + + /** + * @return The data of the Parameter + */ + uint8_t* getData() const + { + return m_Data; + } + /** + * @return The length of the Parameter data + */ + size_t getDataLength() const + { + return m_DataLen; + } + + private: + S7CommParameter(uint8_t* data, size_t dataLen) : m_Data(data), m_DataLen(dataLen) + {} + uint8_t* m_Data; + size_t m_DataLen; + }; + /** + * @class S7CommLayer + * Represents a S7COMM (S7 Communication) protocol + */ + class S7CommLayer : public Layer + { + public: + /** + * A constructor that allocates a new S7comm header + * @param[in] msgType The general type of the message + * @param[in] pduRef Link responses to their requests + * @param[in] paramLength The length of the parameter field + * @param[in] dataLength The length of the data field + * @param[in] errorClass The value of the error class + * @param[in] errorCode The value of the error code + */ + S7CommLayer(uint8_t msgType, uint16_t pduRef, uint16_t paramLength, uint16_t dataLength, uint8_t errorClass = 0, + uint8_t errorCode = 0); + + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data (will be casted to @ref s7commhdr) + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + S7CommLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : Layer(data, dataLen, prevLayer, packet, S7COMM) + { + m_Parameter = nullptr; + } + + virtual ~S7CommLayer() + { + if (m_Parameter) + delete m_Parameter; + } + + /** + * @return S7comm protocol id + */ + uint8_t getProtocolId() const; + + /** + * @return S7comm message type + */ + uint8_t getMsgType() const; + + /** + * @return S7comm PDU ref + */ + uint16_t getPduRef() const; + + /** + * @return S7comm parameter length + */ + uint16_t getParamLength() const; + + /** + * @return S7comm data length + */ + uint16_t getDataLength() const; + + /** + * @return S7comm error code + */ + uint8_t getErrorCode() const; + + /** + * @return S7comm error class + */ + uint8_t getErrorClass() const; + + /** + * @return S7comm parameter + */ + const S7CommParameter* getParameter(); + + /** + * Set the value of the message type + * @param[in] msgType The value of the message type + */ + void setMsgType(uint8_t msgType) const; + + /** + * Set the value of the PDU ref + * @param[in] pduRef The value of the PDU ref + */ + void setPduRef(uint16_t pduRef) const; + + /** + * Set the value of the error code + * @param[in] errorCode The value of the error code + */ + void setErrorCode(uint8_t errorCode) const; + /** + * Set the value of the error class + * @param[in] errorClass The value of the error class + */ + void setErrorClass(uint8_t errorClass) const; + + /** + * @return Size of S7CommLayer + */ + size_t getHeaderLen() const override + { + return m_DataLen; + } + + /** + * Does nothing for this layer (S7CommLayer is always last) + */ + void computeCalculateFields() override + {} + + /** + * Does nothing for this layer (S7CommLayer is always last) + */ + void parseNextLayer() override + {} + + /** + * A static method that takes a byte array and detects whether it is a S7COMM + * @param[in] data A byte array + * @param[in] dataSize The byte array size (in bytes) + * @return True if the data looks like a valid S7COMM layer + */ + static bool isDataValid(const uint8_t* data, size_t dataSize); + + std::string toString() const override; + + OsiModelLayer getOsiModelLayer() const override + { + return OsiModelApplicationLayer; + } + + private: + s7commhdr* getS7commHeader() const + { + return (s7commhdr*)m_Data; + } + + s7comm_ack_data_hdr* getS7commAckDataHeader() const + { + if (getS7commHeader()->msgType == 0x03) + { + return (s7comm_ack_data_hdr*)m_Data; + } + return nullptr; + } + + size_t getS7commHeaderLength() const; + + S7CommParameter* m_Parameter; + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/SSHLayer.h b/Packet++/header/pcapplusplus/SSHLayer.h new file mode 100644 index 0000000000..0c4a638340 --- /dev/null +++ b/Packet++/header/pcapplusplus/SSHLayer.h @@ -0,0 +1,479 @@ +#pragma once + +#include "pcapplusplus/Layer.h" + +/** + * @file + * This file introduces classes and structures that represent the SSH (Secure Shell) protocol. + * + * An overview of this protocol can be found here: https://en.wikipedia.org/wiki/Ssh_(Secure_Shell) + * + * For more details please refer to RFC 4253: https://tools.ietf.org/html/rfc4253 + * + * These current implementation supports parsing of SSH packets when possible (meaning when they are not encrypted). + * Creation and editing of SSH packets is currently __not supported__. + * + * SSH typically uses TCP port 22 so PcapPlusPlus assumes all traffic on this port is SSH traffic. + * PcapPlusPlus uses some heuristics to determine the type of the SSH message (which will be covered later). + * If it doesn't find a match to one of the other SSH messages, it assumes it is an encrypted SSH message. + * + * Following is an overview of the SSH protocol classes currently supported in PcapPlusPlus. They cover the different + * messages of the SSH protocol: + * + @verbatim + + +----------------------------+ SSH version identification + +---| SSHIdentificationMessage | ===> as described here: + | +----------------------------+ https://tools.ietf.org/html/rfc4253#section-4.2 + | + +------------+ | +----------------------------+ SSH handshake message + | SSHLayer |---------+---| SSHHandshakeMessage | ===> which is typically one of the messages described here: + | (abstract) | | +----------------------------+ https://tools.ietf.org/html/rfc4253#section-12 + +------------+ | | + | | +----------------------------+ + | +-----| SSHKeyExchangeInitMessage | ===> SSH Key Exchange message + | +----------------------------+ as described here: + | https://tools.ietf.org/html/rfc4253#section-7 + | + | +----------------------------+ + +---| SSHEncryptedMessage | ===> An encrypted SSH message + +----------------------------+ + + @endverbatim + + * The following points describe the heuristics for deciding the message type for each packet: + * 1. If the data starts with the characters "SSH-" and ends with "\n" (or "\r\n") it's assumed the message is of type + * pcpp#SSHIdentificationMessage + * 2. Try to determine if this is a non-encrypted SSH handshake message: + * - Look at the first 4 bytes of the data which may contain the packet length and see if the value is smaller of + * equal than the entire layer length. + * - The next byte contains the padding length, check if it's smaller or equal than the packet length + * - The next byte contains the message type, check if the value is a valid message type as described in: + * + * + * If all of these condition are met, this message is either pcpp#SSHKeyExchangeInitMessage (if message type is + * pcpp#SSHHandshakeMessage#SSH_MSG_KEX_INIT) or pcpp#SSHHandshakeMessage (for all other message types) + * 3. If non of these conditions are met, it is assumed this is an encrypted message (pcpp#SSHEncryptedMessage) + */ + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * @class SSHLayer + * This is the base class for the SSH layer. It is an abstract class that cannot be instantiated. + * It holds some common functionality, but its most important method is createSSHMessage() + * which takes raw data and creates an SSH message according to the heuristics described + * in the SSHLayer.h file description + */ + class SSHLayer : public Layer + { + public: + /** + * A static method that takes raw packet data and uses the heuristics described in the + * SSHLayer.h file description to create an SSH layer instance. This method assumes the data is + * indeed SSH data and not some other arbitrary data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + * @return An instance of one of the classes that inherit SSHLayer as described in the + * SSHLayer.h file description + */ + static SSHLayer* createSSHMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + /** + * A static method that takes src and dst ports and determines whether it's SSH traffic or not. + * @param[in] portSrc The source TCP port to examine + * @param[in] portDst The dest TCP port to examine + * @return Currently the implementation is very simple and returns "true" if either src or dst ports + * are equal to 22, "false" otherwise + */ + static bool isSSHPort(uint16_t portSrc, uint16_t portDst) + { + return portSrc == 22 || portDst == 22; + } + + // implement abstract methods + + /** + * Several SSH records can reside in a single packets. This method examins the remaining data and creates + * additional SSH records if applicable + */ + void parseNextLayer(); + + /** + * Does nothing for this layer + */ + void computeCalculateFields() + {} + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelApplicationLayer; + } + + protected: + // protected c'tor, this class cannot be instantiated + SSHLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : Layer(data, dataLen, prevLayer, packet, SSH) + {} + + private: + // this layer supports only parsing + SSHLayer(); + }; + + /** + * @class SSHIdentificationMessage + * A class that represents SSH identification message as described in RFC 4253: + * + * + * The message content is typically a string that contains the protocol version, software version and a few more + * details. This string can be retrieved using the getIdentificationMessage() method + */ + class SSHIdentificationMessage : public SSHLayer + { + public: + /** + * @return The SSH identification message which is typically the content of this message + */ + std::string getIdentificationMessage(); + + /** + * A static method that takes raw data and tries to parse it as an SSH identification message using the + * heuristics described in the SSHLayer.h file description. It returns a SSHIdentificationMessage instance if + * such a message can be identified or nullptr otherwise. + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + * @return An instance of SSHIdentificationMessage or nullptr if this is not an identification message + */ + static SSHIdentificationMessage* tryParse(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + // implement abstract methods + + /** + * @return The size of the identification message + */ + size_t getHeaderLen() const + { + return m_DataLen; + } + + std::string toString() const; + + private: + // this layer supports only parsing + SSHIdentificationMessage(); + + // private c'tor, this class cannot be instantiated + SSHIdentificationMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : SSHLayer(data, dataLen, prevLayer, packet) + {} + }; + + /** + * @class SSHHandshakeMessage + * A class representing all of the non-encrypted SSH handshake messages. + * An handshake message typically has the following structure: + * + @verbatim + 0 1 2 3 4 5 6 + +---------+---------+---------+---------+---------+---------+----------- ---------+ + | Packet Length | Padding | Message | Message .... Padding | + | | Length | Type | Content .... | + +---------------------------------------+---------+---------+----------- ---------+ + @endverbatim + * + * The first 4 bytes hold the packet length, followed by 1 byte that holds the padding length (which comes at the + * end of the message), then 1 byte that holds the message type (which can be of type + * SSHHandshakeMessage#SSHHandshakeMessageType) and then the message content. At the end of the content there is + * typically padding. + * + * This class provides access to all of these values. The message content itself is not parse with the exception of + * SSHKeyExchangeInitMessage + * which inherits from this class and provides parsing of the Key Exchange Init message. + */ + class SSHHandshakeMessage : public SSHLayer + { + public: + /** + * An enum that represents SSH non-encrypted message types + */ + enum SSHHandshakeMessageType + { + /** Key Exchange Init message */ + SSH_MSG_KEX_INIT = 20, + /** New Keys message */ + SSH_MSG_NEW_KEYS = 21, + /** Diffie-Hellman Key Exchange Init message */ + SSH_MSG_KEX_DH_INIT = 30, + /** message */ + SSH_MSG_KEX_DH_REPLY = 31, + /** Diffie-Hellman Group Exchange Init message */ + SSH_MSG_KEX_DH_GEX_INIT = 32, + /** "Diffie-Hellman Group Exchange Reply message */ + SSH_MSG_KEX_DH_GEX_REPLY = 33, + /** Diffie-Hellman Group Exchange Request message */ + SSH_MSG_KEX_DH_GEX_REQUEST = 34, + /** Unknown message */ + SSH_MSG_UNKNOWN = 999 + }; + + /** + * @return The message type + */ + SSHHandshakeMessageType getMessageType() const; + + /** + * @return A string representation of the message type + */ + std::string getMessageTypeStr() const; + + /** + * @return A raw byte stream of the message content + */ + uint8_t* getSSHHandshakeMessage() const; + + /** + * @return The message content length in [bytes] which is calculated by the overall packet length + * minus the message header (which includes packet length, padding length and message type) and + * minus the padding bytes + */ + size_t getSSHHandshakeMessageLength() const; + + /** + * @return The padding length in [bytes] + */ + size_t getPaddingLength() const; + + /** + * A static method that takes raw packet data and uses some heuristics described in the + * SSHLayer.h file description to parse it as SSH handshake message instance + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + * @return Upon successful parsing the return value would be an instance of SSHKeyExchangeInitMessage + * for Key Exchange Init message or SSHHandshakeMessage for any other message type. If parsing fails nullptr + * will be returned + */ + static SSHHandshakeMessage* tryParse(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + // implement abstract methods + + /** + * @return The size of the SSH handshake message including the padding and message header + */ + size_t getHeaderLen() const; + + std::string toString() const; + + protected: +#pragma pack(push, 1) + /** + * An internal struct representing the SSH handshake message header + */ + struct ssh_message_base + { + uint32_t packetLength; + uint8_t paddingLength; + uint8_t messageCode; + }; +#pragma pack(pop) + + // this layer supports only parsing + SSHHandshakeMessage(); + + // private c'tor, this class cannot be instantiated + SSHHandshakeMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : SSHLayer(data, dataLen, prevLayer, packet) + {} + + ssh_message_base* getMsgBaseHeader() const + { + return (ssh_message_base*)m_Data; + } + }; + + /** + * @class SSHKeyExchangeInitMessage + * A class representing the SSH Key Exchange Init message. This is a non-encrypted message that contains information + * about the algorithms used for key exchange, encryption, MAC and compression. This class provides methods to + * access these details + */ + class SSHKeyExchangeInitMessage : public SSHHandshakeMessage + { + public: + /** + * A c'tor for this class that accepts raw message data. Please avoid using it as it's used internally + * when parsing SSH handshake messages in SSHHandshakeMessage#tryParse() + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + SSHKeyExchangeInitMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + /** + * Each SSH Key Exchange Init message contains a random 16-byte value generated by the sender. + * This method returns a pointer to this 16-byte cookie. To get the value as a hex string + * please refer to getCookieAsHexStream() + * @return A pointer to the 16-byte cookie value or nullptr if the message is malformed + */ + uint8_t* getCookie(); + + /** + * Each SSH Key Exchange Init message contains a random 16-byte value generated by the sender. + * This method returns the 16-byte cookie as a hex stream. To get the raw data please refer to + * getCookie() + * @return A hex stream of the 16-byte cookie value or an empty string if the message is malformed + */ + std::string getCookieAsHexStream(); + + /** + * @return A comma-separated list of the key exchange algorithms used in this session. + * Can be empty if the value is missing or the message is malformed + */ + std::string getKeyExchangeAlgorithms() + { + return getFieldValue(0); + } + + /** + * @return A comma-separated list of the algorithms supported for the server host key. + * Can be empty if the value is missing or the message is malformed + */ + std::string getServerHostKeyAlgorithms() + { + return getFieldValue(1); + } + + /** + * @return A comma-separated list of acceptable symmetric encryption algorithms (also known as ciphers) + * from the client to the server. Can be empty if the value is missing or the message is malformed + */ + std::string getEncryptionAlgorithmsClientToServer() + { + return getFieldValue(2); + } + + /** + * @return A comma-separated list of acceptable symmetric encryption algorithms (also known as ciphers) + * from the server to the client. Can be empty if the value is missing or the message is malformed + */ + std::string getEncryptionAlgorithmsServerToClient() + { + return getFieldValue(3); + } + + /** + * @return A comma-separated list of acceptable MAC algorithms from the client to the server. + * Can be empty if the value is missing or the message is malformed + */ + std::string getMacAlgorithmsClientToServer() + { + return getFieldValue(4); + } + + /** + * @return A comma-separated list of acceptable MAC algorithms from the server to the client. + * Can be empty if the value is missing or the message is malformed + */ + std::string getMacAlgorithmsServerToClient() + { + return getFieldValue(5); + } + + /** + * @return A comma-separated list of acceptable compression algorithms from the client to the server. + * Can be empty if the value is missing or the message is malformed + */ + std::string getCompressionAlgorithmsClientToServer() + { + return getFieldValue(6); + } + + /** + * @return A comma-separated list of acceptable compression algorithms from the server to the client. + * Can be empty if the value is missing or the message is malformed + */ + std::string getCompressionAlgorithmsServerToClient() + { + return getFieldValue(7); + } + + /** + * @return A comma-separated list of language tags from the client to the server. + * Can be empty if the value is missing or the message is malformed + */ + std::string getLanguagesClientToServer() + { + return getFieldValue(8); + } + + /** + * @return A comma-separated list of language tags from the server to the client. + * Can be empty if the value is missing or the message is malformed + */ + std::string getLanguagesServerToClient() + { + return getFieldValue(9); + } + + /** + * @return Indicates whether a guessed key exchange packet follows. If a + * guessed packet will be sent, the return value is true. If no guessed + * packet will be sent or if this value is missing, the return value is false. + */ + bool isFirstKexPacketFollows(); + + private: + size_t m_FieldOffsets[11]; + bool m_OffsetsInitialized; + + void parseMessageAndInitOffsets(); + + std::string getFieldValue(int fieldOffsetIndex); + }; + + /** + * @class SSHEncryptedMessage + * A class representing an SSH encrypted message. In such messages there is very little information to extract from + * the packet, hence this class doesn't expose any methods or getters, other than the ones inherited from parent + * classes. + * + * It is assumed that any SSH message which does not fit to any of the other SSH message types, according to the + * heuristics described in the SSHLayer.h file description, is considered as an encrypted message. + */ + class SSHEncryptedMessage : public SSHLayer + { + public: + /** + * A c'tor for this class that accepts raw message data. Please avoid using it as it's used internally + * when parsing SSH messages in SSHLayer#createSSHMessage() + */ + SSHEncryptedMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : SSHLayer(data, dataLen, prevLayer, packet) + {} + + // implement abstract methods + + /** + * @return The size of the message which is equal to the size of the layer + */ + size_t getHeaderLen() const + { + return m_DataLen; + } + + std::string toString() const; + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/SSLCommon.h b/Packet++/header/pcapplusplus/SSLCommon.h new file mode 100644 index 0000000000..5f499f9ec9 --- /dev/null +++ b/Packet++/header/pcapplusplus/SSLCommon.h @@ -0,0 +1,609 @@ +#pragma once + +#include +#include + +/** + * @file + * See detailed explanation of the TLS/SSL protocol support in PcapPlusPlus in SSLLayer.h + */ + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * @struct ssl_tls_record_layer + * The common part of all SSL/TLS messages + */ +#pragma pack(push, 1) + struct ssl_tls_record_layer + { + /** Message (record) type (one of ::SSLRecordType) */ + uint8_t recordType; + /** Message (record) version (one of SSLVersion::SSLVersionEnum) */ + uint16_t recordVersion; + /** Message (record) length in bytes */ + uint16_t length; + }; +#pragma pack(pop) + + /** + * @struct ssl_tls_handshake_layer + * The common part of all SSL/TLS handshake message types + */ +#pragma pack(push, 1) + struct ssl_tls_handshake_layer + { + /** Type of the handshake message (one of ::SSLHandshakeType) */ + uint8_t handshakeType; + /** Length of the message. Length is 3-Byte long, This is the MSB byte */ + uint8_t length1; + /** Length of the message. Length is 3-Byte long, This is the 2 LSB bytes */ + uint16_t length2; + }; +#pragma pack(pop) + + /** + * @struct ssl_tls_client_server_hello + * The common header part of client-hello and server-hello handshake messages + */ +#pragma pack(push, 1) + struct ssl_tls_client_server_hello : ssl_tls_handshake_layer + { + /** SSL/TLS handshake version (one of SSLVersion::SSLVersionEnum) */ + uint16_t handshakeVersion; + /** 32-bytes random number */ + uint8_t random[32]; + }; +#pragma pack(pop) + + /** + * @struct ssl_tls_change_cipher_spec + * SSL/TLS change-cipher-spec message structure + */ +#pragma pack(push, 1) + struct ssl_tls_change_cipher_spec + { + /** Unused byte */ + uint8_t changeCipherSpec; + }; +#pragma pack(pop) + + /** + * @struct ssl_tls_alert + * SSL/TLS alert message structure + */ +#pragma pack(push, 1) + struct ssl_tls_alert + { + /** Alert level (one of ::SSLAlertLevel) */ + uint8_t alertLevel; + /** Alert description (one of ::SSLAlertDescription) */ + uint8_t alertDescription; + }; +#pragma pack(pop) + + /** + * SSL/TLS message types + */ + enum SSLRecordType + { + /** Change-cipher-spec message */ + SSL_CHANGE_CIPHER_SPEC = 20, + /** SSL alert message */ + SSL_ALERT = 21, + /** SSL handshake message */ + SSL_HANDSHAKE = 22, + /** SSL data message */ + SSL_APPLICATION_DATA = 23 + }; + + /** + * @class SSLVersion + * A wrapper class for SSL/TLS versions. The SSL/TLS version is typically represented by a 2-byte number, + * for example TLS 1.2 is represented by 0x0303. + * This class wraps the numeric value and provides methods to convert it into an enum, string, etc. + */ + class SSLVersion + { + public: + /** + * SSL/TLS versions enum + */ + enum SSLVersionEnum + { + /** SSL 2.0 */ + SSL2 = 0x0200, + /** SSL 3.0 */ + SSL3 = 0x0300, + /** TLS 1.0 */ + TLS1_0 = 0x0301, + /** TLS 1.1 */ + TLS1_1 = 0x0302, + /** TLS 1.2 */ + TLS1_2 = 0x0303, + /** TLS 1.3 */ + TLS1_3 = 0x0304, + /** TLS 1.3 (draft 14) */ + TLS1_3_D14 = 0x7f0e, + /** TLS 1.3 (draft 15) */ + TLS1_3_D15 = 0x7f0f, + /** TLS 1.3 (draft 16) */ + TLS1_3_D16 = 0x7f10, + /** TLS 1.3 (draft 17) */ + TLS1_3_D17 = 0x7f11, + /** TLS 1.3 (draft 18) */ + TLS1_3_D18 = 0x7f12, + /** TLS 1.3 (draft 19) */ + TLS1_3_D19 = 0x7f13, + /** TLS 1.3 (draft 20) */ + TLS1_3_D20 = 0x7f14, + /** TLS 1.3 (draft 21) */ + TLS1_3_D21 = 0x7f15, + /** TLS 1.3 (draft 22) */ + TLS1_3_D22 = 0x7f16, + /** TLS 1.3 (draft 23) */ + TLS1_3_D23 = 0x7f17, + /** TLS 1.3 (draft 24) */ + TLS1_3_D24 = 0x7f18, + /** TLS 1.3 (draft 25) */ + TLS1_3_D25 = 0x7f19, + /** TLS 1.3 (draft 26) */ + TLS1_3_D26 = 0x7f1a, + /** TLS 1.3 (draft 27) */ + TLS1_3_D27 = 0x7f1b, + /** TLS 1.3 (draft 28) */ + TLS1_3_D28 = 0x7f1c, + /** TLS 1.3 (Facebook draft 23) */ + TLS1_3_FBD23 = 0xfb17, + /** TLS 1.3 (Facebook draft 26) */ + TLS1_3_FBD26 = 0xfb1a, + /** Unknown value */ + Unknown = 0 + }; + + /** + * A c'tor for this class. + * @param[in] sslVersionValue The numeric value representing this SSL/TLS version. For example: + * for TLS 1.2 this would be 0x0303. + */ + explicit SSLVersion(uint16_t sslVersionValue) + { + m_SSLVersionValue = sslVersionValue; + } + + /** + * @return An enum value of type SSLVersion::SSLVersionEnum representing the SSL/TLS version. + * If the numeric value is an invalid SSL/TLS version SSLVersion::Unknown will be returned. + * @param[in] countTlsDraftsAs1_3 A flag indicating whether to return the enum value SSLVersion::TLS1_3 for all + * TLS 1.3 drafts. If set to "true" all TLS 1.3 draft values (i.e 0x7f0e - 0x7f1c, 0xfb17, 0xfb1a) will return + * SSLVersion::TLS1_3, otherwise the corresponding enum values will be returned. The default value is "false". + */ + SSLVersionEnum asEnum(bool countTlsDraftsAs1_3 = false); + + /** + * @return The numeric value of the SSL/TLs version + */ + uint16_t asUInt() + { + return m_SSLVersionValue; + } + + /** + * @return A string representation of the SSL/TLS version. For example: for TLS 1.2 the string "TLS 1.2" is + * returned. If the numeric value is an invalid SSL/TLS version the string "Unknown" will be returned. + * @param[in] countTlsDraftsAs1_3 A flag indicating whether to return the string value "TLS 1.3" for all TLS 1.3 + * drafts. If set to "true" all TLS 1.3 draft values (i.e 0x7f0e - 0x7f1c, 0xfb17, 0xfb1a) will return + * "TLS 1.3", otherwise the corresponding string values will be returned. The default value is "false". + */ + std::string toString(bool countTlsDraftsAs1_3 = false); + + private: + uint16_t m_SSLVersionValue; + + // unimplemented empty c'tor + SSLVersion(); + }; + + /** + * SSL/TLS handshake message types + */ + enum SSLHandshakeType + { + /** Hello-request message type */ + SSL_HELLO_REQUEST = 0, + /** Client-hello message type */ + SSL_CLIENT_HELLO = 1, + /** Server-hello message type */ + SSL_SERVER_HELLO = 2, + /** New-session-ticket message type */ + SSL_NEW_SESSION_TICKET = 4, + /** End-of-early-data message type (TLS 1.3) */ + SSL_END_OF_EARLY_DATE = 5, + /** Encrypted-extensions message type (TLS 1.3) */ + SSL_ENCRYPTED_EXTENSIONS = 8, + /** Certificate message type */ + SSL_CERTIFICATE = 11, + /** Server-key-exchange message type */ + SSL_SERVER_KEY_EXCHANGE = 12, + /** Certificate-request message type */ + SSL_CERTIFICATE_REQUEST = 13, + /** Server-hello-done message type */ + SSL_SERVER_DONE = 14, + /** Certificate-verify message type */ + SSL_CERTIFICATE_VERIFY = 15, + /** Client-key-exchange message type */ + SSL_CLIENT_KEY_EXCHANGE = 16, + /** Finish message type */ + SSL_FINISHED = 20, + /** Key-update message type (TLS 1.3) */ + SSL_KEY_UPDATE = 24, + /** Unknown SSL handshake message */ + SSL_HANDSHAKE_UNKNOWN = 255 + }; + + /** + * SSL/TLS alert levels + */ + enum SSLAlertLevel + { + /** Warning level alert */ + SSL_ALERT_LEVEL_WARNING = 1, + /** Fatal level alert */ + SSL_ALERT_LEVEL_FATAL = 2, + /** For encrypted alerts the level is unknown so this type will be returned */ + SSL_ALERT_LEVEL_ENCRYPTED = 255 + }; + + /** + * SSL/TLS alert description types + */ + enum SSLAlertDescription + { + /** Close notify alert */ + SSL_ALERT_CLOSE_NOTIFY = 0, + /** Unexpected message alert */ + SSL_ALERT_UNEXPECTED_MESSAGE = 10, + /** Bad record MAC alert */ + SSL_ALERT_BAD_RECORD_MAC = 20, + /** Decryption failed alert */ + SSL_ALERT_DECRYPTION_FAILED = 21, + /** */ + SSL_ALERT_RECORD_OVERFLOW = 22, + /** Decompression failure alert */ + SSL_ALERT_DECOMPRESSION_FAILURE = 30, + /** Handshake failure alert */ + SSL_ALERT_HANDSHAKE_FAILURE = 40, + /** No certificate alert */ + SSL_ALERT_NO_CERTIFICATE = 41, + /** Bad certificate alert */ + SSL_ALERT_BAD_CERTIFICATE = 42, + /** Unsupported certificate */ + SSL_ALERT_UNSUPPORTED_CERTIFICATE = 43, + /** Certificate revoked alert */ + SSL_ALERT_CERTIFICATE_REVOKED = 44, + /** Certificate expired alert */ + SSL_ALERT_CERTIFICATE_EXPIRED = 45, + /** Certificate unknown alert */ + SSL_ALERT_CERTIFICATE_UNKNOWN = 46, + /** Illegal parameter alert */ + SSL_ALERT_ILLEGAL_PARAMETER = 47, + /** Unknown CA alert */ + SSL_ALERT_UNKNOWN_CA = 48, + /** Access denied alert */ + SSL_ALERT_ACCESS_DENIED = 49, + /** Decode error alert */ + SSL_ALERT_DECODE_ERROR = 50, + /** Decrypt error alert */ + SSL_ALERT_DECRYPT_ERROR = 51, + /** Export restriction alert */ + SSL_ALERT_EXPORT_RESTRICTION = 60, + /** Protocol version alert */ + SSL_ALERT_PROTOCOL_VERSION = 70, + /** Insufficient security alert */ + SSL_ALERT_INSUFFICIENT_SECURITY = 71, + /** Internal error alert */ + SSL_ALERT_INTERNAL_ERROR = 80, + /** User cancelled alert */ + SSL_ALERT_USER_CANCELLED = 90, + /** No negotiation alert */ + SSL_ALERT_NO_RENEGOTIATION = 100, + /** Unsupported extension alert */ + SSL_ALERT_UNSUPPORTED_EXTENSION = 110, + /** Encrtpyed alert (cannot determine its type) */ + SSL_ALERT_ENCRYPTED = 255 + }; + + /** + * SSL/TLS key exchange algorithms + */ + enum SSLKeyExchangeAlgorithm + { + /** Null value */ + SSL_KEYX_NULL, + /** RSA (Rivest-Shamir-Adleman) */ + SSL_KEYX_RSA, + /** Diffie-Hellman */ + SSL_KEYX_DH, + /** Diffie-Hellman ephemeral */ + SSL_KEYX_DHE, + /** Elliptic curve Diffie�Hellman */ + SSL_KEYX_ECDH, + /** Elliptic curve Diffie�Hellman ephemeral */ + SSL_KEYX_ECDHE, + /** Fortezza Crypto Card */ + SSL_KEYX_FORTEZZA, + /** Kerberos 5 */ + SSL_KEYX_KRB5, + /** Pre-Shared Key */ + SSL_KEYX_PSK, + /** GOST */ + SSL_KEYX_GOST, + /** Secure Remote Password */ + SSL_KEYX_SRP, + /** PCT */ + SSL_KEYX_PCT, + /** Unknown algorithm */ + SSL_KEYX_Unknown + }; + + /** + * SSL/TLS authentication algorithms + */ + enum SSLAuthenticationAlgorithm + { + /** Null value */ + SSL_AUTH_NULL, + /** RSA (Rivest-Shamir-Adleman) */ + SSL_AUTH_RSA, + /** Digital Signature Standard */ + SSL_AUTH_DSS, + /** Anonymous */ + SSL_AUTH_anon, + /** Diffie-Hellman based key-exchange protocol */ + SSL_AUTH_KEA, + /** Kerberos 5 */ + SSL_AUTH_KRB5, + /** Pre-Shared Key */ + SSL_AUTH_PSK, + /** Elliptic Curve Digital Signature Algorithm */ + SSL_AUTH_ECDSA, + /** GOST */ + SSL_AUTH_GOST, + /** SHA-1 (Secure Hash Algorithm) */ + SSL_AUTH_SHA, + /** PCT */ + SSL_AUTH_PCT, + /** Diffie-Hellman ephemeral */ + SSL_AUTH_DHE, + /** Unknown algorithm */ + SSL_AUTH_Unknown + }; + + /** + * SSL/TLS symmetric encryption algorithms + */ + enum SSLSymetricEncryptionAlgorithm + { + /** Null value */ + SSL_SYM_NULL, + /** RC4_40 */ + SSL_SYM_RC4_40, + /** RC4_128 */ + SSL_SYM_RC4_128, + /** RC2_CBC_40 */ + SSL_SYM_RC2_CBC_40, + /** IDEA_CBC */ + SSL_SYM_IDEA_CBC, + /** DES40_CBC */ + SSL_SYM_DES40_CBC, + /** DES_CBC */ + SSL_SYM_DES_CBC, + /** 3DES_EDE_CBC */ + SSL_SYM_3DES_EDE_CBC, + /** FORTEZZA_CBC */ + SSL_SYM_FORTEZZA_CBC, + /** DES_CBC_40 */ + SSL_SYM_DES_CBC_40, + /** AES_128_CBC */ + SSL_SYM_AES_128_CBC, + /** AES_256_CBC */ + SSL_SYM_AES_256_CBC, + /** CAMELLIA_128_CBC */ + SSL_SYM_CAMELLIA_128_CBC, + /** CAMELLIA_128_GCM */ + SSL_SYM_CAMELLIA_128_GCM, + /** CAMELLIA_256_GCM */ + SSL_SYM_CAMELLIA_256_GCM, + /** RC4_56 */ + SSL_SYM_RC4_56, + /** RC2_CBC_56 */ + SSL_SYM_RC2_CBC_56, + /** GOST28147 */ + SSL_SYM_GOST28147, + /** CAMELLIA_256_CBC */ + SSL_SYM_CAMELLIA_256_CBC, + /** SEED_CBC */ + SSL_SYM_SEED_CBC, + /** AES_128 */ + SSL_SYM_AES_128, + /** AES_256 */ + SSL_SYM_AES_256, + /** SSL_SYM_AES_128_GCM */ + SSL_SYM_AES_128_GCM, + /** AES_256_GCM */ + SSL_SYM_AES_256_GCM, + /** RC4_128_EXPORT40 */ + SSL_SYM_RC4_128_EXPORT40, + /** RC2_CBC_128_CBC */ + SSL_SYM_RC2_CBC_128_CBC, + /** IDEA_128_CBC */ + SSL_SYM_IDEA_128_CBC, + /** DES_64_CBC */ + SSL_SYM_DES_64_CBC, + /** DES_192_EDE3_CBC */ + SSL_SYM_DES_192_EDE3_CBC, + /** RC4_64 */ + SSL_SYM_RC4_64, + /** ARIA_128_CBC*/ + SSL_SYM_ARIA_128_CBC, + /** ARIA_256_CBC */ + SSL_SYM_ARIA_256_CBC, + /** ARIA_128_GCM */ + SSL_SYM_ARIA_128_GCM, + /** ARIA_256_GCM */ + SSL_SYM_ARIA_256_GCM, + /** CHACHA20_POLY1305 */ + SSL_SYM_CHACHA20_POLY1305, + /** AES_128_CCM */ + SSL_SYM_AES_128_CCM, + /** AES_128_CCM_8 */ + SSL_SYM_AES_128_CCM_8, + /** Unknown algorithm */ + SSL_SYM_Unknown + }; + + /** + * SSL/TLS hashing algorithms + */ + enum SSLHashingAlgorithm + { + /** Null value */ + SSL_HASH_NULL, + /** Message-Digest Algorithm */ + SSL_HASH_MD5, + /** SHA-1 (Secure Hash Algorithm) */ + SSL_HASH_SHA, + /** SHA-256 (Secure Hash Algorithm) */ + SSL_HASH_SHA256, + /** GOST 28147 */ + SSL_HASH_GOST28147, + /** GOST R 34.11 */ + SSL_HASH_GOSTR3411, + /** SHA-384 (Secure Hash Algorithm) */ + SSL_HASH_SHA384, + /** CCM mode (Counter with CBC-MAC) */ + SSL_HASH_CCM, + /** CCM mode (Counter with CBC-MAC) */ + SSL_HASH_CCM_8, + /** Unknown algorithm */ + SSL_HASH_Unknown + }; + + /** + * SSL/TLS extension types + */ + enum SSLExtensionType + { + /** Server Name Indication extension */ + SSL_EXT_SERVER_NAME = 0, + /** Maximum Fragment Length Negotiation extension */ + SSL_EXT_MAX_FRAGMENT_LENGTH = 1, + /** Client Certificate URLs extension */ + SSL_EXT_CLIENT_CERTIFICATE_URL = 2, + /** Trusted CA Indication extension */ + SSL_EXT_TRUSTED_CA_KEYS = 3, + /** Truncated HMAC extension */ + SSL_EXT_TRUNCATED_HMAC = 4, + /** Certificate Status Request extension */ + SSL_EXT_STATUS_REQUEST = 5, + /** TLS User Mapping extension */ + SSL_EXT_USER_MAPPING = 6, + /** Client Authorization extension */ + SSL_EXT_CLIENT_AUTHZ = 7, + /** Server Authorization extension */ + SSL_EXT_SERVER_AUTHZ = 8, + /** Certificate Type extension */ + SSL_EXT_CERT_TYPE = 9, + /** Supported Groups extension (renamed from "elliptic curves") */ + SSL_EXT_SUPPORTED_GROUPS = 10, + /** Elliptic Curves Point Format extension */ + SSL_EXT_EC_POINT_FORMATS = 11, + /** Secure Remote Password extension */ + SSL_EXT_SRP = 12, + /** Signature Algorithms extension */ + SSL_EXT_SIGNATURE_ALGORITHMS = 13, + /** Use Secure Real-time Transport Protocol extension */ + SSL_EXT_USE_SRTP = 14, + /** TLS Heartbit extension */ + SSL_EXT_HEARTBEAT = 15, + /** Application Layer Protocol Negotiation (ALPN) extension */ + SSL_EXT_APPLICATION_LAYER_PROTOCOL_NEGOTIATION = 16, + /** Status Request extension */ + SSL_EXT_STATUS_REQUEST_V2 = 17, + /** Signed Certificate Timestamp extension */ + SSL_EXT_SIGNED_CERTIFICATE_TIMESTAMP = 18, + /** Client Certificate Type extension */ + SSL_EXT_CLIENT_CERTIFICATE_TYPE = 19, + /** Server Certificate Type extension */ + SSL_EXT_SERVER_CERTIFICATE_TYPE = 20, + /** ClientHello Padding extension */ + SSL_EXT_PADDING = 21, + /** Encrypt-then-MAC extension */ + SSL_EXT_ENCRYPT_THEN_MAC = 22, + /** Extended Master Secret extension */ + SSL_EXT_EXTENDED_MASTER_SECRET = 23, + /** Token Binding extension */ + SSL_EXT_TOKEN_BINDING = 24, + /** SessionTicket TLS extension */ + SSL_EXT_SESSIONTICKET_TLS = 35, + /** Pre-shared key (PSK) extension (TLS 1.3) */ + SSL_EXT_PRE_SHARED_KEY = 41, + /** Early data extension (TLS 1.3) */ + SSL_EXT_EARLY_DATA = 42, + /** Supported versions extension (TLS 1.3) */ + SSL_EXT_SUPPORTED_VERSIONS = 43, + /** Cookie extension (TLS 1.3) */ + SSL_EXT_COOKIE = 44, + /** Pre-Shared Key Exchange Modes extension (TLS 1.3) */ + SSL_EXT_PSK_KEY_EXCHANGE_MODES = 45, + /** Certificate authorities extension (TLS 1.3) */ + SSL_EXT_CERTIFICATE_AUTHORITIES = 47, + /** Old filters extension (TLS 1.3) */ + SSL_EXT_OLD_FILTERS = 48, + /** Post handshake auth extension (TLS 1.3) */ + SSL_EXT_POST_HANDSHAKE_AUTH = 49, + /** Signature algorithm cert extension (TLS 1.3) */ + SSL_EXT_SIGNATURE_ALGORITHM_CERT = 50, + /** Key share extension (TLS 1.3) */ + SSL_EXT_KEY_SHARE = 51, + /** Renegotiation Indication extension */ + SSL_EXT_RENEGOTIATION_INFO = 65281, + /** Unknown extension */ + SSL_EXT_Unknown + }; + + /** + * SSL/TLS client certificate types + */ + enum SSLClientCertificateType + { + /** RSA_SIGN */ + SSL_CCT_RSA_SIGN = 1, + /** DSS_SIGN */ + SSL_CCT_DSS_SIGN = 2, + /** RSA_FIXED_DH */ + SSL_CCT_RSA_FIXED_DH = 3, + /** DSS_FIXED_DH */ + SSL_CCT_DSS_FIXED_DH = 4, + /** RSA_EPHEMERAL_DH_RESERVED */ + SSL_CCT_RSA_EPHEMERAL_DH_RESERVED = 5, + /** DSS_EPHEMERAL_DH_RESERVED */ + SSL_CCT_DSS_EPHEMERAL_DH_RESERVED = 6, + /** FORTEZZA_DMS_RESERVED */ + SSL_CCT_FORTEZZA_DMS_RESERVED = 20, + /** ECDSA_SIGN */ + SSL_CCT_ECDSA_SIGN = 64, + /** FIXED_ECDH */ + SSL_CCT_RSA_FIXED_ECDH = 65, + /** ECDSA_FIXED_ECDH */ + SSL_CCT_ECDSA_FIXED_ECDH = 66, + /** Unknown client certificate type */ + SSL_CCT_UNKNOWN + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/SSLHandshake.h b/Packet++/header/pcapplusplus/SSLHandshake.h new file mode 100644 index 0000000000..e15c83623f --- /dev/null +++ b/Packet++/header/pcapplusplus/SSLHandshake.h @@ -0,0 +1,1186 @@ +#pragma once + +#include +#include "pcapplusplus/SSLCommon.h" +#include "pcapplusplus/PointerVector.h" +#include "pcapplusplus/Asn1Codec.h" + +/** + * @file + * See detailed explanation of the TLS/SSL protocol support in PcapPlusPlus in SSLLayer.h + */ + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * @class SSLCipherSuite + * Represents a cipher-suite and enables access all information about it such as all algorithms it encapsulates, + * its ID (as appears in the client-hello or server-hello messages), + * its name (e.g "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA") etc. PcapPlusPlus contains static instances of this type + * for all known cipher-suites and enables access to them through name or ID (see getCipherSuiteByID() and + * getCipherSuiteByName() ). List of cipher-suite was taken from here: + * http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml + */ + class SSLCipherSuite + { + public: + /** + * A c'tor for this class, should never be used by a user + * @param[in] id Cipher-suite ID + * @param[in] keyExAlg Key-exchange algorithm used in this cipher-suite + * @param[in] authAlg Authentication algorithm used in this cipher-suite + * @param[in] symKeyAlg Symmetric key algorithm used in this cipher-suite + * @param[in] MACAlg MAC algorithm used in this cipher-suite + * @param[in] name String representation of this cipher-suite + */ + SSLCipherSuite(uint16_t id, SSLKeyExchangeAlgorithm keyExAlg, SSLAuthenticationAlgorithm authAlg, + SSLSymetricEncryptionAlgorithm symKeyAlg, SSLHashingAlgorithm MACAlg, const char* name) + : m_Id(id), m_KeyExAlg(keyExAlg), m_AuthAlg(authAlg), m_SymKeyAlg(symKeyAlg), m_MACAlg(MACAlg), m_Name(name) + {} + + /** + * @return Cipher-suite ID + */ + uint16_t getID() const + { + return m_Id; + } + + /** + * @return String representation of this cipher-suite + */ + std::string asString() const + { + return m_Name; + } + + /** + * @return Key-exchange algorithm used in this cipher-suite + */ + SSLKeyExchangeAlgorithm getKeyExchangeAlg() const + { + return m_KeyExAlg; + } + + /** + * @return Authentication algorithm used in this cipher-suite + */ + SSLAuthenticationAlgorithm getAuthAlg() const + { + return m_AuthAlg; + } + + /** + * @return Symmetric key algorithm used in this cipher-suite + */ + SSLSymetricEncryptionAlgorithm getSymKeyAlg() const + { + return m_SymKeyAlg; + } + + /** + * @return MAC algorithm used in this cipher-suite + */ + SSLHashingAlgorithm getMACAlg() const + { + return m_MACAlg; + } + + /** + * A static method that returns a cipher-suite instance by ID + * @param[in] id Cipher-suite ID + * @return A cipher-suite instance matching this ID or nullptr if ID not found + */ + static SSLCipherSuite* getCipherSuiteByID(uint16_t id); + + /** + * A static method that returns a cipher-suite instance by name + * @param[in] name Cipher-suite name (e.g "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA") + * @return A cipher-suite instance matching this name or nullptr if name not found + */ + static SSLCipherSuite* getCipherSuiteByName(std::string name); + + private: + uint16_t m_Id; + SSLKeyExchangeAlgorithm m_KeyExAlg; + SSLAuthenticationAlgorithm m_AuthAlg; + SSLSymetricEncryptionAlgorithm m_SymKeyAlg; + SSLHashingAlgorithm m_MACAlg; + std::string m_Name; + }; + + /** + * @class SSLExtension + * Represents a SSL/TLS extension. This is a base class that can represent any type of extension. Inherited classes + * may contain parsing logic for specific extensions. This class provides capabilities such as getting the extension + * type, length and viewing the extension data as raw (byte array) + */ + class SSLExtension + { + public: + /** + * C'tor for this class + * @param[in] data The raw data for the extension + */ + explicit SSLExtension(uint8_t* data); + + virtual ~SSLExtension() + {} + + /** + * @return The type of the extension as enum + */ + SSLExtensionType getType() const; + + /** + * @return The type of the extension as a numeric value + */ + uint16_t getTypeAsInt() const; + + /** + * @return The length of the extension data in bytes (not including the type and length fields) + */ + uint16_t getLength() const; + + /** + * @return The total length of the extension, including type and length fields and the extension data field + */ + uint16_t getTotalLength() const; + + /** + * @return A pointer to the raw data of the extension + */ + uint8_t* getData() const; + + protected: + /** + * @struct SSLExtensionStruct + * Represents the common fields of the extension + */ + struct SSLExtensionStruct + { + /** Extension type */ + uint16_t extensionType; + /** Extension length */ + uint16_t extensionDataLength; + /** Extension data as raw (byte array) */ + uint8_t extensionData[]; + }; + + uint8_t* m_RawData; + + SSLExtensionStruct* getExtensionStruct() const + { + return (SSLExtensionStruct*)m_RawData; + } + }; + + /** + * @class SSLServerNameIndicationExtension + * Represents SSL/TLS Server Name Indication extension. Inherits from SSLExtension and add parsing of the hostname + * written in the extension data + */ + class SSLServerNameIndicationExtension : public SSLExtension + { + public: + /** + * C'tor for this class + * @param[in] data The raw data for the extension + */ + explicit SSLServerNameIndicationExtension(uint8_t* data) : SSLExtension(data) + {} + + /** + * @return The hostname written in the extension data + */ + std::string getHostName() const; + }; + + /** + * @class SSLSupportedVersionsExtension + * Represents TLS Supported Versions extension. Inherits from SSLExtension and adds parsing of the list + * of supported versions mentioned in the extension data + */ + class SSLSupportedVersionsExtension : public SSLExtension + { + public: + /** + * C'tor for this class + * @param[in] data The raw data for the extension + */ + explicit SSLSupportedVersionsExtension(uint8_t* data) : SSLExtension(data) + {} + + /** + * @return The list of supported versions mentioned in the extension data + */ + std::vector getSupportedVersions() const; + }; + + /** + * @class TLSSupportedGroupsExtension + * Represents TLS Supported Groups extension. Inherits from SSLExtension and adds parsing of the + * supported groups (Elliptic Curves) mentioned in the extension data + */ + class TLSSupportedGroupsExtension : public SSLExtension + { + public: + /** + * C'tor for this class + * @param[in] data The raw data for the extension + */ + explicit TLSSupportedGroupsExtension(uint8_t* data) : SSLExtension(data) + {} + + /** + * @return A vector of the supported groups (also known as "Elliptic Curves") + */ + std::vector getSupportedGroups() const; + }; + + /** + * @class TLSECPointFormatExtension + * Represents TLS EC (Elliptic Curves) Point Format extension. Inherits from SSLExtension and adds parsing of the + * EC point formats mentioned in the extension data + */ + class TLSECPointFormatExtension : public SSLExtension + { + public: + /** + * C'tor for this class + * @param[in] data The raw data for the extension + */ + explicit TLSECPointFormatExtension(uint8_t* data) : SSLExtension(data) + {} + + /** + * @return A vector of the elliptic curves point formats + */ + std::vector getECPointFormatList() const; + }; + + /** + * @class SSLx509Certificate + * Represents a x509v3 certificate. the SSLCertificateMessage class returns an instance of this class as the + * certificate. Currently this class doesn't do much as it doesn't parse the certificate. It only acts as container + * to the raw data and returns general info as data as raw, length, etc. In the future I may add full parsing of the + * certificate + */ + class SSLx509Certificate + { + public: + /** + * C'tor for this class + * @param[in] data The raw data of the certificate + * @param[in] dataLen The length in bytes of the raw data + * @param[in] allDataExists Certificate messages usually spread on more than 1 packet. So a certificate is + * likely to split between 2 packets or more. This field indicates whether the raw data contains all + * certificate data of just a part of it + */ + SSLx509Certificate(uint8_t* data, size_t dataLen, bool allDataExists) + : m_Data(data), m_DataLen(dataLen), m_AllDataExists(allDataExists) + {} + + /** + * @return A pointer to the raw data + */ + uint8_t* getData() const + { + return m_Data; + } + + /** + * @return Raw data length + */ + size_t getDataLength() const + { + return m_DataLen; + } + + /** + * @return The root ASN.1 record of the certificate data. All of the certificate data will be under this record. + * If the Root ASN.1 record is malformed, an exception is thrown + */ + Asn1SequenceRecord* getRootAsn1Record(); + + /** + * Certificate messages usually spread on more than 1 packet. So a certificate is likely to split between 2 + * packets or more. This method provides an indication whether all certificate data exists or only part of it + * @return True if this data contains all certificate data, false otherwise + */ + bool allDataExists() const + { + return m_AllDataExists; + } + + private: + std::unique_ptr m_Asn1Record; + uint8_t* m_Data; + size_t m_DataLen; + bool m_AllDataExists; + }; + + class SSLHandshakeLayer; + + /** + * @class SSLHandshakeMessage + * A base class for SSL/TLS handshake messages. This is an abstract class and cannot be instantiated. SSL/TLS + * handshake messages are contained in SSLHandshakeLayer, meaning a SSLHandshakeLayer instance can contain one or + * more SSLHandshakeMessage instances. For example: one SSLHandshakeLayer may contain a server-hello, certificate, + * server-key-exchange, and server-hello-done messages (although it's not such a common case, most handshake layers + * contain 1 handshake message only) + */ + class SSLHandshakeMessage + { + public: + virtual ~SSLHandshakeMessage() + {} + + /** + * A factory method for creating instances of handshake messages from raw data + * @param[in] data The raw data containing 1 handshake message + * @param[in] dataLen Raw data length in bytes + * @param[in] container A pointer to the SSLHandshakeLayer instance which will contain the created message. + * This parameter is required because the handshake message includes a pointer to its container + */ + static SSLHandshakeMessage* createHandshakeMessage(uint8_t* data, size_t dataLen, SSLHandshakeLayer* container); + + /** + * @return The handshake message type + */ + virtual SSLHandshakeType getHandshakeType() const; + + /** + * @return The handshake message length in bytes. Notice that sometimes the handshake message is divided between + * several packets, in this case this method will return the length of part of the message in the current packet + */ + virtual size_t getMessageLength() const; + + /** + * @return True if current packet contains the entire message or false otherwise. This method is important + * because sometimes handshake messages are divided in consequent packets (happens a lot in certificate messages + * which usually contain several KB of data which is larger than standard packet size, so the message is divided + * between several packets) + */ + virtual bool isMessageComplete() const; + + /** + * @return A pointer to the SSLHandshakeLayer instance containing this message + */ + SSLHandshakeLayer* getContainingLayer() const + { + return m_Container; + } + + /** + * @return A string representation of the message type (e.g "Client Hello message") + */ + virtual std::string toString() const = 0; + + protected: + SSLHandshakeMessage(uint8_t* data, size_t dataLen, SSLHandshakeLayer* container); + + uint8_t* m_Data; + size_t m_DataLen; + SSLHandshakeLayer* m_Container; + }; + + /** + * @class SSLClientHelloMessage + * Represents a client-hello message (type 1). Inherits from SSLHandshakeMessage and adds parsing of all fields + * of this message including the message extensions, cipher-suite list, etc. + */ + class SSLClientHelloMessage : public SSLHandshakeMessage + { + public: + /** + * @struct ClientHelloTLSFingerprint + * A struct that contains all the elements needed for creating a Client Hello TLS fingerprinting: + * TLS version, a list of Cipher Suite IDs, a list of Extensions IDs, a list of support groups and a list of + * EC point formats. + * You can read more about this in SSLClientHelloMessage#generateTLSFingerprint(). + * This struct contains methods to extract the TLS fingerprint itself: toString() and toMD5() + */ + struct ClientHelloTLSFingerprint + { + /** TLS version */ + uint16_t tlsVersion; + /** A list of Cipher Suite IDs */ + std::vector cipherSuites; + /** A list of extension IDs */ + std::vector extensions; + /** A list of Suppotred Groups taken from the "supported groups" TLS extension (if exist in the message) */ + std::vector supportedGroups; + /** A list of EC point formats taken from the "EC point formats" TLS extension (if exist in the message) */ + std::vector ecPointFormats; + + /** + * @return A string representing the TLS fingerprint, for example: + * 771,4866-4867-4865-255,0-11-10-35-22-23-13-43-45-51,29-23-30-25-24,0-1-2 + * + * This string has the following format: + * TLSVersion,CipherSuiteIDs,ExtensionIDs,SupportedGroups,ECPointFormats + * + * The extension IDs, supported groups and EC point formats are each separated by a "-". + * If the message doesn't include the "supported groups" or "EC point formats" extensions, they will be + * replaced by an empty string for example: 771,4866-4867-4865-255,0-11-10-35-22-23-13-43-45-51,, + */ + std::string toString(); + + /** + * @return An MD5 hash of the string generated by toString() + */ + std::string toMD5(); + + /** + * @return A pair of the string and MD5 hash (string is first, MD5 is second). + * If you want both this method is more efficient than calling toString() and toMD5() separately + */ + std::pair toStringAndMD5(); + }; + + /** + * C'tor for this class. Currently only in use in SSLHandshakeMessage::createHandshakeMessage() and shouldn't be + * used by a user + * @param[in] data The message as raw data + * @param[in] dataLen Message raw data length in bytes + * @param[in] container The SSL handshake layer which shall contain this message + */ + SSLClientHelloMessage(uint8_t* data, size_t dataLen, SSLHandshakeLayer* container); + + virtual ~SSLClientHelloMessage() + {} + + /** + * @return A struct containing common fields for client-hello and server-hello messages. Notice this points + * directly to the data, so every change will change the actual packet data + */ + ssl_tls_client_server_hello* getClientHelloHeader() const + { + return (ssl_tls_client_server_hello*)m_Data; + } + + /** + * @return Handshake SSL/TLS version (notice it may be different than SSLLayer#getRecordVersion(). Each + * client-hello or server-hello message has both record version and handshake version and they may differ from + * one another) + */ + SSLVersion getHandshakeVersion() const; + + /** + * @return Session ID length in bytes. If server-hello message doesn't include session ID 0 will be returned + */ + uint8_t getSessionIDLength() const; + + /** + * @return Session ID as byte array. If server-hello message doesn't include session ID nullptr will be returned + */ + uint8_t* getSessionID() const; + + /** + * @return The number of cipher-suites included in this message + */ + int getCipherSuiteCount() const; + + /** + * Get a pointer to a cipher-suite by index. The cipher-suites are numbered according to their order of + * appearance in the message. If index is out of bounds (less than 0 or larger than total amount of cipher + * suites) nullptr will be returned. nullptr will also be returned if the cipher-suite ID is unknown. If you + * still want to get the cipher-suite ID you can use getCipherSuiteID() + * @param[in] index The index of the cipher-suite to return + * @return The pointer to the cipher-suite object or nullptr if index is out of bounds + */ + SSLCipherSuite* getCipherSuite(int index) const; + + /** + * Get the cipher-suite ID by index. This method just parses the ID from the client-hello message and returns + * it. To get more information on the cipher-suite you can use the getCipherSuite() method + * @param[in] index The index of the cipher-suite to return + * @param[out] isValid Set to "true" if parsing succeeded and the return value is valid or "false" if: + * (1) the index is out-of-bounds (less than 0 or larger than total amount of cipher suites) or (2) the parsing + * failed. If the value is "false" the return value can be ignored + * @return The cipher-suite ID if "isValid" is set to "true". If "isValid" is set to "false" the return value + * can be ignored + */ + uint16_t getCipherSuiteID(int index, bool& isValid) const; + + /** + * @return The value of the compression method byte + */ + uint8_t getCompressionMethodsValue() const; + + /** + * @return The number of extensions in this message + */ + int getExtensionCount() const; + + /** + * @return The size (in bytes) of all extensions data in this message. Extracted from the "extensions length" + * field + */ + uint16_t getExtensionsLength() const; + + /** + * Get a pointer to an extension by index. The extensions are numbered according to their order of appearance + * in the message. If index is out of bounds (less than 0 or larger than total amount of extensions) nullptr + * will be returned + * @param[in] index The index of the extension to return + * @return The pointer to the extension or nullptr if index is out of bounds + */ + SSLExtension* getExtension(int index) const; + + /** + * Get a pointer to an extension by numeric type field. Every extension has a 2-byte numeric value representing + * its type (for example: renegotiation info extension type is 0x1ff). This method gets the type and returns a + * pointer to the extension object + * @param[in] type The 2-byte numeric type of the extension + * @return A pointer to the extension object of nullptr if this type doesn't exist in this message + */ + SSLExtension* getExtensionOfType(uint16_t type) const; + + /** + * Get a pointer to an extension by its enum type + * @param[in] type The type of extension to return + * @return A pointer to the extension object or nullptr if this type doesn't exist in this message + */ + SSLExtension* getExtensionOfType(SSLExtensionType type) const; + + /** + * Get a pointer to an extension by its class type. This is a templated method that is used with the type of the + * requested extension and returns the first extension instance of this type + * @return A pointer to the extension object or nullptr if this extension type doesn't exist in this message + * + */ + template TExtension* getExtensionOfType() const; + + /** + * TLS fingerprinting is a way to identify client applications using the details in the TLS Client Hello packet. + * It was initially introduced by Lee Brotherston in his 2015 research: + * This implementation of TLS fingerprint is a C++ version of + * Salesforce's JA3 open source project (originally written in Python and Zeek): + * + * @return A SSLClientHelloMessage#ClientHelloTLSFingerprint struct that contains all the elements needed for + * creating a TLS fingerprint out of this Client Hello message. This struct has also methods to extract the TLS + * fingerprint itself in a string or MD5 formats + */ + ClientHelloTLSFingerprint generateTLSFingerprint() const; + + // implement abstract methods + + std::string toString() const; + + private: + PointerVector m_ExtensionList; + }; + + /** + * @class SSLServerHelloMessage + * Represents SSL/TLS server-hello message (type 2). Inherits from SSLHandshakeMessage and adds parsing of all + * fields of this message including the message extensions, cipher-suite, etc. + */ + class SSLServerHelloMessage : public SSLHandshakeMessage + { + public: + /** + * @struct ServerHelloTLSFingerprint + * A struct that contains all the elements needed for creating a Server Hello TLS fingerprinting: + * TLS version, Cipher Suite ID, and a list of Extensions IDs. + * You can read more about this in SSLServerHelloMessage#generateTLSFingerprint(). + * This struct contains methods to extract the TLS fingerprint itself: toString() and toMD5() + */ + struct ServerHelloTLSFingerprint + { + /** TLS version */ + uint16_t tlsVersion; + /** Cipher Suite ID */ + uint16_t cipherSuite; + /** A list of extension IDs */ + std::vector extensions; + + /** + * @return A string representing the TLS fingerprint, for example: 771,49195,65281-16-11 + * + * This string has the following format: TLSVersion,Cipher,Extensions + * + * The extension ID are separated with a "-" + */ + std::string toString(); + + /** + * @return An MD5 hash of the string generated by toString() + */ + std::string toMD5(); + + /** + * @return A pair of the string and MD5 hash (string is first, MD5 is second). + * If you want both this method is more efficient than calling toString() and toMD5() separately + */ + std::pair toStringAndMD5(); + }; + + /** + * C'tor for this class. Currently only in use in SSLHandshakeMessage::createHandshakeMessage() and shouldn't be + * used by a user + * @param[in] data The message as raw data + * @param[in] dataLen Message raw data length in bytes + * @param[in] container The SSL handshake layer which shall contain this message + */ + SSLServerHelloMessage(uint8_t* data, size_t dataLen, SSLHandshakeLayer* container); + + virtual ~SSLServerHelloMessage() + {} + + /** + * @return A struct containing common fields for client-hello and server-hello messages. Notice this points + * directly to the data, so every change will change the actual packet data + */ + ssl_tls_client_server_hello* getServerHelloHeader() const + { + return (ssl_tls_client_server_hello*)m_Data; + } + + /** + * @return Handshake SSL/TLS version (notice it may be different than SSLLayer#getRecordVersion(). Each + * client-hello or server-hello message has both record version and handshake version and they may differ from + * one another). + * + * NOTE: for TLS 1.3 the handshake version written in ssl_tls_client_server_hello::handshakeVersion is + * still TLS 1.2, so a special check is made here see if a SupportedVersions extension exists and if so extract + * the version from it. This is the most straight-forward way to detect TLS 1.3. + */ + SSLVersion getHandshakeVersion() const; + + /** + * @return Session ID length in bytes. If server-hello message doesn't include session ID 0 will be returned + */ + uint8_t getSessionIDLength() const; + + /** + * @return Session ID as byte array. If server-hello message doesn't include session ID nullptr will be returned + */ + uint8_t* getSessionID() const; + + /** + * @return A pointer to the cipher suite encapsulated in this message (server-hello message contains one + * cipher-suite, the one that will be used to for encryption between client and server). May return nullptr + * if the parsing of the message failed or the cipher-suite ID is unknown. If you still want to get the + * cipher-suite ID you can use the getCipherSuiteID() method + */ + SSLCipherSuite* getCipherSuite() const; + + /** + * Get the cipher-suite ID. This method just parses the ID from the server-hello message and returns it. + * To get more information on the cipher-suite you can use the getCipherSuite() method + * @param[out] isValid Set to "true" if parsing succeeded and the return value is valid or "false" otherwise. + * If the value is "false" the return value can be ignored + * @return The cipher-suite ID if "isValid" is set to "true". If "isValid" is set to "false" the return value + * can be ignored + */ + uint16_t getCipherSuiteID(bool& isValid) const; + + /** + * @return The value of the compression method byte + */ + uint8_t getCompressionMethodsValue() const; + + /** + * @return The number of extensions in this message + */ + int getExtensionCount() const; + + /** + * @return The size (in bytes) of all extensions data in this message. Extracted from the "extensions length" + * field + */ + uint16_t getExtensionsLength() const; + + /** + * Get a pointer to an extension by index. The extensions are numbered according to their order of appearance + * in the message. If index is out of bounds (less than 0 or larger than total amount of extensions) nullptr + * will be returned + * @param[in] index The index of the extension to return + * @return The pointer to the extension or nullptr if index is out of bounds + */ + SSLExtension* getExtension(int index) const; + + /** + * Get a pointer to an extension by numeric type field. Every extension has a 2-byte numeric value representing + * its type (for example: renegotiation info extension type is 0x1ff). This method gets the type and returns a + * pointer to the extension object + * @param[in] type The 2-byte numeric type of the extension + * @return A pointer to the extension object of nullptr if this type doesn't exist in this message + */ + SSLExtension* getExtensionOfType(uint16_t type) const; + + /** + * Get a pointer to an extension by its enum type + * @param[in] type The type of extension to return + * @return A pointer to the extension object or nullptr if this type doesn't exist in this message + */ + SSLExtension* getExtensionOfType(SSLExtensionType type) const; + + /** + * Get a pointer to an extension by its class type. This is a templated method that is used with the type of the + * requested extension and returns the first extension instance of this type + * @return A pointer to the extension object or nullptr if this extension type doesn't exist in this message + * + */ + template TExtension* getExtensionOfType() const; + + /** + * ServerHello TLS fingerprinting is a way to fingerprint TLS Server Hello messages. In conjunction with + * ClientHello TLS fingerprinting it can assist in identifying specific client-server communication (for + * example: a malware connecting to its backend server). + * ServerHello TLS fingerprinting was introduced in Salesforce's JA3S open source project: + * + * This implementation is a C++ version of Salesforce's JAS3 (originally written in Python and Zeek) + * @return A SSLServerHelloMessage#ServerHelloTLSFingerprint struct that contains all the elements needed for + * creating a TLS fingerprint out of this Server Hello message. This struct has also methods to extract the TLS + * fingerprint itself in a string or MD5 formats + */ + ServerHelloTLSFingerprint generateTLSFingerprint() const; + + // implement abstract methods + + std::string toString() const; + + private: + PointerVector m_ExtensionList; + }; + + /** + * @class SSLCertificateMessage + * Represents SSL/TLS certificate message (type 11). Inherits from SSLHandshakeMessage and adds parsing + * functionality such as extracting the certificates data. Notice that in most cases this message is spread over + * more than 1 packet as its size is too big for a single packet. So SSLCertificateMessage instance will be created + * just for the first part of the message - the one encapsulated in the first packet. Other parts (encapsulated in + * the following packets) won't be recognized as SSLCertificateMessage messages + */ + class SSLCertificateMessage : public SSLHandshakeMessage + { + public: + /** + * C'tor for this class. Currently only in use in SSLHandshakeMessage::createHandshakeMessage() and should be + * used by a user + * @param[in] data The message as raw data + * @param[in] dataLen Message raw data length in bytes + * @param[in] container The SSL handshake layer which shall contain this message + */ + SSLCertificateMessage(uint8_t* data, size_t dataLen, SSLHandshakeLayer* container); + + virtual ~SSLCertificateMessage() + {} + + /** + * @return The number of certificates encapsulated in this message (as written in the 'length' field of the + * message). Notice that because the message may spread over several packets, not all certificates will + * necessarily be in this packet. So, for example, there may be a case where this method return 3 (message + * contains 3 certificates) but this message actually contains only 1 certificate as the other 2 are spread over + * the other packets + */ + int getNumOfCertificates() const; + + /** + * Get a certificate by index + * @param[in] index The index of the certificate to retrieve + * @return A pointer to the certificate object. Notice that if index < 0 or index > num of certificates + * encapsulated in current packet a nullptr value will be returned + */ + SSLx509Certificate* getCertificate(int index) const; + + // implement abstract methods + + std::string toString() const; + + private: + PointerVector m_CertificateList; + }; + + /** + * @class SSLHelloRequestMessage + * Represents SSL/TLS hello-request message (type 0). This message has no additional payload except for the common + * payload described in SSLHandshakeMessage + */ + class SSLHelloRequestMessage : public SSLHandshakeMessage + { + public: + /** + * C'tor for this class. Currently only in use in SSLHandshakeMessage::createHandshakeMessage() and should be + * used by a user + * @param[in] data The message as raw data + * @param[in] dataLen Message raw data length in bytes + * @param[in] container The SSL handshake layer which shall contain this message + */ + SSLHelloRequestMessage(uint8_t* data, size_t dataLen, SSLHandshakeLayer* container) + : SSLHandshakeMessage(data, dataLen, container) + {} + + virtual ~SSLHelloRequestMessage() + {} + + // implement abstract methods + + std::string toString() const; + }; + + /** + * @class SSLServerKeyExchangeMessage + * Represents SSL/TLS server-key-exchange message (type 12). Inherits from SSLHandshakeMessage and adds parsing + * functionality such as getting the server key exchange params as raw data (parsing of this may be added in the + * future) + */ + class SSLServerKeyExchangeMessage : public SSLHandshakeMessage + { + public: + /** + * C'tor for this class. Currently only in use in SSLHandshakeMessage::createHandshakeMessage() and should be + * used by a user + * @param[in] data The message as raw data + * @param[in] dataLen Message raw data length in bytes + * @param[in] container The SSL handshake layer which shall contain this message + */ + SSLServerKeyExchangeMessage(uint8_t* data, size_t dataLen, SSLHandshakeLayer* container) + : SSLHandshakeMessage(data, dataLen, container) + {} + + ~SSLServerKeyExchangeMessage() + {} + + /** + * @return A pointer to the raw data of the server key exchange params. Currently this data can only returned as + * raw, parsing may be added in the future. Notice that if the message is spread over more than 1 packet in a + * way params doesn't exist in the first packet, nullptr will be returned + */ + uint8_t* getServerKeyExchangeParams() const; + + /** + * @return The size of the params field. Notice that if the message is spread over more than 1 packet in a way + * the ssl_tls_handshake_layer cannot be parsed from the packet, 0 will be returned. Also, if only part of the + * params exist in current packet (and the rest are on consequent packets), the size that will be returned is + * the size of the part that exists in the current packet (and not total size of params) + */ + size_t getServerKeyExchangeParamsLength() const; + + // implement abstract methods + + std::string toString() const; + }; + + /** + * @class SSLClientKeyExchangeMessage + * Represents SSL/TLS client-key-exchange message (type 16). Inherits from SSLHandshakeMessage and adds parsing + * functionality such as getting the server key exchange params as raw data (parsing of this may be added in the + * future) + */ + class SSLClientKeyExchangeMessage : public SSLHandshakeMessage + { + public: + /** + * C'tor for this class. Currently only in use in SSLHandshakeMessage::createHandshakeMessage() and should be + * used by a user + * @param[in] data The message as raw data + * @param[in] dataLen Message raw data length in bytes + * @param[in] container The SSL handshake layer which shall contain this message + */ + SSLClientKeyExchangeMessage(uint8_t* data, size_t dataLen, SSLHandshakeLayer* container) + : SSLHandshakeMessage(data, dataLen, container) + {} + + ~SSLClientKeyExchangeMessage() + {} + + /** + * @return A pointer to the raw data of the server key exchange params. Currently this data can only be returned + * as raw, parsing may be added in the future. Notice that if the message is spread over more than 1 packet in + * a way params doesn't exist in the first packet, nullptr will be returned + */ + uint8_t* getClientKeyExchangeParams() const; + + /** + * @return The size of the params field. Notice that if the message is spread over more than 1 packet in a way + * the ssl_tls_handshake_layer cannot be parsed from the packet, 0 will be returned. Also, if only part of the + * params exist in current packet (and the rest are on consequent packets), the size that will be returned is + * the size of the part that exists in the current packet (and not the total size of params) + */ + size_t getClientKeyExchangeParamsLength() const; + + // implement abstract methods + + std::string toString() const; + }; + + /** + * @class SSLCertificateRequestMessage + * Represents SSL/TLS certificate-request message (type 13). Inherits from SSLHandshakeMessage and adds parsing + * functionality such as retrieving client certificate types and authority data + */ + class SSLCertificateRequestMessage : public SSLHandshakeMessage + { + public: + /** + * C'tor for this class. Currently only in use in SSLHandshakeMessage::createHandshakeMessage() and should be + * used by a user + * @param[in] data The message as raw data + * @param[in] dataLen Message raw data length in bytes + * @param[in] container The SSL handshake layer which shall contain this message + */ + SSLCertificateRequestMessage(uint8_t* data, size_t dataLen, SSLHandshakeLayer* container); + + ~SSLCertificateRequestMessage() + {} + + /** + * @return A reference to a vector containing all client certificate types exist in this message + */ + std::vector& getCertificateTypes(); + + /** + * @return A pointer to the certificate authority data as raw data (byte array). Parsing of this data may be + * added in the future. Notice that if this message is spread over several packets in a way none of the + * certificate authority data exists in this packet, nullptr will be returned + */ + uint8_t* getCertificateAuthorityData() const; + + /** + * @return The length of certificate authority data returned by getCertificateAuthorityData(). Notice that if + * this message is spread over several packets in a way none of certificate authority data exists in the current + * packet, 0 will be returned. Also, if some of the data exists in the consequent packets, the length that will + * be returned is the length of data exists in the current packet only (and not the total length) + */ + size_t getCertificateAuthorityLength() const; + + // implement abstract methods + + std::string toString() const; + + private: + std::vector m_ClientCertificateTypes; + }; + + /** + * @class SSLServerHelloDoneMessage + * Represents SSL/TLS server-hello-done message (type 14). This message has no additional payload except for the + * common payload described in SSLHandshakeMessage + */ + class SSLServerHelloDoneMessage : public SSLHandshakeMessage + { + public: + /** + * C'tor for this class. Currently only in use in SSLHandshakeMessage::createHandshakeMessage() and should be + * used by a user + * @param[in] data The message as raw data + * @param[in] dataLen Message raw data length in bytes + * @param[in] container The SSL handshake layer which shall contain this message + */ + SSLServerHelloDoneMessage(uint8_t* data, size_t dataLen, SSLHandshakeLayer* container) + : SSLHandshakeMessage(data, dataLen, container) + {} + + virtual ~SSLServerHelloDoneMessage() + {} + + // implement abstract methods + + std::string toString() const; + }; + + /** + * @class SSLCertificateVerifyMessage + * Represents SSL/TLS certificate-verify message (type 15). Inherits from SSLHandshakeMessage and adds parsing + * functionality such as retrieving signed hash data as raw data (parsing may be added in the future) + * @todo This message type wasn't tested in unit-tests + */ + class SSLCertificateVerifyMessage : public SSLHandshakeMessage + { + public: + /** + * C'tor for this class. Currently only in use in SSLHandshakeMessage::createHandshakeMessage() and should be + * used by a user + * @param[in] data The message as raw data + * @param[in] dataLen Message raw data length in bytes + * @param[in] container The SSL handshake layer which shall contain this message + */ + SSLCertificateVerifyMessage(uint8_t* data, size_t dataLen, SSLHandshakeLayer* container) + : SSLHandshakeMessage(data, dataLen, container) + {} + + virtual ~SSLCertificateVerifyMessage() + {} + + /** + * @return A pointer to the signed hash data as raw data (byte array). Parsing of this data may be added + * in the future. Notice that if this message is spread over several packets in a way none of the signed hash + * data exists in this packet, nullptr will be returned + */ + uint8_t* getSignedHash() const; + + /** + * @return The length of signed hash data returned by getSignedHash(). Notice that if this message is spread + * over several packets in a way none of this data exists in the current packet, 0 will be returned. Also, if + * some of the data exists in the consequent packets, the length that will be returned will be the length of + * data exists in the current packet only (and not the total length) + */ + size_t getSignedHashLength() const; + + // implement abstract methods + + std::string toString() const; + }; + + /** + * @class SSLFinishedMessage + * Represents SSL/TLS finished message (type 20). Inherits from SSLHandshakeMessage and adds parsing + * functionality such as retrieving signed hash data as raw data (parsing may be added in the future) + * @todo This message type wasn't tested in unit-tests + */ + class SSLFinishedMessage : public SSLHandshakeMessage + { + public: + /** + * C'tor for this class. Currently only in use in SSLHandshakeMessage::createHandshakeMessage() and should be + * used by a user + * @param[in] data The message as raw data + * @param[in] dataLen Message raw data length in bytes + * @param[in] container The SSL handshake layer which shall contain this message + */ + SSLFinishedMessage(uint8_t* data, size_t dataLen, SSLHandshakeLayer* container) + : SSLHandshakeMessage(data, dataLen, container) + {} + + virtual ~SSLFinishedMessage() + {} + + /** + * @return A pointer to the signed hash data as raw data (byte array). Parsing of this data may be added + * in the future. Notice that if this message is spread over several packets in a way none of the signed hash + * data exists in this packet, nullptr will be returned + */ + uint8_t* getSignedHash() const; + + /** + * @return The length of signed hash data returned by getSignedHash(). Notice that if the message is spread over + * several packets in a way none of this data exists in the current packet, 0 will be returned. Also, if some of + * the data exists in the consequent packets, the length that will be returned will be the length of data exists + * in the current packet only (and not the total length) + */ + size_t getSignedHashLength() const; + + // implement abstract methods + + std::string toString() const; + }; + + /** + * @class SSLNewSessionTicketMessage + * Represents SSL/TLS new-session-ticket message (type 4). Inherits from SSLHandshakeMessage and adds parsing + * functionality such as retrieving session ticket data as raw data (parsing may be added in the future) + */ + class SSLNewSessionTicketMessage : public SSLHandshakeMessage + { + public: + /** + * C'tor for this class. Currently only in use in SSLHandshakeMessage::createHandshakeMessage() and should be + * used by a user + * @param[in] data The message as raw data + * @param[in] dataLen Message raw data length in bytes + * @param[in] container The SSL handshake layer which shall contain this message + */ + SSLNewSessionTicketMessage(uint8_t* data, size_t dataLen, SSLHandshakeLayer* container) + : SSLHandshakeMessage(data, dataLen, container) + {} + + virtual ~SSLNewSessionTicketMessage() + {} + + /** + * @return A pointer to the session ticket data as raw data (byte array). Parsing of this data may be added + * in the future. Notice that if this message is spread over several packets in a way none of the signed hash + * data exists in current packet, nullptr will be returned + */ + uint8_t* getSessionTicketData() const; + + /** + * @return The length of session ticket data returned by getSessionTicketData(). Notice that if this message is + * spread over several packets in a way none of this data exists in the current packet, 0 will be returned. + * Also, if some of the data exist in the consequent packets, the length that will be returned will be the + * length of the data existing in the current packet only (and not the total length) + */ + size_t getSessionTicketDataLength() const; + + // implement abstract methods + + std::string toString() const; + }; + + /** + * @class SSLUnknownMessage + * Represents an unknown type of message or an encrypted message that PcapPlusPlus can't determine its type. In + * these cases length can't always be determined from the message itself (especially if the message is encrypted), + * so the length of this message will always be the size counted from message start until the end of the layer + */ + class SSLUnknownMessage : public SSLHandshakeMessage + { + public: + /** + * C'tor for this class. Currently only in use in SSLHandshakeMessage::createHandshakeMessage() and should be + * used by a user + * @param[in] data The message as raw data + * @param[in] dataLen Message raw data length in bytes + * @param[in] container The SSL handshake layer which shall contain this message + */ + SSLUnknownMessage(uint8_t* data, size_t dataLen, SSLHandshakeLayer* container) + : SSLHandshakeMessage(data, dataLen, container) + {} + + virtual ~SSLUnknownMessage() + {} + + // implement virtual and abstract methods + + /** + * @return Always ::SSL_HANDSHAKE_UNKNOWN (overridden from SSLHandshakeMessage) + */ + SSLHandshakeType getHandshakeType() const; + + /** + * @return The length of the data from message start until the end of the layer. Since it's an unknown type + * or an encrypted message the length parsed from the message can't be guaranteed to be the correct length. + * That's why the length returned is the size until the end of the layer + */ + size_t getMessageLength() const; + + std::string toString() const; + }; + + template TExtension* SSLClientHelloMessage::getExtensionOfType() const + { + size_t vecSize = m_ExtensionList.size(); + for (size_t i = 0; i < vecSize; i++) + { + SSLExtension* curElem = const_cast(m_ExtensionList.at(i)); + if (dynamic_cast(curElem) != nullptr) + return (TExtension*)curElem; + } + + return nullptr; + } + + template TExtension* SSLServerHelloMessage::getExtensionOfType() const + { + size_t vecSize = m_ExtensionList.size(); + for (size_t i = 0; i < vecSize; i++) + { + SSLExtension* curElem = const_cast(m_ExtensionList.at(i)); + if (dynamic_cast(curElem) != nullptr) + return (TExtension*)curElem; + } + + return nullptr; + } + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/SSLLayer.h b/Packet++/header/pcapplusplus/SSLLayer.h new file mode 100644 index 0000000000..ce45e4a6fd --- /dev/null +++ b/Packet++/header/pcapplusplus/SSLLayer.h @@ -0,0 +1,570 @@ +#pragma once + +#include "pcapplusplus/PointerVector.h" +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/SSLCommon.h" +#include "pcapplusplus/SSLHandshake.h" + +/** + * @file + * This file as well as SSLCommon.h and SSLHandshake.h provide structures that represent SSL/TLS protocol. + * Main features: + * - All common SSL/TLS version are supported from SSL 3.0 to TLS 1.3 + * - All SSL/TLS message types are supported (at least the message types that are not encrypted) + * - More than 300 cipher-suites are supported + * - Only parsing capabilities exist, editing and creation of messages are not supported + * - X509 certificate parsing is not supported + * + *

+ * + * __SSL Records:__
+ * + * The SSL/TLS protocol has 4 types of records: + * - Handshake record type + * - Change cipher spec record type + * - Alert record type + * - Application data record type + * + * Each record type corresponds to a layer class, and these classes inherit from one base class which is pcpp::SSLLayer. + * The pcpp::SSLLayer is an abstract class which cannot be instantiated. Only its 4 derived classes can be instantiated. + * This means you'll never see a layer of type pcpp::SSLLayer, you'll only see the type of the derived classes. + * A basic class diagram looks like this: + @verbatim + +----------------------------+ + +---| SSLHandshakeLayer | ===> Handshake record type + | +----------------------------+ + | + | +----------------------------+ + +---| SSLChangeCipherSpecLayer | ===> Change cipher spec record type + | +----------------------------+ + | + +------------+ | +----------------------------+ + | SSLLayer |-------------+---| SSLAlertLayer | ===> Alert record type + | (abstract) | | +----------------------------+ + +------------+ | + | +----------------------------+ + +---| SSLApplicationDataLayer | ===> Application data record type + +----------------------------+ + + @endverbatim + * + * A single packet may include several SSL/TLS records, meaning several layer instances of these types, for example: + * + @verbatim + + +--------------------------+ + | EthLayer | + +--------------------------+ + | IPv4Layer | + +--------------------------+ + | TcpLayer | + +--------------------------+ + | SSLHandshakeLayer | \ + +--------------------------+ \ + | SSLChangeCipherSpecLayer | -------- 3 SSL/TLS records in the same packet! + +--------------------------+ / + | SSLHandshakeLayer | / + +--------------------------+ + + @endverbatim + * + *

+ * + * __SSL/TLS Handshake records:__
+ * + * The SSL/TLS handshake records are the most complex ones. These type of records encapsulate all messages between + * client and server during SSL/TLS connection establishment. To accomplish that a SSL/TLS handshake record holds + * zero or more handshake messages (usually it holds 1 message). These messages form the handshake negotiation between + * the client and the server. There are several types of handshake messages. Some of the are sent from client to server + * and some from server to client. PcapPlusPlus supports 11 of these types (definitely the most common ones). For each + * message there is a designated class which parses the message and exposes its attributes in an easy-to-use manner. + * Here are the list of supported messages: + * - Client-hello + * - Server-hello + * - Certificate + * - Hello-request + * - Server-key-exchange + * - Client-key-exchange + * - Certificate-request + * - Server-hello-done + * - Certificate-verify + * - Finished + * - New-session-ticket + * + * All handshake messages classes inherit from a base abstract class: pcpp::SSLHandshakeMessage which cannot be + * instantiated. + * Also, all of them reside in SSLHandshake.h. Following is a simple diagram of these classes: + * + @verbatim + + SSLHandshakeMessage + | + +-------------------------------+ |--- SSLClientHelloMessage ==> Client-hello message + | SSLHandshakeLayer | | + +-------------------------------+ |--- SSLServerHelloMessage ==> Server-hello message + | -List of SSLHandshakeMessage | | + | Message1 | |---SSLCertificateMessage ==> Certificate message + | Message2 | | + | ... | |---SSLHelloRequestMessage ==> Hello-request message + | | | + +-------------------------------+ |---SSLServerKeyExchangeMessage ==> Server-key-exchange message + | + |---SSLClientKeyExchangeMessage ==> Client-key-exchange message + | + |---SSLCertificateRequestMessage ==> Certificate-request message + | + |---SSLServerHelloDoneMessage ==> Server-hello-done message + | + |---SSLCertificateVerifyMessage ==> Certificate-verify message + | + |---SSLFinishedMessage ==> Finished message + | + |---SSLNewSessionTicketMessage ==> New-session-ticket message + + @endverbatim + * + * In addition, for all handshake messages which aren't supported in PcapPlusPlus or for encrypted handshake messages + * There is another class: pcpp::SSLUnknownMessage + * + *

+ * + * __Cipher suites:__
+ * + * Cipher suites are named combinations of authentication, encryption, message authentication code (MAC) and key + * exchange algorithms used to negotiate the security settings for a network connection using SSL/TLS. + * There are many known cipher-suites. PcapPlusPlus support above 300 of them, according to this list: + * http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml + * There is a designated class in PcapPlusPlus called pcpp::SSLCipherSuite which represents the cipher-suites and + * provides access to their attributes. Then there is a static instance of this class for each one of the supported + * cipher-suites. + * This means there are 300+ static instances of pcpp::SSLCipherSuite representing the different cipher suites. The user + * can access them through static methods in pcpp::SSLCipherSuite or from client-hello and server-hello messages where + * they appear. + * + *

+ * + * __SSL/TLS extensions:__
+ * + * SSL/TLS handshake messages, specifically client-hello and server-hello usually include extensions. There are various + * types of extensions - some are more broadly used, some are less. In PcapPlusPlus there is a base class for all + * extensions: pcpp::SSLExtension. This class is instantiable and represents a generic extension, which means extension + * data isn't parsed and given to the user as raw data. Currently there are only two extension that are fully parsed + * which are server-name-indication (pcpp::SSLServerNameIndicationExtension) and SupportedVersions + * (pcpp::SSLSupportedVersionsExtension). + * Both inherit from pcpp::SSLExtension and add additional parsing relevant for the specific extension. + * All other extensions aren't parsed and are represented by instance of pcpp::SSLExtension. + * Access to extensions is done through the handshake messages classes, specifically pcpp::SSLClientHelloMessage and + * pcpp::SSLServerHelloMessage + */ + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * @class SSLLayer + * The base class for the 4 record type classes. Each record type is represented as a layer. See SSLLayer.h for + * detailed explanation of the TLS/SSL protocol support in PcapPlusPlus. + * This class provides the common functionality used by all record types and also contains static methods for + * identifying an creating SSL/TLS record type layers + */ + class SSLLayer : public Layer + { + public: + /** + * A static method that checks whether the port is considered as SSL/TLS + * @param[in] port The port number to be checked + */ + static inline bool isSSLPort(uint16_t port); + + /** + * A static methods that gets raw data of a layer and checks whether this data is a SSL/TLS record or not. This + * check is done using the source/dest port and matching of a legal record type in the raw data. The list of + * ports identified as SSL/TLS is hard-coded and includes the following ports: + * - Port 443 [HTTPS] + * - Port 261 [NSIIOPS] + * - Port 448 [DDM-SSL] + * - Port 563 [NNTPS] + * - Port 614 [SSHELL] + * - Port 465 [SMTPS] + * - Port 636 [LDAPS] + * - Port 989 [FTPS - data] + * - Port 990 [FTPS - control] + * - Port 992 [Telnet over TLS/SSL] + * - Port 993 [IMAPS] + * - Port 994 [IRCS] + * - Port 995 [POP3S] + * @param[in] srcPort The source port of the packet that contains the raw data. Source port (or dest port) are a + * criteria to identify SSL/TLS packets + * @param[in] dstPort The dest port of the packet that contains the raw data. Dest port (or source port) are a + * criteria to identify SSL/TLS packets + * @param[in] data The data to check + * @param[in] dataLen Length (in bytes) of the data + * @param[in] ignorePorts SSL/TLS ports are only relevant for parsing the first SSL/TLS message, but are not + * relevant for parsing subsequent messages. This parameter can be set to "true" to skip SSL/TLS ports check. + * This is an optional parameter and its default is "false" + */ + static bool IsSSLMessage(uint16_t srcPort, uint16_t dstPort, uint8_t* data, size_t dataLen, + bool ignorePorts = false); + + /** + * A static method that creates SSL/TLS layers by raw data. This method parses the raw data, finds if and which + * SSL/TLS record it is and creates the corresponding record layer. It's the responsibility of the user to free + * the created object when done using it + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + * @return A pointer to the newly created record layer. If no SSL/TLS record could be identified from the raw + * data nullptr is returned + */ + static SSLLayer* createSSLMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + /** + * Get a pointer to the record header. Notice this points directly to the data, so every change will change the + * actual packet data + * @return A pointer to the @ref ssl_tls_record_layer + */ + ssl_tls_record_layer* getRecordLayer() const + { + return (ssl_tls_record_layer*)m_Data; + } + + /** + * @return The SSL/TLS version used in this record (parsed from the record) + */ + SSLVersion getRecordVersion() const; + + /** + * @return The SSL/TLS record type as parsed from the record + */ + SSLRecordType getRecordType() const; + + // implement abstract methods + + /** + * @return The record size as extracted from the record data (in ssl_tls_record_layer#length) + */ + size_t getHeaderLen() const; + + /** + * Several SSL/TLS records can reside in a single packets. So this method checks the remaining data and if it's + * identified as SSL/TLS it creates another SSL/TLS record layer as the next layer + */ + void parseNextLayer(); + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelPresentationLayer; + } + + protected: + SSLLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : Layer(data, dataLen, prevLayer, packet, SSL) + {} + + }; // class SSLLayer + + // The graph below will break the code formatting, so it's disabled. + // clang-format off + /** + * @class SSLHandshakeLayer + * Represents SSL/TLS handshake layer. This layer may contain one or more handshake messages (all of them inherit + * from the base class SSLHandshakeMessage) which are the SSL/TLS handshake message sent between a client and a + * server until they establish a secure connection (e.g client-hello, server-hello, certificate, + * client-key-exchange, server-key-exchange, etc.). + * Usually this layer will contain just one message (as the first example below + * demonstrates). But there are cases a layer may contain more than 1 message. To better explain this layer + * structure. We'll use 2 examples. The first will be client-hello message. The layer structure will look like this: + @verbatim + + |------------------- SSLHandshakeLayer ----------------------| + +----------------------+-------------------------------------+ + | ssl_tls_record_layer | SSLClientHelloMessage | + | struct | | + +----------------------+-------------------------------------+ + / | \ | \ \ \ + / version \ | handshake \ \ \ + / TLS1_0 \ type \ \ rest of + type \ | SSL_CLIENT_HELLO \ \ message fields... + SSL_HANDSHAKE length handshake \ + (22) xxx | version message + TLS1_2 length + | yyy + @endverbatim + + * Second example is a multiple-message handshake layer comprises of server-hello, certificate and + * server-key-exchange messages: + + @verbatim + + |---------------------------------------------- SSLHandshakeLayer -----------------------------------------------------| + +----------------------+-------------------------------------+---------------------------+-----------------------------+ + | ssl_tls_record_layer | SSLServerHelloMessage | SSLCertificateMessage | SSLServerKeyExchangeMessage | + | struct | | | | + +----------------------+-------------------------------------+---------------------------+-----------------------------+ + / | \ | \ \ | \ | \ + / version \ | handshake \ rest of | | rest | | rest + / TLS1_0 \ type \ message handshake of fields... handshake of fields... + type \ | SSL_SERVER_HELLO \ fields...| type | type + SSL_HANDSHAKE length handshake SSL_CERTIFICATE SSL_SERVER_KEY_EXCHANGE + (22) xxx | version,length | | + @endverbatim + */ + // clang-format on + class SSLHandshakeLayer : public SSLLayer + { + public: + /** + * C'tor for this class that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + SSLHandshakeLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + /** + * @return The number of messages in this layer instance + */ + size_t getHandshakeMessagesCount() const + { + return m_MessageList.size(); + } + + /** + * Get a pointer to an handshake message by index. The message are numbered according to their order of + * appearance in the layer. If index is out of bounds (less than 0 or larger than total amount of message) + * nullptr will be returned + * @param[in] index The index of the message to return + * @return The pointer to the message object or nullptr if index is out of bounds + */ + SSLHandshakeMessage* getHandshakeMessageAt(int index) const; + + /** + * A templated method to get a message of a certain type. If no message of such type is found, nullptr is + * returned + * @return A pointer to the message of the requested type, nullptr if not found + */ + template THandshakeMessage* getHandshakeMessageOfType() const; + + /** + * A templated method to get the first message of a certain type, starting to search from a certain message. + * For example: if the layer looks like: HelloRequest(1) -> HelloRequest(2) + * and the user put HelloRequest(1) as a parameter and wishes to search for an HelloRequest message, the + * HelloRequest(2) will be returned.
+ * If no layer of such type is found, nullptr is returned + * @param[in] after A pointer to the message to start search from + * @return A pointer to the message of the requested type, nullptr if not found + */ + template + THandshakeMessage* getNextHandshakeMessageOfType(const SSLHandshakeMessage* after) const; + + // implement abstract methods + + std::string toString() const; + + /** + * There are no calculated fields for this layer + */ + void computeCalculateFields() + {} + + private: + PointerVector m_MessageList; + }; // class SSLHandshakeLayer + + /** + * @class SSLChangeCipherSpecLayer + * Represents SSL/TLS change-cipher-spec layer. This layer has no additional fields besides common fields described + * in SSLLayer + */ + class SSLChangeCipherSpecLayer : public SSLLayer + { + public: + /** + * C'tor for this class that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + SSLChangeCipherSpecLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : SSLLayer(data, dataLen, prevLayer, packet) + {} + + ~SSLChangeCipherSpecLayer() + {} + + // implement abstract methods + + std::string toString() const; + + /** + * There are no calculated fields for this layer + */ + void computeCalculateFields() + {} + }; // class SSLChangeCipherSpecLayer + + /** + * @class SSLAlertLayer + * Represents SSL/TLS alert layer. Inherits from SSLLayer and adds parsing functionality such as retrieving the + * alert level and description + */ + class SSLAlertLayer : public SSLLayer + { + public: + /** + * C'tor for this class that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + SSLAlertLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : SSLLayer(data, dataLen, prevLayer, packet) + {} + + ~SSLAlertLayer() + {} + + /** + * @return SSL/TLS alert level. Will return ::SSL_ALERT_LEVEL_ENCRYPTED if alert is encrypted + */ + SSLAlertLevel getAlertLevel() const; + + /** + * @return SSL/TLS alert description. Will return ::SSL_ALERT_ENCRYPTED if alert is encrypted + */ + SSLAlertDescription getAlertDescription(); + + // implement abstract methods + + std::string toString() const; + + /** + * There are no calculated fields for this layer + */ + void computeCalculateFields() + {} + }; // class SSLAlertLayer + + /** + * @class SSLApplicationDataLayer + * Represents SSL/TLS application data layer. This message contains the encrypted data transferred from client to + * server and vice-versa after the SSL/TLS handshake was completed successfully + */ + class SSLApplicationDataLayer : public SSLLayer + { + public: + /** + * C'tor for this class that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + SSLApplicationDataLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : SSLLayer(data, dataLen, prevLayer, packet) + {} + + ~SSLApplicationDataLayer() + {} + + /** + * @return A pointer to the encrypted data. This data can be decrypted only if you have the symmetric key + * that was agreed between the client and the server during SSL/TLS handshake process + */ + uint8_t* getEncryptedData() const; + + /** + * @return The length in bytes of the encrypted data returned in getEncryptedData() + */ + size_t getEncryptedDataLen() const; + + // implement abstract methods + + std::string toString() const; + + /** + * There are no calculated fields for this layer + */ + void computeCalculateFields() + {} + }; // class SSLApplicationDataLayer + + template THandshakeMessage* SSLHandshakeLayer::getHandshakeMessageOfType() const + { + size_t vecSize = m_MessageList.size(); + for (size_t i = 0; i < vecSize; i++) + { + SSLHandshakeMessage* curElem = const_cast(m_MessageList.at(i)); + if (dynamic_cast(curElem) != nullptr) + return (THandshakeMessage*)curElem; + } + + // element not found + return nullptr; + } // getHandshakeMessageOfType + + template + THandshakeMessage* SSLHandshakeLayer::getNextHandshakeMessageOfType(const SSLHandshakeMessage* after) const + { + size_t vecSize = m_MessageList.size(); + size_t afterIndex; + + // find the index of "after" + for (afterIndex = 0; afterIndex < vecSize; afterIndex++) + { + SSLHandshakeMessage* curElem = const_cast(m_MessageList.at(afterIndex)); + if (curElem == after) + break; + } + + // "after" not found + if (afterIndex == vecSize) + return nullptr; + + for (size_t i = afterIndex + 1; i < vecSize; i++) + { + SSLHandshakeMessage* curElem = const_cast(m_MessageList.at(i)); + if (dynamic_cast(curElem) != nullptr) + return (THandshakeMessage*)curElem; + } + + // element not found + return nullptr; + } // getNextHandshakeMessageOfType + + // implementation of inline methods + + bool SSLLayer::isSSLPort(uint16_t port) + { + if (port == 443) // HTTPS, this is likely case + return true; + + switch (port) + { + case 261: // NSIIOPS + case 448: // DDM-SSL + case 465: // SMTPS + case 563: // NNTPS + case 614: // SSHELL + case 636: // LDAPS + case 989: // FTPS - data + case 990: // FTPS - control + case 992: // Telnet over TLS/SSL + case 993: // IMAPS + case 994: // IRCS + case 995: // POP3S + return true; + default: + return false; + } + } // isSSLPort + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/SdpLayer.h b/Packet++/header/pcapplusplus/SdpLayer.h new file mode 100644 index 0000000000..233f00498a --- /dev/null +++ b/Packet++/header/pcapplusplus/SdpLayer.h @@ -0,0 +1,185 @@ +#pragma once + +#include "pcapplusplus/IpAddress.h" +#include "pcapplusplus/TextBasedProtocol.h" +#include + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + +/** Protocol version (v) */ +#define PCPP_SDP_PROTOCOL_VERSION_FIELD "v" +/** Originator and session identifier (o) */ +#define PCPP_SDP_ORIGINATOR_FIELD "o" +/** Session name (s) */ +#define PCPP_SDP_SESSION_NAME_FIELD "s" +/** Session title, media title or short information (i) */ +#define PCPP_SDP_INFO_FIELD "i" +/** URI of description (u) */ +#define PCPP_SDP_URI_FIELD "u" +/** Email address with optional name of contacts (e) */ +#define PCPP_SDP_EMAIL_FIELD "e" +/** Phone number with optional name of contacts (p) */ +#define PCPP_SDP_PHONE_FIELD "p" +/** Connection information (c) */ +#define PCPP_SDP_CONNECTION_INFO_FIELD "c" +/** Bandwidth information (b) */ +#define PCPP_SDP_BANDWIDTH_FIELD "b" +/** Time the session is active (t) */ +#define PCPP_SDP_TIME_FIELD "t" +/** Repeat times (r) */ +#define PCPP_SDP_REPEAT_TIMES_FIELD "r" +/** Time zone adjustments (z) */ +#define PCPP_SDP_TIME_ZONE_FIELD "z" +/** Encryption key (k) */ +#define PCPP_SDP_ENCRYPTION_KEY_FIELD "k" +/** Media attribute (a) */ +#define PCPP_SDP_MEDIA_ATTRIBUTE_FIELD "a" +/** Media name and transport address (m) */ +#define PCPP_SDP_MEDIA_NAME_FIELD "m" + + /** + * @class SdpLayer + * Represents a SDP (Session Description Protocol) message. SDP is a text-based protocol described by a series of + * fields, one per line (lines are separated by CRLF). The form of each field is as follows:
+ * @code + * [character]=[value] + * @endcode + * Each character represents a certain type of field. All field type are represented as macros in SdpLayer.h file + * (for example: PCPP_SDP_ORIGINATOR_FIELD is a macro for the originator field (o=) ).
+ * For more details about SDP structure please refer to its Wikipedia page: + * https://en.wikipedia.org/wiki/Session_Description_Protocol + */ + class SdpLayer : public TextBasedProtocolMessage + { + public: + /** A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + SdpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + /** + * An empty c'tor which initialize an empty message with no fields + */ + SdpLayer(); + + /** + * A c'tor which initializes a message with the minimum required fields.
+ * After this c'tor the message will look like this: + * + * @code + * v=0 + * o=[username] [sessionID] [sessionVersion] IN IP4 [ipAddress] + * s=[sessionName] + * c=IN IP4 [ipAddress] + * t=[startTime] [endTime] + * @endcode + * + * @param[in] username User's login on the originating host + * @param[in] sessionID A globally unique identifier for the session + * @param[in] sessionVersion A version number for this session description + * @param[in] ipAddress The address of the machine from which the session is created + * @param[in] sessionName A textual session name + * @param[in] startTime The start time of the session + * @param[in] stopTime The stop time of the session + */ + SdpLayer(const std::string& username, long sessionID, long sessionVersion, IPv4Address ipAddress, + const std::string& sessionName, long startTime, long stopTime); + + ~SdpLayer() + {} + + /** + * A copy constructor for this layer. Inherits the base copy constructor and doesn't add + * anything else + * @param[in] other The instance to copy from + */ + SdpLayer(const SdpLayer& other) : TextBasedProtocolMessage(other) + {} + + /** + * An assignment operator overload for this layer. Inherits the base assignment operator + * and doesn't add anything else + * @param[in] other The instance to copy from + */ + SdpLayer& operator=(const SdpLayer& other) + { + TextBasedProtocolMessage::operator=(other); + return *this; + } + + /** + * The 'originator' field (o=) contains the IP address of the the machine from which the session is created. + * This IP address can be used to track the RTP data relevant for the call. This method extracts this IP address + * from the 'originator' field and returns it. A value of IPv4Address#Zero will be returned in the following + * cases: (1) if 'originator' field doesn't exist; (2) if it doesn't contain the IP address; (3) if it contains + * a non-IPv4 address + * @return The IP address of the the machine from which the session is created + */ + IPv4Address getOwnerIPv4Address() const; + + /** + * The 'media-description' field (m=) contains the transport port to which the media stream is sent. This port + * can be used to track the RTP data relevant for the call. This method extracts this port from the + * 'media-description' field and returns it. Since a SDP message can contain several 'media-description' fields, + * one for each media type (e.g audio, image, etc.), the user is required to provide the media type. A value of + * 0 will be returned in the following cases: (1) if 'media-description' field doesn't exist; (2) if provided + * media type was not found; (3) if 'media-description' field didn't contain a port + * @param[in] mediaType The media type to search in + * @return The transport port to which the media stream is sent + */ + uint16_t getMediaPort(const std::string& mediaType) const; + + /** + * Adds a 'media-description' field (m=) with all necessary data and attribute fields (a=) with data relevant + * for this media.
After this method is run the following block of fields will be added at the end of the + * message: + * + * @code + * m=[mediaType] [mediaPort] [mediaProtocol] [mediaFormat] + * a=[1st media attribute] + * a=[2nd media attribute] + * ... + * @endcode + * + * @param[in] mediaType The media type, usually "audio", "video", "text" or "image" + * @param[in] mediaPort The transport port to which the media stream is sent + * @param[in] mediaProtocol The transport protocol, usually "udp", "RTP/AVP" or "RTP/SAVP" + * @param[in] mediaFormat A space-separated list of media format description. For example: "8 96" + * @param[in] mediaAttributes A vector of media attributes. Each string in this vector will be + * translated into a 'media-attribute' field (a=) + * @return True if all fields were added properly or false if at least one field was failed to be added + */ + bool addMediaDescription(const std::string& mediaType, uint16_t mediaPort, const std::string& mediaProtocol, + const std::string& mediaFormat, const std::vector& mediaAttributes); + + // overridden methods + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelSesionLayer; + } + + std::string toString() const; + + protected: + // implementation of abstract methods + char getHeaderFieldNameValueSeparator() const + { + return '='; + } + bool spacesAllowedBetweenHeaderFieldNameAndValue() const + { + return false; + } + }; +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/SingleCommandTextProtocol.h b/Packet++/header/pcapplusplus/SingleCommandTextProtocol.h new file mode 100644 index 0000000000..d53aafac7f --- /dev/null +++ b/Packet++/header/pcapplusplus/SingleCommandTextProtocol.h @@ -0,0 +1,56 @@ +#pragma once + +#include +#include "pcapplusplus/Layer.h" + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * Class for single command text based protocol (FTP, SMTP) messages + */ + class SingleCommandTextProtocol : public Layer + { + private: + size_t getArgumentFieldOffset() const; + void setDelimiter(bool hyphen); + bool hyphenRequired(const std::string& value); + + protected: + SingleCommandTextProtocol(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, + ProtocolType protocol) + : Layer(data, dataLen, prevLayer, packet, protocol) {}; + + SingleCommandTextProtocol(const std::string& command, const std::string& option, ProtocolType protocol); + + bool setCommandInternal(std::string value); + bool setCommandOptionInternal(std::string value); + + std::string getCommandInternal() const; + std::string getCommandOptionInternal() const; + + public: + /** + * Checks if the current message is a multi-line reply. Multi-line messages are indicated with a Hyphen (-) + * immediately after reply code. + * @return true If this is a multi-line reply + * @return false Otherwise + */ + bool isMultiLine() const; + + /** + * A static method that takes a byte array and detects whether it is a single command text based message. + * All single command text based message terminated with single "\r\n". + * @param[in] data A byte array + * @param[in] dataSize The byte array size (in bytes) + * @return True if the data is identified as single command text based message + */ + static bool isDataValid(const uint8_t* data, size_t dataSize); + }; +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/SipLayer.h b/Packet++/header/pcapplusplus/SipLayer.h new file mode 100644 index 0000000000..f38f64f890 --- /dev/null +++ b/Packet++/header/pcapplusplus/SipLayer.h @@ -0,0 +1,779 @@ +#pragma once + +#include "pcapplusplus/TextBasedProtocol.h" + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ +// some popular SIP header fields + +/** From field */ +#define PCPP_SIP_FROM_FIELD "From" +/** To field */ +#define PCPP_SIP_TO_FIELD "To" +/** Via field */ +#define PCPP_SIP_VIA_FIELD "Via" +/** Call-ID field */ +#define PCPP_SIP_CALL_ID_FIELD "Call-ID" +/** Content-Type field */ +#define PCPP_SIP_CONTENT_TYPE_FIELD "Content-Type" +/** Content-Length field */ +#define PCPP_SIP_CONTENT_LENGTH_FIELD "Content-Length" +/** Content-Disposition field */ +#define PCPP_SIP_CONTENT_DISPOSITION_FIELD "Content-Disposition" +/** Content-Encoding field */ +#define PCPP_SIP_CONTENT_ENCODING_FIELD "Content-Encoding" +/** Content-Language field */ +#define PCPP_SIP_CONTENT_LANGUAGE_FIELD "Content-Language" +/** CSeq field */ +#define PCPP_SIP_CSEQ_FIELD "CSeq" +/** Contact field */ +#define PCPP_SIP_CONTACT_FIELD "Contact" +/** Max-Forwards field */ +#define PCPP_SIP_MAX_FORWARDS_FIELD "Max-Forwards" +/** User-Agent field */ +#define PCPP_SIP_USER_AGENT_FIELD "User-Agent" +/** Accept field */ +#define PCPP_SIP_ACCEPT_FIELD "Accept" +/** Accept-Encoding field */ +#define PCPP_SIP_ACCEPT_ENCODING_FIELD "Accept-Encoding" +/** Accept-Language field */ +#define PCPP_SIP_ACCEPT_LANGUAGE_FIELD "Accept-Language" +/** Allow field */ +#define PCPP_SIP_ALLOW_FIELD "Allow" +/** Authorization field */ +#define PCPP_SIP_AUTHORIZATION_FIELD "Authorization" +/** Date field */ +#define PCPP_SIP_DATE_FIELD "Date" +/** MIME-Version field */ +#define PCPP_SIP_MIME_VERSION_FIELD "MIME-Version" +/** Reason field */ +#define PCPP_SIP_REASON_FIELD "Reason" +/** Supported field */ +#define PCPP_SIP_SUPPORTED_FIELD "Supported" +/** Server field */ +#define PCPP_SIP_SERVER_FIELD "Server" +/** WWW-Authenticate fild */ +#define PCPP_SIP_WWW_AUTHENTICATE_FIELD "WWW-Authenticate" +/** Retry-After field */ +#define PCPP_SIP_RETRY_AFTER_FIELD "Retry-After" +/** Record-Route field */ +#define PCPP_SIP_RECORD_ROUTE_FIELD "Record-Route" + + /** + * @class SipLayer + * Represents a general SIP message. It's an abstract class and cannot be instantiated. It's inherited by + * SipRequestLayer and SipResponseLayer + */ + class SipLayer : public TextBasedProtocolMessage + { + public: + /** + * The length of the body of many SIP response messages is determined by a SIP header field called + * "Content-Length". This method parses this field, extracts its value and return it. If this field doesn't + * exist 0 is returned + * @return SIP response body length determined by "Content-Length" field + */ + int getContentLength() const; + + /** + * The length of the body of many SIP messages is determined by a header field called "Content-Length". This + * method sets The content-length field value. The method supports several cases: + * - If the "Content-Length" field exists - the method will only replace the existing value with the new value + * - If the "Content-Length" field doesn't exist - the method will create this field and put the value in it. + * Here are also 2 cases: + * - If prevFieldName is specified - the new "Content-Length" field will be created after it + * - If prevFieldName isn't specified or doesn't exist - the new "Content-Length" field will be created as the + * last field before end-of-header field + * + * @param[in] contentLength The content length value to set + * @param[in] prevFieldName Optional parameter, if specified and "Content-Length" field doesn't exist, it will + * be created after this field + * @return A pointer to the "Content-Length" field, or nullptr if creation failed + */ + HeaderField* setContentLength(int contentLength, const std::string& prevFieldName = ""); + + // Overridden methods + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelSesionLayer; + } + + /** + * Currently identifies only SDP if content-length field exists and set to a value greater than zero. + * If content-length field doesn't exist or set to zero and still there is data after this layer, a PayloadLayer + * will be created + */ + void parseNextLayer(); + + /** + * Set the content-length only if a content-length field already exists and if its current value is different + * than the total length of the next layer(s) + */ + void computeCalculateFields(); + + /** + * A static method that checks whether the port is considered as SIP + * @param[in] port The port number to be checked + */ + static bool isSipPort(uint16_t port) + { + return port == 5060 || port == 5061; + } + + protected: + SipLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, ProtocolType protocol) + : TextBasedProtocolMessage(data, dataLen, prevLayer, packet, protocol) + {} + SipLayer() : TextBasedProtocolMessage() + {} + SipLayer(const SipLayer& other) : TextBasedProtocolMessage(other) + {} + SipLayer& operator=(const SipLayer& other) + { + TextBasedProtocolMessage::operator=(other); + return *this; + } + + // implementation of abstract methods + char getHeaderFieldNameValueSeparator() const + { + return ':'; + } + bool spacesAllowedBetweenHeaderFieldNameAndValue() const + { + return true; + } + }; + + class SipRequestFirstLine; + + /** + * @class SipRequestLayer + * Represents a SIP request header and inherits all basic functionality of SipLayer and TextBasedProtocolMessage. + * The functionality that is added for this class is the SIP first line concept. A SIP request has the following + * first line: INVITE sip:bla@bla.com:12345 SIP/2.0 Since it's not an "ordinary" header field, it requires a + * special treatment and gets a class of it's own: SipRequestFirstLine. In most cases a SIP request will be + * contained in a single packet but for cases it is not, only the first packet will be identified as SIP request + * layer. You can find out whether the header is complete by using SipLayer#isHeaderComplete() + */ + class SipRequestLayer : public SipLayer + { + friend class SipRequestFirstLine; + + public: + /** + * SIP request methods + */ + enum SipMethod + { + /** INVITE */ + SipINVITE, + /** ACK */ + SipACK, + /** BYE */ + SipBYE, + /** CANCEL */ + SipCANCEL, + /** REFISTER */ + SipREGISTER, + /** PRACK */ + SipPRACK, + /** OPTIONS */ + SipOPTIONS, + /** SUBSCRIBE */ + SipSUBSCRIBE, + /** NOTIFY */ + SipNOTIFY, + /** PUBLISH */ + SipPUBLISH, + /** INFO */ + SipINFO, + /** REFER */ + SipREFER, + /** MESSAGE */ + SipMESSAGE, + /** UPDATE */ + SipUPDATE, + /** Unknown SIP method */ + SipMethodUnknown + }; + + /** A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + SipRequestLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + /** + * A constructor that allocates a new SIP request with only the first line filled. The request will be created + * without further fields. The user can then add fields using addField() or insertField() methods + * @param[in] method The SIP method to be used in this SIP request + * @param[in] requestUri The URI of the request + * @param[in] version SIP version to be used in this request. Default is "SIP/2.0" + */ + SipRequestLayer(SipMethod method, const std::string& requestUri, const std::string& version = "SIP/2.0"); + + ~SipRequestLayer(); + + /** + * A copy constructor for this layer. Inherits base copy constructor SipLayer and adds the functionality + * of copying the first line + * @param[in] other The instance to copy from + */ + SipRequestLayer(const SipRequestLayer& other); + + /** + * An assignment operator overload for this layer. This method inherits base assignment operator + * SipLayer#operator=() and adds the functionality of copying the first line + * @param[in] other The instance to copy from + */ + SipRequestLayer& operator=(const SipRequestLayer& other); + + /** + * @return A pointer to the first line instance for this message + */ + SipRequestFirstLine* getFirstLine() const + { + return m_FirstLine; + } + + // implement Layer's abstract methods + + std::string toString() const; + + private: + SipRequestFirstLine* m_FirstLine; + }; + + class SipResponseFirstLine; + + /** + * @class SipResponseLayer + * Represents an SIP response message and inherits all basic functionality of SipLayer and TextBasedProtocolMessage. + * The functionality that is added for this class is the SIP first line concept. A SIP response has the following + * first line: 200 OK SIP/2.0 Since it's not an "ordinary" header field, it requires a special treatment and + * gets a class of it's own: SipResponseFirstLine. In most cases a SIP response will be contained in a single packet + * but for cases it is not, only the first packet will be identified as SIP response layer. You can find out whether + * the header is complete by using SipLayer#isHeaderComplete() + */ + class SipResponseLayer : public SipLayer + { + friend class SipResponseFirstLine; + + public: + /** + * Enum for SIP response status codes. List is taken from Wikipedia: + * https://en.wikipedia.org/wiki/List_of_SIP_response_codes + */ + enum SipResponseStatusCode + { + /** Extended search being performed may take a significant time so a forking proxy must send a 100 Trying + * response */ + Sip100Trying, + /** Destination user agent received INVITE, and is alerting user of call */ + Sip180Ringing, + /** Servers can optionally send this response to indicate a call is being forwarded */ + Sip181CallisBeingForwarded, + /** Indicates that the destination was temporarily unavailable, so the server has queued the call until the + * destination is available. A server may send multiple 182 responses to update progress of the queue */ + Sip182Queued, + /** This response may be used to send extra information for a call which is still being set up */ + Sip183SessioninProgress, + /** Can be used by User Agent Server to indicate to upstream SIP entities (including the User Agent Client + * (UAC)) that an early dialog has been terminated */ + Sip199EarlyDialogTerminated, + /** Indicates the request was successful */ + Sip200OK, + /** Indicates that the request has been accepted for processing, but the processing has not been completed + */ + Sip202Accepted, + /** Indicates the request was successful, but the corresponding response will not be received */ + Sip204NoNotification, + /** The address resolved to one of several options for the user or client to choose between, which are + * listed in the message body or the message's Contact fields */ + Sip300MultipleChoices, + /** The original Request-URI is no longer valid, the new address is given in the Contact header field, and + * the client should update any records of the original Request-URI with the new value */ + Sip301MovedPermanently, + /** The client should try at the address in the Contact field. If an Expires field is present, the client + * may cache the result for that period of time */ + Sip302MovedTemporarily, + /** The Contact field details a proxy that must be used to access the requested destination */ + Sip305UseProxy, + /** The call failed, but alternatives are detailed in the message body */ + Sip380AlternativeService, + /** The request could not be understood due to malformed syntax */ + Sip400BadRequest, + /** The request requires user authentication. This response is issued by UASs and registrars */ + Sip401Unauthorized, + /** Reserved for future use */ + Sip402PaymentRequired, + /** The server understood the request, but is refusing to fulfill it */ + Sip403Forbidden, + /** The server has definitive information that the user does not exist at the domain specified in the + * Request-URI. This status is also returned if the domain in the Request-URI does not match any of the + * domains handled by the recipient of the request */ + Sip404NotFound, + /** The method specified in the Request-Line is understood, but not allowed for the address identified by + * the Request-URI */ + Sip405MethodNotAllowed, + /** The resource identified by the request is only capable of generating response entities that have content + * characteristics but not acceptable according to the Accept header field sent in the request */ + Sip406NotAcceptable, + /** The request requires user authentication. This response is issued by proxies */ + Sip407ProxyAuthenticationRequired, + /** Couldn't find the user in time. The server could not produce a response within a suitable amount of + * time, for example, if it could not determine the location of the user in time. The client MAY repeat the + * request without modifications at any later time */ + Sip408RequestTimeout, + /** User already registered */ + Sip409Conflict, + /** The user existed once, but is not available here any more */ + Sip410Gone, + /** The server will not accept the request without a valid Content-Length */ + Sip411LengthRequired, + /** The given precondition has not been met */ + Sip412ConditionalRequestFailed, + /** Request body too large */ + Sip413RequestEntityTooLarge, + /** The server is refusing to service the request because the Request-URI is longer than the server is + * willing to interpret */ + Sip414RequestURITooLong, + /** Request body in a format not supported */ + Sip415UnsupportedMediaType, + /** Request-URI is unknown to the server */ + Sip416UnsupportedURIScheme, + /** There was a resource-priority option tag, but no Resource-Priority header */ + Sip417UnknownResourcePriority, + /** Bad SIP Protocol Extension used, not understood by the server */ + Sip420BadExtension, + /** The server needs a specific extension not listed in the Supported header */ + Sip421ExtensionRequired, + /** The received request contains a Session-Expires header field with a duration below the minimum timer */ + Sip422SessionIntervalTooSmall, + /** Expiration time of the resource is too short */ + Sip423IntervalTooBrief, + /** The request's location content was malformed or otherwise unsatisfactory */ + Sip424BadLocationInformation, + /** The server rejected a non-interactive emergency call, indicating that the request was malformed enough + * that no reasonable emergency response to the alert can be determined */ + Sip425BadAlertMessage, + /** The server policy requires an Identity header, and one has not been provided */ + Sip428UseIdentityHeader, + /** The server did not receive a valid Referred-By token on the request */ + Sip429ProvideReferrerIdentity, + /** A specific flow to a user agent has failed, although other flows may succeed. This response is intended + * for use between proxy devices, and should not be seen by an endpoint (and if it is seen by one, should be + * treated as a 400 Bad Request response) */ + Sip430FlowFailed, + /** The request has been rejected because it was anonymous */ + Sip433AnonymityDisallowed, + /** The request has an Identity-Info header, and the URI scheme in that header cannot be dereferenced */ + Sip436BadIdentityInfo, + /** The server was unable to validate a certificate for the domain that signed the request */ + Sip437UnsupportedCertificate, + /** The server obtained a valid certificate that the request claimed was used to sign the request, but was + * unable to verify that signature */ + Sip438InvalidIdentityHeader, + /** The first outbound proxy the user is attempting to register through does not support the "outbound" + * feature of RFC 5626, although the registrar does */ + Sip439FirstHopLacksOutboundSupport, + /** If a SIP proxy determines a response context has insufficient Incoming Max-Breadth to carry out a + * desired parallel fork, and the proxy is unwilling/unable to compensate by forking serially or sending a + * redirect, that proxy MUST return a 440 response. A client receiving a 440 response can infer that its + * request did not reach all possible destinations */ + Sip440MaxBreadthExceeded, + /** If a SIP UA receives an INFO request associated with an Info Package that the UA has not indicated + * willingness to receive, the UA MUST send a 469 response, which contains a Recv-Info header field with + * Info Packages for which the UA is willing to receive INFO requests */ + Sip469BadInfoPackage, + /** The source of the request did not have the permission of the recipient to make such a request */ + Sip470ConsentNeeded, + /** Callee currently unavailable */ + Sip480TemporarilyUnavailable, + /** Server received a request that does not match any dialog or transaction */ + Sip481Call_TransactionDoesNotExist, + /** Server has detected a loop */ + Sip482LoopDetected, + /** Max-Forwards header has reached the value '0' */ + Sip483TooManyHops, + /** Request-URI incomplete */ + Sip484AddressIncomplete, + /** Request-URI is ambiguous */ + Sip485Ambiguous, + /** Callee is busy */ + Sip486BusyHere, + /** Request has terminated by bye or cancel */ + Sip487RequestTerminated, + /** Some aspect of the session description or the Request-URI is not acceptable */ + Sip488NotAcceptableHere, + /** The server did not understand an event package specified in an Event header field */ + Sip489BadEvent, + /** Server has some pending request from the same dialog */ + Sip491RequestPending, + /** Request contains an encrypted MIME body, which recipient can not decrypt */ + Sip493Undecipherable, + /** The server has received a request that requires a negotiated security mechanism, and the response + * contains a list of suitable security mechanisms for the requester to choose between, or a digest + * authentication challenge */ + Sip494SecurityAgreementRequired, + /** The server could not fulfill the request due to some unexpected condition */ + Sip500ServerInternalError, + /** The server does not have the ability to fulfill the request, such as because it does not recognize the + * request method. (Compare with 405 Method Not Allowed, where the server recognizes the method but does not + * allow or support it.) */ + Sip501NotImplemented, + /** The server is acting as a gateway or proxy, and received an invalid response from a downstream server + * while attempting to fulfill the request */ + Sip502BadGateway, + /** The server is undergoing maintenance or is temporarily overloaded and so cannot process the request. A + * "Retry-After" header field may specify when the client may reattempt its request */ + Sip503ServiceUnavailable, + /** The server attempted to access another server in attempting to process the request, and did not receive + * a prompt response */ + Sip504ServerTimeout, + /** The SIP protocol version in the request is not supported by the server */ + Sip505VersionNotSupported, + /** The request message length is longer than the server can process */ + Sip513MessageTooLarge, + /** The server does not support the push notification service identified in a 'pn-provider' SIP URI + * parameter */ + Sip555PushNotificationServiceNotSupported, + /** The server is unable or unwilling to meet some constraints specified in the offer */ + Sip580PreconditionFailure, + /** All possible destinations are busy. Unlike the 486 response, this response indicates the destination + * knows there are no alternative destinations (such as a voicemail server) able to accept the call */ + Sip600BusyEverywhere, + /** The destination does not wish to participate in the call, or cannot do so, and additionally the + * destination knows there are no alternative destinations (such as a voicemail server) willing to accept + * the call */ + Sip603Decline, + /** The server has authoritative information that the requested user does not exist anywhere */ + Sip604DoesNotExistAnywhere, + /** The user's agent was contacted successfully but some aspects of the session description such as the + * requested media, bandwidth, or addressing style were not acceptable */ + Sip606NotAcceptable, + /** The called party did not want this call from the calling party. Future attempts from the calling party + * are likely to be similarly rejected */ + Sip607Unwanted, + /** An intermediary machine or process rejected the call attempt */ + Sip608Rejected, + /** Unknown SIP status code */ + SipStatusCodeUnknown + }; + + /** A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + SipResponseLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + /** + * A constructor that allocates a new SIP response with only the first line filled. The request will be created + * without further fields. The user can then add fields using addField() or insertField() methods + * @param[in] statusCode SIP status code to set + * @param[in] statusCodeString Most status codes have their default string, e.g 200 is usually "OK" etc. + * But the user can set a non-default status code string and it will be written in the header first line. Empty + * string ("") means using the default status code string. Also, the default is using the default status code + * string + * @param[in] sipVersion SIP version to set, default is SIP/2.0 + * + */ + explicit SipResponseLayer(SipResponseLayer::SipResponseStatusCode statusCode, std::string statusCodeString = "", + const std::string& sipVersion = "SIP/2.0"); + + virtual ~SipResponseLayer(); + + /** + * A copy constructor for this layer. This copy constructor inherits base copy constructor SipLayer and adds the + * functionality of copying the first line as well + * @param[in] other The instance to copy from + */ + SipResponseLayer(const SipResponseLayer& other); + + /** + * An assignment operator overload for this layer. This method inherits base assignment operator + * SipLayer#operator=() and adds the functionality of copying the first line as well + * @param[in] other The instance to copy from + */ + SipResponseLayer& operator=(const SipResponseLayer& other); + + /** + * @return A pointer to the first line instance for this message + */ + SipResponseFirstLine* getFirstLine() const + { + return m_FirstLine; + } + + // implement Layer's abstract methods + + std::string toString() const; + + private: + SipResponseFirstLine* m_FirstLine; + }; + + /** + * @class SipRequestFirstLine + * Represents an SIP request first line. The first line includes 3 parameters: SIP method (e.g INVITE, ACK, BYE, + * etc.), URI (e.g sip:bla@bla.com:12345) and SIP version (usually SIP/2.0). All these parameters are included in + * this class, and the user can retrieve or set them. This class cannot be instantiated by users, it's created + * inside SipRequestLayer and user can get a pointer to an instance of it. All "getters" of this class retrieve the + * actual data of the SIP request and the "setters" actually change the packet data. Since SIP is a textual + * protocol, most fields aren't of fixed size and this also applies to the first line parameters. So many "setter" + * methods of this class may need to shorten or extend the data in SipRequestLayer. These methods will return a + * false value if this action failed + */ + class SipRequestFirstLine + { + friend class SipRequestLayer; + + public: + /** + * @return The SIP request method + */ + SipRequestLayer::SipMethod getMethod() const + { + return m_Method; + } + + /** + * Set the SIP request method + * @param[in] newMethod The method to set + * @return False if newMethod is SipRequestLayer#SipMethodUnknown or if shortening/extending the SipRequestLayer + * data failed. True otherwise + */ + bool setMethod(SipRequestLayer::SipMethod newMethod); + + /** + * @return A copied version of the URI (notice changing the return value won't change the actual data of the + * packet) + */ + std::string getUri() const; + + /** + * Set the URI + * @param[in] newUri The URI to set + * @return False if shortening/extending the SipRequestLayer data failed. True otherwise + */ + bool setUri(const std::string& newUri); + + /** + * @return The SIP version + */ + std::string getVersion() const + { + return m_Version; + } + + /** + * A static method for parsing the SIP method out of raw data + * @param[in] data The raw data + * @param[in] dataLen The raw data length + * @return The parsed SIP method + */ + static SipRequestLayer::SipMethod parseMethod(const char* data, size_t dataLen); + + /** + * @return The size in bytes of the SIP request first line + */ + int getSize() const + { + return m_FirstLineEndOffset; + } + + /** + * As explained in SipRequestLayer, a SIP message can sometimes spread over more than 1 packet, so when looking + * at a single packet the header can be partial. Same goes for the first line - it can spread over more than 1 + * packet. This method returns an indication whether the first line is partial + * @return False if the first line is partial, true if it's complete + */ + bool isComplete() const + { + return m_IsComplete; + } + + /** + * @class SipRequestFirstLineException + * This exception can be thrown while constructing SipRequestFirstLine (the constructor is private, so the + * construction happens only in SipRequestLayer). This kind of exception is thrown if trying to construct with + * SIP method of SipRequestLayer#SipMethodUnknown or with empty SIP version + */ + class SipRequestFirstLineException : public std::exception + { + public: + ~SipRequestFirstLineException() noexcept + {} + void setMessage(const std::string& message) + { + m_Message = message; + } + virtual const char* what() const noexcept + { + return m_Message.c_str(); + } + + private: + std::string m_Message; + }; + + private: + SipRequestFirstLine(SipRequestLayer* sipRequest); + SipRequestFirstLine(SipRequestLayer* sipRequest, SipRequestLayer::SipMethod method, const std::string& version, + const std::string& uri); + + void parseVersion(); + + SipRequestLayer* m_SipRequest; + SipRequestLayer::SipMethod m_Method; + std::string m_Version; + int m_VersionOffset; + int m_UriOffset; + int m_FirstLineEndOffset; + bool m_IsComplete; + SipRequestFirstLineException m_Exception; + }; + + /** + * @class SipResponseFirstLine + * Represents an SIP response message first line. The first line includes 2 parameters: status code (e.g 100 Trying + * ,200 OK, etc.), and SIP version (usually SIP/2.0). These 2 parameters are included in this class, and the user + * can retrieve or set them. This class cannot be instantiated by users, it's created inside SipResponseLayer and + * user can get a pointer to an instance of it. The "getter" methods of this class will retrieve the actual data of + * the SIP response and the "setter" methods will change the packet data. Since SIP is a textual protocol, most + * fields aren't of fixed size and this also applies to the first line parameters. So most "setter" methods of this + * class may need to shorten or extend the data in SipResponseLayer. These methods will return a false value if this + * action failed + */ + class SipResponseFirstLine + { + friend class SipResponseLayer; + + public: + /** + * @return The status code as SipResponseLayer#SipResponseStatusCode enum + */ + SipResponseLayer::SipResponseStatusCode getStatusCode() const + { + return m_StatusCode; + } + + /** + * @return The status code number as integer (e.g 200, 100, etc.) + */ + int getStatusCodeAsInt() const; + + /** + * @return The status code message (e.g "OK", "Trying", etc.) + */ + std::string getStatusCodeString() const; + + /** + * Set the status code + * @param[in] newStatusCode The new status code to set + * @param[in] statusCodeString An optional parameter: set a non-default status code message (e.g "Bla Bla" + * instead of "Not Found"). If this parameter isn't supplied or supplied as empty string (""), the default + * message for the status code will be set + */ + bool setStatusCode(SipResponseLayer::SipResponseStatusCode newStatusCode, std::string statusCodeString = ""); + + /** + * @return The SIP version + */ + std::string getVersion() const + { + return m_Version; + } + + /** + * Set the SIP version. The version to set is expected to be in the format of SIP/x.y otherwise an error will be + * written to log + * @param[in] newVersion The SIP version to set + */ + void setVersion(const std::string& newVersion); + + /** + * A static method for parsing the SIP status code out of raw data + * @param[in] data The raw data + * @param[in] dataLen The raw data length + * @return The parsed SIP status code as enum + */ + static SipResponseLayer::SipResponseStatusCode parseStatusCode(const char* data, size_t dataLen); + + /** + * A static method for parsing the SIP version out of raw data + * @param[in] data The raw data + * @param[in] dataLen The raw data length + * @return The parsed SIP version string or an empty string if version cannot be extracted + */ + static std::string parseVersion(const char* data, size_t dataLen); + + /** + * @return The size in bytes of the SIP response first line + */ + int getSize() const + { + return m_FirstLineEndOffset; + } + + /** + * As explained in SipResponseLayer, A SIP message can sometimes spread over more than 1 packet, so when looking + * at a single packet the header can be partial. Same goes for the first line - it can spread over more than 1 + * packet. This method returns an indication whether the first line is partial + * @return False if the first line is partial, true if it's complete + */ + bool isComplete() const + { + return m_IsComplete; + } + + /** + * @class SipResponseFirstLineException + * This exception can be thrown while constructing SipResponseFirstLine (the constructor is private, so the + * construction happens only in SipResponseLayer). This kind of exception will be thrown if trying to construct + * with SIP status code of SipResponseLayer#SipStatusCodeUnknown or with an empty SIP version + */ + class SipResponseFirstLineException : public std::exception + { + public: + ~SipResponseFirstLineException() noexcept + {} + void setMessage(const std::string& message) + { + m_Message = message; + } + virtual const char* what() const noexcept + { + return m_Message.c_str(); + } + + private: + std::string m_Message; + }; + + private: + SipResponseFirstLine(SipResponseLayer* sipResponse); + SipResponseFirstLine(SipResponseLayer* sipResponse, const std::string& version, + SipResponseLayer::SipResponseStatusCode statusCode, std::string statusCodeString = ""); + + SipResponseLayer* m_SipResponse; + std::string m_Version; + SipResponseLayer::SipResponseStatusCode m_StatusCode; + int m_FirstLineEndOffset; + bool m_IsComplete; + SipResponseFirstLineException m_Exception; + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/Sll2Layer.h b/Packet++/header/pcapplusplus/Sll2Layer.h new file mode 100644 index 0000000000..d717c4141d --- /dev/null +++ b/Packet++/header/pcapplusplus/Sll2Layer.h @@ -0,0 +1,201 @@ +#pragma once + +#include "pcapplusplus/MacAddress.h" +#include "pcapplusplus/Layer.h" + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + /** + * @struct sll2_header + * Represents SLL2 header + */ +#pragma pack(push, 1) + struct sll2_header + { + /** Contains an Ethernet protocol type of the next layer */ + uint16_t protocol_type; + /** The "Reserved (MBZ)" field is reserved, and must be set to zero */ + uint16_t reserved; + /** The interface index field is a signed integer in network byte + * order and contains the 1-based index of the interface on which the packet was observed + **/ + uint32_t interface_index; + /** Contains a Linux ARPHRD_ value for the link-layer device type */ + uint16_t ARPHRD_type; + /** Specifies whether packet was: specifically sent to us by somebody else (value=0); + * broadcast by somebody else (value=1); multicast, but not broadcast, by somebody else (value=2); + * sent to somebody else by somebody else (value=3); sent by us (value=4) + **/ + uint8_t packet_type; + /** Contains the length of the link-layer address of the sender of the packet. That length could be zero */ + uint8_t link_layer_addr_len; + /** Contains the link-layer address of the sender of the packet; the number of bytes of that field that are + * meaningful is specified by the link-layer address length field + **/ + uint8_t link_layer_addr[8]; + }; +#pragma pack(pop) + + /** + * @class Sll2Layer + * Represents an SLL2 (Linux cooked capture) protocol layer + */ + class Sll2Layer : public Layer + { + public: + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data (will be casted to ether_header) + * @param[in] dataLen Size of the data in bytes + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + Sll2Layer(uint8_t* data, size_t dataLen, Packet* packet) : Layer(data, dataLen, nullptr, packet, SLL2) + {} + + /** + * A constructor that creates a new SLL2 header and allocates the data + * @param[in] interfaceIndex The interface index + * @param[in] ARPHRDType The ARPHRD type + * @param[in] packetType The packet type + */ + Sll2Layer(uint32_t interfaceIndex, uint16_t ARPHRDType, uint8_t packetType); + + ~Sll2Layer() + {} + + /** + * Get a pointer to the Sll header. Notice this points directly to the data, so every change will change the + * actual packet data + * @return A pointer to the sll2_header + */ + sll2_header* getSll2Header() const + { + return (sll2_header*)m_Data; + } + + /** + * A static method that validates the input data + * @param[in] data The pointer to the beginning of a byte stream of an IEEE 802.3 Eth packet + * @param[in] dataLen The length of the byte stream + * @return True if the data is valid and can represent an IEEE 802.3 Eth packet + */ + static bool isDataValid(const uint8_t* data, size_t dataLen); + + /** + * Get a protocol type of this layer + * @return protocol type + */ + uint16_t getProtocolType() const; + + /** + * Set protocol type of this layer + * @param[in] protocolType type to set + */ + void setProtocolType(uint16_t protocolType); + + /** + * Get interface index of this layer + * @return interface index + */ + uint32_t getInterfaceIndex() const; + + /** + * Set interface index of this layer + * @param[in] interfaceIndex interface index to set + */ + void setInterfaceIndex(uint32_t interfaceIndex); + + /** + * Get arphrd type of this layer + * @return arphrd type + */ + uint16_t getArphrdType() const; + + /** + * Set arphrd type of this layer + * @param[in] arphrdType arphrd type to set + */ + void setArphrdType(uint16_t arphrdType); + + /** + * Get packet type of this layer + * @return packet type + */ + uint8_t getPacketType() const; + + /** + * Set packet type of this layer + * @param[in] packetType packet type to set + */ + void setPacketType(uint8_t packetType); + + /** + * Get link layer address length + * @return link layer address length + */ + uint8_t getLinkLayerAddrLen() const; + + /** + * Get link layer address data pointer + * @return link layer address data pointer + */ + const uint8_t* getLinkLayerAddr() const; + + /** + * A setter for the link layer address field + * @param[in] addr The address to set. Memory will be copied to packet + * @param[in] addrLength Address length, must be lower or equal to 8 (which is max length for SLL2 address) + * @return True if address was set successfully, or false of addrLength is out of bounds (0 or larger than 8) + */ + bool setLinkLayerAddr(const uint8_t* addr, size_t addrLength); + + /** + * Get a MAC address in the link layer address field + * @return return macAddress pointer was set successfully, null pointer if d MAC address isn't valid or if set + * failed + */ + MacAddress getLinkLayerAsMacAddress(); + + /** + * Set a MAC address in the link layer address field + * @param[in] macAddr MAC address to set + * @return True if address was set successfully, false if MAC address isn't valid or if set failed + */ + bool setMacAddressAsLinkLayer(const MacAddress& macAddr); + + // implement abstract methods + + /** + * Currently identifies the following next layers: IPv4Layer, IPv6Layer, ArpLayer, VlanLayer, PPPoESessionLayer, + * PPPoEDiscoveryLayer, MplsLayer. Otherwise sets PayloadLayer + */ + void parseNextLayer(); + + /** + * Calculate the next protocol type for known protocols: IPv4, IPv6, ARP, VLAN + */ + void computeCalculateFields(); + + /** + * @return Size of sll2_header + */ + size_t getHeaderLen() const + { + return sizeof(sll2_header); + } + + std::string toString() const; + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelDataLinkLayer; + } + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/SllLayer.h b/Packet++/header/pcapplusplus/SllLayer.h new file mode 100644 index 0000000000..c1b8d8f8f6 --- /dev/null +++ b/Packet++/header/pcapplusplus/SllLayer.h @@ -0,0 +1,118 @@ +#pragma once + +#include "pcapplusplus/MacAddress.h" +#include "pcapplusplus/Layer.h" + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * @struct sll_header + * Represents SLL header + */ +#pragma pack(push, 1) + struct sll_header + { + /** Specifies whether packet was: specifically sent to us by somebody else (value=0); + * broadcast by somebody else (value=1); multicast, but not broadcast, by somebody else (value=2); + * sent to somebody else by somebody else (value=3); sent by us (value=4) + **/ + uint16_t packet_type; + /** Contains a Linux ARPHRD_ value for the link-layer device type */ + uint16_t ARPHRD_type; + /** Contains the length of the link-layer address of the sender of the packet. That length could be zero */ + uint16_t link_layer_addr_len; + /** contains the link-layer address of the sender of the packet; the number of bytes of that field that are + * meaningful is specified by the link-layer address length field + **/ + uint8_t link_layer_addr[8]; + /** Contains an Ethernet protocol type of the next layer */ + uint16_t protocol_type; + }; +#pragma pack(pop) + + /** + * @class SllLayer + * Represents an SLL (Linux cooked capture) protocol layer + */ + class SllLayer : public Layer + { + public: + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data (will be casted to ether_header) + * @param[in] dataLen Size of the data in bytes + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + SllLayer(uint8_t* data, size_t dataLen, Packet* packet) : Layer(data, dataLen, nullptr, packet, SLL) + {} + + /** + * A constructor that creates a new SLL header and allocates the data + * @param[in] packetType The packet type + * @param[in] ARPHRDType The ARPHRD type + */ + SllLayer(uint16_t packetType, uint16_t ARPHRDType); + + ~SllLayer() + {} + + /** + * Get a pointer to the Sll header. Notice this points directly to the data, so every change will change the + * actual packet data + * @return A pointer to the sll_header + */ + sll_header* getSllHeader() const + { + return (sll_header*)m_Data; + } + + /** + * A setter for the link layer address field + * @param[in] addr The address to set. Memory will be copied to packet + * @param[in] addrLength Address length, must be lower or equal to 8 (which is max length for SLL address) + * @return True if address was set successfully, or false of addrLength is out of bounds (0 or larger than 8) + */ + bool setLinkLayerAddr(uint8_t* addr, size_t addrLength); + + /** + * Set a MAC address in the link layer address field + * @param[in] macAddr MAC address to set + * @return True if address was set successfully, false if MAC address isn't valid or if set failed + */ + bool setMacAddressAsLinkLayer(const MacAddress& macAddr); + + /** + * Currently identifies the following next layers: IPv4Layer, IPv6Layer, ArpLayer, VlanLayer, PPPoESessionLayer, + * PPPoEDiscoveryLayer, MplsLayer. Otherwise sets PayloadLayer + */ + void parseNextLayer(); + + /** + * @return Size of sll_header + */ + size_t getHeaderLen() const + { + return sizeof(sll_header); + } + + /** + * Calculate the next protocol type for known protocols: IPv4, IPv6, ARP, VLAN + */ + void computeCalculateFields(); + + std::string toString() const; + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelDataLinkLayer; + } + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/SmtpLayer.h b/Packet++/header/pcapplusplus/SmtpLayer.h new file mode 100644 index 0000000000..167221d03b --- /dev/null +++ b/Packet++/header/pcapplusplus/SmtpLayer.h @@ -0,0 +1,348 @@ +#ifndef PACKETPP_SMTP_LAYER +#define PACKETPP_SMTP_LAYER + +#include "pcapplusplus/PayloadLayer.h" +#include "pcapplusplus/SingleCommandTextProtocol.h" + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + /** + * Class for general SMTP message + */ + class SmtpLayer : public SingleCommandTextProtocol + { + protected: + SmtpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : SingleCommandTextProtocol(data, dataLen, prevLayer, packet, SMTP) {}; + + SmtpLayer(const std::string& command, const std::string& option) + : SingleCommandTextProtocol(command, option, SMTP) {}; + + public: + /** + * A static method that checks whether the port is considered as SMTP control + * @param[in] port The port number to be checked + * @return True if this an SMTP port (25 or 587) + */ + static bool isSmtpPort(uint16_t port) + { + return port == 25 || port == 587; + } + + // overridden methods + + /// SMTP is the always last so does nothing for this layer + void parseNextLayer() + {} + + /** + * @return Get the size of the layer + */ + size_t getHeaderLen() const + { + return m_DataLen; + } + + /// Does nothing for this layer + void computeCalculateFields() + {} + + /** + * @return The OSI layer level of SMTP (Application Layer). + */ + OsiModelLayer getOsiModelLayer() const + { + return OsiModelApplicationLayer; + } + }; + + /** + * Class for representing the request messages of SMTP Layer + */ + class SmtpRequestLayer : public SmtpLayer + { + public: + /** + * Enum for SMTP command codes + */ + enum class SmtpCommand : uint64_t + { + /// Unknown command + UNK, + /// Starting mail body + DATA = ('D') | ('A' << 8) | ('T' << 16) | ('A' << 24), + /// Initiate conversation + EHLO = ('E') | ('H' << 8) | ('L' << 16) | ('O' << 24), + /// Expand the mailing list + EXPN = ('E') | ('X' << 8) | ('P' << 16) | ('N' << 24), + /// Initiate conversation + HELO = ('H') | ('E' << 8) | ('L' << 16) | ('O' << 24), + /// Ask information + HELP = ('H') | ('E' << 8) | ('L' << 16) | ('P' << 24), + /// Sender indication + MAIL = ('M') | ('A' << 8) | ('I' << 16) | ('L' << 24), + /// No operation + NOOP = ('N') | ('O' << 8) | ('O' << 16) | ('P' << 24), + /// Close conversation + QUIT = ('Q') | ('U' << 8) | ('I' << 16) | ('T' << 24), + /// Receiver indication + RCPT = ('R') | ('C' << 8) | ('P' << 16) | ('T' << 24), + /// Abort transaction + RSET = ('R') | ('S' << 8) | ('E' << 16) | ('T' << 24), + /// Identify user + VRFY = ('V') | ('R' << 8) | ('F' << 16) | ('Y' << 24), + /// Start TLS handshake + STARTTLS = (('S') | ('T' << 8) | ('A' << 16) | ('R' << 24) | + static_cast(('T') | ('T' << 8) | ('L' << 16) | ('S' << 24)) << 32), + /// Reverse the role of sender and receiver + TURN = ('T') | ('U' << 8) | ('R' << 16) | ('N' << 24), + /// Send mail to terminal + SEND = ('S') | ('E' << 8) | ('N' << 16) | ('D' << 24), + /// Send mail to terminal or to mailbox + SOML = ('S') | ('O' << 8) | ('M' << 16) | ('L' << 24), + /// Send mail to terminal and mailbox + SAML = ('S') | ('A' << 8) | ('M' << 16) | ('L' << 24), + /// Authenticate client and server + AUTH = ('A') | ('U' << 8) | ('T' << 16) | ('H' << 24), + /// Reverse the role of sender and receiver + ATRN = ('A') | ('T' << 8) | ('R' << 16) | ('N' << 24), + /// Submit mail contents + BDAT = ('B') | ('D' << 8) | ('A' << 16) | ('T' << 24), + /// Request to start SMTP queue processing + ETRN = ('E') | ('T' << 8) | ('R' << 16) | ('N' << 24), + /// Release status of the channel + XADR = ('X') | ('A' << 8) | ('D' << 16) | ('R' << 24), + /// Release status of the circuit checking facility + XCIR = ('X') | ('C' << 8) | ('I' << 16) | ('R' << 24), + /// Release status of the number of messages in channel queues + XSTA = ('X') | ('S' << 8) | ('T' << 16) | ('A' << 24), + /// Release status of whether a compiled configuration and character set are in use + XGEN = ('X') | ('G' << 8) | ('E' << 16) | ('N' << 24) + }; + + /** A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + SmtpRequestLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : SmtpLayer(data, dataLen, prevLayer, packet) {}; + + /** + * A constructor that creates layer with provided input values + * @param[in] command SMTP command + * @param[in] option Argument of the command + */ + explicit SmtpRequestLayer(const SmtpCommand& command, const std::string& option = "") + : SmtpLayer(getCommandAsString(command), option) {}; + + /** + * Set the command of request message + * @param[in] code Value to set command + * @return True if the operation is successful, false otherwise + */ + bool setCommand(SmtpCommand code); + + /** + * Get the command of request message + * @return Value of the command + */ + SmtpCommand getCommand() const; + + /** + * Get the command of request message as string + * @return Value of the command as string + */ + std::string getCommandString() const; + + /** + * Set the command argument of request message + * @param[in] value Value to set command argument + * @return True if the operation is successful, false otherwise + */ + bool setCommandOption(const std::string& value); + + /** + * Get the command argument of request message + * @param[in] removeEscapeCharacters Whether non-alphanumerical characters should be removed or not + * @return Value of command argument + */ + std::string getCommandOption(bool removeEscapeCharacters = true) const; + + /** + * Convert the command info to readable string + * @param[in] code Command code to convert + * @return Returns the command info as readable string + */ + static std::string getCommandInfo(SmtpCommand code); + + /** + * Convert the command to readable string + * @param[in] code Command code to convert + * @return Returns the command as readable string + */ + static std::string getCommandAsString(SmtpCommand code); + + // overridden methods + + /** + * @return Returns the protocol info as readable string + */ + std::string toString() const; + }; + + /** + * Class for representing the response messages of SMTP Layer + */ + class SmtpResponseLayer : public SmtpLayer + { + public: + /** + * Enum for SMTP response codes + */ + enum class SmtpStatusCode : int + { + /// System status, or system help reply + SYSTEM_STATUS = 211, + /// Help message + HELP_MESSAGE = 214, + /// \ Service ready + SERVICE_READY = 220, + /// \ Service closing transmission channel + SERVICE_CLOSE = 221, + /// Authentication successful + AUTH_SUCCESS = 235, + /// Requested mail action okay, completed + COMPLETED = 250, + /// User not local; will forward to + WILL_FORWARD = 251, + /// Cannot VRFY user, but will accept message and attempt delivery + CANNOT_VERIFY = 252, + /// AUTH input + AUTH_INPUT = 334, + /// Start mail input; end with \.\ + MAIL_INPUT = 354, + /// \ Service not available, closing transmission channel + SERVICE_UNAVAILABLE = 421, + /// A password transition is needed + PASS_NEEDED = 432, + /// Requested mail action not taken: mailbox unavailable (mail busy or temporarily blocked) + MAILBOX_UNAVAILABLE_TEMP = 450, + /// Requested action aborted: local error in processing + ABORT_LOCAL_ERROR = 451, + /// Requested action not taken: insufficient system storage + INSUFFICIENT_STORAGE = 452, + /// Temporary authentication failed + TEMP_AUTH_FAILED = 454, + /// Server unable to accommodate parameters + PARAM_NOT_ACCOMMODATED = 455, + /// Syntax error, command unrecognized + CMD_NOT_RECOGNIZED = 500, + /// Syntax error in parameters or arguments + SYNTAX_ERROR_PARAM = 501, + /// Command not implemented + CMD_NOT_IMPLEMENTED = 502, + /// Bad sequence of commands + CMD_BAD_SEQUENCE = 503, + /// Command parameter not implemented + PARAM_NOT_IMPLEMENTED = 504, + /// Server does not accept mail + MAIL_NOT_ACCEPTED = 521, + /// Encryption needed + ENCRYPT_NEED = 523, + /// Authentication required + AUTH_REQUIRED = 530, + /// Authentication mechanism is too weak + AUTH_TOO_WEAK = 534, + /// Authentication credentials invalid + AUTH_CRED_INVALID = 535, + /// Encryption required for requested authentication mechanism + ENCRYPT_REQUIRED = 538, + /// Requested action not taken: mailbox unavailable + MAILBOX_UNAVAILABLE = 550, + /// User not local; please try + USER_NOT_LOCAL = 551, + /// Requested mail action aborted: exceeded storage allocation + EXCEED_STORAGE = 552, + /// Requested action not taken: mailbox name not allowed + NAME_NOT_ALLOWED = 553, + /// Transaction failed + TRANSACTION_FAIL = 554, + /// Domain does not accept mail + DOMAIN_NOT_ACCEPT = 556 + }; + + /** A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + SmtpResponseLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : SmtpLayer(data, dataLen, prevLayer, packet) {}; + + /** + * A constructor that creates layer with provided input values + * @param[in] code Status code + * @param[in] option Argument of the status code + */ + explicit SmtpResponseLayer(const SmtpStatusCode& code, const std::string& option = "") + : SmtpLayer(std::to_string(int(code)), option) {}; + + /** + * Set the status code of response message + * @param[in] code Value to set status code + * @return True if the operation is successful, false otherwise + */ + bool setStatusCode(SmtpStatusCode code); + + /** + * Get the status code of response message + * @return Value of the status code + */ + SmtpStatusCode getStatusCode() const; + + /** + * Get the status code of response message as string + * @return Value of the status code as string + */ + std::string getStatusCodeString() const; + + /** + * Set the argument of response message + * @param[in] value Value to set argument + * @return True if the operation is successful, false otherwise + */ + bool setStatusOption(const std::string& value); + + /** + * Get the argument of response message + * @param[in] removeEscapeCharacters Whether non-alphanumerical characters should be removed or not + * @return Value of argument + */ + std::string getStatusOption(bool removeEscapeCharacters = true) const; + + /** + * Convert the status code to readable string + * @param[in] code Status code to convert + * @return Returns the status info as readable string + */ + static std::string getStatusCodeAsString(SmtpStatusCode code); + + // overridden methods + + /** + * @return Returns the protocol info as readable string + */ + std::string toString() const; + }; +} // namespace pcpp + +#endif /* PACKETPP_SMTP_LAYER */ diff --git a/Packet++/header/pcapplusplus/SomeIpLayer.h b/Packet++/header/pcapplusplus/SomeIpLayer.h new file mode 100644 index 0000000000..6b9f9632c0 --- /dev/null +++ b/Packet++/header/pcapplusplus/SomeIpLayer.h @@ -0,0 +1,488 @@ +#pragma once + +#include "pcapplusplus/Layer.h" +#include + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * @class SomeIpLayer + * Represents a SOME/IP protocol layer + */ + class SomeIpLayer : public Layer + { + public: + /** + * SOME/IP message types + */ + enum class MsgType : uint8_t + { + /** A request expecting a response (even void) */ + REQUEST = 0x00, + /** Acknowledgment for REQUEST(optional) */ + REQUEST_ACK = 0x40, + /** A fire&forget request */ + REQUEST_NO_RETURN = 0x01, + /** Acknowledgment for REQUEST_NO_RETURN(informational) */ + REQUEST_NO_RETURN_ACK = 0x41, + /** A request of a notification expecting no response */ + NOTIFICATION = 0x02, + /** Acknowledgment for NOTIFICATION(informational) */ + NOTIFICATION_ACK = 0x42, + /** The response message */ + RESPONSE = 0x80, + /** The Acknowledgment for RESPONSE(informational) */ + RESPONSE_ACK = 0xC0, + /** The response containing an error */ + ERRORS = 0x81, + /** Acknowledgment for ERROR(informational) */ + ERROR_ACK = 0xC1, + /** A TP request expecting a response (even void) */ + TP_REQUEST = 0x20, + /** A TP fire&forget request */ + TP_REQUEST_NO_RETURN = 0x21, + /** A TP request of a notification/event callback expecting no response */ + TP_NOTIFICATION = 0x22, + /** The TP response message */ + TP_RESPONSE = 0xa0, + /** The TP response containing an error */ + TP_ERROR = 0xa1, + }; + + /** + * @struct someiphdr + * Represents a SOME/IP protocol header + */ +#pragma pack(push, 1) + struct someiphdr + { + /** Service ID */ + uint16_t serviceID; + /** Method ID. Most significant bit 0 when E2E communication. 1 when SOME/IP event */ + uint16_t methodID; + /** Length. Also covers payload. Excludes serviceID, methodID and length field itself */ + uint32_t length; + /** Client ID */ + uint16_t clientID; + /** Session ID */ + uint16_t sessionID; + /** Protocol Version */ + uint8_t protocolVersion; + /** Interface Version */ + uint8_t interfaceVersion; + /** Message Type */ + uint8_t msgType; + /** Return Code */ + uint8_t returnCode; + }; +#pragma pack(pop) + + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data (will be casted to someiphdr) + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + SomeIpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : Layer(data, dataLen, prevLayer, packet, SomeIP) + {} + + /** + * Construct a new layer object + * @param[in] serviceID Service ID + * @param[in] methodID Method ID + * @param[in] clientID Client ID + * @param[in] sessionID Session ID + * @param[in] interfaceVersion Interface Version + * @param[in] type Type of the message + * @param[in] returnCode Return Code + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * holds the reference to a data buffer. This option can be used to reduce the number of copies to generate + * packets. + */ + SomeIpLayer(uint16_t serviceID, uint16_t methodID, uint16_t clientID, uint16_t sessionID, + uint8_t interfaceVersion, MsgType type, uint8_t returnCode, const uint8_t* const data = nullptr, + size_t dataLen = 0); + + /** + * Destroy the layer object + */ + ~SomeIpLayer() + {} + + /** + * A static method that creates a SOME/IP or SOME/IP-TP layer from packet raw data. Returns PayloadLayer if data + * is not valid. + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored + * @return Layer* A newly allocated layer + */ + static Layer* parseSomeIpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + /** + * Get a pointer to the basic SOME/IP header. Notice this points directly to the data, so every change will + * change the actual packet data + * @return A pointer to the someiphdr + */ + someiphdr* getSomeIpHeader() const + { + return (someiphdr*)m_Data; + } + + /** + * Checks if given port is a SOME/IP protocol port (only Service Discovery ports are checked for now) + * @param[in] port Port to check + * @return true if SOME/IP protocol port, false if not + */ + static bool isSomeIpPort(uint16_t port); + + /** + * Adds port to a list of ports where pcap checks for SOME/IP communication. + * Each port must be removed at the end in order to have no memory leak. + * @param[in] port Port to add + */ + static void addSomeIpPort(uint16_t port); + + /** + * Removes port from a list of ports where pcap checks for SOME/IP communication. + * @param[in] port Port to remove + */ + static void removeSomeIpPort(uint16_t port); + + /** + * Removes all ports from a list of ports where pcap checks for SOME/IP communication. + */ + static void removeAllSomeIpPorts(); + + /** + * Get the messageID + * @return uint32_t returned in host endian + */ + uint32_t getMessageID() const; + + /** + * Set the Message ID + * @param[in] messageID messageID to set + */ + void setMessageID(uint32_t messageID); + + /** + * Get the serviceID + * @return uint16_t returned in host endian + */ + uint16_t getServiceID() const; + + /** + * Set the Service ID + * @param[in] serviceID serviceID to set + */ + void setServiceID(uint16_t serviceID); + + /** + * Get the methodID + * @return uint16_t returned in host endian + */ + uint16_t getMethodID() const; + + /** + * Set the Method ID + * @param[in] methodID methodID to set + */ + void setMethodID(uint16_t methodID); + + /** + * Get the Length Field of the SOME/IP header + * @return uint32_t The length field of the SOME/IP header + */ + uint32_t getLengthField() const; + + /** + * Get the requestID + * @return uint32_t returned in host endian + */ + uint32_t getRequestID() const; + + /** + * Set the Request ID + * @param[in] requestID requestID to set + */ + void setRequestID(uint32_t requestID); + + /** + * Get the sessionID + * @return uint16_t returned in host endian + */ + uint16_t getSessionID() const; + + /** + * Set the Session ID + * @param[in] sessionID sessionID to set + */ + void setSessionID(uint16_t sessionID); + + /** + * Get the clientID + * @return uint16_t returned in host endian + */ + uint16_t getClientID() const; + + /** + * Set the Client ID + * @param[in] clientID clientID to set + */ + void setClientID(uint16_t clientID); + + /** + * Get the protocolVersion + * @return uint8_t + */ + uint8_t getProtocolVersion() const; + + /** + * Set the Protocol Version + * @param[in] version version to set + */ + void setProtocolVersion(uint8_t version); + + /** + * Get the interfaceVersion + * @return uint8_t + */ + uint8_t getInterfaceVersion() const; + + /** + * Set the Interface Version + * @param[in] version version to set + */ + void setInterfaceVersion(uint8_t version); + + /** + * Get the message type + * @return uint8_t + */ + uint8_t getMessageTypeAsInt() const; + + /** + * Get the message type + * @return SomeIpLayer::MsgType + */ + SomeIpLayer::MsgType getMessageType() const; + + /** + * Set the Message Type + * @param[in] type Type to set + */ + void setMessageType(MsgType type); + + /** + * Set the Message Type + * @param[in] type Type to set + */ + void setMessageType(uint8_t type); + + /** + * Get the returnCode + * @return uint8_t + */ + uint8_t getReturnCode() const; + + /** + * Set the returnCode + * @param[in] returnCode ReturnCode to set + */ + void setReturnCode(uint8_t returnCode); + + /** + * Set the length field of the SOME/IP header + * @param[in] payloadLength Length of the payload + */ + void setPayloadLength(uint32_t payloadLength); + + /** + * @return A pointer for the layer payload, meaning the first byte after the header + */ + uint8_t* getPduPayload() const + { + return m_Data + getSomeIpHeaderLen(); + } + + /** + * @return The size in bytes of the payload + */ + size_t getPduPayloadSize() const + { + return getHeaderLen() - getSomeIpHeaderLen(); + } + + /** + * Get the Length of the SOME/IP header inc payload + * @return size_t + */ + size_t getHeaderLen() const + { + return sizeof(uint32_t) * 2 + getLengthField(); + } + + /** + * Does nothing for this layer + */ + virtual void computeCalculateFields() + {} + + /** + * Identifies the following next layers: SomeIpLayer, SomeIpTpLayer, SomeIpSdLayer. Otherwise sets PayloadLayer + */ + void parseNextLayer(); + + /** + * @return The string representation of the SOME/IP layer + */ + virtual std::string toString() const; + + /** + * @return The OSI model layer of this layer + */ + OsiModelLayer getOsiModelLayer() const + { + return OsiModelApplicationLayer; + } + + protected: + SomeIpLayer() + {} + + private: + static const uint8_t SOMEIP_PROTOCOL_VERSION = 1; + virtual size_t getSomeIpHeaderLen() const + { + return sizeof(someiphdr); + } + + /* Using unordered_set since insertion and search should be almost constant time */ + static std::unordered_set m_SomeIpPorts; + }; + + /** + * @class SomeIpTpLayer + * Represents an SOME/IP Transport Protocol Layer + */ + class SomeIpTpLayer : public SomeIpLayer + { + public: + /** + * @struct someiptphdr + * Represents an SOME/IP-TP protocol header. + */ +#pragma pack(push, 1) + struct someiptphdr : someiphdr + { + /** Contains the offset and the more segments flag. 28 bit offset field measured in 16 bytes + 3 bit + * reserved + 1 bit more segments flag */ + uint32_t offsetAndFlag; + }; +#pragma pack(pop) + + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data (will be casted to @ref someiptphdr) + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + SomeIpTpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : SomeIpLayer(data, dataLen, prevLayer, packet) + {} + + /** + * A constructor that creates empty layer and sets values + * @param[in] serviceID Service ID + * @param[in] methodID Method ID + * @param[in] clientID Client ID + * @param[in] sessionID Session ID + * @param[in] interfaceVersion Interface Version + * @param[in] type Type of the message + * @param[in] returnCode Return Code + * @param[in] offset Offset indicating the data offset in increments of 16 bytes + * @param[in] moreSegmentsFlag Flag indicating whether more SOME/IP-TP Packets will follow + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + */ + SomeIpTpLayer(uint16_t serviceID, uint16_t methodID, uint16_t clientID, uint16_t sessionID, + uint8_t interfaceVersion, MsgType type, uint8_t returnCode, uint32_t offset, + bool moreSegmentsFlag, const uint8_t* const data = nullptr, size_t dataLen = 0); + + /** + * Destroy the layer object + */ + ~SomeIpTpLayer() + {} + + /** + * Get a pointer to the basic SOME/IP-TP header. Notice this points directly to the data, so every change will + * change the actual packet data + * @return A pointer to the @ref someiptphdr + */ + someiptphdr* getSomeIpTpHeader() const + { + return (someiptphdr*)m_Data; + } + + /** + * Get the Offset. Offset is returned in multiple of 16 bytes. + * @return The offset value + */ + uint32_t getOffset() const; + + /** + * Set the Offset. Already has to be in multiples of 16 bytes. + * If 32 bytes have already been transmitted, the offset has to be set to 2. + * @param[in] offset Offset to set. Already has to be in multiples of 16 bytes. + */ + void setOffset(uint32_t offset); + + /** + * Get the More Segments Flag + * @return true if the More Segments Flag is set, false if it is not set + */ + bool getMoreSegmentsFlag() const; + + /** + * Set the More Segments Flag + * @param[in] flag True if the More Segments Flag shall be set, false for resetting + */ + void setMoreSegmentsFlag(bool flag); + + /** + * Sets the message type in this layer with enabling the TP flag + */ + void computeCalculateFields(); + + /** + * @return The string representation of the SOME/IP-TP layer + */ + std::string toString() const; + + private: + static const uint32_t SOMEIP_TP_MORE_FLAG_MASK = 0x01; + static const uint32_t SOMEIP_TP_OFFSET_MASK = 0xFFFFFFF0; + + size_t getSomeIpHeaderLen() const + { + return sizeof(someiptphdr); + } + + static uint8_t setTpFlag(uint8_t messageType); + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/SomeIpSdLayer.h b/Packet++/header/pcapplusplus/SomeIpSdLayer.h new file mode 100644 index 0000000000..cb46ba777f --- /dev/null +++ b/Packet++/header/pcapplusplus/SomeIpSdLayer.h @@ -0,0 +1,791 @@ +#pragma once + +#include "pcapplusplus/IpAddress.h" +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/SomeIpLayer.h" +#include +#include +#include +#include +#include +#include + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + /** + * Types of protocols that can be referenced in SOME/IP-SD + */ + enum SomeIpSdProtocolType : uint8_t + { + /** TCP */ + SD_TCP = 0x06, + /** UDP */ + SD_UDP = 0x11 + }; + + class SomeIpSdLayer; + + /** + * @class SomeIpSdOption + * Base class of the SOME/IP-SD options. Cannot be instantiated. + */ + class SomeIpSdOption + { + public: + friend class SomeIpSdLayer; + + /** + * Types of options currently available for the SOME/IP-SD protocol + */ + enum class OptionType : uint8_t + { + /** Unknown Option Type */ + Unknown = 0x00, + /** Configuration Option */ + ConfigurationString = 0x01, + /** Load Balancing Option */ + LoadBalancing = 0x02, + /** IPv4 Endpoint Option */ + IPv4Endpoint = 0x04, + /** IPv6 Endpoint Option */ + IPv6Endpoint = 0x06, + /** IPv4 Multicast Option */ + IPv4Multicast = 0x14, + /** IPv6 Multicast Option */ + IPv6Multicast = 0x16, + /** IPv4 SD Endpoint Option */ + IPv4SdEndpoint = 0x24, + /** IPv6 SD Endpoint Option */ + IPv6SdEndpoint = 0x26 + }; + + /** + * @struct someipsdhdroptionsbase + * Represents the common base for SOME/IP-SD header options + */ +#pragma pack(push, 1) + struct someipsdhdroptionsbase + { + /** Length - excluding the 16 bit Length field and the 8 bit type flag */ + uint16_t length; + /** Type */ + uint8_t type; + /** Reserved */ + uint8_t reserved; + }; +#pragma pack(pop) + + /** + * Destroy the SOME/IP-SD Option object and delete allocated data if it has been allocated by a constructor + */ + virtual ~SomeIpSdOption(); + + /** + * Get the Option Type + * @return OptionType + */ + OptionType getType() const; + + /** + * Get the Length of the SOME/IP-SD option + * @return size_t + */ + size_t getLength() const + { + return m_DataLen; + } + + /** + * Get the internal data of the SOME/IP-SD Option + * @return uint8_t* + */ + uint8_t* getDataPtr() const; + + /** + * Get a pointer to the SOME/IP-SD Option base header + * @return someipsdhdroptionsbase* + */ + someipsdhdroptionsbase* getSomeIpSdOptionHeader() const; + + protected: + const IDataContainer* m_DataContainer; + size_t m_Offset; + uint8_t* m_ShadowData; + size_t m_DataLen; + + SomeIpSdOption() : m_DataContainer(nullptr), m_Offset(0), m_ShadowData(nullptr), m_DataLen(0) + {} + + SomeIpSdOption(const IDataContainer* dataContainer, size_t offset) + : m_DataContainer(dataContainer), m_Offset(offset), m_ShadowData(nullptr), m_DataLen(0) + {} + + void initStdFields(OptionType type); + + SomeIpSdOption(const SomeIpSdOption&) = delete; + SomeIpSdOption& operator=(const SomeIpSdOption&) = delete; + }; + + /** + * @class SomeIpSdIPv4Option + * Implements the following SOME/IP-SD Options: IPv4 Endpoint, IPv4 Multicast, IPv4 SD Endpoint + */ + class SomeIpSdIPv4Option : public SomeIpSdOption + { + public: + friend class SomeIpSdLayer; + + /** + * Types of options which are implemented with this class + */ + enum IPv4OptionType + { + /** IPv4 Endpoint Option */ + IPv4Endpoint, + /** IPv4 Multicast Option */ + IPv4Multicast, + /** IPv4 SD Endpoint Option */ + IPv4SdEndpoint, + }; + + /** + * Construct a new SomeIpSdIPv4 Option object + * @param[in] type IPv4 Option type + * @param[in] ipAddress Ipv4 address to use + * @param[in] port Port to use + * @param[in] l4Protocol Protocol to use + */ + SomeIpSdIPv4Option(IPv4OptionType type, IPv4Address ipAddress, uint16_t port, SomeIpSdProtocolType l4Protocol); + + /** + * Construct a new SomeIpSdIPv4 Option object from already existing memory + * @param[in] dataContainer Data containing the SomeIpSdIPv4 Option object + * @param[in] offset Offset for dataContainer + */ + SomeIpSdIPv4Option(const IDataContainer* dataContainer, size_t offset); + + /** + * Get the Ip Address + * @return IPv4Address + */ + IPv4Address getIpAddress() const; + + /** + * Get the Port + * @return uint16_t + */ + uint16_t getPort() const; + + /** + * Get the Protocol + * @return SomeIpSdProtocolType + */ + SomeIpSdProtocolType getProtocol() const; + + private: + /** + * @struct someipsdhdroptionsipv4 + * Represents the IPv4 option types for the SOME/IP-SD header + */ +#pragma pack(push, 1) + struct someipsdhdroptionsipv4 : someipsdhdroptionsbase + { + /* IPv4-Address field */ + uint32_t ipv4Address; + /* Reserved */ + // cppcheck-suppress duplInheritedMember + uint8_t reserved; + /* Layer 4 Protocol field (L4-Proto) - Either UDP or TCP */ + SomeIpSdProtocolType l4Protocol; + /* Port number of UDP or TCP */ + uint16_t portNumber; + }; +#pragma pack(pop) + }; + + /** + * @class SomeIpSdIPv6Option + * Implements the following SOME/IP-SD Options: IPv6 Endpoint, IPv6 Multicast, IPv6 SD Endpoint + */ + class SomeIpSdIPv6Option : public SomeIpSdOption + { + public: + friend class SomeIpSdLayer; + + /** + * Types of options which are implemented with this class + */ + enum IPv6OptionType + { + /** IPv6 Endpoint Option */ + IPv6Endpoint, + /** IPv6 Multicast Option */ + IPv6Multicast, + /** IPv6 SD Endpoint Option */ + IPv6SdEndpoint, + }; + + /** + * Construct a new SomeIpSdIPv6 Option object + * @param[in] type IPv6 Option type + * @param[in] ipAddress Ipv6 address to use + * @param[in] port Port to use + * @param[in] l4Protocol Protocol to use + */ + SomeIpSdIPv6Option(IPv6OptionType type, IPv6Address ipAddress, uint16_t port, SomeIpSdProtocolType l4Protocol); + + /** + * Construct a new SomeIpSdIPv6 Option object from already existing memory + * @param[in] dataContainer Data containing the SomeIpSdIPv6 Option object + * @param[in] offset Offset for dataContainer + */ + SomeIpSdIPv6Option(const IDataContainer* dataContainer, size_t offset); + + /** + * Get the Ip Address + * @return IPv6Address + */ + IPv6Address getIpAddress() const; + + /** + * Get the Port + * @return uint16_t + */ + uint16_t getPort() const; + + /** + * Get the Protocol + * @return SomeIpSdProtocolType + */ + SomeIpSdProtocolType getProtocol() const; + + private: + /** + * @struct someipsdhdroptionsipv6 + * Represents the IPv6 option types for the SOME/IP-SD header + */ +#pragma pack(push, 1) + struct someipsdhdroptionsipv6 : someipsdhdroptionsbase + { + /* IPv6-Address field */ + uint8_t ipv6Address[16]; + /* Reserved */ + // cppcheck-suppress duplInheritedMember + uint8_t reserved; + /* Layer 4 Protocol field (L4-Proto) - Either UDP or TCP */ + SomeIpSdProtocolType l4Protocol; + /* Port number of UDP or TCP */ + uint16_t portNumber; + }; +#pragma pack(pop) + }; + + /** + * @class SomeIpSdConfigurationOption + * Implements the Configuration option of SOME/IP-SD protocol + */ + class SomeIpSdConfigurationOption : public SomeIpSdOption + { + public: + friend class SomeIpSdLayer; + + /** + * Construct a new Configuration Option object + * @param[in] configurationString the configuration string + */ + explicit SomeIpSdConfigurationOption(const std::string& configurationString); + + /** + * Construct a new Configuration Option object from already existing memory + * @param[in] dataContainer Data containing the Configuration Option object + * @param[in] offset Offset for dataContainer + */ + SomeIpSdConfigurationOption(const IDataContainer* dataContainer, size_t offset); + + /** + * Get the configuration string + * @return std::string + */ + std::string getConfigurationString() const; + }; + + /** + * @class SomeIpSdLoadBalancingOption + * Implements the Load Balancing option of SOME/IP-SD protocol + */ + class SomeIpSdLoadBalancingOption : public SomeIpSdOption + { + public: + friend class SomeIpSdLayer; + + /** + * Construct a new Load Balancing object + * @param[in] priority Priority of this instance + * @param[in] weight Weight of this instance + */ + SomeIpSdLoadBalancingOption(uint16_t priority, uint16_t weight); + + /** + * Construct a new Option object from already existing memory + * @param[in] dataContainer Data containing the option object + * @param[in] offset Offset for dataContainer + */ + SomeIpSdLoadBalancingOption(const IDataContainer* dataContainer, size_t offset); + + /** + * Get the priority fild + * @return uint16_t + */ + uint16_t getPriority() const; + + /** + * Get the weight field + * @return uint16_t + */ + uint16_t getWeight() const; + + private: + /** + * @struct someipsdhdroptionsload + * Represents the Load Balancing option header for SOME/IP-SD + */ +#pragma pack(push, 1) + struct someipsdhdroptionsload : someipsdhdroptionsbase + { + /* Priority field */ + uint16_t priority; + /* Weight field */ + uint16_t weight; + }; +#pragma pack(pop) + }; + + /** + * @class SomeIpSdEntry + * Implementation of the SOME/IP-SD Service Entry and Eventgroup Entry Type + */ + class SomeIpSdEntry + { + public: + friend class SomeIpSdLayer; + + /** + * Types of entries that can occur in SOME/IP-SD + */ + enum class EntryType : uint8_t + { + /** Find Service */ + FindService, + /** Offer Service */ + OfferService, + /** Stop Offer Service */ + StopOfferService, + /** Subscribe Eventgroup */ + SubscribeEventgroup, + /** Stop Subscribe Eventgroup */ + StopSubscribeEventgroup, + /** Subscribe Eventgroup Acknowledgment */ + SubscribeEventgroupAck, + /** Subscribe Eventgroup Negative Acknowledgement */ + SubscribeEventgroupNack, + /** Unknown Entry Type */ + UnknownEntryType + }; + + /** + * @struct someipsdhdrentry + * Represents the Service Entry Type and Eventgroup Entry Type + */ +#pragma pack(push, 1) + struct someipsdhdrentry + { + /** Type */ + uint8_t type; + /** Index 1st option */ + uint8_t indexFirstOption; + /** Index 2nd option */ + uint8_t indexSecondOption; +#if (BYTE_ORDER == LITTLE_ENDIAN) + uint8_t + /** Numbers of Option #2 (4bit) */ + nrOpt2 : 4, + /** Numbers of Option #1 (4bit) */ + nrOpt1 : 4; +#else + uint8_t + /** Numbers of Option #1 (4bit) */ + nrOpt1 : 4, + /** Numbers of Option #2 (4bit) */ + nrOpt2 : 4; +#endif + /** Service ID */ + uint16_t serviceID; + /** Instance ID */ + uint16_t instanceID; + /** Major Version (8 bit) + TTL (24 bit) */ + uint32_t majorVersion_ttl; + /** Minor Version (Service Entry Type) or Counter + Eventgroup ID (Eventgroup Entry Type) */ + uint32_t data; + }; +#pragma pack(pop) + + /** + * Construct a new SOME/IP-SD Service Entry Type + * @param[in] type Type to create + * @param[in] serviceID ServiceID to use + * @param[in] instanceID InstanceID to use + * @param[in] majorVersion MajorVersion to use + * @param[in] TTL TTL to use. Has to be 0 for all Stop* entry types + * @param[in] minorVersion MinorVersion to use + */ + SomeIpSdEntry(EntryType type, uint16_t serviceID, uint16_t instanceID, uint8_t majorVersion, uint32_t TTL, + uint32_t minorVersion); + + /** + * Construct a new SOME/IP-SD Eventgroup Entry Type + * @param[in] type Type to create + * @param[in] serviceID ServiceID to use + * @param[in] instanceID InstanceID to use + * @param[in] majorVersion MajorVersion to use + * @param[in] TTL TTL to use. Has to be 0 for all Stop* entry types + * @param[in] counter Counter value to use + * @param[in] eventGroupID EventgroupId to use + */ + SomeIpSdEntry(EntryType type, uint16_t serviceID, uint16_t instanceID, uint8_t majorVersion, uint32_t TTL, + uint8_t counter, uint16_t eventGroupID); + + /** + * Construct a new SomeIpSdEntry object from existing data + * @param[in] pSomeIpSdLayer Layer that this entry is created for + * @param[in] offset Offset for pSomeIpSdLayer + */ + SomeIpSdEntry(const SomeIpSdLayer* pSomeIpSdLayer, size_t offset); + + /** + * Destroy the SomeIpSd Entry object and delete allocated data if it has been allocated by a constructor + */ + ~SomeIpSdEntry(); + + /** + * Get the internal data of the SOME/IP-SD Entry + * @return uint8_t* + */ + uint8_t* getDataPtr() const; + + /** + * Get a pointer to the SOME/IP-SD Entry header + * @return someipsdhdrentry* + */ + someipsdhdrentry* getSomeIpSdEntryHeader() const; + + /** + * Get the Entry Type + * @return EntryType + */ + EntryType getType() const + { + return m_EntryType; + } + + /** + * Get the Length of the SomeIpSd Entry + * @return size_t + */ + size_t getLength() const + { + return sizeof(someipsdhdrentry); + } + + /** + * Get the number of Options of this Entry + * @return uint32_t + */ + uint32_t getNumOptions() const; + + /** + * Get the Service Id in host endianness + * @return uint16_t + */ + uint16_t getServiceId() const; + + /** + * Set the Service Id + * @param[in] serviceId + */ + void setServiceId(uint16_t serviceId); + + /** + * Get the Instance Id in host endianness + * @return uint16_t + */ + uint16_t getInstanceId() const; + + /** + * Set the Instance Id + * @param[in] instanceId + */ + void setInstanceId(uint16_t instanceId); + + /** + * Get the Major version field in host endianness + * @return uint16_t + */ + uint8_t getMajorVersion() const; + + /** + * Set the Major Version + * @param[in] majorVersion + */ + void setMajorVersion(uint8_t majorVersion); + + /** + * Get the Ttl field + * @return uint32_t + */ + uint32_t getTtl() const; + + /** + * Set the Ttl field + * @param[in] ttl + */ + void setTtl(uint32_t ttl); + + /** + * Get the minor version + * @return uint32_t + */ + uint32_t getMinorVersion() const; + + /** + * Set the minor version + * @param[in] minorVersion + */ + void setMinorVersion(uint32_t minorVersion); + + /** + * Get the counter value + * @return uint32_t + */ + uint8_t getCounter() const; + + /** + * Set the counter value + * @param[in] counter + */ + void setCounter(uint8_t counter); + + /** + * Get the eventgroup id + * @return uint32_t + */ + uint16_t getEventgroupId() const; + + /** + * Set the eventgroup id + * @param[in] eventgroupID + */ + void setEventgroupId(uint16_t eventgroupID); + + private: + /** + * These are the entry types used by SOME/IP-SD. They cannot be used for parameter passing since the values + * are not unique. + */ + enum class TypeInternal : uint8_t + { + /** Find Service */ + FindService_Internal = 0x00, + /** Offer Service / Stop Offer Service */ + OfferService_Internal = 0x01, + /** Subscribe Eventgroup & Stop Subscribe Eventgroup */ + SubscribeEventgroup_Internal = 0x06, + /** Subscribe Eventgroup Acknowledgment / Negative Acknowledgement */ + SubscribeEventgroupAck_Internal = 0x07, + }; + + EntryType m_EntryType; + const SomeIpSdLayer* m_Layer; + size_t m_Offset; + uint8_t* m_ShadowData; + + void initStdFields(EntryType type, uint16_t serviceID, uint16_t instanceID, uint8_t majorVersion, uint32_t TTL); + + SomeIpSdEntry(const SomeIpSdEntry&) = delete; + SomeIpSdEntry& operator=(const SomeIpSdEntry&) = delete; + + static const uint32_t SOMEIPSD_HDR_ENTRY_MASK_TTL = 0x00FFFFFF; + }; + + /** + * @class SomeIpSdLayer + * Implementation of the SOME/IP-SD protocol + */ + class SomeIpSdLayer : public SomeIpLayer + { + public: + friend class SomeIpSdEntry; + + typedef SomeIpSdEntry* EntryPtr; + typedef std::vector EntriesVec; + typedef SomeIpSdOption* OptionPtr; + typedef std::vector OptionsVec; + + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + SomeIpSdLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + /** + * Construct a new SomeIpSdLayer object + * @param[in] serviceID Service ID + * @param[in] methodID Method ID + * @param[in] clientID Client ID + * @param[in] sessionID Session ID + * @param[in] interfaceVersion Interface Version + * @param[in] type Type of the message + * @param[in] returnCode Return Code + * @param[in] flags Flags that shall be used in the header + */ + SomeIpSdLayer(uint16_t serviceID, uint16_t methodID, uint16_t clientID, uint16_t sessionID, + uint8_t interfaceVersion, MsgType type, uint8_t returnCode, uint8_t flags); + + /** + * Destroy the layer object + */ + ~SomeIpSdLayer() + {} + + /** + * Checks if given port is a SOME/IP-SD protocol port + * @param[in] port Port to check + * @return true if SOME/IP-SD protocol port, false if not + */ + static bool isSomeIpSdPort(uint16_t port) + { + return port == 30490; + } + + /** + * The static method makes validation of input data + * @param[in] data The pointer to the beginning of byte stream of IP packet + * @param[in] dataLen The length of byte stream + * @return True if the data is valid and can represent the packet + */ + static bool isDataValid(const uint8_t* data, size_t dataLen); + + /** + * Get the Flags of the layer + * @return uint8_t Flags + */ + uint8_t getFlags() const; + + /** + * Set the Flags of the layer + * @param[in] flags Flags to set + */ + void setFlags(uint8_t flags); + + /** + * Get the number of entries in this layer + * @return uint32_t + */ + uint32_t getNumEntries() const; + + /** + * Get the number of options in this layer + * @return uint32_t + */ + uint32_t getNumOptions() const; + + /** + * Get the Entries from this layer + * @return EntriesVec Vector holding pointers to the options + */ + const EntriesVec getEntries() const; + + /** + * Get the Options from this layer + * @return OptionsVec Vector holding pointers to the options + */ + const OptionsVec getOptions() const; + + /** + * Get the Options from a specific Entry + * @param[in] index Index of the Entry, starting with 0. + * @return OptionsVec Vector holding pointers to the options + */ + const OptionsVec getOptionsFromEntry(uint32_t index) const; + + /** + * Adds a given entry to the layer and returns the index of the entry + * @param[in] entry Pointer to the entry that shall be added to the layer + * @return uint32_t Returns the index of the entry starting with 0 + */ + uint32_t addEntry(const SomeIpSdEntry& entry); + + /** + * Adds an option to an entry that has already been added to the layer by using addEntry(). The option + * is also added to the layer itself. If the option cannot by assigned to the entry, the option is not + * copied into the layer. + * @param[in] indexEntry Index of the entry where the option shall be added. First Entry has index 0 + * @param[in] option Pointer to the option that shall be added + * @return True if the option could be assigned to the entry and was copied into the layer, false otherwise + */ + bool addOptionTo(uint32_t indexEntry, const SomeIpSdOption& option); + + /** + * Does nothing for this layer + */ + void computeCalculateFields() {}; + + /** + * @return The string representation of the SOME/IP-SD layer + */ + std::string toString() const; + + private: + /** + * @struct someipsdhdr + * Represents an SOME/IP-SD protocol header + */ +#pragma pack(push, 1) + struct someipsdhdr : someiphdr + { + /** Flags (8 bit) */ + uint8_t flags; + /** Reserved1 field (Bits 0-7 of 24-bits reserved field) */ + uint8_t reserved1; + /** Reserved2 field (Bits 8-15 of 24-bits reserved field) */ + uint8_t reserved2; + /** Reserved3 field (Bits 16-23 of 24-bits reserved field) */ + uint8_t reserved3; + }; +#pragma pack(pop) + + uint32_t m_NumOptions; + + static bool countOptions(uint32_t& count, const uint8_t* data); + uint32_t findOption(const SomeIpSdOption& option); + void addOption(const SomeIpSdOption& option); + bool addOptionIndex(uint32_t indexEntry, uint32_t indexOffset); + OptionPtr parseOption(SomeIpSdOption::OptionType type, size_t offset) const; + + static size_t getLenEntries(const uint8_t* data); + size_t getLenEntries() const; + static size_t getLenOptions(const uint8_t* data); + size_t getLenOptions() const; + void setLenEntries(uint32_t length); + void setLenOptions(uint32_t length); + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/StpLayer.h b/Packet++/header/pcapplusplus/StpLayer.h new file mode 100644 index 0000000000..6ec7a66ce3 --- /dev/null +++ b/Packet++/header/pcapplusplus/StpLayer.h @@ -0,0 +1,902 @@ +#pragma once + +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/MacAddress.h" + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + +/** + * @struct stp_tcn_bpdu + * Represents payload of network changes announcements of BPDU + */ +#pragma pack(push, 1) + struct stp_tcn_bpdu + { + /// Protocol ID. Fixed at 0x0, which represents IEEE 802.1d + uint16_t protoId; + /// Protocol version. 0x0 for STP, 0x2 for RSTP, 0x3 for MSTP + uint8_t version; + /// Type of the BPDU. 0x0 for configuration, 0x2 for RSTP/MSTP, 0x80 for TCN + uint8_t type; + }; +#pragma pack(pop) + + /// Spanning Tree protocol common header + typedef stp_tcn_bpdu stp_header; + +/** + * @struct stp_conf_bpdu + * Represents payload configuration of BPDU for STP + */ +#pragma pack(push, 1) + struct stp_conf_bpdu : stp_tcn_bpdu + { + /// Flag for indicate purpose of BPDU + uint8_t flag; + /// Root bridge ID + uint64_t rootId; + /// Cost of path + uint32_t pathCost; + /// Bridge ID + uint64_t bridgeId; + /// Port ID + uint16_t portId; + /// Age of the BPDU + uint16_t msgAge; + /// Maximum age of the BPDU + uint16_t maxAge; + /// BPDU transmission interval + uint16_t helloTime; + /// Delay for STP + uint16_t forwardDelay; + }; +#pragma pack(pop) + +/** + * @struct rstp_conf_bpdu + * Represents payload configuration of BPDU for Rapid STP (RSTP) + */ +#pragma pack(push, 1) + struct rstp_conf_bpdu : stp_conf_bpdu + { + /// Version1 length. The value is 0x0 + uint8_t version1Len; + }; +#pragma pack(pop) + +/** + * @struct mstp_conf_bpdu + * Represents payload configuration of BPDU for Multiple STP (MSTP) + */ +#pragma pack(push, 1) + struct mstp_conf_bpdu : rstp_conf_bpdu + { + /// Version3 length. + uint16_t version3Len; + /// Configuration id format selector + uint8_t mstConfigFormatSelector; + /// Configuration id name + uint8_t mstConfigName[32]; + /// Configuration id revision + uint16_t mstConfigRevision; + /// Configuration id digest + uint8_t mstConfigDigest[16]; + /// CIST internal root path cost + uint32_t irpc; + /// CIST bridge id + uint64_t cistBridgeId; + /// CIST remaining hop count + uint8_t remainId; + }; +#pragma pack(pop) + +/** + * @struct msti_conf_msg + * Represents MSTI configuration messages. Each message contains 16 bytes and MSTP can contain 0 to 64 MSTI messages. + */ +#pragma pack(push, 1) + struct msti_conf_msg + { + /// MSTI flags + uint8_t flags; + /// Regional root switching id (Priority (4 bits) + ID (12 bits) + Regional root (48 bits - MAC address)) + uint64_t regionalRootId; + /// Total path cost from local port to regional port + uint32_t pathCost; + /// Priority value of switching device + uint8_t bridgePriority; + /// Priority value of port + uint8_t portPriority; + /// Remaining hops of BPDU + uint8_t remainingHops; + }; +#pragma pack(pop) + + /** + * @class StpLayer + * Represents an Spanning Tree Protocol Layer + */ + class StpLayer : public Layer + { + protected: + StpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : Layer(data, dataLen, prevLayer, packet, STP) + {} + + explicit StpLayer(size_t dataLen) + { + m_DataLen = dataLen; + m_Data = new uint8_t[dataLen]; + memset(m_Data, 0, dataLen); + m_Protocol = STP; + } + + static pcpp::MacAddress IDtoMacAddress(uint64_t id); + static uint64_t macAddressToID(const pcpp::MacAddress& addr); + + public: + /// STP protocol uses "01:80:C2:00:00:00" multicast address as destination MAC + static pcpp::MacAddress StpMulticastDstMAC; + /// STP Uplink Fast protocol uses "01:00:0C:CD:CD:CD" as destination MAC + static pcpp::MacAddress StpUplinkFastMulticastDstMAC; + + /** + * Get a pointer to base Spanning tree header + * @return A pointer to spanning tree header + */ + stp_header* getStpHeader() const + { + return (stp_header*)(m_Data); + } + + /** + * Returns the protocol id. Fixed at 0x0 for STP messages which represents IEEE 802.1d + * @return ID of the protocol + */ + uint16_t getProtoId() const + { + return getStpHeader()->protoId; + } + + /** + * Sets the protocol id + * @param[in] value ID of the protocol + */ + void setProtoId(uint16_t value) + { + getStpHeader()->protoId = value; + } + + /** + * Returns the version. Fixed at 0x0 for STP messages + * @return Version number + */ + uint8_t getVersion() const + { + return getStpHeader()->version; + } + + /** + * Sets the version + * @param[in] value Version number + */ + void setVersion(uint8_t value) + { + getStpHeader()->version = value; + } + + /** + * Returns the type of configuration message. + * @return Type of configuration message + */ + uint8_t getType() const + { + return getStpHeader()->type; + } + + /** + * Sets the type of configuration message + * @param[in] value Type of configuration message + */ + void setType(uint8_t value) + { + getStpHeader()->type = value; + } + + // overridden methods + + /** + * @return The size of STP packet + */ + size_t getHeaderLen() const + { + return m_DataLen; + } + + /// Does nothing for this layer + void computeCalculateFields() + {} + + /** + * @return The OSI layer level of STP (Data Link Layer). + */ + OsiModelLayer getOsiModelLayer() const + { + return OsiModelDataLinkLayer; + } + + /** + * A static method that validates the input data + * @param[in] data The pointer to the beginning of a byte stream of an Spanning Tree packet + * @param[in] dataLen The length of the byte stream + * @return True if the data is valid and can represent an Spanning Tree packet + */ + static bool isDataValid(const uint8_t* data, size_t dataLen); + + /** + * A method to create STP layer from existing packet + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored + * @return A newly allocated STP layer of one of the following types (according to the message type): + * StpConfigurationBPDULayer, StpTopologyChangeBPDULayer, RapidStpLayer, MultipleStpLayer + */ + static StpLayer* parseStpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + }; + + /** + * @class StpTopologyChangeBPDULayer + * Represents network topology change BPDU message of Spanning Tree Protocol + */ + class StpTopologyChangeBPDULayer : public StpLayer + { + protected: + explicit StpTopologyChangeBPDULayer(size_t dataLen) : StpLayer(dataLen) + {} + + public: + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + StpTopologyChangeBPDULayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : StpLayer(data, dataLen, prevLayer, packet) + {} + + /** + * Empty c'tor to create a new network topology change (TCN) BPDU layer. + * Initializes the protocol identifier, version and STP type fields with correct values + */ + StpTopologyChangeBPDULayer(); + + /** + * Get a pointer to network topology change (TCN) BPDU message + * @return A pointer to TCN BPDU message + */ + stp_tcn_bpdu* getStpTcnHeader() + { + return getStpHeader(); + } + + // overridden methods + + /** + * @return The size of STP TCN message + */ + size_t getHeaderLen() const + { + return sizeof(stp_tcn_bpdu); + } + + /// Parses next layer + void parseNextLayer(); + + /** + * @return Returns the protocol info as readable string + */ + std::string toString() const + { + return "Spanning Tree Topology Change Notification"; + } + + /** + * A static method that validates the input data + * @param[in] data The pointer to the beginning of a byte stream of an Spanning Tree Topology Change BPDU packet + * @param[in] dataLen The length of the byte stream + * @return True if the data is valid and can represent an Spanning Tree packet + */ + static bool isDataValid(const uint8_t* data, size_t dataLen) + { + return data && dataLen >= sizeof(stp_tcn_bpdu); + } + }; + + /** + * @class StpConfigurationBPDULayer + * Represents configuration BPDU message of Spanning Tree Protocol + */ + class StpConfigurationBPDULayer : public StpTopologyChangeBPDULayer + { + protected: + explicit StpConfigurationBPDULayer(size_t dataLen) : StpTopologyChangeBPDULayer(dataLen) + {} + + public: + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + StpConfigurationBPDULayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : StpTopologyChangeBPDULayer(data, dataLen, prevLayer, packet) + {} + + /** + * Empty c'tor to create a new configuration BPDU layer. + * Initializes the protocol identifier, version and STP type fields with correct values + */ + StpConfigurationBPDULayer(); + + /** + * Get a pointer to configuration BPDU message + * @return A pointer to configuration BPDU message + */ + stp_conf_bpdu* getStpConfHeader() const + { + return (stp_conf_bpdu*)(m_Data); + } + + /** + * Returns the flags of configuration message which indicates purpose of BPDU + * @return Flags of the configuration message + */ + uint8_t getFlag() const + { + return getStpConfHeader()->flag; + } + + /** + * Returns the flags of configuration message which indicates purpose of BPDU + * @param[in] value Flags of the configuration message + */ + void setFlag(uint8_t value) + { + getStpConfHeader()->flag = value; + } + + /** + * Returns the root bridge identifier + * @return Root bridge identifier + */ + uint64_t getRootId() const; + + /** + * Sets the root bridge identifier + * @param[in] value Root bridge identifier + */ + void setRootId(uint64_t value); + + /** + * Returns the priority of root bridge + * @return Priority of root bridge + */ + uint16_t getRootPriority() const; + + /** + * Sets the priority of root bridge + * @param[in] value Priority of root bridge + */ + void setRootPriority(uint16_t value); + + /** + * Returns the system identifier extension of root bridge + * @return System extension of root bridge + */ + uint16_t getRootSystemIDExtension() const; + + /** + * Sets the system identifier extension of root bridge + * @param[in] value System extension of root bridge + */ + void setRootSystemIDExtension(uint16_t value); + + /** + * Returns the system identifier of root bridge + * @return System identifier of root bridge + */ + pcpp::MacAddress getRootSystemID() const + { + return IDtoMacAddress(getRootId()); + } + + /** + * Sets the system identifier of root bridge + * @param[in] value System identifier of root bridge + */ + void setRootSystemID(const pcpp::MacAddress& value); + + /** + * Returns the value of the cost of path + * @return Cost of path + */ + uint32_t getPathCost() const; + + /** + * Sets the value of the cost of path + * @param[in] value Cost of path + */ + void setPathCost(uint32_t value); + + /** + * Returns the bridge identifier + * @return Bridge identifier + */ + uint64_t getBridgeId() const; + + /** + * Sets the bridge identifier + * @param[in] value Bridge identifier + */ + void setBridgeId(uint64_t value); + + /** + * Returns the priority of bridge + * @return Priority of bridge + */ + uint16_t getBridgePriority() const; + + /** + * Sets the priority of bridge + * @param[in] value Priority of bridge + */ + void setBridgePriority(uint16_t value); + + /** + * Returns the system identifier extension of bridge + * @return System extension of bridge + */ + uint16_t getBridgeSystemIDExtension() const; + + /** + * Sets the system identifier extension of bridge + * @param[in] value System extension of bridge + */ + void setBridgeSystemIDExtension(uint16_t value); + + /** + * Returns the system identifier of bridge + * @return System identifier of bridge + */ + pcpp::MacAddress getBridgeSystemID() const + { + return IDtoMacAddress(getBridgeId()); + } + + /** + * Sets the system identifier of bridge + * @param[in] value System identifier of bridge + */ + void setBridgeSystemID(const pcpp::MacAddress& value); + + /** + * Returns the port identifier + * @return Port identifier + */ + uint16_t getPortId() const; + + /** + * Sets the port identifier + * @param[in] value Port identifier + */ + void setPortId(uint16_t value); + + /** + * Returns age of the BPDU message + * @return Age of BPDU in seconds + */ + double getMessageAge() const; + + /** + * Sets age of the BPDU message + * @param[in] value Age of BPDU in seconds + */ + void setMessageAge(double value); + + /** + * Returns maximum age of the BPDU message + * @return Maximum age of BPDU in seconds + */ + double getMaximumAge() const; + + /** + * Sets maximum age of the BPDU message + * @param[in] value Maximum age of BPDU in seconds + */ + void setMaximumAge(double value); + + /** + * Returns the BPDU transmission interval + * @return Value of the transmission interval in seconds + */ + double getTransmissionInterval() const; + + /** + * Sets the BPDU transmission interval + * @param[in] value Value of the transmission interval in seconds + */ + void setTransmissionInterval(double value); + + /** + * Returns the delay for STP message + * @return Value of the forward delay in seconds + */ + double getForwardDelay() const; + + /** + * Sets the delay for STP message + * @param[in] value Value of the forward delay in seconds + */ + void setForwardDelay(double value); + + // overridden methods + + /** + * @return The size of STP configuration BPDU message + */ + size_t getHeaderLen() const + { + return sizeof(stp_conf_bpdu); + } + + /// Parses next layer + void parseNextLayer(); + + /** + * @return Returns the protocol info as readable string + */ + std::string toString() const + { + return "Spanning Tree Configuration"; + } + + /** + * A static method that validates the input data + * @param[in] data The pointer to the beginning of a byte stream of an Spanning Tree Configuration BPDU packet + * @param[in] dataLen The length of the byte stream + * @return True if the data is valid and can represent an Spanning Tree packet + */ + static bool isDataValid(const uint8_t* data, size_t dataLen) + { + return data && dataLen >= sizeof(stp_conf_bpdu); + } + }; + + /** + * @class RapidStpLayer + * Represents Rapid Spanning Tree Protocol (RSTP) + */ + class RapidStpLayer : public StpConfigurationBPDULayer + { + protected: + explicit RapidStpLayer(size_t dataLen) : StpConfigurationBPDULayer(dataLen) + {} + + public: + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + RapidStpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : StpConfigurationBPDULayer(data, dataLen, prevLayer, packet) + {} + + /** + * Empty c'tor to create a new Rapid STP layer. + * Initializes the protocol identifier, version and STP type fields with correct values + */ + RapidStpLayer(); + + /** + * Get a pointer to Rapid STP header + * @return A pointer to Rapid STP header + */ + rstp_conf_bpdu* getRstpConfHeader() const + { + return (rstp_conf_bpdu*)(m_Data); + } + + /** + * Returns the length of version1 field. Fixed at 0x0 for Rapid STP + * @return Length of the version1 field + */ + uint8_t getVersion1Len() const + { + return getRstpConfHeader()->version1Len; + } + + /** + * Returns the length of version1 field + * @param[in] value Length of the version1 field + */ + void setVersion1Len(uint8_t value) + { + getRstpConfHeader()->version1Len = value; + } + + // overridden methods + + /** + * @return The size of Rapid STP message + */ + size_t getHeaderLen() const + { + return sizeof(rstp_conf_bpdu); + } + + /// Parses next layer + void parseNextLayer(); + + /** + * @return Returns the protocol info as readable string + */ + std::string toString() const + { + return "Rapid Spanning Tree"; + } + + /** + * A static method that validates the input data + * @param[in] data The pointer to the beginning of a byte stream of an Rapid STP packet + * @param[in] dataLen The length of the byte stream + * @return True if the data is valid and can represent an Spanning Tree packet + */ + static bool isDataValid(const uint8_t* data, size_t dataLen) + { + return data && dataLen >= sizeof(rstp_conf_bpdu); + } + }; + + /** + * @class MultipleStpLayer + * Represents Multiple Spanning Tree Protocol (MSTP). It has limited capabilities (no crafting / limited editing) + * over MSTI configuration + */ + class MultipleStpLayer : public RapidStpLayer + { + public: + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + MultipleStpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : RapidStpLayer(data, dataLen, prevLayer, packet) + {} + + /** + * Empty c'tor to create a new Multiple STP layer. + * Initializes the protocol identifier, version and STP type fields with correct values + */ + MultipleStpLayer(); + + /** + * Get a pointer to Multiple STP header + * @return A pointer to Multiple STP header + */ + mstp_conf_bpdu* getMstpHeader() const + { + return (mstp_conf_bpdu*)(m_Data); + } + + /** + * @return Length of version3 field + */ + uint16_t getVersion3Len() const; + + /** + * Sets the length of version3 field + * @param[in] value Length of version3 field + */ + void setVersion3Len(uint16_t value); + + /** + * Returns the configuration ID format selector + * @return Configuration ID of format selector + */ + uint8_t getMstConfigurationFormatSelector() const + { + return getMstpHeader()->mstConfigFormatSelector; + } + + /** + * Sets the configuration ID format selector + * @param[in] value Configuration ID of format selector + */ + void setMstConfigurationFormatSelector(uint8_t value) + { + getMstpHeader()->mstConfigFormatSelector = value; + } + + /** + * Returns the pointer to configuration name field + * @return Configuration name + */ + std::string getMstConfigurationName() const; + + /** + * Sets the configuration name field + * @param[in] value Configuration name. Length should be less than 32, if longer value provided first 32 + * characters are used + */ + void setMstConfigurationName(const std::string& value); + + /** + * Returns the revision of configuration ID + * @return Revision of configuration ID + */ + uint16_t getMstConfigRevision() const; + + /** + * Sets the revision of configuration ID + * @param[in] value Revision of configuration ID + */ + void setMstConfigRevision(uint16_t value); + + /** + * Returns the pointer to configuration message digest. The field itself always 16 bytes long. + * @return A pointer to configuration digest + */ + uint8_t* getMstConfigDigest() const + { + return getMstpHeader()->mstConfigDigest; + } + + /** + * Sets the pointer to configuration message digest. The field itself always 16 bytes long. + * @param[in] value Pointer to digest + * @param[in] len Length of the digest, should be less than 16. If longer first 16 bytes are used + */ + void setMstConfigDigest(const uint8_t* value, uint8_t len); + + /** + * Returns CIST internal root path cost + * @return Value of the internal root path cost + */ + uint32_t getCISTIrpc() const; + + /** + * Sets CIST internal root path cost + * @param[in] value Value of the internal root path cost + */ + void setCISTIrpc(uint32_t value); + + /** + * Returns CIST bridge identifier + * @return Value of the bridge identifier + */ + uint64_t getCISTBridgeId() const; + + /** + * Sets CIST bridge identifier + * @param[in] value Value of the bridge identifier + */ + void setCISTBridgeId(uint64_t value); + + /** + * Returns the priority of CIST bridge + * @return Priority of CIST bridge + */ + uint16_t getCISTBridgePriority() const; + + /** + * Sets the priority of CIST bridge + * @param[in] value Priority of CIST bridge + */ + void setCISTBridgePriority(uint16_t value); + + /** + * Returns the system identifier extension of CIST bridge + * @return System extension of CIST bridge + */ + uint16_t getCISTBridgeSystemIDExtension() const; + + /** + * Sets the system identifier extension of CIST bridge + * @param[in] value System extension of CIST bridge + */ + void setCISTBridgeSystemIDExtension(uint16_t value); + + /** + * Returns the system identifier of CIST bridge + * @return System identifier of CIST bridge + */ + pcpp::MacAddress getCISTBridgeSystemID() const + { + return IDtoMacAddress(getCISTBridgeId()); + } + + /** + * Sets the system identifier of CIST bridge + * @param[in] value System identifier of CIST bridge + */ + void setCISTBridgeSystemID(const pcpp::MacAddress& value); + + /** + * Returns the remaining hop count + * @return Value of remaining hop count + */ + uint8_t getRemainingHopCount() const + { + return getMstpHeader()->remainId; + } + + /** + * Returns the remaining hop count + * @param[in] value Value of remaining hop count + */ + void setRemainingHopCount(uint8_t value) + { + getMstpHeader()->remainId = value; + } + + /** + * Returns the total number of MSTI configuration messages + * @return Number of MSTI configuration messages. Can be between 0 and 64. + */ + uint8_t getNumberOfMSTIConfMessages() const + { + return (getVersion3Len() - (sizeof(mstp_conf_bpdu) - sizeof(rstp_conf_bpdu) - sizeof(uint16_t))) / + sizeof(msti_conf_msg); + } + + /** + * Returns a reference to MSTI configuration messages. An MSTP packet can contain between 0 to 64 MSTI messages. + * The number of messages can be obtained by using getNumberOfMSTIConfMessages() + * @return An array pointer to MSTI configuration messages. Returns nullptr if there is no MSTI message. + */ + msti_conf_msg* getMstiConfMessages() const; + + // overridden methods + + /// Parses next layer + void parseNextLayer() + {} + + /** + * @return Returns the protocol info as readable string + */ + std::string toString() const + { + return "Multiple Spanning Tree"; + } + + /** + * A static method that validates the input data + * @param[in] data The pointer to the beginning of a byte stream of an Multiple STP packet + * @param[in] dataLen The length of the byte stream + * @return True if the data is valid and can represent an Spanning Tree packet + */ + static bool isDataValid(const uint8_t* data, size_t dataLen) + { + return data && dataLen >= sizeof(mstp_conf_bpdu); + } + }; +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/TLVData.h b/Packet++/header/pcapplusplus/TLVData.h new file mode 100644 index 0000000000..c96ee71ae0 --- /dev/null +++ b/Packet++/header/pcapplusplus/TLVData.h @@ -0,0 +1,444 @@ +#pragma once + +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/IpAddress.h" +#include + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + /** + * @class TLVRecord + * A wrapper class for a Type-Length-Value (TLV) record. This class does not create or modify TLV records, but + * rather serves as a wrapper and provides useful methods for retrieving data from them. This class has several + * abstract methods that should be implemented in derived classes. These methods are for record length value + * calculation (the 'L' in TLV) which is implemented differently in different protocols + */ + template class TLVRecord + { + protected: + /** A struct representing the TLV construct */ + struct TLVRawData + { + /** Record type */ + TRecType recordType; + /** Record length in bytes */ + TRecLen recordLen; + /** Record value (variable size) */ + uint8_t recordValue[]; + }; + + TLVRawData* m_Data; + + public: + /** + * A c'tor for this class that gets a pointer to the TLV record raw data (byte array) + * @param[in] recordRawData A pointer to the TLV record raw data + */ + TLVRecord(uint8_t* recordRawData) + { + assign(recordRawData); + } + + /** + * A copy c'tor for this class. This copy c'tor doesn't copy the TLV data, but only the pointer to it, + * which means that after calling it both the old and the new instance will point to the same TLV raw data + * @param[in] other The TLVRecord instance to copy from + */ + TLVRecord(const TLVRecord& other) + { + m_Data = other.m_Data; + } + + /** + * A d'tor for this class, currently does nothing + */ + virtual ~TLVRecord() + {} + + /** + * Assign a pointer to the TLV record raw data (byte array) + * @param[in] recordRawData A pointer to the TLV record raw data + */ + void assign(uint8_t* recordRawData) + { + m_Data = reinterpret_cast(recordRawData); + } + + /** + * Check if a pointer can be assigned to the TLV record data + * @param[in] recordRawData A pointer to the TLV record raw data + * @param[in] tlvDataLen The size of the TLV record raw data + * @return True if data is valid and can be assigned + */ + static bool canAssign(const uint8_t* recordRawData, size_t tlvDataLen) + { + return recordRawData != nullptr && + tlvDataLen >= (sizeof(TLVRawData::recordType) + sizeof(TLVRawData::recordLen)); + } + + /** + * Overload of the assignment operator. This operator doesn't copy the TLV data, but rather copies the pointer + * to it, which means that after calling it both the old and the new instance will point to the same TLV raw + * data + * @param[in] other The TLVRecord instance to assign + */ + TLVRecord& operator=(const TLVRecord& other) + { + m_Data = other.m_Data; + return *this; + } + + /** + * Overload of the equality operator. Two record are equal if both of them point to the same data, or if they + * point to different data but their total size is equal and the raw data they both contain is similar. + * @param[in] rhs The object to compare to + * @return True if both objects are equal, false otherwise + */ + bool operator==(const TLVRecord& rhs) const + { + if (m_Data == rhs.m_Data) + return true; + + if (getTotalSize() != rhs.getTotalSize()) + return false; + + if (isNull() || ((TLVRecord&)rhs).isNull()) + return false; + + return (memcmp(m_Data, rhs.m_Data, getTotalSize()) == 0); + } + + /** + * Overload of the not equal operator. + * @param[in] rhs The object to compare to + * @return True if objects are not equal, false otherwise + */ + bool operator!=(const TLVRecord& rhs) const + { + return !operator==(rhs); + } + + /** + * @return The type field of the record (the 'T' in __Type__-Length-Value) + */ + TRecType getType() const + { + if (m_Data == nullptr) + return 0; + + return m_Data->recordType; + } + + /** + * @return A pointer to the value of the record as byte array (the 'V' in Type-Length- __Value__) + */ + uint8_t* getValue() const + { + if (m_Data == nullptr) + return nullptr; + + return m_Data->recordValue; + } + + /** + * @return True if the TLV record raw data is nullptr, false otherwise + */ + bool isNull() const + { + return (m_Data == nullptr); + } + + /** + * @return True if the TLV record raw data is not nullptr, false otherwise + */ + bool isNotNull() const + { + return (m_Data != nullptr); + } + + /** + * @return A pointer to the TLV record raw data byte stream + */ + uint8_t* getRecordBasePtr() const + { + return (uint8_t*)m_Data; + } + + /** + * Free the memory of the TLV record raw data + */ + void purgeRecordData() + { + if (!isNull()) + { + delete[] m_Data; + m_Data = nullptr; + } + } + + /** + * A templated method to retrieve the record data as a certain type T. For example, if record data is 4B long + * (integer) then this method should be used as getValueAs() and it will return the record data as an + * integer.
Notice this return value is a copy of the data, not a pointer to the actual data + * @param[in] offset The offset in the record data to start reading the value from. Useful for cases when you + * want to read some of the data that doesn't start at offset 0. This is an optional parameter and the default + * value is 0, meaning start reading the value at the beginning of the record data + * @return The record data as type T + */ + template T getValueAs(size_t offset = 0) const + { + if (getDataSize() - offset < sizeof(T)) + return 0; + + T result; + memcpy(&result, m_Data->recordValue + offset, sizeof(T)); + return result; + } + + /** + * A templated method to copy data of type T into the TLV record data. For example: if record data is 4[Bytes] + * long use this method with \ to set an integer value into the record data: setValue(num) + * @param[in] newValue The value of type T to copy to the record data + * @param[in] valueOffset An optional parameter that specifies where to start setting the record data (default + * set to 0). For example: if record data is 20 bytes long and you only need to set the 4 last bytes as integer + * then use this method like this: setValue(num, 16) + * @return True if value was set successfully or false if the size of T is larger than the record data size + */ + template bool setValue(T newValue, int valueOffset = 0) + { + if (getDataSize() < sizeof(T)) + return false; + + memcpy(m_Data->recordValue + valueOffset, &newValue, sizeof(T)); + return true; + } + + /** + * @return The total size of the TLV record (in bytes) + */ + virtual size_t getTotalSize() const = 0; + + /** + * @return The size of the record value (meaning the size of the 'V' part in TLV) + */ + virtual size_t getDataSize() const = 0; + }; + + /** + * @class TLVRecordReader + * A class for reading TLV records data out of a byte stream. This class contains helper methods for retrieving and + * counting TLV records. This is a template class that expects template argument class derived from TLVRecord. + */ + template class TLVRecordReader + { + private: + mutable size_t m_RecordCount; + + public: + /** + * A default c'tor for this class + */ + TLVRecordReader() + { + m_RecordCount = (size_t)-1; + } + + /** + * A default copy c'tor for this class + */ + TLVRecordReader(const TLVRecordReader& other) + { + m_RecordCount = other.m_RecordCount; + } + + /** + * A d'tor for this class which currently does nothing + */ + virtual ~TLVRecordReader() + {} + + /** + * Overload of the assignment operator for this class + * @param[in] other The TLVRecordReader instance to assign + */ + TLVRecordReader& operator=(const TLVRecordReader& other) + { + m_RecordCount = other.m_RecordCount; + return *this; + } + + /** + * Get the first TLV record out of a byte stream + * @param[in] tlvDataBasePtr A pointer to the TLV data byte stream + * @param[in] tlvDataLen The TLV data byte stream length + * @return An instance of type TLVRecordType that contains the first TLV record. If tlvDataBasePtr is nullptr or + * tlvDataLen is zero the returned TLVRecordType instance will be logically null, meaning + * TLVRecordType.isNull() will return true + */ + TLVRecordType getFirstTLVRecord(uint8_t* tlvDataBasePtr, size_t tlvDataLen) const + { + TLVRecordType resRec(nullptr); // for NRVO optimization + if (!TLVRecordType::canAssign(tlvDataBasePtr, tlvDataLen)) + return resRec; + + resRec.assign(tlvDataBasePtr); + // resRec pointer is out-bounds of the TLV records memory + if (resRec.getRecordBasePtr() + resRec.getTotalSize() > tlvDataBasePtr + tlvDataLen) + resRec.assign(nullptr); + + // check if there are records at all and the total size is not zero + if (!resRec.isNull() && (tlvDataLen == 0 || resRec.getTotalSize() == 0)) + resRec.assign(nullptr); + + return resRec; + } + + /** + * Get a TLV record that follows a given TLV record in a byte stream + * @param[in] record A given TLV record + * @param[in] tlvDataBasePtr A pointer to the TLV data byte stream + * @param[in] tlvDataLen The TLV data byte stream length + * @return An instance of type TLVRecordType that wraps the record following the record given as input. If the + * input record.isNull() is true or if the next record is out of bounds of the byte stream, a logical null + * instance of TLVRecordType will be returned, meaning TLVRecordType.isNull() will return true + */ + TLVRecordType getNextTLVRecord(TLVRecordType& record, const uint8_t* tlvDataBasePtr, size_t tlvDataLen) const + { + TLVRecordType resRec(nullptr); // for NRVO optimization + + if (record.isNull()) + return resRec; + + if (!TLVRecordType::canAssign(record.getRecordBasePtr() + record.getTotalSize(), + tlvDataBasePtr - record.getRecordBasePtr() + tlvDataLen - + record.getTotalSize())) + return resRec; + + resRec.assign(record.getRecordBasePtr() + record.getTotalSize()); + + if (resRec.getTotalSize() == 0) + resRec.assign(nullptr); + + // resRec pointer is out-bounds of the TLV records memory + if ((resRec.getRecordBasePtr() - tlvDataBasePtr) < 0) + resRec.assign(nullptr); + + // resRec pointer is out-bounds of the TLV records memory + if (!resRec.isNull() && resRec.getRecordBasePtr() + resRec.getTotalSize() > tlvDataBasePtr + tlvDataLen) + resRec.assign(nullptr); + + return resRec; + } + + /** + * Search for the first TLV record that corresponds to a given record type (the 'T' in __Type__-Length-Value) + * @param[in] recordType The record type to search for + * @param[in] tlvDataBasePtr A pointer to the TLV data byte stream + * @param[in] tlvDataLen The TLV data byte stream length + * @return An instance of type TLVRecordType that contains the result record. If record was not found a logical + * null instance of TLVRecordType will be returned, meaning TLVRecordType.isNull() will return true + */ + TLVRecordType getTLVRecord(uint32_t recordType, uint8_t* tlvDataBasePtr, size_t tlvDataLen) const + { + TLVRecordType curRec = getFirstTLVRecord(tlvDataBasePtr, tlvDataLen); + while (!curRec.isNull()) + { + if (curRec.getType() == recordType) + { + return curRec; + } + + curRec = getNextTLVRecord(curRec, tlvDataBasePtr, tlvDataLen); + } + + curRec.assign(nullptr); + return curRec; // for NRVO optimization + } + + /** + * Get the TLV record count in a given TLV data byte stream. For efficiency purposes the count is being cached + * so only the first call to this method will go over all the TLV records, while all consequent calls will + * return the cached number. This implies that if there is a change in the number of records, it's the user's + * responsibility to call changeTLVRecordCount() with the record count change + * @param[in] tlvDataBasePtr A pointer to the TLV data byte stream + * @param[in] tlvDataLen The TLV data byte stream length + * @return The TLV record count + */ + size_t getTLVRecordCount(uint8_t* tlvDataBasePtr, size_t tlvDataLen) const + { + if (m_RecordCount != (size_t)-1) + return m_RecordCount; + + m_RecordCount = 0; + TLVRecordType curRec = getFirstTLVRecord(tlvDataBasePtr, tlvDataLen); + while (!curRec.isNull()) + { + m_RecordCount++; + curRec = getNextTLVRecord(curRec, tlvDataBasePtr, tlvDataLen); + } + + return m_RecordCount; + } + + /** + * As described in getTLVRecordCount(), the TLV record count is being cached for efficiency purposes. So if the + * number of TLV records change, it's the user's responsibility to call this method with the number of TLV + * records being added or removed. If records were added the change should be a positive number, or a negative + * number if records were removed + * @param[in] changedBy Number of records that were added or removed + */ + void changeTLVRecordCount(int changedBy) + { + if (m_RecordCount != (size_t)-1) + m_RecordCount += changedBy; + } + }; + + /** + * @class TLVRecordBuilder + * A base class for building Type-Length-Value (TLV) records. This builder receives the record parameters in its + * c'tor, builds the record raw buffer and provides a method to build a TLVRecord object out of it. Please notice + * this is a base class that lacks the capability of actually building TLVRecord objects and also cannot be + * instantiated. The reason for that is that different protocols build TLV records in different ways, so these + * missing capabilities will be implemented by the derived classes which are specific to each protocol. This class + * only provides the common infrastructure that will be used by them + */ + class TLVRecordBuilder + { + protected: + TLVRecordBuilder(); + + TLVRecordBuilder(uint32_t recType, const uint8_t* recValue, uint8_t recValueLen); + + TLVRecordBuilder(uint32_t recType, uint8_t recValue); + + TLVRecordBuilder(uint32_t recType, uint16_t recValue); + + TLVRecordBuilder(uint32_t recType, uint32_t recValue); + + TLVRecordBuilder(uint32_t recType, const IPv4Address& recValue); + + TLVRecordBuilder(uint32_t recType, const std::string& recValue, bool valueIsHexString = false); + + TLVRecordBuilder(const TLVRecordBuilder& other); + + TLVRecordBuilder& operator=(const TLVRecordBuilder& other); + + virtual ~TLVRecordBuilder(); + + void init(uint32_t recType, const uint8_t* recValue, size_t recValueLen); + + uint8_t* m_RecValue; + size_t m_RecValueLen; + uint32_t m_RecType; + + private: + void copyData(const TLVRecordBuilder& other); + }; +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/TcpLayer.h b/Packet++/header/pcapplusplus/TcpLayer.h new file mode 100644 index 0000000000..43d4542c44 --- /dev/null +++ b/Packet++/header/pcapplusplus/TcpLayer.h @@ -0,0 +1,696 @@ +#pragma once + +#include "pcapplusplus/DeprecationUtils.h" +#include "pcapplusplus/Layer.h" +#include "TLVData.h" +#include + +#define PCPP_DEPRECATED_TCP_OPTION_TYPE \ + PCPP_DEPRECATED("enum TcpOptionType is deprecated; Use enum class TcpOptionEnumType instead") + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * @struct tcphdr + * Represents an TCP protocol header + */ +#pragma pack(push, 1) + struct tcphdr + { + /** Source TCP port */ + uint16_t portSrc; + /** Destination TCP port */ + uint16_t portDst; + /** Sequence number */ + uint32_t sequenceNumber; + /** Acknowledgment number */ + uint32_t ackNumber; +#if (BYTE_ORDER == LITTLE_ENDIAN) + uint16_t reserved : 4; + /** Specifies the size of the TCP header in 32-bit words */ + uint16_t dataOffset : 4; + /** FIN flag */ + uint16_t finFlag : 1; + /** SYN flag */ + uint16_t synFlag : 1; + /** RST flag */ + uint16_t rstFlag : 1; + /** PSH flag */ + uint16_t pshFlag : 1; + /** ACK flag */ + uint16_t ackFlag : 1; + /** URG flag */ + uint16_t urgFlag : 1; + /** ECE flag */ + uint16_t eceFlag : 1; + /** CWR flag */ + uint16_t cwrFlag : 1; +#elif (BYTE_ORDER == BIG_ENDIAN) + /** Specifies the size of the TCP header in 32-bit words */ + uint16_t dataOffset : 4; + /** Reserved */ + uint16_t reserved : 4; + /** CWR flag */ + uint16_t cwrFlag : 1; + /** ECE flag */ + uint16_t eceFlag : 1; + /** URG flag */ + uint16_t urgFlag : 1; + /** ACK flag */ + uint16_t ackFlag : 1; + /** PSH flag */ + uint16_t pshFlag : 1; + /** RST flag */ + uint16_t rstFlag : 1; + /** SYN flag */ + uint16_t synFlag : 1; + /** FIN flag */ + uint16_t finFlag : 1; +#else +# error "Endian is not LE nor BE..." +#endif + /** The size of the receive window, which specifies the number of window size units (by default, bytes) */ + uint16_t windowSize; + /** The 16-bit checksum field is used for error-checking of the header and data */ + uint16_t headerChecksum; + /** If the URG flag (@ref tcphdr#urgFlag) is set, then this 16-bit field is an offset from the sequence number + * indicating the last urgent data byte */ + uint16_t urgentPointer; + }; +#pragma pack(pop) + + /** + * TCP options types + */ + enum TcpOptionType : uint8_t + { + /** Padding */ + PCPP_TCPOPT_NOP = 1, + /** End of options */ + PCPP_TCPOPT_EOL = 0, + /** Segment size negotiating */ + TCPOPT_MSS = 2, + /** Window scaling */ + PCPP_TCPOPT_WINDOW = 3, + /** SACK Permitted */ + TCPOPT_SACK_PERM = 4, + /** SACK Block */ + PCPP_TCPOPT_SACK = 5, + /** Echo (obsoleted by option TcpOptionType::PCPP_TCPOPT_TIMESTAMP) */ + TCPOPT_ECHO = 6, + /** Echo Reply (obsoleted by option TcpOptionType::PCPP_TCPOPT_TIMESTAMP) */ + TCPOPT_ECHOREPLY = 7, + /** TCP Timestamps */ + PCPP_TCPOPT_TIMESTAMP = 8, + /** CC (obsolete) */ + TCPOPT_CC = 11, + /** CC.NEW (obsolete) */ + TCPOPT_CCNEW = 12, + /** CC.ECHO(obsolete) */ + TCPOPT_CCECHO = 13, + /** MD5 Signature Option */ + TCPOPT_MD5 = 19, + /** Multipath TCP */ + TCPOPT_MPTCP = 0x1e, + /** SCPS Capabilities */ + TCPOPT_SCPS = 20, + /** SCPS SNACK */ + TCPOPT_SNACK = 21, + /** SCPS Record Boundary */ + TCPOPT_RECBOUND = 22, + /** SCPS Corruption Experienced */ + TCPOPT_CORREXP = 23, + /** Quick-Start Response */ + TCPOPT_QS = 27, + /** User Timeout Option (also, other known unauthorized use) */ + TCPOPT_USER_TO = 28, + /** RFC3692-style Experiment 1 (also improperly used for shipping products) */ + TCPOPT_EXP_FD = 0xfd, + /** RFC3692-style Experiment 2 (also improperly used for shipping products) */ + TCPOPT_EXP_FE = 0xfe, + /** Riverbed probe option, non IANA registered option number */ + TCPOPT_RVBD_PROBE = 76, + /** Riverbed transparency option, non IANA registered option number */ + TCPOPT_RVBD_TRPY = 78, + /** Unknown option */ + TCPOPT_Unknown = 255 + }; + + /** + * TCP options types + */ + enum class TcpOptionEnumType : uint8_t + { + /** Padding */ + Nop = 1, + /** End of options */ + Eol = 0, + /** Segment size negotiating */ + Mss = 2, + /** Window scaling */ + Window = 3, + /** SACK Permitted */ + SackPerm = 4, + /** SACK Block */ + Sack = 5, + /** Echo (obsoleted by option TcpOptionEnumType::Timestamp) */ + Echo = 6, + /** Echo Reply (obsoleted by option TcpOptionEnumType::Timestamp) */ + EchoReply = 7, + /** TCP Timestamps */ + Timestamp = 8, + /** CC (obsolete) */ + Cc = 11, + /** CC.NEW (obsolete) */ + CcNew = 12, + /** CC.ECHO(obsolete) */ + CcEcho = 13, + /** MD5 Signature Option */ + Md5 = 19, + /** Multipath TCP */ + MpTcp = 0x1e, + /** SCPS Capabilities */ + Scps = 20, + /** SCPS SNACK */ + Snack = 21, + /** SCPS Record Boundary */ + RecBound = 22, + /** SCPS Corruption Experienced */ + CorrExp = 23, + /** Quick-Start Response */ + Qs = 27, + /** User Timeout Option (also, other known unauthorized use) */ + UserTo = 28, + /** RFC3692-style Experiment 1 (also improperly used for shipping products) */ + ExpFd = 0xfd, + /** RFC3692-style Experiment 2 (also improperly used for shipping products) */ + ExpFe = 0xfe, + /** Riverbed probe option, non IANA registered option number */ + RvbdProbe = 76, + /** Riverbed transparency option, non IANA registered option number */ + RvbdTrpy = 78, + /** Unknown option */ + Unknown = 255 + }; + + // TCP option lengths + + /** pcpp::TcpOptionEnumType::Nop length */ +#define PCPP_TCPOLEN_NOP 1 + /** pcpp::TcpOptionEnumType::Eol length */ +#define PCPP_TCPOLEN_EOL 1 + /** pcpp::TcpOptionEnumType::Mss length */ +#define PCPP_TCPOLEN_MSS 4 + /** pcpp::TcpOptionEnumType::Window length */ +#define PCPP_TCPOLEN_WINDOW 3 + /** pcpp::TcpOptionEnumType::SackPerm length */ +#define PCPP_TCPOLEN_SACK_PERM 2 + /** pcpp::TcpOptionEnumType::Sack length */ +#define PCPP_TCPOLEN_SACK_MIN 2 + /** pcpp::TcpOptionEnumType::Echo length */ +#define PCPP_TCPOLEN_ECHO 6 + /** pcpp::TcpOptionEnumType::EchoReply length */ +#define PCPP_TCPOLEN_ECHOREPLY 6 + /** pcpp::TcpOptionEnumType::Timestamp length */ +#define PCPP_TCPOLEN_TIMESTAMP 10 + /** pcpp::TcpOptionEnumType::Cc length */ +#define PCPP_TCPOLEN_CC 6 + /** pcpp::TcpOptionEnumType::CcNew length */ +#define PCPP_TCPOLEN_CCNEW 6 + /** pcpp::TcpOptionEnumType::CcEcho length */ +#define PCPP_TCPOLEN_CCECHO 6 + /** pcpp::TcpOptionEnumType::Md5 length */ +#define PCPP_TCPOLEN_MD5 18 + /** pcpp::TcpOptionEnumType::MpTcp length */ +#define PCPP_TCPOLEN_MPTCP_MIN 8 + /** pcpp::TcpOptionEnumType::Scps length */ +#define PCPP_TCPOLEN_SCPS 4 + /** pcpp::TcpOptionEnumType::Snack length */ +#define PCPP_TCPOLEN_SNACK 6 + /** pcpp::TcpOptionEnumType::RecBound length */ +#define PCPP_TCPOLEN_RECBOUND 2 + /** pcpp::TcpOptionEnumType::CorrExp length */ +#define PCPP_TCPOLEN_CORREXP 2 + /** pcpp::TcpOptionEnumType::Qs length */ +#define PCPP_TCPOLEN_QS 8 + /** pcpp::TcpOptionEnumType::UserTo length */ +#define PCPP_TCPOLEN_USER_TO 4 + /** pcpp::TcpOptionEnumType::RvbdProbe length */ +#define PCPP_TCPOLEN_RVBD_PROBE_MIN 3 + /** pcpp::TcpOptionEnumType::RvbdTrpy length */ +#define PCPP_TCPOLEN_RVBD_TRPY_MIN 16 + /** pcpp::TcpOptionEnumType::ExpFd and pcpp::TcpOptionEnumType::ExpFe length */ +#define PCPP_TCPOLEN_EXP_MIN 2 + + /** + * @class TcpOption + * A wrapper class for TCP options. This class does not create or modify TCP option records, but rather + * serves as a wrapper and provides useful methods for retrieving data from them + */ + class TcpOption : public TLVRecord + { + public: + /** + * A c'tor for this class that gets a pointer to the option raw data (byte array) + * @param[in] optionRawData A pointer to the TCP option raw data + */ + explicit TcpOption(uint8_t* optionRawData) : TLVRecord(optionRawData) + {} + + /** + * A d'tor for this class, currently does nothing + */ + ~TcpOption() = default; + + /** + * @deprecated This method is deprecated, please use getTcpOptionEnumType() + */ + PCPP_DEPRECATED("Use getTcpOptionEnumType instead") + TcpOptionType getTcpOptionType() const + { + return getTcpOptionType(m_Data); + } + + /** + * @return TCP option type casted as pcpp::TcpOptionEnumType enum. If the data is null a value + * of TcpOptionEnumType::Unknown is returned + */ + TcpOptionEnumType getTcpOptionEnumType() const + { + return getTcpOptionEnumType(m_Data); + } + + /** + * Check if a pointer can be assigned to the TLV record data + * @param[in] recordRawData A pointer to the TLV record raw data + * @param[in] tlvDataLen The size of the TLV record raw data + * @return True if data is valid and can be assigned + */ + static bool canAssign(const uint8_t* recordRawData, size_t tlvDataLen) + { + const auto* data = reinterpret_cast(recordRawData); + if (data == nullptr) + return false; + + if (tlvDataLen < sizeof(TLVRawData::recordType)) + return false; + + const auto recordType = getTcpOptionEnumType(data); + if (recordType == TcpOptionEnumType::Nop || recordType == TcpOptionEnumType::Eol) + return true; + + return TLVRecord::canAssign(recordRawData, tlvDataLen); + } + + // implement abstract methods + + size_t getTotalSize() const + { + if (m_Data == nullptr) + return 0; + + const auto recordType = getTcpOptionEnumType(m_Data); + if (recordType == TcpOptionEnumType::Nop || recordType == TcpOptionEnumType::Eol) + return sizeof(uint8_t); + + return static_cast(m_Data->recordLen); + } + + size_t getDataSize() const + { + if (m_Data == nullptr) + return 0; + + const auto recordType = getTcpOptionEnumType(m_Data); + if (recordType == TcpOptionEnumType::Nop || recordType == TcpOptionEnumType::Eol) + return 0; + + return static_cast(m_Data->recordLen) - (2 * sizeof(uint8_t)); + } + + private: + static TcpOptionType getTcpOptionType(const TLVRawData* optionRawData) + { + if (optionRawData == nullptr) + return TcpOptionType::TCPOPT_Unknown; + + return static_cast(optionRawData->recordType); + } + + static TcpOptionEnumType getTcpOptionEnumType(const TLVRawData* optionRawData) + { + if (optionRawData == nullptr) + return TcpOptionEnumType::Unknown; + + return static_cast(optionRawData->recordType); + } + }; + + /** + * @class TcpOptionBuilder + * A class for building TCP option records. This builder receives the TCP option parameters in its c'tor, + * builds the TCP option raw buffer and provides a build() method to get a TcpOption object out of it + */ + class TcpOptionBuilder : public TLVRecordBuilder + { + + public: + /** + * An enum to describe NOP and EOL TCP options. Used in one of this class's c'tors + */ + enum NopEolOptionTypes : uint8_t + { + /** NOP TCP option */ + NOP, + /** EOL TCP option */ + EOL + }; + + /** + * An enum to describe NOP and EOL TCP options. Used in one of this class's c'tors + */ + enum class NopEolOptionEnumType : uint8_t + { + /** NOP TCP option */ + Nop, + /** EOL TCP option */ + Eol + }; + + /** + * @deprecated This method is deprecated, please use constructor with TcpOptionEnumType + */ + PCPP_DEPRECATED_TCP_OPTION_TYPE + TcpOptionBuilder(TcpOptionType optionType, const uint8_t* optionValue, uint8_t optionValueLen) + : TLVRecordBuilder((uint8_t)optionType, optionValue, optionValueLen) + {} + + /** + * A c'tor for building TCP options which their value is a byte array. The TcpOption object can be later + * retrieved by calling build() + * @param[in] optionType TCP option type + * @param[in] optionValue A buffer containing the option value. This buffer is read-only and isn't modified in + * any way. + * @param[in] optionValueLen Option value length in bytes + */ + TcpOptionBuilder(TcpOptionEnumType optionType, const uint8_t* optionValue, uint8_t optionValueLen) + : TLVRecordBuilder(static_cast(optionType), optionValue, optionValueLen) + {} + + /** + * @deprecated This method is deprecated, please use constructor with TcpOptionEnumType + */ + PCPP_DEPRECATED_TCP_OPTION_TYPE + TcpOptionBuilder(TcpOptionType optionType, uint8_t optionValue) + : TLVRecordBuilder((uint8_t)optionType, optionValue) + {} + + /** + * A c'tor for building TCP options which have a 1-byte value. The TcpOption object can be later retrieved + * by calling build() + * @param[in] optionType TCP option type + * @param[in] optionValue A 1-byte option value + */ + TcpOptionBuilder(TcpOptionEnumType optionType, uint8_t optionValue) + : TLVRecordBuilder(static_cast(optionType), optionValue) + {} + + /** + * @deprecated This method is deprecated, please use constructor with TcpOptionEnumType + */ + PCPP_DEPRECATED_TCP_OPTION_TYPE + TcpOptionBuilder(TcpOptionType optionType, uint16_t optionValue) + : TLVRecordBuilder((uint8_t)optionType, optionValue) + {} + + /** + * A c'tor for building TCP options which have a 2-byte value. The TcpOption object can be later retrieved + * by calling build() + * @param[in] optionType TCP option type + * @param[in] optionValue A 2-byte option value + */ + TcpOptionBuilder(TcpOptionEnumType optionType, uint16_t optionValue) + : TLVRecordBuilder(static_cast(optionType), optionValue) + {} + + /** + * @deprecated This method is deprecated, please use constructor with TcpOptionEnumType + */ + PCPP_DEPRECATED_TCP_OPTION_TYPE + TcpOptionBuilder(TcpOptionType optionType, uint32_t optionValue) + : TLVRecordBuilder((uint8_t)optionType, optionValue) + {} + + /** + * A c'tor for building TCP options which have a 4-byte value. The TcpOption object can be later retrieved + * by calling build() + * @param[in] optionType TCP option type + * @param[in] optionValue A 4-byte option value + */ + TcpOptionBuilder(TcpOptionEnumType optionType, uint32_t optionValue) + : TLVRecordBuilder(static_cast(optionType), optionValue) + {} + + /** + * @deprecated This method is deprecated, please use constructor with NopEolOptionEnumType + */ + PCPP_DEPRECATED("enum NopEolOptionTypes is deprecated; Use enum class NopEolOptionEnumType instead") + explicit TcpOptionBuilder(NopEolOptionTypes optionType); + + /** + * A c'tor for building TCP NOP and EOL options. These option types are special in that they contain only 1 byte + * which is the TCP option type (NOP or EOL). The TcpOption object can be later retrieved + * by calling build() + * @param[in] optionType An enum value indicating which option type to build (NOP or EOL) + */ + explicit TcpOptionBuilder(NopEolOptionEnumType optionType); + + /** + * Build the TcpOption object out of the parameters defined in the c'tor + * @return The TcpOption object + */ + TcpOption build() const; + }; + + /** + * @class TcpLayer + * Represents a TCP (Transmission Control Protocol) protocol layer + */ + class TcpLayer : public Layer + { + public: + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data (will be casted to @ref tcphdr) + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + TcpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + /** + * A constructor that allocates a new TCP header with zero TCP options + */ + TcpLayer(); + + /** + * A constructor that allocates a new TCP header with source port and destination port and zero TCP options + * @param[in] portSrc Source port + * @param[in] portDst Destination port + */ + TcpLayer(uint16_t portSrc, uint16_t portDst); + + ~TcpLayer() = default; + + /** + * A copy constructor that copy the entire header from the other TcpLayer (including TCP options) + */ + TcpLayer(const TcpLayer& other); + + /** + * An assignment operator that first delete all data from current layer and then copy the entire header from the + * other TcpLayer (including TCP options) + */ + TcpLayer& operator=(const TcpLayer& other); + + /** + * Get a pointer to the TCP header. Notice this points directly to the data, so every change will change the + * actual packet data + * @return A pointer to the @ref tcphdr + */ + tcphdr* getTcpHeader() const + { + return (tcphdr*)m_Data; + } + + /** + * @return TCP source port + */ + uint16_t getSrcPort() const; + + /** + * @return TCP destination port + */ + uint16_t getDstPort() const; + + /** + * @deprecated This method is deprecated, please use getTcpOption(TcpOptionEnumType option) + */ + PCPP_DEPRECATED_TCP_OPTION_TYPE + TcpOption getTcpOption(TcpOptionType option) const; + + /** + * Get a TCP option by type + * @param[in] option TCP option type to retrieve + * @return An TcpOption object that contains the first option that matches this type, or logical null + * (TcpOption#isNull() == true) if no such option found + */ + TcpOption getTcpOption(TcpOptionEnumType option) const; + + /** + * @return The first TCP option in the packet. If the current layer contains no options the returned value will + * contain a logical null (TcpOption#isNull() == true) + */ + TcpOption getFirstTcpOption() const; + + /** + * Get the TCP option that comes after a given option. If the given option was the last one, the + * returned value will contain a logical null (TcpOption#isNull() == true) + * @param[in] tcpOption A TCP option object that exists in the current layer + * @return A TcpOption object that contains the TCP option data that comes next, or logical null if the given + * TCP option: (1) was the last one; or (2) contains a logical null; or (3) doesn't belong to this packet + */ + TcpOption getNextTcpOption(TcpOption& tcpOption) const; + + /** + * @return The number of TCP options in this layer + */ + size_t getTcpOptionCount() const; + + /** + * Add a new TCP option at the end of the layer (after the last TCP option) + * @param[in] optionBuilder A TcpOptionBuilder object that contains the TCP option data to be added + * @return A TcpOption object that contains the newly added TCP option data or logical null + * (TcpOption#isNull() == true) if addition failed. In case of a failure a corresponding error message will be + * printed to log + */ + TcpOption addTcpOption(const TcpOptionBuilder& optionBuilder); + + /** + * @deprecated This method is deprecated, please use insertTcpOptionAfter(const TcpOptionBuilder& optionBuilder, + * TcpOptionEnumType prevOptionType = TcpOptionEnumType::Unknown) + */ + PCPP_DEPRECATED("Use insertTcpOptionAfter instead") + TcpOption addTcpOptionAfter(const TcpOptionBuilder& optionBuilder, + TcpOptionType prevOptionType = TcpOptionType::TCPOPT_Unknown); + + /** + * Insert a new TCP option after an existing one + * @param[in] optionBuilder A TcpOptionBuilder object that contains the requested TCP option data to be inserted + * @param[in] prevOptionType The TCP option which the newly inserted option should come after. This is an + * optional parameter which gets a default value of TcpOptionType::Unknown if omitted, which means the new + * option will be inserted as the first option in the layer + * @return A TcpOption object containing the newly inserted TCP option data or logical null + * (TcpOption#isNull() == true) if insertion failed. In case of a failure a corresponding error message will be + * printed to log + */ + TcpOption insertTcpOptionAfter(const TcpOptionBuilder& optionBuilder, + TcpOptionEnumType prevOptionType = TcpOptionEnumType::Unknown); + + /** + * @deprecated This method is deprecated, please use removeTcpOption(TcpOptionEnumType) + */ + PCPP_DEPRECATED_TCP_OPTION_TYPE + bool removeTcpOption(TcpOptionType optionType); + + /** + * Remove an existing TCP option from the layer. TCP option is found by type + * @param[in] optionType The TCP option type to remove + * @return True if TCP option was removed or false if type wasn't found or if removal failed (in each case a + * proper error will be written to log) + */ + bool removeTcpOption(TcpOptionEnumType optionType); + + /** + * Remove all TCP options in this layer + * @return True if all TCP options were successfully removed or false if removal failed for some reason + * (a proper error will be written to log) + */ + bool removeAllTcpOptions(); + + /** + * Calculate the checksum from header and data and possibly write the result to @ref tcphdr#headerChecksum + * @param[in] writeResultToPacket If set to true then checksum result will be written to @ref + * tcphdr#headerChecksum + * @return The checksum result + */ + uint16_t calculateChecksum(bool writeResultToPacket); + + /** + * The static method makes validation of input data + * @param[in] data The pointer to the beginning of byte stream of TCP packet + * @param[in] dataLen The length of byte stream + * @return True if the data is valid and can represent a TCP packet + */ + static inline bool isDataValid(const uint8_t* data, size_t dataLen); + + // implement abstract methods + + /** + * Currently identifies the following next layers: HttpRequestLayer, HttpResponseLayer. Otherwise sets + * PayloadLayer + */ + void parseNextLayer(); + + /** + * @return Size of @ref tcphdr + all TCP options + */ + size_t getHeaderLen() const + { + return getTcpHeader()->dataOffset * 4; + } + + /** + * Calculate @ref tcphdr#headerChecksum field + */ + void computeCalculateFields(); + + std::string toString() const; + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelTransportLayer; + } + + private: + TLVRecordReader m_OptionReader; + int m_NumOfTrailingBytes; + + void initLayer(); + uint8_t* getOptionsBasePtr() const + { + return m_Data + sizeof(tcphdr); + } + TcpOption addTcpOptionAt(const TcpOptionBuilder& optionBuilder, int offset); + void adjustTcpOptionTrailer(size_t totalOptSize); + void copyLayerData(const TcpLayer& other); + }; + + // implementation of inline methods + + bool TcpLayer::isDataValid(const uint8_t* data, size_t dataLen) + { + const tcphdr* hdr = reinterpret_cast(data); + return dataLen >= sizeof(tcphdr) && hdr->dataOffset >= 5 /* the minimum TCP header size */ + && dataLen >= hdr->dataOffset * sizeof(uint32_t); + } +} // namespace pcpp + +#undef PCPP_DEPRECATED_TCP_OPTION_TYPE diff --git a/Packet++/header/pcapplusplus/TcpReassembly.h b/Packet++/header/pcapplusplus/TcpReassembly.h new file mode 100644 index 0000000000..174b41faf7 --- /dev/null +++ b/Packet++/header/pcapplusplus/TcpReassembly.h @@ -0,0 +1,568 @@ +#pragma once + +#include "pcapplusplus/Packet.h" +#include "pcapplusplus/IpAddress.h" +#include "pcapplusplus/PointerVector.h" +#include +#include +#include +#include + +/** + * @file + * This is an implementation of TCP reassembly logic, which means reassembly of TCP messages spanning multiple TCP + * segments (or packets).
This logic can be useful in analyzing messages for a large number of protocols implemented + * on top of TCP including HTTP, SSL/TLS, FTP and many many more. + * + * __General Features:__ + * - Manage multiple TCP connections under one pcpp#TcpReassembly instance + * - Support TCP retransmission + * - Support out-of-order packets + * - Support missing TCP data + * - TCP connections can end "naturally" (by FIN/RST packets) or manually by the user + * - Support callbacks for new TCP data, connection start and connection end + * + * __Logic Description:__ + * - The user creates an instance of the pcpp#TcpReassembly class + * - Then the user starts feeding it with TCP packets + * - The pcpp#TcpReassembly instance manages all TCP connections from the packets it's being fed. For each connection it + * manages its 2 sides (A->B and B->A). + * - When a packet arrives, it is first classified to a certain TCP connection + * - Then it is classified to a certain side of the TCP connection + * - Then the pcpp#TcpReassembly logic tries to understand if the data in this packet is the expected data + * (sequence-wise) and if it's new (e.g isn't a retransmission). + * - If the packet data matches these criteria a callback is being invoked. This callback is supplied by the user in the + * creation of the pcpp#TcpReassembly instance. This callback contains the new data (of course), but also information + * about the connection (5-tuple, 4-byte hash key describing the connection, etc.) and also a pointer to a "user + * cookie", meaning a pointer to a structure provided by the user during the creation of the pcpp#TcpReassembly + * instance. + * - If the data in this packet isn't new, it's being ignored + * - If the data in this packet isn't expected (meaning this packet came out-of-order), then the data is being queued + * internally and will be sent to the user when its turn arrives (meaning, after the data before arrives). + * - If the missing data doesn't arrive until a new message from the other side of the connection arrives or until the + * connection ends - this will be considered as missing data and the queued data will be sent to the user, but the + * string "[X bytes missing]" will be added to the message sent in the callback. + * - pcpp#TcpReassembly supports 2 more callbacks - one is invoked when a new TCP connection is first seen and the other + * when it's ended (either by a FIN/RST packet or manually by the user). Both of these callbacks contain data about + * the connection (5-tuple, 4-byte hash key describing the connection, etc.) and also a pointer to a "user cookie", + * meaning a pointer to a structure provided by the user during the creation of the pcpp#TcpReassembly instance. The + * end connection callback also provides the reason for closing it ("naturally" or manually). + * + * __Basic Usage and APIs:__ + * - pcpp#TcpReassembly c'tor - Create an instance, provide the callbacks and the user cookie to the instance + * - pcpp#TcpReassembly#reassemblePacket() - Feed pcpp#TcpReassembly instance with packets + * - pcpp#TcpReassembly#closeConnection() - Manually close a connection by a flow key + * - pcpp#TcpReassembly#closeAllConnections() - Manually close all currently opened connections + * - pcpp#TcpReassembly#OnTcpMessageReady callback - Invoked when new data arrives on a certain connection. Contains the + * new data as well as connection data (5-tuple, flow key). + * - pcpp#TcpReassembly#OnTcpConnectionStart callback - Invoked when a new connection is identified + * - pcpp#TcpReassembly#OnTcpConnectionEnd callback - Invoked when a connection ends (either by FIN/RST or manually by + * the user). + * + * __Additional information:__ + * When the connection is closed the information is not being deleted from memory immediately. There is a delay between + * these moments. Existence of this delay is caused by two reasons: + * - pcpp#TcpReassembly#reassemblePacket() should detect the packets that arrive after the FIN packet has been received. + * - The user can use the information about connections managed by pcpp#TcpReassembly instance. Following methods are + * used for this purpose: pcpp#TcpReassembly#getConnectionInformation and pcpp#TcpReassembly#isConnectionOpen. + * Cleaning of memory can be performed automatically (the default behavior) by pcpp#TcpReassembly#reassemblePacket() or + * manually by calling pcpp#TcpReassembly#purgeClosedConnections in the user code. Automatic cleaning is performed once + * per second. + * + * The struct pcpp#TcpReassemblyConfiguration allows to setup the parameters of cleanup. Following parameters are + * supported: + * - pcpp#TcpReassemblyConfiguration#doNotRemoveConnInfo - if this member is set to false the automatic cleanup mode is + * applied. + * - pcpp#TcpReassemblyConfiguration#closedConnectionDelay - the value of delay expressed in seconds. The minimum value + * is 1. + * - pcpp#TcpReassemblyConfiguration#maxNumToClean - to avoid performance overhead when the cleanup is being performed, + * this parameter is used. It defines the maximum number of items to be removed per one call of + * pcpp#TcpReassembly#purgeClosedConnections. + * - pcpp#TcpReassemblyConfiguration#maxOutOfOrderFragments - the maximum number of unmatched fragments to keep per flow + * before missed fragments are considered lost. A value of 0 means unlimited. + * + */ + +/** + * @namespace pcpp + * @brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * @struct ConnectionData + * Represents basic TCP/UDP + IP connection data + */ + struct ConnectionData + { + /** Source IP address */ + IPAddress srcIP; + /** Destination IP address */ + IPAddress dstIP; + /** Source TCP/UDP port */ + uint16_t srcPort; + /** Destination TCP/UDP port */ + uint16_t dstPort; + /** A 4-byte hash key representing the connection */ + uint32_t flowKey; + /** Start TimeStamp of the connection */ + timeval startTime; + /** End TimeStamp of the connection */ + timeval endTime; + + /** + * A c'tor for this struct that basically zeros all members + */ + ConnectionData() : srcPort(0), dstPort(0), flowKey(0), startTime(), endTime() + {} + + /** + * Set startTime of Connection + * @param[in] startTimeValue integer value + */ + void setStartTime(const timeval& startTimeValue) + { + startTime = startTimeValue; + } + + /** + * Set endTime of Connection + * @param[in] endTimeValue integer value + */ + void setEndTime(const timeval& endTimeValue) + { + endTime = endTimeValue; + } + }; + + class TcpReassembly; + + /** + * @class TcpStreamData + * When following a TCP connection each packet may contain a piece of the data transferred between the client and + * the server. This class represents these pieces: each instance of it contains a piece of data, usually extracted + * from a single packet, as well as information about the connection + */ + class TcpStreamData + { + public: + /** + * A c'tor for this class that get data from outside and set the internal members + * @param[in] tcpData A pointer to buffer containing the TCP data piece + * @param[in] tcpDataLength The length of the buffer + * @param[in] missingBytes The number of missing bytes due to packet loss. + * @param[in] connData TCP connection information for this TCP data + * @param[in] timestamp when this packet was received + */ + TcpStreamData(const uint8_t* tcpData, size_t tcpDataLength, size_t missingBytes, const ConnectionData& connData, + timeval timestamp) + : m_Data(tcpData), m_DataLen(tcpDataLength), m_MissingBytes(missingBytes), m_Connection(connData), + m_Timestamp(timestamp) + {} + + /** + * A getter for the data buffer + * @return A pointer to the buffer + */ + const uint8_t* getData() const + { + return m_Data; + } + + /** + * A getter for buffer length + * @return Buffer length + */ + size_t getDataLength() const + { + return m_DataLen; + } + + /** + * A getter for missing byte count due to packet loss. + * @return Missing byte count + */ + size_t getMissingByteCount() const + { + return m_MissingBytes; + } + + /** + * Determine if bytes are missing. getMissingByteCount can be called to determine the number of missing bytes. + * @return true if bytes are missing. + */ + bool isBytesMissing() const + { + return getMissingByteCount() > 0; + } + + /** + * A getter for the connection data + * @return The const reference to connection data + */ + const ConnectionData& getConnectionData() const + { + return m_Connection; + } + + /** + * A getter for the timestamp of this packet + * @return The const timeval object with timestamp of this packet + */ + timeval getTimeStamp() const + { + return m_Timestamp; + } + + private: + const uint8_t* m_Data; + size_t m_DataLen; + size_t m_MissingBytes; + const ConnectionData& m_Connection; + timeval m_Timestamp; + }; + + /** + * @struct TcpReassemblyConfiguration + * A structure for configuring the TcpReassembly class + */ + struct TcpReassemblyConfiguration + { + /** The flag indicating whether to remove the connection data after a connection is closed */ + bool removeConnInfo; + + /** How long the closed connections will not be cleaned up. The value is expressed in seconds. If the value is + * set to 0 then TcpReassembly should use the default value. This parameter is only relevant if removeConnInfo + * is equal to true. + */ + uint32_t closedConnectionDelay; + + /** The maximum number of items to be cleaned up per one call of purgeClosedConnections. If the value is set to + * 0 then TcpReassembly should use the default value. This parameter is only relevant if removeConnInfo is equal + * to true. + */ + uint32_t maxNumToClean; + + /** The maximum number of fragments with a non-matching sequence-number to store per connection flow before + packets are assumed permanently missed. If the value is 0, TcpReassembly should keep out of order fragments + indefinitely, or until a message from the paired side is seen. + */ + uint32_t maxOutOfOrderFragments; + + /** To enable to clear buffer once packet contains data from a different side than the side seen before + */ + bool enableBaseBufferClearCondition; + + /** + * A c'tor for this struct + * @param[in] removeConnInfo The flag indicating whether to remove the connection data after a connection is + * closed. The default is true + * @param[in] closedConnectionDelay How long the closed connections will not be cleaned up. The value is + * expressed in seconds. If it's set to 0 the default value will be used. The default is 5. + * @param[in] maxNumToClean The maximum number of items to be cleaned up per one call of purgeClosedConnections. + * If it's set to 0 the default value will be used. The default is 30. + * @param[in] maxOutOfOrderFragments The maximum number of unmatched fragments to keep per flow before missed + * fragments are considered lost. The default is unlimited. + * @param[in] enableBaseBufferClearCondition To enable to clear buffer once packet contains data from a + * different side than the side seen before + */ + explicit TcpReassemblyConfiguration(bool removeConnInfo = true, uint32_t closedConnectionDelay = 5, + uint32_t maxNumToClean = 30, uint32_t maxOutOfOrderFragments = 0, + bool enableBaseBufferClearCondition = true) + : removeConnInfo(removeConnInfo), closedConnectionDelay(closedConnectionDelay), + maxNumToClean(maxNumToClean), maxOutOfOrderFragments(maxOutOfOrderFragments), + enableBaseBufferClearCondition(enableBaseBufferClearCondition) + {} + }; + + /** + * @class TcpReassembly + * A class containing the TCP reassembly logic. Please refer to the documentation at the top of TcpReassembly.h for + * understanding how to use this class + */ + class TcpReassembly + { + public: + /** + * An enum for connection end reasons + */ + enum ConnectionEndReason + { + /** Connection ended because of FIN or RST packet */ + TcpReassemblyConnectionClosedByFIN_RST, + /** Connection ended manually by the user */ + TcpReassemblyConnectionClosedManually + }; + + /** + * An enum for providing reassembly status for each processed packet + */ + enum ReassemblyStatus + { + /** + * The processed packet contains valid TCP payload, and its payload is processed by `OnMessageReadyCallback` + * callback function. The packet may be: + * 1. An in-order TCP packet, meaning `packet_sequence == sequence_expected`. + * Note if there's any buffered out-of-order packet waiting for this packet, their associated callbacks + * are called in this `reassemblePacket` call. + * 2. An out-of-order TCP packet which satisfy `packet_sequence < sequence_expected && packet_sequence + + * packet_payload_length > sequence_expected`. Note only the new data (the `[sequence_expected, + * packet_sequence + packet_payload_length]` part ) is processed by `OnMessageReadyCallback` callback + * function. + */ + TcpMessageHandled, + /** + * The processed packet is an out-of-order TCP packet, meaning `packet_sequence > sequence_expected`. It's + * buffered so no `OnMessageReadyCallback` callback function is called. The callback function for this + * packet maybe called LATER, under different circumstances: + * 1. When an in-order packet which is right before this packet arrives(case 1 and case 2 described in + * `TcpMessageHandled` section above). + * 2. When a FIN or RST packet arrives, which will clear the buffered out-of-order packets of this side. + * If this packet contains "new data", meaning `(packet_sequence <= sequence_expected) && + * (packet_sequence + packet_payload_length > sequence_expected)`, the new data is processed by + * `OnMessageReadyCallback` callback. + */ + OutOfOrderTcpMessageBuffered, + /** + * The processed packet is a FIN or RST packet with no payload. + * Buffered out-of-order packets will be cleared. + * If they contain "new data", the new data is processed by `OnMessageReadyCallback` callback. + */ + FIN_RSTWithNoData, + /** + * The processed packet is not a SYN/SYNACK/FIN/RST packet and has no payload. + * Normally it's just a bare ACK packet. + * It's ignored and no callback function is called. + */ + Ignore_PacketWithNoData, + /** + * The processed packet comes from a closed flow(an in-order FIN or RST is seen). + * It's ignored and no callback function is called. + */ + Ignore_PacketOfClosedFlow, + /** + * The processed packet is a restransmission packet with no new data, meaning the `packet_sequence + + * packet_payload_length < sequence_expected`. It's ignored and no callback function is called. + */ + Ignore_Retransimission, + /** + * The processed packet is not an IP packet. + * It's ignored and no callback function is called. + */ + NonIpPacket, + /** + * The processed packet is not a TCP packet. + * It's ignored and no callback function is called. + */ + NonTcpPacket, + /** + * The processed packet does not belong to any known TCP connection. + * It's ignored and no callback function is called. + * Normally this will be happen. + */ + Error_PacketDoesNotMatchFlow, + }; + + /** + * The type for storing the connection information + */ + typedef std::unordered_map ConnectionInfoList; + + /** + * @typedef OnTcpMessageReady + * A callback invoked when new data arrives on a connection + * @param[in] side The side this data belongs to (MachineA->MachineB or vice versa). The value is 0 or 1 where 0 + * is the first side seen in the connection and 1 is the second side seen + * @param[in] tcpData The TCP data itself + connection information + * @param[in] userCookie A pointer to the cookie provided by the user in TcpReassembly c'tor (or nullptr if no + * cookie provided) + */ + typedef void (*OnTcpMessageReady)(int8_t side, const TcpStreamData& tcpData, void* userCookie); + + /** + * @typedef OnTcpConnectionStart + * A callback invoked when a new TCP connection is identified (whether it begins with a SYN packet or not) + * @param[in] connectionData Connection information + * @param[in] userCookie A pointer to the cookie provided by the user in TcpReassembly c'tor (or nullptr if no + * cookie provided) + */ + typedef void (*OnTcpConnectionStart)(const ConnectionData& connectionData, void* userCookie); + + /** + * @typedef OnTcpConnectionEnd + * A callback invoked when a TCP connection is terminated, either by a FIN or RST packet or manually by the user + * @param[in] connectionData Connection information + * @param[in] reason The reason for connection termination: FIN/RST packet or manually by the user + * @param[in] userCookie A pointer to the cookie provided by the user in TcpReassembly c'tor (or nullptr if no + * cookie provided) + */ + typedef void (*OnTcpConnectionEnd)(const ConnectionData& connectionData, ConnectionEndReason reason, + void* userCookie); + + /** + * A c'tor for this class + * @param[in] onMessageReadyCallback The callback to be invoked when new data arrives + * @param[in] userCookie A pointer to an object provided by the user. This pointer will be returned when + * invoking the various callbacks. This parameter is optional, default cookie is nullptr + * @param[in] onConnectionStartCallback The callback to be invoked when a new connection is identified. This + * parameter is optional + * @param[in] onConnectionEndCallback The callback to be invoked when a new connection is terminated (either by + * a FIN/RST packet or manually by the user). This parameter is optional + * @param[in] config Optional parameter for defining special configuration parameters. If not set the default + * parameters will be set + */ + explicit TcpReassembly(OnTcpMessageReady onMessageReadyCallback, void* userCookie = nullptr, + OnTcpConnectionStart onConnectionStartCallback = nullptr, + OnTcpConnectionEnd onConnectionEndCallback = nullptr, + const TcpReassemblyConfiguration& config = TcpReassemblyConfiguration()); + + /** + * The most important method of this class which gets a packet from the user and processes it. If this packet + * opens a new connection, ends a connection or contains new data on an existing connection, the relevant + * callback will be called (TcpReassembly#OnTcpMessageReady, TcpReassembly#OnTcpConnectionStart, + * TcpReassembly#OnTcpConnectionEnd) + * @param[in] tcpData A reference to the packet to process + * @return A enum of `TcpReassembly::ReassemblyStatus`, indicating status of TCP reassembly + */ + ReassemblyStatus reassemblePacket(Packet& tcpData); + + /** + * The most important method of this class which gets a raw packet from the user and processes it. If this + * packet opens a new connection, ends a connection or contains new data on an existing connection, the relevant + * callback will be invoked (TcpReassembly#OnTcpMessageReady, TcpReassembly#OnTcpConnectionStart, + * TcpReassembly#OnTcpConnectionEnd) + * @param[in] tcpRawData A reference to the raw packet to process + * @return A enum of `TcpReassembly::ReassemblyStatus`, indicating status of TCP reassembly + */ + ReassemblyStatus reassemblePacket(RawPacket* tcpRawData); + + /** + * Close a connection manually. If the connection doesn't exist or already closed an error log is printed. This + * method will cause the TcpReassembly#OnTcpConnectionEnd to be invoked with a reason of + * TcpReassembly#TcpReassemblyConnectionClosedManually + * @param[in] flowKey A 4-byte hash key representing the connection. Can be taken from a ConnectionData instance + */ + void closeConnection(uint32_t flowKey); + + /** + * Close all open connections manually. This method will cause the TcpReassembly#OnTcpConnectionEnd to be + * invoked for each connection with a reason of TcpReassembly#TcpReassemblyConnectionClosedManually + */ + void closeAllConnections(); + + /** + * Get a map of all connections managed by this TcpReassembly instance (both connections that are open and those + * that are already closed) + * @return A map of all connections managed. Notice this map is constant and cannot be changed by the user + */ + const ConnectionInfoList& getConnectionInformation() const + { + return m_ConnectionInfo; + } + + /** + * Check if a certain connection managed by this TcpReassembly instance is currently opened or closed + * @param[in] connection The connection to check + * @return A positive number (> 0) if connection is opened, zero (0) if connection is closed, and a negative + * number (< 0) if this connection isn't managed by this TcpReassembly instance + */ + int isConnectionOpen(const ConnectionData& connection) const; + + /** + * Clean up the closed connections from the memory + * @param[in] maxNumToClean The maximum number of items to be cleaned up per one call. This parameter, when its + * value is not zero, overrides the value that was set by the constructor. + * @return The number of cleared items + */ + uint32_t purgeClosedConnections(uint32_t maxNumToClean = 0); + + private: + struct TcpFragment + { + uint32_t sequence; + size_t dataLength; + uint8_t* data; + timeval timestamp; + + TcpFragment() : sequence(0), dataLength(0), data(nullptr) + {} + ~TcpFragment() + { + delete[] data; + } + }; + + struct TcpOneSideData + { + IPAddress srcIP; + uint16_t srcPort; + uint32_t sequence; + PointerVector tcpFragmentList; + bool gotFinOrRst; + + TcpOneSideData() : srcPort(0), sequence(0), gotFinOrRst(false) + {} + }; + + struct TcpReassemblyData + { + bool closed; + int8_t numOfSides; + int8_t prevSide; + TcpOneSideData twoSides[2]; + ConnectionData connData; + + TcpReassemblyData() : closed(false), numOfSides(0), prevSide(-1) + {} + }; + + class OutOfOrderProcessingGuard + { + private: + bool& m_Flag; + + public: + explicit OutOfOrderProcessingGuard(bool& flag) : m_Flag(flag) + { + m_Flag = true; + } + + ~OutOfOrderProcessingGuard() + { + m_Flag = false; + } + + // Disable copy and move operations + OutOfOrderProcessingGuard(const OutOfOrderProcessingGuard&) = delete; + OutOfOrderProcessingGuard& operator=(const OutOfOrderProcessingGuard&) = delete; + }; + + typedef std::unordered_map ConnectionList; + typedef std::map> CleanupList; + + OnTcpMessageReady m_OnMessageReadyCallback; + OnTcpConnectionStart m_OnConnStart; + OnTcpConnectionEnd m_OnConnEnd; + void* m_UserCookie; + ConnectionList m_ConnectionList; + ConnectionInfoList m_ConnectionInfo; + CleanupList m_CleanupList; + bool m_RemoveConnInfo; + uint32_t m_ClosedConnectionDelay; + uint32_t m_MaxNumToClean; + size_t m_MaxOutOfOrderFragments; + time_t m_PurgeTimepoint; + bool m_EnableBaseBufferClearCondition; + bool m_ProcessingOutOfOrder = false; + + void checkOutOfOrderFragments(TcpReassemblyData* tcpReassemblyData, int8_t sideIndex, bool cleanWholeFragList); + + void handleFinOrRst(TcpReassemblyData* tcpReassemblyData, int8_t sideIndex, uint32_t flowKey, bool isRst); + + void closeConnectionInternal(uint32_t flowKey, ConnectionEndReason reason); + + void insertIntoCleanupList(uint32_t flowKey); + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/TelnetLayer.h b/Packet++/header/pcapplusplus/TelnetLayer.h new file mode 100644 index 0000000000..241c04f39a --- /dev/null +++ b/Packet++/header/pcapplusplus/TelnetLayer.h @@ -0,0 +1,363 @@ +#pragma once + +#include "pcapplusplus/Layer.h" + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * Class for representing the Telnet Layer + */ + class TelnetLayer : public Layer + { + private: + // Position iterator for next command + size_t lastPositionOffset; + + // Checks if position is a data field + bool isDataField(uint8_t* pos) const; + // Checks if position is a command field + bool isCommandField(uint8_t* pos) const; + // Returns distance to next IAC + size_t distanceToNextIAC(uint8_t* startPos, size_t maxLength); + // Returns length of provided field + size_t getFieldLen(uint8_t* startPos, size_t maxLength); + // Get position of next data field + uint8_t* getNextDataField(uint8_t* pos, size_t len); + // Get position of next command field + uint8_t* getNextCommandField(uint8_t* pos, size_t len); + // Get options of provided field + int16_t getSubCommand(uint8_t* pos, size_t len); + // Get data of provided field + uint8_t* getCommandData(uint8_t* pos, size_t& slen); + + public: + /** + * Telnet Command Indicator + */ + enum class TelnetCommand : int + { + /// Indicator to parser reached end of packet + TelnetCommandEndOfPacket = -1, + + /// End of file + EndOfFile = 236, + /// Suspend current process + Suspend, + /// Abort Process + Abort, + /// End of Record + EndOfRecordCommand, + /// Marks the end of a Telnet option subnegotiation, used with the SB code to specify more specific option + /// parameters. + SubnegotiationEnd, + /// Null command; does nothing. + NoOperation, + /// Used to mark the end of a sequence of data that the recipient should scan for urgent Telnet commands. + DataMark, + /// Represents the pressing of the “break” or “attention” key on the terminal. + Break, + /// Tells the recipient to interrupt, abort, suspend or terminate the process currently in use. + InterruptProcess, + /// Instructs the remote host to continue running the current process, but discard all remaining output from + /// it. This may be needed if a program starts to send unexpectedly large amounts of data to the user. + AbortOutput, + /// May be used to check that the remote host is still “alive”. When this character is sent the remote host + /// returns some type of output to indicate that it is still functioning. + AreYouThere, + /// Instructs the recipient to delete the last undeleted character from the data stream. Used to “undo” the + /// sending of a character. + EraseCharacter, + /// Tells the recipient to delete all characters from the data stream back to (but not including) the last + /// end of line (CR+LF) sequence. + EraseLine, + /// Used in Telnet half-duplex mode to signal the other device that it may transmit. + GoAhead, + /// Marks the beginning of a Telnet option subnegotiation, used when an option requires the client and + /// server to exchange parameters. + Subnegotiation, + /// Indicates that the device sending this code is willing to perform or continue performing a particular + /// option. + WillPerform, + /// Indicates that the device sending this code is either not willing to perform a particular option, or is + /// now refusing to continue to perform it. + WontPerform, + /// Requests that the other device perform a particular option or confirms the expectation that the other + /// device will perform that option. + DoPerform, + /// Specifies that the other party not perform an option, or confirms a device’s expectation that the other + /// party not perform an option. + DontPerform, + /// Precedes command values 240 through 254 as described above. A pair of IAC bytes in a row represents the + /// data value 255. + InterpretAsCommand + }; + + /** + * Telnet Options + */ + enum class TelnetOption : int + { + /// Internal return for no option detected + TelnetOptionNoOption = -1, + + /// Binary Transmission RFC856 https://www.iana.org/go/rfc856 + TransmitBinary = 0, + /// Echo RFC857 https://www.iana.org/go/rfc857 + Echo, + /// Reconnection + Reconnection, + /// Suppress Go Ahead RFC858 https://www.iana.org/go/rfc858 + SuppressGoAhead, + /// Negotiate approximate message size + ApproxMsgSizeNegotiation, + /// Status RFC859 https://www.iana.org/go/rfc859 + Status, + /// Timing Mark RFC860 https://www.iana.org/go/rfc860 + TimingMark, + /// RCTE, Remote Controlled Transmission and Echo RFC726 https://www.iana.org/go/rfc726 + RemoteControlledTransAndEcho, + /// Output Line Width + OutputLineWidth, + /// Output Page Size + OutputPageSize, + /// NAOCRD, Negotiate About Output Carriage-Return Disposition RFC652 https://www.iana.org/go/rfc652 + OutputCarriageReturnDisposition, + /// NAOHTS, Negotiate About Output Horizontal Tabstops RFC653 https://www.iana.org/go/rfc653 + OutputHorizontalTabStops, + /// NAOHTD, Negotiate About Output Horizontal Tab Disposition RFC654 https://www.iana.org/go/rfc654 + OutputHorizontalTabDisposition, + /// NAOFFD, Negotiate About Output Formfeed Disposition RFC655 https://www.iana.org/go/rfc655 + OutputFormfeedDisposition, + /// NAOVTS, Negotiate About Vertical Tabstops RFC656 https://www.iana.org/go/rfc656 + OutputVerticalTabStops, + /// NAOVTD, Negotiate About Output Vertcial Tab Disposition RFC657 https://www.iana.org/go/rfc657 + OutputVerticalTabDisposition, + /// NAOLFD, Negotiate About Output Linefeed Disposition RFC658 https://www.iana.org/go/rfc658 + OutputLinefeedDisposition, + /// Extended ASCII RFC698 https://www.iana.org/go/rfc698 + ExtendedASCII, + /// Logout RFC727 https://www.iana.org/go/rfc727 + Logout, + /// BM, Byte Macro RFC735 https://www.iana.org/go/rfc735 + ByteMacro, + /// Data Entry Terminal RFC1043 - RFC732 https://www.iana.org/go/rfc1043 https://www.iana.org/go/rfc732 + DataEntryTerminal, + /// SUPDUP RFC736 - RFC734 https://www.iana.org/go/rfc736 https://www.iana.org/go/rfc734 + SUPDUP, + /// SUPDUP Output RFC749 https://www.iana.org/go/rfc749 + SUPDUPOutput, + /// Send Location RFC779 https://www.iana.org/go/rfc779 + SendLocation, + /// Terminal Type RFC1091 https://www.iana.org/go/rfc1091 + TerminalType, + /// End of record RFC885 https://www.iana.org/go/rfc885 + EndOfRecordOption, + /// TUID, TACACS User Identification RFC927 https://www.iana.org/go/rfc927 + TACACSUserIdentification, + /// OUTMRK, Output Marking RFC933 https://www.iana.org/go/rfc933 + OutputMarking, + /// TTYLOC, Terminal Location Number RFC946 https://www.iana.org/go/rfc946 + TerminalLocationNumber, + /// Telnet 3270 Regime RFC1041 https://www.iana.org/go/rfc1041 + Telnet3270Regime, + /// X.3 PAD RFC1053 https://www.iana.org/go/rfc1053 + X3Pad, + /// NAWS, Negotiate About Window Size RFC1073 https://www.iana.org/go/rfc1073 + NegotiateAboutWindowSize, + /// Terminal Speed RFC1079 https://www.iana.org/go/rfc1079 + TerminalSpeed, + /// Remote Flow Control RFC1372 https://www.iana.org/go/rfc1372 + RemoteFlowControl, + /// Line Mode RFC1184 https://www.iana.org/go/rfc1184 + Linemode, + /// X Display Location RFC1096 https://www.iana.org/go/rfc1096 + XDisplayLocation, + /// Environment Option RFC1408 https://www.iana.org/go/rfc1408 + EnvironmentOption, + /// Authentication Option RFC2941 https://www.iana.org/go/rfc2941 + AuthenticationOption, + /// Encryption Option RFC2946 https://www.iana.org/go/rfc2946 + EncryptionOption, + /// New Environment Option RFC1572 https://www.iana.org/go/rfc1572 + NewEnvironmentOption, + /// TN3270E RFC2355 https://www.iana.org/go/rfc2355 + TN3270E, + /// X Server Authentication + XAuth, + /// Charset RFC2066 https://www.iana.org/go/rfc2066 + Charset, + /// RSP, Telnet Remote Serial Port + TelnetRemoteSerialPort, + /// Com Port Control Option RFC2217 https://www.iana.org/go/rfc2217 + ComPortControlOption, + /// Telnet Suppress Local Echo + TelnetSuppressLocalEcho, + /// Telnet Start TLS + TelnetStartTLS, + /// Kermit RFC2840 https://www.iana.org/go/rfc2840 + Kermit, + /// Send URL + SendURL, + /// Forward X Server + ForwardX, + + /// Telnet Option Pragma Logon + TelOptPragmaLogon = 138, + /// Telnet Option SSPI Logon + TelOptSSPILogon, + /// Telnet Option Pragma Heartbeat + TelOptPragmaHeartbeat, + + /// Extended option list + ExtendedOptions = 255 + }; + + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + TelnetLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : Layer(data, dataLen, prevLayer, packet, Telnet) + { + lastPositionOffset = SIZE_MAX; + }; + + /** + * Get the Telnet data as readable string + * @param[in] removeEscapeCharacters Whether non-alphanumerical characters should be removed or not + * @return Full payload as readable string, empty if Telnet packet contains control commands/options. + */ + std::string getDataAsString(bool removeEscapeCharacters = true); + + /** + * Get the total number of detected Telnet commands + * @return size_t The number of Telnet commands + */ + size_t getTotalNumberOfCommands(); + + /** + * Returns the number of occurrences of provided command + * @param[in] command Telnet command to count + * @return size_t Number of occurrences of command + */ + size_t getNumberOfCommands(TelnetCommand command); + + /** + * Returns the first command of packet + * @return TelnetCommand First detected command value, TelnetCommandEndOfPacket if there is no command field + */ + TelnetCommand getFirstCommand(); + + /** + * Returns the next command of packet. Uses an internal iterator. The iterator resets when reached end of + * packet. + * @return TelnetCommand Detected command value, TelnetCommandEndOfPacket if reached the end of packet. + */ + TelnetCommand getNextCommand(); + + /** + * Returns the option of current command. Uses an internal iterator. Iterator can be moved with getNextCommand + * @return TelnetOption Option of current command + */ + TelnetOption getOption(); + + /** + * Returns the option of provided command. It will return option of first occurrence of the command + * @param[in] command Telnet command to search + * @return TelnetOption Option of the command. Returns TelnetOptionNoOption if the provided command not found. + */ + TelnetOption getOption(TelnetCommand command); + + /** + * Returns the data of current command. Uses an internal iterator. Iterator can be moved with getNextCommand + * @param[out] length Length of the data of current command + * @return uint8_t* Pointer to the data of current command. nullptr if there is no data for this command. + */ + uint8_t* getOptionData(size_t& length); + + /** + * Returns the data of provided command. It will return data of first occurrence of the command + * @param[in] command Telnet command to search + * @param[out] length Length of the data of current command + * @return uint8_t* Pointer to the data of current command. nullptr if there is no data for this command or if + * can't find the command. + */ + uint8_t* getOptionData(TelnetCommand command, size_t& length); + + /** + * Convert the Telnet Command to readable string + * @param[in] val Value of the command + * @return The Telnet Command as readable string + */ + static std::string getTelnetCommandAsString(TelnetCommand val); + + /** + * Convert the Telnet option to readable string + * @param[in] val Value of the option + * @return The Telnet Option as readable string + */ + static std::string getTelnetOptionAsString(TelnetOption val); + + /** + * A static method that checks whether the port is considered as Telnet + * @param[in] port The port number to be checked + */ + static bool isTelnetPort(uint16_t port) + { + return port == 23; + } + + /** + * A static method that takes a byte array and detects whether it is a Telnet message + * @param[in] data A byte array + * @param[in] dataSize The byte array size (in bytes) + * @return True if the data is identified as Telnet message + */ + static bool isDataValid(const uint8_t* data, size_t dataSize) + { + return data && dataSize; + } + + // overridden methods + + /// Parses the next layer. Telnet is the always last so does nothing for this layer + void parseNextLayer() + {} + + /** + * @return Get the size of the layer + */ + size_t getHeaderLen() const + { + return m_DataLen; + } + + /// Does nothing for this layer + void computeCalculateFields() + {} + + /** + * @return The OSI layer level of Telnet (Application Layer). + */ + OsiModelLayer getOsiModelLayer() const + { + return OsiModelApplicationLayer; + } + + /** + * @return Returns the protocol info as readable string + */ + std::string toString() const; + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/TextBasedProtocol.h b/Packet++/header/pcapplusplus/TextBasedProtocol.h new file mode 100644 index 0000000000..c325fd8315 --- /dev/null +++ b/Packet++/header/pcapplusplus/TextBasedProtocol.h @@ -0,0 +1,287 @@ +#pragma once + +#include +#include "pcapplusplus/Layer.h" + +/// @file + +namespace pcpp +{ + +/** End of header */ +#define PCPP_END_OF_TEXT_BASED_PROTOCOL_HEADER "" + + class TextBasedProtocolMessage; + + // -------- Class HeaderField ----------------- + + /** + * @class HeaderField + * A wrapper class for each text-based-protocol header field, e.g "Host", "Cookie", "Content-Length", "Via", + * "Call-ID", etc. Each field contains a name (e.g "Host") and a value (e.g "www.wikipedia.org"). The user can get + * and set both of them through dedicated methods. The separator between header fields is either CRLF ("\r\n\") or + * LF ("\n") in more rare cases, which means every HeaderField instance is responsible for wrapping and parsing a + * header field from the previous CRLF (not inclusive) until the next CRLF/LF (inclusive) A special case is with the + * end of a header, meaning 2 consecutive CRLFs ("\r\n\r\n") or consecutive LFs ("\n\n"). PcapPlusPlus treats the + * first CRLF/LF as part of the last field in the header, and the second CRLF is an HeaderField instance of its own + * which name and values are an empty string ("") or pcpp::PCPP_END_OF_TEXT_BASED_PROTOCOL_HEADER + */ + class HeaderField + { + friend class TextBasedProtocolMessage; + + public: + ~HeaderField(); + + /** + * A copy constructor that creates a new instance out of an existing HeaderField instance. The copied instance + * will not have shared resources with the original instance, meaning all members and properties are copied + * @param[in] other The original instance to copy from + */ + HeaderField(const HeaderField& other); + + /** + * Assignment operator for this class. This method copies the data from the other instance and will not share + * any resources with it. Also, if the instance already contains data it will be deleted or zeroed + * @param[in] other The instance to assign from + * @return A reference to the assignee + */ + HeaderField& operator=(const HeaderField& other); + + /** + * @return The field length in bytes, meaning count of all characters from the previous CRLF (not inclusive) + * until the next CRLF (inclusive) For example: the field "Host: www.wikipedia.org\r\n" will have the length of + * 25 + */ + size_t getFieldSize() const + { + return m_FieldSize; + } + + /** + * @return The field name as string. Notice the return data is copied data, so changing it won't change the + * packet data + */ + std::string getFieldName() const; + + /** + * @return The field value as string. Notice the return data is copied data, so changing it won't change the + * packet data + */ + std::string getFieldValue() const; + + /** + * A setter for field value + * @param[in] newValue The new value to set to the field. Old value will be deleted + * @return True if setting the value was completed successfully, false otherwise + */ + bool setFieldValue(const std::string& newValue); + + /** + * Get an indication whether the field is a field that ends the header (meaning contain only CRLF - see class + * explanation) + * @return True if this is a end-of-header field, false otherwise + */ + bool isEndOfHeader() const + { + return m_IsEndOfHeaderField; + } + + private: + HeaderField(const std::string& name, const std::string& value, char nameValueSeparator, + bool spacesAllowedBetweenNameAndValue); + HeaderField(TextBasedProtocolMessage* TextBasedProtocolMessage, int offsetInMessage, char nameValueSeparator, + bool spacesAllowedBetweenNameAndValue); + + char* getData() const; + void setNextField(HeaderField* nextField); + HeaderField* getNextField() const; + void initNewField(const std::string& name, const std::string& value); + void attachToTextBasedProtocolMessage(TextBasedProtocolMessage* message, int fieldOffsetInMessage); + + uint8_t* m_NewFieldData; + TextBasedProtocolMessage* m_TextBasedProtocolMessage; + int m_NameOffsetInMessage; + size_t m_FieldNameSize; + int m_ValueOffsetInMessage; + size_t m_FieldValueSize; + size_t m_FieldSize; + HeaderField* m_NextField; + bool m_IsEndOfHeaderField; + char m_NameValueSeparator; + bool m_SpacesAllowedBetweenNameAndValue; + }; + + // -------- Class TextBasedProtocolMessage ----------------- + + /** + * @class TextBasedProtocolMessage + * An abstract base class that wraps text-based-protocol header layers (both requests and responses). It is the base + * class for all those layers. This class is not meant to be instantiated, hence the protected c'tor + */ + class TextBasedProtocolMessage : public Layer + { + friend class HeaderField; + + public: + ~TextBasedProtocolMessage(); + + /** + * Get a pointer to a header field by name. The search is case insensitive, meaning if a field with name "Host" + * exists and the fieldName parameter is "host" (all letter are lower case), this method will return a pointer + * to "Host" field + * @param[in] fieldName The field name + * @param[in] index Optional parameter. If the field name appears more than once, this parameter will indicate + * which field to get. The default value is 0 (get the first appearance of the field name as appears on the + * packet) + * @return A pointer to an HeaderField instance, or nullptr if field doesn't exist + */ + HeaderField* getFieldByName(std::string fieldName, int index = 0) const; + + /** + * @return A pointer to the first header field exists in this message, or nullptr if no such field exists + */ + HeaderField* getFirstField() const + { + return m_FieldList; + } + + /** + * Get the field which appears after a certain field + * @param[in] prevField A pointer to the field + * @return The field after prevField or nullptr if prevField is the last field. If prevField is nullptr, this + * method will return nullptr + */ + HeaderField* getNextField(HeaderField* prevField) const + { + if (prevField != nullptr) + return prevField->getNextField(); + else + return nullptr; + } + + /** + * @return The number of header fields currently in the layer (not including CRLF at the end of the header) + */ + int getFieldCount() const; + + /** + * Add a new header field to this message. This field will be added last (before the end-of-header field) + * @param[in] fieldName The field name + * @param[in] fieldValue The field value + * @return A pointer to the newly created header field, or nullptr if the field could not be created + */ + virtual HeaderField* addField(const std::string& fieldName, const std::string& fieldValue); + + /** + * Add a new header field to this message. This field will be added last (before the end-of-header field) + * @param[in] newField The header field to add + * @return A pointer to the newly created header field, or nullptr if the field could not be created + */ + virtual HeaderField* addField(const HeaderField& newField); + + /** + * Add the special end-of-header field (see the explanation in HeaderField) + * @return A pointer to the newly created header field, or nullptr if the field could not be created + */ + HeaderField* addEndOfHeader(); + + /** + * Insert a new field after an existing field + * @param[in] prevField A pointer to the existing field. If it's nullptr the new field will be added as first + * field + * @param[in] fieldName The field name + * @param[in] fieldValue The field value + * @return A pointer to the newly created header field, or nullptr if the field could not be created + */ + virtual HeaderField* insertField(HeaderField* prevField, const std::string& fieldName, + const std::string& fieldValue); + + /** + * Insert a new field after an existing field + * @param[in] prevFieldName A name of an existing field. If the field doesn't exist nullptr will be returned. + * If field name is empty ('') the new field will be added as first field + * @param[in] fieldName The field name + * @param[in] fieldValue The field value + * @return A pointer to the newly created header field, or nullptr if the field could not be created + */ + virtual HeaderField* insertField(std::string prevFieldName, const std::string& fieldName, + const std::string& fieldValue); + + /** + * Insert a new field after an existing field + * @param[in] prevField A pointer to the existing field + * @param[in] newField The header field to add + * @return A pointer to the newly created header field, or nullptr if the field could not be created + */ + virtual HeaderField* insertField(HeaderField* prevField, const HeaderField& newField); + + /** + * Remove a field from the message + * @param[in] fieldToRemove A pointer to the field that should be removed + * @return True if the field was removed successfully, or false otherwise (for example: if fieldToRemove is + * nullptr, if it doesn't exist in the message, or if the removal failed) + */ + bool removeField(HeaderField* fieldToRemove); + + /** + * Remove a field from the message + * @param[in] fieldName The name of the field that should be removed + * @param[in] index Optional parameter. If the field name appears more than once, this parameter will indicate + * which field to remove. The default value is 0 (remove the first appearance of the field name as appears on + * the packet) + * @return True if the field was removed successfully, or false otherwise (for example: if fieldName doesn't + * exist in the message, or if the removal failed) + */ + bool removeField(std::string fieldName, int index = 0); + + /** + * Indicate whether the header is complete (ending with end-of-header "\r\n\r\n" or "\n\n") or spread over more + * packets + * @return True if the header is complete or false if not + */ + bool isHeaderComplete() const; + + // implement Layer's abstract methods + + /** + * Currently set only PayloadLayer for the rest of the data + */ + virtual void parseNextLayer(); + + /** + * @return The message length + */ + size_t getHeaderLen() const; + + /** + * Does nothing for this class + */ + virtual void computeCalculateFields(); + + protected: + TextBasedProtocolMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, + ProtocolType protocol); + TextBasedProtocolMessage() : m_FieldList(nullptr), m_LastField(nullptr), m_FieldsOffset(0) + {} + + // copy c'tor + TextBasedProtocolMessage(const TextBasedProtocolMessage& other); + TextBasedProtocolMessage& operator=(const TextBasedProtocolMessage& other); + + void copyDataFrom(const TextBasedProtocolMessage& other); + + void parseFields(); + void shiftFieldsOffset(HeaderField* fromField, int numOfBytesToShift); + + // abstract methods + virtual char getHeaderFieldNameValueSeparator() const = 0; + virtual bool spacesAllowedBetweenHeaderFieldNameAndValue() const = 0; + + HeaderField* m_FieldList; + HeaderField* m_LastField; + int m_FieldsOffset; + std::multimap m_FieldNameToFieldMap; + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/TpktLayer.h b/Packet++/header/pcapplusplus/TpktLayer.h new file mode 100644 index 0000000000..c5d9ca9254 --- /dev/null +++ b/Packet++/header/pcapplusplus/TpktLayer.h @@ -0,0 +1,147 @@ +#pragma once + +#include "pcapplusplus/EthLayer.h" +#include "pcapplusplus/Layer.h" + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * @struct tpkthdr + * Represents a TPKT protocol header + */ +#pragma pack(push, 1) + struct tpkthdr + { + /** message version */ + uint8_t version; + /** message reserved */ + uint8_t reserved; + /** message length */ + uint16_t length; + }; +#pragma pack(pop) + + /** + * @class TpktLayer + * Represents a TPKT (Transport Service on top of the TCP) protocol layer + */ + class TpktLayer : public Layer + { + public: + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data (will be casted to @ref tpkthdr) + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + TpktLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : Layer(data, dataLen, prevLayer, packet, TPKT) + {} + + /** + * A constructor that allocates a new TPKT header + * @param[in] version Protocol version number + * @param[in] length Packet length + */ + TpktLayer(uint8_t version, uint16_t length); + + virtual ~TpktLayer() + {} + + /** + * @return TPKT reserved + */ + uint8_t getReserved() const; + + /** + * @return TPKT version + */ + uint8_t getVersion() const; + + /** + * @return TPKT length + */ + uint16_t getLength() const; + + /** + * Set the value of the version + * @param[in] version The value of the version + */ + void setVersion(uint8_t version) const; + + /** + * Set the value of the length + * @param[in] length The value of the length + */ + void setLength(uint16_t length) const; + + /** + * @return Size of @ref tpkthdr + */ + size_t getHeaderLen() const override + { + return sizeof(tpkthdr); + } + + /** + * Does nothing for this layer + */ + void computeCalculateFields() override + {} + + /** + * Currently parses the rest of the packet as a COTP protocol or generic payload (PayloadLayer) + */ + void parseNextLayer() override; + + /** + * A static method that checks whether a source or dest port match those associated with the TPKT protocol + * @param[in] portSrc Source port number to check + * @param[in] portDst Dest port number to check + * @return True if the source or dest port match those associated with the TPKT protocol + */ + static bool isTpktPort(uint16_t portSrc, uint16_t portDst) + { + return portSrc == 102 || portDst == 102; + } + + /** + * A static method that takes a byte array and detects whether it is a TPKT message + * @param[in] data A byte array + * @param[in] dataSize The byte array size (in bytes) + * @return True if the data size is greater or equal than the size of tpkthdr + */ + static bool isDataValid(const uint8_t* data, size_t dataSize) + { + return data && dataSize >= sizeof(tpkthdr); + } + + std::string toString() const override; + + OsiModelLayer getOsiModelLayer() const override + { + return OsiModelTransportLayer; + } + + private: + /** + * Get a pointer to the TPKT header. Data can be retrieved through the + * other methods of this layer. Notice the return value points directly to the data, so every change will change + * the actual packet data + * @return A pointer to the @ref tpkthdr + */ + tpkthdr* getTpktHeader() const + { + return (tpkthdr*)m_Data; + } + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/UdpLayer.h b/Packet++/header/pcapplusplus/UdpLayer.h new file mode 100644 index 0000000000..79639d8205 --- /dev/null +++ b/Packet++/header/pcapplusplus/UdpLayer.h @@ -0,0 +1,114 @@ +#pragma once + +#include "pcapplusplus/Layer.h" + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * @struct udphdr + * Represents an UDP protocol header + */ +#pragma pack(push, 1) + struct udphdr + { + /** Source port */ + uint16_t portSrc; + /** Destination port */ + uint16_t portDst; + /** Length of header and payload in bytes */ + uint16_t length; + /** Error-checking of the header and data */ + uint16_t headerChecksum; + }; +#pragma pack(pop) + + /** + * @class UdpLayer + * Represents an UDP (User Datagram Protocol) protocol layer + */ + class UdpLayer : public Layer + { + public: + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data (will be casted to @ref udphdr) + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + UdpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : Layer(data, dataLen, prevLayer, packet, UDP) + {} + + /** + * A constructor that allocates a new UDP header with source and destination ports + * @param[in] portSrc Source UDP port address + * @param[in] portDst Destination UDP port + */ + UdpLayer(uint16_t portSrc, uint16_t portDst); + + /** + * Get a pointer to the UDP header. Notice this points directly to the data, so every change will change the + * actual packet data + * @return A pointer to the @ref udphdr + */ + udphdr* getUdpHeader() const + { + return (udphdr*)m_Data; + } + + /** + * @return UDP source port + */ + uint16_t getSrcPort() const; + + /** + * @return UDP destination port + */ + uint16_t getDstPort() const; + + /** + * Calculate the checksum from header and data and possibly write the result to @ref udphdr#headerChecksum + * @param[in] writeResultToPacket If set to true then checksum result will be written to @ref + * udphdr#headerChecksum + * @return The checksum result + */ + uint16_t calculateChecksum(bool writeResultToPacket); + + // implement abstract methods + + /** + * Currently identifies the following next layers: DnsLayer, DhcpLayer, VxlanLayer, SipRequestLayer, + * SipResponseLayer, RadiusLayer. Otherwise sets PayloadLayer + */ + void parseNextLayer(); + + /** + * @return Size of @ref udphdr + */ + size_t getHeaderLen() const + { + return sizeof(udphdr); + } + + /** + * Calculate @ref udphdr#headerChecksum field + */ + void computeCalculateFields(); + + std::string toString() const; + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelTransportLayer; + } + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/VlanLayer.h b/Packet++/header/pcapplusplus/VlanLayer.h new file mode 100644 index 0000000000..f7f1bd2fe8 --- /dev/null +++ b/Packet++/header/pcapplusplus/VlanLayer.h @@ -0,0 +1,148 @@ +#pragma once + +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/EthLayer.h" + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + + /** + * @struct vlan_header + * Represents a VLAN header + */ +#pragma pack(push, 1) + struct vlan_header + { + /** + @verbatim + 0 1 2 + 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |Prio |C| VLAN ID | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + @endverbatim + */ + uint16_t vlan; + /** Ethernet type for next layer */ + uint16_t etherType; + }; +#pragma pack(pop) + + /** + * @class VlanLayer + * Represents a VLAN tunnel layer + */ + class VlanLayer : public Layer + { + public: + /** A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + VlanLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : Layer(data, dataLen, prevLayer, packet, VLAN) + {} + + /** + * A constructor that allocates a new VLAN header + * @param[in] vlanID VLAN ID + * @param[in] cfi CFI value + * @param[in] priority Priority value + * @param[in] etherType Protocol EtherType of the next layer. It's an optional parameter, a value of 0 will be + * set if not provided + */ + VlanLayer(const uint16_t vlanID, bool cfi, uint8_t priority, uint16_t etherType = 0); + + ~VlanLayer() + {} + + /** + * Get a pointer to the VLAN header. Notice this points directly to the data, so every change will change the + * actual packet data + * @return A pointer to the vlan_header + */ + vlan_header* getVlanHeader() const + { + return (vlan_header*)m_Data; + } + + /** + * Get the VLAN ID value. This method differs from vlan_header#vlanID because vlan_header#vlanID is 12 bits long + * in a 16 bit field. This methods extracts only the 12 bit relevant for the VLAN ID + * @return VLAN ID value + * @todo Verify it works in big endian machines as well + */ + uint16_t getVlanID() const; + + /** + * @return The CFI bit value + * @todo Verify it works in big endian machines as well + */ + uint8_t getCFI() const; + + /** + * @return The priority value + * @todo Verify it works in big endian machines as well + */ + uint8_t getPriority() const; + + /** + * Set VLAN ID. This method differs from setting vlan_header#vlanID because vlan_header#vlanID is 12 bits long + * in a 16 bit field. This methods sets only the 12 bit relevant for the VLAN ID + * @param[in] id The VLAN ID to set + * @todo Verify it works in big endian machines as well + */ + void setVlanID(uint16_t id); + + /** + * Set CFI bit + * @param[in] cfi The CFI bit to set + * @todo Verify it works in big endian machines as well + */ + void setCFI(bool cfi); + + /** + * Set priority value + * @param[in] priority The priority value to set + * @todo Verify it works in big endian machines as well + */ + void setPriority(uint8_t priority); + + // implement abstract methods + + /** + * Currently identifies the following next layers: IPv4Layer, IPv6Layer, ArpLayer, VlanLayer, MplsLayer. + * Otherwise sets PayloadLayer + */ + void parseNextLayer(); + + /** + * @return Size of vlan_header + */ + size_t getHeaderLen() const + { + return sizeof(vlan_header); + } + + /** + * Calculate the EtherType for known protocols: IPv4, IPv6, ARP, VLAN + */ + void computeCalculateFields(); + + std::string toString() const; + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelDataLinkLayer; + } + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/VrrpLayer.h b/Packet++/header/pcapplusplus/VrrpLayer.h new file mode 100644 index 0000000000..5e9eaeb2fb --- /dev/null +++ b/Packet++/header/pcapplusplus/VrrpLayer.h @@ -0,0 +1,477 @@ +#pragma once + +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/IpAddress.h" +#include + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + /** + For more info see: + https://datatracker.ietf.org/doc/html/rfc2338 + https://datatracker.ietf.org/doc/html/rfc3768 + https://datatracker.ietf.org/doc/html/rfc5798 + */ + + /* VRRPv2 Packet Format + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |Version| Type | Virtual Rtr ID| Priority | Count IP Addrs| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Auth Type | Adver Int | Checksum | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | IP Address (1) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | . | + | . | + | . | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | IP Address (n) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Authentication Data (1) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Authentication Data (2) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + + /* VRRPv3 Packet Format + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | IPv4 Fields or IPv6 Fields | + ... ... + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |Version| Type | Virtual Rtr ID| Priority |Count IPvX Addr| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |(rsvd) | Max Adver Int | Checksum | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + + + + | IPvX Address(es) | + + + + + + + + + + + + + | | + + + + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + + /** + * @struct vrrp_header + * VRRP generic header + */ + struct vrrp_header + { +#if (BYTE_ORDER == LITTLE_ENDIAN) + /** Type */ + uint8_t type : 4; + + /** Version bits */ + uint8_t version : 4; +#else + /** Version bits */ + uint8_t version : 4; + + /** Type */ + uint8_t type : 4; +#endif + /** The Virtual Router Identifier (VRID) field identifies the virtual router this packet is reporting status + * for*/ + uint8_t vrId; + + /** This specifies the sending VRRP router's priority for the virtual router */ + uint8_t priority; + + /** Specifies how many IPvX addresses are present in this Packet */ + uint8_t ipAddrCount; + + /** This specifies authentication type(v2) or (Max) Advertisement interval (in seconds(v2) or + * centi-seconds(v3)). */ + uint16_t authTypeAdvInt; + + /** This specifies checksum field that is used to detect data corruption in the VRRP message. + * VRRPv2 uses normal checksum algorithm, while VRRPv3 uses "pseudo-header" checksum algorithm. */ + uint16_t checksum; + + /** This specifies one or more IPvX addresses that are associated with the virtual router. */ + uint8_t* ipAddresses[]; + }; + + /** + * @class VrrpLayer + * A base class for all VRRP (Virtual Router Redundancy Protocol) protocol classes. This is an abstract class and + * cannot be instantiated, only its child classes can be instantiated. The inherited classes represent the different + * versions of the protocol: VRRPv2 and VRRPv3 + */ + class VrrpLayer : public Layer + { + private: + bool addIPAddressesAt(const std::vector& ipAddresses, int offset); + + uint8_t getIPAddressLen() const; + + bool isIPAddressValid(IPAddress& ipAddress) const; + + uint8_t* getFirstIPAddressPtr() const; + + uint8_t* getNextIPAddressPtr(uint8_t* ipAddressPtr) const; + + IPAddress getIPAddressFromData(uint8_t* data) const; + + void copyIPAddressToData(uint8_t* data, const IPAddress& ipAddress) const; + + IPAddress::AddressType m_AddressType; + + protected: + VrrpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, ProtocolType vrrpVer, + IPAddress::AddressType addressType) + : Layer(data, dataLen, prevLayer, packet, vrrpVer), m_AddressType(addressType) + {} + + explicit VrrpLayer(ProtocolType subProtocol, uint8_t virtualRouterId, uint8_t priority); + + vrrp_header* getVrrpHeader() const + { + return (vrrp_header*)m_Data; + } + + void setAddressType(IPAddress::AddressType addressType); + + public: + /** + * VRRP message types + */ + enum VrrpType + { + /** Unknown VRRP message */ + VrrpType_Unknown = 0, + + /** VRRP advertisement message */ + VrrpType_Advertisement = 1 + }; + + /** + * An enum describing VRRP special priority values + */ + enum VrrpPriority + { + /** Default priority for a backup VRRP router (value of 100) */ + Default, + /** Current Master has stopped participating in VRRP (value of 0) */ + Stop, + /** This VRRP router owns the virtual router's IP address(es) (value of 255) */ + Owner, + /** Other priority */ + Other + }; + + virtual ~VrrpLayer() + {} + + /** + * @return The VRRP IP Address type + */ + IPAddress::AddressType getAddressType() const; + + /** + * A static method that validates the input data + * @param[in] data VRRP raw data (byte stream) + * @param[in] dataLen The length of the byte stream + * @return One of the values ::VRRPv2, ::VRRPv3 according to detected VRRP version or ::UnknownProtocol if + * couldn't detect VRRP version + */ + static ProtocolType getVersionFromData(uint8_t* data, size_t dataLen); + + /** + * @return VRRP version of this message + */ + uint8_t getVersion() const; + + /** + * @return VRRP type set in vrrp_header#type as VrrpLayer::VrrpType enum. + */ + VrrpType getType() const; + + /** + * @return The virtual router id (vrId) in this message + */ + uint8_t getVirtualRouterID() const; + + /** + * Set the virtual router ID + * @param virtualRouterID new ID to set + */ + void setVirtualRouterID(uint8_t virtualRouterID); + + /** + * @return The priority in this message + */ + uint8_t getPriority() const; + + /** + * @return An enum describing VRRP priority + */ + VrrpPriority getPriorityAsEnum() const; + + /** + * Set the priority + * @param priority new priority to set + */ + void setPriority(uint8_t priority); + + /** + * @return VRRP checksum of this message + */ + uint16_t getChecksum() const; + + /** + * Fill the checksum from header and data and write the result to @ref vrrp_header#checksum + */ + void calculateAndSetChecksum(); + + /** + * Calculate the checksum from header and data and write the result to @ref vrrp_header#checksum + * @return The checksum result + */ + virtual uint16_t calculateChecksum() const = 0; + + /** + * @return True if VRRP checksum is correct + */ + bool isChecksumCorrect() const; + + /** + * @return The count of VRRP virtual IP addresses in this message + */ + uint8_t getIPAddressesCount() const; + + /** + * @return A list of the virtual IP addresses in this message + */ + std::vector getIPAddresses() const; + + /** + * Add a list of virtual IP addresses at a the end of the virtual IP address list. The + * vrrp_header#ipAddressCount field will be incremented accordingly + * @param[in] ipAddresses A vector containing all the virtual IP address + * @return true if added successfully, false otherwise + */ + bool addIPAddresses(const std::vector& ipAddresses); + + /** + * Add a virtual IP address at a the end of the virtual IP address list. The vrrp_header#ipAddressCount field + * will be incremented accordingly + * @param[in] ipAddress Virtual IP address to add + * @return true if add successfully, false otherwise + */ + bool addIPAddress(const IPAddress& ipAddress); + + /** + * Remove a virtual IP address at a certain index. The vrrp_header#ipAddressCount field will be decremented + * accordingly + * @param[in] index The index of the virtual IP address to be removed + * @return True if virtual IP address was removed successfully or false otherwise. If false is returned an + * appropriate error message will be printed to log + */ + bool removeIPAddressAtIndex(int index); + + /** + * Remove all virtual IP addresses in the message. The vrrp_header#ipAddressCount field will be set to 0 + * @return True if virtual IP addresses were cleared successfully or false otherwise. If false is returned an + * appropriate error message will be printed to log + */ + bool removeAllIPAddresses(); + + // implement abstract methods + + /** + * Does nothing for this layer (VRRP layer is always last) + */ + void parseNextLayer() override + {} + + /** + * Calculate the VRRP checksum + */ + void computeCalculateFields() override; + + /** + * @return The message size in bytes which include the size of the basic header + the size of the IP address(es) + */ + size_t getHeaderLen() const override + { + return m_DataLen; + } + + std::string toString() const override; + + OsiModelLayer getOsiModelLayer() const override + { + return OsiModelNetworkLayer; + } + }; + + /** + * @class VrrpV2Layer + * Represents VRRPv2 (Virtual Router Redundancy Protocol ver 2) layer. This class represents all the different + * messages of VRRPv2 + */ + class VrrpV2Layer : public VrrpLayer + { + private: + struct vrrpv2_auth_adv + { + uint8_t authType; + uint8_t advInt; + }; + + public: + /** + * VRRP v2 authentication types + */ + enum class VrrpAuthType : uint8_t + { + /** No Authentication */ + NoAuthentication = 0, + /** Simple Text Password */ + SimpleTextPassword = 1, + /** IP Authentication Header */ + IPAuthenticationHeader = 2, + /** Cisco VRRP MD5 Authentication */ + MD5 = 3, + /** Other/Unknown Authentication Type */ + Other = 4 + }; + + /** A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + VrrpV2Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : VrrpLayer(data, dataLen, prevLayer, packet, VRRPv2, IPAddress::IPv4AddressType) + {} + + /** + * A constructor that allocates a new VRRP v2 layer + * @param virtualRouterId Virtual router ID + * @param priority Priority + * @param advInt Advertisement interval + * @param authType Authentication type (default value is 0) + */ + explicit VrrpV2Layer(uint8_t virtualRouterId, uint8_t priority, uint8_t advInt, uint8_t authType = 0); + + /** + * A destructor for this layer (does nothing) + */ + ~VrrpV2Layer() + {} + + /** + * @return The VRRP advertisement interval in this message + */ + uint8_t getAdvInt() const; + + /** + * Set advertisement interval value in this message + * @param advInt value to set + */ + void setAdvInt(uint8_t advInt); + + /** + * @return The authentication type in this message + */ + uint8_t getAuthType() const; + + /** + * @return The VRRP authentication type as enum + */ + VrrpAuthType getAuthTypeAsEnum() const; + + /** + * Set VRRP authentication type + * @param authType value to set + */ + void setAuthType(uint8_t authType); + + // implement abstract methods + + /** + * Calculate the checksum from header and data and write the result to @ref vrrp_header#checksum + * @return The checksum result + */ + uint16_t calculateChecksum() const override; + }; + + /** + * @class VrrpV3Layer + * Represents VRRPv3 (Virtual Router Redundancy Protocol ver 3) layer. This class represents all the different + * messages of VRRP + */ + class VrrpV3Layer : public VrrpLayer + { + private: + struct vrrpv3_rsvd_adv + { + uint16_t maxAdvInt; + }; + + public: + /** A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + * @param[in] addressType The IP address type to set for this layer + */ + VrrpV3Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, IPAddress::AddressType addressType) + : VrrpLayer(data, dataLen, prevLayer, packet, VRRPv3, addressType) + {} + + /** + * A constructor that allocates a new VRRPv3 + * @param addressType The IP address type to set for this layer + * @param virtualRouterId Virtual router ID + * @param priority Priority + * @param maxAdvInt Max advertisement interval + */ + explicit VrrpV3Layer(IPAddress::AddressType addressType, uint8_t virtualRouterId, uint8_t priority, + uint16_t maxAdvInt); + + /** + * A destructor for this layer (does nothing) + */ + ~VrrpV3Layer() + {} + + /** + * @return The maximum advertisement interval in this message + */ + uint16_t getMaxAdvInt() const; + + /** + * Set the maximum advertisement interval value + * @param maxAdvInt Value to set + */ + void setMaxAdvInt(uint16_t maxAdvInt); + + // implement abstract methods + + /** + * Calculate the checksum from header and data and write the result to @ref vrrp_header#checksum + * @return The checksum result + */ + uint16_t calculateChecksum() const override; + }; +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/VxlanLayer.h b/Packet++/header/pcapplusplus/VxlanLayer.h new file mode 100644 index 0000000000..3cf83c1270 --- /dev/null +++ b/Packet++/header/pcapplusplus/VxlanLayer.h @@ -0,0 +1,158 @@ +#pragma once + +#include "pcapplusplus/Layer.h" + +/// @file + +namespace pcpp +{ + + /** + * @struct vxlan_header + * Represents a VXLAN protocol header + */ +#pragma pack(push, 1) + struct vxlan_header + { +#if (BYTE_ORDER == LITTLE_ENDIAN) + /** Reserved bits */ + uint16_t reserved6_8 : 3; + /** VNI present flag */ + uint16_t vniPresentFlag : 1; + /** Reserved bits */ + uint16_t reserved2_4 : 3; + /** GBP flag */ + uint16_t gbpFlag : 1; + /** Reserved bits */ + uint16_t reserved14_16 : 3; + /** Policy applied flag */ + uint16_t policyAppliedFlag : 1; + /** Reserved bits */ + uint16_t reserved11_12 : 2; + /** Don't learn flag */ + uint16_t dontLearnFlag : 1; + /** Reserved bits */ + uint16_t reserved9 : 1; +#else + /** Reserved bits */ + uint16_t reserved9 : 1; + /** Don't learn flag */ + uint16_t dontLearnFlag : 1; + /** Reserved bits */ + uint16_t reserved11_12 : 2; + /** Policy applied flag */ + uint16_t policyAppliedFlag : 1; + /** Reserved bits */ + uint16_t reserved14_16 : 3; + /** GBP flag */ + uint16_t gbpFlag : 1; + /** Reserved bits */ + uint16_t reserved2_4 : 3; + /** VNI present flag */ + uint16_t vniPresentFlag : 1; + /** Reserved bits */ + uint16_t reserved6_8 : 3; +#endif + + /** Group Policy ID */ + uint16_t groupPolicyID; + + /** VXLAN Network ID (VNI) */ + uint32_t vni : 24; + /** Reserved bits */ + uint32_t pad : 8; + }; +#pragma pack(pop) + + /** + * @class VxlanLayer + * Represents a VXLAN (Virtual eXtensible Local Area Network) protocol layer + */ + class VxlanLayer : public Layer + { + public: + /** A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + VxlanLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : Layer(data, dataLen, prevLayer, packet, VXLAN) + {} + + /** + * A constructor that creates a new VXLAN header and allocates the data. Note: the VNI present flag is set + * automatically + * @param[in] vni VNI (VXLAN Network ID) to set. Optional parameter (default is 0) + * @param[in] groupPolicyID Group Policy ID to set. Optional parameter (default is 0) + * @param[in] setGbpFlag Set GBP flag. Optional parameter (default is false) + * @param[in] setPolicyAppliedFlag Set Policy Applied flag. Optional parameter (default is false) + * @param[in] setDontLearnFlag Set Don't Learn flag. Optional parameter (default is false) + */ + explicit VxlanLayer(uint32_t vni = 0, uint16_t groupPolicyID = 0, bool setGbpFlag = false, + bool setPolicyAppliedFlag = false, bool setDontLearnFlag = false); + + ~VxlanLayer() + {} + + /** + * Get a pointer to the VXLAN header. Notice this points directly to the data, so every change will change the + * actual packet data + * @return A pointer to the vxlan_header + */ + vxlan_header* getVxlanHeader() const + { + return (vxlan_header*)m_Data; + } + + /** + * @return The VXLAN Network ID (VNI) value + */ + uint32_t getVNI() const; + + /** + * Set VXLAN Network ID (VNI) value + * @param[in] vni VNI value to set + */ + void setVNI(uint32_t vni); + + /** + * A static method that checks whether the port is considered as VxLAN + * @param[in] port The port number to be checked + */ + static bool isVxlanPort(uint16_t port) + { + return port == 4789; + } + + // implement abstract methods + + /** + * Next layer for VXLAN is always Ethernet + */ + void parseNextLayer(); + + /** + * @return Size of vxlan_header + */ + size_t getHeaderLen() const + { + return sizeof(vxlan_header); + } + + /** + * Does nothing for this layer + */ + void computeCalculateFields() + {} + + std::string toString() const; + + OsiModelLayer getOsiModelLayer() const + { + return OsiModelDataLinkLayer; + } + }; + +} // namespace pcpp diff --git a/Packet++/header/pcapplusplus/WakeOnLanLayer.h b/Packet++/header/pcapplusplus/WakeOnLanLayer.h new file mode 100644 index 0000000000..1d23855865 --- /dev/null +++ b/Packet++/header/pcapplusplus/WakeOnLanLayer.h @@ -0,0 +1,182 @@ +#pragma once + +#include "pcapplusplus/IpAddress.h" +#include "pcapplusplus/Layer.h" +#include "pcapplusplus/MacAddress.h" + +/// @file + +/** + * \namespace pcpp + * \brief The main namespace for the PcapPlusPlus lib + */ +namespace pcpp +{ + /** + * Class for representing the Wake on LAN Layer + */ + class WakeOnLanLayer : public Layer + { + private: + void init(uint16_t len); + + public: + /** + * @struct wol_header + * Wake On LAN protocol header + */ +#pragma pack(push, 1) + struct wol_header + { + /// Sync stream (FF FF FF FF FF FF) + uint8_t sync[6]; + /// Target MAC address repeated 16 times + uint8_t addrBody[6 * 16]; + }; +#pragma pack(pop) + + /** + * A constructor that creates the layer from an existing packet raw data + * @param[in] data A pointer to the raw data + * @param[in] dataLen Size of the data in bytes + * @param[in] prevLayer A pointer to the previous layer + * @param[in] packet A pointer to the Packet instance where layer will be stored in + */ + WakeOnLanLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : Layer(data, dataLen, prevLayer, packet, WakeOnLan) + {} + + /** + * Construct a new Wake On Lan Layer with provided values + * @param[in] targetAddr Target MAC address + */ + explicit WakeOnLanLayer(const pcpp::MacAddress& targetAddr); + + /** + * Construct a new Wake On Lan Layer with provided values + * @param[in] targetAddr Target MAC address + * @param[in] password Password as array + * @param[in] len Length of the password array, length of the password should be less than 6 bytes + */ + WakeOnLanLayer(const pcpp::MacAddress& targetAddr, uint8_t* password, uint8_t len); + + /** + * Construct a new Wake On Lan Layer with provided values + * @param[in] targetAddr Target MAC address + * @param[in] password Password as MAC address + */ + WakeOnLanLayer(const pcpp::MacAddress& targetAddr, const pcpp::MacAddress& password); + + /** + * Construct a new Wake On Lan Layer with provided values + * @param[in] targetAddr Target MAC address + * @param[in] password Password as IPv4 address + */ + WakeOnLanLayer(const pcpp::MacAddress& targetAddr, const IPv4Address& password); + + /** + * Get a pointer to the Wake On LAN header. Notice this points directly to the data, so every change will change + * the actual packet data + * @return A pointer to the wol_header + */ + inline wol_header* getWakeOnLanHeader() const + { + return (wol_header*)m_Data; + } + + /** + * Get the target MAC address of the command + * @return MAC address of the target + */ + pcpp::MacAddress getTargetAddr() const; + + /** + * Set the target MAC address + * @param[in] targetAddr MAC address of the target + */ + void setTargetAddr(const pcpp::MacAddress& targetAddr); + + /** + * Get the password of the command + * @return Returns the password if exists, empty string otherwise + */ + std::string getPassword() const; + + /** + * Set the password of the command + * @param[in] password Password as array + * @param[in] len Length of the password array, length of the password should be less than 6 bytes + * @return True if operation successful, false otherwise + */ + bool setPassword(const uint8_t* password, uint8_t len); + + /** + * Set the password of the command + * @param[in] password Password as string. Length of the password should be less than 6 bytes + * @return True if operation successful, false otherwise + */ + bool setPassword(const std::string& password); + + /** + * Set the password of the command + * @param[in] addr Password as MAC address + * @return True if operation successful, false otherwise + */ + bool setPassword(const MacAddress& addr); + + /** + * Set the password of the command + * @param addr Password as IPv4 address + * @return True if operation successful, false otherwise + */ + bool setPassword(const IPv4Address& addr); + + /** + * A static method that checks whether the port is considered as Wake on LAN + * @param[in] port The port number to be checked + */ + static bool isWakeOnLanPort(uint16_t port) + { + return (port == 0) || (port == 7) || (port == 9); + } + + /** + * A static method that takes a byte array and detects whether it is a Wake on LAN message + * @param[in] data A byte array + * @param[in] dataSize The byte array size (in bytes) + * @return True if the data is identified as Wake on LAN message + */ + static bool isDataValid(const uint8_t* data, size_t dataSize); + + // overridden methods + + /// Parses the next layer. Wake on LAN is the always last so does nothing for this layer + void parseNextLayer() + {} + + /** + * @return Get the size of the layer + */ + size_t getHeaderLen() const + { + return m_DataLen; + } + + /// Does nothing for this layer + void computeCalculateFields() + {} + + /** + * @return The OSI layer level of Wake on LAN (Data Link Layer) + */ + OsiModelLayer getOsiModelLayer() const + { + return OsiModelDataLinkLayer; + } + + /** + * @return Returns the protocol info as readable string + */ + std::string toString() const; + }; +} // namespace pcpp diff --git a/Packet++/src/ArpLayer.cpp b/Packet++/src/ArpLayer.cpp index 0852d9bb0f..dea0f33136 100644 --- a/Packet++/src/ArpLayer.cpp +++ b/Packet++/src/ArpLayer.cpp @@ -1,7 +1,7 @@ #define LOG_MODULE PacketLogModuleArpLayer -#include "ArpLayer.h" -#include "EthLayer.h" +#include "pcapplusplus/ArpLayer.h" +#include "pcapplusplus/EthLayer.h" #include #include "EndianPortable.h" diff --git a/Packet++/src/Asn1Codec.cpp b/Packet++/src/Asn1Codec.cpp index 5990f70fd0..94aafbce48 100644 --- a/Packet++/src/Asn1Codec.cpp +++ b/Packet++/src/Asn1Codec.cpp @@ -1,9 +1,9 @@ #define LOG_MODULE PacketLogModuleAsn1Codec -#include "Asn1Codec.h" -#include "GeneralUtils.h" +#include "pcapplusplus/Asn1Codec.h" +#include "pcapplusplus/GeneralUtils.h" #include "EndianPortable.h" -#include "GeneralUtils.h" +#include "pcapplusplus/GeneralUtils.h" #include #include #include diff --git a/Packet++/src/BgpLayer.cpp b/Packet++/src/BgpLayer.cpp index e8e48320d7..ab52017e41 100644 --- a/Packet++/src/BgpLayer.cpp +++ b/Packet++/src/BgpLayer.cpp @@ -1,10 +1,10 @@ #define LOG_MODULE PacketLogModuleBgpLayer #include -#include "Logger.h" -#include "BgpLayer.h" +#include "pcapplusplus/Logger.h" +#include "pcapplusplus/BgpLayer.h" #include "EndianPortable.h" -#include "GeneralUtils.h" +#include "pcapplusplus/GeneralUtils.h" namespace pcpp { diff --git a/Packet++/src/CotpLayer.cpp b/Packet++/src/CotpLayer.cpp index f3ea7975db..081fae63dd 100644 --- a/Packet++/src/CotpLayer.cpp +++ b/Packet++/src/CotpLayer.cpp @@ -1,7 +1,7 @@ -#include "../header/CotpLayer.h" +#include "pcapplusplus//CotpLayer.h" #include "EndianPortable.h" -#include "S7CommLayer.h" -#include +#include "pcapplusplus/S7CommLayer.h" +#include "pcapplusplus/PayloadLayer.h" #include #include #include diff --git a/Packet++/src/DhcpLayer.cpp b/Packet++/src/DhcpLayer.cpp index b5f15511fc..01c2abd578 100644 --- a/Packet++/src/DhcpLayer.cpp +++ b/Packet++/src/DhcpLayer.cpp @@ -1,7 +1,7 @@ #define LOG_MODULE PacketLogModuleDhcpLayer -#include "DhcpLayer.h" -#include "Logger.h" +#include "pcapplusplus/DhcpLayer.h" +#include "pcapplusplus/Logger.h" namespace pcpp { diff --git a/Packet++/src/DhcpV6Layer.cpp b/Packet++/src/DhcpV6Layer.cpp index e6a2d2a0e5..44d1314ff9 100644 --- a/Packet++/src/DhcpV6Layer.cpp +++ b/Packet++/src/DhcpV6Layer.cpp @@ -1,8 +1,8 @@ #define LOG_MODULE PacketLogModuleDhcpV6Layer -#include "DhcpV6Layer.h" -#include "Logger.h" -#include "GeneralUtils.h" +#include "pcapplusplus/DhcpV6Layer.h" +#include "pcapplusplus/Logger.h" +#include "pcapplusplus/GeneralUtils.h" #include "EndianPortable.h" namespace pcpp diff --git a/Packet++/src/DnsLayer.cpp b/Packet++/src/DnsLayer.cpp index 6d7ae5ec76..e318370ddb 100644 --- a/Packet++/src/DnsLayer.cpp +++ b/Packet++/src/DnsLayer.cpp @@ -1,8 +1,8 @@ #define LOG_MODULE PacketLogModuleDnsLayer -#include "DnsLayer.h" -#include "Logger.h" -#include "IpAddress.h" +#include "pcapplusplus/DnsLayer.h" +#include "pcapplusplus/Logger.h" +#include "pcapplusplus/IpAddress.h" #include #include #include diff --git a/Packet++/src/DnsResource.cpp b/Packet++/src/DnsResource.cpp index 488d207e99..d53dc818d0 100644 --- a/Packet++/src/DnsResource.cpp +++ b/Packet++/src/DnsResource.cpp @@ -1,7 +1,7 @@ #define LOG_MODULE PacketLogModuleDnsLayer -#include "DnsResource.h" -#include "Logger.h" +#include "pcapplusplus/DnsResource.h" +#include "pcapplusplus/Logger.h" #include #include #include "EndianPortable.h" diff --git a/Packet++/src/DnsResourceData.cpp b/Packet++/src/DnsResourceData.cpp index 7516a94a65..a0c093a62c 100644 --- a/Packet++/src/DnsResourceData.cpp +++ b/Packet++/src/DnsResourceData.cpp @@ -1,8 +1,8 @@ #define LOG_MODULE PacketLogModuleDnsLayer -#include "DnsResourceData.h" -#include "Logger.h" -#include "GeneralUtils.h" +#include "pcapplusplus/DnsResourceData.h" +#include "pcapplusplus/Logger.h" +#include "pcapplusplus/GeneralUtils.h" #include #include #include diff --git a/Packet++/src/EthDot3Layer.cpp b/Packet++/src/EthDot3Layer.cpp index dff65ac12a..087f15af3d 100644 --- a/Packet++/src/EthDot3Layer.cpp +++ b/Packet++/src/EthDot3Layer.cpp @@ -1,7 +1,7 @@ -#include "EthDot3Layer.h" +#include "pcapplusplus/EthDot3Layer.h" #include "EndianPortable.h" -#include "PayloadLayer.h" -#include "LLCLayer.h" +#include "pcapplusplus/PayloadLayer.h" +#include "pcapplusplus/LLCLayer.h" namespace pcpp { diff --git a/Packet++/src/EthLayer.cpp b/Packet++/src/EthLayer.cpp index fe03e28ad0..f3adb20393 100644 --- a/Packet++/src/EthLayer.cpp +++ b/Packet++/src/EthLayer.cpp @@ -1,14 +1,14 @@ #define LOG_MODULE PacketLogModuleEthLayer -#include "EthLayer.h" -#include "IPv4Layer.h" -#include "IPv6Layer.h" -#include "PayloadLayer.h" -#include "ArpLayer.h" -#include "VlanLayer.h" -#include "PPPoELayer.h" -#include "MplsLayer.h" -#include "WakeOnLanLayer.h" +#include "pcapplusplus/EthLayer.h" +#include "pcapplusplus/IPv4Layer.h" +#include "pcapplusplus/IPv6Layer.h" +#include "pcapplusplus/PayloadLayer.h" +#include "pcapplusplus/ArpLayer.h" +#include "pcapplusplus/VlanLayer.h" +#include "pcapplusplus/PPPoELayer.h" +#include "pcapplusplus/MplsLayer.h" +#include "pcapplusplus/WakeOnLanLayer.h" #include "EndianPortable.h" #include diff --git a/Packet++/src/FtpLayer.cpp b/Packet++/src/FtpLayer.cpp index dba5828da4..47f1175f3c 100644 --- a/Packet++/src/FtpLayer.cpp +++ b/Packet++/src/FtpLayer.cpp @@ -1,6 +1,6 @@ #define LOG_MODULE PacketLogModuleFtpLayer -#include "FtpLayer.h" +#include "pcapplusplus/FtpLayer.h" namespace pcpp { diff --git a/Packet++/src/GreLayer.cpp b/Packet++/src/GreLayer.cpp index da8b5d7170..582fbf8240 100644 --- a/Packet++/src/GreLayer.cpp +++ b/Packet++/src/GreLayer.cpp @@ -1,16 +1,16 @@ #define LOG_MODULE PacketLogModuleGreLayer -#include "GreLayer.h" -#include "EthLayer.h" -#include "EthDot3Layer.h" -#include "IPv4Layer.h" -#include "IPv6Layer.h" -#include "PPPoELayer.h" -#include "VlanLayer.h" -#include "MplsLayer.h" -#include "PayloadLayer.h" -#include "PacketUtils.h" -#include "Logger.h" +#include "pcapplusplus/GreLayer.h" +#include "pcapplusplus/EthLayer.h" +#include "pcapplusplus/EthDot3Layer.h" +#include "pcapplusplus/IPv4Layer.h" +#include "pcapplusplus/IPv6Layer.h" +#include "pcapplusplus/PPPoELayer.h" +#include "pcapplusplus/VlanLayer.h" +#include "pcapplusplus/MplsLayer.h" +#include "pcapplusplus/PayloadLayer.h" +#include "pcapplusplus/PacketUtils.h" +#include "pcapplusplus/Logger.h" #include "EndianPortable.h" // ============== diff --git a/Packet++/src/GtpLayer.cpp b/Packet++/src/GtpLayer.cpp index 30113cd5f4..38b72c4fd5 100644 --- a/Packet++/src/GtpLayer.cpp +++ b/Packet++/src/GtpLayer.cpp @@ -2,11 +2,11 @@ #include #include -#include "Logger.h" -#include "GtpLayer.h" -#include "IPv4Layer.h" -#include "IPv6Layer.h" -#include "PayloadLayer.h" +#include "pcapplusplus/Logger.h" +#include "pcapplusplus/GtpLayer.h" +#include "pcapplusplus/IPv4Layer.h" +#include "pcapplusplus/IPv6Layer.h" +#include "pcapplusplus/PayloadLayer.h" #include "EndianPortable.h" namespace pcpp diff --git a/Packet++/src/HttpLayer.cpp b/Packet++/src/HttpLayer.cpp index 46a37531ad..b3b2f8b6ee 100644 --- a/Packet++/src/HttpLayer.cpp +++ b/Packet++/src/HttpLayer.cpp @@ -1,8 +1,8 @@ #define LOG_MODULE PacketLogModuleHttpLayer -#include "Logger.h" -#include "GeneralUtils.h" -#include "HttpLayer.h" +#include "pcapplusplus/Logger.h" +#include "pcapplusplus/GeneralUtils.h" +#include "pcapplusplus/HttpLayer.h" #include #include #include diff --git a/Packet++/src/IPReassembly.cpp b/Packet++/src/IPReassembly.cpp index 470bdbf42b..1701bae812 100644 --- a/Packet++/src/IPReassembly.cpp +++ b/Packet++/src/IPReassembly.cpp @@ -1,10 +1,10 @@ #define LOG_MODULE PacketLogModuleIPReassembly -#include "IPReassembly.h" -#include "IPv4Layer.h" -#include "IPv6Layer.h" -#include "PacketUtils.h" -#include "Logger.h" +#include "pcapplusplus/IPReassembly.h" +#include "pcapplusplus/IPv4Layer.h" +#include "pcapplusplus/IPv6Layer.h" +#include "pcapplusplus/PacketUtils.h" +#include "pcapplusplus/Logger.h" #include #include "EndianPortable.h" diff --git a/Packet++/src/IPSecLayer.cpp b/Packet++/src/IPSecLayer.cpp index 445ddcb54c..b691f7f44e 100644 --- a/Packet++/src/IPSecLayer.cpp +++ b/Packet++/src/IPSecLayer.cpp @@ -1,13 +1,13 @@ #define LOG_MODULE PacketLogModuleIPSecLayer #include "EndianPortable.h" -#include "GeneralUtils.h" -#include "IPSecLayer.h" -#include "IPv4Layer.h" -#include "IPv6Layer.h" -#include "UdpLayer.h" -#include "TcpLayer.h" -#include "PayloadLayer.h" +#include "pcapplusplus/GeneralUtils.h" +#include "pcapplusplus/IPSecLayer.h" +#include "pcapplusplus/IPv4Layer.h" +#include "pcapplusplus/IPv6Layer.h" +#include "pcapplusplus/UdpLayer.h" +#include "pcapplusplus/TcpLayer.h" +#include "pcapplusplus/PayloadLayer.h" #include namespace pcpp diff --git a/Packet++/src/IPv4Layer.cpp b/Packet++/src/IPv4Layer.cpp index 7f09c5db5c..3a998feabd 100644 --- a/Packet++/src/IPv4Layer.cpp +++ b/Packet++/src/IPv4Layer.cpp @@ -1,19 +1,19 @@ #define LOG_MODULE PacketLogModuleIPv4Layer -#include "IPv4Layer.h" -#include "IPv6Layer.h" -#include "PayloadLayer.h" -#include "UdpLayer.h" -#include "TcpLayer.h" -#include "IcmpLayer.h" -#include "GreLayer.h" -#include "IgmpLayer.h" -#include "IPSecLayer.h" -#include "VrrpLayer.h" -#include "PacketUtils.h" +#include "pcapplusplus/Logger.h" +#include "pcapplusplus/IPv4Layer.h" +#include "pcapplusplus/IPv6Layer.h" +#include "pcapplusplus/PayloadLayer.h" +#include "pcapplusplus/UdpLayer.h" +#include "pcapplusplus/TcpLayer.h" +#include "pcapplusplus/IcmpLayer.h" +#include "pcapplusplus/GreLayer.h" +#include "pcapplusplus/IgmpLayer.h" +#include "pcapplusplus/IPSecLayer.h" +#include "pcapplusplus/VrrpLayer.h" +#include "pcapplusplus/PacketUtils.h" #include #include -#include "Logger.h" #include "EndianPortable.h" namespace pcpp diff --git a/Packet++/src/IPv6Extensions.cpp b/Packet++/src/IPv6Extensions.cpp index 3a1bc08bb9..9951d8d050 100644 --- a/Packet++/src/IPv6Extensions.cpp +++ b/Packet++/src/IPv6Extensions.cpp @@ -2,14 +2,14 @@ #include #include "EndianPortable.h" -#include "Logger.h" -#include "IPv6Extensions.h" -#include "IPv6Layer.h" -#include "IPv4Layer.h" -#include "PayloadLayer.h" -#include "UdpLayer.h" -#include "TcpLayer.h" -#include "GreLayer.h" +#include "pcapplusplus/Logger.h" +#include "pcapplusplus/IPv6Extensions.h" +#include "pcapplusplus/IPv6Layer.h" +#include "pcapplusplus/IPv4Layer.h" +#include "pcapplusplus/PayloadLayer.h" +#include "pcapplusplus/UdpLayer.h" +#include "pcapplusplus/TcpLayer.h" +#include "pcapplusplus/GreLayer.h" namespace pcpp { diff --git a/Packet++/src/IPv6Layer.cpp b/Packet++/src/IPv6Layer.cpp index f09e68816b..df8f9e8790 100644 --- a/Packet++/src/IPv6Layer.cpp +++ b/Packet++/src/IPv6Layer.cpp @@ -1,16 +1,16 @@ #define LOG_MODULE PacketLogModuleIPv6Layer #include -#include "IPv6Layer.h" -#include "IPv4Layer.h" -#include "PayloadLayer.h" -#include "UdpLayer.h" -#include "TcpLayer.h" -#include "GreLayer.h" -#include "IPSecLayer.h" -#include "IcmpV6Layer.h" -#include "VrrpLayer.h" -#include "Packet.h" +#include "pcapplusplus/IPv6Layer.h" +#include "pcapplusplus/IPv4Layer.h" +#include "pcapplusplus/PayloadLayer.h" +#include "pcapplusplus/UdpLayer.h" +#include "pcapplusplus/TcpLayer.h" +#include "pcapplusplus/GreLayer.h" +#include "pcapplusplus/IPSecLayer.h" +#include "pcapplusplus/IcmpV6Layer.h" +#include "pcapplusplus/VrrpLayer.h" +#include "pcapplusplus/Packet.h" #include #include "EndianPortable.h" diff --git a/Packet++/src/IcmpLayer.cpp b/Packet++/src/IcmpLayer.cpp index 77370d112a..c11f981d18 100644 --- a/Packet++/src/IcmpLayer.cpp +++ b/Packet++/src/IcmpLayer.cpp @@ -1,10 +1,10 @@ #define LOG_MODULE PacketLogModuleIcmpLayer -#include "IcmpLayer.h" -#include "PayloadLayer.h" -#include "Packet.h" -#include "PacketUtils.h" -#include "Logger.h" +#include "pcapplusplus/IcmpLayer.h" +#include "pcapplusplus/PayloadLayer.h" +#include "pcapplusplus/Packet.h" +#include "pcapplusplus/PacketUtils.h" +#include "pcapplusplus/Logger.h" #include #include #include "EndianPortable.h" diff --git a/Packet++/src/IcmpV6Layer.cpp b/Packet++/src/IcmpV6Layer.cpp index e118d1295f..22f95a0d55 100644 --- a/Packet++/src/IcmpV6Layer.cpp +++ b/Packet++/src/IcmpV6Layer.cpp @@ -1,12 +1,12 @@ #define LOG_MODULE PacketLogModuleIcmpV6Layer -#include "IcmpV6Layer.h" +#include "pcapplusplus/IcmpV6Layer.h" #include "EndianPortable.h" -#include "IPv4Layer.h" -#include "IPv6Layer.h" -#include "NdpLayer.h" -#include "PacketUtils.h" -#include "PayloadLayer.h" +#include "pcapplusplus/IPv4Layer.h" +#include "pcapplusplus/IPv6Layer.h" +#include "pcapplusplus/NdpLayer.h" +#include "pcapplusplus/PacketUtils.h" +#include "pcapplusplus/PayloadLayer.h" #include #include diff --git a/Packet++/src/IgmpLayer.cpp b/Packet++/src/IgmpLayer.cpp index 6f95416b5b..88a48afe0e 100644 --- a/Packet++/src/IgmpLayer.cpp +++ b/Packet++/src/IgmpLayer.cpp @@ -1,8 +1,8 @@ #define LOG_MODULE PacketLogModuleIgmpLayer -#include "IgmpLayer.h" -#include "PacketUtils.h" -#include "Logger.h" +#include "pcapplusplus/IgmpLayer.h" +#include "pcapplusplus/PacketUtils.h" +#include "pcapplusplus/Logger.h" #include #include "EndianPortable.h" diff --git a/Packet++/src/LLCLayer.cpp b/Packet++/src/LLCLayer.cpp index f0a71c0703..80a2cefc42 100644 --- a/Packet++/src/LLCLayer.cpp +++ b/Packet++/src/LLCLayer.cpp @@ -1,8 +1,8 @@ #define LOG_MODULE PacketLogModuleLLCLayer -#include "LLCLayer.h" -#include "PayloadLayer.h" -#include "StpLayer.h" +#include "pcapplusplus/LLCLayer.h" +#include "pcapplusplus/PayloadLayer.h" +#include "pcapplusplus/StpLayer.h" #include namespace pcpp diff --git a/Packet++/src/Layer.cpp b/Packet++/src/Layer.cpp index f51a271eb2..299c5945ab 100644 --- a/Packet++/src/Layer.cpp +++ b/Packet++/src/Layer.cpp @@ -1,9 +1,9 @@ #define LOG_MODULE PacketLogModuleLayer -#include "Layer.h" +#include "pcapplusplus/Layer.h" #include -#include "Logger.h" -#include "Packet.h" +#include "pcapplusplus/Logger.h" +#include "pcapplusplus/Packet.h" namespace pcpp { diff --git a/Packet++/src/LdapLayer.cpp b/Packet++/src/LdapLayer.cpp index c123fc0f2d..fd1edaaf69 100644 --- a/Packet++/src/LdapLayer.cpp +++ b/Packet++/src/LdapLayer.cpp @@ -1,5 +1,5 @@ -#include "LdapLayer.h" -#include "GeneralUtils.h" +#include "pcapplusplus/LdapLayer.h" +#include "pcapplusplus/GeneralUtils.h" #include namespace pcpp diff --git a/Packet++/src/MplsLayer.cpp b/Packet++/src/MplsLayer.cpp index 184222dc91..26d433fac2 100644 --- a/Packet++/src/MplsLayer.cpp +++ b/Packet++/src/MplsLayer.cpp @@ -1,10 +1,10 @@ #define LOG_MODULE PacketLogModuleMplsLayer -#include "MplsLayer.h" -#include "IPv4Layer.h" -#include "IPv6Layer.h" -#include "PayloadLayer.h" -#include "Logger.h" +#include "pcapplusplus/MplsLayer.h" +#include "pcapplusplus/IPv4Layer.h" +#include "pcapplusplus/IPv6Layer.h" +#include "pcapplusplus/PayloadLayer.h" +#include "pcapplusplus/Logger.h" #include #include #include "EndianPortable.h" diff --git a/Packet++/src/NdpLayer.cpp b/Packet++/src/NdpLayer.cpp index c0448938a5..a519dc65ad 100644 --- a/Packet++/src/NdpLayer.cpp +++ b/Packet++/src/NdpLayer.cpp @@ -1,7 +1,7 @@ #define LOG_MODULE PacketLogModuleNdpLayer -#include "NdpLayer.h" -#include "Logger.h" +#include "pcapplusplus/NdpLayer.h" +#include "pcapplusplus/Logger.h" namespace pcpp { diff --git a/Packet++/src/NflogLayer.cpp b/Packet++/src/NflogLayer.cpp index 305a56a3d1..ed53f664b2 100644 --- a/Packet++/src/NflogLayer.cpp +++ b/Packet++/src/NflogLayer.cpp @@ -1,10 +1,10 @@ #define LOG_MODULE PacketLogModuleNflogLayer -#include "NflogLayer.h" -#include "IPv4Layer.h" -#include "IPv6Layer.h" -#include "PayloadLayer.h" -#include "GeneralUtils.h" +#include "pcapplusplus/NflogLayer.h" +#include "pcapplusplus/IPv4Layer.h" +#include "pcapplusplus/IPv6Layer.h" +#include "pcapplusplus/PayloadLayer.h" +#include "pcapplusplus/GeneralUtils.h" #include "EndianPortable.h" #include diff --git a/Packet++/src/NtpLayer.cpp b/Packet++/src/NtpLayer.cpp index 6fc1220ee7..bdcd518424 100644 --- a/Packet++/src/NtpLayer.cpp +++ b/Packet++/src/NtpLayer.cpp @@ -1,9 +1,9 @@ #define LOG_MODULE PacketLogModuleNtpLayer -#include "Logger.h" -#include "NtpLayer.h" -#include "SystemUtils.h" -#include "GeneralUtils.h" +#include "pcapplusplus/Logger.h" +#include "pcapplusplus/NtpLayer.h" +#include "pcapplusplus/SystemUtils.h" +#include "pcapplusplus/GeneralUtils.h" #include #include diff --git a/Packet++/src/NullLoopbackLayer.cpp b/Packet++/src/NullLoopbackLayer.cpp index 7f67472cce..ed912267e4 100644 --- a/Packet++/src/NullLoopbackLayer.cpp +++ b/Packet++/src/NullLoopbackLayer.cpp @@ -1,8 +1,8 @@ -#include "NullLoopbackLayer.h" -#include "EthLayer.h" -#include "IPv4Layer.h" -#include "IPv6Layer.h" -#include "PayloadLayer.h" +#include "pcapplusplus/NullLoopbackLayer.h" +#include "pcapplusplus/EthLayer.h" +#include "pcapplusplus/IPv4Layer.h" +#include "pcapplusplus/IPv6Layer.h" +#include "pcapplusplus/PayloadLayer.h" #include namespace pcpp diff --git a/Packet++/src/PPPoELayer.cpp b/Packet++/src/PPPoELayer.cpp index 25b07f4033..e7305b3884 100644 --- a/Packet++/src/PPPoELayer.cpp +++ b/Packet++/src/PPPoELayer.cpp @@ -1,10 +1,10 @@ #define LOG_MODULE PacketLogModulePPPoELayer -#include "PPPoELayer.h" -#include "IPv4Layer.h" -#include "IPv6Layer.h" -#include "PayloadLayer.h" -#include "Logger.h" +#include "pcapplusplus/PPPoELayer.h" +#include "pcapplusplus/IPv4Layer.h" +#include "pcapplusplus/IPv6Layer.h" +#include "pcapplusplus/PayloadLayer.h" +#include "pcapplusplus/Logger.h" #include #include #include "EndianPortable.h" diff --git a/Packet++/src/Packet.cpp b/Packet++/src/Packet.cpp index 7a7cc82c49..472ea3d0a7 100644 --- a/Packet++/src/Packet.cpp +++ b/Packet++/src/Packet.cpp @@ -1,17 +1,17 @@ #define LOG_MODULE PacketLogModulePacket -#include "Packet.h" -#include "EthLayer.h" -#include "EthDot3Layer.h" -#include "SllLayer.h" -#include "Sll2Layer.h" -#include "NflogLayer.h" -#include "NullLoopbackLayer.h" -#include "IPv4Layer.h" -#include "IPv6Layer.h" -#include "PayloadLayer.h" -#include "PacketTrailerLayer.h" -#include "Logger.h" +#include "pcapplusplus/Packet.h" +#include "pcapplusplus/EthLayer.h" +#include "pcapplusplus/EthDot3Layer.h" +#include "pcapplusplus/SllLayer.h" +#include "pcapplusplus/Sll2Layer.h" +#include "pcapplusplus/NflogLayer.h" +#include "pcapplusplus/NullLoopbackLayer.h" +#include "pcapplusplus/IPv4Layer.h" +#include "pcapplusplus/IPv6Layer.h" +#include "pcapplusplus/PayloadLayer.h" +#include "pcapplusplus/PacketTrailerLayer.h" +#include "pcapplusplus/Logger.h" #include "EndianPortable.h" #include #include diff --git a/Packet++/src/PacketTrailerLayer.cpp b/Packet++/src/PacketTrailerLayer.cpp index f05f381361..a51ca0502e 100644 --- a/Packet++/src/PacketTrailerLayer.cpp +++ b/Packet++/src/PacketTrailerLayer.cpp @@ -1,5 +1,5 @@ -#include "PacketTrailerLayer.h" -#include "GeneralUtils.h" +#include "pcapplusplus/PacketTrailerLayer.h" +#include "pcapplusplus/GeneralUtils.h" #include #include diff --git a/Packet++/src/PacketUtils.cpp b/Packet++/src/PacketUtils.cpp index fda7a9bc40..066774e9fd 100644 --- a/Packet++/src/PacketUtils.cpp +++ b/Packet++/src/PacketUtils.cpp @@ -1,9 +1,9 @@ -#include "PacketUtils.h" -#include "IPv4Layer.h" -#include "IPv6Layer.h" -#include "TcpLayer.h" -#include "UdpLayer.h" -#include "Logger.h" +#include "pcapplusplus/PacketUtils.h" +#include "pcapplusplus/IPv4Layer.h" +#include "pcapplusplus/IPv6Layer.h" +#include "pcapplusplus/TcpLayer.h" +#include "pcapplusplus/UdpLayer.h" +#include "pcapplusplus/Logger.h" #include "EndianPortable.h" namespace pcpp diff --git a/Packet++/src/PayloadLayer.cpp b/Packet++/src/PayloadLayer.cpp index b85177ca85..6b557601ac 100644 --- a/Packet++/src/PayloadLayer.cpp +++ b/Packet++/src/PayloadLayer.cpp @@ -1,7 +1,7 @@ #define LOG_MODULE PacketLogModulePayloadLayer -#include "PayloadLayer.h" -#include "GeneralUtils.h" +#include "pcapplusplus/PayloadLayer.h" +#include "pcapplusplus/GeneralUtils.h" #include #include diff --git a/Packet++/src/RadiusLayer.cpp b/Packet++/src/RadiusLayer.cpp index d5ad43ec36..5dd3ac2b75 100644 --- a/Packet++/src/RadiusLayer.cpp +++ b/Packet++/src/RadiusLayer.cpp @@ -1,7 +1,7 @@ #define LOG_MODULE PacketLogModuleRadiusLayer -#include "RadiusLayer.h" -#include "Logger.h" -#include "GeneralUtils.h" +#include "pcapplusplus/RadiusLayer.h" +#include "pcapplusplus/Logger.h" +#include "pcapplusplus/GeneralUtils.h" #include #include diff --git a/Packet++/src/RawPacket.cpp b/Packet++/src/RawPacket.cpp index 4ae29bea8a..052927137e 100644 --- a/Packet++/src/RawPacket.cpp +++ b/Packet++/src/RawPacket.cpp @@ -1,9 +1,9 @@ #define LOG_MODULE PacketLogModuleRawPacket -#include "RawPacket.h" +#include "pcapplusplus/RawPacket.h" #include -#include "Logger.h" -#include "TimespecTimeval.h" +#include "pcapplusplus/Logger.h" +#include "pcapplusplus/TimespecTimeval.h" namespace pcpp { diff --git a/Packet++/src/S7CommLayer.cpp b/Packet++/src/S7CommLayer.cpp index 40af5c0b29..283ca20a57 100644 --- a/Packet++/src/S7CommLayer.cpp +++ b/Packet++/src/S7CommLayer.cpp @@ -1,7 +1,7 @@ #include "EndianPortable.h" -#include "S7CommLayer.h" -#include "TcpLayer.h" +#include "pcapplusplus/S7CommLayer.h" +#include "pcapplusplus/TcpLayer.h" #include #include diff --git a/Packet++/src/SSHLayer.cpp b/Packet++/src/SSHLayer.cpp index 2023bc11a5..63f2eeb939 100644 --- a/Packet++/src/SSHLayer.cpp +++ b/Packet++/src/SSHLayer.cpp @@ -1,8 +1,8 @@ #define LOG_MODULE PacketLogModuleSSHLayer -#include "SSHLayer.h" -#include "GeneralUtils.h" -#include "Logger.h" +#include "pcapplusplus/SSHLayer.h" +#include "pcapplusplus/GeneralUtils.h" +#include "pcapplusplus/Logger.h" #include "EndianPortable.h" #include diff --git a/Packet++/src/SSLCommon.cpp b/Packet++/src/SSLCommon.cpp index 31207d8866..b081396b38 100644 --- a/Packet++/src/SSLCommon.cpp +++ b/Packet++/src/SSLCommon.cpp @@ -1,6 +1,6 @@ #define LOG_MODULE PacketLogModuleSSLLayer -#include "SSLCommon.h" +#include "pcapplusplus/SSLCommon.h" namespace pcpp { diff --git a/Packet++/src/SSLHandshake.cpp b/Packet++/src/SSLHandshake.cpp index 847f27a06b..89fdf593b9 100644 --- a/Packet++/src/SSLHandshake.cpp +++ b/Packet++/src/SSLHandshake.cpp @@ -7,8 +7,8 @@ #include #include #include -#include "Logger.h" -#include "SSLHandshake.h" +#include "pcapplusplus/Logger.h" +#include "pcapplusplus/SSLHandshake.h" namespace pcpp { diff --git a/Packet++/src/SSLLayer.cpp b/Packet++/src/SSLLayer.cpp index 3025bdd582..3fa4adf603 100644 --- a/Packet++/src/SSLLayer.cpp +++ b/Packet++/src/SSLLayer.cpp @@ -1,7 +1,7 @@ #define LOG_MODULE PacketLogModuleSSLLayer -#include "Logger.h" -#include "SSLLayer.h" +#include "pcapplusplus/Logger.h" +#include "pcapplusplus/SSLLayer.h" #include "EndianPortable.h" #include diff --git a/Packet++/src/SdpLayer.cpp b/Packet++/src/SdpLayer.cpp index 375eb7371b..dd9b4c5bcc 100644 --- a/Packet++/src/SdpLayer.cpp +++ b/Packet++/src/SdpLayer.cpp @@ -1,7 +1,7 @@ #define LOG_MODULE PacketLogModuleSdpLayer -#include "SdpLayer.h" -#include "Logger.h" +#include "pcapplusplus/SdpLayer.h" +#include "pcapplusplus/Logger.h" #include #include #include diff --git a/Packet++/src/SingleCommandTextProtocol.cpp b/Packet++/src/SingleCommandTextProtocol.cpp index f24407f56d..95087a6321 100644 --- a/Packet++/src/SingleCommandTextProtocol.cpp +++ b/Packet++/src/SingleCommandTextProtocol.cpp @@ -1,5 +1,5 @@ -#include "SingleCommandTextProtocol.h" -#include "Logger.h" +#include "pcapplusplus/SingleCommandTextProtocol.h" +#include "pcapplusplus/Logger.h" #include #include diff --git a/Packet++/src/SipLayer.cpp b/Packet++/src/SipLayer.cpp index 6cfa8256c9..687cc80236 100644 --- a/Packet++/src/SipLayer.cpp +++ b/Packet++/src/SipLayer.cpp @@ -1,10 +1,10 @@ #define LOG_MODULE PacketLogModuleSipLayer -#include "SipLayer.h" -#include "SdpLayer.h" -#include "PayloadLayer.h" -#include "Logger.h" -#include "GeneralUtils.h" +#include "pcapplusplus/SipLayer.h" +#include "pcapplusplus/SdpLayer.h" +#include "pcapplusplus/PayloadLayer.h" +#include "pcapplusplus/Logger.h" +#include "pcapplusplus/GeneralUtils.h" #include #include #include diff --git a/Packet++/src/Sll2Layer.cpp b/Packet++/src/Sll2Layer.cpp index 99638b46bb..0313593af6 100644 --- a/Packet++/src/Sll2Layer.cpp +++ b/Packet++/src/Sll2Layer.cpp @@ -1,14 +1,14 @@ #define LOG_MODULE PacketLogModuleSll2Layer -#include "Sll2Layer.h" -#include "Logger.h" -#include "IPv4Layer.h" -#include "IPv6Layer.h" -#include "PayloadLayer.h" -#include "ArpLayer.h" -#include "VlanLayer.h" -#include "PPPoELayer.h" -#include "MplsLayer.h" +#include "pcapplusplus/Sll2Layer.h" +#include "pcapplusplus/Logger.h" +#include "pcapplusplus/IPv4Layer.h" +#include "pcapplusplus/IPv6Layer.h" +#include "pcapplusplus/PayloadLayer.h" +#include "pcapplusplus/ArpLayer.h" +#include "pcapplusplus/VlanLayer.h" +#include "pcapplusplus/PPPoELayer.h" +#include "pcapplusplus/MplsLayer.h" #include #include "EndianPortable.h" diff --git a/Packet++/src/SllLayer.cpp b/Packet++/src/SllLayer.cpp index 405990cc99..6370617aa0 100644 --- a/Packet++/src/SllLayer.cpp +++ b/Packet++/src/SllLayer.cpp @@ -1,14 +1,14 @@ #define LOG_MODULE PacketLogModuleSllLayer -#include "SllLayer.h" -#include "Logger.h" -#include "IPv4Layer.h" -#include "IPv6Layer.h" -#include "PayloadLayer.h" -#include "ArpLayer.h" -#include "VlanLayer.h" -#include "PPPoELayer.h" -#include "MplsLayer.h" +#include "pcapplusplus/SllLayer.h" +#include "pcapplusplus/Logger.h" +#include "pcapplusplus/IPv4Layer.h" +#include "pcapplusplus/IPv6Layer.h" +#include "pcapplusplus/PayloadLayer.h" +#include "pcapplusplus/ArpLayer.h" +#include "pcapplusplus/VlanLayer.h" +#include "pcapplusplus/PPPoELayer.h" +#include "pcapplusplus/MplsLayer.h" #include #include "EndianPortable.h" diff --git a/Packet++/src/SmtpLayer.cpp b/Packet++/src/SmtpLayer.cpp index bf2a703637..f2d0d3f026 100644 --- a/Packet++/src/SmtpLayer.cpp +++ b/Packet++/src/SmtpLayer.cpp @@ -1,6 +1,6 @@ #define LOG_MODULE PacketLogModuleSmtpLayer -#include "SmtpLayer.h" +#include "pcapplusplus/SmtpLayer.h" #include diff --git a/Packet++/src/SomeIpLayer.cpp b/Packet++/src/SomeIpLayer.cpp index 9c351d0675..648b261412 100644 --- a/Packet++/src/SomeIpLayer.cpp +++ b/Packet++/src/SomeIpLayer.cpp @@ -1,9 +1,9 @@ #define LOG_MODULE PacketLogModuleSomeIpLayer -#include "SomeIpLayer.h" -#include "SomeIpSdLayer.h" -#include "Packet.h" -#include "PayloadLayer.h" +#include "pcapplusplus/SomeIpLayer.h" +#include "pcapplusplus/SomeIpSdLayer.h" +#include "pcapplusplus/Packet.h" +#include "pcapplusplus/PayloadLayer.h" #include "EndianPortable.h" #include #include diff --git a/Packet++/src/SomeIpSdLayer.cpp b/Packet++/src/SomeIpSdLayer.cpp index 2538959944..bfc10f2245 100644 --- a/Packet++/src/SomeIpSdLayer.cpp +++ b/Packet++/src/SomeIpSdLayer.cpp @@ -1,6 +1,6 @@ #define LOG_MODULE PacketLogModuleSomeIpSdLayer -#include "SomeIpSdLayer.h" +#include "pcapplusplus/SomeIpSdLayer.h" #include "EndianPortable.h" #include #include diff --git a/Packet++/src/StpLayer.cpp b/Packet++/src/StpLayer.cpp index 147395018d..d08f209356 100644 --- a/Packet++/src/StpLayer.cpp +++ b/Packet++/src/StpLayer.cpp @@ -1,9 +1,9 @@ #define LOG_MODULE PacketLogModuleStpLayer -#include "StpLayer.h" -#include "PayloadLayer.h" +#include "pcapplusplus/StpLayer.h" +#include "pcapplusplus/PayloadLayer.h" #include "EndianPortable.h" -#include "Logger.h" +#include "pcapplusplus/Logger.h" namespace pcpp { diff --git a/Packet++/src/TLVData.cpp b/Packet++/src/TLVData.cpp index 7fc571635d..babaca55a9 100644 --- a/Packet++/src/TLVData.cpp +++ b/Packet++/src/TLVData.cpp @@ -1,5 +1,5 @@ -#include "TLVData.h" -#include "GeneralUtils.h" +#include "pcapplusplus/TLVData.h" +#include "pcapplusplus/GeneralUtils.h" #include "EndianPortable.h" namespace pcpp diff --git a/Packet++/src/TcpLayer.cpp b/Packet++/src/TcpLayer.cpp index c6963d2259..92ecff649c 100644 --- a/Packet++/src/TcpLayer.cpp +++ b/Packet++/src/TcpLayer.cpp @@ -1,25 +1,25 @@ #define LOG_MODULE PacketLogModuleTcpLayer #include "EndianPortable.h" -#include "TcpLayer.h" -#include "IPv4Layer.h" -#include "IPv6Layer.h" -#include "PayloadLayer.h" -#include "HttpLayer.h" -#include "SSLLayer.h" -#include "SipLayer.h" -#include "BgpLayer.h" -#include "SSHLayer.h" -#include "DnsLayer.h" -#include "TelnetLayer.h" -#include "TpktLayer.h" -#include "FtpLayer.h" -#include "SomeIpLayer.h" -#include "SmtpLayer.h" -#include "LdapLayer.h" -#include "PacketUtils.h" -#include "Logger.h" -#include "DeprecationUtils.h" +#include "pcapplusplus/TcpLayer.h" +#include "pcapplusplus/IPv4Layer.h" +#include "pcapplusplus/IPv6Layer.h" +#include "pcapplusplus/PayloadLayer.h" +#include "pcapplusplus/HttpLayer.h" +#include "pcapplusplus/SSLLayer.h" +#include "pcapplusplus/SipLayer.h" +#include "pcapplusplus/BgpLayer.h" +#include "pcapplusplus/SSHLayer.h" +#include "pcapplusplus/DnsLayer.h" +#include "pcapplusplus/TelnetLayer.h" +#include "pcapplusplus/TpktLayer.h" +#include "pcapplusplus/FtpLayer.h" +#include "pcapplusplus/SomeIpLayer.h" +#include "pcapplusplus/SmtpLayer.h" +#include "pcapplusplus/LdapLayer.h" +#include "pcapplusplus/PacketUtils.h" +#include "pcapplusplus/Logger.h" +#include "pcapplusplus/DeprecationUtils.h" #include #include diff --git a/Packet++/src/TcpReassembly.cpp b/Packet++/src/TcpReassembly.cpp index 697041c915..62b8ac2e0f 100644 --- a/Packet++/src/TcpReassembly.cpp +++ b/Packet++/src/TcpReassembly.cpp @@ -1,14 +1,14 @@ #define LOG_MODULE PacketLogModuleTcpReassembly -#include "TcpReassembly.h" -#include "TcpLayer.h" -#include "IPLayer.h" -#include "PacketUtils.h" -#include "Logger.h" +#include "pcapplusplus/TcpReassembly.h" +#include "pcapplusplus/TcpLayer.h" +#include "pcapplusplus/IPLayer.h" +#include "pcapplusplus/PacketUtils.h" +#include "pcapplusplus/Logger.h" #include #include #include "EndianPortable.h" -#include "TimespecTimeval.h" +#include "pcapplusplus/TimespecTimeval.h" #ifdef _MSC_VER # include #endif diff --git a/Packet++/src/TelnetLayer.cpp b/Packet++/src/TelnetLayer.cpp index b8ee8cbbd4..04852a04d8 100644 --- a/Packet++/src/TelnetLayer.cpp +++ b/Packet++/src/TelnetLayer.cpp @@ -1,10 +1,10 @@ #define LOG_MODULE PacketLogModuleTelnetLayer -#include "TelnetLayer.h" -#include "Logger.h" +#include "pcapplusplus/TelnetLayer.h" +#include "pcapplusplus/Logger.h" -#include "GeneralUtils.h" -#include "SystemUtils.h" +#include "pcapplusplus/GeneralUtils.h" +#include "pcapplusplus/SystemUtils.h" #include diff --git a/Packet++/src/TextBasedProtocol.cpp b/Packet++/src/TextBasedProtocol.cpp index 6c01010813..6c9f9ecf30 100644 --- a/Packet++/src/TextBasedProtocol.cpp +++ b/Packet++/src/TextBasedProtocol.cpp @@ -1,6 +1,6 @@ -#include "TextBasedProtocol.h" -#include "Logger.h" -#include "PayloadLayer.h" +#include "pcapplusplus/TextBasedProtocol.h" +#include "pcapplusplus/Logger.h" +#include "pcapplusplus/PayloadLayer.h" #include #include #include diff --git a/Packet++/src/TpktLayer.cpp b/Packet++/src/TpktLayer.cpp index 941402c20d..c60ae38668 100644 --- a/Packet++/src/TpktLayer.cpp +++ b/Packet++/src/TpktLayer.cpp @@ -1,8 +1,8 @@ -#include "TpktLayer.h" +#include "pcapplusplus/TpktLayer.h" +#include "pcapplusplus/TcpLayer.h" +#include "pcapplusplus/CotpLayer.h" +#include "pcapplusplus/PayloadLayer.h" #include "EndianPortable.h" -#include "TcpLayer.h" -#include "CotpLayer.h" -#include "PayloadLayer.h" #include #include #include diff --git a/Packet++/src/UdpLayer.cpp b/Packet++/src/UdpLayer.cpp index 2e17b9cddc..59f20a67b7 100644 --- a/Packet++/src/UdpLayer.cpp +++ b/Packet++/src/UdpLayer.cpp @@ -1,22 +1,22 @@ #define LOG_MODULE PacketLogModuleUdpLayer #include "EndianPortable.h" -#include "UdpLayer.h" -#include "PayloadLayer.h" -#include "IPv4Layer.h" -#include "IPv6Layer.h" -#include "DnsLayer.h" -#include "DhcpLayer.h" -#include "DhcpV6Layer.h" -#include "VxlanLayer.h" -#include "SipLayer.h" -#include "RadiusLayer.h" -#include "GtpLayer.h" -#include "NtpLayer.h" -#include "SomeIpLayer.h" -#include "WakeOnLanLayer.h" -#include "PacketUtils.h" -#include "Logger.h" +#include "pcapplusplus/UdpLayer.h" +#include "pcapplusplus/PayloadLayer.h" +#include "pcapplusplus/IPv4Layer.h" +#include "pcapplusplus/IPv6Layer.h" +#include "pcapplusplus/DnsLayer.h" +#include "pcapplusplus/DhcpLayer.h" +#include "pcapplusplus/DhcpV6Layer.h" +#include "pcapplusplus/VxlanLayer.h" +#include "pcapplusplus/SipLayer.h" +#include "pcapplusplus/RadiusLayer.h" +#include "pcapplusplus/GtpLayer.h" +#include "pcapplusplus/NtpLayer.h" +#include "pcapplusplus/SomeIpLayer.h" +#include "pcapplusplus/WakeOnLanLayer.h" +#include "pcapplusplus/PacketUtils.h" +#include "pcapplusplus/Logger.h" #include #include diff --git a/Packet++/src/VlanLayer.cpp b/Packet++/src/VlanLayer.cpp index fe72a1263e..93c1e3a71b 100644 --- a/Packet++/src/VlanLayer.cpp +++ b/Packet++/src/VlanLayer.cpp @@ -1,13 +1,13 @@ #define LOG_MODULE PacketLogModuleVlanLayer -#include "VlanLayer.h" -#include "IPv4Layer.h" -#include "IPv6Layer.h" -#include "PayloadLayer.h" -#include "ArpLayer.h" -#include "PPPoELayer.h" -#include "MplsLayer.h" -#include "LLCLayer.h" +#include "pcapplusplus/VlanLayer.h" +#include "pcapplusplus/IPv4Layer.h" +#include "pcapplusplus/IPv6Layer.h" +#include "pcapplusplus/PayloadLayer.h" +#include "pcapplusplus/ArpLayer.h" +#include "pcapplusplus/PPPoELayer.h" +#include "pcapplusplus/MplsLayer.h" +#include "pcapplusplus/LLCLayer.h" #include #include #include "EndianPortable.h" diff --git a/Packet++/src/VrrpLayer.cpp b/Packet++/src/VrrpLayer.cpp index c56cd7f058..e42fe02d4b 100644 --- a/Packet++/src/VrrpLayer.cpp +++ b/Packet++/src/VrrpLayer.cpp @@ -1,12 +1,12 @@ #define LOG_MODULE PacketLogModuleVrrpLayer -#include -#include "PacketUtils.h" -#include "Logger.h" +#include "pcapplusplus/SystemUtils.h" +#include "pcapplusplus/PacketUtils.h" +#include "pcapplusplus/Logger.h" #include "EndianPortable.h" -#include "IPv4Layer.h" -#include "PayloadLayer.h" -#include "VrrpLayer.h" +#include "pcapplusplus/IPv4Layer.h" +#include "pcapplusplus/PayloadLayer.h" +#include "pcapplusplus/VrrpLayer.h" namespace pcpp { diff --git a/Packet++/src/VxlanLayer.cpp b/Packet++/src/VxlanLayer.cpp index 1ec5c806eb..f1b78458d0 100644 --- a/Packet++/src/VxlanLayer.cpp +++ b/Packet++/src/VxlanLayer.cpp @@ -1,5 +1,5 @@ -#include "VxlanLayer.h" -#include "EthLayer.h" +#include "pcapplusplus/VxlanLayer.h" +#include "pcapplusplus/EthLayer.h" #include #include "EndianPortable.h" diff --git a/Packet++/src/WakeOnLanLayer.cpp b/Packet++/src/WakeOnLanLayer.cpp index 1175375d5a..ae1a4cc313 100644 --- a/Packet++/src/WakeOnLanLayer.cpp +++ b/Packet++/src/WakeOnLanLayer.cpp @@ -1,8 +1,8 @@ #define LOG_MODULE PacketLogModuleWakeOnLanLayer -#include "WakeOnLanLayer.h" -#include "GeneralUtils.h" -#include "Logger.h" +#include "pcapplusplus/WakeOnLanLayer.h" +#include "pcapplusplus/GeneralUtils.h" +#include "pcapplusplus/Logger.h" namespace pcpp { diff --git a/Pcap++/CMakeLists.txt b/Pcap++/CMakeLists.txt index 0f1ca03cba..2be29e593b 100644 --- a/Pcap++/CMakeLists.txt +++ b/Pcap++/CMakeLists.txt @@ -25,55 +25,55 @@ add_library( $) set(public_headers - header/Device.h - header/NetworkUtils.h - header/PcapDevice.h - header/PcapFileDevice.h - header/PcapFilter.h - header/PcapLiveDevice.h - header/PcapLiveDeviceList.h - header/RawSocketDevice.h) + header/pcapplusplus/Device.h + header/pcapplusplus/NetworkUtils.h + header/pcapplusplus/PcapDevice.h + header/pcapplusplus/PcapFileDevice.h + header/pcapplusplus/PcapFilter.h + header/pcapplusplus/PcapLiveDevice.h + header/pcapplusplus/PcapLiveDeviceList.h + header/pcapplusplus/RawSocketDevice.h) if(PCAPPP_USE_DPDK) list( APPEND public_headers - header/DpdkDevice.h - header/DpdkDeviceList.h - header/MBufRawPacket.h) + header/pcapplusplus/DpdkDevice.h + header/pcapplusplus/DpdkDeviceList.h + header/pcapplusplus/MBufRawPacket.h) endif() if(PCAPPP_USE_DPDK_KNI) list( APPEND public_headers - header/KniDevice.h - header/KniDeviceList.h) + header/pcapplusplus/KniDevice.h + header/pcapplusplus/KniDeviceList.h) endif() if(PCAPPP_USE_PF_RING) list( APPEND public_headers - header/PfRingDevice.h - header/PfRingDeviceList.h) + header/pcapplusplus/PfRingDevice.h + header/pcapplusplus/PfRingDeviceList.h) endif() if(PCAPPP_USE_XDP) - list(APPEND public_headers header/XdpDevice.h) + list(APPEND public_headers header/pcapplusplus/XdpDevice.h) endif() if(LINUX) - list(APPEND public_headers header/LinuxNicInformationSocket.h) + list(APPEND public_headers header/pcapplusplus/LinuxNicInformationSocket.h) endif() if(WIN32) list( APPEND public_headers - header/WinPcapLiveDevice.h - header/PcapRemoteDevice.h - header/PcapRemoteDeviceList.h) + header/pcapplusplus/WinPcapLiveDevice.h + header/pcapplusplus/PcapRemoteDevice.h + header/pcapplusplus/PcapRemoteDeviceList.h) endif() set_property(TARGET Pcap++ PROPERTY PUBLIC_HEADER ${public_headers}) diff --git a/Pcap++/header/Device.h b/Pcap++/header/pcapplusplus/Device.h similarity index 95% rename from Pcap++/header/Device.h rename to Pcap++/header/pcapplusplus/Device.h index d8ba547076..e1f59e6052 100644 --- a/Pcap++/header/Device.h +++ b/Pcap++/header/pcapplusplus/Device.h @@ -2,9 +2,9 @@ /// @file -#include "PointerVector.h" -#include "RawPacket.h" -#include "PcapFilter.h" +#include "pcapplusplus/PointerVector.h" +#include "pcapplusplus/RawPacket.h" +#include "pcapplusplus/PcapFilter.h" /** * \namespace pcpp diff --git a/Pcap++/header/DeviceUtils.h b/Pcap++/header/pcapplusplus/DeviceUtils.h similarity index 87% rename from Pcap++/header/DeviceUtils.h rename to Pcap++/header/pcapplusplus/DeviceUtils.h index b453eb3d97..6bf0e44b06 100644 --- a/Pcap++/header/DeviceUtils.h +++ b/Pcap++/header/pcapplusplus/DeviceUtils.h @@ -3,8 +3,8 @@ /// @file #include -#include "IpAddress.h" -#include "PcapUtils.h" +#include "pcapplusplus/IpAddress.h" +#include "pcapplusplus/PcapUtils.h" namespace pcpp { diff --git a/Pcap++/header/DpdkDevice.h b/Pcap++/header/pcapplusplus/DpdkDevice.h similarity index 100% rename from Pcap++/header/DpdkDevice.h rename to Pcap++/header/pcapplusplus/DpdkDevice.h diff --git a/Pcap++/header/DpdkDeviceList.h b/Pcap++/header/pcapplusplus/DpdkDeviceList.h similarity index 100% rename from Pcap++/header/DpdkDeviceList.h rename to Pcap++/header/pcapplusplus/DpdkDeviceList.h diff --git a/Pcap++/header/KniDevice.h b/Pcap++/header/pcapplusplus/KniDevice.h similarity index 100% rename from Pcap++/header/KniDevice.h rename to Pcap++/header/pcapplusplus/KniDevice.h diff --git a/Pcap++/header/KniDeviceList.h b/Pcap++/header/pcapplusplus/KniDeviceList.h similarity index 98% rename from Pcap++/header/KniDeviceList.h rename to Pcap++/header/pcapplusplus/KniDeviceList.h index ed5e737a97..3cc9f1d9f1 100644 --- a/Pcap++/header/KniDeviceList.h +++ b/Pcap++/header/pcapplusplus/KniDeviceList.h @@ -4,8 +4,8 @@ #include -#include "KniDevice.h" -#include "DpdkDeviceList.h" +#include "pcapplusplus/KniDevice.h" +#include "pcapplusplus/DpdkDeviceList.h" /** * \namespace pcpp diff --git a/Pcap++/header/LinuxNicInformationSocket.h b/Pcap++/header/pcapplusplus/LinuxNicInformationSocket.h similarity index 100% rename from Pcap++/header/LinuxNicInformationSocket.h rename to Pcap++/header/pcapplusplus/LinuxNicInformationSocket.h diff --git a/Pcap++/header/MBufRawPacket.h b/Pcap++/header/pcapplusplus/MBufRawPacket.h similarity index 99% rename from Pcap++/header/MBufRawPacket.h rename to Pcap++/header/pcapplusplus/MBufRawPacket.h index 51e024cbed..582274504e 100644 --- a/Pcap++/header/MBufRawPacket.h +++ b/Pcap++/header/pcapplusplus/MBufRawPacket.h @@ -3,8 +3,8 @@ // GCOVR_EXCL_START #include -#include "Packet.h" -#include "PointerVector.h" +#include "pcapplusplus/Packet.h" +#include "pcapplusplus/PointerVector.h" struct rte_mbuf; struct rte_mempool; diff --git a/Pcap++/header/NetworkUtils.h b/Pcap++/header/pcapplusplus/NetworkUtils.h similarity index 97% rename from Pcap++/header/NetworkUtils.h rename to Pcap++/header/pcapplusplus/NetworkUtils.h index 7df6b397a3..f4fa617f9b 100644 --- a/Pcap++/header/NetworkUtils.h +++ b/Pcap++/header/pcapplusplus/NetworkUtils.h @@ -1,8 +1,8 @@ #pragma once -#include "MacAddress.h" -#include "IpAddress.h" -#include "PcapLiveDevice.h" +#include "pcapplusplus/MacAddress.h" +#include "pcapplusplus/IpAddress.h" +#include "pcapplusplus/PcapLiveDevice.h" /// @file diff --git a/Pcap++/header/PcapDevice.h b/Pcap++/header/pcapplusplus/PcapDevice.h similarity index 99% rename from Pcap++/header/PcapDevice.h rename to Pcap++/header/pcapplusplus/PcapDevice.h index 6c5d2ac84c..aa6c7a062e 100644 --- a/Pcap++/header/PcapDevice.h +++ b/Pcap++/header/pcapplusplus/PcapDevice.h @@ -1,6 +1,6 @@ #pragma once -#include "Device.h" +#include "pcapplusplus/Device.h" // forward declaration for the pcap descriptor defined in pcap.h struct pcap; diff --git a/Pcap++/header/PcapFileDevice.h b/Pcap++/header/pcapplusplus/PcapFileDevice.h similarity index 99% rename from Pcap++/header/PcapFileDevice.h rename to Pcap++/header/pcapplusplus/PcapFileDevice.h index 8006943745..cc2d98e741 100644 --- a/Pcap++/header/PcapFileDevice.h +++ b/Pcap++/header/pcapplusplus/PcapFileDevice.h @@ -1,7 +1,7 @@ #pragma once -#include "PcapDevice.h" -#include "RawPacket.h" +#include "pcapplusplus/PcapDevice.h" +#include "pcapplusplus/RawPacket.h" #include // forward declaration for structs and typedefs defined in pcap.h diff --git a/Pcap++/header/PcapFilter.h b/Pcap++/header/pcapplusplus/PcapFilter.h similarity index 99% rename from Pcap++/header/PcapFilter.h rename to Pcap++/header/pcapplusplus/PcapFilter.h index 9e72ed8b7b..2c5c976dc2 100644 --- a/Pcap++/header/PcapFilter.h +++ b/Pcap++/header/pcapplusplus/PcapFilter.h @@ -3,10 +3,10 @@ #include #include #include -#include "ProtocolType.h" +#include "pcapplusplus/ProtocolType.h" #include -#include "ArpLayer.h" -#include "RawPacket.h" +#include "pcapplusplus/ArpLayer.h" +#include "pcapplusplus/RawPacket.h" // Forward Declaration - used in GeneralFilter struct bpf_program; diff --git a/Pcap++/header/PcapLiveDevice.h b/Pcap++/header/pcapplusplus/PcapLiveDevice.h similarity index 99% rename from Pcap++/header/PcapLiveDevice.h rename to Pcap++/header/pcapplusplus/PcapLiveDevice.h index 4a2e66d262..e7e240dd31 100644 --- a/Pcap++/header/PcapLiveDevice.h +++ b/Pcap++/header/pcapplusplus/PcapLiveDevice.h @@ -6,9 +6,9 @@ #include #include -#include "IpAddress.h" -#include "Packet.h" -#include "PcapDevice.h" +#include "pcapplusplus/IpAddress.h" +#include "pcapplusplus/Packet.h" +#include "pcapplusplus/PcapDevice.h" // forward declarations for structs and typedefs that are defined in pcap.h struct pcap_if; diff --git a/Pcap++/header/PcapLiveDeviceList.h b/Pcap++/header/pcapplusplus/PcapLiveDeviceList.h similarity index 98% rename from Pcap++/header/PcapLiveDeviceList.h rename to Pcap++/header/pcapplusplus/PcapLiveDeviceList.h index 84f33b4ab6..5e0db0d208 100644 --- a/Pcap++/header/PcapLiveDeviceList.h +++ b/Pcap++/header/pcapplusplus/PcapLiveDeviceList.h @@ -1,7 +1,7 @@ #pragma once -#include "IpAddress.h" -#include "PcapLiveDevice.h" +#include "pcapplusplus/IpAddress.h" +#include "pcapplusplus/PcapLiveDevice.h" #include #include diff --git a/Pcap++/header/PcapRemoteDevice.h b/Pcap++/header/pcapplusplus/PcapRemoteDevice.h similarity index 100% rename from Pcap++/header/PcapRemoteDevice.h rename to Pcap++/header/pcapplusplus/PcapRemoteDevice.h diff --git a/Pcap++/header/PcapRemoteDeviceList.h b/Pcap++/header/pcapplusplus/PcapRemoteDeviceList.h similarity index 100% rename from Pcap++/header/PcapRemoteDeviceList.h rename to Pcap++/header/pcapplusplus/PcapRemoteDeviceList.h diff --git a/Pcap++/header/PcapUtils.h b/Pcap++/header/pcapplusplus/PcapUtils.h similarity index 100% rename from Pcap++/header/PcapUtils.h rename to Pcap++/header/pcapplusplus/PcapUtils.h diff --git a/Pcap++/header/PfRingDevice.h b/Pcap++/header/pcapplusplus/PfRingDevice.h similarity index 100% rename from Pcap++/header/PfRingDevice.h rename to Pcap++/header/pcapplusplus/PfRingDevice.h diff --git a/Pcap++/header/PfRingDeviceList.h b/Pcap++/header/pcapplusplus/PfRingDeviceList.h similarity index 100% rename from Pcap++/header/PfRingDeviceList.h rename to Pcap++/header/pcapplusplus/PfRingDeviceList.h diff --git a/Pcap++/header/RawSocketDevice.h b/Pcap++/header/pcapplusplus/RawSocketDevice.h similarity index 99% rename from Pcap++/header/RawSocketDevice.h rename to Pcap++/header/pcapplusplus/RawSocketDevice.h index 254af4e186..a42d29aa39 100644 --- a/Pcap++/header/RawSocketDevice.h +++ b/Pcap++/header/pcapplusplus/RawSocketDevice.h @@ -2,7 +2,7 @@ /// @file -#include "IpAddress.h" +#include "pcapplusplus/IpAddress.h" #include "Device.h" /** diff --git a/Pcap++/header/WinPcapLiveDevice.h b/Pcap++/header/pcapplusplus/WinPcapLiveDevice.h similarity index 100% rename from Pcap++/header/WinPcapLiveDevice.h rename to Pcap++/header/pcapplusplus/WinPcapLiveDevice.h diff --git a/Pcap++/header/XdpDevice.h b/Pcap++/header/pcapplusplus/XdpDevice.h similarity index 100% rename from Pcap++/header/XdpDevice.h rename to Pcap++/header/pcapplusplus/XdpDevice.h diff --git a/Pcap++/src/DeviceUtils.cpp b/Pcap++/src/DeviceUtils.cpp index 25bb5e5f20..e990c75462 100644 --- a/Pcap++/src/DeviceUtils.cpp +++ b/Pcap++/src/DeviceUtils.cpp @@ -1,11 +1,11 @@ -#include "DeviceUtils.h" +#include "pcapplusplus/DeviceUtils.h" #include #include #include "pcap.h" -#include "Logger.h" -#include "IpAddress.h" +#include "pcapplusplus/Logger.h" +#include "pcapplusplus/IpAddress.h" namespace pcpp { diff --git a/Pcap++/src/NetworkUtils.cpp b/Pcap++/src/NetworkUtils.cpp index 06e26f5315..5b07bdb9d8 100644 --- a/Pcap++/src/NetworkUtils.cpp +++ b/Pcap++/src/NetworkUtils.cpp @@ -4,21 +4,19 @@ #include #include #include -#include "Logger.h" -#include "Packet.h" -#include "EthLayer.h" -#include "ArpLayer.h" -#include "IPv4Layer.h" -#include "UdpLayer.h" -#include "DnsLayer.h" -#include "PcapFilter.h" -#include "NetworkUtils.h" +#include "pcapplusplus/Logger.h" +#include "pcapplusplus/Packet.h" +#include "pcapplusplus/EthLayer.h" +#include "pcapplusplus/ArpLayer.h" +#include "pcapplusplus/IPv4Layer.h" +#include "pcapplusplus/UdpLayer.h" +#include "pcapplusplus/DnsLayer.h" +#include "pcapplusplus/PcapFilter.h" +#include "pcapplusplus/NetworkUtils.h" +#include "pcapplusplus/SystemUtils.h" #include "EndianPortable.h" -#ifdef _MSC_VER -# include "SystemUtils.h" -#endif #ifndef ETIMEDOUT -# define ETIMEDOUT 10060 +#define ETIMEDOUT 10060 #endif #define DNS_PORT 53 diff --git a/Pcap++/src/PcapDevice.cpp b/Pcap++/src/PcapDevice.cpp index 9cef275c07..062bd73a66 100644 --- a/Pcap++/src/PcapDevice.cpp +++ b/Pcap++/src/PcapDevice.cpp @@ -1,7 +1,7 @@ -#include "PcapDevice.h" -#include "PcapFilter.h" -#include "Logger.h" -#include "TimespecTimeval.h" +#include "pcapplusplus/PcapDevice.h" +#include "pcapplusplus/PcapFilter.h" +#include "pcapplusplus/Logger.h" +#include "pcapplusplus/TimespecTimeval.h" #include "pcap.h" namespace pcpp diff --git a/Pcap++/src/PcapFileDevice.cpp b/Pcap++/src/PcapFileDevice.cpp index 3aa00fff67..bf4d53d797 100644 --- a/Pcap++/src/PcapFileDevice.cpp +++ b/Pcap++/src/PcapFileDevice.cpp @@ -2,10 +2,10 @@ #include #include -#include "PcapFileDevice.h" +#include "pcapplusplus/PcapFileDevice.h" #include "light_pcapng_ext.h" -#include "Logger.h" -#include "TimespecTimeval.h" +#include "pcapplusplus/Logger.h" +#include "pcapplusplus/TimespecTimeval.h" #include "pcap.h" #include #include diff --git a/Pcap++/src/PcapFilter.cpp b/Pcap++/src/PcapFilter.cpp index c3d905e856..8a28bbec20 100644 --- a/Pcap++/src/PcapFilter.cpp +++ b/Pcap++/src/PcapFilter.cpp @@ -1,17 +1,17 @@ #define LOG_MODULE PcapLogModuleLiveDevice -#include "PcapFilter.h" -#include "Logger.h" -#include "IPv4Layer.h" -#include "PcapUtils.h" +#include "pcapplusplus/PcapFilter.h" +#include "pcapplusplus/Logger.h" +#include "pcapplusplus/IPv4Layer.h" +#include "pcapplusplus/PcapUtils.h" #include #include #if defined(_WIN32) # include #endif #include "pcap.h" -#include "RawPacket.h" -#include "TimespecTimeval.h" +#include "pcapplusplus/RawPacket.h" +#include "pcapplusplus/TimespecTimeval.h" namespace pcpp { diff --git a/Pcap++/src/PcapLiveDevice.cpp b/Pcap++/src/PcapLiveDevice.cpp index 7ac0f79edc..3466aa31ed 100644 --- a/Pcap++/src/PcapLiveDevice.cpp +++ b/Pcap++/src/PcapLiveDevice.cpp @@ -1,18 +1,18 @@ #define LOG_MODULE PcapLogModuleLiveDevice -#include "IpUtils.h" -#include "DeviceUtils.h" -#include "PcapUtils.h" -#include "PcapLiveDevice.h" -#include "PcapLiveDeviceList.h" -#include "Packet.h" +#include "pcapplusplus/IpUtils.h" +#include "pcapplusplus/DeviceUtils.h" +#include "pcapplusplus/PcapUtils.h" +#include "pcapplusplus/PcapLiveDevice.h" +#include "pcapplusplus/PcapLiveDeviceList.h" +#include "pcapplusplus/Packet.h" #ifndef _MSC_VER # include #endif // ! _MSC_VER #include "pcap.h" #include -#include "Logger.h" -#include "SystemUtils.h" +#include "pcapplusplus/Logger.h" +#include "pcapplusplus/SystemUtils.h" #include #include #include diff --git a/Pcap++/src/PcapLiveDeviceList.cpp b/Pcap++/src/PcapLiveDeviceList.cpp index e65cd23d2f..d36147c8cd 100644 --- a/Pcap++/src/PcapLiveDeviceList.cpp +++ b/Pcap++/src/PcapLiveDeviceList.cpp @@ -1,12 +1,12 @@ #define LOG_MODULE PcapLogModuleLiveDevice -#include "IpUtils.h" -#include "IpAddressUtils.h" -#include "PcapLiveDeviceList.h" -#include "Logger.h" -#include "PcapUtils.h" -#include "DeviceUtils.h" -#include "SystemUtils.h" +#include "pcapplusplus/IpUtils.h" +#include "pcapplusplus/IpAddressUtils.h" +#include "pcapplusplus/PcapLiveDeviceList.h" +#include "pcapplusplus/Logger.h" +#include "pcapplusplus/PcapUtils.h" +#include "pcapplusplus/DeviceUtils.h" +#include "pcapplusplus/SystemUtils.h" #include "pcap.h" #include #include diff --git a/Pcap++/src/PcapRemoteDevice.cpp b/Pcap++/src/PcapRemoteDevice.cpp index e4e037df17..a702125ecf 100644 --- a/Pcap++/src/PcapRemoteDevice.cpp +++ b/Pcap++/src/PcapRemoteDevice.cpp @@ -1,7 +1,7 @@ #define LOG_MODULE PcapLogModuleRemoteDevice -#include "PcapRemoteDevice.h" -#include "Logger.h" +#include "pcapplusplus/PcapRemoteDevice.h" +#include "pcapplusplus/Logger.h" #include "pcap.h" namespace pcpp diff --git a/Pcap++/src/PcapRemoteDeviceList.cpp b/Pcap++/src/PcapRemoteDeviceList.cpp index 368529789a..02b88857ee 100644 --- a/Pcap++/src/PcapRemoteDeviceList.cpp +++ b/Pcap++/src/PcapRemoteDeviceList.cpp @@ -1,10 +1,10 @@ #define LOG_MODULE PcapLogModuleRemoteDevice -#include "PcapRemoteDeviceList.h" -#include "Logger.h" -#include "IpUtils.h" -#include "PcapUtils.h" -#include "IpAddressUtils.h" +#include "pcapplusplus/PcapRemoteDeviceList.h" +#include "pcapplusplus/Logger.h" +#include "pcapplusplus/IpUtils.h" +#include "pcapplusplus/PcapUtils.h" +#include "pcapplusplus/IpAddressUtils.h" #include "pcap.h" #include #include diff --git a/Pcap++/src/PcapUtils.cpp b/Pcap++/src/PcapUtils.cpp index df8ee5f4c7..ecdc3b31ef 100644 --- a/Pcap++/src/PcapUtils.cpp +++ b/Pcap++/src/PcapUtils.cpp @@ -1,4 +1,4 @@ -#include "PcapUtils.h" +#include "pcapplusplus/PcapUtils.h" #include "pcap.h" diff --git a/Pcap++/src/PfRingDevice.cpp b/Pcap++/src/PfRingDevice.cpp index 8a945a9c20..e175ecd76a 100644 --- a/Pcap++/src/PfRingDevice.cpp +++ b/Pcap++/src/PfRingDevice.cpp @@ -2,10 +2,10 @@ #define LOG_MODULE PcapLogModulePfRingDevice -#include "PfRingDevice.h" -#include "EthLayer.h" -#include "VlanLayer.h" -#include "Logger.h" +#include "pcapplusplus/PfRingDevice.h" +#include "pcapplusplus/EthLayer.h" +#include "pcapplusplus/VlanLayer.h" +#include "pcapplusplus/Logger.h" #include #include #include diff --git a/Pcap++/src/PfRingDeviceList.cpp b/Pcap++/src/PfRingDeviceList.cpp index be41d07be8..15dccccb7d 100644 --- a/Pcap++/src/PfRingDeviceList.cpp +++ b/Pcap++/src/PfRingDeviceList.cpp @@ -4,10 +4,10 @@ #include #include -#include "PfRingDeviceList.h" -#include "SystemUtils.h" -#include "DeviceUtils.h" -#include "Logger.h" +#include "pcapplusplus/PfRingDeviceList.h" +#include "pcapplusplus/SystemUtils.h" +#include "pcapplusplus/DeviceUtils.h" +#include "pcapplusplus/Logger.h" #include "pcap.h" #include "pfring.h" diff --git a/Pcap++/src/RawSocketDevice.cpp b/Pcap++/src/RawSocketDevice.cpp index 00174272c8..b2375fff8d 100644 --- a/Pcap++/src/RawSocketDevice.cpp +++ b/Pcap++/src/RawSocketDevice.cpp @@ -1,4 +1,4 @@ -#include "RawSocketDevice.h" +#include "pcapplusplus/RawSocketDevice.h" #include "EndianPortable.h" #include #ifdef __linux__ @@ -11,11 +11,11 @@ # include #endif #include -#include "Logger.h" -#include "IpUtils.h" -#include "SystemUtils.h" -#include "Packet.h" -#include "EthLayer.h" +#include "pcapplusplus/Logger.h" +#include "pcapplusplus/IpUtils.h" +#include "pcapplusplus/SystemUtils.h" +#include "pcapplusplus/Packet.h" +#include "pcapplusplus/EthLayer.h" namespace pcpp { diff --git a/Pcap++/src/WinPcapLiveDevice.cpp b/Pcap++/src/WinPcapLiveDevice.cpp index 94f20f2cd3..0e6c9bf08f 100644 --- a/Pcap++/src/WinPcapLiveDevice.cpp +++ b/Pcap++/src/WinPcapLiveDevice.cpp @@ -1,8 +1,8 @@ #define LOG_MODULE PcapLogModuleWinPcapLiveDevice -#include "WinPcapLiveDevice.h" -#include "Logger.h" -#include "TimespecTimeval.h" +#include "pcapplusplus/WinPcapLiveDevice.h" +#include "pcapplusplus/Logger.h" +#include "pcapplusplus/TimespecTimeval.h" #include "pcap.h" namespace pcpp diff --git a/Pcap++/src/XdpDevice.cpp b/Pcap++/src/XdpDevice.cpp index d1f9e99f75..9093fd0e9a 100644 --- a/Pcap++/src/XdpDevice.cpp +++ b/Pcap++/src/XdpDevice.cpp @@ -1,9 +1,9 @@ #define LOG_MODULE PcapLogModuleXdpDevice -#include "XdpDevice.h" -#include "GeneralUtils.h" -#include "Logger.h" -#include "Packet.h" +#include "pcapplusplus/XdpDevice.h" +#include "pcapplusplus/GeneralUtils.h" +#include "pcapplusplus/Logger.h" +#include "pcapplusplus/Packet.h" #include #include #include diff --git a/Tests/Packet++Test/main.cpp b/Tests/Packet++Test/main.cpp index b5fdf00748..7553452106 100644 --- a/Tests/Packet++Test/main.cpp +++ b/Tests/Packet++Test/main.cpp @@ -1,11 +1,11 @@ #include #include #include -#include "PcapPlusPlusVersion.h" -#include "PcppTestFrameworkRun.h" -#include "TestDefinition.h" -#include "Logger.h" -#include "../../Tests/Packet++Test/Utils/TestUtils.h" +#include +#include +#include +#include +#include "Utils/TestUtils.h" static struct option PacketTestOptions[] = { { "include-tags", required_argument, nullptr, 't' }, diff --git a/Tests/Pcap++Test/main.cpp b/Tests/Pcap++Test/main.cpp index 3e6479110f..0743afaaf5 100644 --- a/Tests/Pcap++Test/main.cpp +++ b/Tests/Pcap++Test/main.cpp @@ -1,9 +1,9 @@ #include #include -#include "PcapPlusPlusVersion.h" -#include "Logger.h" -#include "PcppTestFrameworkRun.h" -#include "TestDefinition.h" +#include +#include +#include +#include #include "Common/GlobalTestArgs.h" #include "Common/TestUtils.h" #include