#ifndef PACKETPP_IPV6_LAYER #define PACKETPP_IPV6_LAYER #include "Layer.h" #include "IPLayer.h" #include "IPv6Extensions.h" #include "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 NULL is returned * @return A pointer to the extension instance or NULL 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 NULL 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 NULL 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 != NULL && dynamic_cast(curExt) == NULL) curExt = curExt->getNextHeader(); return (TIPv6Extension*)curExt; } template TIPv6Extension* IPv6Layer::addExtension(const TIPv6Extension& extensionHeader) { int offsetToAddHeader = (int)getHeaderLen(); if (!extendLayer(offsetToAddHeader, extensionHeader.getExtensionLen())) { return NULL; } TIPv6Extension* newHeader = new TIPv6Extension(this, (size_t)offsetToAddHeader); (*newHeader) = extensionHeader; if (m_FirstExtension != NULL) { 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 #endif /* PACKETPP_IPV6_LAYER */