You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by al...@apache.org on 2017/11/14 01:48:29 UTC
[15/25] nifi-minifi-cpp git commit: MINIFICPP-250: Initial
implementation fo CapturePacket Processor that uses lipcap.
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/c0a788b3/thirdparty/pcap++/Packet++/header/TcpReassembly.h
----------------------------------------------------------------------
diff --git a/thirdparty/pcap++/Packet++/header/TcpReassembly.h b/thirdparty/pcap++/Packet++/header/TcpReassembly.h
new file mode 100644
index 0000000..ddf7565
--- /dev/null
+++ b/thirdparty/pcap++/Packet++/header/TcpReassembly.h
@@ -0,0 +1,309 @@
+#ifndef PACKETPP_TCP_REASSEMBLY
+#define PACKETPP_TCP_REASSEMBLY
+
+#include <Packet.h>
+#include <IpAddress.h>
+#include <PointerVector.h>
+#include <map>
+
+/**
+ * @file
+ * This is an implementation of TCP reassembly logic, which means reassembly of TCP messages spanning multiple TCP segments (or packets).<BR>
+ * This logic can be helpful 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)
+ */
+
+/**
+ * @namespace pcpp
+ * @brief The main namespace for the PcapPlusPlus lib
+ */
+namespace pcpp
+{
+
+/**
+ * @struct ConnectionData
+ * Represents basic TCP/UDP + IPv4 connection data
+ */
+struct ConnectionData
+{
+ /** Source IP address */
+ IPv4Address srcIP;
+ /** Destination IP address */
+ IPv4Address dstIP;
+ /** Source TCP/UDP port */
+ size_t srcPort;
+ /** Destination TCP/UDP port */
+ size_t dstPort;
+ /** A 4-byte hash key representing the connection */
+ uint32_t flowKey;
+
+ /**
+ * A c'tor for this struct that basically zeros all members
+ */
+ ConnectionData() : srcIP(IPv4Address::Zero), dstIP(IPv4Address::Zero), srcPort(0), dstPort(0), flowKey(0) {}
+};
+
+
+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
+{
+ friend class TcpReassembly;
+
+public:
+
+ /**
+ * A c'tor for this class that basically zeros all members
+ */
+ TcpStreamData();
+
+ /**
+ * A c'tor for this class that get data from outside and set the internal members. Notice that when this class is destroyed it also frees the TCP data it stores
+ * @param[in] tcpData A buffer containing the TCP data piece
+ * @param[in] tcpDataLength The length of the buffer
+ * @param[in] connData TCP connection information for this TCP data
+ */
+ TcpStreamData(uint8_t* tcpData, size_t tcpDataLength, ConnectionData connData);
+
+ /**
+ * A d'tor for this class
+ */
+ ~TcpStreamData();
+
+ /**
+ * A copy c'tor for this class. Notice the data buffer is copied from the source instance to this instance, so even if the source instance is destroyed the data in this instance
+ * stays valid. When this instance is destroyed it also frees the data buffer
+ * @param[in] other The instance to copy from
+ */
+ TcpStreamData(TcpStreamData& other);
+
+ /**
+ * Overload of the assignment operator. Notice the data buffer is copied from the source instance to this instance, so even if the source instance is destroyed the data in this instance
+ * stays valid. When this instance is destroyed it also frees the data buffer
+ * @param[in] other The instance to copy from
+ * @return A reference to this instance
+ */
+ TcpStreamData& operator=(const TcpStreamData& other);
+
+ /**
+ * A getter for the data buffer
+ * @return A pointer to the buffer
+ */
+ inline uint8_t* getData() { return m_Data; }
+
+ /**
+ * A getter for buffer length
+ * @return Buffer length
+ */
+ inline size_t getDataLength() { return m_DataLen; }
+
+ /**
+ * A getter for the connection data
+ * @return The connection data
+ */
+ inline ConnectionData getConnectionData() { return m_Connection; }
+
+private:
+ uint8_t* m_Data;
+ size_t m_DataLen;
+ ConnectionData m_Connection;
+ bool m_DeleteDataOnDestruction;
+
+ void setDeleteDataOnDestruction(bool flag) { m_DeleteDataOnDestruction = flag; }
+ void copyData(const TcpStreamData& other);
+};
+
+
+/**
+ * @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
+ };
+
+ /**
+ * @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 NULL if no cookie provided)
+ */
+ typedef void (*OnTcpMessageReady)(int side, 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 NULL if no cookie provided)
+ */
+ typedef void (*OnTcpConnectionStart)(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 NULL if no cookie provided)
+ */
+ typedef void (*OnTcpConnectionEnd)(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 NULL
+ * @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
+ */
+ TcpReassembly(OnTcpMessageReady onMessageReadyCallback, void* userCookie = NULL, OnTcpConnectionStart onConnectionStartCallback = NULL, OnTcpConnectionEnd onConnectionEndCallback = NULL);
+
+ /**
+ * A d'tor for this class. Frees all internal structures. Notice that if the d'tor is called while connections are still open, all data is lost and TcpReassembly#OnTcpConnectionEnd won't
+ * be called for those connections
+ */
+ ~TcpReassembly();
+
+ /**
+ * 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
+ */
+ void 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
+ */
+ void 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 list of all connections managed by this TcpReassembly instance (both connections that are open and those that are already closed)
+ * @return A list of all connections managed. Notice this list is constant and cannot be changed by the user
+ */
+ const std::vector<ConnectionData>& getConnectionInformation() const;
+
+ /**
+ * 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);
+
+private:
+ struct TcpFragment
+ {
+ uint32_t sequence;
+ size_t dataLength;
+ uint8_t* data;
+
+ TcpFragment() { sequence = 0; dataLength = 0; data = NULL; }
+ ~TcpFragment() { if (data != NULL) delete [] data; }
+ };
+
+ struct TcpOneSideData
+ {
+ uint32_t srcIP;
+ uint16_t srcPort;
+ uint32_t sequence;
+ PointerVector<TcpFragment> tcpFragmentList;
+ bool gotFinOrRst;
+
+ TcpOneSideData() { srcIP = 0; srcPort = 0; sequence = 0; gotFinOrRst = false; }
+ };
+
+ struct TcpReassemblyData
+ {
+ int numOfSides;
+ int prevSide;
+ TcpOneSideData twoSides[2];
+ ConnectionData connData;
+
+ TcpReassemblyData() { numOfSides = 0; prevSide = -1; }
+ };
+
+ OnTcpMessageReady m_OnMessageReadyCallback;
+ OnTcpConnectionStart m_OnConnStart;
+ OnTcpConnectionEnd m_OnConnEnd;
+ void* m_UserCookie;
+ std::map<uint32_t, TcpReassemblyData*> m_ConnectionList;
+ std::map<uint32_t, bool> m_ClosedConnectionList;
+ std::vector<ConnectionData> m_ConnectionInfo;
+
+ void checkOutOfOrderFragments(TcpReassemblyData* tcpReassemblyData, int sideIndex, bool cleanWholeFragList);
+
+ std::string prepareMissingDataMessage(uint32_t missingDataLen);
+
+ void handleFinOrRst(TcpReassemblyData* tcpReassemblyData, int sideIndex, uint32_t flowKey);
+
+ void closeConnectionInternal(uint32_t flowKey, ConnectionEndReason reason);
+};
+
+}
+
+#endif /* PACKETPP_TCP_REASSEMBLY */
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/c0a788b3/thirdparty/pcap++/Packet++/header/TextBasedProtocol.h
----------------------------------------------------------------------
diff --git a/thirdparty/pcap++/Packet++/header/TextBasedProtocol.h b/thirdparty/pcap++/Packet++/header/TextBasedProtocol.h
new file mode 100644
index 0000000..141b4ea
--- /dev/null
+++ b/thirdparty/pcap++/Packet++/header/TextBasedProtocol.h
@@ -0,0 +1,251 @@
+#ifndef PACKETPP_TEXT_BASED_PROTOCOL_LAYER
+#define PACKETPP_TEXT_BASED_PROTOCOL_LAYER
+
+#include <map>
+#include "Layer.h"
+
+
+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);
+
+ /**
+ * @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
+ */
+ inline size_t getFieldSize() { 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
+ */
+ bool setFieldValue(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
+ */
+ inline bool isEndOfHeader() { return m_IsEndOfHeaderField; }
+
+private:
+ HeaderField(std::string name, std::string value, char nameValueSeperator, bool spacesAllowedBetweenNameAndValue);
+ HeaderField(TextBasedProtocolMessage* TextBasedProtocolMessage, int offsetInMessage, char nameValueSeperator, bool spacesAllowedBetweenNameAndValue);
+ char* getData();
+ inline void setNextField(HeaderField* nextField) { m_NextField = nextField; }
+ inline HeaderField* getNextField() { return m_NextField; }
+ void initNewField(std::string name, 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_NameValueSeperator;
+ 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 NULL if field doesn't exist
+ */
+ HeaderField* getFieldByName(std::string fieldName, int index = 0);
+
+ /**
+ * @return A pointer to the first header field exists in this message, or NULL if no such field exists
+ */
+ inline HeaderField* getFirstField() { 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 NULL if prevField is the last field. If prevField is NULL, this method will return NULL
+ */
+ inline HeaderField* getNextField(HeaderField* prevField) { if (prevField != NULL) return prevField->getNextField(); else return NULL; }
+
+ /**
+ * @return The number of header fields currently in the layer (not including CRLF at the end of the header)
+ */
+ int getFieldCount();
+
+ /**
+ * 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 NULL 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 NULL 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 NULL 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 NULL 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 NULL 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 NULL 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 NULL 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 NULL 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 NULL, 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();
+
+ // 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();
+
+ /**
+ * Does nothing for this class
+ */
+ virtual void computeCalculateFields();
+
+protected:
+ TextBasedProtocolMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet);
+ TextBasedProtocolMessage() : m_FieldList(NULL), m_LastField(NULL), 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() = 0;
+ virtual bool spacesAllowedBetweenHeaderFieldNameAndValue() = 0;
+
+ HeaderField* m_FieldList;
+ HeaderField* m_LastField;
+ int m_FieldsOffset;
+ std::multimap<std::string, HeaderField*> m_FieldNameToFieldMap;
+};
+
+
+}
+
+
+#endif // PACKETPP_TEXT_BASED_PROTOCOL_LAYER
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/c0a788b3/thirdparty/pcap++/Packet++/header/UdpLayer.h
----------------------------------------------------------------------
diff --git a/thirdparty/pcap++/Packet++/header/UdpLayer.h b/thirdparty/pcap++/Packet++/header/UdpLayer.h
new file mode 100644
index 0000000..125511d
--- /dev/null
+++ b/thirdparty/pcap++/Packet++/header/UdpLayer.h
@@ -0,0 +1,93 @@
+#ifndef PACKETPP_UDP_LAYER
+#define PACKETPP_UDP_LAYER
+
+#include <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) { m_Protocol = 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
+ */
+ inline udphdr* getUdpHeader() { return (udphdr*)m_Data; };
+
+ /**
+ * 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. Otherwise sets PayloadLayer
+ */
+ void parseNextLayer();
+
+ /**
+ * @return Size of @ref udphdr
+ */
+ inline size_t getHeaderLen() { return sizeof(udphdr); }
+
+ /**
+ * Calculate @ref udphdr#headerChecksum field
+ */
+ void computeCalculateFields();
+
+ std::string toString();
+
+ OsiModelLayer getOsiModelLayer() { return OsiModelTransportLayer; }
+ };
+
+} // namespace pcpp
+
+#endif /* PACKETPP_UDP_LAYER */
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/c0a788b3/thirdparty/pcap++/Packet++/header/VlanLayer.h
----------------------------------------------------------------------
diff --git a/thirdparty/pcap++/Packet++/header/VlanLayer.h b/thirdparty/pcap++/Packet++/header/VlanLayer.h
new file mode 100644
index 0000000..8b55239
--- /dev/null
+++ b/thirdparty/pcap++/Packet++/header/VlanLayer.h
@@ -0,0 +1,141 @@
+#ifndef PACKETPP_VLAN_LAYER
+#define PACKETPP_VLAN_LAYER
+
+#include <Layer.h>
+#include <EthLayer.h>
+#if defined(WIN32) || defined(WINx64)
+#include <winsock2.h>
+#endif
+
+/// @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 {
+#if (BYTE_ORDER == LITTLE_ENDIAN)
+ /** Priority code point (PCP) */
+ uint16_t priority:3,
+ /** Drop eligible indicator (DEI) - formerly CFI */
+ cfi:1,
+ /** VLAN ID */
+ vlanID:12;
+#else
+ uint16_t vlanID:12,
+ cfi:1,
+ priority:3;
+#endif
+ /** 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) { m_Protocol = 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
+ */
+ VlanLayer(const uint16_t vlanID, bool cfi, uint8_t priority, uint16_t etherType);
+
+ ~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
+ */
+ inline vlan_header* getVlanHeader() { 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
+ */
+ inline uint16_t getVlanID() { return getVlanHeader()->vlanID >> 4; }
+
+ /**
+ * @return The CFI bit value
+ * @todo Verify it works in big endian machines as well
+ */
+ inline uint8_t getCFI() { return getVlanHeader()->vlanID & 0x1; }
+
+ /**
+ * @return The priority value
+ * @todo Verify it works in big endian machines as well
+ */
+ inline uint8_t getPriority() { return (getVlanHeader()->vlanID & 0xF) >> 1; }
+
+ /**
+ * 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
+ */
+ inline void setVlanID(uint16_t id) { getVlanHeader()->vlanID = ((id << 4) & 0xff0) | (id >> 8); }
+
+ /**
+ * Set CFI bit
+ * @param[in] cfi The CFI bit to set
+ * @todo Verify it works in big endian machines as well
+ */
+ inline void setCFI(bool cfi) { getVlanHeader()->vlanID |= cfi; }
+
+ /**
+ * Set priority value
+ * @param[in] priority The priority value to set
+ * @todo Verify it works in big endian machines as well
+ */
+ inline void setPriority(uint8_t priority) { getVlanHeader()->vlanID |= ((priority & 0x7) << 1); }
+
+ // implement abstract methods
+
+ /**
+ * Currently identifies the following next layers: IPv4Layer, IPv6Layer, ArpLayer, VlanLayer, MplsLayer. Otherwise sets PayloadLayer
+ */
+ void parseNextLayer();
+
+ /**
+ * @return Size of vlan_header
+ */
+ inline size_t getHeaderLen() { return sizeof(vlan_header); }
+
+ /**
+ * Does nothing for this layer
+ */
+ void computeCalculateFields() {}
+
+ std::string toString();
+
+ OsiModelLayer getOsiModelLayer() { return OsiModelDataLinkLayer; }
+ };
+
+} // namespace pcpp
+
+#endif /* PACKETPP_VLAN_LAYER */
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/c0a788b3/thirdparty/pcap++/Packet++/header/VxlanLayer.h
----------------------------------------------------------------------
diff --git a/thirdparty/pcap++/Packet++/header/VxlanLayer.h b/thirdparty/pcap++/Packet++/header/VxlanLayer.h
new file mode 100644
index 0000000..24f2f4f
--- /dev/null
+++ b/thirdparty/pcap++/Packet++/header/VxlanLayer.h
@@ -0,0 +1,137 @@
+#ifndef PACKETPP_VXLAN_LAYER
+#define PACKETPP_VXLAN_LAYER
+
+#include <Layer.h>
+
+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) { m_Protocol = 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)
+ */
+ 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
+ */
+ inline vxlan_header* getVxlanHeader() { return (vxlan_header*)m_Data; }
+
+ /**
+ * @return The VXLAN Network ID (VNI) value
+ */
+ uint32_t getVNI();
+
+ /**
+ * Set VXLAN Network ID (VNI) value
+ * @param[in] vni VNI value to set
+ */
+ void setVNI(uint32_t vni);
+
+
+ // implement abstract methods
+
+ /**
+ * Next layer for VXLAN is always Ethernet
+ */
+ void parseNextLayer();
+
+ /**
+ * @return Size of vxlan_header
+ */
+ inline size_t getHeaderLen() { return sizeof(vxlan_header); }
+
+ /**
+ * Does nothing for this layer
+ */
+ void computeCalculateFields() {}
+
+ std::string toString();
+
+ OsiModelLayer getOsiModelLayer() { return OsiModelDataLinkLayer; }
+
+ };
+
+}
+
+#endif // PACKETPP_VXLAN_LAYER
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/c0a788b3/thirdparty/pcap++/Packet++/src/ArpLayer.cpp
----------------------------------------------------------------------
diff --git a/thirdparty/pcap++/Packet++/src/ArpLayer.cpp b/thirdparty/pcap++/Packet++/src/ArpLayer.cpp
new file mode 100644
index 0000000..ef3cc86
--- /dev/null
+++ b/thirdparty/pcap++/Packet++/src/ArpLayer.cpp
@@ -0,0 +1,58 @@
+#define LOG_MODULE PacketLogModuleArpLayer
+
+#include <ArpLayer.h>
+#include <EthLayer.h>
+#include <string.h>
+#if defined(WIN32) || defined(WINx64)
+#include <winsock2.h>
+#elif LINUX
+#include <in.h>
+#elif MAC_OS_X
+#include <arpa/inet.h>
+#endif
+
+namespace pcpp
+{
+
+ArpLayer::ArpLayer(ArpOpcode opCode, const MacAddress& senderMacAddr, const MacAddress& targetMacAddr, const IPv4Address senderIpAddr, const IPv4Address& targetIpAddr)
+{
+ m_DataLen = sizeof(arphdr);
+ m_Data = new uint8_t[m_DataLen];
+ memset(m_Data, 0, sizeof(m_DataLen));
+ m_Protocol = ARP;
+
+ arphdr* arpHeader = getArpHeader();
+ arpHeader->opcode = htons(opCode);
+ targetMacAddr.copyTo(arpHeader->targetMacAddr);
+ senderMacAddr.copyTo(arpHeader->senderMacAddr);
+ arpHeader->targetIpAddr = targetIpAddr.toInt();
+ arpHeader->senderIpAddr = senderIpAddr.toInt();
+}
+
+void ArpLayer::computeCalculateFields()
+{
+ arphdr* arpHeader = getArpHeader();
+ arpHeader->hardwareType = htons(1); //Ethernet
+ arpHeader->hardwareSize = 6;
+ arpHeader->protocolType = htons(PCPP_ETHERTYPE_IP); //assume IPv4 over ARP
+ arpHeader->protocolSize = 4; //assume IPv4 over ARP
+ if (arpHeader->opcode == htons(ARP_REQUEST))
+ {
+ MacAddress targetMacAddress("00:00:00:00:00:00");
+ targetMacAddress.copyTo(arpHeader->targetMacAddr);
+ }
+}
+
+std::string ArpLayer::toString()
+{
+ if (ntohs(getArpHeader()->opcode) == ARP_REQUEST)
+ {
+ return "ARP Layer, ARP request, who has " + getTargetIpAddr().toString() + " ? Tell " + getSenderIpAddr().toString();
+ }
+ else
+ {
+ return "ARP Layer, ARP reply, " + getSenderIpAddr().toString() + " is at " + getSenderMacAddress().toString();
+ }
+}
+
+} // namespace pcpp
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/c0a788b3/thirdparty/pcap++/Packet++/src/DhcpLayer.cpp
----------------------------------------------------------------------
diff --git a/thirdparty/pcap++/Packet++/src/DhcpLayer.cpp b/thirdparty/pcap++/Packet++/src/DhcpLayer.cpp
new file mode 100644
index 0000000..9099866
--- /dev/null
+++ b/thirdparty/pcap++/Packet++/src/DhcpLayer.cpp
@@ -0,0 +1,390 @@
+#define LOG_MODULE PacketLogModuleDhcpLayer
+
+#include <DhcpLayer.h>
+#include <Logger.h>
+
+namespace pcpp
+{
+
+#define DHCP_MAGIC_NUMBER 0x63538263
+
+DhcpLayer::DhcpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) : Layer(data, dataLen, prevLayer, packet)
+{
+ m_Protocol = DHCP;
+ m_DhcpOptionsCount = -1;
+}
+
+void DhcpLayer::initDhcpLayer(size_t numOfBytesToAllocate)
+{
+ m_DataLen = numOfBytesToAllocate;
+ m_Data = new uint8_t[m_DataLen];
+ memset(m_Data, 0, m_DataLen);
+ m_Protocol = DHCP;
+ m_DhcpOptionsCount = -1;
+}
+
+DhcpLayer::DhcpLayer() : Layer()
+{
+ initDhcpLayer(sizeof(dhcp_header));
+}
+
+DhcpLayer::DhcpLayer(DhcpMessageType msgType, const MacAddress& clientMacAddr) : Layer()
+{
+ initDhcpLayer(sizeof(dhcp_header) + 4*sizeof(uint8_t));
+
+ setClientHardwareAddress(clientMacAddr);
+
+ uint8_t* msgTypeOptionPtr = m_Data + sizeof(dhcp_header);
+ msgTypeOptionPtr[0] = (uint8_t)DHCPOPT_DHCP_MESSAGE_TYPE; // option code
+ msgTypeOptionPtr[1] = 1; // option len
+ msgTypeOptionPtr[2] = (uint8_t)msgType; // option data - message type
+
+ msgTypeOptionPtr[3] = (uint8_t)DHCPOPT_END;
+}
+
+IPv4Address DhcpLayer::getClientIpAddress()
+{
+ return IPv4Address(getDhcpHeader()->clientIpAddress);
+}
+
+void DhcpLayer::setClientIpAddress(const IPv4Address& addr)
+{
+ getDhcpHeader()->clientIpAddress = addr.toInt();
+}
+
+IPv4Address DhcpLayer::getServerIpAddress()
+{
+ return IPv4Address(getDhcpHeader()->serverIpAddress);
+}
+
+void DhcpLayer::setServerIpAddress(const IPv4Address& addr)
+{
+ getDhcpHeader()->serverIpAddress = addr.toInt();
+}
+
+IPv4Address DhcpLayer::getYourIpAddress()
+{
+ return IPv4Address(getDhcpHeader()->yourIpAddress);
+}
+
+void DhcpLayer::setYourIpAddress(const IPv4Address& addr)
+{
+ getDhcpHeader()->yourIpAddress = addr.toInt();
+}
+
+IPv4Address DhcpLayer::getGatewayIpAddress()
+{
+ return IPv4Address(getDhcpHeader()->gatewayIpAddress);
+}
+
+void DhcpLayer::setGatewayIpAddress(const IPv4Address& addr)
+{
+ getDhcpHeader()->gatewayIpAddress = addr.toInt();
+}
+
+MacAddress DhcpLayer::getClientHardwareAddress()
+{
+ dhcp_header* hdr = getDhcpHeader();
+ if (hdr != NULL && hdr->hardwareType == 1 && hdr->hardwareAddressLength == 6)
+ return MacAddress(hdr->clientHardwareAddress);
+
+ LOG_DEBUG("Hardware type isn't Ethernet or hardware addr len != 6, returning MacAddress:Zero");
+
+ return MacAddress::Zero;
+}
+
+void DhcpLayer::setClientHardwareAddress(const MacAddress& addr)
+{
+ dhcp_header* hdr = getDhcpHeader();
+ hdr->hardwareType = 1; // Ethernet
+ hdr->hardwareAddressLength = 6; // MAC address length
+ addr.copyTo(hdr->clientHardwareAddress);
+}
+
+size_t DhcpLayer::getHeaderLen()
+{
+ // assuming no more layers DHCP
+ return m_DataLen;
+}
+
+void DhcpLayer::computeCalculateFields()
+{
+ dhcp_header* hdr = getDhcpHeader();
+
+ hdr->magicNumber = DHCP_MAGIC_NUMBER;
+
+ DhcpMessageType msgType = getMesageType();
+ switch(msgType)
+ {
+ case DHCP_DISCOVER:
+ case DHCP_REQUEST:
+ case DHCP_DECLINE:
+ case DHCP_RELEASE:
+ case DHCP_INFORM:
+ case DHCP_UNKNOWN_MSG_TYPE:
+ hdr->opCode = DHCP_BOOTREQUEST;
+ break;
+ case DHCP_OFFER:
+ case DHCP_ACK:
+ case DHCP_NAK:
+ hdr->opCode = DHCP_BOOTREPLY;
+ break;
+ default:
+ break;
+ }
+
+ hdr->hardwareType = 1; //Ethernet
+ hdr->hardwareAddressLength = 6; // MAC address length
+}
+
+std::string DhcpLayer::toString()
+{
+ std::string msgType = "Unknown";
+ switch (getMesageType())
+ {
+ case DHCP_DISCOVER:
+ {
+ msgType = "Discover";
+ break;
+ }
+ case DHCP_OFFER:
+ {
+ msgType = "Offer";
+ break;
+ }
+ case DHCP_REQUEST:
+ {
+ msgType = "Request";
+ break;
+ }
+ case DHCP_DECLINE:
+ {
+ msgType = "Decline";
+ break;
+ }
+ case DHCP_ACK:
+ {
+ msgType = "Acknowledge";
+ break;
+ }
+ case DHCP_NAK:
+ {
+ msgType = "Negative Acknowledge";
+ break;
+ }
+ case DHCP_RELEASE:
+ {
+ msgType = "Release";
+ break;
+ }
+ case DHCP_INFORM:
+ {
+ msgType = "Inform";
+ break;
+ }
+ default:
+ break;
+
+ }
+
+ return "DHCP layer (" + msgType + ")";
+}
+
+DhcpMessageType DhcpLayer::getMesageType()
+{
+ DhcpOptionData* opt = getOptionData(DHCPOPT_DHCP_MESSAGE_TYPE);
+ if (opt == NULL)
+ return DHCP_UNKNOWN_MSG_TYPE;
+
+ return (DhcpMessageType)opt->getValueAs<uint8_t>();
+}
+
+bool DhcpLayer::setMesageType(DhcpMessageType msgType)
+{
+ if (msgType == DHCP_UNKNOWN_MSG_TYPE)
+ return false;
+
+ DhcpOptionData* opt = getOptionData(DHCPOPT_DHCP_MESSAGE_TYPE);
+ if (opt == NULL)
+ {
+ opt = addOptionAfter(DHCPOPT_DHCP_MESSAGE_TYPE, 1, NULL, DHCPOPT_UNKNOWN);
+ if (opt == NULL)
+ return false;
+ }
+
+ opt->setValue<uint8_t>((uint8_t)msgType);
+ return true;
+}
+
+DhcpOptionData* DhcpLayer::castPtrToOptionData(uint8_t* ptr)
+{
+ return (DhcpOptionData*)ptr;
+}
+
+DhcpOptionData* DhcpLayer::getOptionData(DhcpOptionTypes option)
+{
+ // check if there are DHCP options at all
+ if (m_DataLen <= sizeof(dhcp_header))
+ return NULL;
+
+ if (option == DHCPOPT_UNKNOWN)
+ return NULL;
+
+ uint8_t* curOptPtr = m_Data + sizeof(dhcp_header);
+ while ((curOptPtr - m_Data) < (int)m_DataLen)
+ {
+ DhcpOptionData* curOpt = castPtrToOptionData(curOptPtr);
+ if ((int)curOpt->opCode == option)
+ return curOpt;
+
+ curOptPtr += curOpt->getTotalSize();
+ }
+
+ return NULL;
+}
+
+DhcpOptionData* DhcpLayer::getFirstOptionData()
+{
+ // check if there are DHCP options at all
+ if (getHeaderLen() <= sizeof(dhcp_header))
+ return NULL;
+
+ uint8_t* curOptPtr = m_Data + sizeof(dhcp_header);
+ return castPtrToOptionData(curOptPtr);
+}
+
+DhcpOptionData* DhcpLayer::getNextOptionData(DhcpOptionData* dhcpOption)
+{
+ if (dhcpOption == NULL)
+ return NULL;
+
+ // prev opt was the last opt
+ if ((uint8_t*)dhcpOption + dhcpOption->getTotalSize() - m_Data >= (int)getHeaderLen())
+ return NULL;
+
+ DhcpOptionData* nextOption = castPtrToOptionData((uint8_t*)dhcpOption + dhcpOption->getTotalSize());
+
+ // TOOD: see if this is necessary
+ // if (nextOption->option == TCPOPT_DUMMY)
+ // return NULL;
+
+ return nextOption;
+}
+
+size_t DhcpLayer::getOptionsCount()
+{
+ if (m_DhcpOptionsCount != (size_t)-1)
+ return m_DhcpOptionsCount;
+
+ m_DhcpOptionsCount = 0;
+ DhcpOptionData* curOpt = getFirstOptionData();
+ while (curOpt != NULL)
+ {
+ m_DhcpOptionsCount++;
+ curOpt = getNextOptionData(curOpt);
+ }
+
+ return m_DhcpOptionsCount;
+}
+
+DhcpOptionData* DhcpLayer::addOptionAt(DhcpOptionTypes optionType, uint16_t optionLen, const uint8_t* optionData, int offset)
+{
+ size_t sizeToExtend = optionLen + 2*sizeof(uint8_t);
+
+ if ((optionType == DHCPOPT_END || optionType == DHCPOPT_PAD))
+ {
+ if (optionLen != 0)
+ {
+ LOG_ERROR("Can't set DHCP END option or DHCP PAD option with size different than 0, tried to set size %d", optionLen);
+ return NULL;
+ }
+
+ sizeToExtend = sizeof(uint8_t);
+ }
+
+ if (!extendLayer(offset, sizeToExtend))
+ {
+ LOG_ERROR("Could not extend DhcpLayer in [%d] bytes", optionLen);
+ return NULL;
+ }
+
+ uint8_t optionTypeVal = (uint8_t)optionType;
+ memcpy(m_Data + offset, &optionTypeVal, sizeof(uint8_t));
+
+ if (optionLen > 0)
+ {
+ memcpy(m_Data + offset + sizeof(uint8_t), &optionLen, sizeof(uint8_t));
+ if (optionLen > 1 && optionData != NULL)
+ memcpy(m_Data + offset + 2*sizeof(uint8_t), optionData, optionLen);
+ }
+
+ uint8_t* newOptPtr = m_Data + offset;
+
+ m_DhcpOptionsCount++;
+
+ return castPtrToOptionData(newOptPtr);
+}
+
+DhcpOptionData* DhcpLayer::addOption(DhcpOptionTypes optionType, uint16_t optionLen, const uint8_t* optionData)
+{
+ int offset = 0;
+ DhcpOptionData* endOpt = getOptionData(DHCPOPT_END);
+ if (endOpt != NULL)
+ offset = ((uint8_t*)endOpt) - m_Data;
+ else
+ offset = getHeaderLen();
+
+ return addOptionAt(optionType, optionLen, optionData, offset);
+}
+
+DhcpOptionData* DhcpLayer::addOptionAfter(DhcpOptionTypes optionType, uint16_t optionLen, const uint8_t* optionData, DhcpOptionTypes prevOption)
+{
+ int offset = 0;
+
+ DhcpOptionData* prevOpt = getOptionData(prevOption);
+
+ if (prevOpt == NULL)
+ {
+ offset = sizeof(dhcp_header);
+ }
+ else
+ {
+ offset = (uint8_t*)prevOpt + prevOpt->getTotalSize() - m_Data;
+ }
+
+ return addOptionAt(optionType, optionLen, optionData, offset);
+}
+
+bool DhcpLayer::removeOption(DhcpOptionTypes optionType)
+{
+ DhcpOptionData* opt = getOptionData(optionType);
+ if (opt == NULL)
+ {
+ return false;
+ }
+
+ int offset = (uint8_t*)opt - m_Data;
+
+ if (!shortenLayer(offset, opt->getTotalSize()))
+ {
+ return false;
+ }
+
+ m_DhcpOptionsCount--;
+
+ return true;
+}
+
+bool DhcpLayer::removeAllOptions()
+{
+ int offset = sizeof(dhcp_header);
+
+ if (!shortenLayer(offset, getHeaderLen()-offset))
+ return false;
+
+ m_DhcpOptionsCount = 0;
+ return true;
+}
+
+
+}
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/c0a788b3/thirdparty/pcap++/Packet++/src/DnsLayer.cpp
----------------------------------------------------------------------
diff --git a/thirdparty/pcap++/Packet++/src/DnsLayer.cpp b/thirdparty/pcap++/Packet++/src/DnsLayer.cpp
new file mode 100644
index 0000000..880ec14
--- /dev/null
+++ b/thirdparty/pcap++/Packet++/src/DnsLayer.cpp
@@ -0,0 +1,1240 @@
+#define LOG_MODULE PacketLogModuleDnsLayer
+
+#include "DnsLayer.h"
+#include "Logger.h"
+#include "IpAddress.h"
+#include <sstream>
+#include <string.h>
+#include <iomanip>
+#include <stdlib.h>
+
+namespace pcpp
+{
+
+static std::map<uint16_t, bool> createDNSPortMap()
+{
+ std::map<uint16_t, bool> result;
+ result[53] = true;
+ result[5353] = true;
+ result[5355] = true;
+ return result;
+}
+
+static const std::map<uint16_t, bool> DNSPortMap = createDNSPortMap();
+
+
+
+IDnsResource::IDnsResource(DnsLayer* dnsLayer, size_t offsetInLayer)
+ : m_DnsLayer(dnsLayer), m_OffsetInLayer(offsetInLayer), m_NextResource(NULL)
+{
+ m_NameLength = decodeName((const char*)getRawData(), m_DecodedName);
+}
+
+IDnsResource::IDnsResource(uint8_t* emptyRawData)
+ : m_DnsLayer(NULL), m_OffsetInLayer(0), m_NextResource(NULL), m_DecodedName(""), m_NameLength(0), m_ExternalRawData(emptyRawData)
+{
+}
+
+uint8_t* IDnsResource::getRawData()
+{
+ if (m_DnsLayer == NULL)
+ return m_ExternalRawData;
+
+ return m_DnsLayer->m_Data + m_OffsetInLayer;
+}
+
+size_t IDnsResource::decodeName(const char* encodedName, std::string& result, int iteration)
+{
+ size_t encodedNameLength = 0;
+ result = "";
+
+ size_t curOffsetInLayer = (uint8_t*)encodedName - m_DnsLayer->m_Data;
+ if (curOffsetInLayer + 1 > m_DnsLayer->m_DataLen)
+ return encodedNameLength;
+
+ if (iteration > 20)
+ return encodedNameLength;
+
+ uint8_t wordLength = encodedName[0];
+
+ // A string to parse
+ while (wordLength != 0)
+ {
+ // A pointer to another place in the packet
+ if ((wordLength & 0xc0) == 0xc0)
+ {
+ if (curOffsetInLayer + 2 > m_DnsLayer->m_DataLen)
+ return encodedNameLength;
+
+ uint16_t offsetInLayer = (wordLength & 0x3f)*256 + (0xFF & encodedName[1]);
+ if (offsetInLayer < sizeof(dnshdr) || offsetInLayer >= m_DnsLayer->m_DataLen)
+ {
+ LOG_ERROR("DNS parsing error: name pointer is illegal");
+ return 0;
+ }
+
+ std::string tempResult;
+ decodeName((const char*)(m_DnsLayer->m_Data + offsetInLayer), tempResult, iteration+1);
+ result += tempResult;
+
+ // in this case the length of the pointer is: 1B for 0xc0 + 1B for the offset itself
+ return encodedNameLength + sizeof(uint16_t);
+ }
+ else
+ {
+ if (curOffsetInLayer + wordLength + 1 > m_DnsLayer->m_DataLen)
+ return encodedNameLength;
+
+ result.append(encodedName+1, wordLength);
+ result.append(".");
+ encodedName += wordLength + 1;
+ encodedNameLength += wordLength + 1;
+
+ curOffsetInLayer = (uint8_t*)encodedName - m_DnsLayer->m_Data;
+ if (curOffsetInLayer + 1 > m_DnsLayer->m_DataLen)
+ return encodedNameLength;
+
+ wordLength = encodedName[0];
+ }
+ }
+
+ // remove the last "."
+ if (result != "")
+ result = result.substr(0, result.size()-1);
+
+ // add the last '\0' to encodedNameLength
+ encodedNameLength++;
+ return encodedNameLength;
+}
+
+
+void IDnsResource::encodeName(const std::string& decodedName, char* result, size_t& resultLen)
+{
+ resultLen = 0;
+ std::stringstream strstream(decodedName);
+ std::string word;
+ while (getline(strstream, word, '.'))
+ {
+ result[0] = word.length();
+ result++;
+ memcpy(result, word.c_str(), word.length());
+ result += word.length();
+ resultLen += word.length() + 1;
+ }
+
+ // add '\0' at the end
+ result[0] = 0;
+ resultLen++;
+}
+
+
+DnsType IDnsResource::getDnsType()
+{
+ uint16_t dnsType = *(uint16_t*)(getRawData() + m_NameLength);
+ return (DnsType)ntohs(dnsType);
+}
+
+void IDnsResource::setDnsType(DnsType newType)
+{
+ uint16_t newTypeAsInt = htons((uint16_t)newType);
+ memcpy(getRawData() + m_NameLength, &newTypeAsInt, sizeof(uint16_t));
+}
+
+DnsClass IDnsResource::getDnsClass()
+{
+ uint16_t dnsClass = *(uint16_t*)(getRawData() + m_NameLength + sizeof(uint16_t));
+ return (DnsClass)ntohs(dnsClass);
+}
+
+void IDnsResource::setDnsClass(DnsClass newClass)
+{
+ uint16_t newClassAsInt = htons((uint16_t)newClass);
+ memcpy(getRawData() + m_NameLength + sizeof(uint16_t), &newClassAsInt, sizeof(uint16_t));
+}
+
+bool IDnsResource::setName(const std::string& newName)
+{
+ char encodedName[256];
+ size_t encodedNameLen = 0;
+ encodeName(newName, encodedName, encodedNameLen);
+ if (m_DnsLayer != NULL)
+ {
+ if (encodedNameLen > m_NameLength)
+ {
+ if (!m_DnsLayer->extendLayer(m_OffsetInLayer, encodedNameLen-m_NameLength, this))
+ {
+ LOG_ERROR("Couldn't set name for DNS query, unable to extend layer");
+ return false;
+ }
+ }
+ else if (encodedNameLen < m_NameLength)
+ {
+ if (!m_DnsLayer->shortenLayer(m_OffsetInLayer, m_NameLength-encodedNameLen, this))
+ {
+ LOG_ERROR("Couldn't set name for DNS query, unable to shorten layer");
+ return false;
+ }
+ }
+ }
+ else
+ {
+ size_t size = getSize();
+ char* tempData = new char[size];
+ memcpy(tempData, m_ExternalRawData, getSize());
+ memcpy(m_ExternalRawData + encodedNameLen, tempData, getSize());
+ delete[] tempData;
+ }
+
+ memcpy(getRawData(), encodedName, encodedNameLen);
+ m_NameLength = encodedNameLen;
+ m_DecodedName = newName;
+
+ return true;
+}
+
+void IDnsResource::setDnsLayer(DnsLayer* dnsLayer, size_t offsetInLayer)
+{
+ memcpy(dnsLayer->m_Data + offsetInLayer, m_ExternalRawData, getSize());
+ m_DnsLayer = dnsLayer;
+ m_OffsetInLayer = offsetInLayer;
+ m_ExternalRawData = NULL;
+}
+
+uint32_t DnsResource::getTTL()
+{
+ uint32_t ttl = *(uint32_t*)(getRawData() + m_NameLength + 2*sizeof(uint16_t));
+ return ntohl(ttl);
+}
+
+void DnsResource::setTTL(uint32_t newTTL)
+{
+ newTTL = htonl(newTTL);
+ memcpy(getRawData() + m_NameLength + 2*sizeof(uint16_t), &newTTL, sizeof(uint32_t));
+}
+
+size_t DnsResource::getDataLength()
+{
+ uint16_t dataLength = *(uint16_t*)(getRawData() + m_NameLength + 2*sizeof(uint16_t) + sizeof(uint32_t));
+ return ntohs(dataLength);
+}
+
+std::string DnsResource::getDataAsString()
+{
+ uint8_t* resourceRawData = getRawData() + m_NameLength + 3*sizeof(uint16_t) + sizeof(uint32_t);
+ size_t dataLength = getDataLength();
+
+ DnsType dnsType = getDnsType();
+
+ std::string result = "";
+
+ switch (dnsType)
+ {
+ case DNS_TYPE_A:
+ {
+ if (dataLength != 4)
+ {
+ LOG_ERROR("DNS type is A but resource length is not 4 - packet is malformed");
+ break;
+ }
+
+ uint32_t addrAsInt = *(uint32_t*)resourceRawData;
+ IPv4Address ip4AddrElad(addrAsInt);
+ if (!ip4AddrElad.isValid())
+ {
+ LOG_ERROR("Invalid IPv4 address for DNS resource of type A");
+ break;
+ }
+
+ result = ip4AddrElad.toString();
+ break;
+ }
+
+ case DNS_TYPE_AAAA:
+ {
+ if (dataLength != 16)
+ {
+ LOG_ERROR("DNS type is AAAA but resource length is not 16 - packet is malformed");
+ break;
+ }
+
+ IPv6Address ip6Addr(resourceRawData);
+ if (!ip6Addr.isValid())
+ {
+ LOG_ERROR("Invalid IPv6 address for DNS resource of type AAAA");
+ break;
+ }
+ result = ip6Addr.toString();
+ break;
+ }
+
+ case DNS_TYPE_NS:
+ case DNS_TYPE_CNAME:
+ case DNS_TYPE_DNAM:
+ case DNS_TYPE_PTR:
+ case DNS_TYPE_MX:
+ {
+ decodeName((const char*)resourceRawData, result);
+ break;
+ }
+
+ default:
+ {
+ std::stringstream sstream;
+ sstream << "0x" << std::hex;
+ for(size_t i = 0; i < dataLength; i++)
+ sstream << std::setw(2) << std::setfill('0') << (int)resourceRawData[i];
+ result = sstream.str();
+
+ break;
+ }
+
+ }
+
+ return result;
+
+}
+
+bool DnsResource::setData(const std::string& dataAsString)
+{
+ // convert data to byte array according to the DNS type
+ size_t dataLength = 0;
+ uint8_t dataAsByteArr[256];
+
+ switch (getDnsType())
+ {
+ case DNS_TYPE_A:
+ {
+ IPv4Address ip4Addr((std::string)dataAsString);
+ if (!ip4Addr.isValid())
+ {
+ LOG_ERROR("Requested DNS type is A but data '%s' is an illegal IPv4 address. Couldn't set data for resource", dataAsString.c_str());
+ return false;
+ }
+ dataLength = 4;
+ uint32_t addrAsInt = ip4Addr.toInt();
+ memcpy(dataAsByteArr, &addrAsInt, dataLength);
+ break;
+ }
+
+ case DNS_TYPE_AAAA:
+ {
+ IPv6Address ip6Addr((std::string)dataAsString);
+ if (!ip6Addr.isValid())
+ {
+ LOG_ERROR("Requested DNS type is AAAA but data '%s' is an illegal IPv6 address. Couldn't set data for resource", dataAsString.c_str());
+ return false;
+ }
+ dataLength = 16;
+ ip6Addr.copyTo(dataAsByteArr);
+ break;
+ }
+
+ case DNS_TYPE_NS:
+ case DNS_TYPE_CNAME:
+ case DNS_TYPE_DNAM:
+ case DNS_TYPE_PTR:
+ case DNS_TYPE_MX:
+ {
+ encodeName(dataAsString, (char*)dataAsByteArr, dataLength);
+ break;
+ }
+
+ default:
+ {
+ if (dataAsString.substr(0, 2) != "0x")
+ {
+ LOG_ERROR("DNS data for DNS type %d should be an hex stream and begin with '0x'", getDnsType());
+ return false;
+ }
+ if (dataAsString.length() % 2 != 0)
+ {
+ LOG_ERROR("DNS data for DNS type %d should be an hex stream with an even number of character. "
+ "Current character count is an odd number: %d", getDnsType(), (int)dataAsString.length());
+ return false;
+ }
+ char* dataAsCharPtr = (char*)dataAsString.c_str();
+ dataAsCharPtr += 2; //skip the '0x' prefix
+ char strtolBuf[5] = { '0', 'x', 0, 0, 0 };
+ char* strtolEndPtr;
+ while (*dataAsCharPtr != 0)
+ {
+ strtolBuf[2] = dataAsCharPtr[0];
+ strtolBuf[3] = dataAsCharPtr[1];
+ dataAsByteArr[dataLength] = strtol(strtolBuf, &strtolEndPtr, 0);
+
+ if (strtolEndPtr[0] != '\0') {
+ //non-hexadecimal character encountered
+ LOG_ERROR("DNS data for DNS type %d should be a valid hex stream", getDnsType());
+ return false;
+ }
+
+ dataAsCharPtr += 2 * sizeof(char);
+ dataLength++;
+ }
+ break;
+ }
+ }
+
+ size_t dataLengthOffset = m_NameLength + (2*sizeof(uint16_t)) + sizeof(uint32_t);
+ size_t dataOffset = dataLengthOffset + sizeof(uint16_t);
+
+ if (m_DnsLayer != NULL)
+ {
+ size_t curLength = getDataLength();
+ if (dataLength > curLength)
+ {
+ if (!m_DnsLayer->extendLayer(m_OffsetInLayer + dataOffset, dataLength-curLength, this))
+ {
+ LOG_ERROR("Couldn't set data for DNS query, unable to extend layer");
+ return false;
+ }
+ }
+ else if (dataLength < curLength)
+ {
+ if (!m_DnsLayer->shortenLayer(m_OffsetInLayer + dataOffset, curLength-dataLength, this))
+ {
+ LOG_ERROR("Couldn't set data for DNS query, unable to shorten layer");
+ return false;
+ }
+ }
+ }
+
+ // write data to resource
+ memcpy(getRawData() + dataOffset, dataAsByteArr, dataLength);
+ //update data length in resource
+ dataLength = htons(dataLength);
+ memcpy(getRawData() + dataLengthOffset, &dataLength, sizeof(uint16_t));
+
+ return true;
+}
+
+uint16_t DnsResource::getCustomDnsClass()
+{
+ uint16_t value = *(uint16_t*)(getRawData() + m_NameLength + sizeof(uint16_t));
+ return ntohs(value);
+}
+
+void DnsResource::setCustomDnsClass(uint16_t customValue)
+{
+ memcpy(getRawData() + m_NameLength + sizeof(uint16_t), &customValue, sizeof(uint16_t));
+}
+
+DnsLayer::DnsLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
+ : Layer(data, dataLen, prevLayer, packet)
+{
+ m_Protocol = DNS;
+ m_ResourceList = NULL;
+
+ m_FirstQuery = NULL;
+ m_FirstAnswer = NULL;
+ m_FirstAuthority = NULL;
+ m_FirstAdditional = NULL;
+
+ parseResources();
+}
+
+DnsLayer::DnsLayer()
+{
+ m_DataLen = sizeof(dnshdr);
+ m_Data = new uint8_t[m_DataLen];
+ memset(m_Data, 0, m_DataLen);
+ m_Protocol = DNS;
+
+ m_ResourceList = NULL;
+
+ m_FirstQuery = NULL;
+ m_FirstAnswer = NULL;
+ m_FirstAuthority = NULL;
+ m_FirstAdditional = NULL;
+}
+
+DnsLayer::DnsLayer(const DnsLayer& other) : Layer(other)
+{
+ m_Protocol = DNS;
+
+ m_ResourceList = NULL;
+
+ m_FirstQuery = NULL;
+ m_FirstAnswer = NULL;
+ m_FirstAuthority = NULL;
+ m_FirstAdditional = NULL;
+
+ parseResources();
+}
+
+DnsLayer& DnsLayer::operator=(const DnsLayer& other)
+{
+ Layer::operator=(other);
+
+ IDnsResource* curResource = m_ResourceList;
+ while (curResource != NULL)
+ {
+ IDnsResource* temp = curResource->getNextResource();
+ delete curResource;
+ curResource = temp;
+ }
+
+ m_ResourceList = NULL;
+
+ m_FirstQuery = NULL;
+ m_FirstAnswer = NULL;
+ m_FirstAuthority = NULL;
+ m_FirstAdditional = NULL;
+
+ parseResources();
+
+ return (*this);
+}
+
+DnsLayer::~DnsLayer()
+{
+ IDnsResource* curResource = m_ResourceList;
+ while (curResource != NULL)
+ {
+ IDnsResource* nextResource = curResource->getNextResource();
+ delete curResource;
+ curResource = nextResource;
+ }
+}
+
+bool DnsLayer::extendLayer(int offsetInLayer, size_t numOfBytesToExtend, IDnsResource* resource)
+{
+ if (!Layer::extendLayer(offsetInLayer, numOfBytesToExtend))
+ return false;
+
+ IDnsResource* curResource = resource->getNextResource();
+ while (curResource != NULL)
+ {
+ curResource->m_OffsetInLayer += numOfBytesToExtend;
+ curResource = curResource->getNextResource();
+ }
+ return true;
+}
+
+
+bool DnsLayer::shortenLayer(int offsetInLayer, size_t numOfBytesToShorten, IDnsResource* resource)
+{
+ if (!Layer::shortenLayer(offsetInLayer, numOfBytesToShorten))
+ return false;
+
+ IDnsResource* curResource = resource->getNextResource();
+ while (curResource != NULL)
+ {
+ curResource->m_OffsetInLayer -= numOfBytesToShorten;
+ curResource = curResource->getNextResource();
+ }
+ return true;
+}
+
+
+void DnsLayer::parseResources()
+{
+ size_t offsetInPacket = sizeof(dnshdr);
+ IDnsResource* curResource = m_ResourceList;
+
+ uint16_t numOfQuestions = ntohs(getDnsHeader()->numberOfQuestions);
+ uint16_t numOfAnswers = ntohs(getDnsHeader()->numberOfAnswers);
+ uint16_t numOfAuthority = ntohs(getDnsHeader()->numberOfAuthority);
+ uint16_t numOfAdditional = ntohs(getDnsHeader()->numberOfAdditional);
+
+ uint16_t numOfOtherResources = numOfQuestions + numOfAnswers + numOfAuthority + numOfAdditional;
+
+ if (numOfOtherResources > 300)
+ {
+ LOG_ERROR("DNS layer contains more than 300 resources, probably a bad packet. "
+ "Skipping parsing DNS resources");
+ return;
+ }
+
+ for (uint16_t i = 0; i < numOfOtherResources; i++)
+ {
+ IDnsResource::ResourceType resType;
+ if (numOfQuestions > 0)
+ {
+ resType = IDnsResource::DnsQuery;
+ numOfQuestions--;
+ }
+ else if (numOfAnswers > 0)
+ {
+ resType = IDnsResource::DnsAnswer;
+ numOfAnswers--;
+ }
+ else if (numOfAuthority > 0)
+ {
+ resType = IDnsResource::DnsAuthority;
+ numOfAuthority--;
+ }
+ else
+ {
+ resType = IDnsResource::DnsAdditional;
+ numOfAdditional--;
+ }
+
+ IDnsResource* newResource = NULL;
+ if (resType == IDnsResource::DnsQuery)
+ newResource = new DnsQuery(this, offsetInPacket);
+ else
+ newResource = new DnsResource(this, offsetInPacket, resType);
+
+ offsetInPacket += newResource->getSize();
+
+ if (offsetInPacket > m_DataLen)
+ {
+ //Parse packet failed, DNS resource is out of bounds. Probably a bad packet
+ delete newResource;
+ return;
+ }
+
+ // this resource is the first resource
+ if (m_ResourceList == NULL)
+ {
+ m_ResourceList = newResource;
+ curResource = m_ResourceList;
+ }
+ else
+ {
+ curResource->setNexResource(newResource);
+ curResource = curResource->getNextResource();
+ }
+
+ if (resType == IDnsResource::DnsQuery && m_FirstQuery == NULL)
+ m_FirstQuery = dynamic_cast<DnsQuery*>(newResource);
+ else if (resType == IDnsResource::DnsAnswer && m_FirstAnswer == NULL)
+ m_FirstAnswer = dynamic_cast<DnsResource*>(newResource);
+ else if (resType == IDnsResource::DnsAuthority && m_FirstAuthority == NULL)
+ m_FirstAuthority = dynamic_cast<DnsResource*>(newResource);
+ else if (resType == IDnsResource::DnsAdditional && m_FirstAdditional == NULL)
+ m_FirstAdditional = dynamic_cast<DnsResource*>(newResource);
+ }
+
+}
+
+IDnsResource* DnsLayer::getResourceByName(IDnsResource* startFrom, size_t resourceCount, const std::string& name, bool exactMatch)
+{
+ uint16_t i = 0;
+ while (i < resourceCount)
+ {
+ if (startFrom == NULL)
+ return NULL;
+
+ std::string resourceName = startFrom->getName();
+ if (exactMatch && resourceName == name)
+ return startFrom;
+ else if (!exactMatch && resourceName.find(name) != std::string::npos)
+ return startFrom;
+
+ startFrom = startFrom->getNextResource();
+
+ i++;
+ }
+
+ return NULL;
+}
+
+DnsQuery* DnsLayer::getQuery(const std::string& name, bool exactMatch)
+{
+ uint16_t numOfQueries = ntohs(getDnsHeader()->numberOfQuestions);
+ IDnsResource* res = getResourceByName(m_FirstQuery, numOfQueries, name, exactMatch);
+ if (res != NULL)
+ return dynamic_cast<DnsQuery*>(res);
+ return NULL;
+}
+
+
+DnsQuery* DnsLayer::getFirstQuery()
+{
+ return m_FirstQuery;
+}
+
+
+DnsQuery* DnsLayer::getNextQuery(DnsQuery* query)
+{
+ if (query == NULL || query->getNextResource() == NULL || query->getType() != IDnsResource::DnsQuery)
+ return NULL;
+
+ return dynamic_cast<DnsQuery*>(query->getNextResource());
+}
+
+size_t DnsLayer::getQueryCount()
+{
+ return ntohs(getDnsHeader()->numberOfQuestions);
+}
+
+DnsResource* DnsLayer::getAnswer(const std::string& name, bool exactMatch)
+{
+ uint16_t numOfAnswers = ntohs(getDnsHeader()->numberOfAnswers);
+ IDnsResource* res = getResourceByName(m_FirstAnswer, numOfAnswers, name, exactMatch);
+ if (res != NULL)
+ return dynamic_cast<DnsResource*>(res);
+ return NULL;
+}
+
+DnsResource* DnsLayer::getFirstAnswer()
+{
+ return m_FirstAnswer;
+}
+
+DnsResource* DnsLayer::getNextAnswer(DnsResource* answer)
+{
+ if (answer == NULL
+ || answer->getNextResource() == NULL
+ || answer->getType() != IDnsResource::DnsAnswer
+ || answer->getNextResource()->getType() != IDnsResource::DnsAnswer)
+ return NULL;
+
+ return dynamic_cast<DnsResource*>(answer->getNextResource());
+}
+
+size_t DnsLayer::getAnswerCount()
+{
+ return ntohs(getDnsHeader()->numberOfAnswers);
+}
+
+DnsResource* DnsLayer::getAuthority(const std::string& name, bool exactMatch)
+{
+ uint16_t numOfAuthorities = ntohs(getDnsHeader()->numberOfAuthority);
+ IDnsResource* res = getResourceByName(m_FirstAuthority, numOfAuthorities, name, exactMatch);
+ if (res != NULL)
+ return dynamic_cast<DnsResource*>(res);
+ return NULL;
+}
+
+DnsResource* DnsLayer::getFirstAuthority()
+{
+ return m_FirstAuthority;
+}
+
+DnsResource* DnsLayer::getNextAuthority(DnsResource* authority)
+{
+ if (authority == NULL
+ || authority->getNextResource() == NULL
+ || authority->getType() != IDnsResource::DnsAuthority
+ || authority->getNextResource()->getType() != IDnsResource::DnsAuthority)
+ return NULL;
+
+ return dynamic_cast<DnsResource*>(authority->getNextResource());
+}
+
+size_t DnsLayer::getAuthorityCount()
+{
+ return ntohs(getDnsHeader()->numberOfAuthority);
+}
+
+DnsResource* DnsLayer::getAdditionalRecord(const std::string& name, bool exactMatch)
+{
+ uint16_t numOfAdditionalRecords = ntohs(getDnsHeader()->numberOfAdditional);
+ IDnsResource* res = getResourceByName(m_FirstAdditional, numOfAdditionalRecords, name, exactMatch);
+ if (res != NULL)
+ return dynamic_cast<DnsResource*>(res);
+ return NULL;
+}
+
+DnsResource* DnsLayer::getFirstAdditionalRecord()
+{
+ return m_FirstAdditional;
+}
+
+DnsResource* DnsLayer::getNextAdditionalRecord(DnsResource* additionalRecord)
+{
+ if (additionalRecord == NULL
+ || additionalRecord->getNextResource() == NULL
+ || additionalRecord->getType() != IDnsResource::DnsAdditional
+ || additionalRecord->getNextResource()->getType() != IDnsResource::DnsAdditional)
+ return NULL;
+
+ return dynamic_cast<DnsResource*>(additionalRecord->getNextResource());
+}
+
+size_t DnsLayer::getAdditionalRecordCount()
+{
+ return ntohs(getDnsHeader()->numberOfAdditional);
+}
+
+std::string DnsLayer::toString()
+{
+ std::ostringstream tidAsString;
+ tidAsString << ntohs(getDnsHeader()->transactionID);
+
+ std::ostringstream queryCount;
+ queryCount << getQueryCount();
+
+ std::ostringstream answerCount;
+ answerCount << getAnswerCount();
+
+ std::ostringstream authorityCount;
+ authorityCount << getAuthorityCount();
+
+ std::ostringstream additionalCount;
+ additionalCount << getAdditionalRecordCount();
+
+ if (getAnswerCount() > 0)
+ {
+ return "DNS query response, ID: " + tidAsString.str() + ";" +
+ " queries: " + queryCount.str() +
+ ", answers: " + answerCount.str() +
+ ", authorities: " + authorityCount.str() +
+ ", additional record: " + additionalCount.str();
+ }
+ else if (getQueryCount() > 0)
+ {
+ return "DNS query, ID: " + tidAsString.str() + ";" +
+ " queries: " + queryCount.str() +
+ ", answers: " + answerCount.str() +
+ ", authorities: " + authorityCount.str() +
+ ", additional record: " + additionalCount.str();
+
+ }
+ else // not likely - a DNS with no answers and no queries
+ {
+ return "DNS record without queries and answers, ID: " + tidAsString.str() + ";" +
+ " queries: " + queryCount.str() +
+ ", answers: " + answerCount.str() +
+ ", authorities: " + authorityCount.str() +
+ ", additional record: " + additionalCount.str();
+ }
+}
+
+IDnsResource* DnsLayer::getFirstResource(IDnsResource::ResourceType resType)
+{
+ switch (resType)
+ {
+ case IDnsResource::DnsQuery:
+ {
+ return m_FirstQuery;
+ }
+ case IDnsResource::DnsAnswer:
+ {
+ return m_FirstAnswer;
+ }
+ case IDnsResource::DnsAuthority:
+ {
+ return m_FirstAuthority;
+ }
+ case IDnsResource::DnsAdditional:
+ {
+ return m_FirstAdditional;
+ }
+ default:
+ return NULL;
+ }
+}
+
+void DnsLayer::setFirstResource(IDnsResource::ResourceType resType, IDnsResource* resource)
+{
+ switch (resType)
+ {
+ case IDnsResource::DnsQuery:
+ {
+ m_FirstQuery = dynamic_cast<DnsQuery*>(resource);
+ break;
+ }
+ case IDnsResource::DnsAnswer:
+ {
+ m_FirstAnswer = dynamic_cast<DnsResource*>(resource);
+ break;
+ }
+ case IDnsResource::DnsAuthority:
+ {
+ m_FirstAuthority = dynamic_cast<DnsResource*>(resource);
+ break;
+ }
+ case IDnsResource::DnsAdditional:
+ {
+ m_FirstAdditional = dynamic_cast<DnsResource*>(resource);
+ break;
+ }
+ default:
+ return;
+ }
+}
+
+DnsResource* DnsLayer::addResource(IDnsResource::ResourceType resType, const std::string& name, DnsType dnsType, DnsClass dnsClass,
+ uint32_t ttl, const std::string& data)
+{
+ // create new query on temporary buffer
+ uint8_t newResourceRawData[256];
+ memset(newResourceRawData, 0, 256);
+
+ DnsResource* newResource = new DnsResource(newResourceRawData, resType);
+
+ newResource->setDnsClass(dnsClass);
+
+ newResource->setDnsType(dnsType);
+
+ // cannot return false since layer shouldn't be extended or shortened in this stage
+ newResource->setName(name);
+
+ newResource->setTTL(ttl);
+
+ if (!newResource->setData(data))
+ {
+ delete newResource;
+ LOG_ERROR("Couldn't set new resource data");
+ return NULL;
+ }
+
+ size_t newResourceOffsetInLayer = sizeof(dnshdr);
+ IDnsResource* curResource = m_ResourceList;
+ while (curResource != NULL && curResource->getType() <= resType)
+ {
+ newResourceOffsetInLayer += curResource->getSize();
+ IDnsResource* nextResource = curResource->getNextResource();
+ if (nextResource == NULL || nextResource->getType() > resType)
+ break;
+ curResource = nextResource;
+ }
+
+
+ // set next resource for new resource. This must happen here for extendLayer to succeed
+ if (curResource != NULL)
+ {
+ if (curResource->getType() > newResource->getType())
+ newResource->setNexResource(m_ResourceList);
+ else
+ newResource->setNexResource(curResource->getNextResource());
+ }
+ else //curResource != NULL
+ newResource->setNexResource(m_ResourceList);
+
+ // extend layer to make room for the new resource
+ if (!extendLayer(newResourceOffsetInLayer, newResource->getSize(), newResource))
+ {
+ LOG_ERROR("Couldn't extend DNS layer, addResource failed");
+ delete newResource;
+ return NULL;
+ }
+
+ // connect the new resource to layer
+ newResource->setDnsLayer(this, newResourceOffsetInLayer);
+
+ // connect the new resource to the layer's resource list
+ if (curResource != NULL)
+ {
+ curResource->setNexResource(newResource);
+ // this means the new resource is the first of it's type
+ if (curResource->getType() < newResource->getType())
+ {
+ setFirstResource(resType, newResource);
+ }
+ // this means the new resource should be the first resource in the packet
+ else if (curResource->getType() > newResource->getType())
+ {
+ m_ResourceList = newResource;
+
+ setFirstResource(resType, newResource);
+ }
+ }
+ else // curResource != NULL, meaning this is the first resource in layer
+ {
+ m_ResourceList = newResource;
+
+ setFirstResource(resType, newResource);
+ }
+
+ return newResource;
+}
+
+
+DnsQuery* DnsLayer::addQuery(const std::string& name, DnsType dnsType, DnsClass dnsClass)
+{
+ // create new query on temporary buffer
+ uint8_t newQueryRawData[256];
+ DnsQuery* newQuery = new DnsQuery(newQueryRawData);
+
+ newQuery->setDnsClass(dnsClass);
+ newQuery->setDnsType(dnsType);
+
+ // cannot return false since layer shouldn't be extended or shortened in this stage
+ newQuery->setName(name);
+
+
+ // find the offset in the layer to insert the new query
+ size_t newQueryOffsetInLayer = sizeof(dnshdr);
+ DnsQuery* curQuery = getFirstQuery();
+ while (curQuery != NULL)
+ {
+ newQueryOffsetInLayer += curQuery->getSize();
+ DnsQuery* nextQuery = getNextQuery(curQuery);
+ if (nextQuery == NULL)
+ break;
+ curQuery = nextQuery;
+
+ }
+
+ // set next resource for new query. This must happen here for extendLayer to succeed
+ if (curQuery != NULL)
+ newQuery->setNexResource(curQuery->getNextResource());
+ else
+ newQuery->setNexResource(m_ResourceList);
+
+ // extend layer to make room for the new query
+ if (!extendLayer(newQueryOffsetInLayer, newQuery->getSize(), newQuery))
+ {
+ LOG_ERROR("Couldn't extend DNS layer, addQuery failed");
+ delete newQuery;
+ return NULL;
+ }
+
+ // connect the new query to layer
+ newQuery->setDnsLayer(this, newQueryOffsetInLayer);
+
+ // connect the new query to the layer's resource list
+ if (curQuery != NULL)
+ curQuery->setNexResource(newQuery);
+ else // curQuery == NULL, meaning this is the first query
+ {
+ m_ResourceList = newQuery;
+ m_FirstQuery = newQuery;
+ }
+
+ // increase number of queries
+ getDnsHeader()->numberOfQuestions = htons(getQueryCount() + 1);
+
+ return newQuery;
+}
+
+DnsQuery* DnsLayer::addQuery(DnsQuery* const copyQuery)
+{
+ if (copyQuery == NULL)
+ return NULL;
+
+ return addQuery(copyQuery->getName(), copyQuery->getDnsType(), copyQuery->getDnsClass());
+}
+
+bool DnsLayer::removeQuery(const std::string& queryNameToRemove, bool exactMatch)
+{
+ DnsQuery* queryToRemove = getQuery(queryNameToRemove, exactMatch);
+ if (queryToRemove == NULL)
+ {
+ LOG_DEBUG("Query not found");
+ return false;
+ }
+
+ return removeQuery(queryToRemove);
+}
+
+bool DnsLayer::removeQuery(DnsQuery* queryToRemove)
+{
+ bool res = removeResource(queryToRemove);
+ if (res)
+ {
+ // decrease number of query records
+ getDnsHeader()->numberOfQuestions = htons(getQueryCount() - 1);
+ }
+
+ return res;
+}
+
+DnsResource* DnsLayer::addAnswer(const std::string& name, DnsType dnsType, DnsClass dnsClass, uint32_t ttl, const std::string& data)
+{
+ DnsResource* res = addResource(IDnsResource::DnsAnswer, name, dnsType, dnsClass, ttl, data);
+ if (res != NULL)
+ {
+ // increase number of answer records
+ getDnsHeader()->numberOfAnswers = htons(getAnswerCount() + 1);
+ }
+
+ return res;
+}
+
+DnsResource* DnsLayer::addAnswer(DnsResource* const copyAnswer)
+{
+ if (copyAnswer == NULL)
+ return NULL;
+
+ return addAnswer(copyAnswer->getName(), copyAnswer->getDnsType(), copyAnswer->getDnsClass(), copyAnswer->getTTL(), copyAnswer->getDataAsString());
+}
+
+bool DnsLayer::removeAnswer(const std::string& answerNameToRemove, bool exactMatch)
+{
+ DnsResource* answerToRemove = getAnswer(answerNameToRemove, exactMatch);
+ if (answerToRemove == NULL)
+ {
+ LOG_DEBUG("Answer record not found");
+ return false;
+ }
+
+ return removeAnswer(answerToRemove);
+}
+
+bool DnsLayer::removeAnswer(DnsResource* answerToRemove)
+{
+ bool res = removeResource(answerToRemove);
+ if (res)
+ {
+ // decrease number of answer records
+ getDnsHeader()->numberOfAnswers = htons(getAnswerCount() - 1);
+ }
+
+ return res;
+}
+
+const std::map<uint16_t, bool>* DnsLayer::getDNSPortMap()
+{
+ return &DNSPortMap;
+}
+
+
+DnsResource* DnsLayer::addAuthority(const std::string& name, DnsType dnsType, DnsClass dnsClass, uint32_t ttl, const std::string& data)
+{
+ DnsResource* res = addResource(IDnsResource::DnsAuthority, name, dnsType, dnsClass, ttl, data);
+ if (res != NULL)
+ {
+ // increase number of authority records
+ getDnsHeader()->numberOfAuthority = htons(getAuthorityCount() + 1);
+ }
+
+ return res;
+}
+
+DnsResource* DnsLayer::addAuthority(DnsResource* const copyAuthority)
+{
+ if (copyAuthority == NULL)
+ return NULL;
+
+ return addAuthority(copyAuthority->getName(), copyAuthority->getDnsType(), copyAuthority->getDnsClass(), copyAuthority->getTTL(), copyAuthority->getDataAsString());
+}
+
+bool DnsLayer::removeAuthority(const std::string& authorityNameToRemove, bool exactMatch)
+{
+ DnsResource* authorityToRemove = getAuthority(authorityNameToRemove, exactMatch);
+ if (authorityToRemove == NULL)
+ {
+ LOG_DEBUG("Authority not found");
+ return false;
+ }
+
+ return removeAuthority(authorityToRemove);
+}
+
+bool DnsLayer::removeAuthority(DnsResource* authorityToRemove)
+{
+ bool res = removeResource(authorityToRemove);
+ if (res)
+ {
+ // decrease number of authority records
+ getDnsHeader()->numberOfAuthority = htons(getAuthorityCount() - 1);
+ }
+
+ return res;
+}
+
+
+DnsResource* DnsLayer::addAdditionalRecord(const std::string& name, DnsType dnsType, DnsClass dnsClass, uint32_t ttl, const std::string& data)
+{
+ DnsResource* res = addResource(IDnsResource::DnsAdditional, name, dnsType, dnsClass, ttl, data);
+ if (res != NULL)
+ {
+ // increase number of authority records
+ getDnsHeader()->numberOfAdditional = htons(getAdditionalRecordCount() + 1);
+ }
+
+ return res;
+}
+
+DnsResource* DnsLayer::addAdditionalRecord(const std::string& name, DnsType dnsType, uint16_t customData1, uint32_t customData2, const std::string& data)
+{
+ DnsResource* res = addAdditionalRecord(name, dnsType, DNS_CLASS_ANY, customData2, data);
+ if (res != NULL)
+ {
+ res->setCustomDnsClass(customData1);
+ }
+
+ return res;
+}
+
+DnsResource* DnsLayer::addAdditionalRecord(DnsResource* const copyAdditionalRecord)
+{
+ if (copyAdditionalRecord == NULL)
+ return NULL;
+
+ return addAdditionalRecord(copyAdditionalRecord->getName(), copyAdditionalRecord->getDnsType(), copyAdditionalRecord->getCustomDnsClass(), copyAdditionalRecord->getTTL(), copyAdditionalRecord->getDataAsString());
+}
+
+bool DnsLayer::removeAdditionalRecord(const std::string& additionalRecordNameToRemove, bool exactMatch)
+{
+ DnsResource* additionalRecordToRemove = getAdditionalRecord(additionalRecordNameToRemove, exactMatch);
+ if (additionalRecordToRemove == NULL)
+ {
+ LOG_DEBUG("Additional record not found");
+ return false;
+ }
+
+ return removeAdditionalRecord(additionalRecordToRemove);
+}
+
+bool DnsLayer::removeAdditionalRecord(DnsResource* additionalRecordToRemove)
+{
+ bool res = removeResource(additionalRecordToRemove);
+ if (res)
+ {
+ // decrease number of additional records
+ getDnsHeader()->numberOfAdditional = htons(getAdditionalRecordCount() - 1);
+ }
+
+ return res;
+}
+
+bool DnsLayer::removeResource(IDnsResource* resourceToRemove)
+{
+ if (resourceToRemove == NULL)
+ {
+ LOG_DEBUG("resourceToRemove cannot be NULL");
+ return false;
+ }
+
+ // find the resource preceding resourceToRemove
+ IDnsResource* prevResource = m_ResourceList;
+
+ if (m_ResourceList != resourceToRemove)
+ {
+ while (prevResource != NULL)
+ {
+ IDnsResource* temp = prevResource->getNextResource();
+ if (temp == resourceToRemove)
+ break;
+
+ prevResource = temp;
+ }
+ }
+
+ if (prevResource == NULL)
+ {
+ LOG_DEBUG("Resource not found");
+ return false;
+ }
+
+ // shorten the layer and fix offset in layer for all next DNS resources in the packet
+ if (!shortenLayer(resourceToRemove->m_OffsetInLayer, resourceToRemove->getSize(), resourceToRemove))
+ {
+ LOG_ERROR("Couldn't shorten the DNS layer, resource cannot be removed");
+ return false;
+ }
+
+ // remove resourceToRemove from the resources linked list
+ if (m_ResourceList != resourceToRemove)
+ {
+ prevResource->setNexResource(resourceToRemove->getNextResource());
+ }
+ else
+ {
+ m_ResourceList = resourceToRemove->getNextResource();
+ }
+
+ // check whether resourceToRemove was the first of its type
+ if (getFirstResource(resourceToRemove->getType()) == resourceToRemove)
+ {
+ IDnsResource* nextResource = resourceToRemove->getNextResource();
+ if (nextResource != NULL && nextResource->getType() == resourceToRemove->getType())
+ setFirstResource(resourceToRemove->getType(), nextResource);
+ else
+ setFirstResource(resourceToRemove->getType(), NULL);
+ }
+
+ // free resourceToRemove memory
+ delete resourceToRemove;
+
+ return true;
+}
+
+} // namespace pcpp
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/c0a788b3/thirdparty/pcap++/Packet++/src/EthLayer.cpp
----------------------------------------------------------------------
diff --git a/thirdparty/pcap++/Packet++/src/EthLayer.cpp b/thirdparty/pcap++/Packet++/src/EthLayer.cpp
new file mode 100644
index 0000000..c418de5
--- /dev/null
+++ b/thirdparty/pcap++/Packet++/src/EthLayer.cpp
@@ -0,0 +1,99 @@
+#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 <string.h>
+#if defined(WIN32) || defined(WINx64)
+#include <winsock2.h>
+#elif LINUX
+#include <in.h>
+#elif MAC_OS_X
+#include <arpa/inet.h>
+#endif
+
+namespace pcpp
+{
+
+EthLayer::EthLayer(const MacAddress& sourceMac, const MacAddress& destMac, uint16_t etherType) : Layer()
+{
+ m_DataLen = sizeof(ether_header);
+ m_Data = new uint8_t[m_DataLen];
+ memset(m_Data, 0, m_DataLen);
+ ether_header* ethHdr = (ether_header*)m_Data;
+ destMac.copyTo(ethHdr->dstMac);
+ sourceMac.copyTo(ethHdr->srcMac);
+ ethHdr->etherType = htons(etherType);
+ m_Protocol = Ethernet;
+}
+
+void EthLayer::parseNextLayer()
+{
+ if (m_DataLen <= sizeof(ether_header))
+ return;
+
+ ether_header* hdr = getEthHeader();
+ switch (ntohs(hdr->etherType))
+ {
+ case PCPP_ETHERTYPE_IP:
+ m_NextLayer = new IPv4Layer(m_Data + sizeof(ether_header), m_DataLen - sizeof(ether_header), this, m_Packet);
+ break;
+ case PCPP_ETHERTYPE_IPV6:
+ m_NextLayer = new IPv6Layer(m_Data + sizeof(ether_header), m_DataLen - sizeof(ether_header), this, m_Packet);
+ break;
+ case PCPP_ETHERTYPE_ARP:
+ m_NextLayer = new ArpLayer(m_Data + sizeof(ether_header), m_DataLen - sizeof(ether_header), this, m_Packet);
+ break;
+ case PCPP_ETHERTYPE_VLAN:
+ m_NextLayer = new VlanLayer(m_Data + sizeof(ether_header), m_DataLen - sizeof(ether_header), this, m_Packet);
+ break;
+ case PCPP_ETHERTYPE_PPPOES:
+ m_NextLayer = new PPPoESessionLayer(m_Data + sizeof(ether_header), m_DataLen - sizeof(ether_header), this, m_Packet);
+ break;
+ case PCPP_ETHERTYPE_PPPOED:
+ m_NextLayer = new PPPoEDiscoveryLayer(m_Data + sizeof(ether_header), m_DataLen - sizeof(ether_header), this, m_Packet);
+ break;
+ case PCPP_ETHERTYPE_MPLS:
+ m_NextLayer = new MplsLayer(m_Data + sizeof(ether_header), m_DataLen - sizeof(ether_header), this, m_Packet);
+ break;
+ default:
+ m_NextLayer = new PayloadLayer(m_Data + sizeof(ether_header), m_DataLen - sizeof(ether_header), this, m_Packet);
+ }
+
+}
+
+void EthLayer::computeCalculateFields()
+{
+ if (m_NextLayer == NULL)
+ return;
+
+ switch (m_NextLayer->getProtocol())
+ {
+ case IPv4:
+ getEthHeader()->etherType = htons(PCPP_ETHERTYPE_IP);
+ break;
+ case IPv6:
+ getEthHeader()->etherType = htons(PCPP_ETHERTYPE_IPV6);
+ break;
+ case ARP:
+ getEthHeader()->etherType = htons(PCPP_ETHERTYPE_ARP);
+ break;
+ case VLAN:
+ getEthHeader()->etherType = htons(PCPP_ETHERTYPE_VLAN);
+ break;
+ default:
+ return;
+ }
+}
+
+std::string EthLayer::toString()
+{
+ return "Ethernet II Layer, Src: " + getSourceMac().toString() + ", Dst: " + getDestMac().toString();
+}
+
+} // namespace pcpp