summaryrefslogtreecommitdiffstats
path: root/libnetutil
diff options
context:
space:
mode:
Diffstat (limited to 'libnetutil')
-rw-r--r--libnetutil/ARPHeader.cc313
-rw-r--r--libnetutil/ARPHeader.h223
-rw-r--r--libnetutil/ApplicationLayerElement.h71
-rw-r--r--libnetutil/DataLinkLayerElement.h70
-rw-r--r--libnetutil/DestOptsHeader.cc95
-rw-r--r--libnetutil/DestOptsHeader.h86
-rw-r--r--libnetutil/EthernetHeader.cc219
-rw-r--r--libnetutil/EthernetHeader.h133
-rw-r--r--libnetutil/FragmentHeader.cc212
-rw-r--r--libnetutil/FragmentHeader.h113
-rw-r--r--libnetutil/HopByHopHeader.cc388
-rw-r--r--libnetutil/HopByHopHeader.h122
-rw-r--r--libnetutil/ICMPHeader.h83
-rw-r--r--libnetutil/ICMPv4Header.cc1187
-rw-r--r--libnetutil/ICMPv4Header.h530
-rw-r--r--libnetutil/ICMPv6Header.cc1358
-rw-r--r--libnetutil/ICMPv6Header.h669
-rw-r--r--libnetutil/ICMPv6Option.cc326
-rw-r--r--libnetutil/ICMPv6Option.h235
-rw-r--r--libnetutil/ICMPv6RRBody.cc111
-rw-r--r--libnetutil/ICMPv6RRBody.h200
-rw-r--r--libnetutil/IPv4Header.cc634
-rw-r--r--libnetutil/IPv4Header.h220
-rw-r--r--libnetutil/IPv6ExtensionHeader.h81
-rw-r--r--libnetutil/IPv6Header.cc505
-rw-r--r--libnetutil/IPv6Header.h172
-rw-r--r--libnetutil/Makefile.in41
-rw-r--r--libnetutil/NetworkLayerElement.cc62
-rw-r--r--libnetutil/NetworkLayerElement.h92
-rw-r--r--libnetutil/PacketElement.cc70
-rw-r--r--libnetutil/PacketElement.h268
-rw-r--r--libnetutil/PacketParser.cc1789
-rw-r--r--libnetutil/PacketParser.h132
-rw-r--r--libnetutil/RawData.cc172
-rw-r--r--libnetutil/RawData.h90
-rw-r--r--libnetutil/RoutingHeader.cc313
-rw-r--r--libnetutil/RoutingHeader.h176
-rw-r--r--libnetutil/TCPHeader.cc936
-rw-r--r--libnetutil/TCPHeader.h259
-rw-r--r--libnetutil/TransportLayerElement.cc126
-rw-r--r--libnetutil/TransportLayerElement.h91
-rw-r--r--libnetutil/UDPHeader.cc298
-rw-r--r--libnetutil/UDPHeader.h127
-rw-r--r--libnetutil/libnetutil.vcxproj128
-rw-r--r--libnetutil/netutil.cc4777
-rw-r--r--libnetutil/netutil.h565
-rw-r--r--libnetutil/npacket.h93
47 files changed, 18961 insertions, 0 deletions
diff --git a/libnetutil/ARPHeader.cc b/libnetutil/ARPHeader.cc
new file mode 100644
index 0000000..eeb135e
--- /dev/null
+++ b/libnetutil/ARPHeader.cc
@@ -0,0 +1,313 @@
+/***************************************************************************
+ * ARPHeader.cc -- The ARPHeader Class represents an ARP packet. It *
+ * contains methods to set any header field. In general, these methods do *
+ * error checkings and byte order conversion. *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#include "ARPHeader.h"
+
+/******************************************************************************/
+/* CONTRUCTORS, DESTRUCTORS AND INITIALIZATION METHODS */
+/******************************************************************************/
+ARPHeader::ARPHeader() {
+ this->reset();
+} /* End of ARPHeader constructor */
+
+
+ARPHeader::~ARPHeader() {
+
+} /* End of ARPHeader destructor */
+
+
+/** Sets every attribute to its default value */
+void ARPHeader::reset(){
+ memset (&this->h, 0, sizeof(nping_arp_hdr_t));
+ this->length=ARP_HEADER_LEN;
+} /* End of reset() */
+
+
+/******************************************************************************/
+/* PacketElement:: OVERWRITTEN METHODS */
+/******************************************************************************/
+
+/** @warning This method is essential for the superclass getBinaryBuffer()
+ * method to work. Do NOT change a thing unless you know what you're doing */
+u8 *ARPHeader::getBufferPointer(){
+ return (u8*)(&h);
+} /* End of getBufferPointer() */
+
+
+/** Stores supplied packet in the internal buffer so the information
+ * can be accessed using the standard get & set methods.
+ * @warning The ARPHeader class is able to hold a maximum of 28 bytes.
+ * If the supplied buffer is longer than that, only the first 28 bytes will be
+ * stored in the internal buffer.
+ * @warning Supplied len MUST be at least 28 bytes (ARP header length).
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error */
+int ARPHeader::storeRecvData(const u8 *buf, size_t len){
+ if(buf==NULL || len<ARP_HEADER_LEN){
+ return OP_FAILURE;
+ }else{
+ this->reset(); /* Re-init the object, just in case the caller had used it already */
+ this->length=ARP_HEADER_LEN;
+ memcpy(&(this->h), buf, ARP_HEADER_LEN);
+ }
+ return OP_SUCCESS;
+} /* End of storeRecvData() */
+
+
+/* Returns a protocol identifier. This is used by packet parsing funtions
+ * that return linked lists of PacketElement objects, to determine the protocol
+ * the object represents. */
+int ARPHeader::protocol_id() const {
+ return HEADER_TYPE_ARP;
+} /* End of protocol_id() */
+
+
+/** Determines if the data stored in the object after an storeRecvData() call
+ * is valid and safe to use. This mainly checks the length of the data but may
+ * also test the value of certain protocol fields to ensure their correctness.
+ * @return the length, in bytes, of the header, if its found to be valid or
+ * OP_FAILURE (-1) otherwise. */
+int ARPHeader::validate(){
+ if( this->length!=ARP_HEADER_LEN)
+ return OP_FAILURE;
+ else
+ return ARP_HEADER_LEN;
+} /* End of validate() */
+
+
+/** Prints the contents of the header and calls print() on the next protocol
+ * header in the chain (if there is any).
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error. */
+int ARPHeader::print(FILE *output, int detail) const {
+ fprintf(output, "ARP[]");
+ if(this->next!=NULL){
+ print_separator(output, detail);
+ next->print(output, detail);
+ }
+ return OP_SUCCESS;
+} /* End of print() */
+
+
+/******************************************************************************/
+/* PROTOCOL-SPECIFIC METHODS */
+/******************************************************************************/
+
+/** Sets HardwareType.
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error. */
+int ARPHeader::setHardwareType(u16 val){
+ this->h.ar_hrd=htons(val);
+ return OP_SUCCESS;
+} /* End of setHardwareType() */
+
+
+/** Sets HardwareType to ETHERNET.
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error. */
+int ARPHeader::setHardwareType(){
+ this->h.ar_hrd=htons(HDR_ETH10MB);
+ return OP_SUCCESS;
+} /* End of setHardwareType() */
+
+
+/** Returns value of attribute h.ar_hrd */
+u16 ARPHeader::getHardwareType(){
+ return ntohs(this->h.ar_hrd);
+} /* End of getHardwareType() */
+
+
+/** Sets ProtocolType.
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error. */
+int ARPHeader::setProtocolType(u16 val){
+ this->h.ar_pro=htons(val);
+ return OP_SUCCESS;
+} /* End of setProtocolType() */
+
+
+/** Sets ProtocolType.
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error. */
+int ARPHeader::setProtocolType(){
+ this->h.ar_pro=htons(0x0800); /* DEFAULT: IPv4 */
+ return OP_SUCCESS;
+} /* End of setProtocolType() */
+
+
+/** Returns value of attribute h.ar_pro */
+u16 ARPHeader::getProtocolType(){
+ return ntohs(this->h.ar_pro);
+} /* End of getProtocolType() */
+
+
+/** Sets HwAddrLen.
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error. */
+int ARPHeader::setHwAddrLen(u8 val){
+ this->h.ar_hln=val;
+ return OP_SUCCESS;
+} /* End of setHwAddrLen() */
+
+
+/** Sets HwAddrLen.
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error. */
+int ARPHeader::setHwAddrLen(){
+ this->h.ar_hln=ETH_ADDRESS_LEN;
+ return OP_SUCCESS;
+} /* End of setHwAddrLen() */
+
+
+/** Returns value of attribute h.ar_hln */
+u8 ARPHeader::getHwAddrLen(){
+ return this->h.ar_hln;
+} /* End of getHwAddrLen() */
+
+
+/** Sets ProtoAddrLen.
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error. */
+int ARPHeader::setProtoAddrLen(u8 val){
+ this->h.ar_pln=val;
+ return OP_SUCCESS;
+} /* End of setProtoAddrLen() */
+
+
+/** Sets ProtoAddrLen.
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error. */
+int ARPHeader::setProtoAddrLen(){
+ this->h.ar_pln=IPv4_ADDRESS_LEN; /* DEFAULT: IPv4 */
+ return OP_SUCCESS;
+} /* End of setProtoAddrLen() */
+
+
+/** Returns value of attribute h.ar_pln */
+u8 ARPHeader::getProtoAddrLen(){
+ return this->h.ar_pln;
+} /* End of getProtoAddrLen() */
+
+
+/** Sets OpCode.
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error. */
+int ARPHeader::setOpCode(u16 val){
+ this->h.ar_op=htons(val);
+ return OP_SUCCESS;
+} /* End of setOpCode() */
+
+
+/** Returns value of attribute h.ar_op */
+u16 ARPHeader::getOpCode(){
+ return ntohs(this->h.ar_op);
+} /* End of getOpCode() */
+
+
+/** Sets SenderMAC.
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error. */
+int ARPHeader::setSenderMAC(const u8 * val){
+ if(val==NULL)
+ return OP_FAILURE;
+ memcpy(this->h.data, val, ETH_ADDRESS_LEN);
+ return OP_SUCCESS;
+} /* End of setSenderMAC() */
+
+
+/** Returns value of attribute h.ar_sha */
+u8 * ARPHeader::getSenderMAC(){
+ return this->h.data;
+} /* End of getSenderMAC() */
+
+
+/** Sets SenderIP.
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error. */
+int ARPHeader::setSenderIP(struct in_addr val){
+ memcpy(this->h.data+6, &val.s_addr, 4);
+ return OP_SUCCESS;
+} /* End of setSenderIP() */
+
+
+/** Returns value of attribute h.ar_sip */
+u32 ARPHeader::getSenderIP(){
+ u32 *p = (u32 *)(this->h.data+6);
+ return *p;
+} /* End of getSenderIP() */
+
+
+/** Sets TargetMAC.
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error. */
+int ARPHeader::setTargetMAC(u8 * val){
+ if(val==NULL)
+ return OP_FAILURE;
+ memcpy(this->h.data+10, val, ETH_ADDRESS_LEN);
+ return OP_SUCCESS;
+} /* End of setTargetMAC() */
+
+
+/** Returns value of attribute h.ar_tha */
+u8 * ARPHeader::getTargetMAC(){
+ return this->h.data+10;
+} /* End of getTargetMAC() */
+
+
+/** Sets TargetIP.
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error. */
+int ARPHeader::setTargetIP(struct in_addr val){
+ memcpy(this->h.data+16, &val.s_addr, 4);
+ return OP_SUCCESS;
+} /* End of setTargetIP() */
+
+
+/** Returns value of attribute h.ar_tip */
+u32 ARPHeader::getTargetIP(){
+ u32 *p = (u32 *)(this->h.data+16);
+ return *p;
+} /* End of getTargetIP() */
diff --git a/libnetutil/ARPHeader.h b/libnetutil/ARPHeader.h
new file mode 100644
index 0000000..8386e0b
--- /dev/null
+++ b/libnetutil/ARPHeader.h
@@ -0,0 +1,223 @@
+/***************************************************************************
+ * ARPHeader.h -- The ARPHeader Class represents an ARP packet. It *
+ * contains methods to set any header field. In general, these methods do *
+ * error checkings and byte order conversion. *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#ifndef __ARPHEADER_H__
+#define __ARPHEADER_H__ 1
+
+#include "NetworkLayerElement.h"
+
+/* Lengths */
+#define ARP_HEADER_LEN 28
+#define IPv4_ADDRESS_LEN 4
+#define ETH_ADDRESS_LEN 6
+
+/* Hardware Types */
+#define HDR_RESERVED 0 /* [RFC5494] */
+#define HDR_ETH10MB 1 /* Ethernet (10Mb) */
+#define HDR_ETH3MB 2 /* Experimental Ethernet (3Mb) */
+#define HDR_AX25 3 /* Amateur Radio AX.25 */
+#define HDR_PRONET_TR 4 /* Proteon ProNET Token Ring */
+#define HDR_CHAOS 5 /* Chaos */
+#define HDR_IEEE802 6 /* IEEE 802 Networks */
+#define HDR_ARCNET 7 /* ARCNET [RFC1201] */
+#define HDR_HYPERCHANNEL 8 /* Hyperchannel */
+#define HDR_LANSTAR 9 /* Lanstar */
+#define HDR_AUTONET 10 /* Autonet Short Address */
+#define HDR_LOCALTALK 11 /* LocalTalk */
+#define HDR_LOCALNET 12 /* LocalNet (IBM PCNet or SYTEK LocalNET) */
+#define HDR_ULTRALINK 13 /* Ultra link */
+#define HDR_SMDS 14 /* SMDS */
+#define HDR_FRAMERELAY 15 /* Frame Relay */
+#define HDR_ATM 16 /* Asynchronous Transmission Mode (ATM) */
+#define HDR_HDLC 17 /* HDLC */
+#define HDR_FIBRE 18 /* Fibre Channel [RFC4338] */
+#define HDR_ATMb 19 /* Asynchronous Transmission Mode (ATM) */
+#define HDR_SERIAL 20 /* Serial Line */
+#define HDR_ATMc 21 /* Asynchronous Transmission Mode [RFC2225] */
+#define HDR_MILSTD 22 /* MIL-STD-188-220 */
+#define HDR_METRICOM 23 /* Metricom */
+#define HDR_IEEE1394 24 /* IEEE 1394.199 */
+#define HDR_MAPOS 25 /* MAPOS [RFC2176] */
+#define HDR_TWINAXIAL 26 /* Twinaxial */
+#define HDR_EUI64 27 /* EUI-64 */
+#define HDR_HIPARP 28 /* HIPARP */
+#define HDR_ISO7816 29 /* IP and ARP over ISO 7816-3 */
+#define HDR_ARPSEC 30 /* ARPSec */
+#define HDR_IPSEC 31 /* IPsec tunnel */
+#define HDR_INFINIBAND 32 /* InfiniBand (TM) */
+#define HDR_TIA102 33 /* TIA-102 Project 25 Common Air Interface */
+#define HDR_WIEGAND 34 /* Wiegand Interface */
+#define HDR_PUREIP 35 /* Pure IP */
+#define HDR_HW_EXP1 36 /* HW_EXP1 [RFC5494] */
+#define HDR_HW_EXP2 37 /* HW_EXP2 [RFC5494] */
+
+/* Operation Codes */
+#define OP_ARP_REQUEST 1 /* ARP Request */
+#define OP_ARP_REPLY 2 /* ARP Reply */
+#define OP_RARP_REQUEST 3 /* Reverse ARP Request */
+#define OP_RARP_REPLY 4 /* Reverse ARP Reply */
+#define OP_DRARP_REQUEST 5 /* DRARP-Request */
+#define OP_DRARP_REPLY 6 /* DRARP-Reply */
+#define OP_DRARP_ERROR 7 /* DRARP-Error */
+#define OP_INARP_REQUEST 8 /* InARP-Request */
+#define OP_INARP_REPLY 9 /* InARP-Reply */
+#define OP_ARPNAK 10 /* ARP-NAK */
+#define OP_MARS_REQUEST 11 /* MARS-Request */
+#define OP_MARS_MULTI 12 /* MARS-Multi */
+#define OP_MARS_MSERV 13 /* MARS-MServ */
+#define OP_MARS_JOIN 14 /* MARS-Join */
+#define OP_MARS_LEAVE 15 /* MARS-Leave */
+#define OP_MARS_NAK 16 /* MARS-NAK */
+#define OP_MARS_UNSERV 17 /* MARS-Unserv */
+#define OP_MARS_SJOIN 18 /* MARS-SJoin */
+#define OP_MARS_SLEAVE 19 /* MARS-SLeave */
+#define OP_MARS_GL_REQ 20 /* MARS-Grouplist-Request */
+#define OP_MARS_GL_REP 21 /* MARS-Grouplist-Reply */
+#define OP_MARS_REDIR_MAP 22 /* MARS-Redirect-Map */
+#define OP_MAPOS_UNARP 23 /* MAPOS-UNARP [RFC2176] */
+#define OP_EXP1 24 /* OP_EXP1 [RFC5494] */
+#define OP_EXP2 25 /* OP_EXP2 [RFC5494] */
+#define OP_RESERVED 65535 /* Reserved [RFC5494] */
+
+
+/* TODO @todo: getTargetIP() and getSenderIP() should either
+ * return struct in_addr or IPAddress but not u32. */
+
+class ARPHeader : public NetworkLayerElement {
+
+ private:
+
+ struct nping_arp_hdr{
+
+ u16 ar_hrd; /* Hardware Type. */
+ u16 ar_pro; /* Protocol Type. */
+ u8 ar_hln; /* Hardware Address Length. */
+ u8 ar_pln; /* Protocol Address Length. */
+ u16 ar_op; /* Operation Code. */
+ u8 data[20];
+ // Cannot use these because the four-flushing alignment screws up
+ // everything. I miss ANSI C.
+ //u8 ar_sha[6]; /* Sender Hardware Address. */
+ //u32 ar_sip; /* Sender Protocol Address (IPv4 address). */
+ //u8 ar_tha[6]; /* Target Hardware Address. */
+ //u32 ar_tip; /* Target Protocol Address (IPv4 address). */
+ }__attribute__((__packed__));
+
+ typedef struct nping_arp_hdr nping_arp_hdr_t;
+
+ nping_arp_hdr_t h;
+
+ public:
+
+ /* Misc */
+ ARPHeader();
+ ~ARPHeader();
+ void reset();
+ u8 *getBufferPointer();
+ int storeRecvData(const u8 *buf, size_t len);
+ int protocol_id() const;
+ int validate();
+ int print(FILE *output, int detail) const;
+
+ /* Hardware Type */
+ int setHardwareType(u16 t);
+ int setHardwareType();
+ u16 getHardwareType();
+
+ /* Protocol Type */
+ int setProtocolType(u16 t);
+ int setProtocolType();
+ u16 getProtocolType();
+
+ /* Hardware Address Length */
+ int setHwAddrLen(u8 v);
+ int setHwAddrLen();
+ u8 getHwAddrLen();
+
+ /* Hardware Address Length */
+ int setProtoAddrLen(u8 v);
+ int setProtoAddrLen();
+ u8 getProtoAddrLen();
+
+ /* Operation Code */
+ int setOpCode(u16 c);
+ u16 getOpCode();
+
+ /* Sender Hardware Address */
+ int setSenderMAC(const u8 *m);
+ u8 *getSenderMAC();
+
+ /* Sender Protocol address */
+ int setSenderIP(struct in_addr i);
+ u32 getSenderIP();
+
+ /* Target Hardware Address */
+ int setTargetMAC(u8 *m);
+ u8 *getTargetMAC();
+
+ /* Target Protocol Address */
+ int setTargetIP(struct in_addr i);
+ u32 getTargetIP();
+
+}; /* End of class ARPHeader */
+
+#endif /* __ARPHEADER_H__ */
+
diff --git a/libnetutil/ApplicationLayerElement.h b/libnetutil/ApplicationLayerElement.h
new file mode 100644
index 0000000..f1e7eb5
--- /dev/null
+++ b/libnetutil/ApplicationLayerElement.h
@@ -0,0 +1,71 @@
+/***************************************************************************
+ * ApplicationLayerElement.h -- Class ApplicationLayerElement is a *
+ * generic class that represents an application layer protocol header or *
+ * any kind of payload or buffer. Classes like RawData inherit from it. *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#ifndef APPLICATIONLAYERELEMENT_H
+#define APPLICATIONLAYERELEMENT_H 1
+
+#include "PacketElement.h"
+
+
+class ApplicationLayerElement : public PacketElement {
+};
+
+#endif
diff --git a/libnetutil/DataLinkLayerElement.h b/libnetutil/DataLinkLayerElement.h
new file mode 100644
index 0000000..a0d24a7
--- /dev/null
+++ b/libnetutil/DataLinkLayerElement.h
@@ -0,0 +1,70 @@
+/***************************************************************************
+ * DataLinkLayerElement.h -- Class DataLinkLayerElement is a generic *
+ * class that represents a data link layer protocol header (and maybe a *
+ * footer) Classes like EthernetHeader inherit from it. *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#ifndef DATALINKLAYERELEMENT_H
+#define DATALINKLAYERELEMENT_H 1
+
+#include "PacketElement.h"
+
+class DataLinkLayerElement : public PacketElement {
+};
+
+#endif
diff --git a/libnetutil/DestOptsHeader.cc b/libnetutil/DestOptsHeader.cc
new file mode 100644
index 0000000..478c3f7
--- /dev/null
+++ b/libnetutil/DestOptsHeader.cc
@@ -0,0 +1,95 @@
+/***************************************************************************
+ * DestOptsHeader.cc -- The DestOptsHeader Class represents an IPv6 *
+ * Destination Options extension header. *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#include "DestOptsHeader.h"
+#include <assert.h>
+
+/******************************************************************************/
+/* CONTRUCTORS, DESTRUCTORS AND INITIALIZATION METHODS */
+/******************************************************************************/
+DestOptsHeader::DestOptsHeader() {
+ this->reset();
+} /* End of DestOptsHeader constructor */
+
+
+DestOptsHeader::~DestOptsHeader() {
+
+} /* End of DestOptsHeader destructor */
+
+
+/** Prints the contents of the header and calls print() on the next protocol
+ * header in the chain (if there is any).
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error. */
+int DestOptsHeader::print(FILE *output, int detail) const {
+ fprintf(output, "DestOpts[%d,%d]", this->h.nh, this->h.len);
+ // TODO: @todo : Implement this
+ if(this->next!=NULL){
+ print_separator(output, detail);
+ next->print(output, detail);
+ }
+ return OP_SUCCESS;
+} /* End of print() */
+
+
+/* Returns a protocol identifier. This is used by packet parsing funtions
+ * that return linked lists of PacketElement objects, to determine the protocol
+ * the object represents. */
+int DestOptsHeader::protocol_id() const {
+ return HEADER_TYPE_IPv6_OPTS;
+} /* End of protocol_id() */
diff --git a/libnetutil/DestOptsHeader.h b/libnetutil/DestOptsHeader.h
new file mode 100644
index 0000000..131d8d9
--- /dev/null
+++ b/libnetutil/DestOptsHeader.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+ * DestOptsHeader.h -- The DestOptsHeader Class represents an IPv6 *
+ * Destination Options extension header. *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#ifndef __DESTOPTS_HEADER_H__
+#define __DESTOPTS_HEADER_H__ 1
+
+#include "HopByHopHeader.h"
+
+class DestOptsHeader : public HopByHopHeader {
+
+ private:
+ /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Next Header | Hdr Ext Len | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+ | |
+ . .
+ . Options .
+ . .
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+ // Implemented in HopByHopHeader.h
+ public:
+ DestOptsHeader();
+ ~DestOptsHeader();
+ int print(FILE *output, int detail) const;
+ int protocol_id() const;
+
+}; /* End of class DestOptsHeader */
+
+#endif
diff --git a/libnetutil/EthernetHeader.cc b/libnetutil/EthernetHeader.cc
new file mode 100644
index 0000000..5daa3f1
--- /dev/null
+++ b/libnetutil/EthernetHeader.cc
@@ -0,0 +1,219 @@
+/***************************************************************************
+ * EthernetHeader.cc -- The EthernetHeader Class represents an Ethernet *
+ * header and footer. It contains methods to set the different header *
+ * fields. These methods tipically perform the necessary error checks and *
+ * byte order conversions. *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#include "EthernetHeader.h"
+
+/******************************************************************************/
+/* CONTRUCTORS, DESTRUCTORS AND INITIALIZATION METHODS */
+/******************************************************************************/
+EthernetHeader::EthernetHeader(){
+ this->reset();
+} /* End of EthernetHeader constructor */
+
+
+EthernetHeader::~EthernetHeader(){
+
+} /* End of EthernetHeader destructor */
+
+
+/** Sets every attribute to its default value */
+void EthernetHeader::reset(){
+ memset(&this->h, 0, sizeof(nping_eth_hdr_t));
+ this->length=ETH_HEADER_LEN;
+} /* End of reset() */
+
+
+/** @warning This method is essential for the superclass getBinaryBuffer()
+ * method to work. Do NOT change a thing unless you know what you're doing */
+u8 * EthernetHeader::getBufferPointer(){
+ return (u8*)(&h);
+} /* End of getBufferPointer() */
+
+
+/******************************************************************************/
+/* PacketElement:: OVERWRITTEN METHODS */
+/******************************************************************************/
+
+/** Stores supplied packet in the internal buffer so the information
+ * can be accessed using the standard get & set methods.
+ * @warning The EthernetHeader class is able to hold a maximum of 14 bytes.
+ * If the supplied buffer is longer than that, only the first 14 bytes will be
+ * stored in the internal buffer.
+ * @warning Supplied len MUST be at least 14 bytes (Ethernet header length).
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error */
+int EthernetHeader::storeRecvData(const u8 *buf, size_t len){
+ if(buf==NULL || len<ETH_HEADER_LEN){
+ return OP_FAILURE;
+ }else{
+ this->reset(); /* Re-init the object, just in case the caller had used it already */
+ this->length=ETH_HEADER_LEN;
+ memcpy(&(this->h), buf, ETH_HEADER_LEN);
+ }
+ return OP_SUCCESS;
+} /* End of storeRecvData() */
+
+
+/* Returns a protocol identifier. This is used by packet parsing funtions
+ * that return linked lists of PacketElement objects, to determine the protocol
+ * the object represents. */
+int EthernetHeader::protocol_id() const {
+ return HEADER_TYPE_ETHERNET;
+} /* End of protocol_id() */
+
+
+/** Determines if the data stored in the object after an storeRecvData() call
+ * is valid and safe to use. This mainly checks the length of the data but may
+ * also test the value of certain protocol fields to ensure their correctness.
+ * @return the length, in bytes, of the header, if its found to be valid or
+ * OP_FAILURE (-1) otherwise. */
+int EthernetHeader::validate(){
+ if( this->length!=ETH_HEADER_LEN)
+ return OP_FAILURE;
+ else
+ return ETH_HEADER_LEN;
+} /* End of validate() */
+
+
+/** Prints the contents of the header and calls print() on the next protocol
+ * header in the chain (if there is any).
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error. */
+int EthernetHeader::print(FILE *output, int detail) const {
+
+ fprintf(output, "Eth[");
+
+ for(int i=0; i<6; i++){
+ fprintf(output, "%02x", this->h.eth_smac[i]);
+ if(i<5)
+ fprintf(output, ":");
+ }
+
+ fprintf(output, " > ");
+
+ for(int i=0; i<6; i++){
+ fprintf(output, "%02x", this->h.eth_dmac[i]);
+ if(i<5)
+ fprintf(output, ":");
+ }
+
+ if(detail>=PRINT_DETAIL_MED)
+ fprintf(output, " Type=%04x", this->getEtherType());
+
+ fprintf(output, "]");
+
+ if(this->next!=NULL){
+ print_separator(output, detail);
+ next->print(output, detail);
+ }
+ return OP_SUCCESS;
+} /* End of print() */
+
+
+/******************************************************************************/
+/* PROTOCOL-SPECIFIC METHODS */
+/******************************************************************************/
+
+/** Sets Source MAC address
+ * @warning Supplied buffer must contain at least 6 bytes */
+int EthernetHeader::setSrcMAC(const u8 *m){
+ if(m==NULL)
+ netutil_fatal("EthernetHeader::setSrcMAC(u8*): NULL value supplied ");
+ memcpy(h.eth_smac, m, 6);
+ return OP_SUCCESS;
+} /* End of setSrcMAC() */
+
+
+/** Returns source port in HOST byte order
+ * @warning Returned pointer points directly to a Class internal buffer. If
+ * contents are changed, the instance of the class will be affected. */
+const u8* EthernetHeader::getSrcMAC() const {
+ return this->h.eth_smac;
+} /* End of getSrcMAC() */
+
+
+/** Sets Destination MAC address
+ * @warning Supplied buffer must contain at least 6 bytes */
+int EthernetHeader::setDstMAC(u8 *m){
+ if(m==NULL)
+ netutil_fatal("EthernetHeader::setDstMAC(u8 *): NULL value supplied ");
+ memcpy(h.eth_dmac, m, 6);
+ return OP_SUCCESS;
+} /* End of setDstMAC() */
+
+
+
+/** Returns destination port in HOST byte order */
+const u8 *EthernetHeader::getDstMAC() const {
+ return this->h.eth_dmac;
+} /* End of getDstMAC() */
+
+
+int EthernetHeader::setEtherType(u16 val){
+ h.eth_type=htons(val);
+ return OP_SUCCESS;
+} /* End of setEtherType() */
+
+
+/** Returns destination port in HOST byte order */
+u16 EthernetHeader::getEtherType() const {
+ return ntohs(this->h.eth_type);
+} /* End of getEtherType() */
+
diff --git a/libnetutil/EthernetHeader.h b/libnetutil/EthernetHeader.h
new file mode 100644
index 0000000..6052461
--- /dev/null
+++ b/libnetutil/EthernetHeader.h
@@ -0,0 +1,133 @@
+/***************************************************************************
+ * EthernetHeader.h -- The EthernetHeader Class represents an Ethernet *
+ * header and footer. It contains methods to set the different header *
+ * fields. These methods tipically perform the necessary error checks and *
+ * byte order conversions. *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#ifndef ETHERNETHEADER_H
+#define ETHERNETHEADER_H 1
+
+#include "DataLinkLayerElement.h"
+
+/* Ether Types. (From RFC 5342 http://www.rfc-editor.org/rfc/rfc5342.txt) */
+#define ETHTYPE_IPV4 0x0800 /* Internet Protocol Version 4 */
+#define ETHTYPE_ARP 0x0806 /* Address Resolution Protocol */
+#define ETHTYPE_FRAMERELAY 0x0808 /* Frame Relay ARP */
+#define ETHTYPE_PPTP 0x880B /* Point-to-Point Tunneling Protocol */
+#define ETHTYPE_GSMP 0x880C /* General Switch Management Protocol */
+#define ETHTYPE_RARP 0x8035 /* Reverse Address Resolution Protocol */
+#define ETHTYPE_IPV6 0x86DD /* Internet Protocol Version 6 */
+#define ETHTYPE_MPLS 0x8847 /* MPLS */
+#define ETHTYPE_MPS_UAL 0x8848 /* MPLS with upstream-assigned label */
+#define ETHTYPE_MCAP 0x8861 /* Multicast Channel Allocation Protocol */
+#define ETHTYPE_PPPOE_D 0x8863 /* PPP over Ethernet Discovery Stage */
+#define ETHTYPE_PPOE_S 0x8864 /* PPP over Ethernet Session Stage */
+#define ETHTYPE_CTAG 0x8100 /* Customer VLAN Tag Type */
+#define ETHTYPE_EPON 0x8808 /* Ethernet Passive Optical Network */
+#define ETHTYPE_PBNAC 0x888E /* Port-based network access control */
+#define ETHTYPE_STAG 0x88A8 /* Service VLAN tag identifier */
+#define ETHTYPE_ETHEXP1 0x88B5 /* Local Experimental Ethertype */
+#define ETHTYPE_ETHEXP2 0x88B6 /* Local Experimental Ethertype */
+#define ETHTYPE_ETHOUI 0x88B7 /* OUI Extended Ethertype */
+#define ETHTYPE_PREAUTH 0x88C7 /* Pre-Authentication */
+#define ETHTYPE_LLDP 0x88CC /* Link Layer Discovery Protocol (LLDP) */
+#define ETHTYPE_MACSEC 0x88E5 /* Media Access Control Security */
+#define ETHTYPE_MVRP 0x88F5 /* Multiple VLAN Registration Protocol */
+#define ETHTYPE_MMRP 0x88F6 /* Multiple Multicast Registration Protocol */
+#define ETHTYPE_FRRR 0x890D /* Fast Roaming Remote Request */
+
+#define ETH_HEADER_LEN 14
+
+class EthernetHeader : public DataLinkLayerElement {
+
+ private:
+
+ struct nping_eth_hdr{
+ u8 eth_dmac[6];
+ u8 eth_smac[6];
+ u16 eth_type;
+ }__attribute__((__packed__));
+
+ typedef struct nping_eth_hdr nping_eth_hdr_t;
+
+ nping_eth_hdr_t h;
+
+ public:
+
+ EthernetHeader();
+ ~EthernetHeader();
+ void reset();
+ u8 *getBufferPointer();
+ int storeRecvData(const u8 *buf, size_t len);
+ int protocol_id() const;
+ int validate();
+ int print(FILE *output, int detail) const;
+
+ int setSrcMAC(const u8 *m);
+ const u8 *getSrcMAC() const;
+
+ int setDstMAC(u8 *m);
+ const u8 *getDstMAC() const;
+
+ int setEtherType(u16 val);
+ u16 getEtherType() const;
+
+};
+
+#endif
diff --git a/libnetutil/FragmentHeader.cc b/libnetutil/FragmentHeader.cc
new file mode 100644
index 0000000..f89e00c
--- /dev/null
+++ b/libnetutil/FragmentHeader.cc
@@ -0,0 +1,212 @@
+/***************************************************************************
+ * FragmentHeader.cc -- The FragmentHeader Class represents an IPv6 *
+ * Hop-by-Hop extension header. *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#include "FragmentHeader.h"
+#include <assert.h>
+
+/******************************************************************************/
+/* CONTRUCTORS, DESTRUCTORS AND INITIALIZATION METHODS */
+/******************************************************************************/
+FragmentHeader::FragmentHeader() {
+ this->reset();
+} /* End of FragmentHeader constructor */
+
+
+FragmentHeader::~FragmentHeader() {
+
+} /* End of FragmentHeader destructor */
+
+
+/** Sets every attribute to its default value */
+void FragmentHeader::reset(){
+ memset(&this->h, 0, sizeof(nping_ipv6_ext_fragment_hdr_t));
+ this->length=8;
+} /* End of reset() */
+
+
+/******************************************************************************/
+/* PacketElement:: OVERWRITTEN METHODS */
+/******************************************************************************/
+
+/** @warning This method is essential for the superclass getBinaryBuffer()
+ * method to work. Do NOT change a thing unless you know what you're doing */
+u8 *FragmentHeader::getBufferPointer(){
+ return (u8*)(&this->h);
+} /* End of getBufferPointer() */
+
+
+/** Stores supplied packet in the internal buffer so the information
+ * can be accessed using the standard get & set methods.
+ * @warning The FragmentHeader class is able to hold a maximum of
+ * sizeof(nping_icmpv6_hdr_t) bytes. If the supplied buffer is longer than
+ * that, only the first 1508 bytes will be stored in the internal buffer.
+ * @warning Supplied len MUST be at least 8 bytes (min ICMPv6 header length).
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error */
+int FragmentHeader::storeRecvData(const u8 *buf, size_t len){
+ if(buf==NULL || len<FRAGMENT_HEADER_LEN){
+ this->length=0;
+ return OP_FAILURE;
+ }else{
+ int stored_len = MIN(FRAGMENT_HEADER_LEN, len);
+ this->reset(); /* Re-init the object, just in case the caller had used it already */
+ this->length=stored_len;
+ memcpy(&(this->h), buf, stored_len);
+ }
+ return OP_SUCCESS;
+} /* End of storeRecvData() */
+
+
+/* Returns a protocol identifier. This is used by packet parsing funtions
+ * that return linked lists of PacketElement objects, to determine the protocol
+ * the object represents. */
+int FragmentHeader::protocol_id() const {
+ return HEADER_TYPE_IPv6_FRAG;
+} /* End of protocol_id() */
+
+
+
+/** Determines if the data stored in the object after an storeRecvData() call
+ * is valid and safe to use. This mainly checks the length of the data but may
+ * also test the value of certain protocol fields to ensure their correctness.
+ * @return the length, in bytes, of the header, if its found to be valid or
+ * OP_FAILURE (-1) otherwise. */
+int FragmentHeader::validate(){
+ /* Check the object's length makes sense*/
+ if(this->length != FRAGMENT_HEADER_LEN){
+ return OP_FAILURE;
+ }
+ /* There is not much to check for here, since header fields may take any
+ * value. We could certainly check the NextHeader value, but let's leave
+ * that for the class user. */
+ return this->length;
+} /* End of validate() */
+
+
+/** Prints the contents of the header and calls print() on the next protocol
+ * header in the chain (if there is any).
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error. */
+int FragmentHeader::print(FILE *output, int detail) const {
+ fprintf(output, "Fragment[%d, %d]", this->h.nh, this->h.id);
+ // TODO: @todo : Implement this
+ if(this->next!=NULL){
+ print_separator(output, detail);
+ next->print(output, detail);
+ }
+ return OP_SUCCESS;
+} /* End of print() */
+
+
+/******************************************************************************/
+/* PROTOCOL-SPECIFIC METHODS */
+/******************************************************************************/
+
+/** Set Next Header field */
+int FragmentHeader::setNextHeader(u8 val){
+ this->h.nh = val;
+ return OP_SUCCESS;
+} /* End of setNextHeader() */
+
+
+/** Returns next header id */
+u8 FragmentHeader::getNextHeader(){
+ return this->h.nh;
+} /* End of getNextHeader() */
+
+
+/** Set Offset field */
+int FragmentHeader::setOffset(u16 val){
+ this->h.off_res_flag[0]=(u8)(val >> 8);
+ this->h.off_res_flag[1]=(u8)((this->h.off_res_flag[1] & 0x7) | (val & ~0x7));
+ return OP_SUCCESS;
+} /* End of setOffset() */
+
+
+/** Returns fragment offset */
+u16 FragmentHeader::getOffset(){
+ return ((this->h.off_res_flag[0] << 8) + this->h.off_res_flag[1]) & 0xfff8;
+} /* End of getOffset() */
+
+
+/* Sets the "More Fragments" flag. */
+int FragmentHeader::setM(bool m_flag){
+ if(m_flag)
+ this->h.off_res_flag[1]= (u8)((this->h.off_res_flag[1] & ~0x01) | 0x01);
+ else
+ this->h.off_res_flag[1]= (u8)((this->h.off_res_flag[1] & ~0x1));
+ return OP_SUCCESS;
+} /* End of setM() */
+
+
+/* Returns true if the "More Fragments" flag is set; false otherwise. */
+bool FragmentHeader::getM(){
+ return (this->h.off_res_flag[1] & 0x01);
+} /* End of getM() */
+
+
+/** Set the fragment identifier */
+int FragmentHeader::setIdentification(u32 val){
+ this->h.id=htonl(val);
+ return OP_SUCCESS;
+} /* End of setIdentification() */
+
+
+/** Returns the fragment identifier*/
+u32 FragmentHeader::getIdentification(){
+ return ntohl(this->h.id);
+} /* End of getIdentification.() */
diff --git a/libnetutil/FragmentHeader.h b/libnetutil/FragmentHeader.h
new file mode 100644
index 0000000..9f4592f
--- /dev/null
+++ b/libnetutil/FragmentHeader.h
@@ -0,0 +1,113 @@
+/***************************************************************************
+ * FragmentHeader.h -- The FragmentHeader Class represents an IPv6 *
+ * Hop-by-Hop extension header. *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#ifndef __FRAGMENT_HEADER_H__
+#define __FRAGMENT_HEADER_H__ 1
+
+#include "IPv6ExtensionHeader.h"
+
+#define FRAGMENT_HEADER_LEN 8
+
+
+class FragmentHeader : public IPv6ExtensionHeader {
+
+ private:
+
+ /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Next Header | Reserved | Fragment Offset |Res|M|
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Identification |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+ struct nping_ipv6_ext_fragment_hdr{
+ u8 nh;
+ u8 res1;
+ u8 off_res_flag[2];
+ u32 id;
+ }__attribute__((__packed__));
+ typedef struct nping_ipv6_ext_fragment_hdr nping_ipv6_ext_fragment_hdr_t;
+
+ nping_ipv6_ext_fragment_hdr_t h;
+
+ public:
+ FragmentHeader();
+ ~FragmentHeader();
+ void reset();
+ u8 *getBufferPointer();
+ int storeRecvData(const u8 *buf, size_t len);
+ int protocol_id() const;
+ int validate();
+ int print(FILE *output, int detail) const;
+
+ /* Protocol specific methods */
+ int setNextHeader(u8 val);
+ u8 getNextHeader();
+
+ int setOffset(u16 val);
+ u16 getOffset();
+
+ int setM(bool m_flag);
+ bool getM();
+
+ int setIdentification(u32 val);
+ u32 getIdentification();
+
+
+}; /* End of class FragmentHeader */
+
+#endif
diff --git a/libnetutil/HopByHopHeader.cc b/libnetutil/HopByHopHeader.cc
new file mode 100644
index 0000000..b0e4467
--- /dev/null
+++ b/libnetutil/HopByHopHeader.cc
@@ -0,0 +1,388 @@
+/***************************************************************************
+ * HopByHopHeader.cc -- The HopByHopHeader Class represents an IPv6 *
+ * Hop-by-Hop extension header. *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#include "HopByHopHeader.h"
+#include <assert.h>
+
+/******************************************************************************/
+/* CONTRUCTORS, DESTRUCTORS AND INITIALIZATION METHODS */
+/******************************************************************************/
+HopByHopHeader::HopByHopHeader() {
+ this->reset();
+} /* End of HopByHopHeader constructor */
+
+
+HopByHopHeader::~HopByHopHeader() {
+
+} /* End of HopByHopHeader destructor */
+
+
+/** Sets every attribute to its default value */
+void HopByHopHeader::reset(){
+ memset(&this->h, 0, sizeof(nping_ipv6_ext_hopbyhop_hdr_t));
+ curr_option=(u8*)this->h.options;
+ this->length=2;
+ this->addOption(EXTOPT_PADN, 4, (const u8*)"\x00\x00\x00\x00");
+} /* End of reset() */
+
+
+/******************************************************************************/
+/* PacketElement:: OVERWRITTEN METHODS */
+/******************************************************************************/
+
+/** @warning This method is essential for the superclass getBinaryBuffer()
+ * method to work. Do NOT change a thing unless you know what you're doing */
+u8 *HopByHopHeader::getBufferPointer(){
+ return (u8*)(&this->h);
+} /* End of getBufferPointer() */
+
+
+/** Stores supplied packet in the internal buffer so the information
+ * can be accessed using the standard get & set methods.
+ * @warning The HopByHopHeader class is able to hold a maximum of
+ * sizeof(nping_icmpv6_hdr_t) bytes. If the supplied buffer is longer than
+ * that, only the first 1508 bytes will be stored in the internal buffer.
+ * @warning Supplied len MUST be at least 8 bytes (min ICMPv6 header length).
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error */
+int HopByHopHeader::storeRecvData(const u8 *buf, size_t len){
+ if(buf==NULL || len<HOPBYHOP_MIN_HEADER_LEN){
+ this->length=0;
+ return OP_FAILURE;
+ }else{
+ /* Store the first 4 bytes, so we can access the HdrExtLen field. */
+ memcpy(&(this->h), buf, 4);
+
+ /* Check that the HdrExtLen field makes sense:
+ * 1) Check that it carries as many octets as it claims
+ * 2) Check that we don't exceed our internal storage space. */
+ // h.len cannot exceed 0xff, so max is (0xff+1)*8, but HOPBYHOP_MAX_HEADER_LEN is 8 + 0x100*8
+ if( ((unsigned int)(this->h.len+1))*8 > len){
+ this->length=0;
+ return OP_FAILURE;
+ }else{
+ int mylen=(this->h.len+1)*8;
+ this->reset();
+ this->length=mylen;
+ memcpy(&(this->h), buf, this->length);
+ return OP_SUCCESS;
+ }
+ }
+ return OP_FAILURE;
+} /* End of storeRecvData() */
+
+
+/* Returns a protocol identifier. This is used by packet parsing funtions
+ * that return linked lists of PacketElement objects, to determine the protocol
+ * the object represents. */
+int HopByHopHeader::protocol_id() const {
+ return HEADER_TYPE_IPv6_HOPOPT;
+} /* End of protocol_id() */
+
+
+/** Determines if the data stored in the object after an storeRecvData() call
+ * is valid and safe to use. This mainly checks the length of the data but may
+ * also test the value of certain protocol fields to ensure their correctness.
+ * @return the length, in bytes, of the header, if its found to be valid or
+ * OP_FAILURE (-1) otherwise. */
+int HopByHopHeader::validate(){
+ nping_ipv6_ext_hopbyhop_opt_t *curr_opt=NULL;
+ u8 *curr_pnt=(u8 *)this->h.options;
+ int bytes_left=this->length-2;
+
+ /* Check the object's length makes sense*/
+ if(this->length%8!=0 || this->length < HOPBYHOP_MIN_HEADER_LEN || this->length > HOPBYHOP_MAX_HEADER_LEN){
+ return OP_FAILURE;
+ }
+ /* Check the header's length field. It should match the object's length */
+ if( (this->h.len+1)*8 != this->length){
+ return OP_FAILURE;
+ }
+
+ /* Now validate the TLV-encoded options. */
+ while(bytes_left>0){
+ /* Use the opts structure as a template to access current option */
+ curr_opt=(nping_ipv6_ext_hopbyhop_opt_t *)curr_pnt;
+
+ /* Let's see what we have. */
+ switch(curr_opt->type){
+
+ /* Pad1
+ +-+-+-+-+-+-+-+-+
+ | 0 |
+ +-+-+-+-+-+-+-+-+ */
+ case EXTOPT_PAD1:
+ curr_pnt++; /* Skip one octet */
+ bytes_left++;
+ break;
+
+ /* PadN
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- - - - - - - - -
+ | 1 | Padding Len | Padding
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- - - - - - - - - */
+ case EXTOPT_PADN:
+ /* Check we have as many octets as the option advertises */
+ if(bytes_left<2+curr_opt->len)
+ return OP_FAILURE;
+ curr_pnt+=2+curr_opt->len;
+ bytes_left-=2+curr_opt->len;
+ break;
+
+ /* Jumbo Payload Option (RFC 2675).
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Option Type | Opt Data Len |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Jumbo Payload Length |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+ case EXTOPT_JUMBO:
+ /* Jumbo has a fixed length of 4 octets (plus 2). */
+ if(curr_opt->len!=4)
+ return OP_FAILURE;
+ /* Check if we actually have all the octets */
+ if(bytes_left<2+4)
+ return OP_FAILURE;
+ curr_pnt+=6;
+ bytes_left-=6;
+ break;
+
+ /* Tunnel Encapsulation limit (RFC 2473).
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Option Type | 1 | Tun Encap Lim |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+ case EXTOPT_TUNENCAPLIM:
+ /* This one also has a fixed length. */
+ if(curr_opt->len!=1)
+ return OP_FAILURE;
+ /* Check if we actually have all the octets */
+ if(bytes_left<2+1)
+ return OP_FAILURE;
+ curr_pnt+=3;
+ bytes_left-=3;
+ break;
+
+ /* Router Alert (RFC 2711).
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Option Type | 2 | Value (2 octets) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+ case EXTOPT_ROUTERALERT:
+ /* Fixed length (two octets)*/
+ if(curr_opt->len!=2)
+ return OP_FAILURE;
+ /* Check that we actually have all the octets */
+ if(bytes_left<2+2)
+ return OP_FAILURE;
+ curr_pnt+=4;
+ bytes_left-=4;
+ break;
+
+ /* Quick-Start (RFC 4782).
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Option | Length=6 | Func. | Rate | Not Used |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | QS Nonce | R |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+ case EXTOPT_QUICKSTART:
+ /* Fixed length (two octets)*/
+ if(curr_opt->len!=6)
+ return OP_FAILURE;
+ /* Check that we actually have all the octets */
+ if(bytes_left<2+6)
+ return OP_FAILURE;
+ curr_pnt+=8;
+ bytes_left-=8;
+ break;
+
+ /* CALIPSO (RFC 5570).
+ +----------------------------+
+ | Option Type | Option Length|
+ +-------------+---------------+-------------+--------------+
+ | CALIPSO Domain of Interpretation |
+ +-------------+---------------+-------------+--------------+
+ | Cmpt Length | Sens Level | Checksum (CRC-16) |
+ +-------------+---------------+-------------+--------------+
+ | Compartment Bitmap (Optional; variable length) |
+ +-------------+---------------+-------------+--------------+ */
+ case EXTOPT_CALIPSO:
+ /* The length of the CALIPSO option is variable because the
+ * Compartment Bitmap is not mandatory. However, the length
+ * must be at least 8. */
+ if(curr_opt->len<8)
+ return OP_FAILURE;
+ /* Check that we actually have all the octets */
+ if(bytes_left<2+curr_opt->len)
+ return OP_FAILURE;
+ curr_pnt+=2+curr_opt->len;
+ bytes_left-=2+curr_opt->len;
+ break;
+
+
+ /* Home Address (RFC 6275).
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Option Type | Option Length |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ + +
+ | |
+ + Home Address +
+ | |
+ + +
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*/
+ case EXTOPT_HOMEADDR:
+ /* Fixed length of 16 */
+ if(curr_opt->len!=16)
+ return OP_FAILURE;
+ /* Check if we actually have all the octets */
+ if(bytes_left<2+16)
+ return OP_FAILURE;
+ curr_pnt+=18;
+ bytes_left-=18;
+ break;
+
+ /* Option Type Unknown */
+ default:
+ /* If we don't know the option, we can still try to validate it,
+ * checking if the OptionLength contains something reasonable. */
+ /* Fixed length of 16 */
+ if(bytes_left<2+curr_opt->len)
+ return OP_FAILURE;
+ curr_pnt+=2+curr_opt->len;
+ bytes_left-=2+curr_opt->len;
+ break;
+ }
+ }
+ return this->length;
+} /* End of validate() */
+
+
+/** Prints the contents of the header and calls print() on the next protocol
+ * header in the chain (if there is any).
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error. */
+int HopByHopHeader::print(FILE *output, int detail) const {
+ fprintf(output, "HopByHop[%d,%d]", this->h.nh, this->h.len);
+ // TODO: @todo : Implement this
+ if(this->next!=NULL){
+ print_separator(output, detail);
+ next->print(output, detail);
+ }
+ return OP_SUCCESS;
+} /* End of print() */
+
+
+/******************************************************************************/
+/* PROTOCOL-SPECIFIC METHODS */
+/******************************************************************************/
+
+/** Set Next Header field */
+int HopByHopHeader::setNextHeader(u8 val){
+ this->h.nh = val;
+ return OP_SUCCESS;
+} /* End of setNextHeader() */
+
+
+/** Returns next header id */
+u8 HopByHopHeader::getNextHeader(){
+ return this->h.nh;
+} /* End of getNextHeader() */
+
+
+/* Add TLV encoded option */
+int HopByHopHeader::addOption(u8 type, u8 len, const u8 *data){
+ /* Make sure we don't screw up due to buffer length issues */
+ if(data==NULL)
+ return OP_FAILURE;
+ if ( (this->length+len+2) > HOPBYHOP_MAX_HEADER_LEN ) /* No space for more */
+ return OP_FAILURE;
+
+ /* Store the option */
+ curr_option[0]=type;
+ curr_option[1]=len;
+ memcpy(curr_option+2, data, len);
+ /* Update internal option offset and object's length */
+ curr_option+=(len+2);
+ this->length+=(len+2);
+ this->addPadding();
+ return OP_SUCCESS;
+
+} /* End of addOption() */
+
+
+/* If the current length of the extension header is not a multiple of 8 octets,
+ * this method adds the necessary padding (either PadN or Pad1 options)*/
+int HopByHopHeader::addPadding(){
+ u8 zeroes[8]={0,0,0,0,0,0,0,0};
+ // required_octets in range [0,7]
+ int required_octets=(8 - (this->length % 8)) % 8;
+
+ /* Make sure we have enough space for the padding. */
+ if ( (this->length+required_octets) > HOPBYHOP_MAX_HEADER_LEN )
+ return OP_FAILURE;
+
+ /* Insert Pad1 or PadN to fill the necessary octets */
+ if (required_octets == 1) {
+ curr_option[0]=EXTOPT_PAD1;
+ curr_option++;
+ this->length++;
+ }
+ else if (required_octets > 0) {
+ this->addOption(EXTOPT_PADN, required_octets-2, zeroes );
+ }
+ assert(this->length%8==0);
+ this->h.len=(this->length/8)-1;
+ return OP_SUCCESS;
+} /* End of addPadding() */
diff --git a/libnetutil/HopByHopHeader.h b/libnetutil/HopByHopHeader.h
new file mode 100644
index 0000000..9fdfd45
--- /dev/null
+++ b/libnetutil/HopByHopHeader.h
@@ -0,0 +1,122 @@
+/***************************************************************************
+ * HopByHopHeader.h -- The HopByHopHeader Class represents an IPv6 *
+ * Hop-by-Hop extension header. *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#ifndef __HOP_BY_HOP_HEADER_H__
+#define __HOP_BY_HOP_HEADER_H__ 1
+
+#include "IPv6ExtensionHeader.h"
+
+#define HOP_BY_HOP_MAX_OPTIONS_LEN 256*8
+#define HOPBYHOP_MIN_HEADER_LEN 8
+#define HOPBYHOP_MAX_HEADER_LEN (HOPBYHOP_MIN_HEADER_LEN + HOP_BY_HOP_MAX_OPTIONS_LEN)
+#define HOPBYHOP_MAX_OPTION_LEN 256
+
+class HopByHopHeader : public IPv6ExtensionHeader {
+
+ protected:
+ /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Next Header | Hdr Ext Len | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
+ | |
+ . .
+ . Options .
+ . .
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+ struct nping_ipv6_ext_hopbyhop_hdr{
+ u8 nh;
+ u8 len;
+ u8 options[HOP_BY_HOP_MAX_OPTIONS_LEN];
+ }__attribute__((__packed__));
+ typedef struct nping_ipv6_ext_hopbyhop_hdr nping_ipv6_ext_hopbyhop_hdr_t;
+
+
+ /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- - - - - - - - -
+ | Option Type | Opt Data Len | Option Data
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- - - - - - - - - */
+ struct nping_ipv6_ext_hopbyhop_opt{
+ u8 type;
+ u8 len;
+ u8 data[HOPBYHOP_MAX_OPTION_LEN];
+ }__attribute__((__packed__));
+ typedef struct nping_ipv6_ext_hopbyhop_opt nping_ipv6_ext_hopbyhop_opt_t;
+
+ nping_ipv6_ext_hopbyhop_hdr_t h;
+ u8 *curr_option;
+
+ public:
+ HopByHopHeader();
+ ~HopByHopHeader();
+ void reset();
+ u8 *getBufferPointer();
+ int storeRecvData(const u8 *buf, size_t len);
+ int protocol_id() const;
+ int validate();
+ int print(FILE *output, int detail) const;
+
+ /* Protocol specific methods */
+ int setNextHeader(u8 val);
+ u8 getNextHeader();
+
+ int addOption(u8 type, u8 len, const u8 *data);
+ int addPadding();
+
+}; /* End of class HopByHopHeader */
+
+#endif
diff --git a/libnetutil/ICMPHeader.h b/libnetutil/ICMPHeader.h
new file mode 100644
index 0000000..1f5bff4
--- /dev/null
+++ b/libnetutil/ICMPHeader.h
@@ -0,0 +1,83 @@
+/***************************************************************************
+ * ICMPHeader.h -- Class ICMPHeader is a generic class for the ICMP *
+ * protocol. Its aim is to provide a little bit of abstraction from the *
+ * underlying ICMP version. Classes like ICMPv4Header or ICMPv6Header *
+ * inherit from it. *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#ifndef __ICMPHEADER_H__
+#define __ICMPHEADER_H__ 1
+
+#include "PacketElement.h"
+
+class ICMPHeader : public PacketElement {
+
+ public:
+
+ virtual u8 getType() const = 0;
+
+ virtual int setType(u8 val) = 0;
+
+ virtual u8 getCode() const = 0;
+
+ virtual int setCode(u8 val) = 0;
+
+ virtual bool isError() const = 0;
+};
+
+#endif /* __ICMPHEADER_H__ */
diff --git a/libnetutil/ICMPv4Header.cc b/libnetutil/ICMPv4Header.cc
new file mode 100644
index 0000000..3de406d
--- /dev/null
+++ b/libnetutil/ICMPv4Header.cc
@@ -0,0 +1,1187 @@
+/***************************************************************************
+ * ICMPv4Header.cc -- The ICMPv4Header Class represents an ICMP version 4 *
+ * packet. It contains methods to set any header field. In general, these *
+ * methods do error checkings and byte order conversion. *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#include "ICMPv4Header.h"
+
+/******************************************************************************/
+/* CONTRUCTORS, DESTRUCTORS AND INITIALIZATION METHODS */
+/******************************************************************************/
+ICMPv4Header::ICMPv4Header() {
+ this->reset();
+} /* End of ICMPv4Header constructor */
+
+
+ICMPv4Header::~ICMPv4Header() {
+
+} /* End of ICMPv4Header destructor */
+
+
+/** Sets every attribute to its default value */
+void ICMPv4Header::reset(){
+ memset(&this->h, 0, sizeof(nping_icmpv4_hdr_t));
+ h_du = (icmp4_dest_unreach_msg_t *)this->h.data;
+ h_te = (icmp4_time_exceeded_msg_t *)this->h.data;
+ h_pp = (icmp4_parameter_problem_msg_t *)this->h.data;
+ h_sq = (icmp4_source_quench_msg_t *)this->h.data;
+ h_r = (icmp4_redirect_msg_t *)this->h.data;
+ h_e = (icmp4_echo_msg_t *)this->h.data;
+ h_t = (icmp4_timestamp_msg_t *)this->h.data;
+ h_i = (icmp4_information_msg_t *)this->h.data;
+ h_ra = (icmp4_router_advert_msg_t *)this->h.data;
+ h_rs = (icmp4_router_solicit_msg_t *)this->h.data;
+ h_sf = (icmp4_security_failures_msg_t *)this->h.data;
+ h_am = (icmp4_address_mask_msg_t *)this->h.data;
+ h_trc = (icmp4_traceroute_msg_t *)this->h.data;
+ h_dn = (icmp4_domain_name_request_msg_t *)this->h.data;
+ h_dnr = (icmp4_domain_name_reply_msg_t *)this->h.data;
+ this->routeradventries=0;
+ this->domainnameentries=0;
+} /* End of reset() */
+
+
+/******************************************************************************/
+/* PacketElement:: OVERWRITTEN METHODS */
+/******************************************************************************/
+
+/** @warning This method is essential for the superclass getBinaryBuffer()
+ * method to work. Do NOT change a thing unless you know what you're doing */
+u8 *ICMPv4Header::getBufferPointer(){
+ return (u8*)(&h);
+} /* End of getBufferPointer() */
+
+
+/** Stores supplied packet in the internal buffer so the information
+ * can be accessed using the standard get & set methods.
+ * @warning The ICMPv4Header class is able to hold a maximum of 1508 bytes.
+ * If the supplied buffer is longer than that, only the first 1508 bytes will
+ * be stored in the internal buffer.
+ * @warning Supplied len MUST be at least 8 bytes (min ICMPv4 header length).
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error */
+int ICMPv4Header::storeRecvData(const u8 *buf, size_t len){
+ if(buf==NULL || len<ICMP_STD_HEADER_LEN){
+ return OP_FAILURE;
+ }else{
+ int stored_len = MIN((ICMP_MAX_PAYLOAD_LEN+4), len);
+ this->reset(); /* Re-init the object, just in case the caller had used it already */
+ this->length=stored_len;
+ memcpy(&(this->h), buf, stored_len);
+ }
+ return OP_SUCCESS;
+} /* End of storeRecvData() */
+
+
+/* Returns a protocol identifier. This is used by packet parsing funtions
+ * that return linked lists of PacketElement objects, to determine the protocol
+ * the object represents. */
+int ICMPv4Header::protocol_id() const {
+ return HEADER_TYPE_ICMPv4;
+} /* End of protocol_id() */
+
+
+/** Determines if the data stored in the object after an storeRecvData() call
+ * is valid and safe to use. This mainly checks the length of the data but may
+ * also test the value of certain protocol fields to ensure their correctness.
+ * @return the length, in bytes, of the header, if its found to be valid or
+ * OP_FAILURE (-1) otherwise. */
+int ICMPv4Header::validate(){
+ int should_have=this->getICMPHeaderLengthFromType( this->getType() );
+ if(this->length < should_have){
+ return OP_FAILURE;
+ }else{
+ /* WARNING: TODO: @todo This does not work for those messages whose
+ * length is variable (e.g: router advertisements). */
+ return should_have;
+ }
+} /* End of validate() */
+
+
+/** Prints the contents of the header and calls print() on the next protocol
+ * header in the chain (if there is any).
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error. */
+int ICMPv4Header::print(FILE *output, int detail) const {
+ u8 type=this->getType();
+ u8 code=this->getCode();
+ char auxstr[64];
+ struct in_addr auxaddr;
+ const char *typestr=this->type2string(type, code);
+
+ fprintf(output, "ICMPv4[%s", typestr);
+ if(detail>=PRINT_DETAIL_MED)
+ fprintf(output, " (type=%u/code=%u)", type, code);
+
+ switch(type) {
+ case ICMP_ECHOREPLY:
+ case ICMP_ECHO:
+ case ICMP_INFO:
+ case ICMP_INFOREPLY:
+ fprintf(output, " id=%u seq=%u", this->getIdentifier(), this->getSequence());
+ break;
+
+ case ICMP_UNREACH:
+ case ICMP_SOURCEQUENCH:
+ case ICMP_ROUTERSOLICIT:
+ if(detail>=PRINT_DETAIL_HIGH)
+ fprintf(output, " unused=%u", this->getUnused());
+ break;
+
+ case ICMP_REDIRECT:
+ auxaddr=this->getGatewayAddress();
+ inet_ntop(AF_INET, &auxaddr, auxstr, sizeof(auxstr)-1);
+ fprintf(output, " addr=%s", auxstr);
+ break;
+
+ case ICMP_ROUTERADVERT:
+ fprintf(output, " addrs=%u addrlen=%u lifetime=%d",
+ this->getNumAddresses(),
+ this->getAddrEntrySize(),
+ this->getLifetime()
+ );
+ break;
+
+ case ICMP_PARAMPROB:
+ fprintf(output, " pointer=%u", this->getParameterPointer());
+ break;
+
+ case ICMP_TSTAMP:
+ case ICMP_TSTAMPREPLY:
+ fprintf(output, " id=%u seq=%u", this->getIdentifier(), this->getSequence());
+ fprintf(output, " orig=%lu recv=%lu trans=%lu",
+ (unsigned long)this->getOriginateTimestamp(),
+ (unsigned long)this->getReceiveTimestamp(),
+ (unsigned long)this->getTransmitTimestamp() );
+ break;
+
+ case ICMP_MASK:
+ case ICMP_MASKREPLY:
+ fprintf(output, " id=%u seq=%u", this->getIdentifier(), this->getSequence());
+ auxaddr=this->getAddressMask();
+ inet_ntop(AF_INET, &auxaddr, auxstr, sizeof(auxstr)-1);
+ fprintf(output, " mask=%s", auxstr);
+ break;
+
+ case ICMP_TRACEROUTE:
+ fprintf(output, " id=%u", this->getIDNumber());
+ if(detail>=PRINT_DETAIL_HIGH)
+ fprintf(output, " unused=%u", this->getUnused());
+ if(detail>=PRINT_DETAIL_MED){
+ fprintf(output, " outhops=%u", this->getOutboundHopCount() );
+ fprintf(output, " rethops=%u", this->getReturnHopCount() );
+ }
+ if(detail>=PRINT_DETAIL_HIGH){
+ fprintf(output, " speed=%lu", (unsigned long)this->getOutputLinkSpeed() );
+ fprintf(output, " mtu=%lu", (unsigned long)this->getOutputLinkMTU());
+ }
+ break;
+
+ case ICMP_DOMAINNAME:
+ case ICMP_DOMAINNAMEREPLY:
+ fprintf(output, " id=%u seq=%u", this->getIdentifier(), this->getSequence());
+ /* TODO: print TTL and domain names in replies */
+ // UNIMPLEMENTED
+ break;
+
+ case ICMP_SECURITYFAILURES:
+ if(detail>=PRINT_DETAIL_HIGH)
+ fprintf(output, " reserved=%u",this->getReserved());
+ fprintf(output, " pointer=%u",this->getSecurityPointer());
+ break;
+
+ default:
+ /* Print nothing */
+ break;
+ }
+
+ if(detail>=PRINT_DETAIL_HIGH)
+ fprintf(output, " csum=0x%04X", ntohs(this->getSum()));
+ fprintf(output, "]");
+ if(this->next!=NULL){
+ print_separator(output, detail);
+ next->print(output, detail);
+ }
+ return OP_SUCCESS;
+} /* End of print() */
+
+
+/******************************************************************************/
+/* PROTOCOL-SPECIFIC METHODS */
+/******************************************************************************/
+
+/* ICMPv4 common fields *****************************************************/
+int ICMPv4Header::setType(u8 val){
+ h.type = val;
+ length = getICMPHeaderLengthFromType( val );
+ return OP_SUCCESS;
+} /* End of setType() */
+
+
+/** @warning Returned value is in HOST byte order */
+u8 ICMPv4Header::getType() const {
+ return h.type;
+} /* End of getType() */
+
+/** Returns true if the supplied type is an RFC compliant type */
+bool ICMPv4Header::validateType(u8 val){
+ switch( val ){
+ case ICMP_ECHOREPLY:
+ case ICMP_UNREACH:
+ case ICMP_SOURCEQUENCH:
+ case ICMP_REDIRECT:
+ case ICMP_ECHO:
+ case ICMP_ROUTERADVERT:
+ case ICMP_ROUTERSOLICIT:
+ case ICMP_TIMXCEED:
+ case ICMP_PARAMPROB:
+ case ICMP_TSTAMP:
+ case ICMP_TSTAMPREPLY:
+ case ICMP_INFO:
+ case ICMP_INFOREPLY:
+ case ICMP_MASK:
+ case ICMP_MASKREPLY:
+ case ICMP_TRACEROUTE:
+ case ICMP_DOMAINNAME:
+ case ICMP_DOMAINNAMEREPLY:
+ return true;
+ break;
+
+ default:
+ return false;
+ break;
+ }
+ return false;
+} /* End of validateType() */
+
+
+/** Returns true if the type fields contains an RFC compliant ICMP message
+ * type. */
+bool ICMPv4Header::validateType(){
+ return validateType( this->h.type );
+} /* End of validateType() */
+
+
+/** Set ICMP code field */
+int ICMPv4Header::setCode(u8 val){
+ h.code = val;
+ return OP_SUCCESS;
+} /* End of setCode() */
+
+
+/** @warning Returned value is in HOST byte order */
+u8 ICMPv4Header::getCode() const {
+ return h.code;
+} /* End of getCode() */
+
+
+/** Given an ICMP Type and a code, determines whether the code corresponds to
+ * a RFC compliant code (eg: code 0x03 for "port unreachable" in ICMP
+ * Unreachable messages) or just some other bogus code. */
+bool ICMPv4Header::validateCode(u8 type, u8 code){
+ switch (type){
+ case ICMP_ECHOREPLY:
+ return (code==0);
+ break;
+
+ case ICMP_UNREACH:
+ switch( code ){
+ case ICMP_UNREACH_NET:
+ case ICMP_UNREACH_HOST:
+ case ICMP_UNREACH_PROTOCOL:
+ case ICMP_UNREACH_PORT:
+ case ICMP_UNREACH_NEEDFRAG:
+ case ICMP_UNREACH_SRCFAIL:
+ case ICMP_UNREACH_NET_UNKNOWN:
+ case ICMP_UNREACH_HOST_UNKNOWN:
+ case ICMP_UNREACH_ISOLATED:
+ case ICMP_UNREACH_NET_PROHIB:
+ case ICMP_UNREACH_HOST_PROHIB:
+ case ICMP_UNREACH_TOSNET:
+ case ICMP_UNREACH_TOSHOST:
+ case ICMP_UNREACH_COMM_PROHIB:
+ case ICMP_UNREACH_HOSTPRECEDENCE:
+ case ICMP_UNREACH_PRECCUTOFF:
+ return true;
+ }
+ break;
+
+ case ICMP_REDIRECT:
+ switch( code ){
+ case ICMP_REDIRECT_NET:
+ case ICMP_REDIRECT_HOST:
+ case ICMP_REDIRECT_TOSNET:
+ case ICMP_REDIRECT_TOSHOST:
+ return true;
+ }
+ break;
+
+ case ICMP_ROUTERADVERT:
+ switch( code ){
+ case 0:
+ case ICMP_ROUTERADVERT_MOBILE:
+ return true;
+ }
+ break;
+
+ case ICMP_TIMXCEED:
+ switch( code ){
+ case ICMP_TIMXCEED_INTRANS:
+ case ICMP_TIMXCEED_REASS:
+ return true;
+ }
+ break;
+
+ case ICMP_PARAMPROB:
+ switch( code ){
+ case ICMM_PARAMPROB_POINTER:
+ case ICMP_PARAMPROB_OPTABSENT:
+ case ICMP_PARAMPROB_BADLEN:
+ return true;
+ }
+ break;
+
+ case ICMP_TSTAMP:
+ case ICMP_TSTAMPREPLY:
+ case ICMP_INFO:
+ case ICMP_INFOREPLY:
+ case ICMP_MASK:
+ case ICMP_MASKREPLY:
+ case ICMP_ROUTERSOLICIT:
+ case ICMP_SOURCEQUENCH:
+ case ICMP_ECHO:
+ return (code==0);
+ break;
+
+ case ICMP_TRACEROUTE:
+ switch( code ){
+ case ICMP_TRACEROUTE_SUCCESS:
+ case ICMP_TRACEROUTE_DROPPED:
+ return true;
+ }
+ break;
+
+ default:
+ return false;
+ break;
+ }
+ return false;
+} /* End of validateCode() */
+
+
+/** Computes the ICMP header checksum and sets the checksum field to the right
+ * value. */
+int ICMPv4Header::setSum(){
+ u8 buffer[65535];
+ int total_len=0;
+ h.checksum = 0;
+
+ memcpy(buffer, &h, length);
+
+ if( this->getNextElement() != NULL)
+ total_len=next->dumpToBinaryBuffer(buffer+length, 65535-length);
+ total_len+=length;
+
+ h.checksum = in_cksum((unsigned short *)buffer, total_len);
+
+ return OP_SUCCESS;
+} /* End of setSum() */
+
+
+/** @warning Sum is set to supplied value with NO byte ordering conversion
+ * performed.
+ * @warning If sum is supplied this way, no error checks are made. Caller is
+ * responsible for the correctness of the value. */
+int ICMPv4Header::setSum(u16 s){
+ h.checksum = s;
+ return OP_SUCCESS;
+} /* End of setSum() */
+
+
+/** Returns the value of the checksum field.
+ * @warning The returned value is in NETWORK byte order, no conversion is
+ * performed */
+u16 ICMPv4Header::getSum() const {
+ return h.checksum;
+} /* End of getSum() */
+
+
+
+/* Dest unreach/Source quench/Time exceeded **********************************/
+/** @warning Supplied value MUST be in host byte order because it will get
+ * converted by this method using htonl() */
+int ICMPv4Header::setReserved(u32 val){
+ u32 aux32=0;
+ u8 *auxpnt=(u8 *)&aux32;
+
+ switch(this->h.type){
+
+ case ICMP_UNREACH:
+ this->h_du->unused=htonl(val);
+ break;
+
+ case ICMP_TIMXCEED:
+ this->h_te->unused=htonl(val);
+ break;
+
+ case ICMP_PARAMPROB:
+ /* The reserved field in Parameter Problem messages is only
+ * 24-bits long so we convert the supplied value to big endian and
+ * use only the 24 least significant bits. */
+ aux32=htonl(val);
+ this->h_pp->unused[0]=auxpnt[1];
+ this->h_pp->unused[1]=auxpnt[2];
+ this->h_pp->unused[2]=auxpnt[3];
+ break;
+
+ case ICMP_SOURCEQUENCH:
+ this->h_sq->unused=htonl(val);
+ break;
+
+ case ICMP_ROUTERSOLICIT:
+ this->h_rs->reserved=htonl(val);
+ break;
+
+ case ICMP_SECURITYFAILURES:
+ /* The reserved field in Security failure messages is only
+ * 16-bits long so we cast it to u16 first (callers are not supposed to
+ * pass values higher than 2^16) */
+ this->h_sf->reserved= htons((u16)val);
+ break;
+
+ case ICMP_TRACEROUTE:
+ /* The reserved field in Traceroute messages is only
+ * 16-bits long so we cast it to u16 first (callers are not supposed to
+ * pass values higher than 2^16) */
+ this->h_trc->unused=htons((u16)val);
+ break;
+
+ default:
+ return OP_FAILURE;
+ break;
+ }
+ return OP_SUCCESS;
+} /* End of setReserved() */
+
+
+/** @warning Returned value is in host byte order */
+u32 ICMPv4Header::getReserved() const {
+ u32 aux32=0;
+ u8 *auxpnt=(u8 *)&aux32;
+
+ switch(this->h.type){
+
+ case ICMP_UNREACH:
+ return ntohl(this->h_du->unused);
+ break;
+
+ case ICMP_TIMXCEED:
+ return ntohl(this->h_te->unused);
+ break;
+
+ case ICMP_PARAMPROB:
+ /* The unused field in Parameter Problem messages is only
+ * 24-bits long so we extract the stored value and convert it to host
+ * byte order. */
+ auxpnt[0]=0;
+ auxpnt[1]=this->h_pp->unused[0];
+ auxpnt[2]=this->h_pp->unused[1];
+ auxpnt[3]=this->h_pp->unused[2];
+ return ntohl(aux32);
+ break;
+
+ case ICMP_SOURCEQUENCH:
+ return ntohl(this->h_sq->unused);
+ break;
+
+ case ICMP_ROUTERSOLICIT:
+ return ntohl(this->h_rs->reserved);
+ break;
+
+ case ICMP_SECURITYFAILURES:
+ /* The unused field in Security Failures messages is only
+ * 16-bits long so we extract the stored value and cast it to an u32 in
+ * host byte order */
+ return (u32)ntohs(h_sf->reserved);
+ break;
+
+ case ICMP_TRACEROUTE:
+ /* The reserved field in Traceroute messages is only
+ * 16-bits long so we extract the stored value and cast it to an u32 in
+ * host byte order */
+ return (u32)ntohs(h_trc->unused);
+ break;
+
+ default:
+ return OP_FAILURE;
+ break;
+ }
+ return OP_SUCCESS;
+} /* End of setReserved() */
+
+
+int ICMPv4Header::setUnused(u32 val){
+ return this->setReserved(val);
+} /* End of setUnused() */
+
+
+u32 ICMPv4Header::getUnused() const {
+ return this->getReserved();
+} /* End of getUnused() */
+
+
+/* Redirect ******************************************************************/
+/** @warning Supplied IP MUST be in NETWORK byte order */
+int ICMPv4Header::setGatewayAddress(struct in_addr ipaddr){
+ h_r->gateway_address=ipaddr;
+ return OP_SUCCESS;
+} /* End of setPreferredRouter() */
+
+
+struct in_addr ICMPv4Header::getGatewayAddress() const {
+ return h_r->gateway_address;
+} /* End of getPreferredRouter() */
+
+
+
+/* Parameter problem *********************************************************/
+/** Sets pointer value in Parameter Problem messages */
+int ICMPv4Header::setParameterPointer(u8 val){
+ h_pp->pointer=val;
+ return OP_SUCCESS;
+} /* End of setParameterPointer() */
+
+
+/** @warning Returned value is in HOST byte order */
+u8 ICMPv4Header::getParameterPointer() const {
+ return h_pp->pointer;
+} /* End of getParameterPointer() */
+
+
+/* Router Advertisement ******************************************************/
+int ICMPv4Header::setNumAddresses(u8 val){
+ h_ra->num_addrs=val;
+ return OP_SUCCESS;
+} /* End of setNumAddresses() */
+
+
+u8 ICMPv4Header::getNumAddresses() const {
+ return h_ra->num_addrs;
+} /* End of getNumAddresses() */
+
+
+int ICMPv4Header::setAddrEntrySize(u8 val){
+ h_ra->addr_entry_size=val;
+ return OP_SUCCESS;
+} /* End of setAddrEntrySize() */
+
+
+/** @warning Returned value is in HOST byte order */
+u8 ICMPv4Header::getAddrEntrySize() const {
+ return h_ra->addr_entry_size;
+} /* End of getAddrEntrySize() */
+
+
+/** @warning Supplied value MUST be in host byte order because it will get
+ * converted by this method using htons() */
+int ICMPv4Header::setLifetime(u16 val){
+ h_ra->lifetime= htons(val);
+ return OP_SUCCESS;
+} /* End of setLifetime() */
+
+
+/** @warning Returned value is in HOST byte order */
+u16 ICMPv4Header::getLifetime() const {
+ return ntohs( h_ra->lifetime );
+} /* End of getLifetime() */
+
+
+/** @warning Asummes entries have a length of 2*32bits and consist of
+ * two 32bit values.
+ * @warning This method automatically updates field "Number of addreses"
+ * calling this->setNumAddresses(). If you want to place a bogus number
+ * on such field, setNumAddresses() must be called AFTER any calls to
+ * addRouterAdvEntry()
+ * */
+int ICMPv4Header::addRouterAdvEntry(struct in_addr raddr, u32 pref){
+ if ( this->routeradventries >= MAX_ROUTER_ADVERT_ENTRIES )
+ return OP_FAILURE;
+ h_ra->adverts[this->routeradventries].router_addr=raddr;
+ h_ra->adverts[this->routeradventries].preference_level=htonl(pref);
+ this->routeradventries++; /* Update internal entry count */
+ length += 8; /* Update total length of the ICMP packet */
+ this->setNumAddresses( this->routeradventries ); /* Update number of addresses */
+ return OP_SUCCESS;
+} /* End of addRouterAdEntry() */
+
+
+u8 *ICMPv4Header::getRouterAdvEntries(int *num) const {
+ if( this->routeradventries <= 0 )
+ return NULL;
+ if (num!=NULL)
+ *num = this->routeradventries;
+ return (u8*)h_ra->adverts;
+} /* End of getRouterEntries() */
+
+
+/* Echo/Timestamp/Mask *******************************************************/
+/** @warning Supplied value MUST be in host byte order because it will get
+ * converted by this method using htons() */
+int ICMPv4Header::setIdentifier(u16 val){
+ switch(this->h.type){
+ case ICMP_ECHOREPLY:
+ case ICMP_ECHO:
+ h_e->identifier=htons(val);
+ break;
+
+ case ICMP_TSTAMP:
+ case ICMP_TSTAMPREPLY:
+ h_t->identifier=htons(val);
+ break;
+
+ case ICMP_INFO:
+ case ICMP_INFOREPLY:
+ h_i->identifier=htons(val);
+ break;
+
+ case ICMP_MASK:
+ case ICMP_MASKREPLY:
+ h_am->identifier=htons(val);
+ break;
+
+ case ICMP_DOMAINNAME:
+ h_dn->identifier=htons(val);
+ break;
+
+ case ICMP_DOMAINNAMEREPLY:
+ h_dnr->identifier=htons(val);
+ break;
+
+ default:
+ return OP_FAILURE;
+ break;
+ }
+ return OP_SUCCESS;
+} /* End of setIdentifier() */
+
+
+/** @warning Returned value is in HOST byte order */
+u16 ICMPv4Header::getIdentifier() const {
+ switch(this->h.type){
+ case ICMP_ECHOREPLY:
+ case ICMP_ECHO:
+ return ntohs(h_e->identifier);
+ break;
+
+ case ICMP_TSTAMP:
+ case ICMP_TSTAMPREPLY:
+ return ntohs(h_t->identifier);
+ break;
+
+ case ICMP_INFO:
+ case ICMP_INFOREPLY:
+ return ntohs(h_i->identifier);
+ break;
+
+ case ICMP_MASK:
+ case ICMP_MASKREPLY:
+ return ntohs(h_am->identifier);
+ break;
+
+ case ICMP_DOMAINNAME:
+ return ntohs(h_dn->identifier);
+ break;
+
+ case ICMP_DOMAINNAMEREPLY:
+ return ntohs(h_dnr->identifier);
+ break;
+
+ default:
+ return 0;
+ break;
+ }
+ return 0;
+} /* End of getIdentifier() */
+
+
+/** @warning Supplied value MUST be in host byte order because it will get
+ * converted by this method using htons() */
+int ICMPv4Header::setSequence(u16 val){
+ switch(this->h.type){
+ case ICMP_ECHOREPLY:
+ case ICMP_ECHO:
+ h_e->sequence=htons(val);
+ break;
+
+ case ICMP_TSTAMP:
+ case ICMP_TSTAMPREPLY:
+ h_t->sequence=htons(val);
+ break;
+
+ case ICMP_INFO:
+ case ICMP_INFOREPLY:
+ h_i->sequence=htons(val);
+ break;
+
+ case ICMP_MASK:
+ case ICMP_MASKREPLY:
+ h_am->sequence=htons(val);
+ break;
+
+ case ICMP_DOMAINNAME:
+ h_dn->sequence=htons(val);
+ break;
+
+ case ICMP_DOMAINNAMEREPLY:
+ h_dnr->sequence=htons(val);
+ break;
+
+ default:
+ return OP_FAILURE;
+ break;
+ }
+ return OP_SUCCESS;
+} /* End of setSequence() */
+
+
+/** @warning Returned value is in HOST byte order */
+u16 ICMPv4Header::getSequence() const {
+ switch(this->h.type){
+ case ICMP_ECHOREPLY:
+ case ICMP_ECHO:
+ return ntohs(h_e->sequence);
+ break;
+
+ case ICMP_TSTAMP:
+ case ICMP_TSTAMPREPLY:
+ return ntohs(h_t->sequence);
+ break;
+
+ case ICMP_INFO:
+ case ICMP_INFOREPLY:
+ return ntohs(h_i->sequence);
+ break;
+
+ case ICMP_MASK:
+ case ICMP_MASKREPLY:
+ return ntohs(h_am->sequence);
+ break;
+
+ case ICMP_DOMAINNAME:
+ return ntohs(h_dn->sequence);
+ break;
+
+ case ICMP_DOMAINNAMEREPLY:
+ return ntohs(h_dnr->sequence);
+ break;
+
+ default:
+ return 0;
+ break;
+ }
+ return 0;
+} /* End of getSequence() */
+
+
+
+/* Timestamp only ************************************************************/
+/** @warning Supplied value MUST be in host byte order because it will get
+ * converted by this method using htonl() */
+int ICMPv4Header::setOriginateTimestamp(u32 val){
+ h_t->originate_ts=htonl(val);
+ return OP_SUCCESS;
+} /* End of setOriginateTimestamp() */
+
+
+/** @warning Returned value is in HOST byte order */
+u32 ICMPv4Header::getOriginateTimestamp() const {
+ return ntohl(h_t->originate_ts);
+} /* End of getOriginateTimestamp() */
+
+
+/** @warning Supplied value MUST be in host byte order because it will get
+ * converted by this method using htonl() */
+int ICMPv4Header::setReceiveTimestamp(u32 val){
+ h_t->receive_ts=htonl(val);
+ return OP_SUCCESS;
+} /* End of setReceiveTimestamp() */
+
+
+/** @warning Returned value is in HOST byte order */
+u32 ICMPv4Header::getReceiveTimestamp() const {
+ return ntohl(h_t->receive_ts);
+} /* End of getReceiveTimestamp() */
+
+
+/** @warning Supplied value MUST be in host byte order because it will get
+ * converted by this method using htonl() */
+int ICMPv4Header::setTransmitTimestamp(u32 val){
+ h_t->transmit_ts=htonl(val);
+ return OP_SUCCESS;
+} /* End of setTransmitTimestamp() */
+
+
+/** @warning Returned value is in HOST byte order */
+u32 ICMPv4Header::getTransmitTimestamp() const {
+ return ntohl(h_t->transmit_ts);
+} /* End of getTransmitTimestamp() */
+
+
+
+/* Mask only ****************************************************************/
+int ICMPv4Header::setAddressMask(struct in_addr ipaddr){
+ h_am->address_mask=ipaddr;
+ return OP_SUCCESS;
+} /* End of AddressMask() */
+
+
+struct in_addr ICMPv4Header::getAddressMask() const {
+ return h_am->address_mask;
+} /* End of getAddressMask() */
+
+
+
+/* Security Failures *********************************************************/
+int ICMPv4Header::setSecurityPointer(u16 val){
+ h_sf->pointer=htons(val);
+ return OP_SUCCESS;
+} /* End of setSecurityPointer() */
+
+
+u16 ICMPv4Header::getSecurityPointer() const {
+ return ntohs(h_sf->pointer);
+} /* End of getSecurityPointer() */
+
+
+
+/* Traceroute ****************************************************************/
+int ICMPv4Header::setIDNumber(u16 val){
+ h_trc->id_number = htons(val);
+ return OP_SUCCESS;
+} /* End of setIDNumber() */
+
+
+u16 ICMPv4Header::getIDNumber() const {
+ return ntohs(h_trc->id_number);
+} /* End of getIDNumber() */
+
+
+int ICMPv4Header::setOutboundHopCount(u16 val){
+ h_trc->outbound_hop_count = htons(val);
+ return OP_SUCCESS;
+} /* End of setOutboundHopCount() */
+
+
+u16 ICMPv4Header::getOutboundHopCount() const {
+ return ntohs(h_trc->outbound_hop_count);
+} /* End of getOutboundHopCount() */
+
+
+int ICMPv4Header::setReturnHopCount(u16 val){
+ h_trc->return_hop_count = htons(val);
+ return OP_SUCCESS;
+} /* End of seReturnHopCountt() */
+
+
+u16 ICMPv4Header::getReturnHopCount() const {
+ return ntohs(h_trc->return_hop_count);
+} /* End of getReturnHopCount() */
+
+
+int ICMPv4Header::setOutputLinkSpeed(u32 val){
+ h_trc->output_link_speed = htonl(val);
+ return OP_SUCCESS;
+} /* End of setOutputLinkSpeed() */
+
+
+u32 ICMPv4Header::getOutputLinkSpeed() const {
+ return ntohl(h_trc->output_link_speed);
+} /* End of getOutputLinkSpeed() */
+
+
+int ICMPv4Header::setOutputLinkMTU(u32 val){
+ h_trc->output_link_mtu = htonl(val);
+ return OP_SUCCESS;
+} /* End of setOutputLinkMTU() */
+
+
+u32 ICMPv4Header::getOutputLinkMTU() const {
+ return ntohl(h_trc->output_link_mtu);
+} /* End of getOutputLinkMTU() */
+
+
+/* Miscellaneous *************************************************************/
+/** Returns the standard ICMP header length for the supplied ICMP message type.
+ * @warning Return value corresponds strictly to the ICMP header, this is,
+ * the minimum length of the ICMP header, variable length payload is never
+ * included. For example, an ICMP Router Advertising has a fixed header of 8
+ * bytes but then the packet contains a variable number of Router Addresses
+ * and Preference Levels, so while the length of that ICMP packet is
+ * 8bytes + ValueInFieldNumberOfAddresses*8, we only return 8 because we
+ * cannot guarantee that the NumberOfAddresses field has been set before
+ * the call to this method. Same applies to the rest of types. */
+int ICMPv4Header::getICMPHeaderLengthFromType( u8 type ) const {
+
+ switch( type ){
+
+ case ICMP_ECHO:
+ case ICMP_ECHOREPLY:
+ return 8; /* (+ optional data) */
+ break;
+
+ case ICMP_UNREACH:
+ return 8; /* (+ payload) */
+ break;
+
+ case ICMP_SOURCEQUENCH:
+ return 8; /* (+ payload) */
+ break;
+
+ case ICMP_REDIRECT:
+ return 8; /* (+ payload) */
+ break;
+
+ case ICMP_ROUTERADVERT:
+ return 8; /* (+ value of NumAddr field * 8 ) */
+ break;
+
+ case ICMP_ROUTERSOLICIT:
+ return 8;
+ break;
+
+ case ICMP_TIMXCEED:
+ return 8; /* (+ payload) */
+ break;
+
+ case ICMP_PARAMPROB:
+ return 8; /* (+ payload) */
+ break;
+
+ case ICMP_TSTAMP:
+ case ICMP_TSTAMPREPLY:
+ return 20;
+ break;
+
+ case ICMP_INFO:
+ case ICMP_INFOREPLY:
+ return 8;
+ break;
+
+ case ICMP_MASK:
+ case ICMP_MASKREPLY:
+ return 12;
+ break;
+
+ case ICMP_TRACEROUTE:
+ return 20;
+ break;
+
+ case ICMP_DOMAINNAME:
+ case ICMP_DOMAINNAMEREPLY:
+ return 8;
+ break;
+
+ /* Packets with non RFC-Compliant types will be represented as
+ an 8-byte ICMP header, just like the types that don't include
+ additional info (time exceeded, router solicitation, etc) */
+ default:
+ return 8;
+ break;
+ }
+ return 8;
+} /* End of getICMPHeaderLengthFromType() */
+
+
+const char *ICMPv4Header::type2string(int type, int code) const {
+ switch(type) {
+ case ICMP_ECHOREPLY:
+ return "Echo reply";
+ break;
+
+ case ICMP_UNREACH:
+ switch(code) {
+ case ICMP_UNREACH_NET: return "Network unreachable"; break;
+ case ICMP_UNREACH_HOST: return "Host unreachable"; break;
+ case ICMP_UNREACH_PROTOCOL: return "Protocol unreachable"; break;
+ case ICMP_UNREACH_PORT: return "Port unreachable"; break;
+ case ICMP_UNREACH_NEEDFRAG: return "Fragmentation required"; break;
+ case ICMP_UNREACH_SRCFAIL: return "Source route failed"; break;
+ case ICMP_UNREACH_NET_UNKNOWN: return "Destination network unknown"; break;
+ case ICMP_UNREACH_HOST_UNKNOWN: return "Destination host unknown"; break;
+ case ICMP_UNREACH_ISOLATED: return "Source host isolated"; break;
+ case ICMP_UNREACH_NET_PROHIB: return "Network prohibited"; break;
+ case ICMP_UNREACH_HOST_PROHIB: return "Host prohibited"; break;
+ case ICMP_UNREACH_TOSNET: return "Network unreachable for TOS"; break;
+ case ICMP_UNREACH_TOSHOST: return "Host unreachable for TOS"; break;
+ case ICMP_UNREACH_COMM_PROHIB: return "Communication prohibited"; break;
+ case ICMP_UNREACH_HOSTPRECEDENCE: return "Precedence violation"; break;
+ case ICMP_UNREACH_PRECCUTOFF: return "Precedence cutoff"; break;
+ default: return "Destination unreachable (unknown code)"; break;
+ } /* End of ICMP Code switch */
+ break;
+
+ case ICMP_SOURCEQUENCH:
+ return "Source quench";
+ break;
+
+ case ICMP_REDIRECT:
+ switch(code){
+ case ICMP_REDIRECT_NET: return "Redirect for network"; break;
+ case ICMP_REDIRECT_HOST: return "Redirect for host"; break;
+ case ICMP_REDIRECT_TOSNET: return "Redirect for TOS and network"; break;
+ case ICMP_REDIRECT_TOSHOST: return "Redirect for TOS and host"; break;
+ default: return "Redirect (unknown code)"; break;
+ }
+ break;
+
+ case ICMP_ECHO:
+ return "Echo request";
+ break;
+
+ case ICMP_ROUTERADVERT:
+ switch(code){
+ case ICMP_ROUTERADVERT_MOBILE: return "Router advertisement (Mobile Agent Only)"; break;
+ default: return "Router advertisement"; break;
+ }
+ break;
+
+ case ICMP_ROUTERSOLICIT:
+ return "Router solicitation";
+ break;
+
+ case ICMP_TIMXCEED:
+ switch(code){
+ case ICMP_TIMXCEED_INTRANS: return "TTL=0 during transit"; break;
+ case ICMP_TIMXCEED_REASS: return "Reassembly time exceeded"; break;
+ default: return "TTL exceeded (unknown code)"; break;
+ }
+ break;
+
+ case ICMP_PARAMPROB:
+ switch(code){
+ case ICMM_PARAMPROB_POINTER: return "Parameter problem (pointer indicates error)"; break;
+ case ICMP_PARAMPROB_OPTABSENT: return "Parameter problem (option missing)"; break;
+ case ICMP_PARAMPROB_BADLEN: return "Parameter problem (bad length)"; break;
+ default: return "Parameter problem (unknown code)"; break;
+ }
+ break;
+
+ case ICMP_TSTAMP:
+ return "Timestamp request";
+ break;
+
+ case ICMP_TSTAMPREPLY:
+ return "Timestamp reply";
+ break;
+
+ case ICMP_INFO:
+ return "Information request";
+ break;
+
+ case ICMP_INFOREPLY:
+ return "Information reply";
+ break;
+
+ case ICMP_MASK:
+ return "Address mask request ";
+ break;
+
+ case ICMP_MASKREPLY:
+ return "Address mask reply";
+ break;
+
+ case ICMP_TRACEROUTE:
+ return "Traceroute";
+ break;
+
+ case ICMP_DOMAINNAME:
+ return "Domain name request";
+ break;
+
+ case ICMP_DOMAINNAMEREPLY:
+ return "Domain name reply";
+ break;
+
+ case ICMP_SECURITYFAILURES:
+ return "Security failures";
+ break;
+
+ default:
+ return "Unknown ICMP type";
+ break;
+ } /* End of ICMP Type switch */
+ return "Unknown ICMP type";
+} /* End of type2string() */
+
+
+/* Returns true if the packet is an ICMPv4 error message. */
+bool ICMPv4Header::isError() const {
+ switch( this->getType() ){
+ case ICMP_UNREACH:
+ case ICMP_TIMXCEED:
+ case ICMP_PARAMPROB:
+ case ICMP_SOURCEQUENCH:
+ case ICMP_REDIRECT:
+ case ICMP_SECURITYFAILURES:
+ return true;
+ break;
+
+ default:
+ return false;
+ break;
+ }
+} /* End of isError() */
diff --git a/libnetutil/ICMPv4Header.h b/libnetutil/ICMPv4Header.h
new file mode 100644
index 0000000..01bd6c9
--- /dev/null
+++ b/libnetutil/ICMPv4Header.h
@@ -0,0 +1,530 @@
+/***************************************************************************
+ * ICMPv4Header.h -- The ICMPv4Header Class represents an ICMP version 4 *
+ * packet. It contains methods to set any header field. In general, these *
+ * methods do error checkings and byte order conversion. *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#ifndef ICMPv4HEADER_H
+#define ICMPv4HEADER_H 1
+
+#include "ICMPHeader.h"
+
+/* ICMP types and codes. These defines were originally taken from Slirp 1.0
+ * source file ip_icmp.h http://slirp.sourceforge.net/ (BSD licensed) and
+ * then, partially modified for Nping */
+#define ICMP_ECHOREPLY 0 /* Echo reply */
+#define ICMP_UNREACH 3 /* Destination unreachable: */
+#define ICMP_UNREACH_NET 0 /* --> Bad network */
+#define ICMP_UNREACH_HOST 1 /* --> Bad host */
+#define ICMP_UNREACH_PROTOCOL 2 /* --> Bad protocol */
+#define ICMP_UNREACH_PORT 3 /* --> Bad port */
+#define ICMP_UNREACH_NEEDFRAG 4 /* --> DF flag caused pkt drop */
+#define ICMP_UNREACH_SRCFAIL 5 /* --> Source route failed */
+#define ICMP_UNREACH_NET_UNKNOWN 6 /* --> Unknown network */
+#define ICMP_UNREACH_HOST_UNKNOWN 7 /* --> Unknown host */
+#define ICMP_UNREACH_ISOLATED 8 /* --> Source host isolated */
+#define ICMP_UNREACH_NET_PROHIB 9 /* --> Prohibited access */
+#define ICMP_UNREACH_HOST_PROHIB 10 /* --> Prohibited access */
+#define ICMP_UNREACH_TOSNET 11 /* --> Bad TOS for network */
+#define ICMP_UNREACH_TOSHOST 12 /* --> Bad TOS for host */
+#define ICMP_UNREACH_COMM_PROHIB 13 /* --> Prohibited communication */
+#define ICMP_UNREACH_HOSTPRECEDENCE 14 /* --> Host precedence violation */
+#define ICMP_UNREACH_PRECCUTOFF 15 /* --> Precedence cutoff */
+#define ICMP_SOURCEQUENCH 4 /* Source Quench. */
+#define ICMP_REDIRECT 5 /* Redirect: */
+#define ICMP_REDIRECT_NET 0 /* --> For the network */
+#define ICMP_REDIRECT_HOST 1 /* --> For the host */
+#define ICMP_REDIRECT_TOSNET 2 /* --> For the TOS and network */
+#define ICMP_REDIRECT_TOSHOST 3 /* --> For the TOS and host */
+#define ICMP_ECHO 8 /* Echo request */
+#define ICMP_ROUTERADVERT 9 /* Router advertisement */
+#define ICMP_ROUTERADVERT_MOBILE 16 /* Used by mobile IP agents */
+#define ICMP_ROUTERSOLICIT 10 /* Router solicitation */
+#define ICMP_TIMXCEED 11 /* Time exceeded: */
+#define ICMP_TIMXCEED_INTRANS 0 /* --> TTL==0 in transit */
+#define ICMP_TIMXCEED_REASS 1 /* --> TTL==0 in reassembly */
+#define ICMP_PARAMPROB 12 /* Parameter problem */
+#define ICMM_PARAMPROB_POINTER 0 /* --> Pointer shows the problem */
+#define ICMP_PARAMPROB_OPTABSENT 1 /* --> Option missing */
+#define ICMP_PARAMPROB_BADLEN 2 /* --> Bad datagram length */
+#define ICMP_TSTAMP 13 /* Timestamp request */
+#define ICMP_TSTAMPREPLY 14 /* Timestamp reply */
+#define ICMP_INFO 15 /* Information request */
+#define ICMP_INFOREPLY 16 /* Information reply */
+#define ICMP_MASK 17 /* Address mask request */
+#define ICMP_MASKREPLY 18 /* Address mask reply */
+#define ICMP_TRACEROUTE 30 /* Traceroute */
+#define ICMP_TRACEROUTE_SUCCESS 0 /* --> Dgram sent to next router */
+#define ICMP_TRACEROUTE_DROPPED 1 /* --> Dgram was dropped */
+#define ICMP_DOMAINNAME 37 /* Domain name request */
+#define ICMP_DOMAINNAMEREPLY 38 /* Domain name reply */
+#define ICMP_SECURITYFAILURES 40 /* Security failures */
+
+
+#define ICMP_STD_HEADER_LEN 8
+#define ICMP_MAX_PAYLOAD_LEN 1500
+#define MAX_ROUTER_ADVERT_ENTRIES (((ICMP_MAX_PAYLOAD_LEN-4)/8)-1)
+
+
+class ICMPv4Header : public ICMPHeader {
+
+ private:
+
+ /**********************************************************************/
+ /* COMMON ICMPv4 packet HEADER */
+ /**********************************************************************/
+ /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Code | Checksum |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ + Message Body +
+ | | */
+ struct nping_icmpv4_hdr {
+ u8 type; /* ICMP Message Type */
+ u8 code; /* ICMP Message Code */
+ u16 checksum; /* Checksum */
+ u8 data[ICMP_MAX_PAYLOAD_LEN];
+ }__attribute__((__packed__));
+ typedef struct nping_icmpv4_hdr nping_icmpv4_hdr_t;
+
+
+ /**********************************************************************/
+ /* ICMPv4 MESSAGE SPECIFIC HEADERS */
+ /**********************************************************************/
+
+ /* Destination Unreachable Message
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Code | Checksum |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | unused |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Internet Header + 64 bits of Original Data Datagram |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+ struct icmp4_dest_unreach_msg{
+ u32 unused;
+ //u8 original_dgram[?];
+ }__attribute__((__packed__));
+ typedef struct icmp4_dest_unreach_msg icmp4_dest_unreach_msg_t;
+
+
+ /* Time Exceeded Message
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Code | Checksum |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | unused |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Internet Header + 64 bits of Original Data Datagram |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+ struct icmp4_time_exceeded_msg{
+ u32 unused;
+ //u8 original_dgram[?];
+ }__attribute__((__packed__));
+ typedef struct icmp4_time_exceeded_msg icmp4_time_exceeded_msg_t;
+
+
+ /* Parameter Problem Message
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Code | Checksum |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Pointer | unused |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Internet Header + 64 bits of Original Data Datagram |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+
+ struct icmp4_parameter_problem_msg{
+ u8 pointer;
+ u8 unused[3];
+ //u8 original_dgram[?];
+ }__attribute__((__packed__));
+ typedef struct icmp4_parameter_problem_msg icmp4_parameter_problem_msg_t;
+
+
+ /* Source Quench Message
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Code | Checksum |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | unused |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Internet Header + 64 bits of Original Data Datagram |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+ struct icmp4_source_quench_msg{
+ u32 unused;
+ //u8 original_dgram[?];
+ }__attribute__((__packed__));
+ typedef struct icmp4_source_quench_msg icmp4_source_quench_msg_t;
+
+
+ /* Redirect Message
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Code | Checksum |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Gateway Internet Address |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Internet Header + 64 bits of Original Data Datagram |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+ struct icmp4_redirect_msg{
+ struct in_addr gateway_address;
+ //u8 original_dgram[?];
+ }__attribute__((__packed__));
+ typedef struct icmp4_redirect_msg icmp4_redirect_msg_t;
+
+
+ /* Echo Request/Reply Message
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Code | Checksum |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Identifier | Sequence Number |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Data ...
+ +-+-+-+-+- */
+ struct icmp4_echo_msg{
+ u16 identifier;
+ u16 sequence;
+ //u8 data[?];
+ }__attribute__((__packed__));
+ typedef struct icmp4_echo_msg icmp4_echo_msg_t;
+
+
+ /* Timestamp Request/Reply Message
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Code | Checksum |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Identifier | Sequence Number |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Originate Timestamp |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Receive Timestamp |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Transmit Timestamp |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+ struct icmp4_timestamp_msg{
+ u16 identifier;
+ u16 sequence;
+ u32 originate_ts;
+ u32 receive_ts;
+ u32 transmit_ts;
+ }__attribute__((__packed__));
+ typedef struct icmp4_timestamp_msg icmp4_timestamp_msg_t;
+
+
+ /* Information Request/Reply Message
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Code | Checksum |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Identifier | Sequence Number |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+ struct icmp4_information_msg{
+ u16 identifier;
+ u16 sequence;
+ }__attribute__((__packed__));
+ typedef struct icmp4_information_msg icmp4_information_msg_t;
+
+
+ /* ICMP Router Advertisement Message
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Code | Checksum |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Num Addrs |Addr Entry Size| Lifetime |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Router Address[1] |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Preference Level[1] |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Router Address[2] |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Preference Level[2] |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | . |
+ | . |
+ | . | */
+ struct icmp4_router_advert_entry{
+ struct in_addr router_addr;
+ u32 preference_level;
+ }__attribute__((__packed__));
+ typedef struct icmp4_router_advert_entry icmp4_router_advert_entry_t;
+
+ struct icmp4_router_advert_msg{
+ u8 num_addrs;
+ u8 addr_entry_size;
+ u16 lifetime;
+ icmp4_router_advert_entry_t adverts[MAX_ROUTER_ADVERT_ENTRIES];
+ }__attribute__((__packed__));
+ typedef struct icmp4_router_advert_msg icmp4_router_advert_msg_t;
+
+
+ /* ICMP Router Solicitation Message
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Code | Checksum |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Reserved |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+ struct icmp4_router_solicit_msg{
+ u32 reserved;
+ }__attribute__((__packed__));
+ typedef struct icmp4_router_solicit_msg icmp4_router_solicit_msg_t;
+
+
+ /* ICMP Security Failures Message
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Code | Checksum |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Reserved | Pointer |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ ~ Original Internet Headers + 64 bits of Payload ~
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+ struct icmp4_security_failures_msg{
+ u16 reserved;
+ u16 pointer;
+ //u8 original_headers[?];
+ }__attribute__((__packed__));
+ typedef struct icmp4_security_failures_msg icmp4_security_failures_msg_t;
+
+
+ /* ICMP Address Mask Request/Reply Message
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Code | Checksum |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Identifier | Sequence Number |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Address Mask |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+ struct icmp4_address_mask_msg{
+ u16 identifier;
+ u16 sequence;
+ struct in_addr address_mask;
+ }__attribute__((__packed__));
+ typedef struct icmp4_address_mask_msg icmp4_address_mask_msg_t;
+
+
+ /* ICMP Traceroute Message
+ +---------------+---------------+---------------+---------------+
+ | Type | Code | Checksum |
+ +---------------+---------------+---------------+---------------+
+ | ID Number | unused |
+ +---------------+---------------+---------------+---------------+
+ | Outbound Hop Count | Return Hop Count |
+ +---------------+---------------+---------------+---------------+
+ | Output Link Speed |
+ +---------------+---------------+---------------+---------------+
+ | Output Link MTU |
+ +---------------+---------------+---------------+---------------+ */
+ struct icmp4_traceroute_msg{
+ u16 id_number;
+ u16 unused;
+ u16 outbound_hop_count;
+ u16 return_hop_count;
+ u32 output_link_speed;
+ u32 output_link_mtu;
+ }__attribute__((__packed__));
+ typedef struct icmp4_traceroute_msg icmp4_traceroute_msg_t;
+
+
+ /* ICMP Domain Name Request Message
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Code | Checksum |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Identifier | Sequence Number |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+ struct icmp4_domain_name_request_msg{
+ u16 identifier;
+ u16 sequence;
+ }__attribute__((__packed__));
+ typedef struct icmp4_domain_name_request_msg icmp4_domain_name_request_msg_t;
+
+
+ /* ICMP Domain Name Reply Message
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Code | Checksum |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Identifier | Sequence Number |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Time-To-Live |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Names ...
+ +-+-+-+-+-+-+-+- */
+ struct icmp4_domain_name_reply_msg{
+ u16 identifier;
+ u16 sequence;
+ s16 ttl; /* Signed! */
+ u8 names[ICMP_MAX_PAYLOAD_LEN-8];
+ }__attribute__((__packed__));
+ typedef struct icmp4_domain_name_reply_msg icmp4_domain_name_reply_msg_t;
+
+
+ /* Main data structure */
+ nping_icmpv4_hdr_t h;
+
+ /* Helper pointers */
+ icmp4_dest_unreach_msg_t *h_du;
+ icmp4_time_exceeded_msg_t *h_te;
+ icmp4_parameter_problem_msg_t *h_pp;
+ icmp4_source_quench_msg_t *h_sq;
+ icmp4_redirect_msg_t *h_r;
+ icmp4_echo_msg_t *h_e;
+ icmp4_timestamp_msg_t *h_t;
+ icmp4_information_msg_t *h_i;
+ icmp4_router_advert_msg_t *h_ra;
+ icmp4_router_solicit_msg_t *h_rs;
+ icmp4_security_failures_msg_t *h_sf;
+ icmp4_address_mask_msg_t *h_am;
+ icmp4_traceroute_msg_t *h_trc;
+ icmp4_domain_name_request_msg_t *h_dn;
+ icmp4_domain_name_reply_msg_t *h_dnr;
+
+ /* Internal counts */
+ int routeradventries;
+ int domainnameentries;
+
+ public:
+ /* PacketElement:: Mandatory methods */
+ ICMPv4Header();
+ ~ICMPv4Header();
+ void reset();
+ u8 *getBufferPointer();
+ int storeRecvData(const u8 *buf, size_t len);
+ int protocol_id() const;
+ int validate();
+ int print(FILE *output, int detail) const;
+
+ /* ICMP Type */
+ int setType(u8 val);
+ u8 getType() const;
+ bool validateType();
+ bool validateType(u8 val);
+
+ /* ICMP Code */
+ int setCode(u8 c);
+ u8 getCode() const;
+ bool validateCode();
+ bool validateCode(u8 type, u8 code);
+
+ /* Checksum */
+ int setSum();
+ int setSum(u16 s);
+ u16 getSum() const;
+
+ /* Unused and reserved fields */
+ int setUnused(u32 val);
+ u32 getUnused() const;
+ int setReserved( u32 val );
+ u32 getReserved() const;
+
+ /* Redirect */
+ int setGatewayAddress(struct in_addr ipaddr);
+ struct in_addr getGatewayAddress() const;
+
+ /* Parameter problem */
+ int setParameterPointer(u8 val);
+ u8 getParameterPointer() const;
+
+ /* Router advertisement */
+ int setNumAddresses(u8 val);
+ u8 getNumAddresses() const;
+ int setAddrEntrySize(u8 val);
+ u8 getAddrEntrySize() const;
+ int setLifetime(u16 val);
+ u16 getLifetime() const;
+ int addRouterAdvEntry(struct in_addr raddr, u32 pref);
+ u8 *getRouterAdvEntries(int *num) const;
+ int clearRouterAdvEntries();
+
+ /* Echo/Timestamp/Mask */
+ int setIdentifier(u16 val);
+ u16 getIdentifier() const;
+ int setSequence(u16 val);
+ u16 getSequence() const;
+
+ /* Timestamp only */
+ int setOriginateTimestamp(u32 t);
+ u32 getOriginateTimestamp() const;
+ int setReceiveTimestamp(u32 t);
+ u32 getReceiveTimestamp() const;
+ int setTransmitTimestamp(u32 t);
+ u32 getTransmitTimestamp() const;
+
+ /* Mask only */
+ int setAddressMask(struct in_addr mask);
+ struct in_addr getAddressMask() const;
+
+ /* Security Failures */
+ int setSecurityPointer(u16 val);
+ u16 getSecurityPointer() const;
+
+ /* Traceroute */
+ int setIDNumber(u16 val);
+ u16 getIDNumber() const;
+ int setOutboundHopCount(u16 val);
+ u16 getOutboundHopCount() const;
+ int setReturnHopCount(u16 val);
+ u16 getReturnHopCount() const;
+ int setOutputLinkSpeed(u32 val);
+ u32 getOutputLinkSpeed() const;
+ int setOutputLinkMTU(u32 val);
+ u32 getOutputLinkMTU() const;
+
+ /* Misc */
+ int getICMPHeaderLengthFromType( u8 type ) const;
+ const char *type2string(int type, int code) const;
+ bool isError() const;
+
+
+}; /* End of class ICMPv4Header */
+
+#endif
diff --git a/libnetutil/ICMPv6Header.cc b/libnetutil/ICMPv6Header.cc
new file mode 100644
index 0000000..ee28151
--- /dev/null
+++ b/libnetutil/ICMPv6Header.cc
@@ -0,0 +1,1358 @@
+/***************************************************************************
+ * ICMPv6Header.cc -- The ICMPv6Header Class represents an ICMP version 6 *
+ * packet. It contains methods to set any header field. In general, these *
+ * methods do error checkings and byte order conversion. *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#include "ICMPv6Header.h"
+#include "IPv6Header.h"
+#include <assert.h>
+
+/******************************************************************************/
+/* CONTRUCTORS, DESTRUCTORS AND INITIALIZATION METHODS */
+/******************************************************************************/
+ICMPv6Header::ICMPv6Header() {
+ this->reset();
+} /* End of ICMPv6Header constructor */
+
+
+ICMPv6Header::~ICMPv6Header() {
+
+} /* End of ICMPv6Header destructor */
+
+
+/** Sets every attribute to its default value */
+void ICMPv6Header::reset(){
+ memset(&this->h, 0, sizeof(nping_icmpv6_hdr_t));
+ h_du = (dest_unreach_msg_t *)this->h.data;
+ h_ptb= (pkt_too_big_msg_t *)this->h.data;
+ h_te = (time_exceeded_msg_t *)this->h.data;
+ h_pp = (parameter_problem_msg_t *)this->h.data;
+ h_e = (echo_msg_t *)this->h.data;
+ h_ra = (router_advert_msg_t *)this->h.data;
+ h_rs = (router_solicit_msg_t *)this->h.data;
+ h_na = (neighbor_advert_msg_t *)this->h.data;
+ h_ns = (neighbor_solicit_msg_t *)this->h.data;
+ h_r = (redirect_msg_t *)this->h.data;
+ h_rr = (router_renumbering_msg_t *)this->h.data;
+ h_ni = (nodeinfo_msg_t *)this->h.data;
+ h_mld= (mld_msg_t *)this->h.data;
+} /* End of reset() */
+
+
+/******************************************************************************/
+/* PacketElement:: OVERWRITTEN METHODS */
+/******************************************************************************/
+
+/** @warning This method is essential for the superclass getBinaryBuffer()
+ * method to work. Do NOT change a thing unless you know what you're doing */
+u8 *ICMPv6Header::getBufferPointer(){
+ return (u8*)(&this->h);
+} /* End of getBufferPointer() */
+
+
+/** Stores supplied packet in the internal buffer so the information
+ * can be accessed using the standard get & set methods.
+ * @warning The ICMPv6Header class is able to hold a maximum of
+ * sizeof(nping_icmpv6_hdr_t) bytes. If the supplied buffer is longer than
+ * that, only the first 1508 bytes will be stored in the internal buffer.
+ * @warning Supplied len MUST be at least 8 bytes (min ICMPv6 header length).
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error */
+int ICMPv6Header::storeRecvData(const u8 *buf, size_t len){
+ if(buf==NULL || len<ICMPv6_MIN_HEADER_LEN){
+ this->length=0;
+ return OP_FAILURE;
+ }else{
+ int stored_len = MIN( sizeof(nping_icmpv6_hdr_t), len);
+ this->reset(); /* Re-init the object, just in case the caller had used it already */
+ this->length=stored_len;
+ memcpy(&(this->h), buf, stored_len);
+ }
+ return OP_SUCCESS;
+} /* End of storeRecvData() */
+
+
+/* Returns a protocol identifier. This is used by packet parsing funtions
+ * that return linked lists of PacketElement objects, to determine the protocol
+ * the object represents. */
+int ICMPv6Header::protocol_id() const {
+ return HEADER_TYPE_ICMPv6;
+} /* End of protocol_id() */
+
+
+/** Determines if the data stored in the object after an storeRecvData() call
+ * is valid and safe to use. This mainly checks the length of the data but may
+ * also test the value of certain protocol fields to ensure their correctness.
+ * @return the length, in bytes, of the header, if its found to be valid or
+ * OP_FAILURE (-1) otherwise. */
+int ICMPv6Header::validate(){
+ int should_have=this->getHeaderLengthFromType( this->getType() );
+ if(this->length < should_have){
+ return OP_FAILURE;
+ }else{
+ /* WARNING: If we extend this class to support new ICMPv6 types with
+ * a variable length header (not even sure they exist), we need to
+ * parse the objects data and return our actual size, not this size that
+ * is obtained from the type. */
+ return should_have;
+ }
+} /* End of validate() */
+
+
+/** Prints the contents of the header and calls print() on the next protocol
+ * header in the chain (if there is any).
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error. */
+int ICMPv6Header::print(FILE *output, int detail) const {
+ u8 type=this->getType();
+ u8 code=this->getCode();
+ const char *typestr=this->type2string(type, code);
+
+ fprintf(output, "ICMPv6[%s", typestr);
+ if(detail>=PRINT_DETAIL_MED)
+ fprintf(output, " (type=%u/code=%u)", type, code);
+
+ switch(type) {
+
+ case ICMPv6_UNREACH:
+ case ICMPv6_TIMXCEED:
+ if(detail>=PRINT_DETAIL_HIGH)
+ fprintf(output, " unused=%lu", (long unsigned int)this->getUnused());
+ break;
+
+ case ICMPv6_ROUTERSOLICIT:
+ if(detail>=PRINT_DETAIL_HIGH)
+ fprintf(output, " reserved=%lu", (long unsigned int)this->getReserved());
+ break;
+
+ case ICMPv6_PKTTOOBIG:
+ fprintf(output, " mtu=%lu", (long unsigned int)this->getMTU());
+ break;
+
+ case ICMPv6_PARAMPROB:
+ fprintf(output, " pointer=%lu", (long unsigned int)this->getPointer());
+ break;
+
+ case ICMPv6_ECHO:
+ case ICMPv6_ECHOREPLY:
+ fprintf(output, " id=%u seq=%u", this->getIdentifier(), this->getSequence());
+ break;
+
+ case ICMPv6_NODEINFOQUERY:
+ case ICMPv6_NODEINFORESP:
+ if(this->getNodeInfoFlags()!=0){
+ fprintf(output, " flags=");
+ if(this->getNodeInfoFlags() & ICMPv6_NI_FLAG_T)
+ fprintf(output, "T");
+ if(this->getNodeInfoFlags() & ICMPv6_NI_FLAG_A)
+ fprintf(output, "A");
+ if(this->getNodeInfoFlags() & ICMPv6_NI_FLAG_C)
+ fprintf(output, "C");
+ if(this->getNodeInfoFlags() & ICMPv6_NI_FLAG_L)
+ fprintf(output, "L");
+ if(this->getNodeInfoFlags() & ICMPv6_NI_FLAG_G)
+ fprintf(output, "G");
+ if(this->getNodeInfoFlags() & ICMPv6_NI_FLAG_S)
+ fprintf(output, "S");
+ }
+ if(detail>=PRINT_DETAIL_HIGH){
+ #ifdef WIN32
+ fprintf(output, " nonce=%I64u", (long long unsigned int)this->getNonce());
+ #else
+ fprintf(output, " nonce=%llu", (long long unsigned int)this->getNonce());
+ #endif
+ }
+ break;
+
+ default:
+ /* Print nothing */
+ break;
+ }
+
+ if(detail>=PRINT_DETAIL_HIGH)
+ fprintf(output, " csum=0x%04X", ntohs(this->getSum()));
+ fprintf(output, "]");
+ if(this->next!=NULL){
+ print_separator(output, detail);
+ next->print(output, detail);
+ }
+ return OP_SUCCESS;
+} /* End of print() */
+
+
+/******************************************************************************/
+/* PROTOCOL-SPECIFIC METHODS */
+/******************************************************************************/
+
+/******************************************************************************/
+/* ICMPv6 COMMON HEADER */
+/******************************************************************************/
+
+/** Set ICMPv6 type field */
+int ICMPv6Header::setType(u8 val){
+ this->h.type = val;
+ this->length = getHeaderLengthFromType(val);
+ return OP_SUCCESS;
+} /* End of setType() */
+
+
+/** Returns ICMPv6 type field */
+u8 ICMPv6Header::getType() const {
+ return this->h.type;
+} /* End of getType() */
+
+
+/* Returns true if the supplied ICMPv6 type is supported by this class */
+bool ICMPv6Header::validateType(u8 val){
+ switch( val ){
+ case ICMPv6_UNREACH:
+ case ICMPv6_PKTTOOBIG:
+ case ICMPv6_TIMXCEED:
+ case ICMPv6_PARAMPROB:
+ case ICMPv6_ECHO:
+ case ICMPv6_ECHOREPLY:
+ case ICMPv6_ROUTERSOLICIT:
+ case ICMPv6_ROUTERADVERT:
+ case ICMPv6_NGHBRSOLICIT:
+ case ICMPv6_NGHBRADVERT:
+ case ICMPv6_REDIRECT:
+ case ICMPv6_RTRRENUM:
+ return true;
+ break;
+
+ default:
+ return false;
+ break;
+ }
+ return false;
+} /* End of validateType() */
+
+
+bool ICMPv6Header::validateType(){
+ return validateType(this->h.type);
+} /* End of validateType() */
+
+
+/** Set ICMPv6 code field */
+int ICMPv6Header::setCode(u8 val){
+ this->h.code = val;
+ return OP_SUCCESS;
+} /* End of setCode() */
+
+
+/** Returns ICMPv6 code field */
+u8 ICMPv6Header::getCode() const {
+ return this->h.code;
+} /* End of getCode() */
+
+
+/** Given an ICMP Type and a code, determines whether the code corresponds to
+ * a RFC compliant code (eg: code 0x03 for "port unreachable" in ICMP
+ * Unreachable messages) or just some other bogus code. */
+bool ICMPv6Header::validateCode(u8 type, u8 code){
+// switch (type){
+//
+// case ICMPv6_UNREACH:
+// return (code==0);
+// break;
+//
+// case ICMPv6_PKTTOOBIG:
+// switch( code ){
+// case XXXXXXXXXXXX:
+// case YYYYYYYYYYYY:
+// case ZZZZZZZZZZZZ:
+// return true;
+// break;
+// }
+// break;
+//
+// case ICMPv6_TIMXCEED:
+//
+// break;
+//
+// case ICMPv6_PARAMPROB:
+//
+// break;
+//
+// case ICMPv6_ECHO:
+//
+// break;
+//
+// case ICMPv6_ECHOREPLY:
+//
+// break;
+//
+// case ICMPv6_ROUTERSOLICIT:
+// case ICMPv6_ROUTERADVERT:
+// case ICMPv6_NGHBRSOLICIT:
+// case ICMPv6_NGHBRADVERT:
+// case ICMPv6_REDIRECT:
+// break;
+//
+// default:
+// return false;
+// break;
+// }
+ return false;
+} /* End of validateCode() */
+
+
+/** Computes the ICMP header checksum and sets the checksum field to the right
+ * value.
+ * @warning This method requires the ICMPv6Object to be linked to an IPv6Header
+ * object, so make sure setNextElement() has been called like this:
+ *
+ * IPv6Header ip6;
+ * ICMPv6Header icmp6;
+ * [...] # Set header fields
+ * ip6.setNextElement(&icmp6);
+ * icmp6.setSum();
+ *
+ * Note that there can be a number of extension headers between the ICMPv6
+ * header and the IPv6 one, but all of them need to be linked in order for this
+ * method to traverse the list of headers and find the IPv6 source and
+ * destination address, required to compute the checksum. So things like the
+ * following are OK:
+ *
+ * IPv6Header ip6;
+ * HopByHopHeader hop;
+ * RoutingHeader rte;
+ * FragmentHeader frg;
+ * ICMPv6Header icmp6;
+ * [...] # Set whatever header fields you need
+ * ip6.setNextElement(&hop);
+ * hop.setNextElement(&rte);
+ * rte.setNextElement(&frg);
+ * frg.setNextElement(&icmp6);
+ * icmp6.setSum(); # setSum() will be able to reach the IPv6Header.
+ *
+ */
+int ICMPv6Header::setSum(){
+ PacketElement *hdr;
+ hdr=this->getPrevElement();
+ /* Traverse the list of headers backwards until we find the IPv6 header */
+ while(hdr!=NULL){
+ if (hdr->protocol_id()==HEADER_TYPE_IPv6){
+ IPv6Header *v6hdr=(IPv6Header *)hdr;
+ struct in6_addr i6src, i6dst;
+ this->h.checksum=0;
+ memcpy(i6src.s6_addr, v6hdr->getSourceAddress(), 16);
+ memcpy(i6dst.s6_addr, v6hdr->getDestinationAddress(), 16);
+ u8 *buff=(u8 *)safe_malloc(this->getLen());
+ this->dumpToBinaryBuffer(buff, this->getLen());
+ this->h.checksum=ipv6_pseudoheader_cksum(&i6src, &i6dst, this->protocol_id(), this->getLen(), buff);
+ free(buff);
+ return OP_SUCCESS;
+ }else{
+ hdr=hdr->getPrevElement();
+ }
+ }
+ return OP_FAILURE;
+} /* End of setSum() */
+
+
+/** @warning Sum is set to supplied value with NO byte ordering conversion
+ * performed.
+ * @warning If sum is supplied this way, no error checks are made. Caller is
+ * responsible for the correctness of the value. */
+int ICMPv6Header::setSum(u16 s){
+ this->h.checksum=s;
+ return OP_SUCCESS;
+} /* End of setSum() */
+
+
+/** Returns the value of the checksum field.
+ * @warning The returned value is in NETWORK byte order, no conversion is
+ * performed */
+u16 ICMPv6Header::getSum() const{
+ return this->h.checksum;
+} /* End of getSum() */
+
+
+/** @warning Supplied value MUST be in host byte order because it will get
+ * converted by this method using htonl() */
+int ICMPv6Header::setReserved(u32 val){
+ u32 aux32=0;
+ u8 *auxpnt=(u8 *)&aux32;
+
+ switch(this->h.type){
+
+ case ICMPv6_UNREACH:
+ this->h_du->unused=htonl(val);
+ break;
+
+ case ICMPv6_TIMXCEED:
+ this->h_te->unused=htonl(val);
+ break;
+
+ case ICMPv6_ROUTERSOLICIT:
+ this->h_rs->reserved=htonl(val);
+ break;
+
+ case ICMPv6_NGHBRSOLICIT:
+ this->h_ns->reserved=htonl(val);
+ break;
+
+ case ICMPv6_REDIRECT:
+ this->h_r->reserved=htonl(val);
+ break;
+
+
+ case ICMPv6_NGHBRADVERT:
+ /* The reserved field in Neighbor Advertisement messages is only
+ * 24-bits long so we convert the supplied value to big endian and
+ * use only the 24 least significant bits. */
+ aux32=htonl(val);
+ this->h_na->reserved[0]=auxpnt[1];
+ this->h_na->reserved[1]=auxpnt[2];
+ this->h_na->reserved[2]=auxpnt[3];
+ break;
+
+ case ICMPv6_RTRRENUM:
+ this->h_rr->reserved=htonl(val);
+ break;
+
+ /* Types that don't have a reserved field */
+ case ICMPv6_ROUTERADVERT:
+ case ICMPv6_ECHO:
+ case ICMPv6_ECHOREPLY:
+ case ICMPv6_PARAMPROB:
+ case ICMPv6_PKTTOOBIG:
+ default:
+ return OP_FAILURE;
+ break;
+ }
+ return OP_SUCCESS;
+} /* End of setReserved() */
+
+
+/** @warning Returned value is in host byte order */
+u32 ICMPv6Header::getReserved() const {
+ u32 aux32=0;
+ u8 *auxpnt=(u8 *)&aux32;
+
+ switch(this->h.type){
+
+ case ICMPv6_UNREACH:
+ return ntohl(this->h_du->unused);
+ break;
+
+ case ICMPv6_TIMXCEED:
+ return ntohl(this->h_te->unused);
+ break;
+
+ case ICMPv6_ROUTERSOLICIT:
+ return ntohl(this->h_rs->reserved);
+ break;
+
+ case ICMPv6_NGHBRSOLICIT:
+ return ntohl(this->h_ns->reserved);
+ break;
+
+ case ICMPv6_REDIRECT:
+ return ntohl(this->h_r->reserved);
+ break;
+
+ case ICMPv6_NGHBRADVERT:
+ /* The reserved field in Neighbor Advertisement messages is only
+ * 24-bits long so we extract the stored value and convert it to host
+ * byte order. */
+ auxpnt[0]=0;
+ auxpnt[1]=this->h_na->reserved[0];
+ auxpnt[2]=this->h_na->reserved[1];
+ auxpnt[3]=this->h_na->reserved[2];
+ return ntohl(aux32);
+ break;
+
+ case ICMPv6_RTRRENUM:
+ return ntohl(this->h_rr->reserved);
+ break;
+
+ /* Types that don't have a reserved field */
+ case ICMPv6_ROUTERADVERT:
+ case ICMPv6_ECHO:
+ case ICMPv6_ECHOREPLY:
+ case ICMPv6_PARAMPROB:
+ case ICMPv6_PKTTOOBIG:
+ default:
+ return 0;
+ break;
+ }
+} /* End of setReserved() */
+
+int ICMPv6Header::setUnused(u32 val){
+ return this->setReserved(val);
+} /* End of setUnused() */
+
+
+u32 ICMPv6Header::getUnused() const {
+ return this->getReserved();
+} /* End of getUnused() */
+
+
+int ICMPv6Header::setFlags(u8 val){
+ switch(this->h.type){
+
+ case ICMPv6_ROUTERADVERT:
+ this->h_ra->autoconfig_flags=val;
+ break;
+
+ case ICMPv6_NGHBRADVERT:
+ this->h_na->flags=val;
+ break;
+
+ case ICMPv6_RTRRENUM:
+ this->h_rr->flags=val;
+ break;
+
+ case ICMPv6_NODEINFOQUERY:
+ case ICMPv6_NODEINFORESP:
+ netutil_fatal("setFlags() cannot be used in NI, use setNodeInfoFlags() instead\n");
+ break;
+
+ /* Types that don't have a flags field */
+ case ICMPv6_TIMXCEED:
+ case ICMPv6_UNREACH:
+ case ICMPv6_ROUTERSOLICIT:
+ case ICMPv6_NGHBRSOLICIT:
+ case ICMPv6_REDIRECT:
+ case ICMPv6_ECHO:
+ case ICMPv6_ECHOREPLY:
+ case ICMPv6_PARAMPROB:
+ case ICMPv6_PKTTOOBIG:
+ default:
+ return OP_FAILURE;
+ break;
+ }
+ return OP_SUCCESS;
+} /* End of setFlags() */
+
+
+u8 ICMPv6Header::getFlags() const {
+ switch(this->h.type){
+
+ case ICMPv6_ROUTERADVERT:
+ return this->h_ra->autoconfig_flags;
+ break;
+
+ case ICMPv6_NGHBRADVERT:
+ return this->h_na->flags;
+ break;
+
+ case ICMPv6_RTRRENUM:
+ return this->h_rr->flags;
+ break;
+
+ case ICMPv6_NODEINFOQUERY:
+ case ICMPv6_NODEINFORESP:
+ netutil_fatal("getFlags() cannot be used in NI, use getNodeInfoFlags() instead\n");
+ return 0;
+ break;
+
+ /* Types that don't have a flags field */
+ case ICMPv6_TIMXCEED:
+ case ICMPv6_UNREACH:
+ case ICMPv6_ROUTERSOLICIT:
+ case ICMPv6_NGHBRSOLICIT:
+ case ICMPv6_REDIRECT:
+ case ICMPv6_ECHO:
+ case ICMPv6_ECHOREPLY:
+ case ICMPv6_PARAMPROB:
+ case ICMPv6_PKTTOOBIG:
+ default:
+ return 0;
+ break;
+ }
+} /* End of getFlags() */
+
+/******************************************************************************/
+/* ICMPv6 DESTINATION UNREACHABLE */
+/******************************************************************************/
+
+/******************************************************************************/
+/* ICMPv6 PACKET TOO BIG */
+/******************************************************************************/
+int ICMPv6Header::setMTU(u32 mtu){
+ this->h_ptb->mtu=htonl(mtu);
+ return OP_SUCCESS;
+} /* End of setMTU() */
+
+u32 ICMPv6Header::getMTU() const {
+ return ntohl(this->h_ptb->mtu);
+} /* End of getMTU() */
+
+/******************************************************************************/
+/* ICMPv6 TIME EXCEEDED */
+/******************************************************************************/
+
+/******************************************************************************/
+/* ICMPv6 PARAMETER PROBLEM */
+/******************************************************************************/
+int ICMPv6Header::setPointer(u32 pnt){
+ this->h_pp->pointer=htonl(pnt);
+ return OP_SUCCESS;
+} /* End of setPointer() */
+
+
+u32 ICMPv6Header::getPointer() const {
+ return ntohl(this->h_pp->pointer);
+} /* End of getPointer() */
+
+/******************************************************************************/
+/* ICMPv6 ECHO */
+/******************************************************************************/
+int ICMPv6Header::setIdentifier(u16 val){
+ this->h_e->id=htons(val);
+ return OP_SUCCESS;
+} /* End of setIdentifier() */
+
+
+u16 ICMPv6Header::getIdentifier() const{
+ return ntohs(this->h_e->id);
+} /* End of getIdentifier() */
+
+
+int ICMPv6Header::setSequence(u16 val){
+ switch(this->h.type){
+ case ICMPv6_RTRRENUM:
+ this->h_rr->seq=htonl( ((u32)val) );
+ break;
+
+ case ICMPv6_ECHO:
+ case ICMPv6_ECHOREPLY:
+ this->h_e->seq=htons(val);
+ break;
+
+ default:
+ return OP_FAILURE;
+ break;
+ }
+ return OP_SUCCESS;
+} /* End of setSequence() */
+
+
+int ICMPv6Header::setSequence(u32 val){
+ switch(this->h.type){
+ case ICMPv6_RTRRENUM:
+ this->h_rr->seq=htonl(val);
+ break;
+
+ case ICMPv6_ECHO:
+ case ICMPv6_ECHOREPLY:
+ this->h_e->seq=htons( ((u16)val) );
+ break;
+
+ default:
+ return OP_FAILURE;
+ break;
+ }
+ return OP_SUCCESS;
+} /* End of setSequence() */
+
+
+u32 ICMPv6Header::getSequence() const{
+ switch(this->h.type){
+ case ICMPv6_RTRRENUM:
+ return ntohl(this->h_rr->seq);
+ break;
+
+ case ICMPv6_ECHO:
+ case ICMPv6_ECHOREPLY:
+ return (u32)ntohs(this->h_e->seq);
+ break;
+ }
+ return 0;
+} /* End of getSequence() */
+
+
+/******************************************************************************/
+/* ICMPv6 ROUTER ADVERTISEMENT */
+/******************************************************************************/
+int ICMPv6Header::setCurrentHopLimit(u8 val){
+ this->h_ra->current_hop_limit=val;
+ return OP_SUCCESS;
+} /* End of setCurrentHopLimit() */
+
+u8 ICMPv6Header::getCurrentHopLimit() const {
+ return this->h_ra->current_hop_limit;
+} /* End of getCurrentHopLimit() */
+
+int ICMPv6Header::setRouterLifetime(u16 val){
+ this->h_ra->router_lifetime=val;
+ return OP_SUCCESS;
+} /* End of setRouterLifetime() */
+
+u16 ICMPv6Header::getRouterLifetime() const {
+ return this->h_ra->router_lifetime;
+} /* End of getRouterLifetime() */
+
+int ICMPv6Header::setReachableTime(u32 val){
+ this->h_ra->reachable_time=val;
+ return OP_SUCCESS;
+} /* End of setReachableTime() */
+
+u32 ICMPv6Header::getReachableTime() const {
+ return this->h_ra->reachable_time;
+} /* End of getReachableTime() */
+
+int ICMPv6Header::setRetransmissionTimer(u32 val){
+ this->h_ra->retransmission_timer=val;
+ return OP_SUCCESS;
+} /* End of setRetransmissionTimer() */
+
+u32 ICMPv6Header::getRetransmissionTimer() const {
+ return this->h_ra->retransmission_timer;
+} /* End of getRetransmissionTimer() */
+
+/******************************************************************************/
+/* ICMPv6 ROUTER SOLICITATION */
+/******************************************************************************/
+
+/******************************************************************************/
+/* ICMPv6 NEIGHBOR ADVERTISEMENT */
+/******************************************************************************/
+
+int ICMPv6Header::setTargetAddress(struct in6_addr addr){
+ switch(this->h.type){
+ case ICMPv6_NGHBRADVERT:
+ memcpy(this->h_na->target_address, addr.s6_addr, 16);
+ break;
+
+ case ICMPv6_NGHBRSOLICIT:
+ memcpy(this->h_ns->target_address, addr.s6_addr, 16);
+ break;
+
+ case ICMPv6_REDIRECT:
+ memcpy(this->h_r->target_address, addr.s6_addr, 16);
+ break;
+
+ default:
+ return OP_FAILURE;
+ break;
+ }
+ return OP_SUCCESS;
+} /* End of setTargetAddress() */
+
+
+struct in6_addr ICMPv6Header::getTargetAddress() const {
+ struct in6_addr addr;
+ memset(&addr, 0, sizeof(struct in6_addr));
+
+ switch(this->h.type){
+ case ICMPv6_NGHBRADVERT:
+ memcpy(addr.s6_addr, this->h_na->target_address, 16);
+ break;
+
+ case ICMPv6_NGHBRSOLICIT:
+ memcpy(addr.s6_addr, this->h_ns->target_address, 16);
+ break;
+
+ case ICMPv6_REDIRECT:
+ memcpy(addr.s6_addr, this->h_r->target_address, 16);
+ break;
+ }
+ return addr;
+} /* End of setTargetAddress() */
+
+
+int ICMPv6Header::setDestinationAddress(struct in6_addr addr){
+ switch(this->h.type){
+ case ICMPv6_REDIRECT:
+ memcpy(this->h_r->destination_address, addr.s6_addr, 16);
+ break;
+
+ default:
+ return OP_FAILURE;
+ break;
+ }
+ return OP_SUCCESS;
+} /* End of setDestinationAddress() */
+
+
+struct in6_addr ICMPv6Header::getDestinationAddress() const {
+ struct in6_addr addr;
+ memset(&addr, 0, sizeof(struct in6_addr));
+
+ switch(this->h.type){
+ case ICMPv6_REDIRECT:
+ memcpy(addr.s6_addr, this->h_r->destination_address, 16);
+ break;
+ }
+ return addr;
+} /* End of setTargetAddress() */
+
+
+/******************************************************************************/
+/* ICMPv6 NEIGHBOR SOLICITATION */
+/******************************************************************************/
+
+/******************************************************************************/
+/* ICMPv6 REDIRECT */
+/******************************************************************************/
+
+/******************************************************************************/
+/* ICMPv6 ROUTER RENUMBERING */
+/******************************************************************************/
+int ICMPv6Header::setSegmentNumber(u8 val){
+ this->h_rr->segment_number=val;
+ return OP_SUCCESS;
+} /* End of setSegmentNumber() */
+
+u8 ICMPv6Header::getSegmentNumber() const {
+ return this->h_rr->segment_number;
+} /* End of getSegmentNumber() */
+
+int ICMPv6Header::setMaxDelay(u16 val){
+ switch(this->h.type){
+ case ICMPv6_RTRRENUM:
+ this->h_rr->max_delay=htons(val);
+ return OP_SUCCESS;
+ break;
+
+ case ICMPv6_GRPMEMBQUERY:
+ case ICMPv6_GRPMEMBREP:
+ case ICMPv6_GRPMEMBRED:
+ this->h_mld->max_response_delay=htons(val);
+ return OP_SUCCESS;
+ break;
+
+ default:
+ return OP_FAILURE;
+ break;
+ }
+} /* End of setMaxDelay() */
+
+
+u16 ICMPv6Header::getMaxDelay() const {
+ switch(this->h.type){
+ case ICMPv6_RTRRENUM:
+ return ntohs(this->h_rr->max_delay);
+ break;
+
+ case ICMPv6_GRPMEMBQUERY:
+ case ICMPv6_GRPMEMBREP:
+ case ICMPv6_GRPMEMBRED:
+ return ntohs(this->h_mld->max_response_delay);
+ break;
+
+ default:
+ return 0;
+ break;
+ }
+} /* End of getMaxDelay() */
+
+
+
+/******************************************************************************/
+/* ICMPv6 NODE INFORMATION QUERIES */
+/******************************************************************************/
+/** Set NI Qtype */
+int ICMPv6Header::setQtype(u16 val){
+ this->h_ni->qtype = htons(val);
+ return OP_SUCCESS;
+} /* End of setQtype() */
+
+
+/** Returns NI Qtype */
+u16 ICMPv6Header::getQtype() const {
+ return ntohs(this->h_ni->qtype);
+} /* End of getQtype() */
+
+
+/** Set NI Flags */
+int ICMPv6Header::setNodeInfoFlags(u16 val){
+ this->h_ni->flags = htons(val);
+ return OP_SUCCESS;
+} /* End of setNodeInfoFlags() */
+
+
+/** Returns NI Flags */
+u16 ICMPv6Header::getNodeInfoFlags() const {
+ return ntohs(this->h_ni->flags);
+} /* End of getNodeInfoFlags() */
+
+
+/* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | unused |G|S|L|C|A|T|
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+
+/* Set NI Flag G */
+int ICMPv6Header::setG(bool flag_value){
+ u16 current_flags = this->getNodeInfoFlags();
+ if(flag_value)
+ current_flags = current_flags | 0x0020;
+ else
+ current_flags = current_flags & ~0x0020;
+ this->setNodeInfoFlags(current_flags);
+ return OP_SUCCESS;
+} /* End of setG() */
+
+
+/* Get NI Flag G */
+bool ICMPv6Header::getG() const {
+ return this->getNodeInfoFlags() & 0x0020;
+} /* End of getG() */
+
+
+/* Set NI Flag S */
+int ICMPv6Header::setS(bool flag_value){
+ u16 current_flags = this->getNodeInfoFlags();
+ if(flag_value)
+ current_flags = current_flags | 0x0010;
+ else
+ current_flags = current_flags & ~0x0010;
+ this->setNodeInfoFlags(current_flags);
+ return OP_SUCCESS;
+} /* End of setS() */
+
+
+/* Get NI Flag S */
+bool ICMPv6Header::getS() const {
+ return this->getNodeInfoFlags() & 0x0010;
+} /* End of getS() */
+
+
+/* Set NI Flag L */
+int ICMPv6Header::setL(bool flag_value){
+ u16 current_flags = this->getNodeInfoFlags();
+ if(flag_value)
+ current_flags = current_flags | 0x0008;
+ else
+ current_flags = current_flags & ~0x0008;
+ this->setNodeInfoFlags(current_flags);
+ return OP_SUCCESS;
+} /* End of setL() */
+
+
+/* Get NI Flag L */
+bool ICMPv6Header::getL() const {
+ return this->getNodeInfoFlags() & 0x0008;
+} /* End of getL() */
+
+
+/* Set NI Flag C */
+int ICMPv6Header::setC(bool flag_value){
+ u16 current_flags = this->getNodeInfoFlags();
+ if(flag_value)
+ current_flags = current_flags | 0x0004;
+ else
+ current_flags = current_flags & ~0x0004;
+ this->setNodeInfoFlags(current_flags);
+ return OP_SUCCESS;
+} /* End of setC() */
+
+
+/* Get NI Flag C */
+bool ICMPv6Header::getC() const {
+ return this->getNodeInfoFlags() & 0x0004;
+} /* End of getC() */
+
+
+/* Set NI Flag A */
+int ICMPv6Header::setA(bool flag_value){
+ u16 current_flags = this->getNodeInfoFlags();
+ if(flag_value)
+ current_flags = current_flags | 0x0002;
+ else
+ current_flags = current_flags & ~0x0002;
+ this->setNodeInfoFlags(current_flags);
+ return OP_SUCCESS;
+} /* End of setA() */
+
+
+/* Get NI Flag A */
+bool ICMPv6Header::getA() const {
+ return this->getNodeInfoFlags() & 0x0002;
+} /* End of getA() */
+
+
+/* Set NI Flag T */
+int ICMPv6Header::setT(bool flag_value){
+ u16 current_flags = this->getNodeInfoFlags();
+ if(flag_value)
+ current_flags = current_flags | 0x0001;
+ else
+ current_flags = current_flags & ~0x0001;
+ this->setNodeInfoFlags(current_flags);
+ return OP_SUCCESS;
+} /* End of setT() */
+
+
+/* Get NI Flag T */
+bool ICMPv6Header::getT() const {
+ return this->getNodeInfoFlags() & 0x0001;
+} /* End of getT() */
+
+
+/* Set the Nonce field. */
+int ICMPv6Header::setNonce(u64 nonce_value){
+ this->h_ni->nonce=nonce_value;
+ return OP_SUCCESS;
+} /* End of setNonce() */
+
+
+/* Set the Nonce field.
+ * @warning: Supplied buffer must contain 8 bytes. */
+int ICMPv6Header::setNonce(const u8 *nonce){
+ if(nonce==NULL)
+ return OP_FAILURE;
+ memcpy(&(this->h_ni->nonce), nonce, NI_NONCE_LEN);
+ return OP_SUCCESS;
+} /* End of setNonce() */
+
+
+/* Returns a pointer to the nonce buffer.
+ * @warning: The returned pointer is guaranteed to point to an 8-byte buffer.
+ * However, what comes after the 8th byte is unspecified. */
+u64 ICMPv6Header::getNonce() const {
+ return this->h_ni->nonce;
+} /* End of getNonce() */
+
+
+/******************************************************************************/
+/* MULTICAST LISTENER DISCOVERY */
+/******************************************************************************/
+
+int ICMPv6Header::setMulticastAddress(struct in6_addr addr){
+ switch(this->h.type){
+ case ICMPv6_GRPMEMBQUERY:
+ case ICMPv6_GRPMEMBREP:
+ case ICMPv6_GRPMEMBRED:
+ memcpy(this->h_mld->mcast_address, addr.s6_addr, 16);
+ break;
+
+ default:
+ return OP_FAILURE;
+ break;
+ }
+
+ return OP_SUCCESS;
+} /* End of setMulticastAddress() */
+
+
+struct in6_addr ICMPv6Header::getMulticastAddress() const {
+ struct in6_addr addr;
+ memset(&addr, 0, sizeof(struct in6_addr));
+
+ switch(this->h.type){
+ case ICMPv6_GRPMEMBQUERY:
+ case ICMPv6_GRPMEMBREP:
+ case ICMPv6_GRPMEMBRED:
+ memcpy(addr.s6_addr, this->h_mld->mcast_address, 16);
+ break;
+ }
+ return addr;
+} /* End of setMulticastAddress() */
+
+
+/******************************************************************************/
+/* MISCELLANEOUS STUFF */
+/******************************************************************************/
+
+/** Returns the standard ICMPv6 header length for the supplied ICMP message type.
+ * @warning Return value corresponds strictly to the ICMP header, this is,
+ * the minimum length of the ICMP header, variable length payload is never
+ * included. For example, an ICMPv6 Redirect has a fixed header of 40
+ * bytes but then the packet may contain ICMPv6 options. We only return 40
+ * because we don't know in advance the total number of bytes for the message.
+ * Same applies to the rest of types. */
+int ICMPv6Header::getHeaderLengthFromType(u8 type) const {
+
+ switch( type ){
+ case ICMPv6_UNREACH:
+ return ICMPv6_UNREACH_LEN;
+ break;
+ case ICMPv6_PKTTOOBIG:
+ return ICMPv6_PKTTOOBIG_LEN;
+ break;
+
+ case ICMPv6_TIMXCEED:
+ return ICMPv6_TIMXCEED_LEN;
+ break;
+
+ case ICMPv6_PARAMPROB:
+ return ICMPv6_PARAMPROB_LEN;
+ break;
+
+ case ICMPv6_ECHO:
+ return ICMPv6_ECHO_LEN;
+ break;
+
+ case ICMPv6_ECHOREPLY:
+ return ICMPv6_ECHOREPLY_LEN;
+ break;
+
+ case ICMPv6_ROUTERSOLICIT:
+ return ICMPv6_ROUTERSOLICIT_LEN;
+ break;
+
+ case ICMPv6_ROUTERADVERT:
+ return ICMPv6_ROUTERADVERT_LEN;
+ break;
+
+ case ICMPv6_NGHBRSOLICIT:
+ return ICMPv6_NGHBRSOLICIT_LEN;
+ break;
+
+ case ICMPv6_NGHBRADVERT:
+ return ICMPv6_NGHBRADVERT_LEN;
+ break;
+
+ case ICMPv6_REDIRECT:
+ return ICMPv6_REDIRECT_LEN;
+ break;
+
+ case ICMPv6_RTRRENUM:
+ return ICMPv6_RTRRENUM_LEN;
+ break;
+
+ case ICMPv6_NODEINFOQUERY:
+ case ICMPv6_NODEINFORESP:
+ return ICMPv6_NODEINFO_LEN;
+ break;
+
+ case ICMPv6_GRPMEMBQUERY:
+ case ICMPv6_GRPMEMBREP:
+ case ICMPv6_GRPMEMBRED:
+ return ICMPv6_MLD_LEN;
+ break;
+
+ /* Packets with non RFC-Compliant types will be represented as an 8-byte
+ * ICMPv6 header, just like the types that don't include additional info */
+ default:
+ return ICMPv6_MIN_HEADER_LEN;
+ break;
+ }
+} /* End of getHeaderLengthFromType() */
+
+
+/* Returns true if the packet is an ICMPv6 error message. */
+bool ICMPv6Header::isError() const {
+ switch( this->getType() ){
+ case ICMPv6_UNREACH:
+ case ICMPv6_PKTTOOBIG:
+ case ICMPv6_TIMXCEED:
+ case ICMPv6_PARAMPROB:
+ return true;
+ break;
+
+ default:
+ return false;
+ break;
+ }
+} /* End of isError() */
+
+
+const char *ICMPv6Header::type2string(int type, int code) const {
+ switch(type) {
+
+ case ICMPv6_UNREACH:
+ switch(code) {
+ case ICMPv6_UNREACH_NO_ROUTE: return "Network unreachable"; break;
+ case ICMPv6_UNREACH_PROHIBITED: return "Comm prohibited"; break;
+ case ICMPv6_UNREACH_BEYOND_SCOPE: return "Beyond scope"; break;
+ case ICMPv6_UNREACH_ADDR_UNREACH: return "Address unreachable"; break;
+ case ICMPv6_UNREACH_PORT_UNREACH: return "Port unreachable"; break;
+ case ICMPv6_UNREACH_SRC_ADDR_FAILED: return "Source address failed"; break;
+ case ICMPv6_UNREACH_REJECT_ROUTE: return "Reject route"; break;
+ default: return "Destination unreachable (unknown code)"; break;
+ }
+ break;
+
+ case ICMPv6_PKTTOOBIG:
+ return "Packet too big";
+ break;
+
+ case ICMPv6_TIMXCEED:
+ switch(code){
+ case ICMPv6_TIMXCEED_HOP_EXCEEDED: return "HopLimit=0 in transit"; break;
+ case ICMPv6_TIMXCEED_REASS_EXCEEDED: return "Reassembly time exceeded"; break;
+ default: return "Time exceeded (unknown code)"; break;
+ }
+ break;
+
+ case ICMPv6_PARAMPROB:
+ switch(code){
+ case ICMPv6_PARAMPROB_FIELD: return "Parameter problem (bad field)"; break;
+ case ICMPv6_PARAMPROB_NEXT_HDR: return "Parameter problem (next header unknown)"; break;
+ case ICMPv6_PARAMPROB_OPTION: return "Parameter problem (bad option)"; break;
+ default: return "Parameter problem (unknown code)"; break;
+ }
+ break;
+
+ case ICMPv6_ECHO:
+ return "Echo request";
+ break;
+ case ICMPv6_ECHOREPLY:
+ return "Echo reply";
+ break;
+ case ICMPv6_GRPMEMBQUERY:
+ return "Group membership query";
+ break;
+ case ICMPv6_GRPMEMBREP:
+ return "Group membership report";
+ break;
+ case ICMPv6_GRPMEMBRED:
+ return "Group membership reduction";
+ break;
+ case ICMPv6_ROUTERSOLICIT:
+ return "Router sol";
+ break;
+ case ICMPv6_ROUTERADVERT:
+ return "Router advert";
+ break;
+ case ICMPv6_NGHBRSOLICIT:
+ return "Neighbor sol";
+ break;
+ case ICMPv6_NGHBRADVERT:
+ return "Neighbor advert";
+ break;
+ case ICMPv6_REDIRECT:
+ return "Redirect";
+ break;
+ case ICMPv6_RTRRENUM:
+ switch(code){
+ case ICMPv6_RTRRENUM_COMMAND: return "Renumbering command"; break;
+ case ICMPv6_RTRRENUM_RESULT: return "Renumbering result"; break;
+ case ICMPv6_RTRRENUM_SEQ_RESET: return "Renumbering reset"; break;
+ default: return "Router Renumbering (unknown code)"; break;
+ }
+ break;
+ case ICMPv6_NODEINFOQUERY:
+ switch(code){
+ case ICMPv6_NODEINFOQUERY_IPv6ADDR: return "Node info query (IPv6 addr)"; break;
+ case ICMPv6_NODEINFOQUERY_NAME: return "Node info query (name)"; break;
+ case ICMPv6_NODEINFOQUERY_IPv4ADDR: return "Node info query (IPv4 addr)"; break;
+ default: return "Node info query (unknown code)"; break;
+ }
+ break;
+
+ case ICMPv6_NODEINFORESP:
+ switch(code){
+ case ICMPv6_NODEINFORESP_SUCCESS: return "Node info reply (success)"; break;
+ case ICMPv6_NODEINFORESP_REFUSED: return "Node info reply (refused)"; break;
+ case ICMPv6_NODEINFORESP_UNKNOWN: return "Node info reply (qtype unknown)"; break;
+ default: return "Node info reply (unknown code)"; break;
+ }
+ break;
+
+ case ICMPv6_INVNGHBRSOLICIT:
+ return "Inverse neighbor sol";
+ break;
+
+ case ICMPv6_INVNGHBRADVERT:
+ return "Inverse neighbor advert";
+ break;
+
+ case ICMPv6_MLDV2:
+ return "MLDv2 report";
+ break;
+
+ case ICMPv6_AGENTDISCOVREQ:
+ return "Home agent request";
+ break;
+
+ case ICMPv6_AGENTDISCOVREPLY:
+ return "Home agent reply";
+ break;
+
+ case ICMPv6_MOBPREFIXSOLICIT:
+ return "Prefix sol";
+ break;
+
+ case ICMPv6_MOBPREFIXADVERT:
+ return "Prefix advert";
+ break;
+
+ case ICMPv6_CERTPATHSOLICIT:
+ return "Cert path sol";
+ break;
+
+ case ICMPv6_CERTPATHADVERT:
+ return "Cert path advert";
+ break;
+
+ case ICMPv6_EXPMOBILITY:
+ return "Experimental mobility";
+ break;
+
+ case ICMPv6_MRDADVERT:
+ return "Multicast router advert";
+ break;
+
+ case ICMPv6_MRDSOLICIT:
+ return "Multicast router sol";
+ break;
+
+ case ICMPv6_MRDTERMINATE:
+ return "Multicast router term";
+ break;
+
+ case ICMPv6_FMIPV6:
+ return "FMIPv6";
+ break;
+
+ default:
+ return "Unknown ICMPv6 type";
+ break;
+ } /* End of ICMP Type switch */
+ return "Unknown ICMPv6 type";
+} /* End of type2string() */
+
+
+
diff --git a/libnetutil/ICMPv6Header.h b/libnetutil/ICMPv6Header.h
new file mode 100644
index 0000000..f496caa
--- /dev/null
+++ b/libnetutil/ICMPv6Header.h
@@ -0,0 +1,669 @@
+/***************************************************************************
+ * ICMPv6Header.h -- The ICMPv6Header Class represents an ICMP version 6 *
+ * packet. It contains methods to set any header field. In general, these *
+ * methods do error checkings and byte order conversion. *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#ifndef ICMPv6HEADER_H
+#define ICMPv6HEADER_H 1
+
+#include "ICMPHeader.h"
+
+/******************************************************************************/
+/* IMPORTANT INFORMATION ON HOW TO USE THIS CLASS. */
+/******************************************************************************/
+/* This class represents an ICMPv6 messages. ICMPv6 messages may be of
+ * different types. Each type has its own header and possibly a variable
+ * length data field. Information messages have an "invoking packet" field
+ * which is the IP packet that triggered the emission of the ICMPv6 message.
+ * Other messages may contain a "data" field, like echo requests an replies.
+ * Some others may contain ICMPv6 Options.
+ *
+ * So the thing is, that this class only represents fixed-length ICMPv6
+ * headers and does NOT offer storage for ANY variable-length field. This
+ * fields may be added to the ICMPv6 header using instances of the RawData
+ * class the ICMPv6Option class or even the IPv6Header class (in those cases
+ * where a whole packet is appendend to the ICMPv6 message).
+ *
+ * So, how does this work? Let's look at some examples.
+ *
+ * 1. Imagine we need to build an ICMP echo request message that includes some
+ * arbitrary data to be echoed. We could do the following:
+ *
+ * u8 final_packet[1024]; <-- Buffer to store the resulting packet
+ * u32 final_packet_len=0; <-- Length of the resulting packet
+ * ICMPv6Header header; <-- The ICMPv6 fixed-length part
+ * RawData data; <-- The data to append to the echo message
+ *
+ * header.setType(ICMPv6_ECHO); <-- Set ICMPv6 type to "Echo request"
+ * data.store("1234567890"); <-- Store data we need to send.
+ * header.setNextElement(&data); <-- Tell ICMPv6Header what's after it
+ * header.setSum(); <-- Compute the checksum
+ *
+ * final_packet_len=header.dumpToBinaryBuffer(fina_packet, 1024);
+ * send_packet(final_packet, final_packet_len)
+ *
+ * 2. If we are sending a parameter problem message and we need to include the
+ * invoking datagram, we can call setNextElement() passing an IPv6Header
+ * pointer.
+ *
+ * u8 final_packet[1024]; <-- Buffer to store the resulting packet
+ * u32 final_packet_len=0; <-- Length of the resulting packet
+ * ICMPv6Header header; <-- The ICMPv6 fixed-length part
+ * IPv6Header ipv6; <-- The IPv6 packet that triggered ICMPv6
+ *
+ * header.setType(ICMPv6_PARAMPROB); <-- Set ICMPv6 type to "Param Problem"
+ * header.setNextElement(&ipv6); <-- Tell ICMPv6Header what's after it
+ * header.setSum(); <-- Compute the checksum
+ *
+ * Note that here we don't show how the ipv6 object is set.
+ *
+ * 3. If we are sending a router solicitation message, we'll call
+ * setNextElement() passing an IPv6Options Pointer.
+ *
+ * u8 final_packet[1024]; <-- Buffer to store the resulting packet
+ * u32 final_packet_len=0; <-- Length of the resulting packet
+ * ICMPv6Header header; <-- The ICMPv6 fixed-length part
+ * IPv6Options opts1; <-- IPv6 options
+ * IPv6Options opts2; <-- IPv6 options
+ * IPv6Options opts3; <-- IPv6 options
+ *
+ * header.setType(ICMPv6_ROUTERSOLICIT); <-- Set ICMPv6 type
+ *
+ * opts1.setXXXX(); <-- Set up the options
+ * .
+ * .
+ * .
+ * opts3.setYYYY();
+ *
+ * opts2.setNextElement(&opts3); <-- Link the options
+ * opts1.setNextElement(&opts2);
+ * header.setNextElement(&opts1);
+ * header.setNextElement(&ipv6); <-- Link the first option to the ICMPv6
+ * header.setSum(); <-- Compute the checksum
+ *
+ * And so on...
+ *
+ */
+
+
+/* Packet header diagrams included in this file have been taken from the
+ * following IETF RFC documents: RFC 4443, RFC 2461, RFC 2894 */
+
+/* ICMP types and codes.
+ * The following types and codes have been defined by IANA. A complete list
+ * may be found at http://www.iana.org/assignments/icmpv6-parameters
+ *
+ * Definitions on the first level of indentation are ICMPv6 Types.
+ * Definitions on the second level of indentation (values enclosed in
+ * parenthesis) are ICMPv6 Codes */
+#define ICMPv6_UNREACH 1 /* Destination unreachable [RFC 2463, 4443] */
+#define ICMPv6_UNREACH_NO_ROUTE (0) /* --> No route to destination */
+#define ICMPv6_UNREACH_PROHIBITED (1) /* --> Communication administratively prohibited */
+#define ICMPv6_UNREACH_BEYOND_SCOPE (2) /* --> Beyond scope of source address [RFC4443] */
+#define ICMPv6_UNREACH_ADDR_UNREACH (3) /* --> Address unreachable */
+#define ICMPv6_UNREACH_PORT_UNREACH (4) /* --> Port unreachable */
+#define ICMPv6_UNREACH_SRC_ADDR_FAILED (5) /* --> Source address failed ingress/egress policy [RFC4443] */
+#define ICMPv6_UNREACH_REJECT_ROUTE (6) /* --> Reject route to destination [RFC4443] */
+#define ICMPv6_PKTTOOBIG 2 /* Packet too big [RFC 2463, 4443] */
+#define ICMPv6_TIMXCEED 3 /* Time exceeded [RFC 2463, 4443] */
+#define ICMPv6_TIMXCEED_HOP_EXCEEDED (0) /* --> Hop limit exceeded in transit */
+#define ICMPv6_TIMXCEED_REASS_EXCEEDED (1) /* --> Fragment reassembly time exceeded */
+#define ICMPv6_PARAMPROB 4 /* Parameter problem [RFC 2463, 4443] */
+#define ICMPv6_PARAMPROB_FIELD (0) /* --> Erroneous header field encountered */
+#define ICMPv6_PARAMPROB_NEXT_HDR (1) /* --> Unrecognized Next Header type encountered */
+#define ICMPv6_PARAMPROB_OPTION (2) /* --> Unrecognized IPv6 option encountered */
+#define ICMPv6_ECHO 128 /* Echo request [RFC 2463, 4443] */
+#define ICMPv6_ECHOREPLY 129 /* Echo reply [RFC 2463, 4443] */
+#define ICMPv6_GRPMEMBQUERY 130 /* Group Membership Query [RFC 2710] */
+#define ICMPv6_GRPMEMBREP 131 /* Group Membership Report [RFC 2710] */
+#define ICMPv6_GRPMEMBRED 132 /* Group Membership Reduction [RFC 2710] */
+#define ICMPv6_ROUTERSOLICIT 133 /* Router Solicitation [RFC 2461] */
+#define ICMPv6_ROUTERADVERT 134 /* Router Advertisement [RFC 2461] */
+#define ICMPv6_NGHBRSOLICIT 135 /* Neighbor Solicitation [RFC 2461] */
+#define ICMPv6_NGHBRADVERT 136 /* Neighbor Advertisement [RFC 2461] */
+#define ICMPv6_REDIRECT 137 /* Redirect [RFC 2461] */
+#define ICMPv6_RTRRENUM 138 /* Router Renumbering [RFC 2894] */
+#define ICMPv6_RTRRENUM_COMMAND (0) /* --> Router Renumbering Command */
+#define ICMPv6_RTRRENUM_RESULT (1) /* --> Router Renumbering Result */
+#define ICMPv6_RTRRENUM_SEQ_RESET (255) /* Sequence Number Reset */
+#define ICMPv6_NODEINFOQUERY 139 /* ICMP Node Information Query [RFC 4620] */
+#define ICMPv6_NODEINFOQUERY_IPv6ADDR (0) /* --> The Data field contains an IPv6 address */
+#define ICMPv6_NODEINFOQUERY_NAME (1) /* --> The Data field contains a name */
+#define ICMPv6_NODEINFOQUERY_IPv4ADDR (2) /* --> The Data field contains an IPv4 address */
+#define ICMPv6_NODEINFORESP 140 /* ICMP Node Information Response [RFC 4620] */
+#define ICMPv6_NODEINFORESP_SUCCESS (0) /* --> A successful reply. */
+#define ICMPv6_NODEINFORESP_REFUSED (1) /* --> The Responder refuses to supply the answer */
+#define ICMPv6_NODEINFORESP_UNKNOWN (2) /* --> The Qtype of the Query is unknown */
+#define ICMPv6_INVNGHBRSOLICIT 141 /* Inverse Neighbor Discovery Solicitation Message [RFC 3122] */
+#define ICMPv6_INVNGHBRADVERT 142 /* Inverse Neighbor Discovery Advertisement Message [RFC 3122] */
+#define ICMPv6_MLDV2 143 /* MLDv2 Multicast Listener Report [RFC 3810] */
+#define ICMPv6_AGENTDISCOVREQ 144 /* Home Agent Address Discovery Request Message [RFC 3775] */
+#define ICMPv6_AGENTDISCOVREPLY 145 /* Home Agent Address Discovery Reply Message [RFC 3775] */
+#define ICMPv6_MOBPREFIXSOLICIT 146 /* Mobile Prefix Solicitation [RFC 3775] */
+#define ICMPv6_MOBPREFIXADVERT 147 /* Mobile Prefix Advertisement [RFC 3775] */
+#define ICMPv6_CERTPATHSOLICIT 148 /* Certification Path Solicitation [RFC 3971] */
+#define ICMPv6_CERTPATHADVERT 149 /* Certification Path Advertisement [RFC 3971] */
+#define ICMPv6_EXPMOBILITY 150 /* Experimental mobility protocols [RFC 4065] */
+#define ICMPv6_MRDADVERT 151 /* MRD, Multicast Router Advertisement [RFC 4286] */
+#define ICMPv6_MRDSOLICIT 152 /* MRD, Multicast Router Solicitation [RFC 4286] */
+#define ICMPv6_MRDTERMINATE 153 /* MRD, Multicast Router Termination [RFC 4286] */
+#define ICMPv6_FMIPV6 154 /* FMIPv6 messages [RFC 5568] */
+
+/* Node Information parameters */
+/* -> Query types */
+#define NI_QTYPE_NOOP 0
+#define NI_QTYPE_UNUSED 1
+#define NI_QTYPE_NODENAME 2
+#define NI_QTYPE_NODEADDRS 3
+#define NI_QTYPE_IPv4ADDRS 4
+/* -> Misc */
+#define NI_NONCE_LEN 8
+
+/* Nping ICMPv6Header Class internal definitions */
+#define ICMPv6_COMMON_HEADER_LEN 4
+#define ICMPv6_MIN_HEADER_LEN 8
+#define ICMPv6_UNREACH_LEN (ICMPv6_COMMON_HEADER_LEN+4)
+#define ICMPv6_PKTTOOBIG_LEN (ICMPv6_COMMON_HEADER_LEN+4)
+#define ICMPv6_TIMXCEED_LEN (ICMPv6_COMMON_HEADER_LEN+4)
+#define ICMPv6_PARAMPROB_LEN (ICMPv6_COMMON_HEADER_LEN+4)
+#define ICMPv6_ECHO_LEN (ICMPv6_COMMON_HEADER_LEN+4)
+#define ICMPv6_ECHOREPLY_LEN (ICMPv6_COMMON_HEADER_LEN+4)
+#define ICMPv6_ROUTERSOLICIT_LEN (ICMPv6_COMMON_HEADER_LEN+4)
+#define ICMPv6_ROUTERADVERT_LEN (ICMPv6_COMMON_HEADER_LEN+12)
+#define ICMPv6_NGHBRSOLICIT_LEN (ICMPv6_COMMON_HEADER_LEN+20)
+#define ICMPv6_NGHBRADVERT_LEN (ICMPv6_COMMON_HEADER_LEN+20)
+#define ICMPv6_REDIRECT_LEN (ICMPv6_COMMON_HEADER_LEN+36)
+#define ICMPv6_RTRRENUM_LEN (ICMPv6_COMMON_HEADER_LEN+12)
+#define ICMPv6_NODEINFO_LEN (ICMPv6_COMMON_HEADER_LEN+12)
+#define ICMPv6_MLD_LEN (ICMPv6_COMMON_HEADER_LEN+20)
+/* This must the MAX() of all values defined above*/
+#define ICMPv6_MAX_MESSAGE_BODY (ICMPv6_REDIRECT_LEN-ICMPv6_COMMON_HEADER_LEN)
+
+
+
+/* Node Information flag bitmaks */
+#define ICMPv6_NI_FLAG_T 0x01
+#define ICMPv6_NI_FLAG_A 0x02
+#define ICMPv6_NI_FLAG_C 0x04
+#define ICMPv6_NI_FLAG_L 0x08
+#define ICMPv6_NI_FLAG_G 0x10
+#define ICMPv6_NI_FLAG_S 0x20
+
+class ICMPv6Header : public ICMPHeader {
+
+ /**********************************************************************/
+ /* COMMON ICMPv6 packet HEADER */
+ /**********************************************************************/
+ /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Code | Checksum |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ + Message Body +
+ | | */
+ struct nping_icmpv6_hdr{
+ u8 type;
+ u8 code;
+ u16 checksum;
+ u8 data[ICMPv6_MAX_MESSAGE_BODY];
+ }__attribute__((__packed__));
+ typedef struct nping_icmpv6_hdr nping_icmpv6_hdr_t;
+
+
+ /**********************************************************************/
+ /* ICMPv6 MESSAGE SPECIFIC HEADERS */
+ /**********************************************************************/
+
+ /* Destination Unreachable Message
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Code | Checksum |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Unused |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | As much of invoking packet |
+ + as possible without the ICMPv6 packet +
+ | exceeding the minimum IPv6 MTU [IPv6] | */
+ struct dest_unreach_msg{
+ u32 unused;
+ //u8 invoking_pkt[?];
+ }__attribute__((__packed__));
+ typedef struct dest_unreach_msg dest_unreach_msg_t;
+
+
+ /* Packet Too Big Message
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Code | Checksum |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | MTU |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | As much of invoking packet |
+ + as possible without the ICMPv6 packet +
+ | exceeding the minimum IPv6 MTU [IPv6] | */
+ struct pkt_too_big_msg{
+ u32 mtu;
+ //u8 invoking_pkt[?];
+ }__attribute__((__packed__));
+ typedef struct pkt_too_big_msg pkt_too_big_msg_t;
+
+
+ /* Time Exceeded Message
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Code | Checksum |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Unused |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | As much of invoking packet |
+ + as possible without the ICMPv6 packet +
+ | exceeding the minimum IPv6 MTU [IPv6] | */
+ struct time_exceeded_msg{
+ u32 unused;
+ //u8 invoking_pkt[?];
+ }__attribute__((__packed__));
+ typedef struct time_exceeded_msg time_exceeded_msg_t;
+
+
+ /* Parameter Problem Message
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Code | Checksum |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Pointer |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | As much of invoking packet |
+ + as possible without the ICMPv6 packet +
+ | exceeding the minimum IPv6 MTU [IPv6] | */
+ struct parameter_problem_msg{
+ u32 pointer;
+ //u8 invoking_pkt[?];
+ }__attribute__((__packed__));
+ typedef struct parameter_problem_msg parameter_problem_msg_t;
+
+
+ /* Echo Request/Response Messages
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Code | Checksum |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Identifier | Sequence Number |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Data ...
+ +-+-+-+-+- */
+ struct echo_msg{
+ u16 id;
+ u16 seq;
+ //u8 data[?];
+ }__attribute__((__packed__));
+ typedef struct echo_msg echo_msg_t;
+
+ /* Router Advertisement Message
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Code | Checksum |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Cur Hop Limit |M|O|H|Prf|P|R|R| Router Lifetime |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Reachable Time |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Retrans Timer |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Options ...
+ +-+-+-+-+-+-+-+-+-+-+-+- */
+ struct router_advert_msg{
+ u8 current_hop_limit;
+ u8 autoconfig_flags; /* See RFC 5175 */
+ u16 router_lifetime;
+ u32 reachable_time;
+ u32 retransmission_timer;
+ //u8 icmpv6_options[?];
+ }__attribute__((__packed__));
+ typedef struct router_advert_msg router_advert_msg_t;
+
+
+ /* Router Solicitation Message
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Code | Checksum |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Reserved |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Options ...
+ +-+-+-+-+-+-+-+-+-+-+-+- */
+ struct router_solicit_msg{
+ u32 reserved;
+ //u8 icmpv6_options[?];
+ }__attribute__((__packed__));
+ typedef struct router_solicit_msg router_solicit_msg_t;
+
+
+ /* Neighbor Advertisement Message
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Code | Checksum |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ |R|S|O| Reserved |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ + +
+ | |
+ + Target Address +
+ | |
+ + +
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Options ...
+ +-+-+-+-+-+-+-+-+-+-+-+- */
+ struct neighbor_advert_msg{
+ u8 flags;
+ u8 reserved[3];
+ u8 target_address[16];
+ //u8 icmpv6_options[?];
+ }__attribute__((__packed__));
+ typedef struct neighbor_advert_msg neighbor_advert_msg_t;
+
+
+ /* Neighbor Solicitation Message
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Code | Checksum |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Reserved |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ + +
+ | |
+ + Target Address +
+ | |
+ + +
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Options ...
+ +-+-+-+-+-+-+-+-+-+-+-+- */
+ struct neighbor_solicit_msg{
+ u32 reserved;
+ u8 target_address[16];
+ //u8 icmpv6_options[?];
+ }__attribute__((__packed__));
+ typedef struct neighbor_solicit_msg neighbor_solicit_msg_t;
+
+
+ /* Redirect Message
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Code | Checksum |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Reserved |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ + +
+ | |
+ + Target Address +
+ | |
+ + +
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ + +
+ | |
+ + Destination Address +
+ | |
+ + +
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Options ...
+ +-+-+-+-+-+-+-+-+-+-+-+- */
+ struct redirect_msg{
+ u32 reserved;
+ u8 target_address[16];
+ u8 destination_address[16];
+ //u8 icmpv6_options[?];
+ }__attribute__((__packed__));
+ typedef struct redirect_msg redirect_msg_t;
+
+
+ /* Router Renumbering Header
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Code | Checksum |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | SequenceNumber |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | SegmentNumber | Flags | MaxDelay |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | reserved |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ / RR Message Body /
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+ struct router_renumbering_msg{
+ u32 seq;
+ u8 segment_number;
+ u8 flags;
+ u16 max_delay;
+ u32 reserved;
+ //u8 rr_msg_body[?];
+ }__attribute__((__packed__));
+ typedef struct router_renumbering_msg router_renumbering_msg_t;
+
+
+ /* Node Information Queries
+ 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
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Code | Checksum |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Qtype | unused |G|S|L|C|A|T|
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ + Nonce +
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ / Data /
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+ struct nodeinfo_msg{
+ u16 qtype;
+ u16 flags;
+ u64 nonce;
+ //u8 data[?];
+ }__attribute__((__packed__));
+ typedef struct nodeinfo_msg nodeinfo_msg_t;
+
+
+ /* Multicast Listener Discovery
+ 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
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Code | Checksum |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Maximum Response Delay | Reserved |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ + +
+ | |
+ + Multicast Address +
+ | |
+ + +
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+ struct mld_msg{
+ u16 max_response_delay;
+ u16 reserved;
+ u8 mcast_address[16];
+ }__attribute__((__packed__));
+ typedef struct mld_msg mld_msg_t;
+
+
+ nping_icmpv6_hdr_t h;
+
+ /* Helper pointers */
+ dest_unreach_msg_t *h_du;
+ pkt_too_big_msg_t *h_ptb;
+ time_exceeded_msg_t *h_te;
+ parameter_problem_msg_t *h_pp;
+ echo_msg_t *h_e;
+ router_advert_msg_t *h_ra;
+ router_solicit_msg_t *h_rs;
+ neighbor_advert_msg_t *h_na;
+ neighbor_solicit_msg_t *h_ns;
+ redirect_msg_t *h_r;
+ router_renumbering_msg_t *h_rr;
+ nodeinfo_msg_t *h_ni;
+ mld_msg_t *h_mld;
+
+ public:
+ ICMPv6Header();
+ ~ICMPv6Header();
+ void reset();
+ u8 *getBufferPointer();
+ int storeRecvData(const u8 *buf, size_t len);
+ int protocol_id() const;
+ int validate();
+ int print(FILE *output, int detail) const;
+
+ /* ICMP Type */
+ int setType(u8 val);
+ u8 getType() const;
+ bool validateType();
+ bool validateType(u8 val);
+
+ /* Code */
+ int setCode(u8 c);
+ u8 getCode() const;
+ bool validateCode();
+ bool validateCode(u8 type, u8 code);
+
+ /* Checksum */
+ int setSum();
+ int setSum(u16 s);
+ int setSumRandom();
+ u16 getSum() const;
+
+ int setReserved(u32 val);
+ u32 getReserved() const;
+ int setUnused(u32 val);
+ u32 getUnused() const;
+
+ int setFlags(u8 val);
+ u8 getFlags() const;
+
+ int setMTU(u32 mtu);
+ u32 getMTU() const;
+
+ /* Parameter problem */
+ int setPointer(u32 val);
+ u32 getPointer() const;
+
+ /* Echo */
+ int setIdentifier(u16 val);
+ u16 getIdentifier() const;
+ int setSequence(u16 val);
+ int setSequence(u32 val);
+ u32 getSequence() const;
+
+ /* Router Advertisement */
+ int setCurrentHopLimit(u8 val);
+ u8 getCurrentHopLimit() const;
+
+ int setRouterLifetime(u16 val);
+ u16 getRouterLifetime() const;
+
+ int setReachableTime(u32 val);
+ u32 getReachableTime() const;
+
+ int setRetransmissionTimer(u32 val);
+ u32 getRetransmissionTimer() const;
+
+ int setTargetAddress(struct in6_addr addr);
+ struct in6_addr getTargetAddress() const;
+
+ int setDestinationAddress(struct in6_addr addr);
+ struct in6_addr getDestinationAddress() const;
+
+ int setSegmentNumber(u8 val);
+ u8 getSegmentNumber() const;
+
+ int setMaxDelay(u16 val);
+ u16 getMaxDelay() const;
+
+ /* Node Information Queries */
+ int setQtype(u16 val);
+ u16 getQtype() const;
+ int setNodeInfoFlags(u16 val);
+ u16 getNodeInfoFlags() const;
+ int setG(bool flag_value=true);
+ bool getG() const;
+ int setS(bool flag_value=true);
+ bool getS() const;
+ int setL(bool flag_value=true);
+ bool getL() const;
+ int setC(bool flag_value=true);
+ bool getC() const;
+ int setA(bool flag_value=true);
+ bool getA() const;
+ int setT(bool flag_value=true);
+ bool getT() const;
+ int setNonce(u64 nonce_value);
+ int setNonce(const u8 *nonce);
+ u64 getNonce() const;
+
+ /* Multicast Listener Discovery */
+ int setMulticastAddress(struct in6_addr addr);
+ struct in6_addr getMulticastAddress() const;
+
+ /* Misc */
+ int getHeaderLengthFromType(u8 type) const;
+ bool isError() const;
+ const char *type2string(int type, int code) const;
+
+}; /* End of class ICMPv6Header */
+
+#endif
diff --git a/libnetutil/ICMPv6Option.cc b/libnetutil/ICMPv6Option.cc
new file mode 100644
index 0000000..04976a1
--- /dev/null
+++ b/libnetutil/ICMPv6Option.cc
@@ -0,0 +1,326 @@
+/***************************************************************************
+ * ICMPv6Option.cc -- The ICMPv6Option Class represents an ICMP version 6 *
+ * option. It contains methods to set any header field. In general, these *
+ * methods do error checkings and byte order conversion. *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#include "ICMPv6Option.h"
+
+
+ICMPv6Option::ICMPv6Option() {
+ this->reset();
+} /* End of ICMPv6Option constructor */
+
+
+ICMPv6Option::~ICMPv6Option() {
+
+} /* End of ICMPv6Option destructor */
+
+
+/** Sets every class attribute to zero */
+void ICMPv6Option::reset(){
+ memset(&this->h, 0, sizeof(nping_icmpv6_option_t));
+ h_la = (link_addr_option_t *)this->h.data;
+ h_pi = (prefix_info_option_t *)this->h.data;
+ h_r = (redirect_option_t *)this->h.data;
+ h_mtu = (mtu_option_t *)this->h.data;
+} /* End of reset() */
+
+
+/** @warning This method is essential for the superclass getBinaryBuffer()
+ * method to work. Do NOT change a thing unless you know what you're doing */
+u8 *ICMPv6Option::getBufferPointer(){
+ return (u8*)(&this->h);
+} /* End of getBufferPointer() */
+
+
+/** Stores supplied packet in the internal buffer so the information
+ * can be accessed using the standard get & set methods.
+ * @warning The ICMPv6Option class is able to hold a maximum of
+ * sizeof(nping_icmpv6_option_t) bytes. If the supplied buffer is longer than
+ * that, only the first sizeof(nping_icmpv6_option_t) bytes will be stored in
+ * the internal buffer.
+ * @warning Supplied len MUST be at least ICMPv6_OPTION_MIN_HEADER_LEN bytes
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error */
+int ICMPv6Option::storeRecvData(const u8 *buf, size_t len){
+ if(buf==NULL || len<ICMPv6_OPTION_MIN_HEADER_LEN){
+ return OP_FAILURE;
+ }else{
+ int stored_len = MIN( sizeof(nping_icmpv6_option_t), len);
+ this->reset(); /* Re-init the object, just in case the caller had used it already */
+ this->length=stored_len;
+ memcpy(&(this->h), buf, stored_len);
+ }
+ return OP_SUCCESS;
+} /* End of storeRecvData() */
+
+int ICMPv6Option::protocol_id() const {
+ return HEADER_TYPE_ICMPv6_OPTION;
+}
+
+
+int ICMPv6Option::setType(u8 val){
+ this->h.type=val;
+ this->length = getHeaderLengthFromType(val);
+ this->h.length = this->length / 8;
+ return OP_SUCCESS;
+} /* End of setType() */
+
+u8 ICMPv6Option::getType(){
+ return this->h.type;
+} /* End of getType() */
+
+
+bool ICMPv6Option::validateType(u8 val){
+ switch( val ){
+ case ICMPv6_OPTION_SRC_LINK_ADDR:
+ case ICMPv6_OPTION_TGT_LINK_ADDR:
+ case ICMPv6_OPTION_PREFIX_INFO:
+ case ICMPv6_OPTION_REDIR_HDR:
+ case ICMPv6_OPTION_MTU:
+ return true;
+ break;
+
+ default:
+ return false;
+ break;
+ }
+ return false;
+} /* End of validateType() */
+
+
+
+int ICMPv6Option::setLength(u8 val){
+ this->h.length=val;
+ return OP_SUCCESS;
+} /* End of setLength() */
+
+u8 ICMPv6Option::getLength(){
+ return this->h.length;
+} /* End of getLength() */
+
+
+int ICMPv6Option::setLinkAddress(u8* val){
+ if(val==NULL)
+ return OP_FAILURE;
+ switch(this->h.type){
+ case ICMPv6_OPTION_SRC_LINK_ADDR:
+ case ICMPv6_OPTION_TGT_LINK_ADDR:
+ memcpy(this->h_la->link_addr, val, ICMPv6_OPTION_LINK_ADDRESS_LEN);
+ return OP_SUCCESS;
+ break;
+
+ default:
+ return OP_FAILURE;
+ break;
+ }
+} /* End of setLinkAddress() */
+
+
+u8 *ICMPv6Option::getLinkAddress(){
+ switch(this->h.type){
+ case ICMPv6_OPTION_SRC_LINK_ADDR:
+ case ICMPv6_OPTION_TGT_LINK_ADDR:
+ return this->h_la->link_addr;
+ break;
+
+ default:
+ return NULL;
+ break;
+ }
+} /* End of getLinkAddress() */
+
+
+int ICMPv6Option::setPrefixLength(u8 val){
+ if(this->h.type!=ICMPv6_OPTION_PREFIX_INFO)
+ return OP_FAILURE;
+ this->h_pi->prefix_length=val;
+ return OP_SUCCESS;
+} /* End of setPrefixLength() */
+
+
+u8 ICMPv6Option::getPrefixLength(){
+ if(this->h.type!=ICMPv6_OPTION_PREFIX_INFO)
+ return 0;
+ else
+ return this->h_pi->prefix_length;
+} /* End of getPrefixLength() */
+
+
+int ICMPv6Option::setFlags(u8 val){
+ if(this->h.type!=ICMPv6_OPTION_PREFIX_INFO)
+ return OP_FAILURE;
+ this->h_pi->flags=val;
+ return OP_SUCCESS;
+} /* End of setFlags() */
+
+
+u8 ICMPv6Option::getFlags(){
+ if(this->h.type!=ICMPv6_OPTION_PREFIX_INFO)
+ return 0;
+ else
+ return this->h_pi->flags;
+} /* End of getFlags() */
+
+
+int ICMPv6Option::setValidLifetime(u32 val){
+ if(this->h.type!=ICMPv6_OPTION_PREFIX_INFO)
+ return OP_FAILURE;
+ this->h_pi->valid_lifetime=htonl(val);
+ return OP_SUCCESS;
+} /* End of setValidLifetime() */
+
+
+u32 ICMPv6Option::getValidLifetime(){
+ if(this->h.type!=ICMPv6_OPTION_PREFIX_INFO)
+ return 0;
+ else
+ return ntohl(this->h_pi->valid_lifetime);
+} /* End of getValidLifetime() */
+
+
+int ICMPv6Option::setPreferredLifetime(u32 val){
+ if(this->h.type!=ICMPv6_OPTION_PREFIX_INFO)
+ return OP_FAILURE;
+ this->h_pi->preferred_lifetime=htonl(val);
+ return OP_SUCCESS;
+} /* End of setPreferredLifetime() */
+
+
+u32 ICMPv6Option::getPreferredLifetime(){
+ if(this->h.type!=ICMPv6_OPTION_PREFIX_INFO)
+ return 0;
+ else
+ return ntohl(this->h_pi->preferred_lifetime);
+} /* End of getPreferredLifetime() */
+
+
+int ICMPv6Option::setPrefix(u8 *val){
+ if(val==NULL || this->h.type!=ICMPv6_OPTION_PREFIX_INFO)
+ return OP_FAILURE;
+ else
+ memcpy(this->h_pi->prefix, val, 16);
+ return OP_SUCCESS;
+} /* End of setPrefix() */
+
+
+u8 *ICMPv6Option::getPrefix(){
+ if(this->h.type!=ICMPv6_OPTION_PREFIX_INFO)
+ return NULL;
+ else
+ return this->h_pi->prefix;
+} /* End of getPrefix() */
+
+
+int ICMPv6Option::setMTU(u32 val){
+ if(this->h.type!=ICMPv6_OPTION_MTU)
+ return OP_FAILURE;
+ this->h_mtu->mtu=htonl(val);
+ return OP_SUCCESS;
+} /* End of setMTU() */
+
+
+u32 ICMPv6Option::getMTU(){
+ if(this->h.type!=ICMPv6_OPTION_MTU)
+ return 0;
+ else
+ return ntohl(this->h_mtu->mtu);
+} /* End of getMTU() */
+
+
+
+/******************************************************************************/
+/* MISCELLANEOUS STUFF */
+/******************************************************************************/
+
+/** Returns the standard ICMPv6 optiom length for the supplied option type.
+ * @warning Return value corresponds strictly to the ICMPv7 option header, this
+ * is, the minimum length of the OPTION, variable length payload is never
+ * included. For example, an ICMPv6 Redirect option has a fixed header of 8
+ * bytes but then it may contain an IPv6 header. We only return 8
+ * because we don't know in advance the total number of bytes for the message.
+ * Same applies to the rest of types. */
+int ICMPv6Option::getHeaderLengthFromType(u8 type){
+ switch( type ){
+ case ICMPv6_OPTION_SRC_LINK_ADDR:
+ return ICMPv6_OPTION_SRC_LINK_ADDR_LEN;
+ break;
+
+ case ICMPv6_OPTION_TGT_LINK_ADDR:
+ return ICMPv6_OPTION_TGT_LINK_ADDR_LEN;
+ break;
+
+ case ICMPv6_OPTION_PREFIX_INFO:
+ return ICMPv6_OPTION_PREFIX_INFO_LEN;
+ break;
+
+ case ICMPv6_OPTION_REDIR_HDR:
+ return ICMPv6_OPTION_REDIR_HDR_LEN;
+ break;
+
+ case ICMPv6_OPTION_MTU:
+ return ICMPv6_OPTION_MTU_LEN;
+ break;
+
+ /* Packets with non RFC-Compliant option types will be represented as an
+ * 8-byte ICMPv6 option. */
+ default:
+ return ICMPv6_OPTION_MIN_HEADER_LEN;
+ break;
+ }
+} /* End of getHeaderLengthFromType() */
diff --git a/libnetutil/ICMPv6Option.h b/libnetutil/ICMPv6Option.h
new file mode 100644
index 0000000..91e1b97
--- /dev/null
+++ b/libnetutil/ICMPv6Option.h
@@ -0,0 +1,235 @@
+/***************************************************************************
+ * ICMPv6Option.h -- The ICMPv6Option Class represents an ICMP version 6 *
+ * option. It contains methods to set any header field. In general, these *
+ * methods do error checkings and byte order conversion. *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#ifndef __ICMPv6OPTION_H__
+#define __ICMPv6OPTION_H__ 1
+
+#include "NetworkLayerElement.h"
+
+/* Packet header diagrams included in this file have been taken from the
+ * following IETF RFC documents: RFC 2461, RFC 2894 */
+
+/* The following codes have been defined by IANA. A complete list may be found
+ * at http://www.iana.org/assignments/icmpv6-parameters */
+
+/* ICMPv6 Option Types */
+#define ICMPv6_OPTION_SRC_LINK_ADDR 1
+#define ICMPv6_OPTION_TGT_LINK_ADDR 2
+#define ICMPv6_OPTION_PREFIX_INFO 3
+#define ICMPv6_OPTION_REDIR_HDR 4
+#define ICMPv6_OPTION_MTU 5
+
+/* Nping ICMPv6Options Class internal definitions */
+#define ICMPv6_OPTION_COMMON_HEADER_LEN 2
+#define ICMPv6_OPTION_MIN_HEADER_LEN 8
+#define ICMPv6_OPTION_SRC_LINK_ADDR_LEN (ICMPv6_OPTION_COMMON_HEADER_LEN+6)
+#define ICMPv6_OPTION_TGT_LINK_ADDR_LEN (ICMPv6_OPTION_COMMON_HEADER_LEN+6)
+#define ICMPv6_OPTION_PREFIX_INFO_LEN (ICMPv6_OPTION_COMMON_HEADER_LEN+30)
+#define ICMPv6_OPTION_REDIR_HDR_LEN (ICMPv6_OPTION_COMMON_HEADER_LEN+6)
+#define ICMPv6_OPTION_MTU_LEN (ICMPv6_OPTION_COMMON_HEADER_LEN+6)
+/* This must the MAX() of all values defined above*/
+#define ICMPv6_OPTION_MAX_MESSAGE_BODY (ICMPv6_OPTION_PREFIX_INFO_LEN-ICMPv6_OPTION_COMMON_HEADER_LEN)
+
+#define ICMPv6_OPTION_LINK_ADDRESS_LEN 6
+
+class ICMPv6Option : public NetworkLayerElement {
+
+ private:
+
+ /**********************************************************************/
+ /* COMMON ICMPv6 OPTION HEADER */
+ /**********************************************************************/
+
+ struct nping_icmpv6_option{
+ u8 type;
+ u8 length;
+ u8 data[ICMPv6_OPTION_MAX_MESSAGE_BODY];
+ }__attribute__((__packed__));
+ typedef struct nping_icmpv6_option nping_icmpv6_option_t;
+
+ /**********************************************************************/
+ /* ICMPv6 OPTION FORMATS */
+ /**********************************************************************/
+ /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Length | ... |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ~ ... ~
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+
+
+ /* Source/Target Link-layer Address
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Length | Link-Layer Address ...
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+ struct link_addr_option{
+ u8 link_addr[6];
+ }__attribute__((__packed__));
+ typedef struct link_addr_option link_addr_option_t;
+
+
+ /* Prefix Information
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Length | Prefix Length |L|A| Reserved1 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Valid Lifetime |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Preferred Lifetime |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Reserved2 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ + +
+ | |
+ + Prefix +
+ | |
+ + +
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+ struct prefix_info_option{
+ u8 prefix_length;
+ u8 flags;
+ u32 valid_lifetime;
+ u32 preferred_lifetime;
+ u32 reserved;
+ u8 prefix[16];
+ }__attribute__((__packed__));
+ typedef struct prefix_info_option prefix_info_option_t;
+
+
+ /* Redirect Header
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Length | Reserved |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Reserved |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ ~ IP header + data ~
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+ struct redirect_option{
+ u16 reserved_1;
+ u32 reserved_2;
+ //u8 invoking_pkt[?];
+ }__attribute__((__packed__));
+ typedef struct redirect_option redirect_option_t;
+
+
+ /* MTU
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Type | Length | Reserved |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | MTU |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+ struct mtu_option{
+ u16 reserved;
+ u32 mtu;
+ }__attribute__((__packed__));
+ typedef struct mtu_option mtu_option_t;
+
+
+ nping_icmpv6_option_t h;
+
+ link_addr_option_t *h_la;
+ prefix_info_option_t *h_pi;
+ redirect_option_t *h_r;
+ mtu_option_t *h_mtu;
+
+ public:
+ ICMPv6Option();
+ ~ICMPv6Option();
+ void reset();
+ u8 *getBufferPointer();
+ int storeRecvData(const u8 *buf, size_t len);
+ int protocol_id() const;
+
+ int setType(u8 val);
+ u8 getType();
+ bool validateType(u8 val);
+
+ int setLength(u8 val);
+ u8 getLength();
+
+ int setLinkAddress(u8* val);
+ u8 *getLinkAddress();
+
+ int setPrefixLength(u8 val);
+ u8 getPrefixLength();
+
+ int setFlags(u8 val);
+ u8 getFlags();
+
+ int setValidLifetime(u32 val);
+ u32 getValidLifetime();
+
+ int setPreferredLifetime(u32 val);
+ u32 getPreferredLifetime();
+
+ int setPrefix(u8 *val);
+ u8 *getPrefix();
+
+ int setMTU(u32 val);
+ u32 getMTU();
+
+ int getHeaderLengthFromType(u8 type);
+
+}; /* End of class ICMPv6Option */
+
+#endif
diff --git a/libnetutil/ICMPv6RRBody.cc b/libnetutil/ICMPv6RRBody.cc
new file mode 100644
index 0000000..8d72cda
--- /dev/null
+++ b/libnetutil/ICMPv6RRBody.cc
@@ -0,0 +1,111 @@
+/***************************************************************************
+ * ICMPv6RRBody.h -- The ICMPv6RRBody Class represents an ICMP version 6 *
+ * Router Renumbering message body. It contains methods to set any header *
+ * field. In general, these methods do error checkings and byte order *
+ * conversions. *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#include "ICMPv6RRBody.h"
+
+
+ICMPv6RRBody::ICMPv6RRBody() {
+ this->reset();
+} /* End of ICMPv6RRBody constructor */
+
+
+ICMPv6RRBody::~ICMPv6RRBody() {
+
+} /* End of ICMPv6RRBody destructor */
+
+
+/** Sets every class attribute to zero */
+void ICMPv6RRBody::reset(){
+ memset(&this->h, 0, sizeof(nping_icmpv6_rr_body_t));
+ h_mp = (rr_match_prefix_t *)this->h.data;
+ h_up = (rr_use_prefix_t *)this->h.data;
+ h_r = (rr_result_msg_t *)this->h.data;
+} /* End of reset() */
+
+
+/** @warning This method is essential for the superclass getBinaryBuffer()
+ * method to work. Do NOT change a thing unless you know what you're doing */
+u8 *ICMPv6RRBody::getBufferPointer(){
+ return (u8*)(&this->h);
+} /* End of getBufferPointer() */
+
+
+/** Stores supplied packet in the internal buffer so the information
+ * can be accessed using the standard get & set methods.
+ * @warning The ICMPv6RRBody class is able to hold a maximum of
+ * sizeof(nping_icmpv6_rr_body_t) bytes. If the supplied buffer is longer than
+ * that, only the first sizeof(nping_icmpv6_rr_body_t) bytes will be stored in
+ * the internal buffer.
+ * @warning Supplied len MUST be at least ICMPv6_RR_MIN_LENGTH bytes
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error */
+int ICMPv6RRBody::storeRecvData(const u8 *buf, size_t len){
+ if(buf==NULL || len<ICMPv6_RR_MIN_LENGTH){
+ return OP_FAILURE;
+ }else{
+ int stored_len = MIN( sizeof(nping_icmpv6_rr_body_t), len);
+ this->reset(); /* Re-init the object, just in case the caller had used it already */
+ this->length=stored_len;
+ memcpy(&(this->h), buf, stored_len);
+ }
+ return OP_SUCCESS;
+} /* End of storeRecvData() */
+
diff --git a/libnetutil/ICMPv6RRBody.h b/libnetutil/ICMPv6RRBody.h
new file mode 100644
index 0000000..4f6deff
--- /dev/null
+++ b/libnetutil/ICMPv6RRBody.h
@@ -0,0 +1,200 @@
+/***************************************************************************
+ * ICMPv6RRBody.cc -- The ICMPv6RRBody Class represents an ICMP version 6 *
+ * Router Renumbering message body. It contains methods to set any header *
+ * field. In general, these methods do error checkings and byte order *
+ * conversions. *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#ifndef ICMPv6RRBODY_H
+#define ICMPv6RRBODY_H 1
+
+#include "NetworkLayerElement.h"
+
+/* Packet header diagrams included in this file have been taken from the
+ * following IETF RFC documents: RFC 2894 */
+
+/* Nping ICMPv6RRBody Class internal definitions */
+#define ICMPv6_RR_MATCH_PREFIX_LEN 24
+#define ICMPv6_RR_USE_PREFIX_LEN 32
+#define ICMPv6_RR_RESULT_MSG_LEN 24
+/* This must the MAX() of all values defined above*/
+#define ICMPv6_RR_MAX_LENGTH (ICMPv6_RR_USE_PREFIX_LEN)
+#define ICMPv6_RR_MIN_LENGTH (ICMPv6_RR_MATCH_PREFIX_LEN)
+
+
+class ICMPv6RRBody : public NetworkLayerElement {
+
+ private:
+
+ /**********************************************************************/
+ /* COMMON ICMPv6 OPTION HEADER */
+ /**********************************************************************/
+
+ struct nping_icmpv6_rr_body{
+ u8 data[ICMPv6_RR_MAX_LENGTH];
+ }__attribute__((__packed__));
+ typedef struct nping_icmpv6_rr_body nping_icmpv6_rr_body_t;
+
+ /**********************************************************************/
+ /* ICMPv6 OPTION FORMATS */
+ /**********************************************************************/
+
+
+ /* Match-Prefix Part
+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | OpCode | OpLength | Ordinal | MatchLen |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | MinLen | MaxLen | reserved |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ +- -+
+ | |
+ +- MatchPrefix -+
+ | |
+ +- -+
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ struct rr_match_prefix{
+ u8 op_code;
+ u8 op_length;
+ u8 ordinal;
+ u8 match_length;
+ u8 min_length;
+ u8 max_length;
+ u16 reserved;
+ u8 match_prefix[16];
+ }__attribute__((__packed__));
+ typedef struct rr_match_prefix rr_match_prefix_t;
+
+
+ /* Use-Prefix Part
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | UseLen | KeepLen | FlagMask | RAFlags |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Valid Lifetime |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Preferred Lifetime |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ |V|P| reserved |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ +- -+
+ | |
+ +- UsePrefix -+
+ | |
+ +- -+
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ struct rr_use_prefix{
+ u8 use_len;
+ u8 keep_len;
+ u8 flag_mask;
+ u8 ra_flags;
+ u32 valid_lifetime;
+ u32 preferred_lifetime;
+ u8 flags;
+ u8 reserved[3];
+ u8 use_prefix[16];
+ }__attribute__((__packed__));
+ typedef struct rr_use_prefix rr_use_prefix_t;
+
+
+ /* Result Message
+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | reserved |B|F| Ordinal | MatchedLen |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | InterfaceIndex |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ +- -+
+ | |
+ +- MatchedPrefix -+
+ | |
+ +- -+
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+ struct rr_result_msg{
+ u8 reserved;
+ u8 flags;
+ u8 ordinal;
+ u8 matched_length;
+ u32 interface_index;
+ u8 matched_prefix[16];
+ }__attribute__((__packed__));
+ typedef struct rr_result_msg rr_result_msg_t;
+
+ nping_icmpv6_rr_body_t h;
+
+ rr_match_prefix_t *h_mp;
+ rr_use_prefix_t *h_up;
+ rr_result_msg_t *h_r;
+
+ public:
+ ICMPv6RRBody();
+ ~ICMPv6RRBody();
+ void reset();
+ u8 *getBufferPointer();
+ int storeRecvData(const u8 *buf, size_t len);
+
+}; /* End of class ICMPv6RRBody */
+
+#endif
diff --git a/libnetutil/IPv4Header.cc b/libnetutil/IPv4Header.cc
new file mode 100644
index 0000000..b206902
--- /dev/null
+++ b/libnetutil/IPv4Header.cc
@@ -0,0 +1,634 @@
+/***************************************************************************
+ * IPv4Header.cc -- The IPv4Header Class represents an IPv4 datagram. It *
+ * contains methods to set any header field. In general, these methods do *
+ * error checkings and byte order conversion. *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#include "IPv4Header.h"
+#include <assert.h>
+
+/******************************************************************************/
+/* CONTRUCTORS, DESTRUCTORS AND INITIALIZATION METHODS */
+/******************************************************************************/
+IPv4Header::IPv4Header() {
+ this->reset();
+} /* End of IPv4Header constructor */
+
+
+IPv4Header::~IPv4Header() {
+
+} /* End of IPv4Header destructor */
+
+
+/** Sets every attribute to its default value */
+void IPv4Header::reset() {
+ memset(&this->h, 0, sizeof(nping_ipv4_hdr_t));
+ this->ipoptlen=0;
+ this->length=20; /* Initial value 20. This will be incremented if options are used */
+ this->setVersion();
+ this->setHeaderLength();
+ this->setTOS(IPv4_DEFAULT_TOS);
+ this->setIdentification(IPv4_DEFAULT_ID);
+ this->setTTL(IPv4_DEFAULT_TTL);
+ this->setNextProto(IPv4_DEFAULT_PROTO);
+ this->setTotalLength();
+} /* End of IPv4Header destructor */
+
+
+/******************************************************************************/
+/* PacketElement:: OVERWRITTEN METHODS */
+/******************************************************************************/
+
+/** @warning This method is essential for the superclass getBinaryBuffer()
+ * method to work. Do NOT change a thing unless you know what you're doing */
+u8 *IPv4Header::getBufferPointer(){
+ return (u8*)(&h);
+} /* End of getBufferPointer() */
+
+/** Stores supplied packet in the internal buffer so the information
+ * can be accessed using the standard get & set methods.
+ * @warning The IPv4Header class is able to hold a maximum of 60 bytes. If the
+ * supplied buffer is longer than that, only the first 60 bytes will be stored
+ * in the internal buffer.
+ * @warning Supplied len MUST be at least 20 bytes (min IP header length).
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error */
+int IPv4Header::storeRecvData(const u8 *buf, size_t len){
+ if(buf==NULL || len<IP_HEADER_LEN){
+ return OP_FAILURE;
+ }else{
+ int stored_len = MIN((IP_HEADER_LEN + MAX_IP_OPTIONS_LEN), len);
+ this->reset(); /* Re-init the object, just in case the caller had used it already */
+ this->length=stored_len;
+ memcpy(&(this->h), buf, stored_len);
+ }
+ return OP_SUCCESS;
+} /* End of storeRecvData() */
+
+
+/* Returns a protocol identifier. This is used by packet parsing funtions
+ * that return linked lists of PacketElement objects, to determine the protocol
+ * the object represents. */
+int IPv4Header::protocol_id() const {
+ return HEADER_TYPE_IPv4;
+} /* End of protocol_id() */
+
+
+/** Performs some VERY BASIC checks that intend to validate the information
+ * stored in the internal buffer, as a valid protocol header.
+ * @warning If the information stored in the object has been set through a
+ * call to storeRecvData(), the object's internal length count may be updated
+ * if the validation is successful.
+ * @return the length, in bytes, of the header, if its found to be valid or
+ * OP_FAILURE (-1) otherwise. */
+int IPv4Header::validate(){
+ if(this->getVersion()!=4)
+ return OP_FAILURE;
+ else if( this->getHeaderLength()<5)
+ return OP_FAILURE;
+ else if( this->getHeaderLength()*4 > this->length)
+ return OP_FAILURE;
+ this->length=this->getHeaderLength()*4;
+ return this->length;
+} /* End of validate() */
+
+
+/** Prints the contents of the header and calls print() on the next protocol
+ * header in the chain (if there is any).
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error. */
+int IPv4Header::print(FILE *output, int detail) const {
+ static char ipstring[256];
+ memset(ipstring, 0, 256);
+ struct in_addr addr;
+ int frag_off = 8 * this->getFragOffset() & 8191; /* 2^13 - 1 */;
+ char ipinfo[512] = ""; /* Temp info about IP. */
+ char fragnfo[64] = ""; /* Temp info about fragmentation. */
+
+ fprintf(output, "IPv4[");
+
+ this->getSourceAddress(&addr);
+ inet_ntop(AF_INET, &addr, ipstring, sizeof(ipstring));
+ fprintf(output, "%s", ipstring);
+
+ fprintf(output, " >");
+
+ this->getDestinationAddress(&addr);
+ inet_ntop(AF_INET, &addr, ipstring, sizeof(ipstring));
+ fprintf(output, " %s", ipstring);
+
+ /* Is this a fragmented packet? is it the last fragment? */
+ if (frag_off || this->getMF()) {
+ Snprintf(fragnfo, sizeof(fragnfo), " frag offset=%d%s", frag_off, this->getMF() ? "+" : "");
+ }
+
+ /* Create a string with information relevant to the specified level of detail */
+ if( detail == PRINT_DETAIL_LOW ){
+ Snprintf(ipinfo, sizeof(ipinfo), "ttl=%d id=%d iplen=%d%s%s%s%s",
+ this->getTTL(), this->getIdentification(), this->getTotalLength(), fragnfo,
+ this->getHeaderLength()==5?"":" ipopts={",
+ this->getHeaderLength()?"":format_ip_options(this->h.options , MIN(this->getHeaderLength()*4, this->length-IP_HEADER_LEN)),
+ this->getHeaderLength()?"":"}");
+ }else if( detail == PRINT_DETAIL_MED ){
+ Snprintf(ipinfo, sizeof(ipinfo), "ttl=%d id=%d proto=%d csum=0x%04X iplen=%d%s%s%s%s",
+ this->getTTL(), this->getIdentification(),
+ this->getNextProto(), this->getSum(),
+ this->getTotalLength(), fragnfo,
+ this->getHeaderLength()==5?"":" ipopts={",
+ this->getHeaderLength()==5?"":format_ip_options(this->h.options , MIN(this->getHeaderLength()*4, this->length-IP_HEADER_LEN)),
+ this->getHeaderLength()==5?"":"}");
+ }else if( detail>=PRINT_DETAIL_HIGH ){
+ Snprintf(ipinfo, sizeof(ipinfo), "ver=%d ihl=%d tos=0x%02x iplen=%d id=%d%s%s%s%s foff=%d%s ttl=%d proto=%d csum=0x%04X%s%s%s",
+ this->getVersion(), this->getHeaderLength(),
+ this->getTOS(), this->getTotalLength(),
+ this->getIdentification(),
+ (this->getRF() ||this->getDF()||this->getMF()) ? " flg=" : "",
+ (this->getRF()) ? "x" : "",
+ (this->getDF() )? "D" : "",
+ (this->getMF() )? "M": "",
+ frag_off, (this->getMF()) ? "+" : "",
+ this->getTTL(), this->getNextProto(),
+ this->getSum(),
+ this->getHeaderLength()==5?"":" ipopts={",
+ this->getHeaderLength()==5?"":format_ip_options(this->h.options , MIN(this->getHeaderLength()*4, this->length-IP_HEADER_LEN)),
+ this->getHeaderLength()==5?"":"}");
+ }
+
+ fprintf(output, " %s]", ipinfo);
+
+ if(this->next!=NULL){
+ print_separator(output, detail);
+ next->print(output, detail);
+ }
+ return OP_SUCCESS;
+} /* End of print() */
+
+
+/******************************************************************************/
+/* PROTOCOL-SPECIFIC METHODS */
+/******************************************************************************/
+
+int IPv4Header::setVersion(){
+ h.ip_v = 4;
+ return 4;
+} /* End of setVersion() */
+
+
+u8 IPv4Header::getVersion() const {
+ return (u8)h.ip_v;
+} /* End of getVersion() */
+
+
+int IPv4Header::setHeaderLength(){
+ h.ip_hl = 5 + (ipoptlen/4);
+ return OP_SUCCESS;
+} /* End of setHeaderLength() */
+
+
+int IPv4Header::setHeaderLength(u8 l){
+ h.ip_hl = l;
+ return OP_SUCCESS;
+} /* End of setHeaderLength() */
+
+
+u8 IPv4Header::getHeaderLength() const {
+ return h.ip_hl;
+} /* End of getHeaderLength() */
+
+
+int IPv4Header::setTOS(u8 v){
+ h.ip_tos = v;
+ return OP_SUCCESS;
+} /* End of setTOS() */
+
+
+u8 IPv4Header::getTOS() const {
+ return h.ip_tos;
+} /* End of getTOS() */
+
+
+int IPv4Header::setTotalLength(){
+ int mylen = 4*getHeaderLength();
+ int otherslen=0;
+
+ if (next!=NULL)
+ otherslen=next->getLen();
+ h.ip_len=htons( mylen+otherslen );
+ return OP_SUCCESS;
+} /* End of setTotalLength() */
+
+
+/** @warning Supplied value MUST be in host byte order because it will get
+ * converted by this method using htons() */
+int IPv4Header::setTotalLength(u16 l){
+ h.ip_len = htons(l);
+ return OP_SUCCESS;
+} /* End of setTotalLength() */
+
+
+/** @warning Returned value is already in host byte order. */
+u16 IPv4Header::getTotalLength() const {
+ return ntohs(h.ip_len);
+} /* End of getTotalLength() */
+
+
+/** Sets identification field to a random value */
+int IPv4Header::setIdentification(){
+ h.ip_id=get_random_u16();
+ return OP_SUCCESS;
+} /* End of setIdentification() */
+
+
+/** @warning Supplied value MUST be in host byte order because it will get
+ * converted by this method using htons() */
+int IPv4Header::setIdentification(u16 i){
+ h.ip_id = htons(i);
+ return OP_SUCCESS;
+} /* End of setIdentification() */
+
+
+/** @warning Returned value is already in host byte order. */
+u16 IPv4Header::getIdentification() const {
+ return ntohs(h.ip_id);
+} /* End of getIdentification() */
+
+
+/** Sets fragment offset field to a random value */
+int IPv4Header::setFragOffset(){
+ /* TODO: Should we check here that i<8192 ? */
+ h.ip_off=get_random_u16();
+ return OP_SUCCESS;
+} /* End of setFragOffset() */
+
+
+/** @warning Supplied value MUST be in host byte order because it will get
+ * converted by this method using htons() */
+int IPv4Header::setFragOffset(u16 i){
+ /* TODO: Should we check here that i<8192 ? */
+ h.ip_off = htons(i);
+ return OP_SUCCESS;
+} /* End of setFragOffset() */
+
+
+/** @warning Returned value is already in host byte order. */
+u16 IPv4Header::getFragOffset() const {
+ return ntohs(h.ip_off);
+} /* End of getFragOffset() */
+
+
+/** Set RF flag */
+int IPv4Header::setRF(){
+ h.ip_off |= htons(IP_RF);
+ return OP_SUCCESS;
+} /* End of setRF() */
+
+/** Unset RF flag */
+int IPv4Header::unsetRF(){
+ h.ip_off = h.ip_off & ~(htons(IP_RF));
+ return OP_SUCCESS;
+} /* End of unsetRF() */
+
+
+/** Get RF flag */
+bool IPv4Header::getRF() const {
+ return h.ip_off & htons(IP_RF);
+} /* End of getRF() */
+
+
+/** Set MF flag */
+int IPv4Header::setMF(){
+ h.ip_off |= htons(IP_MF);
+ return OP_SUCCESS;
+} /* End of setMF() */
+
+
+/** Unset MF flag */
+int IPv4Header::unsetMF(){
+ h.ip_off = h.ip_off & ~(htons(IP_MF));
+ return OP_SUCCESS;
+} /* End of unsetMF() */
+
+
+/* Get MF flag */
+bool IPv4Header::getMF() const {
+ return h.ip_off & htons(IP_MF);
+} /* End of getMF() */
+
+
+/** Set DF flag */
+int IPv4Header::setDF(){
+ h.ip_off |= htons(IP_DF);
+ return OP_SUCCESS;
+} /* End of setDF() */
+
+
+/** Unset DF flag */
+int IPv4Header::unsetDF(){
+ h.ip_off = h.ip_off & ~(htons(IP_DF));
+ return OP_SUCCESS;
+} /* End of unsetDF() */
+
+
+/** Get DF flag */
+bool IPv4Header::getDF() const {
+ return h.ip_off & htons(IP_DF);
+} /* End of getDF) */
+
+
+/** Sets TTL field to a random value */
+int IPv4Header::setTTL(){
+ h.ip_ttl=get_random_u8();
+ return OP_SUCCESS;
+} /* End of setTTL() */
+
+
+/** @warning Supplied value MUST be in host byte order because it will get
+ * converted by this method using htons() */
+int IPv4Header::setTTL(u8 t){
+ h.ip_ttl = t;
+ return OP_SUCCESS;
+} /* End of setTTL() */
+
+
+/** @warning Returned value is already in host byte order. */
+u8 IPv4Header::getTTL() const {
+ return h.ip_ttl;
+} /* End of getTTL() */
+
+
+/** Sets field "next protocol" to the supplied value.
+ * @warning: No error checks are made. Make sure the supplied value
+ * corresponds to an actual IANA number. Check
+ * http://www.iana.org/assignments/protocol-numbers/ for more details. */
+int IPv4Header::setNextProto(u8 p){
+ h.ip_p = p;
+ return OP_SUCCESS;
+} /* End of setNextProto() */
+
+
+/** Sets field "next protocol" to the number that corresponds to the supplied
+ * protocol name. Currently only TCP, UDP and ICMP are supported. Any
+ * help to extend this functionality would be appreciated. For a list of all
+ * proto names and numbers check:
+ * http://www.iana.org/assignments/protocol-numbers/ */
+int IPv4Header::setNextProto(const char *p){
+ if (p==NULL){
+ printf("setNextProto(): NULL pointer supplied\n");
+ return OP_FAILURE;
+ }
+ if( !strcasecmp(p, "TCP") )
+ h.ip_p=6; /* 6=IANA number for proto TCP */
+
+ else if( !strcasecmp(p, "UDP") )
+ h.ip_p=17; /* 17=IANA number for proto UDP */
+
+ else if( !strcasecmp(p, "ICMP") )
+ h.ip_p=1; /* 1=IANA number for proto ICMP */
+ else{
+ printf("setNextProto(): Invalid protocol number\n");
+ return OP_FAILURE;
+ }
+ return OP_SUCCESS;
+} /* End of setNextProto() */
+
+
+/** Returns next protocol number */
+u8 IPv4Header::getNextProto() const {
+ return h.ip_p;
+} /* End of getNextProto() */
+
+
+u8 IPv4Header::getNextHeader() const {
+ return this->getNextProto();
+} /* End of getNextHeader() */
+
+
+int IPv4Header::setNextHeader(u8 val){
+ return this->setNextProto(val);
+} /* End of setNextHeader() */
+
+
+/** Computes the IPv4 header checksum and sets the ip_sum field to the right
+ * value. */
+int IPv4Header::setSum(){
+ h.ip_sum = 0;
+ /* ip_checksum() comes from libdnet */
+ ip_checksum((void*)&h, 20 + ipoptlen );
+ return OP_SUCCESS;
+} /* End of setSum() */
+
+
+/** @warning Sum is set to supplied value with NO byte ordering conversion
+ * performed.
+ * @warning If sum is supplied this way, no error checks are made. Caller is
+ * responsible for the correctness of the value. */
+int IPv4Header::setSum(u16 s){
+ h.ip_sum = s;
+ return OP_SUCCESS;
+} /* End of setSum() */
+
+
+/** Set the checksum field to a random value */
+int IPv4Header::setSumRandom(){
+ h.ip_sum=get_random_u16();
+ return OP_SUCCESS;
+} /* End of setRandomSum() */
+
+
+/** Returns the value of the checksum field.
+ * @warning The returned value is in NETWORK byte order, no conversion is
+ * performed */
+u16 IPv4Header::getSum() const {
+ return h.ip_sum;
+} /* End of getSum() */
+
+
+/** Sets destination IP address.
+ * @warning Destination IP must be supplied in NETWORK byte order. Usually
+ * all regular library functions return IPs in network byte order so there
+ * should be no need to worry. */
+int IPv4Header::setDestinationAddress(u32 d){
+ h.ip_dst.s_addr = d;
+ return OP_SUCCESS;
+} /* End of setDestinationAddress() */
+
+/** Sets destination IP address.
+ * @warning Destination IP must be supplied in NETWORK byte order. Usually
+ * all regular library functions return IPs in network byte order so there
+ * should be no need to worry. */
+int IPv4Header::setDestinationAddress(struct in_addr d){
+ h.ip_dst=d;
+ return OP_SUCCESS;
+} /* End of setDestinationAddress() */
+
+
+/** Returns destination IP address.
+ * @warning Returned value is in NETWORK byte order. */
+const u8 *IPv4Header::getDestinationAddress() const {
+ return (u8 *)(&h.ip_dst.s_addr);
+} /* End of getDestinationAddress() */
+
+
+/** Returns destination IP address.
+ * @warning Returned value is in NETWORK byte order. */
+struct in_addr IPv4Header::getDestinationAddress(struct in_addr *result) const {
+ if(result!=NULL)
+ *result=this->h.ip_dst;
+ return h.ip_dst;
+} /* End of getDestinationAddress() */
+
+
+/** Sets source IP address.
+ * @warning Destination IP must be supplied in NETWORK byte order. Usually
+ * all regular library functions return IPs in network byte order so there
+ * should be no need to worry. */
+int IPv4Header::setSourceAddress(u32 d){
+ h.ip_src.s_addr = d;
+ return OP_SUCCESS;
+} /* End of setSourceAddress() */
+
+
+/** Sets source IP address.
+ * @warning Destination IP must be supplied in NETWORK byte order. Usually
+ * all regular library functions return IPs in network byte order so there
+ * should be no need to worry. */
+int IPv4Header::setSourceAddress(struct in_addr d){
+ h.ip_src=d;
+ return OP_SUCCESS;
+} /* End of setSourceAddress() */
+
+
+/** Returns source ip
+ * @warning Returned value is in NETWORK byte order. */
+const u8 *IPv4Header::getSourceAddress() const {
+ return (u8 *)(&h.ip_src.s_addr);
+} /* End of getSourceAddress() */
+
+
+/** Returns source ip
+ * @warning Returned value is in NETWORK byte order. */
+struct in_addr IPv4Header::getSourceAddress(struct in_addr *result) const {
+ if(result!=NULL)
+ *result=this->h.ip_src;
+ return h.ip_src;
+} /* End of getSourceAddress() */
+
+
+/** Returns the length of an IPv4 address. */
+u16 IPv4Header::getAddressLength() const {
+ return 4;
+} /* End of getAddressLength()*/
+
+
+int IPv4Header::setOpts(const char *txt){
+ int foo=0;
+ int bar=0;
+ int ret=0;
+ u8 buffer[128];
+ char errstr[256];
+
+ if(txt==NULL){
+ printf("setOpts(): NULL pointer supplied.\n");
+ return OP_FAILURE;
+ }
+
+ /* Parse IP options */
+ if((ret=parse_ip_options(txt, buffer, 128, &foo, &bar, errstr, sizeof(errstr)))==OP_FAILURE){
+ printf("%s\n", errstr);
+ return OP_FAILURE;
+ }else{
+ /* Copy options to our IP header */
+ this->setOpts(buffer, ret);
+ }
+ return OP_SUCCESS;
+} /* End of setOpts() */
+
+
+int IPv4Header::setOpts(u8 *opts_buff, u32 opts_len){
+ if(opts_buff==NULL || opts_len==0)
+ return OP_FAILURE;
+ assert(opts_len<=MAX_IP_OPTIONS_LEN); /* Max length for IP options */
+ memcpy(this->h.options, opts_buff, opts_len);
+ this->ipoptlen=opts_len;
+ this->length += opts_len;
+ this->setHeaderLength();
+ return OP_SUCCESS;
+} /* End of setOpts() */
+
+
+const u8 *IPv4Header::getOpts() const {
+ return h.options;
+} /* End of getOpts() */
+
+
+const u8 *IPv4Header::getOpts(int *len) const {
+ if(len==NULL)
+ printf("getOpts(): NULL pointer supplied.\n");
+ else
+ *len=ipoptlen;
+ return h.options;
+} /* End of getOpts() */
+
+
+int IPv4Header::printOptions() const {
+ char *p=format_ip_options(this->h.options, this->ipoptlen);
+ printf("%s", p);
+ return OP_SUCCESS;
+} /* End of printOptions() */
+
+const char *IPv4Header::getOptionsString() const {
+ return format_ip_options(this->h.options, this->ipoptlen);
+} /* End of getOptionsString() */
diff --git a/libnetutil/IPv4Header.h b/libnetutil/IPv4Header.h
new file mode 100644
index 0000000..5541000
--- /dev/null
+++ b/libnetutil/IPv4Header.h
@@ -0,0 +1,220 @@
+/***************************************************************************
+ * IPv4Header.h -- The IPv4Header Class represents an IPv4 datagram. It *
+ * contains methods to set any header field. In general, these methods do *
+ * error checkings and byte order conversion. *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#ifndef IPV4HEADER_H
+#define IPV4HEADER_H 1
+
+#include "NetworkLayerElement.h"
+
+#define IP_RF 0x8000 /* Reserved fragment flag */
+#define IP_DF 0x4000 /* Don't fragment flag */
+#define IP_MF 0x2000 /* More fragments flag */
+#define IP_OFFMASK 0x1fff /* Mask for fragmenting bits */
+#define IP_HEADER_LEN 20 /* Length of the standard header */
+#define MAX_IP_OPTIONS_LEN 40 /* Max Length for IP Options */
+
+/* Default header values */
+#define IPv4_DEFAULT_TOS 0
+#define IPv4_DEFAULT_ID 0
+#define IPv4_DEFAULT_TTL 64
+#define IPv4_DEFAULT_PROTO 6 /* TCP */
+
+class IPv4Header : public NetworkLayerElement {
+
+ private:
+ /*
+ 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| IHL |Type of Service| Total Length |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Identification |Flags| Fragment Offset |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Time to Live | Protocol | Header Checksum |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Source Address |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Destination Address |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Options | Padding |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ struct nping_ipv4_hdr {
+ #if WORDS_BIGENDIAN
+ u8 ip_v:4; /* Version */
+ u8 ip_hl:4; /* Header length */
+ #else
+ u8 ip_hl:4; /* Header length */
+ u8 ip_v:4; /* Version */
+ #endif
+ u8 ip_tos; /* Type of service */
+ u16 ip_len; /* Total length */
+ u16 ip_id; /* Identification */
+ u16 ip_off; /* Fragment offset field */
+ u8 ip_ttl; /* Time to live */
+ u8 ip_p; /* Protocol */
+ u16 ip_sum; /* Checksum */
+ struct in_addr ip_src; /* Source IP address */
+ struct in_addr ip_dst; /* Destination IP address */
+ u8 options[MAX_IP_OPTIONS_LEN]; /* IP Options */
+ }__attribute__((__packed__));
+
+ typedef struct nping_ipv4_hdr nping_ipv4_hdr_t;
+
+ nping_ipv4_hdr_t h;
+
+ int ipoptlen; /**< Length of IP options */
+
+ public:
+
+ /* Misc */
+ IPv4Header();
+ ~IPv4Header();
+ void reset();
+ u8 *getBufferPointer();
+ int storeRecvData(const u8 *buf, size_t len);
+ int protocol_id() const;
+ int validate();
+ int print(FILE *output, int detail) const;
+
+ /* IP version */
+ int setVersion();
+ u8 getVersion() const;
+
+ /* Header Length */
+ int setHeaderLength();
+ int setHeaderLength(u8 l);
+ u8 getHeaderLength() const;
+
+ /* Type of Service */
+ int setTOS(u8 v);
+ u8 getTOS() const;
+
+ /* Total length of the datagram */
+ int setTotalLength();
+ int setTotalLength(u16 l);
+ u16 getTotalLength() const;
+
+ /* Identification value */
+ int setIdentification();
+ int setIdentification(u16 i);
+ u16 getIdentification() const;
+
+ /* Fragment Offset */
+ int setFragOffset();
+ int setFragOffset(u16 f);
+ u16 getFragOffset() const;
+
+ /* Flags */
+ int setRF();
+ int unsetRF();
+ bool getRF() const;
+ int setDF();
+ int unsetDF();
+ bool getDF() const;
+ int setMF();
+ int unsetMF();
+ bool getMF() const;
+
+ /* Time to live */
+ int setTTL();
+ int setTTL(u8 t);
+ u8 getTTL() const;
+
+ /* Next protocol */
+ int setNextProto(u8 p);
+ int setNextProto(const char *p);
+ u8 getNextProto() const;
+ int setNextHeader(u8 val);
+ u8 getNextHeader() const;
+
+ /* Checksum */
+ int setSum();
+ int setSum(u16 s);
+ int setSumRandom();
+ u16 getSum() const;
+
+ /* Destination IP */
+ int setDestinationAddress(u32 d);
+ int setDestinationAddress(struct in_addr d);
+ const u8 *getDestinationAddress() const;
+ struct in_addr getDestinationAddress(struct in_addr *result) const;
+
+
+ /* Source IP */
+ int setSourceAddress(u32 d);
+ int setSourceAddress(struct in_addr d);
+ const u8 *getSourceAddress() const;
+ struct in_addr getSourceAddress(struct in_addr *result) const;
+
+ u16 getAddressLength() const;
+
+ /* IP Options */
+ int setOpts(const char *txt);
+ int setOpts(u8 *opts_buff, u32 opts_len);
+ const u8 *getOpts() const;
+ const u8 *getOpts(int *len) const;
+ int printOptions() const;
+ const char *getOptionsString() const;
+
+}; /* End of class IPv4Header */
+
+#endif
diff --git a/libnetutil/IPv6ExtensionHeader.h b/libnetutil/IPv6ExtensionHeader.h
new file mode 100644
index 0000000..54c191f
--- /dev/null
+++ b/libnetutil/IPv6ExtensionHeader.h
@@ -0,0 +1,81 @@
+/***************************************************************************
+ * IPv6ExtensionHeader.h -- The IPv6ExtensionHeader class represents *
+ * a generic class for IPv6 extension headers. Specific headers (like *
+ * Hop-by-Hop or Routing) inherit from this class. *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#ifndef __IPv6_EXTENSION_HEADER_H__
+#define __IPv6_EXTENSION_HEADER_H__ 1
+
+#include "PacketElement.h"
+
+/* Extension header option codes */
+#define EXTOPT_PAD1 0x00 /* Pad1 (RFC 2460) */
+#define EXTOPT_PADN 0x01 /* PadN (RFC 2460) */
+#define EXTOPT_JUMBO 0xC2 /* Jumbo Payload (RFC 2675) */
+#define EXTOPT_TUNENCAPLIM 0x04 /* Tunnel Encapsulation Limit (RFC 2473) */
+#define EXTOPT_ROUTERALERT 0x05 /* Router Alert (RFC 2711) */
+#define EXTOPT_QUICKSTART 0x26 /* Quick-Start (RFC 4782) */
+#define EXTOPT_CALIPSO 0x07 /* CALIPSO (RFC 5570) */
+#define EXTOPT_HOMEADDR 0xC9 /* Home Address (RFC 6275) */
+
+class IPv6ExtensionHeader : public PacketElement {
+
+};
+
+#endif
+
diff --git a/libnetutil/IPv6Header.cc b/libnetutil/IPv6Header.cc
new file mode 100644
index 0000000..8035a98
--- /dev/null
+++ b/libnetutil/IPv6Header.cc
@@ -0,0 +1,505 @@
+/***************************************************************************
+ * IPv6Header.cc -- The IPv6Header Class represents an IPv4 datagram. It *
+ * contains methods to set any header field. In general, these methods do *
+ * error checkings and byte order conversion. *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#include "IPv6Header.h"
+
+/******************************************************************************/
+/* CONTRUCTORS, DESTRUCTORS AND INITIALIZATION METHODS */
+/******************************************************************************/
+IPv6Header::IPv6Header() {
+ this->reset();
+} /* End of IPv6Header constructor */
+
+
+IPv6Header::~IPv6Header() {
+
+} /* End of IPv6Header destructor */
+
+
+/** Sets every attribute to its default value */
+void IPv6Header::reset(){
+ memset(&this->h, 0, sizeof(nping_ipv6_hdr_t));
+ this->length=IPv6_HEADER_LEN;
+ this->setVersion();
+ this->setTrafficClass(IPv6_DEFAULT_TCLASS);
+ this->setFlowLabel(IPv6_DEFAULT_FLABEL);
+ this->setHopLimit(IPv6_DEFAULT_HOPLIM);
+ this->setNextHeader(IPv6_DEFAULT_NXTHDR); /* No next header */
+ this->setPayloadLength(0);
+} /* End of reset() */
+
+
+/******************************************************************************/
+/* PacketElement:: OVERWRITTEN METHODS */
+/******************************************************************************/
+
+/** @warning This method is essential for the superclass getBinaryBuffer()
+ * method to work. Do NOT change a thing unless you know what you're doing */
+u8 *IPv6Header::getBufferPointer(){
+ return (u8*)(&h);
+} /* End of getBufferPointer() */
+
+
+/** Stores supplied packet in the internal buffer so the information
+ * can be accessed using the standard get & set methods.
+ * @warning The IPv6Header class is able to hold a maximum of 40 bytes. If the
+ * supplied buffer is longer than that, only the first 40 bytes will be stored
+ * in the internal buffer.
+ * @warning Supplied len MUST be at least 40 bytes (IPv6 header length).
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error */
+int IPv6Header::storeRecvData(const u8 *buf, size_t len){
+ if(buf==NULL || len<IPv6_HEADER_LEN){
+ return OP_FAILURE;
+ }else{
+ this->reset(); /* Re-init the object, just in case the caller had used it already */
+ this->length=IPv6_HEADER_LEN;
+ memcpy(&(this->h), buf, IPv6_HEADER_LEN);
+ }
+ return OP_SUCCESS;
+} /* End of storeRecvData() */
+
+
+/* Returns a protocol identifier. This is used by packet parsing funtions
+ * that return linked lists of PacketElement objects, to determine the protocol
+ * the object represents. */
+int IPv6Header::protocol_id() const {
+ return HEADER_TYPE_IPv6;
+} /* End of protocol_id() */
+
+
+/** Determines if the data stored in the object after an storeRecvData() call
+ * is valid and safe to use. This mainly checks the length of the data but may
+ * also test the value of certain protocol fields to ensure their correctness.
+ * @return the length, in bytes, of the header, if its found to be valid or
+ * OP_FAILURE (-1) otherwise. */
+int IPv6Header::validate(){
+ if( this->length!=IPv6_HEADER_LEN)
+ return OP_FAILURE;
+ else
+ return IPv6_HEADER_LEN;
+} /* End of validate() */
+
+
+/** Prints the contents of the header and calls print() on the next protocol
+ * header in the chain (if there is any).
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error. */
+int IPv6Header::print(FILE *output, int detail) const {
+ static char ipstring[256];
+ memset(ipstring, 0, 256);
+ struct in6_addr addr;
+ char ipinfo[512] = ""; /* Temp info about IP. */
+
+ fprintf(output, "IPv6[");
+ this->getSourceAddress(&addr);
+ inet_ntop(AF_INET6, &addr, ipstring, sizeof(ipstring));
+ fprintf(output, "%s", ipstring);
+ fprintf(output, " >");
+ this->getDestinationAddress(&addr);
+ inet_ntop(AF_INET6, &addr, ipstring, sizeof(ipstring));
+ fprintf(output, " %s", ipstring);
+
+ /* Create a string with information relevant to the specified level of detail */
+ if( detail == PRINT_DETAIL_LOW ){
+ Snprintf(ipinfo, sizeof(ipinfo), "hlim=%d", this->getHopLimit());
+ }else if( detail == PRINT_DETAIL_MED ){
+ Snprintf(ipinfo, sizeof(ipinfo), "hlim=%d tclass=%d flow=%d",
+ this->getHopLimit(), this->getTrafficClass(), this->getFlowLabel() );
+ }else if( detail>=PRINT_DETAIL_HIGH ){
+ Snprintf(ipinfo, sizeof(ipinfo), "ver=%d hlim=%d tclass=%d flow=%d plen=%d nh=%d",
+ this->getVersion(), this->getHopLimit(), this->getTrafficClass(),
+ this->getFlowLabel(), this->getPayloadLength(), this->getNextHeader() );
+ }
+ fprintf(output, " %s]", ipinfo);
+ if(this->next!=NULL){
+ print_separator(output, detail);
+ next->print(output, detail);
+ }
+ return OP_SUCCESS;
+} /* End of print() */
+
+
+/******************************************************************************/
+/* PROTOCOL-SPECIFIC METHODS */
+/******************************************************************************/
+
+/** Set Version field (4 bits). */
+int IPv6Header::setVersion(u8 val){
+ union{
+ struct firstbyte{
+ #if WORDS_BIGENDIAN
+ u8 ver:4;
+ u8 tclass:4;
+ #else
+ u8 tclass:4;
+ u8 ver:4;
+ #endif
+ }halfbyte;
+ u8 fullbyte;
+ }header1stbyte;
+
+ header1stbyte.fullbyte = h.ip6_start[0];
+ header1stbyte.halfbyte.ver=val;
+ h.ip6_start[0]=header1stbyte.fullbyte;
+ return OP_SUCCESS;
+} /* End of setVersion() */
+
+
+/** Set Version field to value 6. */
+int IPv6Header::setVersion(){
+ this->setVersion(6);
+ return OP_SUCCESS;
+} /* End of setVersion() */
+
+
+/** Returns an 8bit number containing the value of the Version field. */
+u8 IPv6Header::getVersion() const {
+ union{
+ struct firstbyte{
+ #if WORDS_BIGENDIAN
+ u8 ver:4;
+ u8 tclass:4;
+ #else
+ u8 tclass:4;
+ u8 ver:4;
+ #endif
+ }halfbyte;
+ u8 fullbyte;
+ }header1stbyte;
+
+ header1stbyte.fullbyte = h.ip6_start[0];
+ return (u8)header1stbyte.halfbyte.ver;
+} /* End of getVersion() */
+
+
+int IPv6Header::setTrafficClass(u8 val){
+ union{
+ struct firstbyte{
+ #if WORDS_BIGENDIAN
+ u8 ver:4;
+ u8 tclass1:4;
+ #else
+ u8 tclass1:4;
+ u8 ver:4;
+ #endif
+ }halfbyte;
+ u8 fullbyte;
+ }header1stbyte;
+ union{
+ struct firstbyte{
+ #if WORDS_BIGENDIAN
+ u8 tclass2:4;
+ u8 flow:4;
+ #else
+ u8 flow:4;
+ u8 tclass2:4;
+ #endif
+ }halfbyte;
+ u8 fullbyte;
+ }header2ndbyte;
+
+ /* Store old contents */
+ header1stbyte.fullbyte = h.ip6_start[0];
+ header2ndbyte.fullbyte = h.ip6_start[1];
+
+ /* Fill the two 4bit halves */
+ header1stbyte.halfbyte.tclass1=val>>4;
+ header2ndbyte.halfbyte.tclass2=val;
+
+ /* Write the bytes back to the header */
+ h.ip6_start[0]=header1stbyte.fullbyte;
+ h.ip6_start[1]=header2ndbyte.fullbyte;
+
+ return OP_SUCCESS;
+} /* End of setTrafficClass() */
+
+
+u8 IPv6Header::getTrafficClass() const {
+ union{
+ struct firstbyte{
+ #if WORDS_BIGENDIAN
+ u8 ver:4;
+ u8 tclass1:4;
+ #else
+ u8 tclass1:4;
+ u8 ver:4;
+ #endif
+ }halfbyte;
+ u8 fullbyte;
+ }header1stbyte;
+ union{
+ struct firstbyte{
+ #if WORDS_BIGENDIAN
+ u8 tclass2:4;
+ u8 flow:4;
+ #else
+ u8 flow:4;
+ u8 tclass2:4;
+ #endif
+ }halfbyte;
+ u8 fullbyte;
+ }header2ndbyte;
+ union{
+ struct firstbyte{
+ #if WORDS_BIGENDIAN
+ u8 tclass1:4;
+ u8 tclass2:4;
+ #else
+ u8 tclass2:4;
+ u8 tclass1:4;
+ #endif
+ }halfbyte;
+ u8 fullbyte;
+ }finalbyte;
+
+ header1stbyte.fullbyte = h.ip6_start[0];
+ header2ndbyte.fullbyte = h.ip6_start[1];
+ finalbyte.halfbyte.tclass1=header1stbyte.halfbyte.tclass1;
+ finalbyte.halfbyte.tclass2=header2ndbyte.halfbyte.tclass2;
+ return finalbyte.fullbyte;
+} /* End of getTrafficClass() */
+
+
+int IPv6Header::setFlowLabel(u32 val){
+ u32 netbyte = htonl(val);
+ u8 *pnt=(u8*)&netbyte;
+ union{
+ struct firstbyte{
+ #if WORDS_BIGENDIAN
+ u8 tclass2:4;
+ u8 flow:4;
+ #else
+ u8 flow:4;
+ u8 tclass2:4;
+ #endif
+ }halfbyte;
+ u8 fullbyte;
+ }header2ndbyte;
+
+ header2ndbyte.fullbyte = h.ip6_start[1];
+ header2ndbyte.halfbyte.flow=pnt[1];
+ h.ip6_start[1]=header2ndbyte.fullbyte;
+ h.ip6_start[2]=pnt[2];
+ h.ip6_start[3]=pnt[3];
+ return OP_SUCCESS;
+} /* End of setFlowLabel() */
+
+
+u32 IPv6Header::getFlowLabel() const {
+ u32 hostbyte=0;
+ u8 *pnt=(u8*)&hostbyte;
+ union{
+ struct firstbyte{
+ #if WORDS_BIGENDIAN
+ u8 tclass2:4;
+ u8 flow:4;
+ #else
+ u8 flow:4;
+ u8 tclass2:4;
+ #endif
+ }halfbyte;
+ u8 fullbyte;
+ }header2ndbyte;
+
+ header2ndbyte.fullbyte = h.ip6_start[1];
+ pnt[0]=0;
+ pnt[1]=header2ndbyte.halfbyte.flow;
+ pnt[2]=h.ip6_start[2];
+ pnt[3]=h.ip6_start[3];
+ hostbyte=ntohl(hostbyte);
+ return hostbyte;
+} /* End of getFlowLabel() */
+
+
+int IPv6Header::setPayloadLength(u16 val){
+ this->h.ip6_len = htons(val);
+ return OP_SUCCESS;
+} /* End of setPayloadLength() */
+
+
+int IPv6Header::setPayloadLength(){
+ int otherslen=0;
+ if (next!=NULL)
+ otherslen=next->getLen();
+ setPayloadLength( otherslen );
+ return OP_SUCCESS;
+} /* End of setTotalLength() */
+
+
+u16 IPv6Header::getPayloadLength() const {
+ return ntohs(this->h.ip6_len);
+} /* End of getPayloadLength() */
+
+
+int IPv6Header::setNextHeader(u8 val){
+ this->h.ip6_nh = val;
+ return OP_SUCCESS;
+} /* End of setNextHeader() */
+
+
+u8 IPv6Header::getNextHeader() const {
+ return this->h.ip6_nh;
+} /* End of getNextHeader() */
+
+
+/** Sets field "next header" to the number that corresponds to the supplied
+ * protocol name. Currently only TCP, UDP and ICMP are supported. Any
+ * help to extend this functionality would be appreciated. For a list of all
+ * proto names and numbers check:
+ * http://www.iana.org/assignments/protocol-numbers/ */
+int IPv6Header::setNextHeader(const char *p){
+
+ if (p==NULL){
+ printf("setNextProto(): NULL pointer supplied\n");
+ return OP_FAILURE;
+ }
+ if( !strcasecmp(p, "TCP") )
+ setNextHeader(6); /* 6=IANA number for proto TCP */
+ else if( !strcasecmp(p, "UDP") )
+ setNextHeader(17); /* 17=IANA number for proto UDP */
+ else if( !strcasecmp(p, "ICMPv6"))
+ setNextHeader(58); /* 58=IANA number for proto ICMPv6 */
+ else
+ netutil_fatal("setNextProto(): Invalid protocol number\n");
+ return OP_SUCCESS;
+} /* End of setNextHeader() */
+
+
+int IPv6Header::setHopLimit(u8 val){
+ this->h.ip6_hopl = val;
+ return OP_SUCCESS;
+} /* End of setHopLimit() */
+
+
+u8 IPv6Header::getHopLimit() const {
+ return this->h.ip6_hopl;
+} /* End of getHopLimit() */
+
+
+int IPv6Header::setSourceAddress(u8 *val){
+ if(val==NULL)
+ netutil_fatal("setSourceAddress(): NULL value supplied.");
+ memcpy(this->h.ip6_src, val, 16);
+ return OP_SUCCESS;
+} /* End of setSourceAddress() */
+
+
+int IPv6Header::setSourceAddress(struct in6_addr val){
+ memcpy(this->h.ip6_src, val.s6_addr, 16);
+ return OP_SUCCESS;
+} /* End of setSourceAddress() */
+
+
+const u8 *IPv6Header::getSourceAddress() const {
+ return this->h.ip6_src;
+} /* End of getSourceAddress() */
+
+
+/** Returns source IPv6 address
+ * @warning Returned value is in NETWORK byte order. */
+struct in6_addr IPv6Header::getSourceAddress(struct in6_addr *result) const {
+ struct in6_addr myaddr;
+ memset(&myaddr, 0, sizeof(myaddr));
+ memcpy(myaddr.s6_addr, this->h.ip6_src, 16);
+
+ if(result!=NULL)
+ *result=myaddr;
+ return myaddr;
+} /* End of getSourceAddress() */
+
+
+int IPv6Header::setDestinationAddress(u8 *val){
+ if(val==NULL)
+ netutil_fatal("setDestinationAddress(): NULL value supplied.");
+ memcpy(this->h.ip6_dst, val, 16);
+ return OP_SUCCESS;
+} /* End of setDestinationAddress() */
+
+
+int IPv6Header::setDestinationAddress(struct in6_addr val){
+ memcpy(this->h.ip6_dst, val.s6_addr, 16);
+ return OP_SUCCESS;
+} /* End of setDestinationAddress() */
+
+
+/** Returns destination IPv6 address. */
+const u8 *IPv6Header::getDestinationAddress() const {
+ return this->h.ip6_dst;
+} /* End of getDestinationAddress() */
+
+
+/** Returns destination IPv6 address
+ * @warning Returned value is in NETWORK byte order. */
+struct in6_addr IPv6Header::getDestinationAddress(struct in6_addr *result) const {
+ struct in6_addr myaddr;
+ memset(&myaddr, 0, sizeof(myaddr));
+ memcpy(myaddr.s6_addr, this->h.ip6_dst, 16);
+
+ if(result!=NULL)
+ *result=myaddr;
+ return myaddr;
+} /* End of getDestinationAddress() */
+
+
+/** Returns the length of an IPv4 address. */
+u16 IPv6Header::getAddressLength() const {
+ return 16;
+} /* End of getAddressLength()*/
+
diff --git a/libnetutil/IPv6Header.h b/libnetutil/IPv6Header.h
new file mode 100644
index 0000000..4932923
--- /dev/null
+++ b/libnetutil/IPv6Header.h
@@ -0,0 +1,172 @@
+/***************************************************************************
+ * IPv6Header.h -- The IPv6Header Class represents an IPv6 datagram. It *
+ * contains methods to set any header field. In general, these methods do *
+ * error checkings and byte order conversion. *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#ifndef IPV6HEADER_H
+#define IPV6HEADER_H 1
+
+#include "NetworkLayerElement.h"
+
+#define IPv6_HEADER_LEN 40
+
+/* Default header values */
+#define IPv6_DEFAULT_TCLASS 0
+#define IPv6_DEFAULT_FLABEL 0
+#define IPv6_DEFAULT_HOPLIM 64
+#define IPv6_DEFAULT_NXTHDR 6 /* TCP */
+
+class IPv6Header : public NetworkLayerElement {
+
+ private:
+
+ /* IPv6 Header 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 2
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ |Version| Traffic Class | Flow Label |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Payload Length | Next Header | Hop Limit |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ +-- --+
+ | |
+ +-- Source Address --+
+ | |
+ +-- --+
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ +-- --+
+ | |
+ +-- Destination Address --+
+ | |
+ +-- --+
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+ struct nping_ipv6_hdr {
+ u8 ip6_start[4]; /* Version, Traffic and Flow */
+ u16 ip6_len; /* Payload length */
+ u8 ip6_nh; /* Next Header */
+ u8 ip6_hopl; /* Hop Limit */
+ u8 ip6_src[16]; /* Source IP Address */
+ u8 ip6_dst[16]; /* Destination IP Address */
+ }__attribute__((__packed__));
+
+ typedef struct nping_ipv6_hdr nping_ipv6_hdr_t;
+
+ nping_ipv6_hdr_t h;
+
+ public:
+
+ /* Misc */
+ IPv6Header();
+ ~IPv6Header();
+ void reset();
+ u8 *getBufferPointer();
+ int storeRecvData(const u8 *buf, size_t len);
+ int protocol_id() const;
+ int validate();
+ int print(FILE *output, int detail) const;
+
+ /* IP version */
+ int setVersion();
+ int setVersion(u8 val);
+ u8 getVersion() const;
+
+ /* Traffic class */
+ int setTrafficClass(u8 val);
+ u8 getTrafficClass() const;
+
+ /* Flow Label */
+ int setFlowLabel(u32 val);
+ u32 getFlowLabel() const;
+
+ /* Payload Length */
+ int setPayloadLength(u16 val);
+ int setPayloadLength();
+ u16 getPayloadLength() const;
+
+ /* Next Header */
+ int setNextHeader(u8 val);
+ int setNextHeader(const char *p);
+ u8 getNextHeader() const;
+
+ /* Hop Limit */
+ int setHopLimit(u8 val);
+ u8 getHopLimit() const;
+
+ /* Source Address */
+ int setSourceAddress(u8 *val);
+ int setSourceAddress(struct in6_addr val);
+ const u8 *getSourceAddress() const;
+ struct in6_addr getSourceAddress(struct in6_addr *result) const;
+
+ /* Destination Address*/
+ int setDestinationAddress(u8 *val);
+ int setDestinationAddress(struct in6_addr val);
+ const u8 *getDestinationAddress() const;
+ struct in6_addr getDestinationAddress(struct in6_addr *result) const;
+
+ u16 getAddressLength() const;
+};
+
+#endif
diff --git a/libnetutil/Makefile.in b/libnetutil/Makefile.in
new file mode 100644
index 0000000..c7deb92
--- /dev/null
+++ b/libnetutil/Makefile.in
@@ -0,0 +1,41 @@
+top_srcdir = @top_srcdir@
+srcdir = @srcdir@
+
+CXX = @CXX@
+CXXFLAGS = @CXXFLAGS@
+CPPFLAGS = @CPPFLAGS@ $(DEFS)
+DEFS = @DEFS@
+DEFS += -D_FORTIFY_SOURCE=2
+AR = ar
+RANLIB = @RANLIB@
+
+LIBDNETDIR = @LIBDNETDIR@
+LIBPCAPDIR = @libpcapdir@
+
+TARGET = libnetutil.a
+
+SRCS = $(srcdir)/netutil.cc $(srcdir)/PacketElement.cc $(srcdir)/NetworkLayerElement.cc $(srcdir)/ARPHeader.cc $(srcdir)/PacketElement.cc $(srcdir)/NetworkLayerElement.cc $(srcdir)/TransportLayerElement.cc $(srcdir)/ARPHeader.cc $(srcdir)/EthernetHeader.cc $(srcdir)/ICMPv4Header.cc $(srcdir)/ICMPv6Header.cc $(srcdir)/IPv4Header.cc $(srcdir)/IPv6Header.cc $(srcdir)/TCPHeader.cc $(srcdir)/UDPHeader.cc $(srcdir)/RawData.cc $(srcdir)/HopByHopHeader.cc $(srcdir)/DestOptsHeader.cc $(srcdir)/FragmentHeader.cc $(srcdir)/RoutingHeader.cc $(srcdir)/PacketParser.cc
+OBJS = netutil.o PacketElement.o NetworkLayerElement.o TransportLayerElement.o ARPHeader.o EthernetHeader.o ICMPv4Header.o ICMPv6Header.o IPv4Header.o IPv6Header.o TCPHeader.o UDPHeader.o RawData.o HopByHopHeader.o DestOptsHeader.o FragmentHeader.o RoutingHeader.o PacketParser.o
+
+all: $(TARGET)
+
+$(TARGET): $(OBJS)
+ rm -f $@
+ $(AR) cr $@ $(OBJS)
+ $(RANLIB) $@
+
+clean:
+ rm -f $(OBJS) $(TARGET)
+
+distclean: clean
+ rm -rf Makefile makefile.dep
+
+Makefile: Makefile.in
+ cd $(top_srcdir) && ./config.status
+
+.cc.o:
+ $(CXX) -c $(CPPFLAGS) $(CXXFLAGS) $< -o $@
+
+makefile.dep:
+ $(CXX) -MM $(CPPFLAGS) $(SRCS) > $@
+-include makefile.dep
diff --git a/libnetutil/NetworkLayerElement.cc b/libnetutil/NetworkLayerElement.cc
new file mode 100644
index 0000000..6a85489
--- /dev/null
+++ b/libnetutil/NetworkLayerElement.cc
@@ -0,0 +1,62 @@
+/***************************************************************************
+ * NetworkLayerElement.cc -- Class NetworkLayerElement is a generic class *
+ * that represents a network layer protocol header. Classes like IPv4Header*
+ * or IPv6Header inherit from it. *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#include "NetworkLayerElement.h"
diff --git a/libnetutil/NetworkLayerElement.h b/libnetutil/NetworkLayerElement.h
new file mode 100644
index 0000000..eb185ad
--- /dev/null
+++ b/libnetutil/NetworkLayerElement.h
@@ -0,0 +1,92 @@
+/***************************************************************************
+ * NetworkLayerElement.h -- Class NetworkLayerElement is a generic class *
+ * that represents a network layer protocol header. Classes like IPv4Header*
+ * or IPv6Header inherit from it. *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#ifndef NETWORKLAYERELEMENT_H
+#define NETWORKLAYERELEMENT_H 1
+
+#include "PacketElement.h"
+
+/// class NetworkLayerElement -
+class NetworkLayerElement : public PacketElement {
+
+ public:
+ virtual u16 getAddressLength() const{
+ return 0;
+ }
+
+ virtual const u8 *getSourceAddress() const{
+ return NULL;
+ }
+
+ virtual const u8 *getDestinationAddress() const{
+ return NULL;
+ }
+
+ virtual int setNextHeader(u8 val){
+ return 0;
+ }
+
+ virtual u8 getNextHeader() const{
+ return 0;
+ }
+};
+
+#endif
diff --git a/libnetutil/PacketElement.cc b/libnetutil/PacketElement.cc
new file mode 100644
index 0000000..61c9b74
--- /dev/null
+++ b/libnetutil/PacketElement.cc
@@ -0,0 +1,70 @@
+/***************************************************************************
+ * PacketElement.cc -- The PacketElement Class is a generic class that *
+ * represents a protocol header or a part of a network packet. Many other *
+ * classes inherit from it (NetworkLayerElement, TransportLayerElement, *
+ * etc). *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#include "PacketElement.h"
+
+PacketElement::PacketElement(){
+ next=NULL; /* It's very important these get initialized to NULL */
+ prev=NULL;
+ length=0;
+} /* End of PacketElement constructor */
+
diff --git a/libnetutil/PacketElement.h b/libnetutil/PacketElement.h
new file mode 100644
index 0000000..834956c
--- /dev/null
+++ b/libnetutil/PacketElement.h
@@ -0,0 +1,268 @@
+/***************************************************************************
+ * PacketElement.h -- The PacketElement Class is a generic class that *
+ * represents a protocol header or a part of a network packet. Many other *
+ * classes inherit from it (NetworkLayerElement, TransportLayerElement, *
+ * etc). *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#ifndef PACKETELEMENT_H
+#define PACKETELEMENT_H 1
+
+#include "nbase.h"
+#include "netutil.h"
+
+#define HEADER_TYPE_IPv6_HOPOPT 0 /* IPv6 Hop-by-Hop Option */
+#define HEADER_TYPE_ICMPv4 1 /* ICMP Internet Control Message */
+#define HEADER_TYPE_IGMP 2 /* IGMP Internet Group Management */
+#define HEADER_TYPE_IPv4 4 /* IPv4 IPv4 encapsulation */
+#define HEADER_TYPE_TCP 6 /* TCP Transmission Control */
+#define HEADER_TYPE_EGP 8 /* EGP Exterior Gateway Protocol */
+#define HEADER_TYPE_UDP 17 /* UDP User Datagram */
+#define HEADER_TYPE_IPv6 41 /* IPv6 IPv6 encapsulation */
+#define HEADER_TYPE_IPv6_ROUTE 43 /* IPv6-Route Routing Header for IPv6 */
+#define HEADER_TYPE_IPv6_FRAG 44 /* IPv6-Frag Fragment Header for IPv6 */
+#define HEADER_TYPE_GRE 47 /* GRE General Routing Encapsulation */
+#define HEADER_TYPE_ESP 50 /* ESP Encap Security Payload */
+#define HEADER_TYPE_AH 51 /* AH Authentication Header */
+#define HEADER_TYPE_ICMPv6 58 /* IPv6-ICMP ICMP for IPv6 */
+#define HEADER_TYPE_IPv6_NONXT 59 /* IPv6-NoNxt No Next Header for IPv6 */
+#define HEADER_TYPE_IPv6_OPTS 60 /* IPv6-Opts IPv6 Destination Options */
+#define HEADER_TYPE_EIGRP 88 /* EIGRP */
+#define HEADER_TYPE_ETHERNET 97 /* Ethernet */
+#define HEADER_TYPE_L2TP 115 /* L2TP Layer Two Tunneling Protocol */
+#define HEADER_TYPE_SCTP 132 /* SCTP Stream Control Transmission P. */
+#define HEADER_TYPE_IPv6_MOBILE 135 /* Mobility Header */
+#define HEADER_TYPE_MPLS_IN_IP 137 /* MPLS-in-IP */
+#define HEADER_TYPE_ARP 2054 /* ARP Address Resolution Protocol */
+#define HEADER_TYPE_ICMPv6_OPTION 9997 /* ICMPv6 option */
+#define HEADER_TYPE_NEP 9998 /* Nping Echo Protocol */
+#define HEADER_TYPE_RAW_DATA 9999 /* Raw unknown data */
+
+#define PRINT_DETAIL_LOW 1
+#define PRINT_DETAIL_MED 2
+#define PRINT_DETAIL_HIGH 3
+
+#define DEFAULT_PRINT_DETAIL (PRINT_DETAIL_LOW)
+#define DEFAULT_PRINT_DESCRIPTOR stdout
+
+class PacketElement {
+
+ protected:
+
+ int length;
+ PacketElement *next; /**< Next PacketElement (next proto header) */
+ PacketElement *prev; /**< Prev PacketElement (previous proto header) */
+
+ public:
+
+ PacketElement();
+
+ virtual ~PacketElement(){
+
+ } /* End of PacketElement destructor */
+
+ /** This function MUST be overwritten on ANY class that inherits from
+ * this one. Otherwise getBinaryBuffer will fail */
+ virtual u8 * getBufferPointer(){
+ netutil_fatal("getBufferPointer(): Attempting to use superclass PacketElement method.\n");
+ return NULL;
+ } /* End of getBufferPointer() */
+
+
+ /** Returns a buffer that contains the header of the packet + all the
+ * lower level headers and payload. Returned buffer should be ok to be
+ * passes to a send() call to be transferred trough a socket.
+ * @return a pointer to a free()able buffer that contains packet's binary
+ * data.
+ * @warning If there are linked elements, their getBinaryBuffer() method
+ * will be called recursively and the buffers that they return WILL be
+ * free()d as soon as we copy the data in our own allocated buffer.
+ * @warning Calls to this method may not ve very efficient since they
+ * always involved a few malloc()s and free()s. If you want efficiency
+ * use dumpToBinaryBuffer(); */
+ virtual u8 * getBinaryBuffer(){
+ u8 *ourbuff=NULL;
+ u8 *othersbuff=NULL;
+ u8 *totalbuff=NULL;
+ long otherslen=0;
+
+ /* Get our own buffer address */
+ if ( (ourbuff=getBufferPointer()) == NULL ){
+ netutil_fatal("getBinaryBuffer(): Couldn't get own data pointer\n");
+ }
+ if( next != NULL ){ /* There is some other packet element */
+ othersbuff = next->getBinaryBuffer();
+ otherslen=next->getLen();
+ totalbuff=(u8 *)safe_zalloc(otherslen + length);
+ memcpy(totalbuff, ourbuff, length);
+ memcpy(totalbuff+length, othersbuff, otherslen);
+ free(othersbuff);
+ }else{
+ totalbuff=(u8 *)safe_zalloc(length);
+ memcpy(totalbuff, ourbuff, length);
+ }
+ return totalbuff;
+ } /* End of getBinaryBuffer() */
+
+
+ virtual int dumpToBinaryBuffer(u8* dst, int maxlen){
+ u8 *ourbuff=NULL;
+ long ourlength=0;
+ /* Get our own buffer address and length */
+ if ( (ourbuff=getBufferPointer()) == NULL || (ourlength=this->length) < 0 )
+ netutil_fatal("getBinaryBuffer(): Couldn't get own data pointer\n");
+ /* Copy our part of the buffer */
+ if ( maxlen < ourlength )
+ netutil_fatal("getBinaryBuffer(): Packet exceeds maximum length %d\n", maxlen);
+ memcpy( dst, ourbuff, ourlength);
+ /* If there are more elements, tell them to copy their part */
+ if( next!= NULL ){
+ next->dumpToBinaryBuffer(dst+ourlength, maxlen-ourlength);
+ }
+ return this->getLen();
+ } /* End of dumpToBinaryBuffer() */
+
+
+ /** Does the same as the previous one but it stores the length of the
+ * return buffer on the memory pointed by the supplied int pointer. */
+ virtual u8 * getBinaryBuffer(int *len){
+ u8 *buff = getBinaryBuffer();
+ if( len != NULL )
+ *len = getLen();
+ return buff;
+ } /* End of getBinaryBuffer() */
+
+
+ /** Returns the length of this PacketElement + the length of all the
+ * PacketElements that are next to it (are linked trough the "next"
+ * attribute). So for example, if we have IPv4Header p1, linked to
+ * a TCPHeader p2, representing a simple TCP SYN with no options,
+ * a call to p1.getLen() will return 20 (IP header with no options) + 20
+ * (TCP header with no options) = 40 bytes. */
+ int getLen() const {
+ /* If we have some other packet element linked, get its length */
+ if (next!=NULL)
+ return length + next->getLen();
+ else
+ return length;
+ } /* End of getLen() */
+
+
+ /** Returns the address of the next PacketElement that is linked to this */
+ virtual PacketElement *getNextElement() const {
+ return next;
+ } /* End of getNextElement() */
+
+
+ /** Links current object with the next header in the protocol chain. Note
+ * that this method also links the next element with this one, calling
+ * setPrevElement(). */
+ virtual int setNextElement(PacketElement *n){
+ next=n;
+ if(next!=NULL)
+ next->setPrevElement(this);
+ return OP_SUCCESS;
+ } /* End of setNextElement() */
+
+ /** Sets attribute prev with the supplied pointer value.
+ * @warning Supplied pointer must point to a PacketElement object or
+ * an object that inherits from it. */
+ virtual int setPrevElement(PacketElement *n){
+ this->prev=n;
+ return OP_SUCCESS;
+ } /* End of setPrevElement() */
+
+
+ /** Returns the address of the previous PacketElement that is linked to
+ * this one.
+ * @warning In many cases this function will return NULL since there is
+ * a high probability that the user of this class does not link
+ * PacketElements in both directions. Normally one would set attribute
+ * "next" of an IPHeader object to the TCPHeader that follows it, but
+ * not the other way around. */
+ virtual PacketElement *getPrevElement(){
+ return prev;
+ } /* End of getPrevElement() */
+
+ /** This method should be overwritten by any class that inherits from
+ * PacketElement. It should print the object contents and then call
+ * this->next->print(), providing this->next!=NULL */
+ virtual int print(FILE *output, int detail) const {
+ if(this->next!=NULL)
+ this->next->print(output, detail);
+ return OP_SUCCESS;
+ } /* End of printf() */
+
+ virtual int print() const {
+ return print(DEFAULT_PRINT_DESCRIPTOR, DEFAULT_PRINT_DETAIL);
+ }
+
+ virtual int print(int detail) const {
+ return print(DEFAULT_PRINT_DESCRIPTOR, detail);
+ }
+
+ virtual void print_separator(FILE *output, int detail) const {
+ fprintf(output, " ");
+ }
+
+ /* Returns the type of protocol an object represents. This method MUST
+ * be overwritten by all children. */
+ virtual int protocol_id() const = 0;
+};
+
+#endif
diff --git a/libnetutil/PacketParser.cc b/libnetutil/PacketParser.cc
new file mode 100644
index 0000000..01c661b
--- /dev/null
+++ b/libnetutil/PacketParser.cc
@@ -0,0 +1,1789 @@
+/***************************************************************************
+ * PacketParser.cc -- The PacketParser Class offers methods to parse *
+ * received network packets. Its main purpose is to facilitate the *
+ * conversion of raw sequences of bytes into chains of objects of the *
+ * PacketElement family. *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+ /* This code was originally part of the Nping tool. */
+
+#include "PacketParser.h"
+#include <assert.h>
+
+#define PKTPARSERDEBUG false
+
+PacketParser::PacketParser() {
+ this->reset();
+} /* End of PacketParser constructor */
+
+
+PacketParser::~PacketParser() {
+
+} /* End of PacketParser destructor */
+
+
+/** Sets every attribute to its default value- */
+void PacketParser::reset() {
+
+} /* End of PacketParser destructor */
+
+
+const char *PacketParser::header_type2string(int val){
+ header_type_string_t header_types[]={
+ {HEADER_TYPE_IPv6_HOPOPT, "IPv6 Hop-by-Hop"},
+ {HEADER_TYPE_ICMPv4,"ICMPv4"},
+ {HEADER_TYPE_IGMP,"IGMP"},
+ {HEADER_TYPE_IPv4,"IPv4"},
+ {HEADER_TYPE_TCP,"TCP"},
+ {HEADER_TYPE_EGP,"EGP"},
+ {HEADER_TYPE_UDP,"UDP"},
+ {HEADER_TYPE_IPv6,"IPv6"},
+ {HEADER_TYPE_IPv6_ROUTE,"IPv6-Route"},
+ {HEADER_TYPE_IPv6_FRAG,"IPv6-Frag"},
+ {HEADER_TYPE_GRE,"GRE"},
+ {HEADER_TYPE_ESP,"ESP"},
+ {HEADER_TYPE_AH,"AH"},
+ {HEADER_TYPE_ICMPv6,"ICMPv6"},
+ {HEADER_TYPE_IPv6_NONXT,"IPv6-NoNxt"},
+ {HEADER_TYPE_IPv6_OPTS,"IPv6-Opts"},
+ {HEADER_TYPE_EIGRP,"EIGRP"},
+ {HEADER_TYPE_ETHERNET,"Ethernet"},
+ {HEADER_TYPE_L2TP,"L2TP"},
+ {HEADER_TYPE_SCTP,"SCTP"},
+ {HEADER_TYPE_IPv6_MOBILE,"Mobility Header"},
+ {HEADER_TYPE_MPLS_IN_IP,"MPLS-in-IP"},
+ {HEADER_TYPE_ARP,"ARP"},
+ {HEADER_TYPE_RAW_DATA,"Raw Data"},
+ {0,NULL}
+ };
+ int i=0;
+ for(i=0; header_types[i].str!=NULL; i++ ){
+ if((int)header_types[i].type==val)
+ return header_types[i].str;
+ }
+ return NULL;
+} /* End of header_type2string() */
+
+
+
+#define MAX_HEADERS_IN_PACKET 32
+pkt_type_t *PacketParser::parse_packet(const u8 *pkt, size_t pktlen, bool eth_included){
+ if(PKTPARSERDEBUG)printf("%s(%p, %lu)\n", __func__, pkt, (long unsigned)pktlen);
+ static pkt_type_t this_packet[MAX_HEADERS_IN_PACKET+1]; /* Packet structure array */
+ u8 current_header=0; /* Current array position of "this_packet" */
+ const u8 *curr_pkt=pkt; /* Pointer to current part of the packet */
+ size_t curr_pktlen=pktlen; /* Remaining packet length */
+ int ethlen=0, arplen=0; /* Aux length variables: link layer */
+ int iplen=0,ip6len=0; /* Aux length variables: network layer */
+ int tcplen=0,udplen=0,icmplen=0; /* Aux length variables: transport layer */
+ int exthdrlen=0; /* Aux length variables: extension headers */
+ int next_layer=0; /* Next header type to process */
+ int expected=0; /* Next protocol expected */
+ bool finished=false; /* Loop breaking flag */
+ bool unknown_hdr=false; /* Indicates unknown header found */
+ IPv4Header ip4;
+ IPv6Header ip6;
+ TCPHeader tcp;
+ UDPHeader udp;
+ ICMPv4Header icmp4;
+ ICMPv6Header icmp6;
+ EthernetHeader eth;
+ DestOptsHeader ext_dopts;
+ FragmentHeader ext_frag;
+ HopByHopHeader ext_hopt;
+ RoutingHeader ext_routing;
+ ARPHeader arp;
+ memset(this_packet, 0, sizeof(this_packet));
+
+ /* Decide which layer we have to start from */
+ if( eth_included ){
+ next_layer=LINK_LAYER;
+ expected=HEADER_TYPE_ETHERNET;
+ }else{
+ next_layer=NETWORK_LAYER;
+ }
+
+ /* Header processing loop */
+ while(!finished && curr_pktlen>0 && current_header<MAX_HEADERS_IN_PACKET){
+ /* Ethernet and ARP headers ***********************************************/
+ if(next_layer==LINK_LAYER ){
+ if(PKTPARSERDEBUG)puts("Next Layer=Link");
+ if(expected==HEADER_TYPE_ETHERNET){
+ if(PKTPARSERDEBUG)puts("Expected Layer=Ethernet");
+ if(eth.storeRecvData(curr_pkt, curr_pktlen)==OP_FAILURE){
+ unknown_hdr=true;
+ break;
+ }
+ if( (ethlen=eth.validate())==OP_FAILURE){
+ unknown_hdr=true;
+ break;
+ }
+ /* Determine next header type */
+ switch( eth.getEtherType() ){
+ case ETHTYPE_IPV4:
+ expected=HEADER_TYPE_IPv4;
+ next_layer=NETWORK_LAYER;
+ break;
+ case ETHTYPE_IPV6:
+ expected=HEADER_TYPE_IPv6;
+ next_layer=NETWORK_LAYER;
+ break;
+ case ETHTYPE_ARP:
+ next_layer=LINK_LAYER;
+ expected=HEADER_TYPE_ARP;
+ break;
+ default:
+ next_layer=APPLICATION_LAYER;
+ expected=HEADER_TYPE_RAW_DATA;
+ break;
+ }
+ this_packet[current_header].length=ethlen;
+ this_packet[current_header++].type=HEADER_TYPE_ETHERNET;
+ eth.reset();
+ curr_pkt+=ethlen;
+ curr_pktlen-=ethlen;
+ }else if(expected==HEADER_TYPE_ARP){
+ if(PKTPARSERDEBUG)puts("Expected Layer=ARP");
+ if(arp.storeRecvData(curr_pkt, curr_pktlen)==OP_FAILURE){
+ unknown_hdr=true;
+ break;
+ }
+ if( (arplen=arp.validate())==OP_FAILURE){
+ unknown_hdr=true;
+ break;
+ }
+ this_packet[current_header].length=arplen;
+ this_packet[current_header++].type=HEADER_TYPE_ARP;
+ arp.reset();
+ curr_pkt+=arplen;
+ curr_pktlen-=arplen;
+ if(curr_pktlen>0){
+ next_layer=APPLICATION_LAYER;
+ expected=HEADER_TYPE_RAW_DATA;
+ }else{
+ finished=true;
+ }
+ }else{
+ assert(finished==true);
+ }
+ /* IPv4 and IPv6 headers **************************************************/
+ }else if(next_layer==NETWORK_LAYER){
+ if(PKTPARSERDEBUG)puts("Next Layer=Network");
+ /* Determine IP version */
+ if (ip4.storeRecvData(curr_pkt, curr_pktlen)==OP_FAILURE){
+ unknown_hdr=true;
+ break;
+ }
+
+ /* IP version 4 ---------------------------------*/
+ if(ip4.getVersion()==4){
+ if( (iplen=ip4.validate())==OP_FAILURE){
+ unknown_hdr=true;
+ break;
+ }
+ /* Determine next header type */
+ switch(ip4.getNextProto()){
+ case HEADER_TYPE_ICMPv4:
+ next_layer=TRANSPORT_LAYER;
+ expected=HEADER_TYPE_ICMPv4;
+ break;
+ case HEADER_TYPE_IPv4: /* IP in IP */
+ next_layer=NETWORK_LAYER;
+ expected=HEADER_TYPE_IPv4;
+ break;
+ case HEADER_TYPE_TCP:
+ next_layer=TRANSPORT_LAYER;
+ expected=HEADER_TYPE_TCP;
+ break;
+ case HEADER_TYPE_UDP:
+ next_layer=TRANSPORT_LAYER;
+ expected=HEADER_TYPE_UDP;
+ break;
+ case HEADER_TYPE_IPv6: /* IPv6 in IPv4 */
+ next_layer=NETWORK_LAYER;
+ expected=HEADER_TYPE_IPv6;
+ break;
+ default:
+ next_layer=APPLICATION_LAYER;
+ expected=HEADER_TYPE_RAW_DATA;
+ break;
+ }
+ this_packet[current_header].length=iplen;
+ this_packet[current_header++].type=HEADER_TYPE_IPv4;
+ ip4.reset();
+ curr_pkt+=iplen;
+ curr_pktlen-=iplen;
+ /* IP version 6 ---------------------------------*/
+ }else if(ip4.getVersion()==6){
+ ip4.reset();
+ if (ip6.storeRecvData(curr_pkt, curr_pktlen)==OP_FAILURE){
+ unknown_hdr=true;
+ break;
+ }
+ if( (ip6len=ip6.validate())==OP_FAILURE ){
+ unknown_hdr=true;
+ break;
+ }
+ switch( ip6.getNextHeader() ){
+ case HEADER_TYPE_ICMPv6:
+ next_layer=TRANSPORT_LAYER;
+ expected=HEADER_TYPE_ICMPv6;
+ break;
+ case HEADER_TYPE_IPv4: /* IPv4 in IPv6 */
+ next_layer=NETWORK_LAYER;
+ expected=HEADER_TYPE_IPv4;
+ break;
+ case HEADER_TYPE_TCP:
+ next_layer=TRANSPORT_LAYER;
+ expected=HEADER_TYPE_TCP;
+ break;
+ case HEADER_TYPE_UDP:
+ next_layer=TRANSPORT_LAYER;
+ expected=HEADER_TYPE_UDP;
+ break;
+ case HEADER_TYPE_IPv6: /* IPv6 in IPv6 */
+ next_layer=NETWORK_LAYER;
+ expected=HEADER_TYPE_IPv6;
+ break;
+ case HEADER_TYPE_IPv6_HOPOPT:
+ next_layer=EXTHEADERS_LAYER;
+ expected=HEADER_TYPE_IPv6_HOPOPT;
+ break;
+ case HEADER_TYPE_IPv6_OPTS:
+ next_layer=EXTHEADERS_LAYER;
+ expected=HEADER_TYPE_IPv6_OPTS;
+ break;
+ case HEADER_TYPE_IPv6_ROUTE:
+ next_layer=EXTHEADERS_LAYER;
+ expected=HEADER_TYPE_IPv6_ROUTE;
+ break;
+ case HEADER_TYPE_IPv6_FRAG:
+ next_layer=EXTHEADERS_LAYER;
+ expected=HEADER_TYPE_IPv6_FRAG;
+ break;
+ default:
+ next_layer=APPLICATION_LAYER;
+ expected=HEADER_TYPE_RAW_DATA;
+ break;
+ }
+ this_packet[current_header].length=ip6len;
+ this_packet[current_header++].type=HEADER_TYPE_IPv6;
+ ip6.reset();
+ curr_pkt+=ip6len;
+ curr_pktlen-=ip6len;
+ /* Bogus IP version -----------------------------*/
+ }else{
+ /* Wrong IP version, treat as raw data. */
+ next_layer=APPLICATION_LAYER;
+ expected=HEADER_TYPE_RAW_DATA;
+ }
+ /* TCP, UDP, ICMPv4 and ICMPv6 headers ************************************/
+ }else if(next_layer==TRANSPORT_LAYER){
+ if(PKTPARSERDEBUG)puts("Next Layer=Transport");
+ if(expected==HEADER_TYPE_TCP){
+ if(PKTPARSERDEBUG)puts("Expected Layer=TCP");
+ if(tcp.storeRecvData(curr_pkt, curr_pktlen)==OP_FAILURE ){
+ unknown_hdr=true;
+ break;
+ }
+ if( (tcplen=tcp.validate())==OP_FAILURE){
+ unknown_hdr=true;
+ break;
+ }
+ expected=HEADER_TYPE_RAW_DATA;
+ this_packet[current_header].length=tcplen;
+ this_packet[current_header++].type=HEADER_TYPE_TCP;
+ tcp.reset();
+ curr_pkt+=tcplen;
+ curr_pktlen-=tcplen;
+ next_layer=APPLICATION_LAYER;
+ }else if(expected==HEADER_TYPE_UDP){
+ if(PKTPARSERDEBUG)puts("Expected Layer=UDP");
+ if(udp.storeRecvData(curr_pkt, curr_pktlen)==OP_FAILURE ){
+ unknown_hdr=true;
+ break;
+ }
+ if( (udplen=udp.validate())==OP_FAILURE){
+ unknown_hdr=true;
+ break;
+ }
+ expected=HEADER_TYPE_RAW_DATA;
+ this_packet[current_header].length=udplen;
+ this_packet[current_header++].type=HEADER_TYPE_UDP;
+ udp.reset();
+ curr_pkt+=udplen;
+ curr_pktlen-=udplen;
+ next_layer=APPLICATION_LAYER;
+ }else if(expected==HEADER_TYPE_ICMPv4){
+ if(PKTPARSERDEBUG)puts("Expected Layer=ICMPv4");
+ if(icmp4.storeRecvData(curr_pkt, curr_pktlen)==OP_FAILURE ){
+ unknown_hdr=true;
+ break;
+ }
+ if( (icmplen=icmp4.validate())==OP_FAILURE){
+ unknown_hdr=true;
+ break;
+ }
+ switch( icmp4.getType() ){
+ /* Types that include an IPv4 packet as payload */
+ case ICMP_UNREACH:
+ case ICMP_TIMXCEED:
+ case ICMP_PARAMPROB:
+ case ICMP_SOURCEQUENCH:
+ case ICMP_REDIRECT:
+ next_layer=NETWORK_LAYER;
+ expected=HEADER_TYPE_IPv4;
+ break;
+ /* ICMP types that include misc payloads (or no payload) */
+ default:
+ expected=HEADER_TYPE_RAW_DATA;
+ next_layer=APPLICATION_LAYER;
+ break;
+ }
+ this_packet[current_header].length=icmplen;
+ this_packet[current_header++].type=HEADER_TYPE_ICMPv4;
+ icmp4.reset();
+ curr_pkt+=icmplen;
+ curr_pktlen-=icmplen;
+ }else if(expected==HEADER_TYPE_ICMPv6){
+ if(PKTPARSERDEBUG)puts("Expected Layer=ICMPv6");
+ if(icmp6.storeRecvData(curr_pkt, curr_pktlen)==OP_FAILURE){
+ unknown_hdr=true;
+ break;
+ }
+ if( (icmplen=icmp6.validate())==OP_FAILURE){
+ unknown_hdr=true;
+ break;
+ }
+ switch( icmp6.getType() ){
+ /* Types that include an IPv6 packet as payload */
+ case ICMPv6_UNREACH:
+ case ICMPv6_PKTTOOBIG:
+ case ICMPv6_TIMXCEED:
+ case ICMPv6_PARAMPROB:
+ next_layer=NETWORK_LAYER;
+ expected=HEADER_TYPE_IPv6;
+ break;
+ /* ICMPv6 types that include misc payloads (or no payload) */
+ default:
+ expected=HEADER_TYPE_RAW_DATA;
+ next_layer=APPLICATION_LAYER;
+ break;
+ }
+ this_packet[current_header].length=icmplen;
+ this_packet[current_header++].type=HEADER_TYPE_ICMPv6;
+ icmp6.reset();
+ curr_pkt+=icmplen;
+ curr_pktlen-=icmplen;
+ }else{
+ /* Wrong application layer protocol, treat as raw data. */
+ next_layer=APPLICATION_LAYER;
+ expected=HEADER_TYPE_RAW_DATA;
+ }
+
+ /* IPv6 Extension Headers */
+ }else if(next_layer==EXTHEADERS_LAYER){
+ if(PKTPARSERDEBUG)puts("Next Layer=ExtHdr");
+ u8 ext_next=0;
+ /* Hop-by-Hop Options */
+ if(expected==HEADER_TYPE_IPv6_HOPOPT){
+ if(PKTPARSERDEBUG)puts("Expected=Hopt");
+ if(ext_hopt.storeRecvData(curr_pkt, curr_pktlen)==OP_FAILURE ){
+ unknown_hdr=true;
+ break;
+ }
+ if( (exthdrlen=ext_hopt.validate())==OP_FAILURE){
+ unknown_hdr=true;
+ break;
+ }
+ ext_next=ext_hopt.getNextHeader();
+ ext_hopt.reset();
+ /* Routing Header */
+ }else if(expected==HEADER_TYPE_IPv6_ROUTE){
+ if(PKTPARSERDEBUG)puts("Expected=Route");
+ if(ext_routing.storeRecvData(curr_pkt, curr_pktlen)==OP_FAILURE ){
+ unknown_hdr=true;
+ break;
+ }
+ if( (exthdrlen=ext_routing.validate())==OP_FAILURE){
+ unknown_hdr=true;
+ break;
+ }
+ ext_next=ext_routing.getNextHeader();
+ ext_routing.reset();
+ /* Fragmentation Header */
+ }else if(expected==HEADER_TYPE_IPv6_FRAG){
+ if(PKTPARSERDEBUG)puts("Expected=Frag");
+ if(ext_frag.storeRecvData(curr_pkt, curr_pktlen)==OP_FAILURE ){
+ unknown_hdr=true;
+ break;
+ }
+ if( (exthdrlen=ext_frag.validate())==OP_FAILURE){
+ unknown_hdr=true;
+ break;
+ }
+ ext_next=ext_frag.getNextHeader();
+ ext_frag.reset();
+ /* Destination Options Header */
+ }else if(expected==HEADER_TYPE_IPv6_OPTS){
+ if(PKTPARSERDEBUG)puts("Expected=Dopts");
+ if(ext_dopts.storeRecvData(curr_pkt, curr_pktlen)==OP_FAILURE ){
+ unknown_hdr=true;
+ break;
+ }
+ if( (exthdrlen=ext_dopts.validate())==OP_FAILURE){
+ unknown_hdr=true;
+ break;
+ }
+ ext_next=ext_dopts.getNextHeader();
+ ext_dopts.reset();
+ }else{
+ /* Should never happen. */
+ unknown_hdr=true;
+ break;
+ }
+
+ /* Update the info for this header */
+ this_packet[current_header].length=exthdrlen;
+ this_packet[current_header++].type=expected;
+ curr_pkt+=exthdrlen;
+ curr_pktlen-=exthdrlen;
+
+ /* Lets's see what comes next */
+ switch(ext_next){
+ case HEADER_TYPE_ICMPv6:
+ next_layer=TRANSPORT_LAYER;
+ expected=HEADER_TYPE_ICMPv6;
+ break;
+ case HEADER_TYPE_IPv4: /* IPv4 in IPv6 */
+ next_layer=NETWORK_LAYER;
+ expected=HEADER_TYPE_IPv4;
+ break;
+ case HEADER_TYPE_TCP:
+ next_layer=TRANSPORT_LAYER;
+ expected=HEADER_TYPE_TCP;
+ break;
+ case HEADER_TYPE_UDP:
+ next_layer=TRANSPORT_LAYER;
+ expected=HEADER_TYPE_UDP;
+ break;
+ case HEADER_TYPE_IPv6: /* IPv6 in IPv6 */
+ next_layer=NETWORK_LAYER;
+ expected=HEADER_TYPE_IPv6;
+ break;
+ case HEADER_TYPE_IPv6_HOPOPT:
+ next_layer=EXTHEADERS_LAYER;
+ expected=HEADER_TYPE_IPv6_HOPOPT;
+ break;
+ case HEADER_TYPE_IPv6_OPTS:
+ next_layer=EXTHEADERS_LAYER;
+ expected=HEADER_TYPE_IPv6_OPTS;
+ break;
+ case HEADER_TYPE_IPv6_ROUTE:
+ next_layer=EXTHEADERS_LAYER;
+ expected=HEADER_TYPE_IPv6_ROUTE;
+ break;
+ case HEADER_TYPE_IPv6_FRAG:
+ next_layer=EXTHEADERS_LAYER;
+ expected=HEADER_TYPE_IPv6_FRAG;
+ break;
+ default:
+ next_layer=APPLICATION_LAYER;
+ expected=HEADER_TYPE_RAW_DATA;
+ break;
+ }
+
+ /* Miscellaneous payloads *************************************************/
+ }else{ // next_layer==APPLICATION_LAYER
+ if(PKTPARSERDEBUG)puts("Next Layer=Application");
+
+ /* If we get here it is possible that the packet is ARP but
+ * we have no access to the original Ethernet header. We
+ * determine if this header is ARP by checking its size
+ * and checking for some common values. */
+ if(arp.storeRecvData(curr_pkt, curr_pktlen)!=OP_FAILURE){
+ if( (arplen=arp.validate())!=OP_FAILURE){
+ if(arp.getHardwareType()==HDR_ETH10MB){
+ if(arp.getProtocolType()==0x0800){
+ if(arp.getHwAddrLen()==ETH_ADDRESS_LEN){
+ if(arp.getProtoAddrLen()==IPv4_ADDRESS_LEN){
+ this_packet[current_header].length=arplen;
+ this_packet[current_header++].type=HEADER_TYPE_ARP;
+ arp.reset();
+ curr_pkt+=arplen;
+ curr_pktlen-=arplen;
+ if(curr_pktlen>0){
+ next_layer=APPLICATION_LAYER;
+ expected=HEADER_TYPE_RAW_DATA;
+ }else{
+ finished=true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //if(expected==HEADER_TYPE_DNS){
+ //}else if(expected==HEADER_TYPE_HTTP){
+ //}... ETC
+ this_packet[current_header].length=curr_pktlen;
+ this_packet[current_header++].type=HEADER_TYPE_RAW_DATA;
+ curr_pktlen=0;
+ finished=true;
+ }
+ } /* End of header processing loop */
+
+ /* If we couldn't validate some header, treat that header and any remaining
+ * data, as raw application data. */
+ if (unknown_hdr==true){
+ if(curr_pktlen>0){
+ if(PKTPARSERDEBUG)puts("Unknown layer found. Treating it as raw data.");
+ this_packet[current_header].length=curr_pktlen;
+ this_packet[current_header++].type=HEADER_TYPE_RAW_DATA;
+ }
+ }
+
+ return this_packet;
+} /* End of parse_received_packet() */
+
+
+/* TODO: remove */
+int PacketParser::dummy_print_packet_type(const u8 *pkt, size_t pktlen, bool eth_included){
+ pkt_type_t *packetheaders=PacketParser::parse_packet(pkt, pktlen, eth_included);
+ for(int i=0; packetheaders[i].length!=0; i++){
+ printf("%s:", header_type2string(packetheaders[i].type));
+ }
+ printf("\n");
+ return OP_SUCCESS;
+} /* End of dummy_print_packet_type() */
+
+
+int PacketParser::dummy_print_packet(const u8 *pkt, size_t pktlen, bool eth_included){
+ PacketElement *me=NULL, *aux=NULL;
+ if( (me=split(pkt, pktlen, eth_included))==NULL )
+ return OP_FAILURE;
+ else{
+ me->print(stdout, PRINT_DETAIL_HIGH);
+ printf("\n");
+ }
+ /* Free the structs */
+ while(me!=NULL){
+ aux=me->getNextElement();
+ delete me;
+ me=aux;
+ }
+ return OP_SUCCESS;
+} /* End of dummy_print_packet() */
+
+
+
+/** For a given packet, this method determines where the application layer data
+ * begins. It returs a positive offset if any application data was found, zero
+ * if the packet did not contain application data and a negative integer in
+ * case of error. */
+int PacketParser::payload_offset(const u8 *pkt, size_t pktlen, bool link_included){
+ PacketElement *me=NULL, *aux=NULL;
+ size_t offset=pktlen; /* Initially, point to the end of the packet. */
+
+ /* Safe checks*/
+ if(pkt==NULL || pktlen<=0)
+ return -1;
+
+ dummy_print_packet_type(pkt, pktlen, link_included);
+
+ /* Split the packet into separate protocol headers */
+ if( (me=split(pkt, pktlen, link_included))==NULL )
+ return -2;
+ else{
+ aux=me;
+ }
+
+ /* Find if there is application data and where it begins */
+ while(me!=NULL){
+ /* When we find application data, we compute the offset by substacting the
+ length of the application data from the packet's total length */
+ if(me->protocol_id()==HEADER_TYPE_RAW_DATA){
+ offset = pktlen - me->getLen();
+ break;
+ }
+ me = me->getNextElement();
+ }
+
+ /* Free the structs */
+ me=aux;
+ while(me!=NULL){
+ aux=me->getNextElement();
+ delete me;
+ me=aux;
+ }
+
+ /* Return 0 if we didn't find any application data */
+ if(offset==pktlen){
+ return 0;
+ }else{
+ return offset;
+ }
+} /* End of payload_offset() */
+
+
+
+
+PacketElement *PacketParser::split(const u8 *pkt, size_t pktlen){
+ return split(pkt, pktlen, false);
+} /* End of split() */
+
+
+PacketElement *PacketParser::split(const u8 *pkt, size_t pktlen, bool eth_included){
+ pkt_type_t *packetheaders=NULL;
+ const u8 *curr_pkt=pkt;
+ PacketElement *first=NULL;
+ PacketElement *last=NULL;
+ IPv4Header *ip4=NULL;
+ IPv6Header *ip6=NULL;
+ DestOptsHeader *ext_dopts=NULL;
+ FragmentHeader *ext_frag=NULL;
+ HopByHopHeader *ext_hopt=NULL;
+ RoutingHeader *ext_routing=NULL;
+ TCPHeader *tcp=NULL;
+ UDPHeader *udp=NULL;
+ ICMPv4Header *icmp4=NULL;
+ ICMPv6Header *icmp6=NULL;
+ EthernetHeader *eth=NULL;
+ ARPHeader *arp=NULL;
+ RawData *raw=NULL;
+
+ /* Analyze the packet. This returns a list of header types and lengths */
+ if((packetheaders=PacketParser::parse_packet(pkt, pktlen, eth_included))==NULL)
+ return NULL;
+
+ /* Store each header in its own PacketHeader object type */
+ for(int i=0; packetheaders[i].length!=0; i++){
+
+ switch(packetheaders[i].type){
+
+ case HEADER_TYPE_ETHERNET:
+ eth=new EthernetHeader();
+ eth->storeRecvData(curr_pkt, packetheaders[i].length);
+ if(first==NULL){
+ first=eth;
+ }else{
+ last->setNextElement(eth);
+ }
+ last=eth;
+ break;
+
+ case HEADER_TYPE_ARP:
+ arp=new ARPHeader();
+ arp->storeRecvData(curr_pkt, packetheaders[i].length);
+ if(first==NULL){
+ first=arp;
+ }else{
+ last->setNextElement(arp);
+ }
+ last=arp;
+ break;
+
+ case HEADER_TYPE_IPv4:
+ ip4=new IPv4Header();
+ ip4->storeRecvData(curr_pkt, packetheaders[i].length);
+ if(first==NULL){
+ first=ip4;
+ }else{
+ last->setNextElement(ip4);
+ }
+ last=ip4;
+ break;
+
+ case HEADER_TYPE_IPv6:
+ ip6=new IPv6Header();
+ ip6->storeRecvData(curr_pkt, packetheaders[i].length);
+ if(first==NULL){
+ first=ip6;
+ }else{
+ last->setNextElement(ip6);
+ }
+ last=ip6;
+ break;
+
+ case HEADER_TYPE_TCP:
+ tcp=new TCPHeader();
+ tcp->storeRecvData(curr_pkt, packetheaders[i].length);
+ if(first==NULL){
+ first=tcp;
+ }else{
+ last->setNextElement(tcp);
+ }
+ last=tcp;
+ break;
+
+ case HEADER_TYPE_UDP:
+ udp=new UDPHeader();
+ udp->storeRecvData(curr_pkt, packetheaders[i].length);
+ if(first==NULL){
+ first=udp;
+ }else{
+ last->setNextElement(udp);
+ }
+ last=udp;
+ break;
+
+ case HEADER_TYPE_ICMPv4:
+ icmp4=new ICMPv4Header();
+ icmp4->storeRecvData(curr_pkt, packetheaders[i].length);
+ if(first==NULL){
+ first=icmp4;
+ }else{
+ last->setNextElement(icmp4);
+ }
+ last=icmp4;
+ break;
+
+ case HEADER_TYPE_ICMPv6:
+ icmp6=new ICMPv6Header();
+ icmp6->storeRecvData(curr_pkt, packetheaders[i].length);
+ if(first==NULL){
+ first=icmp6;
+ }else{
+ last->setNextElement(icmp6);
+ }
+ last=icmp6;
+ break;
+
+ case HEADER_TYPE_IPv6_HOPOPT:
+ ext_hopt=new HopByHopHeader();
+ ext_hopt->storeRecvData(curr_pkt, packetheaders[i].length);
+ if(first==NULL){
+ first=ext_hopt;
+ }else{
+ last->setNextElement(ext_hopt);
+ }
+ last=ext_hopt;
+ break;
+
+ case HEADER_TYPE_IPv6_ROUTE:
+ ext_routing=new RoutingHeader();
+ ext_routing->storeRecvData(curr_pkt, packetheaders[i].length);
+ if(first==NULL){
+ first=ext_routing;
+ }else{
+ last->setNextElement(ext_routing);
+ }
+ last=ext_routing;
+ break;
+
+ case HEADER_TYPE_IPv6_FRAG:
+ ext_frag=new FragmentHeader();
+ ext_frag->storeRecvData(curr_pkt, packetheaders[i].length);
+ if(first==NULL){
+ first=ext_frag;
+ }else{
+ last->setNextElement(ext_frag);
+ }
+ last=ext_frag;
+ break;
+
+ case HEADER_TYPE_IPv6_OPTS:
+ ext_dopts=new DestOptsHeader();
+ ext_dopts->storeRecvData(curr_pkt, packetheaders[i].length);
+ if(first==NULL){
+ first=ext_dopts;
+ }else{
+ last->setNextElement(ext_dopts);
+ }
+ last=ext_dopts;
+ break;
+
+ case HEADER_TYPE_RAW_DATA:
+ default:
+ raw=new RawData();
+ raw->storeRecvData(curr_pkt, packetheaders[i].length);
+ if(first==NULL){
+ first=raw;
+ }else{
+ last->setNextElement(raw);
+ }
+ last=raw;
+ break;
+ }
+ curr_pkt+=packetheaders[i].length;
+ }
+ return first;
+} /* End of split() */
+
+
+/* This method frees a chain of PacketElement objects. Note that objects in
+ * the chain are freed by calling "delete" on them, so only those instances
+ * that have been obtained through a call to "new" should be passed to this
+ * method. Chains returned by PacketParser::split() are safe to use with this.*/
+int PacketParser::freePacketChain(PacketElement *first){
+ PacketElement *curr=first;
+ PacketElement *next=NULL;
+ while(curr!=NULL){
+ next=curr->getNextElement();
+ delete curr;
+ curr=next;
+ }
+ return OP_SUCCESS;
+} /* End of freePacketChain() */
+
+
+/* This method is for debugging purposes only. It tests the packet parser and
+ * the PacketElement class family. Basically it checks that the supplied
+ * chain of PacketElements can be serialized and de-serialized correctly.
+ * Returns NULL on success or an error string in case of failure. */
+const char *PacketParser::test_packet_parser(PacketElement *test_pkt){
+ const char *errmsg=NULL;
+ PacketElement *parsed_pkt=NULL;
+ PacketElement *orig_pkt=NULL;
+ PacketElement *new_pkt=NULL;
+ u8 *mypktbuff2=NULL;
+ u8 *mypktbuff=NULL;
+
+ if(test_pkt==NULL){
+ errmsg="NULL pointer supplied";
+ goto end;
+ }
+
+ /* Generate a serialized version of the packet */
+ mypktbuff=(u8 *)safe_malloc(test_pkt->getLen());
+ test_pkt->dumpToBinaryBuffer(mypktbuff, test_pkt->getLen());
+
+ /* Generate a chain of PacketElement objects from the serialized version. */
+ parsed_pkt=PacketParser::split(mypktbuff, test_pkt->getLen());
+
+ if(parsed_pkt==NULL){
+ errmsg="PacketParser::split() returned NULL";
+ goto end;
+ }
+ if(parsed_pkt->getLen()!=test_pkt->getLen()){
+ errmsg="Packets have different lengths";
+ goto end;
+ }
+
+ /* Generate a serialized version of the new chain */
+ mypktbuff2=(u8 *)safe_malloc(parsed_pkt->getLen());
+ parsed_pkt->dumpToBinaryBuffer(mypktbuff2, parsed_pkt->getLen());
+
+ /* Make sure both packets produce the exact same binary buffer */
+ if(memcmp(mypktbuff, mypktbuff2, parsed_pkt->getLen())!=0){
+ errmsg="The two packets do not result in the same binary buffer";
+ goto end;
+ }
+
+ /* Now let's check that both chains have the same number and type of
+ * PacketElements. */
+ orig_pkt=test_pkt;
+ new_pkt=parsed_pkt;
+ while(orig_pkt!=NULL && new_pkt!=NULL){
+ if(orig_pkt->protocol_id() != new_pkt->protocol_id() ){
+ errmsg="Protocol IDs do not match";
+ goto end;
+ }
+ orig_pkt=orig_pkt->getNextElement();
+ new_pkt=new_pkt->getNextElement();
+ }
+
+ if(orig_pkt!=NULL || new_pkt!=NULL){
+ errmsg="The two packets do not have the same number of chained elements.";
+ goto end;
+ }
+
+ end:
+ /* Free our allocations */
+ if(mypktbuff!=NULL)
+ free(mypktbuff);
+ if(mypktbuff2!=NULL)
+ free(mypktbuff2);
+ if(parsed_pkt!=NULL)
+ PacketParser::freePacketChain(parsed_pkt);
+
+ /* If everything went well, errmsg should still be NULL. Otherwise it
+ * should point to an error message.*/
+ return errmsg;
+}
+
+
+
+/* Returns true if the supplied "rcvd" packet is a response to the "sent" packet.
+ * This method currently handles IPv4, IPv6, ICMPv4, ICMPv6, TCP and UDP. Here
+ * some examples of what can be matched using it:
+ *
+ * Probe: TCP SYN -> Response TCP SYN|ACK
+ * Probe: TCP SYN -> Response TCP RST|ACK
+ * Probe: UDP:53 -> Response UDP from port 53.
+ * Probe ICMP Echo -> Response ICMP Echo reply
+ * Probe ICMPv6 Neighbor Solicitation -> Response ICMPv6 Neighbor Advert
+ * Probe Malformed IPv6 -> Response ICMPv6 Parameter Problem
+ * Probe MLDv1 Query -> Response MLDv1 Report
+ * Probe ICMP Timestamp request -> Response ICMP timestamp response
+ * etc...
+ *
+ * Note that ICMP error messages are matched against sent probes (e.g: an ICMP
+ * Parameter Problem generated as a result of an invalid TCP segment is matched
+ * positively with the original TCP segment). Therefore, the caller must ensure
+ * that the received packet is what it expects before using it (e.g: the packet
+ * is an actual TCP packet, not an ICMP error).
+ *
+ * Warning: this method assumes that the probes you send are reasonably
+ * different from each other. Don't expect a 100% accuracy if you send a bunch
+ * of TCP segments with the same source and destination port numbers, or a
+ * bunch of ICMP messages with the same identifier and sequence number. */
+bool PacketParser::is_response(PacketElement *sent, PacketElement *rcvd){
+ if(PKTPARSERDEBUG)printf("%s(): called\n", __func__);
+
+ if(sent==NULL || rcvd==NULL)
+ return false;
+
+ /* If any of the packets is encapsulated in an Ethernet frame, strip the
+ * link layer header before proceeding with the matching process. */
+ if(rcvd->protocol_id()==HEADER_TYPE_ETHERNET)
+ if( (rcvd=rcvd->getNextElement())==NULL)
+ return false;
+ if(sent->protocol_id()==HEADER_TYPE_ETHERNET)
+ if( (sent=sent->getNextElement())==NULL)
+ return false;
+
+ /* Make sure both packets have the same network layer */
+ if(rcvd->protocol_id()!=sent->protocol_id())
+ return false;
+
+ /* The packet could be ARP */
+ if(rcvd->protocol_id()==HEADER_TYPE_ARP){
+ ARPHeader *sent_arp=(ARPHeader *)sent;
+ ARPHeader *rcvd_arp=(ARPHeader *)rcvd;
+ switch(sent_arp->getOpCode()){
+ case OP_ARP_REQUEST:
+ if(rcvd_arp->getOpCode()==OP_ARP_REPLY){
+ /* TODO @todo: getTargetIP() and getSenderIP() should
+ * either return struct in_addr or IPAddress but not u32. */
+ if(sent_arp->getTargetIP()==rcvd_arp->getSenderIP())
+ if(sent_arp->getSenderIP()==rcvd_arp->getTargetIP())
+ return true;
+ }
+ return false;
+ break;
+
+ /* We only support ARP, not RARP or other weird stuff. Also, if
+ * we didn't send a request, then we don't expect any response */
+ case OP_RARP_REQUEST:
+ case OP_DRARP_REQUEST:
+ case OP_INARP_REQUEST:
+ default:
+ return false;
+ break;
+
+ }
+ return false;
+ }
+
+ /* The packet is IPv4 or IPv6 */
+ if(rcvd->protocol_id()!=HEADER_TYPE_IPv6 && rcvd->protocol_id()!=HEADER_TYPE_IPv4)
+ return false;
+ if(PKTPARSERDEBUG)printf("%s(): Both packets use IP.\n", __func__);
+
+ /* Handle the network layer with a more specific class */
+ NetworkLayerElement *rcvd_ip=(NetworkLayerElement *)rcvd;
+ NetworkLayerElement *sent_ip=(NetworkLayerElement *)sent;
+
+ /* Ensure the packet comes from the host we sent the probe to */
+ if( memcmp(rcvd_ip->getSourceAddress(), sent_ip->getDestinationAddress(), rcvd_ip->getAddressLength())!=0 )
+ return false;
+ /* Ensure the received packet is destined to us */
+ if( memcmp(rcvd_ip->getDestinationAddress(), sent_ip->getSourceAddress(), rcvd_ip->getAddressLength())!=0 )
+ return false;
+
+ if(PKTPARSERDEBUG)printf("%s(): Src and Dst addresses make sense.\n", __func__);
+
+ /* Skip layers until we find ICMP or a transport protocol */
+ PacketElement *rcvd_layer4=rcvd_ip->getNextElement();
+ PacketElement *sent_layer4=sent_ip->getNextElement();
+ while(rcvd_layer4!=NULL){
+ if(rcvd_layer4->protocol_id()==HEADER_TYPE_UDP || rcvd_layer4->protocol_id()==HEADER_TYPE_TCP ||
+ rcvd_layer4->protocol_id()==HEADER_TYPE_ICMPv4 || rcvd_layer4->protocol_id()==HEADER_TYPE_ICMPv6 ){
+ break;
+ }else{
+ rcvd_layer4=rcvd_layer4->getNextElement();
+ }
+ }
+ while(sent_layer4!=NULL){
+ if(sent_layer4->protocol_id()==HEADER_TYPE_UDP || sent_layer4->protocol_id()==HEADER_TYPE_TCP ||
+ sent_layer4->protocol_id()==HEADER_TYPE_ICMPv4 || sent_layer4->protocol_id()==HEADER_TYPE_ICMPv6 ){
+ break;
+ }else{
+ sent_layer4=sent_layer4->getNextElement();
+ }
+ }
+ if(rcvd_layer4==NULL || sent_layer4==NULL)
+ return false;
+
+ if(PKTPARSERDEBUG)printf("%s(): Layer 4 found for both packets.\n", __func__);
+
+ /* If we get here it means that both packets have a proper layer4 protocol
+ * header. Now we have to check which type are they and see if a probe-response
+ * relation can be established. */
+ if(sent_layer4->protocol_id()==HEADER_TYPE_ICMPv6 || sent_layer4->protocol_id()==HEADER_TYPE_ICMPv4){
+
+ if(PKTPARSERDEBUG)printf("%s(): Sent packet is ICMP.\n", __func__);
+
+ /* Make sure received packet is ICMP (we only expect ICMP responses for
+ * ICMP probes) */
+ if(rcvd_layer4->protocol_id()!=HEADER_TYPE_ICMPv6 && rcvd_layer4->protocol_id()!=HEADER_TYPE_ICMPv4 )
+ return false;
+
+ /* Make sure both packets have the same ICMP version */
+ if(sent_layer4->protocol_id()!=rcvd_layer4->protocol_id())
+ return false;
+
+ if(PKTPARSERDEBUG)printf("%s(): Received packet is ICMP too.\n", __func__);
+
+ /* Check if the received ICMP is an error message. We don't care which kind
+ * of error message it is. The only important thing is that error messages
+ * contain a copy of the original datagram, and that's what we want to
+ * match against the sent probe. */
+ if( ((ICMPHeader *)rcvd_layer4)->isError() ){
+ NetworkLayerElement *iperror=(NetworkLayerElement *)rcvd_layer4->getNextElement();
+
+ if(PKTPARSERDEBUG)printf("%s(): Received ICMP is an error message.\n", __func__);
+
+ /* ICMP error message must contain the original datagram */
+ if(iperror==NULL)
+ return false;
+
+ /* The first header must be IP */
+ if(iperror->protocol_id()!=HEADER_TYPE_IPv6 && iperror->protocol_id()!=HEADER_TYPE_IPv4)
+ return false;
+
+ /* The IP version must match the probe's */
+ if(iperror->protocol_id()!=sent_ip->protocol_id())
+ return false;
+
+ /* Source and destination addresses must match the probe's */
+ if( memcmp(iperror->getSourceAddress(), sent_ip->getSourceAddress(), iperror->getAddressLength())!=0 )
+ return false;
+ if( memcmp(iperror->getDestinationAddress(), sent_ip->getDestinationAddress(), iperror->getAddressLength())!=0 )
+ return false;
+
+ /* So far we've verified that the ICMP error contains an IP datagram that matches
+ * what we sent. Now, let's find the upper layer ICMP header (skip extension
+ * headers until we find ICMP) */
+ ICMPHeader *inner_icmp=(ICMPHeader *)iperror->getNextElement();
+ while(inner_icmp!=NULL){
+ if(inner_icmp->protocol_id()==HEADER_TYPE_ICMPv4 || inner_icmp->protocol_id()==HEADER_TYPE_ICMPv6 ){
+ break;
+ }else{
+ inner_icmp=(ICMPHeader *)inner_icmp->getNextElement();
+ }
+ }
+ if(inner_icmp==NULL)
+ return false;
+
+ /* If we get here it means that we've found an ICMP header inside the
+ * ICMP error message that we received. First of all, check that the
+ * ICMP version matches what we sent. */
+ if(sent_layer4->protocol_id() != inner_icmp->protocol_id())
+ return false;
+
+ /* Make sure ICMP type and code match */
+ if( ((ICMPHeader*)sent_layer4)->getType() != inner_icmp->getType() )
+ return false;
+ if( ((ICMPHeader*)sent_layer4)->getCode() != inner_icmp->getCode() )
+ return false;
+
+ /* Now go into a bit of detail and try to determine if both headers
+ * are equal, comparing the values of specific fields. */
+ if(sent_layer4->protocol_id()==HEADER_TYPE_ICMPv6){
+ ICMPv6Header *sent_icmp6=(ICMPv6Header *)sent_layer4;
+ ICMPv6Header *inner_icmp6=(ICMPv6Header *)inner_icmp;
+
+ switch(sent_icmp6->getType()){
+ case ICMPv6_UNREACH:
+ case ICMPv6_TIMXCEED :
+ /* For these we cannot guarantee that the received ICMPv6 error
+ * packet included data beyond the inner ICMPv6 header, so we just
+ * assume that they are a match to the sent probe. (We shouldn't
+ * really be sending ICMPv6 error messages and expect ICMPv6 error
+ * responses that contain our ICMv6P error messages, should we?
+ * Well, even if we do, there is a good chance we are able to match
+ * those responses with the original probe) */
+ break;
+
+ case ICMPv6_PKTTOOBIG:
+ if(sent_icmp6->getMTU() != inner_icmp6->getMTU())
+ return false;
+ break;
+
+ case ICMPv6_PARAMPROB:
+ if(sent_icmp6->getPointer() != inner_icmp6->getPointer())
+ return false;
+ break;
+
+ case ICMPv6_ECHO:
+ case ICMPv6_ECHOREPLY:
+ if(sent_icmp6->getIdentifier() != inner_icmp6->getIdentifier())
+ return false;
+ if(sent_icmp6->getSequence() != inner_icmp6->getSequence())
+ return false;
+ break;
+
+ case ICMPv6_ROUTERSOLICIT:
+ /* Here we do not have much to compare, so we just test that
+ * the reserved field contains the same value, usually zero. */
+ if(sent_icmp6->getReserved()!=inner_icmp6->getReserved())
+ return false;
+ break;
+
+ case ICMPv6_ROUTERADVERT:
+ if(sent_icmp6->getCurrentHopLimit() != inner_icmp6->getCurrentHopLimit() )
+ return false;
+ if(sent_icmp6->getRouterLifetime() != inner_icmp6->getRouterLifetime() )
+ return false;
+ if(sent_icmp6->getReachableTime() != inner_icmp6->getReachableTime() )
+ return false;
+ if(sent_icmp6->getRetransmissionTimer() != inner_icmp6->getRetransmissionTimer() )
+ return false;
+ break;
+
+ case ICMPv6_REDIRECT:
+ if( memcmp(sent_icmp6->getTargetAddress().s6_addr, inner_icmp6->getTargetAddress().s6_addr, 16) !=0 )
+ return false;
+ if( memcmp(sent_icmp6->getDestinationAddress().s6_addr, inner_icmp6->getDestinationAddress().s6_addr, 16) !=0 )
+ return false;
+ break;
+
+ case ICMPv6_NGHBRSOLICIT:
+ case ICMPv6_NGHBRADVERT:
+ if( memcmp(sent_icmp6->getTargetAddress().s6_addr, inner_icmp6->getTargetAddress().s6_addr, 16) !=0 )
+ return false;
+ break;
+
+ case ICMPv6_RTRRENUM:
+ if(sent_icmp6->getSequence() != inner_icmp6->getSequence() )
+ return false;
+ if(sent_icmp6->getSegmentNumber() != inner_icmp6->getSegmentNumber() )
+ return false;
+ if(sent_icmp6->getMaxDelay() != inner_icmp6->getMaxDelay() )
+ return false;
+ if(sent_icmp6->getFlags() != inner_icmp6->getFlags() )
+ return false;
+ break;
+
+ case ICMPv6_NODEINFOQUERY:
+ case ICMPv6_NODEINFORESP:
+ if(sent_icmp6->getNodeInfoFlags() != inner_icmp6->getNodeInfoFlags() )
+ return false;
+ if(sent_icmp6->getNonce() != inner_icmp6->getNonce())
+ return false;
+ if(sent_icmp6->getQtype() != inner_icmp6->getQtype() )
+ return false;
+ break;
+
+
+ case ICMPv6_GRPMEMBQUERY:
+ case ICMPv6_GRPMEMBREP:
+ case ICMPv6_GRPMEMBRED:
+ case ICMPv6_INVNGHBRSOLICIT:
+ case ICMPv6_INVNGHBRADVERT:
+ case ICMPv6_MLDV2:
+ case ICMPv6_AGENTDISCOVREQ:
+ case ICMPv6_AGENTDISCOVREPLY:
+ case ICMPv6_MOBPREFIXSOLICIT:
+ case ICMPv6_MOBPREFIXADVERT:
+ case ICMPv6_CERTPATHSOLICIT:
+ case ICMPv6_CERTPATHADVERT:
+ case ICMPv6_EXPMOBILITY:
+ case ICMPv6_MRDADVERT:
+ case ICMPv6_MRDSOLICIT:
+ case ICMPv6_MRDTERMINATE:
+ case ICMPv6_FMIPV6:
+ /* All these types are not currently implemented but since the
+ * sent_icmp.getType() has returned such type, we assume
+ * that there is a match (don't return false here). */
+ break;
+
+ default:
+ /* Do not match ICMPv6 types we don't know about */
+ return false;
+ break;
+ }
+ }else if(sent_layer4->protocol_id()==HEADER_TYPE_ICMPv4){
+ ICMPv4Header *sent_icmp4=(ICMPv4Header *)sent_layer4;
+ ICMPv4Header *inner_icmp4=(ICMPv4Header *)inner_icmp;
+
+ switch(sent_icmp4->getType()){
+ case ICMP_ECHOREPLY:
+ case ICMP_ECHO:
+ case ICMP_TSTAMP:
+ case ICMP_TSTAMPREPLY:
+ case ICMP_INFO:
+ case ICMP_INFOREPLY:
+ case ICMP_MASK:
+ case ICMP_MASKREPLY:
+ case ICMP_DOMAINNAME:
+ case ICMP_DOMAINNAMEREPLY:
+ /* Check the message identifier and sequence number */
+ if(sent_icmp4->getIdentifier() != inner_icmp4->getIdentifier())
+ return false;
+ if(sent_icmp4->getSequence() != inner_icmp4->getSequence())
+ return false;
+ break;
+
+ case ICMP_ROUTERADVERT:
+ /* Check only the main fields, no need to parse the whole list
+ * of addresses (maybe we didn't even get enough octets to
+ * check that). */
+ if(sent_icmp4->getNumAddresses() != inner_icmp4->getNumAddresses() )
+ return false;
+ if(sent_icmp4->getAddrEntrySize() != inner_icmp4->getAddrEntrySize())
+ return false;
+ if(sent_icmp4->getLifetime() != inner_icmp4->getLifetime() )
+ return false;
+ break;
+
+ case ICMP_ROUTERSOLICIT:
+ /* Here we do not have much to compare, so we just test that
+ * the reserved field contains the same value, usually zero. */
+ if(sent_icmp4->getReserved()!=inner_icmp4->getReserved())
+ return false;
+ break;
+
+ case ICMP_UNREACH:
+ case ICMP_SOURCEQUENCH:
+ case ICMP_TIMXCEED:
+ /* For these we cannot guarantee that the received ICMP error
+ * packet included data beyond the inner ICMP header, so we just
+ * assume that they are a match to the sent probe. (We shouldn't
+ * really be sending ICMP error messages and expect ICMP error
+ * responses that contain our ICMP error messages, should we?
+ * Well, even if we do, there is a good chance we are able to match
+ * those responses with the original probe) */
+ break;
+
+ case ICMP_REDIRECT:
+ if(sent_icmp4->getGatewayAddress().s_addr != inner_icmp4->getGatewayAddress().s_addr)
+ return false;
+ break;
+
+ case ICMP_PARAMPROB:
+ if(sent_icmp4->getParameterPointer() != inner_icmp4->getParameterPointer())
+ return false;
+ break;
+
+ case ICMP_TRACEROUTE:
+ if(sent_icmp4->getIDNumber() != inner_icmp4->getIDNumber())
+ return false;
+ if(sent_icmp4->getOutboundHopCount() != inner_icmp4->getOutboundHopCount())
+ return false;
+ if(sent_icmp4->getOutputLinkSpeed() != inner_icmp4->getOutputLinkSpeed() )
+ return false;
+ if(sent_icmp4->getOutputLinkMTU() != inner_icmp4->getOutputLinkMTU() )
+ return false;
+ break;
+
+ case ICMP_SECURITYFAILURES:
+ /* Check the pointer and the reserved field */
+ if(sent_icmp4->getSecurityPointer() != inner_icmp4->getSecurityPointer())
+ return false;
+ if(sent_icmp4->getReserved() != inner_icmp4->getReserved())
+ return false;
+ break;
+
+ default:
+ /* Do not match ICMP types we don't know about */
+ return false;
+ break;
+ }
+ }else{
+ return false; // Should never happen, though.
+ }
+ }else{ /* Received ICMP is informational. */
+
+ if(PKTPARSERDEBUG)printf("%s(): Received ICMP is an informational message.\n", __func__);
+
+ /* If we get here it means that we received an informational ICMPv6
+ * message. So now we have to check if the received message is the
+ * expected reply to the probe we sent (like an Echo reply for an Echo
+ * request, etc). */
+
+ if(sent_layer4->protocol_id()==HEADER_TYPE_ICMPv6 && rcvd_layer4->protocol_id()==HEADER_TYPE_ICMPv6){
+ ICMPv6Header *sent_icmp6=(ICMPv6Header *)sent_layer4;
+ ICMPv6Header *rcvd_icmp6=(ICMPv6Header *)rcvd_layer4;
+
+ switch( sent_icmp6->getType() ){
+
+ case ICMPv6_UNREACH:
+ case ICMPv6_TIMXCEED :
+ case ICMPv6_PKTTOOBIG:
+ case ICMPv6_PARAMPROB:
+ /* This should never happen. If we got here, the received type
+ * should be of an informational message, not an error message. */
+ printf("Error in isResponse()\n");
+ return false;
+ break;
+
+ case ICMPv6_ECHO:
+ /* For Echo request, we expect echo replies */
+ if(rcvd_icmp6->getType()!=ICMPv6_ECHOREPLY)
+ return false;
+ /* And we expect the ID and sequence number of the reply to
+ * match the ID and seq of the request. */
+ if(sent_icmp6->getIdentifier() != rcvd_icmp6->getIdentifier())
+ return false;
+ if(sent_icmp6->getSequence() != rcvd_icmp6->getSequence())
+ return false;
+ break;
+
+ case ICMPv6_ECHOREPLY:
+ /* We don't expect replies to Echo replies */
+ return false;
+ break;
+
+ case ICMPv6_ROUTERSOLICIT:
+ /* For Router solicitations, we expect Router advertisements.
+ * We only check if the received ICMP is a router advert because
+ * there is nothing else that can be used to match the solicitation
+ * with the response. */
+ if(rcvd_icmp6->getType()!=ICMPv6_ROUTERADVERT)
+ return false;
+ break;
+
+ case ICMPv6_ROUTERADVERT:
+ /* We don't expect replies to router advertisements */
+ return false;
+ break;
+
+ case ICMPv6_REDIRECT:
+ /* We don't expect replies to Redirect messages */
+ return false;
+ break;
+
+ case ICMPv6_NGHBRSOLICIT:
+ if(PKTPARSERDEBUG)printf("%s(): Sent ICMP is an ICMPv6 Neighbor Solicitation.\n", __func__);
+ /* For Neighbor solicitations, we expect Neighbor advertisements
+ * with the "S" flag set (solicited flag) and the same address
+ * in the "TargetAddress" field. */
+ if(rcvd_icmp6->getType()!=ICMPv6_NGHBRADVERT)
+ return false;
+ if(PKTPARSERDEBUG)printf("%s(): Received ICMP is an ICMPv6 Neighbor Advertisement.\n", __func__);
+ if( !(rcvd_icmp6->getFlags() & 0x40) )
+ return false;
+ if( memcmp(sent_icmp6->getTargetAddress().s6_addr, rcvd_icmp6->getTargetAddress().s6_addr, 16) !=0 )
+ return false;
+ break;
+
+ case ICMPv6_NGHBRADVERT:
+ /* We don't expect replies to Neighbor advertisements */
+ return false;
+ break;
+
+ case ICMPv6_NODEINFOQUERY:
+ /* For Node Information Queries we expect Node Information
+ * responses with the same Nonce value that we used in the query. */
+ if(rcvd_icmp6->getType()!=ICMPv6_NODEINFORESP)
+ return false;
+ if(sent_icmp6->getNonce() != rcvd_icmp6->getNonce())
+ return false;
+ break;
+
+ case ICMPv6_NODEINFORESP:
+ /* Obviously, we do not expect responses to a response */
+ return false;
+ break;
+
+ case ICMPv6_INVNGHBRSOLICIT:
+ /* For Inverse Neighbor Discovery Solicitations we expect
+ * advertisements in response. We don't do any additional
+ * validation since any advert can be considered a response
+ * to the solicitation. */
+ if(rcvd_icmp6->getType()!=ICMPv6_INVNGHBRADVERT)
+ return false;
+ break;
+
+ case ICMPv6_INVNGHBRADVERT:
+ /* We don't expect responses to advertisements */
+ return false;
+ break;
+
+
+ case ICMPv6_RTRRENUM:
+ /* We don't expect specific responses to router renumbering
+ * messages. */
+ return false;
+ break;
+
+ case ICMPv6_GRPMEMBQUERY:
+ /* For Multicast Listener Discovery (MLD) queries, we expect
+ * either MLD Responses or MLD Done messages. We can't handle MLDv2
+ * yet, so we don't match it. TODO: Implement support for MLDv2 */
+ if(rcvd_icmp6->getType()!=ICMPv6_GRPMEMBREP && rcvd_icmp6->getType()!=ICMPv6_GRPMEMBRED)
+ return false;
+ /* Now we have two possibilities:
+ * a) The query is a "General Query" where the multicast address
+ * is set to zero.
+ * b) The query is a "Multicast-Address-Specific Query", where
+ * the multicast address field is set to an actual multicast
+ * address.
+ * In the first case, we match any query response to the request,
+ * as we don't have a multicast address to compare. In the second
+ * case, we verify that the target mcast address of the query
+ * matches the one in the response. */
+ struct in6_addr zeroaddr;
+ memset(&zeroaddr, 0, sizeof(struct in6_addr));
+ if( memcmp( sent_icmp6->getMulticastAddress().s6_addr, zeroaddr.s6_addr, 16) != 0 ){ /* Case B: */
+ if (memcmp( sent_icmp6->getMulticastAddress().s6_addr, rcvd_icmp6->getMulticastAddress().s6_addr, 16)!=0 )
+ return false;
+ }
+ break;
+
+ case ICMPv6_GRPMEMBREP:
+ case ICMPv6_GRPMEMBRED:
+ /* We don't expect responses to MLD reports */
+ return false;
+ break;
+
+ case ICMPv6_MLDV2:
+ case ICMPv6_AGENTDISCOVREQ:
+ case ICMPv6_AGENTDISCOVREPLY:
+ case ICMPv6_MOBPREFIXSOLICIT:
+ case ICMPv6_MOBPREFIXADVERT:
+ case ICMPv6_CERTPATHSOLICIT:
+ case ICMPv6_CERTPATHADVERT:
+ case ICMPv6_EXPMOBILITY:
+ case ICMPv6_MRDADVERT:
+ case ICMPv6_MRDSOLICIT:
+ case ICMPv6_MRDTERMINATE:
+ case ICMPv6_FMIPV6:
+ default:
+ /* Do not match ICMPv6 types we don't implement or know about *
+ * TODO: Implement these ICMPv6 types. */
+ return false;
+ break;
+
+ }
+
+ }else if(sent_layer4->protocol_id()==HEADER_TYPE_ICMPv4 && rcvd_layer4->protocol_id()==HEADER_TYPE_ICMPv4){
+ ICMPv4Header *sent_icmp4=(ICMPv4Header *)sent_layer4;
+ ICMPv4Header *rcvd_icmp4=(ICMPv4Header *)rcvd_layer4;
+
+ switch( sent_icmp4->getType() ){
+
+ case ICMP_ECHOREPLY:
+ /* We don't expect replies to Echo replies. */
+ return false;
+ break;
+
+ case ICMP_UNREACH:
+ case ICMP_SOURCEQUENCH:
+ case ICMP_REDIRECT:
+ case ICMP_TIMXCEED:
+ case ICMP_PARAMPROB:
+ /* Nodes are not supposed to respond to error messages, so
+ * we don't expect any replies. */
+ return false;
+ break;
+
+ case ICMP_ECHO:
+ /* For Echo request, we expect echo replies */
+ if(rcvd_icmp4->getType()!=ICMP_ECHOREPLY)
+ return false;
+ /* And we expect the ID and sequence number of the reply to
+ * match the ID and seq of the request. */
+ if(sent_icmp4->getIdentifier() != rcvd_icmp4->getIdentifier())
+ return false;
+ if(sent_icmp4->getSequence() != rcvd_icmp4->getSequence())
+ return false;
+ break;
+
+ case ICMP_ROUTERSOLICIT:
+ /* For ICMPv4 router solicitations, we expect router advertisements.
+ * We don't validate anything else because in IPv4 any advert that
+ * comes from the host we sent the solicitation to can be
+ * considered a response. */
+ if(rcvd_icmp4->getType()!=ICMP_ROUTERADVERT)
+ return false;
+ break;
+
+ case ICMP_ROUTERADVERT:
+ /* We don't expect responses to advertisements */
+ return false;
+ break;
+
+ case ICMP_TSTAMP:
+ /* For Timestampt requests, we expect timestamp replies */
+ if(rcvd_icmp4->getType()!=ICMP_TSTAMPREPLY)
+ return false;
+ /* And we expect the ID and sequence number of the reply to
+ * match the ID and seq of the request. */
+ if(sent_icmp4->getIdentifier() != rcvd_icmp4->getIdentifier())
+ return false;
+ if(sent_icmp4->getSequence() != rcvd_icmp4->getSequence())
+ return false;
+ break;
+
+ case ICMP_TSTAMPREPLY:
+ /* We do not expect responses to timestamp replies */
+ return false;
+ break;
+
+ case ICMP_INFO:
+ /* For Information requests, we expect Information replies */
+ if(rcvd_icmp4->getType()!=ICMP_INFOREPLY)
+ return false;
+ /* And we expect the ID and sequence number of the reply to
+ * match the ID and seq of the request. */
+ if(sent_icmp4->getIdentifier() != rcvd_icmp4->getIdentifier())
+ return false;
+ if(sent_icmp4->getSequence() != rcvd_icmp4->getSequence())
+ return false;
+ break;
+
+ case ICMP_INFOREPLY:
+ /* We do not expect responses to Information replies */
+ return false;
+ break;
+
+ case ICMP_MASK:
+ /* For Netmask requests, we expect Netmask replies */
+ if(rcvd_icmp4->getType()!=ICMP_MASKREPLY)
+ return false;
+ /* And we expect the ID and sequence number of the reply to
+ * match the ID and seq of the request. */
+ if(sent_icmp4->getIdentifier() != rcvd_icmp4->getIdentifier())
+ return false;
+ if(sent_icmp4->getSequence() != rcvd_icmp4->getSequence())
+ return false;
+ break;
+
+ case ICMP_MASKREPLY:
+ /* We do not expect responses to netmask replies */
+ return false;
+ break;
+
+ case ICMP_TRACEROUTE:
+ /* We don't expect replies to a traceroute message as it is
+ * sent as a response to an IP datagram that contains the
+ * IP traceroute option. Also, note that this function does
+ * not take this into account when processing IPv4 datagrams
+ * so if we receive an ICMP_TRACEROUTE we'll not be able
+ * to match it with the original IP datagram. */
+ return false;
+ break;
+
+ case ICMP_DOMAINNAME:
+ /* For Domain Name requests, we expect Domain Name replies */
+ if(rcvd_icmp4->getType()!=ICMP_DOMAINNAMEREPLY)
+ return false;
+ /* And we expect the ID and sequence number of the reply to
+ * match the ID and seq of the request. */
+ if(sent_icmp4->getIdentifier() != rcvd_icmp4->getIdentifier())
+ return false;
+ if(sent_icmp4->getSequence() != rcvd_icmp4->getSequence())
+ return false;
+ break;
+
+ case ICMP_DOMAINNAMEREPLY:
+ /* We do not expect replies to DN replies */
+ return false;
+ break;
+
+ case ICMP_SECURITYFAILURES:
+ /* Nodes are not expected to send replies to this message, as it
+ * is an ICMP error. */
+ return false;
+ break;
+ }
+ }else{
+ return false; // Should never happen
+ }
+ }
+ }else if(sent_layer4->protocol_id()==HEADER_TYPE_TCP || sent_layer4->protocol_id()==HEADER_TYPE_UDP){
+
+ if(PKTPARSERDEBUG)printf("%s(): Sent packet has a transport layer header.\n", __func__);
+
+ /* Both are TCP or both UDP */
+ if(sent_layer4->protocol_id()==rcvd_layer4->protocol_id()){
+
+ if(PKTPARSERDEBUG)printf("%s(): Received packet has a transport layer header too.\n", __func__);
+
+ /* Probe source port must equal response target port */
+ if( ((TransportLayerElement *)sent_layer4)->getSourcePort() != ((TransportLayerElement *)rcvd_layer4)->getDestinationPort() )
+ return false;
+ /* Probe target port must equal response source port */
+ if( ((TransportLayerElement *)rcvd_layer4)->getSourcePort() != ((TransportLayerElement *)sent_layer4)->getDestinationPort() )
+ return false;
+
+ /* If we sent TCP or UDP and got ICMP in response, we need to find a copy of our packet in the
+ * ICMP payload, providing it is an ICMP error message. */
+ }else if(rcvd_layer4->protocol_id()==HEADER_TYPE_ICMPv6 || rcvd_layer4->protocol_id()==HEADER_TYPE_ICMPv4){
+
+ if(PKTPARSERDEBUG)printf("%s(): Received packet does not have transport layer header but an ICMP header.\n", __func__);
+
+ /* We only expect ICMP error messages */
+ if( !(((ICMPHeader *)rcvd_layer4)->isError()) )
+ return false;
+
+ /* Let's validate the original header */
+ NetworkLayerElement *iperror=(NetworkLayerElement *)rcvd_layer4->getNextElement();
+
+ /* ICMP error message must contain the original datagram */
+ if(iperror==NULL)
+ return false;
+
+ /* The first header must be IP */
+ if(iperror->protocol_id()!=HEADER_TYPE_IPv6 && iperror->protocol_id()!=HEADER_TYPE_IPv4)
+ return false;
+
+ /* The IP version must match the probe's */
+ if(iperror->protocol_id()!=sent_ip->protocol_id())
+ return false;
+
+ /* Source and destination addresses must match the probe's (NATs are
+ * supposed to rewrite them too, so this should be OK) */
+ if( memcmp(iperror->getSourceAddress(), sent_ip->getSourceAddress(), iperror->getAddressLength())!=0 )
+ return false;
+ if( memcmp(iperror->getDestinationAddress(), sent_ip->getDestinationAddress(), iperror->getAddressLength())!=0 )
+ return false;
+
+ /* So far we've verified that the ICMP error contains an IP datagram that matches
+ * what we sent. Now, let's find the upper layer protocol (skip extension
+ * headers and the like until we find some transport protocol). */
+ TransportLayerElement *layer4error=(TransportLayerElement *)iperror->getNextElement();
+ while(layer4error!=NULL){
+ if(layer4error->protocol_id()==HEADER_TYPE_UDP || layer4error->protocol_id()==HEADER_TYPE_TCP ){
+ break;
+ }else{
+ layer4error=(TransportLayerElement *)layer4error->getNextElement();
+ }
+ }
+ if(layer4error==NULL)
+ return false;
+
+ /* Now make sure we see the same port numbers */
+ if( layer4error->getSourcePort() != ((TransportLayerElement *)sent_layer4)->getSourcePort() )
+ return false;
+ if( layer4error->getDestinationPort() != ((TransportLayerElement *)sent_layer4)->getDestinationPort() )
+ return false;
+ } else {
+ return false;
+ }
+ }else{
+ /* We sent a layer 4 other than ICMP, ICMPv6, TCP, or UDP. We return false
+ * as we cannot match responses for protocols we don't understand */
+ return false;
+ }
+
+ /* If we get there it means the packet passed all the tests. Return true
+ * to indicate that the packet is a response to this FPProbe. */
+ if(PKTPARSERDEBUG)printf("%s(): The received packet was successfully matched with the sent packet.\n", __func__);
+ return true;
+}
+
+/* Tries to find a transport layer header in the supplied chain of
+ * protocol headers. On success it returns a pointer to a PacketElement
+ * of one of these types:
+ *
+ * HEADER_TYPE_TCP
+ * HEADER_TYPE_UDP
+ * HEADER_TYPE_ICMPv4
+ * HEADER_TYPE_ICMPv6
+ * HEADER_TYPE_SCTP
+ * HEADER_TYPE_ARP
+ *
+ * It returns NULL if no transport layer header is found.
+ *
+ * Note that this method only understands IPv4, IPv6 (and its
+ * extension headers) and Ethernet. If the supplied packet contains
+ * something different before the tranport layer, NULL will be returned.
+ * */
+PacketElement *PacketParser::find_transport_layer(PacketElement *chain){
+ PacketElement *aux=chain;
+ /* Traverse the chain of PacketElements */
+ while(aux!=NULL){
+ switch(aux->protocol_id()){
+ /* If we have a link or a network layer header, skip it. */
+ case HEADER_TYPE_IPv6_HOPOPT:
+ case HEADER_TYPE_IPv4:
+ case HEADER_TYPE_IPv6:
+ case HEADER_TYPE_IPv6_ROUTE:
+ case HEADER_TYPE_IPv6_FRAG:
+ case HEADER_TYPE_IPv6_NONXT:
+ case HEADER_TYPE_IPv6_OPTS:
+ case HEADER_TYPE_ETHERNET:
+ case HEADER_TYPE_IPv6_MOBILE:
+ aux=aux->getNextElement();
+ break;
+
+ /* If we found the transport layer, return it. */
+ case HEADER_TYPE_TCP:
+ case HEADER_TYPE_UDP:
+ case HEADER_TYPE_ICMPv4:
+ case HEADER_TYPE_ICMPv6:
+ case HEADER_TYPE_SCTP:
+ case HEADER_TYPE_ARP:
+ return aux;
+ break;
+
+ /* Otherwise, the packet contains headers we don't understand
+ * so we just return NULL to indicate that no valid transport
+ * layer was found. */
+ default:
+ return NULL;
+ break;
+ }
+ }
+ return NULL;
+} /* End of find_transport_layer() */
diff --git a/libnetutil/PacketParser.h b/libnetutil/PacketParser.h
new file mode 100644
index 0000000..b5bf821
--- /dev/null
+++ b/libnetutil/PacketParser.h
@@ -0,0 +1,132 @@
+/***************************************************************************
+ * PacketParser.h -- The PacketParser Class offers methods to parse *
+ * received network packets. Its main purpose is to facilitate the *
+ * conversion of raw sequences of bytes into chains of objects of the *
+ * PacketElement family. *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#ifndef __PACKETPARSER_H__
+#define __PACKETPARSER_H__ 1
+
+#include "ApplicationLayerElement.h"
+#include "ARPHeader.h"
+#include "DataLinkLayerElement.h"
+#include "EthernetHeader.h"
+#include "ICMPHeader.h"
+#include "ICMPv4Header.h"
+#include "ICMPv6Header.h"
+#include "ICMPv6Option.h"
+#include "ICMPv6RRBody.h"
+#include "IPv4Header.h"
+#include "IPv6Header.h"
+#include "NetworkLayerElement.h"
+#include "PacketElement.h"
+#include "RawData.h"
+#include "TCPHeader.h"
+#include "TransportLayerElement.h"
+#include "UDPHeader.h"
+#include "HopByHopHeader.h"
+#include "DestOptsHeader.h"
+#include "FragmentHeader.h"
+#include "RoutingHeader.h"
+
+
+#define LINK_LAYER 2
+#define NETWORK_LAYER 3
+#define TRANSPORT_LAYER 4
+#define APPLICATION_LAYER 5
+#define EXTHEADERS_LAYER 6
+
+typedef struct header_type_string{
+ u32 type;
+ const char *str;
+}header_type_string_t;
+
+
+typedef struct packet_type{
+ u32 type;
+ u32 length;
+}pkt_type_t;
+
+
+class PacketParser {
+
+ private:
+
+ public:
+
+ /* Misc */
+ PacketParser();
+ ~PacketParser();
+ void reset();
+
+ static const char *header_type2string(int val);
+ static pkt_type_t *parse_packet(const u8 *pkt, size_t pktlen, bool eth_included);
+ static int dummy_print_packet_type(const u8 *pkt, size_t pktlen, bool eth_included); /* TODO: remove */
+ static int dummy_print_packet(const u8 *pkt, size_t pktlen, bool eth_included); /* TODO: remove */
+ static int payload_offset(const u8 *pkt, size_t pktlen, bool link_included);
+ static PacketElement *split(const u8 *pkt, size_t pktlen, bool eth_included);
+ static PacketElement *split(const u8 *pkt, size_t pktlen);
+ static int freePacketChain(PacketElement *first);
+ static const char *test_packet_parser(PacketElement *test_pkt);
+ static bool is_response(PacketElement *sent, PacketElement *rcvd);
+ static PacketElement *find_transport_layer(PacketElement *chain);
+
+}; /* End of class PacketParser */
+
+#endif /* __PACKETPARSER_H__ */
diff --git a/libnetutil/RawData.cc b/libnetutil/RawData.cc
new file mode 100644
index 0000000..92500c5
--- /dev/null
+++ b/libnetutil/RawData.cc
@@ -0,0 +1,172 @@
+/***************************************************************************
+ * RawData.cc -- The RawData Class represents a network packet payload. It *
+ * is essentially a single buffer that may contain either random data or *
+ * caller supplied data. This class can be used, for example, to be linked *
+ * to a UDP datagram. *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#include "RawData.h"
+
+/******************************************************************************/
+/* CONTRUCTORS, DESTRUCTORS AND INITIALIZATION METHODS */
+/******************************************************************************/
+RawData::RawData(){
+ this->reset();
+} /* End of RawData contructor */
+
+
+RawData::~RawData(){
+ if(this->data!=NULL){
+ free(this->data);
+ this->data=NULL;
+ }
+} /* End of RawData destructor */
+
+
+/** Sets every attribute to its default value */
+void RawData::reset(){
+ this->data=NULL;
+ this->length=0;
+} /* End of reset() */
+
+
+/******************************************************************************/
+/* PacketElement:: OVERWRITTEN METHODS */
+/******************************************************************************/
+
+u8 * RawData::getBufferPointer(){
+ return this->getBufferPointer(NULL);
+} /* End of getBufferPointer() */
+
+
+u8 * RawData::getBufferPointer(int *mylen){
+ if(mylen!=NULL)
+ *mylen=this->length;
+ return this->data;
+} /* End of getBufferPointer() */
+
+
+/** Added for consistency with the rest of classes of the PacketElement family. */
+int RawData::storeRecvData(const u8 *buf, size_t len){
+ return this->store(buf, len);
+} /* End of storeRecvData() */
+
+
+/* Returns a protocol identifier. This is used by packet parsing funtions
+ * that return linked lists of PacketElement objects, to determine the protocol
+ * the object represents. */
+int RawData::protocol_id() const {
+ return HEADER_TYPE_RAW_DATA;
+} /* End of protocol_id() */
+
+
+/** Determines if the data stored in the object after an storeRecvData() call
+ * is valid and safe to use. This mainly checks the length of the data but may
+ * also test the value of certain protocol fields to ensure their correctness.
+ * @return the length, in bytes, of the header, if its found to be valid or
+ * OP_FAILURE (-1) otherwise. */
+int RawData::validate(){
+ return this->length;
+} /* End of validate() */
+
+
+/** Prints the contents of the header and calls print() on the next protocol
+ * header in the chain (if there is any).
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error. */
+int RawData::print(FILE *output, int detail) const {
+ fprintf(output, "Payload[");
+ fprintf(output, "%d byte%s]", this->length, (this->length!=1)? "s":"");
+ if(this->next!=NULL){
+ print_separator(output, detail);
+ next->print(output, detail);
+ }
+ return OP_SUCCESS;
+} /* End of print() */
+
+
+/******************************************************************************/
+/* PROTOCOL-SPECIFIC METHODS */
+/******************************************************************************/
+
+int RawData::store(const u8 *buf, size_t len){
+ /* If buffer had already been set, try to reuse it. */
+ if(this->data!=NULL){
+ if( this->length >= (int)len ){
+ memcpy(this->data, buf, len);
+ this->length=(int)len;
+ return OP_SUCCESS;
+ }else{
+ free(this->data);
+ }
+ }
+ if( (this->data=(u8 *)calloc(len, sizeof(u8)))==NULL )
+ return OP_FAILURE;
+ memcpy(this->data, buf, len);
+ this->length=(int)len;
+ return OP_SUCCESS;
+} /* End of store() */
+
+
+int RawData::store(const char *str){
+ if(str==NULL)
+ return OP_FAILURE;
+ else
+ return this->store((const u8*)str, strlen(str));
+} /* End of store() */
+
+
diff --git a/libnetutil/RawData.h b/libnetutil/RawData.h
new file mode 100644
index 0000000..545e010
--- /dev/null
+++ b/libnetutil/RawData.h
@@ -0,0 +1,90 @@
+/***************************************************************************
+ * RawData.h -- The RawData Class represents a network packet payload. It *
+ * is essentially a single buffer that may contain either random data or *
+ * caller supplied data. This class can be used, for example, to be linked *
+ * to a UDP datagram. *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#ifndef RAWDATA_H
+#define RAWDATA_H 1
+
+#include "ApplicationLayerElement.h"
+
+
+class RawData : public ApplicationLayerElement {
+
+ private:
+ u8 *data;
+
+ public:
+ RawData();
+ ~RawData();
+ void reset();
+ u8 *getBufferPointer();
+ int storeRecvData(const u8 *buf, size_t len);
+ int protocol_id() const;
+ int validate();
+ int print(FILE *output, int detail) const;
+
+ u8 *getBufferPointer(int *mylen);
+ int store(const u8 *buf, size_t len);
+ int store(const char *str);
+
+};
+
+#endif
diff --git a/libnetutil/RoutingHeader.cc b/libnetutil/RoutingHeader.cc
new file mode 100644
index 0000000..b978163
--- /dev/null
+++ b/libnetutil/RoutingHeader.cc
@@ -0,0 +1,313 @@
+/***************************************************************************
+ * RoutingHeader.cc -- The RoutingHeader Class represents an IPv6 Routing *
+ * extension header. *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#include "RoutingHeader.h"
+#include <assert.h>
+
+/******************************************************************************/
+/* CONTRUCTORS, DESTRUCTORS AND INITIALIZATION METHODS */
+/******************************************************************************/
+RoutingHeader::RoutingHeader() {
+ this->reset();
+} /* End of RoutingHeader constructor */
+
+
+RoutingHeader::~RoutingHeader() {
+
+} /* End of RoutingHeader destructor */
+
+
+/** Sets every attribute to its default value */
+void RoutingHeader::reset(){
+ memset(&this->h, 0, sizeof(nping_ipv6_ext_routing_hdr_t));
+ this->length=ROUTING_HEADER_MIN_LEN;
+ this->curr_addr=(u8 *)this->h.data;
+} /* End of reset() */
+
+
+/******************************************************************************/
+/* PacketElement:: OVERWRITTEN METHODS */
+/******************************************************************************/
+
+/** @warning This method is essential for the superclass getBinaryBuffer()
+ * method to work. Do NOT change a thing unless you know what you're doing */
+u8 *RoutingHeader::getBufferPointer(){
+ return (u8*)(&this->h);
+} /* End of getBufferPointer() */
+
+
+/** Stores supplied packet in the internal buffer so the information
+ * can be accessed using the standard get & set methods.
+ * @warning The RoutingHeader class is able to hold a maximum of
+ * sizeof(nping_icmpv6_hdr_t) bytes. If the supplied buffer is longer than
+ * that, only the first 1508 bytes will be stored in the internal buffer.
+ * @warning Supplied len MUST be at least 8 bytes (min ICMPv6 header length).
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error */
+int RoutingHeader::storeRecvData(const u8 *buf, size_t len){
+ if(buf==NULL || len<ROUTING_HEADER_MIN_LEN){
+ this->length=0;
+ return OP_FAILURE;
+ }else{
+ /* Store the first 4 bytes, so we can access length and routing type */
+ memcpy(&(this->h), buf, 4);
+
+ /* Our behaviour is different depending on the routing type. */
+ switch(this->h.type){
+
+ // No checks against ROUTING_HEADER_MAX_LEN because h.len cannot get that large:
+ // h.len is u8, max value 0xff, so (0xff+1)*8 = 0x800
+ // but ROUTING_HEADER_MAX_LEN is 8+256*8 = 0x808
+
+ /* Routing Type 0 (deprecated by RFC 5095)*/
+ case 0:
+ /* Type 0 has a variable length, but the value of its HdrExtLen
+ * field must be even (because it must be a multiple of the
+ * IPv6 address size). We also make sure that the received buffer
+ * has as many bytes as the HdrExtLen field says it has, and
+ * that it doesn't exceed the maximum number of octets we
+ * can store in this object. */
+ if(this->h.len%2==1 || ((unsigned int)(this->h.len+1))*8 > len){
+ this->length=0;
+ return OP_FAILURE;
+ }else{
+ int pkt_len=(this->h.len+1)*8;
+ this->reset();
+ this->length=pkt_len;
+ memcpy(&(this->h), buf, this->length);
+ return OP_SUCCESS;
+ }
+ break;
+
+ /* Routing Type 2 (For IPv6 Mobility. See RFC 6275) */
+ case 2:
+ /* Type 2 has a fixed length. If we have that many octets, store
+ * them. We'll perform validation later in validate(). */
+ if(len<ROUTING_TYPE_2_HEADER_LEN){
+ this->length=0;
+ return OP_FAILURE;
+ }else{
+ this->reset();
+ memcpy(&(this->h), buf, ROUTING_TYPE_2_HEADER_LEN);
+ this->length=ROUTING_TYPE_2_HEADER_LEN;
+ return OP_SUCCESS;
+ }
+ break;
+
+ /* Unknown routing type */
+ default:
+ /* If this is some routing type that we don't know about, we'll have
+ * to store as much data as the header says it has. Obvioulsy, we
+ * check that we received as much data as the HdrExtLen advertises,
+ * and that we don't exceed our own internal limit. */
+ if( ((unsigned int)(this->h.len+1))*8 > len){
+ this->length=0;
+ return OP_FAILURE;
+ }else{
+ this->reset();
+ this->length=(this->h.len+1)*8;
+ memcpy(&(this->h), buf, this->length);
+ return OP_SUCCESS;
+ }
+ break;
+ }
+ }
+ return OP_FAILURE;
+} /* End of storeRecvData() */
+
+
+/* Returns a protocol identifier. This is used by packet parsing funtions
+ * that return linked lists of PacketElement objects, to determine the protocol
+ * the object represents. */
+int RoutingHeader::protocol_id() const {
+ return HEADER_TYPE_IPv6_ROUTE;
+} /* End of protocol_id() */
+
+
+/** Determines if the data stored in the object after an storeRecvData() call
+ * is valid and safe to use. This mainly checks the length of the data but may
+ * also test the value of certain protocol fields to ensure their correctness.
+ * @return the length, in bytes, of the header, if its found to be valid or
+ * OP_FAILURE (-1) otherwise. */
+int RoutingHeader::validate(){
+
+ /* Check the object's length makes sense*/
+ if(this->length < ROUTING_HEADER_MIN_LEN || this->length%8!=0) {
+ return OP_FAILURE;
+ }
+
+ switch(this->h.type){
+ /* Routing Type 0 (deprecated by RFC 5095)*/
+ case 0:
+ /* Here we check that:
+ * 1) The length in HdrExtLen is even.
+ * 2) The length in HdrExtLen matches the octects stored in this object.
+ * 3) The length in HdrExtLen does not exceed our internal limit. */
+ if(this->h.len%2==1 || (this->h.len+1)*8 != this->length){
+ return OP_FAILURE;
+ }
+
+ /* Also, for Type 0, the value in the SegmentsLeft field should be less
+ * than or equal to the number of addresses in the packet. We verify
+ * that using the value of the HDrExtLen field which, divided by two,
+ * yields the number of addresses in the packet. It certainly doesn't
+ * make sense for the packet to say there are 5 hops left when we
+ * have less than 5 IPv6 addresses. We allow it to be less than
+ * the number of addresses present in the packet because the RFC 2460
+ * only talkes about segleft being greater than HDrExtLen/2, not less. */
+ if(this->h.segleft > this->h.len/2){
+ return OP_FAILURE;
+ }
+ break;
+
+ /* Routing Type 2 (For IPv6 Mobility. See RFC 6275) */
+ case 2:
+ /* Check that we have the exact number of octets we expect. */
+ if(this->length!= ROUTING_TYPE_2_HEADER_LEN){
+ return OP_FAILURE;
+ }
+ /* Also check that the HdrExtLen and SegmentsLeft fields have the
+ * value that RFC 6275 dictates. */
+ if(this->h.segleft!=1 || this->h.len!=2){
+ return OP_FAILURE;
+ }
+ break;
+
+ /* Unknown routing type */
+ default:
+ /* If this is some routing type that we don't know about, we just
+ * check that the length makes sense because we cannot make assumptions
+ * about the semantics of other fields. */
+ if( this->length!=(this->h.len+1)*8){
+ return OP_FAILURE;
+ }
+ break;
+
+ }
+ return this->length;
+} /* End of validate() */
+
+
+/** Prints the contents of the header and calls print() on the next protocol
+ * header in the chain (if there is any).
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error. */
+int RoutingHeader::print(FILE *output, int detail) const {
+ fprintf(output, "Routing[nh=%d len=%d type=%d segleft=%d]", this->h.nh, this->h.len, this->h.type, this->h.segleft);
+ // TODO: @todo : Implement this
+ if(this->next!=NULL){
+ print_separator(output, detail);
+ next->print(output, detail);
+ }
+ return OP_SUCCESS;
+} /* End of print() */
+
+
+/******************************************************************************/
+/* PROTOCOL-SPECIFIC METHODS */
+/******************************************************************************/
+
+/** Set Next Header field */
+int RoutingHeader::setNextHeader(u8 val){
+ this->h.nh = val;
+ return OP_SUCCESS;
+} /* End of setNextHeader() */
+
+
+/** Returns next header id */
+u8 RoutingHeader::getNextHeader(){
+ return this->h.nh;
+} /* End of getNextHeader() */
+
+
+/** Set routing type */
+int RoutingHeader::setRoutingType(u8 val){
+ this->h.type = val;
+ return OP_SUCCESS;
+} /* End of setRoutingType() */
+
+
+/** Returns the routing type */
+u8 RoutingHeader::getRoutingType(){
+ return this->h.type;
+} /* End of getRoutingType() */
+
+
+/** Set number of segments left */
+int RoutingHeader::setSegmentsLeft(u8 val){
+ this->h.segleft = val;
+ return OP_SUCCESS;
+} /* End of setSegmentsLeft() */
+
+
+/** Returns the number of segments left */
+u8 RoutingHeader::getSegmentsLeft(){
+ return this->h.segleft;
+} /* End of getSegmentsLeft() */
+
+
+/** Set number of segments left */
+int RoutingHeader::addAddress(struct in6_addr val){
+ /* Check we don't exceed max length */
+ if((this->length + 16)>ROUTING_HEADER_MAX_LEN)
+ return OP_FAILURE;
+ memcpy(this->curr_addr, val.s6_addr, 16);
+ this->curr_addr+=16;
+ this->h.len+=2;
+ this->length+=16;
+ return OP_SUCCESS;
+} /* End of setSegmentsLeft() */
diff --git a/libnetutil/RoutingHeader.h b/libnetutil/RoutingHeader.h
new file mode 100644
index 0000000..ebfdd7d
--- /dev/null
+++ b/libnetutil/RoutingHeader.h
@@ -0,0 +1,176 @@
+/***************************************************************************
+ * RoutingHeader.h -- The RoutingHeader Class represents an IPv6 Routing *
+ * extension header. *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#ifndef __ROUTING_HEADER_H__
+#define __ROUTING_HEADER_H__ 1
+
+#include "IPv6ExtensionHeader.h"
+
+#define ROUTING_HEADER_MIN_LEN 8
+#define ROUTING_HEADER_MAX_LEN (8 + 256*8)
+#define ROUTING_MAX_DATA_LEN 256*8
+#define ROUTING_TYPE_2_HEADER_LEN 24
+#define ROUTING_TYPE_0_MIN_LEN 8
+
+class RoutingHeader : public IPv6ExtensionHeader {
+
+ private:
+
+ /*
+ 1) Generic Routing Header:
+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Next Header | Hdr Ext Len | Routing Type | Segments Left |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ . .
+ . type-specific data .
+ . .
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ 2) Type 0 Routing header:
+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Next Header | Hdr Ext Len | Routing Type=0| Segments Left |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Reserved |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ + +
+ | |
+ + Address[1] +
+ | |
+ + +
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ + +
+ | |
+ + Address[2] +
+ | |
+ + +
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ . . .
+ . . .
+ . . .
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ + +
+ | |
+ + Address[n] +
+ | |
+ + +
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ 3) Type 2 Routing header:
+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Next Header | Hdr Ext Len=2 | Routing Type=2|Segments Left=1|
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Reserved |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ + +
+ | |
+ + Home Address +
+ | |
+ + +
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
+ struct nping_ipv6_ext_routing_hdr{
+ u8 nh;
+ u8 len;
+ u8 type;
+ u8 segleft;
+ u32 reserved;
+ u8 data[ROUTING_MAX_DATA_LEN];
+ }__attribute__((__packed__));
+ typedef struct nping_ipv6_ext_routing_hdr nping_ipv6_ext_routing_hdr_t;
+
+ nping_ipv6_ext_routing_hdr_t h;
+ u8 *curr_addr;
+
+ public:
+ RoutingHeader();
+ ~RoutingHeader();
+ void reset();
+ u8 *getBufferPointer();
+ int storeRecvData(const u8 *buf, size_t len);
+ int protocol_id() const;
+ int validate();
+ int print(FILE *output, int detail) const;
+
+ /* Protocol specific methods */
+ int setNextHeader(u8 val);
+ u8 getNextHeader();
+
+ int setRoutingType(u8 val);
+ u8 getRoutingType();
+
+ int setSegmentsLeft(u8 val);
+ u8 getSegmentsLeft();
+
+ int addAddress(struct in6_addr val);
+
+}; /* End of class RoutingHeader */
+
+#endif
diff --git a/libnetutil/TCPHeader.cc b/libnetutil/TCPHeader.cc
new file mode 100644
index 0000000..e35d5e1
--- /dev/null
+++ b/libnetutil/TCPHeader.cc
@@ -0,0 +1,936 @@
+/***************************************************************************
+ * TCPHeader.cc -- The TCPHeader Class represents a TCP packet. It *
+ * contains methods to set the different header fields. These methods *
+ * tipically perform the necessary error checks and byte order *
+ * conversions. *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#include "TCPHeader.h"
+#include <assert.h>
+/******************************************************************************/
+/* CONTRUCTORS, DESTRUCTORS AND INITIALIZATION METHODS */
+/******************************************************************************/
+TCPHeader::TCPHeader(){
+ this->reset();
+} /* End of TCPHeader constructor */
+
+
+TCPHeader::~TCPHeader(){
+
+} /* End of TCPHeader destructor */
+
+/** Sets every attribute to its default value */
+void TCPHeader::reset(){
+ memset(&this->h, 0, sizeof(nping_tcp_hdr_t));
+ this->length=TCP_HEADER_LEN; /* Initial value 20. This will be incremented if options are used */
+ this->tcpoptlen=0;
+ this->setSourcePort(TCP_DEFAULT_SPORT);
+ this->setDestinationPort(TCP_DEFAULT_DPORT);
+ this->setSeq(TCP_DEFAULT_SEQ);
+ this->setAck(TCP_DEFAULT_ACK);
+ this->setFlags(TCP_DEFAULT_FLAGS);
+ this->setWindow(TCP_DEFAULT_WIN);
+ this->setUrgPointer(TCP_DEFAULT_URP);
+ this->setOffset();
+} /* End of reset() */
+
+
+/******************************************************************************/
+/* PacketElement:: OVERWRITTEN METHODS */
+/******************************************************************************/
+
+/** @warning This method is essential for the superclass getBinaryBuffer()
+ * method to work. Do NOT change a thing unless you know what you're doing */
+u8 * TCPHeader::getBufferPointer(){
+ return (u8*)(&h);
+} /* End of getBufferPointer() */
+
+
+/** Stores supplied packet in the internal buffer so the information
+ * can be accessed using the standard get & set methods.
+ * @warning The TCPHeader class is able to hold a maximum of 60 bytes. If the
+ * supplied buffer is longer than that, only the first 60 bytes will be stored
+ * in the internal buffer.
+ * @warning Supplied len MUST be at least 20 bytes (min TCP header length).
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error */
+int TCPHeader::storeRecvData(const u8 *buf, size_t len){
+ if(buf==NULL || len<TCP_HEADER_LEN){
+ return OP_FAILURE;
+ }else{
+ int stored_len = MIN((TCP_HEADER_LEN + MAX_TCP_OPTIONS_LEN), len);
+ this->reset(); /* Re-init the object, just in case the caller had used it already */
+ this->length=stored_len;
+ if(stored_len>TCP_HEADER_LEN)
+ this->tcpoptlen=stored_len-TCP_HEADER_LEN;
+ memcpy(&(this->h), buf, stored_len);
+ }
+ return OP_SUCCESS;
+} /* End of storeRecvData() */
+
+
+/* Returns a protocol identifier. This is used by packet parsing funtions
+ * that return linked lists of PacketElement objects, to determine the protocol
+ * the object represents. */
+int TCPHeader::protocol_id() const {
+ return HEADER_TYPE_TCP;
+} /* End of protocol_id() */
+
+
+/** Determines if the data stored in the object after an storeRecvData() call
+ * is valid and safe to use. This mainly checks the length of the data but may
+ * also test the value of certain protocol fields to ensure their correctness.
+ * @warning If the information stored in the object has been set through a
+ * call to storeRecvData(), the object's internal length count may be updated
+ * if the validation is successful.
+ * @return the length, in bytes, of the header, if its found to be valid or
+ * OP_FAILURE (-1) otherwise. */
+int TCPHeader::validate(){
+ if(this->getOffset()<5)
+ return OP_FAILURE;
+ else if(this->getOffset()*4 > this->length)
+ return OP_FAILURE;
+ this->length=this->getOffset()*4;
+ return this->length;
+} /* End of validate() */
+
+
+/** Prints the contents of the header and calls print() on the next protocol
+ * header in the chain (if there is any).
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error. */
+int TCPHeader::print(FILE *output, int detail) const {
+ char optinfo[256];
+ fprintf(output, "TCP[");
+ fprintf(output, "%d", this->getSourcePort());
+ fprintf(output, " >");
+ fprintf(output, " %d", this->getDestinationPort());
+ fprintf(output, " %s%s%s%s%s%s%s%s",
+ !this->getSYN() ? "" : "S",
+ !this->getFIN() ? "" : "F",
+ !this->getRST() ? "" : "R",
+ !this->getPSH() ? "" : "P",
+ !this->getACK() ? "" : "A",
+ !this->getURG() ? "" : "U",
+ !this->getECN() ? "" : "E",
+ !this->getCWR() ? "" : "C"
+ );
+ fprintf(output, " seq=%lu", (long unsigned int)this->getSeq() );
+ if(detail>=PRINT_DETAIL_HIGH){
+ fprintf(output, " ack=%lu", (long unsigned int)this->getAck() );
+ fprintf(output, " off=%d", this->getOffset() );
+ fprintf(output, " res=%d", this->h.th_x2);
+ }
+ fprintf(output, " win=%hu", this->getWindow() );
+ if(detail>=PRINT_DETAIL_MED)
+ fprintf(output, " csum=0x%04X", ntohs( this->getSum() ));
+ if(detail>=PRINT_DETAIL_HIGH)
+ fprintf(output, " urp=%d", this->getUrgPointer() );
+
+ if(this->tcpoptlen>0 && (this->length >= TCP_HEADER_LEN+this->tcpoptlen) && this->tcpoptlen<=MAX_TCP_OPTIONS_LEN){
+ this->__tcppacketoptinfo(this->h.options, this->tcpoptlen, optinfo, sizeof(optinfo)-1);
+ optinfo[255]='\0';
+ fprintf(output, " %s", optinfo);
+ }
+ fprintf(output, "]");
+
+ if(this->next!=NULL){
+ print_separator(output, detail);
+ next->print(output, detail);
+ }
+ return OP_SUCCESS;
+} /* End of print() */
+
+
+/* Get an ASCII information about a tcp option which is pointed by
+ optp, with a length of len. The result is stored in the result
+ buffer. The result may look like "<mss 1452,sackOK,timestamp
+ 45848914 0,nop,wscale 7>" */
+void TCPHeader::__tcppacketoptinfo(const u8 *optp, int len, char *result, int bufsize) const {
+ assert(optp);
+ assert(result);
+ char *p, ch;
+ const u8 *q;
+ int opcode;
+ u16 tmpshort;
+ u32 tmpword1, tmpword2;
+ unsigned int i=0;
+
+ p = result;
+ *p = '\0';
+ q = optp;
+ ch = '<';
+
+ while (len > 0 && bufsize > 2) {
+ Snprintf(p, bufsize, "%c", ch);
+ bufsize--;
+ p++;
+ opcode = *q++;
+ if (!opcode) { /* End of List */
+
+ Snprintf(p, bufsize, "eol");
+ bufsize -= strlen(p);
+ p += strlen(p);
+
+ len--;
+
+ } else if (opcode == 1) { /* No Op */
+ Snprintf(p, bufsize, "nop");
+ bufsize -= strlen(p);
+ p += strlen(p);
+
+ len--;
+ } else if (opcode == 2) { /* MSS */
+ if (len < 4)
+ break; /* MSS has 4 bytes */
+
+ q++;
+ memcpy(&tmpshort, q, 2);
+
+ Snprintf(p, bufsize, "mss %u", ntohs(tmpshort));
+ bufsize -= strlen(p);
+ p += strlen(p);
+
+ q += 2;
+ len -= 4;
+ } else if (opcode == 3) { /* Window Scale */
+ if (len < 3)
+ break; /* Window Scale option has 3 bytes */
+
+ q++;
+
+ Snprintf(p, bufsize, "wscale %u", *q);
+ bufsize -= strlen(p);
+ p += strlen(p);
+
+ q++;
+ len -= 3;
+ } else if (opcode == 4) { /* SACK permitted */
+ if (len < 2)
+ break; /* SACK permitted option has 2 bytes */
+
+ Snprintf(p, bufsize, "sackOK");
+ bufsize -= strlen(p);
+ p += strlen(p);
+
+ q++;
+ len -= 2;
+ } else if (opcode == 5) { /* SACK */
+ unsigned sackoptlen = *q;
+ if ((unsigned) len < sackoptlen)
+ break;
+
+ /* This would break parsing, so it's best to just give up */
+ if (sackoptlen < 2)
+ break;
+
+ q++;
+
+ if ((sackoptlen - 2) == 0 || ((sackoptlen - 2) % 8 != 0)) {
+ Snprintf(p, bufsize, "malformed sack");
+ bufsize -= strlen(p);
+ p += strlen(p);
+ } else {
+ Snprintf(p, bufsize, "sack %d ", (sackoptlen - 2) / 8);
+ bufsize -= strlen(p);
+ p += strlen(p);
+ for (i = 0; i < sackoptlen - 2; i += 8) {
+ memcpy(&tmpword1, q + i, 4);
+ memcpy(&tmpword2, q + i + 4, 4);
+ Snprintf(p, bufsize, "{%u:%u}", tmpword1, tmpword2);
+ bufsize -= strlen(p);
+ p += strlen(p);
+ }
+ }
+
+ q += sackoptlen - 2;
+ len -= sackoptlen;
+ } else if (opcode == 8) { /* Timestamp */
+ if (len < 10)
+ break; /* Timestamp option has 10 bytes */
+
+ q++;
+ memcpy(&tmpword1, q, 4);
+ memcpy(&tmpword2, q + 4, 4);
+
+ Snprintf(p, bufsize, "timestamp %u %u", ntohl(tmpword1),
+ ntohl(tmpword2));
+ bufsize -= strlen(p);
+ p += strlen(p);
+
+ q += 8;
+ len -= 10;
+ }
+
+ ch = ',';
+ }
+
+ if (len > 0) {
+ *result = '\0';
+ return;
+ }
+
+ Snprintf(p, bufsize, ">");
+}
+
+
+
+/******************************************************************************/
+/* PROTOCOL-SPECIFIC METHODS */
+/******************************************************************************/
+
+/** Sets source port.
+ * @warning Port must be supplied in host byte order. This method performs
+ * byte order conversion using htons() */
+int TCPHeader::setSourcePort(u16 p){
+ h.th_sport = htons(p);
+ return OP_SUCCESS;
+} /* End of setSourcePort() */
+
+
+/** Returns source port in HOST byte order */
+u16 TCPHeader::getSourcePort() const {
+ return ntohs(h.th_sport);
+} /* End of getSourcePort() */
+
+
+/** Sets destination port.
+ * @warning Port must be supplied in host byte order. This method performs
+ * byte order conversion using htons() */
+int TCPHeader::setDestinationPort(u16 p){
+ h.th_dport = htons(p);
+ return OP_SUCCESS;
+} /* End of setDestinationPort() */
+
+
+/** Returns destination port in HOST byte order */
+u16 TCPHeader::getDestinationPort() const {
+ return ntohs(h.th_dport);
+} /* End of getDestinationPort() */
+
+
+/** Sets sequence number.
+ * @warning Seq number must be supplied in host byte order. This method
+ * performs byte order conversion using htonl() */
+int TCPHeader::setSeq(u32 p){
+ h.th_seq = htonl(p);
+ return OP_SUCCESS;
+} /* End of setSeq() */
+
+
+/** Returns sequence number in HOST byte order */
+u32 TCPHeader::getSeq() const {
+ return ntohl(h.th_seq);
+} /* End of getSeq() */
+
+
+/** Sets acknowledgement number.
+ * @warning ACK number must be supplied in host byte order. This method
+ * performs byte order conversion using htonl() */
+int TCPHeader::setAck(u32 p){
+ h.th_ack = htonl(p);
+ return OP_SUCCESS;
+} /* End of setAck() */
+
+
+/** Returns ACK number in HOST byte order */
+u32 TCPHeader::getAck() const {
+ return ntohl(h.th_ack);
+} /* End of getAck() */
+
+
+/* TODO: Test this method. It may not work becuasse th_off is supposed to
+ * be 4 bits long and arg o is 8.
+ * UPDATE: It seems to work just fine. However, let's keep this note just
+ * in case problems arise. */
+int TCPHeader::setOffset(u8 o){
+ h.th_off = o;
+ return OP_SUCCESS;
+} /* End of setOffset() */
+
+
+int TCPHeader::setOffset(){
+ h.th_off = 5 + tcpoptlen/4;
+ return OP_SUCCESS;
+} /* End of setOffset() */
+
+
+/** Returns offset value */
+u8 TCPHeader::getOffset() const {
+ return h.th_off;
+} /* End of getOffset() */
+
+
+/* Sets the 4-bit reserved field (Note that there are not 4 reserved bits anymore
+ * as RFC 3540 introduces a new TCP flag, so calling this will overwrite
+ * the value of such flag. */
+int TCPHeader::setReserved(u8 r){
+ h.th_x2 = r;
+ return OP_SUCCESS;
+}
+
+
+u8 TCPHeader::getReserved() const {
+ return h.th_x2;
+}
+
+
+/** Sets TCP flags */
+int TCPHeader::setFlags(u8 f){
+ h.th_flags = f;
+ return OP_SUCCESS;
+} /* End of setFlags() */
+
+
+/** Returns the 8bit flags field of the TCP header */
+u8 TCPHeader::getFlags() const {
+ return h.th_flags;
+} /* End of getFlags() */
+
+
+/* Returns the 16bit flags field of the TCP header. As RFC 3540 defines a new
+ * flag (NS), we no longer can store all TCP flags in a single octet, so
+ * this method returns the flags as a two-octet unsigned integer. */
+u16 TCPHeader::getFlags16() const {
+ /* Obtain the value of dataoff+reserved+flags in host byte order */
+ u16 field=ntohs(*(u16 *)(((u8 *)&this->h)+12));
+ /* Erase the contents of the data offset field */
+ field = field & 0x0FFF;
+ return field;
+} /* End of getFlags16() */
+
+
+/** Sets flag CWR
+ * @return Previous state of the flag */
+bool TCPHeader::setCWR(){
+ u8 prev = h.th_flags & TH_CWR;
+ h.th_flags |= TH_CWR;
+ return prev;
+} /* End of setCWR() */
+
+
+/** Unsets flag CWR
+ * @return Previous state of the flag */
+bool TCPHeader::unsetCWR(){
+ u8 prev = h.th_flags & TH_CWR;
+ h.th_flags ^= TH_CWR;
+ return prev;
+} /* End of unsetCWR() */
+
+
+/** Get CWR flag */
+bool TCPHeader::getCWR() const {
+ return h.th_flags & TH_CWR;
+} /* End of getCWR() */
+
+
+/** Sets flag ECE/ECN
+ * @return Previous state of the flag */
+bool TCPHeader::setECE(){
+ u8 prev = h.th_flags & TH_ECN;
+ h.th_flags |= TH_ECN;
+ return prev;
+} /* End of setECE() */
+
+
+/** Unsets flag ECE/ECN
+ * @return Previous state of the flag */
+bool TCPHeader::unsetECE(){
+ u8 prev = h.th_flags & TH_ECN;
+ h.th_flags ^= TH_ECN;
+ return prev;
+} /* End of unsetECE() */
+
+
+/** Get CWR flag */
+bool TCPHeader::getECE() const {
+ return h.th_flags & TH_ECN;
+} /* End of getECE() */
+
+
+/** Same as setECE() but with a different name since there are two possible
+ * ways to call this flag
+ * @return Previous state of the flag */
+bool TCPHeader::setECN(){
+ u8 prev = h.th_flags & TH_ECN;
+ h.th_flags |= TH_ECN;
+ return prev;
+} /* End of setECN() */
+
+
+/** Unsets flag ECE/ECN
+ * @return Previous state of the flag */
+bool TCPHeader::unsetECN(){
+ u8 prev = h.th_flags & TH_ECN;
+ h.th_flags ^= TH_ECN;
+ return prev;
+} /* End of unsetECN() */
+
+
+/** Get ECN flag */
+bool TCPHeader::getECN() const {
+ return h.th_flags & TH_ECN;
+} /* End of getECN() */
+
+
+/** Sets flag URG
+ * @return Previous state of the flag */
+bool TCPHeader::setURG(){
+ u8 prev = h.th_flags & TH_URG;
+ h.th_flags |= TH_URG;
+ return prev;
+} /* End of setURG() */
+
+
+/** Unsets flag URG
+ * @return Previous state of the flag */
+bool TCPHeader::unsetURG(){
+ u8 prev = h.th_flags & TH_URG;
+ h.th_flags ^= TH_URG;
+ return prev;
+} /* End of unsetURG() */
+
+
+/** Get URG flag */
+bool TCPHeader::getURG() const {
+ return h.th_flags & TH_URG;
+} /* End of getURG() */
+
+
+/** Sets flag ACK
+ * @return Previous state of the flag */
+bool TCPHeader::setACK(){
+ u8 prev = h.th_flags & TH_ACK;
+ h.th_flags |= TH_ACK;
+ return prev;
+} /* End of setACK() */
+
+
+/** Unsets flag ACK
+ * @return Previous state of the flag */
+bool TCPHeader::unsetACK(){
+ u8 prev = h.th_flags & TH_ACK;
+ h.th_flags ^= TH_ACK;
+ return prev;
+} /* End of unsetACK() */
+
+
+/** Get ACK flag */
+bool TCPHeader::getACK() const {
+ return h.th_flags & TH_ACK;
+} /* End of getACK() */
+
+
+/** Sets flag PSH
+ * @return Previous state of the flag */
+bool TCPHeader::setPSH(){
+ u8 prev = h.th_flags & TH_PSH;
+ h.th_flags |= TH_PSH;
+ return prev;
+} /* End of setPSH() */
+
+
+/** Unsets flag PSH
+ * @return Previous state of the flag */
+bool TCPHeader::unsetPSH(){
+ u8 prev = h.th_flags & TH_PSH;
+ h.th_flags ^= TH_PSH;
+ return prev;
+} /* End of unsetPSH() */
+
+
+/** Get PSH flag */
+bool TCPHeader::getPSH() const {
+ return h.th_flags & TH_PSH;
+} /* End of getPSH() */
+
+
+/** Sets flag RST
+ * @return Previous state of the flag */
+bool TCPHeader::setRST(){
+ u8 prev = h.th_flags & TH_RST;
+ h.th_flags |= TH_RST;
+ return prev;
+} /* End of setRST() */
+
+
+/** Unsets flag RST
+ * @return Previous state of the flag */
+bool TCPHeader::unsetRST(){
+ u8 prev = h.th_flags & TH_RST;
+ h.th_flags ^= TH_RST;
+ return prev;
+} /* End of unsetRST() */
+
+
+/** Get RST flag */
+bool TCPHeader::getRST() const {
+ return h.th_flags & TH_RST;
+} /* End of getRST() */
+
+
+/** Sets flag SYN
+ * @return Previous state of the flag */
+bool TCPHeader::setSYN(){
+ u8 prev = h.th_flags & TH_SYN;
+ h.th_flags |= TH_SYN;
+ return prev;
+} /* End of setSYN() */
+
+
+/** Unsets flag SYN
+ * @return Previous state of the flag */
+bool TCPHeader::unsetSYN(){
+ u8 prev = h.th_flags & TH_SYN;
+ h.th_flags ^= TH_SYN;
+ return prev;
+} /* End of unsetSYN() */
+
+
+/** Get SYN flag */
+bool TCPHeader::getSYN() const {
+ return h.th_flags & TH_SYN;
+} /* End of getSYN() */
+
+
+/** Sets flag FIN
+ * @return Previous state of the flag */
+bool TCPHeader::setFIN(){
+ u8 prev = h.th_flags & TH_FIN;
+ h.th_flags |= TH_FIN;
+ return prev;
+} /* End of setFIN() */
+
+
+/** Unsets flag FIN
+ * @return Previous state of the flag */
+bool TCPHeader::unsetFIN(){
+ u8 prev = h.th_flags & TH_FIN;
+ h.th_flags ^= TH_FIN;
+ return prev;
+} /* End of unsetFIN() */
+
+
+/** Get FIN flag */
+bool TCPHeader::getFIN() const {
+ return h.th_flags & TH_FIN;
+} /* End of getFIN() */
+
+
+/** Sets window size.
+ * @warning Win number must be supplied in host byte order. This method
+ * performs byte order conversion using htons() */
+int TCPHeader::setWindow(u16 p){
+ h.th_win = htons(p);
+ return OP_SUCCESS;
+} /* End of setWindow() */
+
+
+/** Returns window size in HOST byte order. */
+u16 TCPHeader::getWindow() const {
+ return ntohs(h.th_win);
+} /* End of getWindow() */
+
+
+/** Sets urgent pointer.
+ * @warning Pointer must be supplied in host byte order. This method
+ * performs byte order conversion using htons() */
+int TCPHeader::setUrgPointer(u16 l){
+ h.th_urp = htons(l);
+ return OP_SUCCESS;
+} /* End of setUrgPointer() */
+
+
+/** Returns Urgent Pointer in HOST byte order. */
+u16 TCPHeader::getUrgPointer() const {
+ return ntohs(h.th_urp);
+} /* End of getUrgPointer() */
+
+
+int TCPHeader::setSum(struct in_addr src, struct in_addr dst){
+ int bufflen;
+ u8 aux[ MAX_TCP_PAYLOAD_LEN ];
+ /* FROM: RFC 1323: TCP Extensions for High Performance, March 4, 2009
+ *
+ * "With IP Version 4, the largest amount of TCP data that can be sent in
+ * a single packet is 65495 bytes (64K - 1 - size of fixed IP and TCP
+ * headers)".
+ *
+ * In theory TCP should not worry about the practical max payload length
+ * because it is supposed to be independent of the network layer. However,
+ * since TCP does not have any length field and we need to allocate a
+ * buffer, we are using that value. (Note htat in UDPHeader.cc we do just
+ * the opposite, forget about the practical limitation and allow the
+ * theorical limit for the payload. */
+ h.th_sum = 0;
+
+ /* Copy packet contents to a buffer */
+ bufflen=dumpToBinaryBuffer(aux, MAX_TCP_PAYLOAD_LEN);
+
+ /* Compute checksum */
+ h.th_sum = ipv4_pseudoheader_cksum(&src, &dst, IPPROTO_TCP, bufflen, (char *)aux);
+
+ return OP_SUCCESS;
+} /* End of setSum() */
+
+
+/** @warning Sum is set to supplied value with NO byte ordering conversion
+ * performed. */
+int TCPHeader::setSum(u16 s){
+ h.th_sum = s;
+ return OP_SUCCESS;
+} /* End of setSum() */
+
+
+int TCPHeader::setSum(){
+ this->h.th_sum=0;
+ this->h.th_sum = this->compute_checksum();
+ return OP_SUCCESS;
+} /* End of setSum() */
+
+
+/** Set the TCP checksum field to a random value, which may accidentally
+ * match the correct checksum */
+int TCPHeader::setSumRandom(){
+ h.th_sum=get_random_u16();
+ return OP_SUCCESS;
+} /* End of setSumRandom() */
+
+/** Set the TCP checksum field to a random value. It takes the source and
+ * destination address to make sure the random generated sum does not
+ * accidentally match the correct checksum. This function only handles
+ * IPv4 address. */
+int TCPHeader::setSumRandom(struct in_addr source, struct in_addr destination){
+ u16 correct_csum=0;
+ /* Compute the correct checksum */
+ this->setSum(source, destination);
+ correct_csum=this->getSum();
+ /* Generate numbers until one does not match the correct sum */
+ while( (h.th_sum=get_random_u16())==correct_csum);
+ return OP_SUCCESS;
+} /* End of setSumRandom() */
+
+
+/** Returns the TCP checksum field in NETWORK byte order */
+u16 TCPHeader::getSum() const {
+ return h.th_sum;
+} /* End of getSum() */
+
+
+/* Copies the supplied buffer into the TCP options field. Note that the supplied
+ * buffer MUST NOT exceed MAX_TCP_OPTIONS_LEN octets and should be a multiple of
+ * four. If it is not a multiple of four, no error will be returned but the
+ * behaviour is unspecified. If this method is called passing NULL and zero
+ * ( t.setOptions(NULL, 0), any existing options are cleared, and the object's
+ * internal length is updated accordingly. Also, note that a call to setOptions()
+ * involves an automatic call to setOffset(), which updates the Offset field
+ * to take into account the new header length. If you need to set a bogus
+ * data offset, you can do so after calling setOptions(), but not before.
+ * It returns OP_SUCCESS on success and OP_FAILURE in case of error */
+int TCPHeader::setOptions(const u8 *optsbuff, size_t optslen){
+ /* NULL and length=0 means delete existing options */
+ if(optsbuff==NULL && optslen==0){
+ this->tcpoptlen=0;
+ this->length=TCP_HEADER_LEN;
+ memset(this->h.options, 0, MAX_TCP_OPTIONS_LEN);
+ return OP_SUCCESS;
+
+ /* Make sure params are safe to use */
+ }else if(optsbuff==NULL || optslen==0 || optslen>MAX_TCP_OPTIONS_LEN){
+ return OP_FAILURE;
+
+ /* Copy supplied buffer into the options field, and update the offset field. */
+ }else{
+ memcpy(this->h.options, optsbuff, optslen);
+ this->tcpoptlen=optslen;
+ this->length=TCP_HEADER_LEN+optslen;
+ this->setOffset();
+ return OP_SUCCESS;
+ }
+} /* End of setOptions() */
+
+
+/* Returns a pointer to the start of the TCP options field. If the supplied
+ * "optslen" pointer is not NULL, the length of the options will be stored
+ * there. */
+const u8 *TCPHeader::getOptions(size_t *optslen) const {
+ if(optslen!=NULL)
+ *optslen=this->tcpoptlen;
+ return this->h.options;
+} /* End of getOptions() */
+
+
+/* Returns the index-th option in the TCP header. On success it returns a
+ * structure filled with option information. If there is no index-th option,
+ * it returns a structure with st.value==NULL. Note that this function does
+ * not perform strict validity checking. It does check that the length claimed
+ * by the options does not exceed the available buffer but it does not check,
+ * for example, that the MSS option always contains a length of 4. Also,
+ * if the returned option type is TCPOPT_EOL or TCPOPT_NOOP, the len field
+ * would be set to zero and the "value" field should NOT be accessed, as it
+ * will not contain reliable information. */
+nping_tcp_opt_t TCPHeader::getOption(unsigned int index) const {
+ nping_tcp_opt_t *curr_opt=NULL;
+ u8 *curr_pnt=(u8 *)this->h.options;
+ int bytes_left=this->length - TCP_HEADER_LEN;
+ assert((this->length - TCP_HEADER_LEN) == this->tcpoptlen);
+ unsigned int optsfound=0;
+ nping_tcp_opt_t result;
+ memset(&result, 0, sizeof(nping_tcp_opt_t));
+
+ while(bytes_left>0){
+ /* Use the opts structure as a template to access current option. It is
+ * OK to use it because we only access the first two elements. */
+ curr_opt=(nping_tcp_opt_t *)curr_pnt;
+
+ /* If we are right in the option that the caller wants, just return it */
+ if(optsfound==index){
+ result.type=curr_opt->type;
+ if(result.type==TCPOPT_EOL || result.type==TCPOPT_NOOP)
+ result.len=1;
+ else
+ result.len=curr_opt->len;
+ result.value=(u8 *)curr_pnt+2;
+ return result;
+ }
+
+ /* Otherwise, we have to parse it, so we can skip it and access the next
+ * option */
+ switch(curr_opt->type){
+
+ /* EOL or NOOP
+ +-+-+-+-+-+-+-+-+
+ | X |
+ +-+-+-+-+-+-+-+-+ */
+ case TCPOPT_EOL:
+ goto out;
+
+ case TCPOPT_NOOP:
+ curr_pnt++; /* Skip one octet */
+ bytes_left--;
+ break;
+
+ /* TLV encoded option */
+ default:
+ /* If we don't have as many octets as the option advertises, the
+ * option is bogus. Return failure. */
+ if(bytes_left<curr_opt->len)
+ return result;
+ curr_pnt+=curr_opt->len;
+ bytes_left-=curr_opt->len;
+ break;
+ }
+ optsfound++;
+ }
+
+out:
+ return result;
+}
+
+
+/* Returns a textual representation of a TCP Options code */
+const char *TCPHeader::optcode2str(u8 optcode){
+ switch(optcode){
+ case TCPOPT_EOL:
+ return "EOL";
+ case TCPOPT_NOOP:
+ return "NOOP";
+ case TCPOPT_MSS:
+ return "MSS";
+ case TCPOPT_WSCALE:
+ return "WScale";
+ case TCPOPT_SACKOK:
+ return "SAckOK";
+ case TCPOPT_SACK:
+ return "SAck";
+ case TCPOPT_ECHOREQ:
+ return "EchoReq";
+ case TCPOPT_ECHOREP:
+ return "EchoRep";
+ case TCPOPT_TSTAMP:
+ return "TStamp";
+ case TCPOPT_POCP:
+ return "POCP";
+ case TCPOPT_POSP:
+ return "POSP";
+ case TCPOPT_CC:
+ return "CC";
+ case TCPOPT_CCNEW:
+ return "CC.NEW";
+ case TCPOPT_CCECHO:
+ return "CC.ECHO";
+ case TCPOPT_ALTCSUMREQ:
+ return "AltSumReq";
+ case TCPOPT_ALTCSUMDATA:
+ return "AltSumData";
+ case TCPOPT_MD5:
+ return "MD5";
+ case TCPOPT_SCPS:
+ return "SCPS";
+ case TCPOPT_SNACK:
+ return "SNAck";
+ case TCPOPT_QSRES:
+ return "QStart";
+ case TCPOPT_UTO:
+ return "UTO";
+ case TCPOPT_AO:
+ return "AO";
+ default:
+ return "Unknown";
+ }
+} /* End of optcode2str() */
+
+
diff --git a/libnetutil/TCPHeader.h b/libnetutil/TCPHeader.h
new file mode 100644
index 0000000..6178be2
--- /dev/null
+++ b/libnetutil/TCPHeader.h
@@ -0,0 +1,259 @@
+/***************************************************************************
+ * TCPHeader.h -- The TCPHeader Class represents a TCP packet. It contains *
+ * methods to set the different header fields. These methods tipically *
+ * perform the necessary error checks and byte order conversions. *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#ifndef __TCPHEADER_H__
+#define __TCPHEADER_H__ 1
+
+#include "TransportLayerElement.h"
+
+/* TCP FLAGS */
+#define TH_FIN 0x01
+#define TH_SYN 0x02
+#define TH_RST 0x04
+#define TH_PSH 0x08
+#define TH_ACK 0x10
+#define TH_URG 0x20
+#define TH_ECN 0x40
+#define TH_CWR 0x80
+
+/* TCP OPTIONS */
+#define TCPOPT_EOL 0 /* End of Option List (RFC793) */
+#define TCPOPT_NOOP 1 /* No-Operation (RFC793) */
+#define TCPOPT_MSS 2 /* Maximum Segment Size (RFC793) */
+#define TCPOPT_WSCALE 3 /* WSOPT - Window Scale (RFC1323) */
+#define TCPOPT_SACKOK 4 /* SACK Permitted (RFC2018) */
+#define TCPOPT_SACK 5 /* SACK (RFC2018) */
+#define TCPOPT_ECHOREQ 6 /* Echo (obsolete) (RFC1072)(RFC6247) */
+#define TCPOPT_ECHOREP 7 /* Echo Reply (obsolete) (RFC1072)(RFC6247) */
+#define TCPOPT_TSTAMP 8 /* TSOPT - Time Stamp Option (RFC1323) */
+#define TCPOPT_POCP 9 /* Partial Order Connection Permitted (obsol.) */
+#define TCPOPT_POSP 10 /* Partial Order Service Profile (obsolete) */
+#define TCPOPT_CC 11 /* CC (obsolete) (RFC1644)(RFC6247) */
+#define TCPOPT_CCNEW 12 /* CC.NEW (obsolete) (RFC1644)(RFC6247) */
+#define TCPOPT_CCECHO 13 /* CC.ECHO (obsolete) (RFC1644)(RFC6247) */
+#define TCPOPT_ALTCSUMREQ 14 /* TCP Alternate Checksum Request (obsolete) */
+#define TCPOPT_ALTCSUMDATA 15 /* TCP Alternate Checksum Data (obsolete) */
+#define TCPOPT_MD5 19 /* MD5 Signature Option (obsolete) (RFC2385) */
+#define TCPOPT_SCPS 20 /* SCPS Capabilities */
+#define TCPOPT_SNACK 21 /* Selective Negative Acknowledgements */
+#define TCPOPT_QSRES 27 /* Quick-Start Response (RFC4782) */
+#define TCPOPT_UTO 28 /* User Timeout Option (RFC5482) */
+#define TCPOPT_AO 29 /* TCP Authentication Option (RFC5925) */
+
+/* Internal constants */
+#define TCP_HEADER_LEN 20
+#define MAX_TCP_OPTIONS_LEN 40
+#define MAX_TCP_PAYLOAD_LEN 65495 /**< Max len of a TCP packet */
+
+/* Default header values */
+#define TCP_DEFAULT_SPORT 20
+#define TCP_DEFAULT_DPORT 80
+#define TCP_DEFAULT_SEQ 0
+#define TCP_DEFAULT_ACK 0
+#define TCP_DEFAULT_FLAGS 0x02
+#define TCP_DEFAULT_WIN 8192
+#define TCP_DEFAULT_URP 0
+
+
+
+/*
++--------+--------+---------+--------...
+| Type | Len | Value
++--------+--------+---------+--------...
+*/
+struct nping_tcp_opt {
+ u8 type; /* Option type code. */
+ u8 len; /* Option length. */
+ u8 *value; /* Option value */
+}__attribute__((__packed__));
+typedef struct nping_tcp_opt nping_tcp_opt_t;
+
+
+class TCPHeader : public TransportLayerElement {
+
+ private:
+ /*
+ 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
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Source Port | Destination Port |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Sequence Number |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Acknowledgment Number |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Offset| Res. |C|E|U|A|P|R|S|F| Window |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Checksum | Urgent Pointer |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Options | Padding |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ struct nping_tcp_hdr {
+ u16 th_sport; /* Source port */
+ u16 th_dport; /* Destination port */
+ u32 th_seq; /* Sequence number */
+ u32 th_ack; /* Acknowledgement number */
+ #if WORDS_BIGENDIAN
+ u8 th_off:4; /* Data offset */
+ u8 th_x2:4; /* Reserved */
+ #else
+ u8 th_x2:4; /* Reserved */
+ u8 th_off:4; /* Data offset */
+ #endif
+ u8 th_flags; /* Flags */
+ u16 th_win; /* Window size */
+ u16 th_sum; /* Checksum */
+ u16 th_urp; /* Urgent pointer */
+
+ u8 options[MAX_TCP_OPTIONS_LEN ]; /* Space for TCP Options */
+ }__attribute__((__packed__));
+
+ typedef struct nping_tcp_hdr nping_tcp_hdr_t;
+
+ nping_tcp_hdr_t h;
+
+ int tcpoptlen; /**< Length of TCP options */
+
+ void __tcppacketoptinfo(const u8 *optp, int len, char *result, int bufsize) const;
+
+ public:
+
+ TCPHeader();
+ ~TCPHeader();
+ void reset();
+ u8 *getBufferPointer();
+ int storeRecvData(const u8 *buf, size_t len);
+ int protocol_id() const;
+ int validate();
+ int print(FILE *output, int detail) const;
+
+ int setSourcePort(u16 p);
+ u16 getSourcePort() const;
+
+ int setDestinationPort(u16 p);
+ u16 getDestinationPort() const;
+
+ int setSeq(u32 p);
+ u32 getSeq() const;
+
+ int setAck(u32 p);
+ u32 getAck() const;
+
+ int setOffset(u8 o);
+ int setOffset();
+ u8 getOffset() const;
+
+ int setReserved(u8 r);
+ u8 getReserved() const;
+
+ int setFlags(u8 f);
+ u8 getFlags() const;
+ u16 getFlags16() const;
+ bool setCWR();
+ bool unsetCWR();
+ bool getCWR() const;
+ bool setECE();
+ bool unsetECE();
+ bool getECE() const;
+ bool setECN();
+ bool unsetECN();
+ bool getECN() const;
+ bool setURG();
+ bool unsetURG();
+ bool getURG() const;
+ bool setACK();
+ bool unsetACK();
+ bool getACK() const;
+ bool setPSH();
+ bool unsetPSH();
+ bool getPSH() const;
+ bool setRST();
+ bool unsetRST();
+ bool getRST() const;
+ bool setSYN();
+ bool unsetSYN();
+ bool getSYN() const;
+ bool setFIN();
+ bool unsetFIN();
+ bool getFIN() const;
+
+ int setWindow(u16 p);
+ u16 getWindow() const;
+
+ int setUrgPointer(u16 l);
+ u16 getUrgPointer() const;
+
+ int setSum(u16 s);
+ int setSum(struct in_addr source, struct in_addr destination);
+ int setSum();
+ int setSumRandom();
+ int setSumRandom(struct in_addr source, struct in_addr destination);
+ u16 getSum() const;
+
+ int setOptions(const u8 *optsbuff, size_t optslen);
+ const u8 *getOptions(size_t *optslen) const;
+ nping_tcp_opt_t getOption(unsigned int index) const;
+ static const char *optcode2str(u8 optcode);
+
+}; /* End of class TCPHeader */
+
+#endif /* __TCPHEADER_H__ */
diff --git a/libnetutil/TransportLayerElement.cc b/libnetutil/TransportLayerElement.cc
new file mode 100644
index 0000000..cdbbb9e
--- /dev/null
+++ b/libnetutil/TransportLayerElement.cc
@@ -0,0 +1,126 @@
+/***************************************************************************
+ * TransportLayerElement.cc -- Class TransportLayerElement is a generic *
+ * class that represents a transport layer protocol header. Classes like *
+ * TCPHeader or UDPHeader inherit from it. *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#include "TransportLayerElement.h"
+#include "IPv4Header.h"
+#include "IPv6Header.h"
+
+
+/** Computes and returns the Internet checksum.
+ * @warning This method requires the object to be linked to either an IPv6Header
+ * object or an IPv4Header one, so the caller must ensure that objects are
+ * properly linked with calls to setNextElement() like this:
+ *
+ * IPv6Header ip6;
+ * TCPHeader tcp;
+ * [...] # Set header fields
+ * ip6.setNextElement(&tcp);
+ * tcp.setSum();
+ *
+ * Note that there can be a number of other headers (like IPv6 extension headers)
+ * between the transport header and the network one, but all of them need to
+ * be linked in order for this method to traverse the list of headers and find
+ * the IP source and destination address, required to compute the checksum. So
+ * things like the following are OK:
+ *
+ * IPv6Header ip6;
+ * HopByHopHeader hop;
+ * RoutingHeader rte;
+ * FragmentHeader frg;
+ * UDPHeader udp;
+ * [...] # Set whatever header fields you need
+ * ip6.setNextElement(&hop);
+ * hop.setNextElement(&rte);
+ * rte.setNextElement(&frg);
+ * frg.setNextElement(&udp);
+ * udp.setSum(); # setSum() will be able to reach the IPv6Header. */
+u16 TransportLayerElement::compute_checksum(){
+ PacketElement *hdr;
+ hdr=this->getPrevElement();
+ u16 final_sum=0;
+ /* Traverse the list of headers backwards until we find an IP header */
+ while(hdr!=NULL){
+ if (hdr->protocol_id()==HEADER_TYPE_IPv6){
+ IPv6Header *v6hdr=(IPv6Header *)hdr;
+ struct in6_addr i6src, i6dst;
+ memcpy(i6src.s6_addr, v6hdr->getSourceAddress(), 16);
+ memcpy(i6dst.s6_addr, v6hdr->getDestinationAddress(), 16);
+ u8 *buff=(u8 *)safe_malloc(this->getLen());
+ this->dumpToBinaryBuffer(buff, this->getLen());
+ final_sum=ipv6_pseudoheader_cksum(&i6src, &i6dst, this->protocol_id(), this->getLen(), buff);
+ free(buff);
+ return final_sum;
+ }else if(hdr->protocol_id()==HEADER_TYPE_IPv4){
+ IPv4Header *v4hdr=(IPv4Header *)hdr;
+ struct in_addr i4src, i4dst;
+ memcpy(&(i4src.s_addr), v4hdr->getSourceAddress(), 4);
+ memcpy(&(i4dst.s_addr), v4hdr->getDestinationAddress(), 4);
+ u8 *buff=(u8 *)safe_malloc(this->getLen());
+ this->dumpToBinaryBuffer(buff, this->getLen());
+ final_sum=ipv4_pseudoheader_cksum(&i4src, &i4dst, this->protocol_id(), this->getLen(), buff);
+ free(buff);
+ return final_sum;
+ }else{
+ hdr=hdr->getPrevElement();
+ }
+ }
+ return 0;
+} /* End of setSum() */
diff --git a/libnetutil/TransportLayerElement.h b/libnetutil/TransportLayerElement.h
new file mode 100644
index 0000000..2496af1
--- /dev/null
+++ b/libnetutil/TransportLayerElement.h
@@ -0,0 +1,91 @@
+/***************************************************************************
+ * TransportLayerElement.cc -- Class TransportLayerElement is a generic *
+ * class that represents a transport layer protocol header. Classes like *
+ * TCPHeader or UDPHeader inherit from it. *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#ifndef TRANSPORTLAYERELEMENT_H
+#define TRANSPORTLAYERELEMENT_H 1
+
+#include "PacketElement.h"
+
+/// class TransportLayerElement -
+class TransportLayerElement : public PacketElement {
+
+ public:
+
+ /* Returns source port. */
+ virtual u16 getSourcePort() const = 0;
+
+ /* Sets source port. */
+ virtual int setSourcePort(u16 val) = 0;
+
+ /* Returns destination port. */
+ virtual u16 getDestinationPort() const = 0;
+
+ /* Sets destination port. */
+ virtual int setDestinationPort(u16 val) = 0;
+
+ /* Sets checksum. */
+ virtual int setSum(u16 val) = 0;
+
+ protected:
+ u16 compute_checksum();
+};
+
+#endif
diff --git a/libnetutil/UDPHeader.cc b/libnetutil/UDPHeader.cc
new file mode 100644
index 0000000..3c86d68
--- /dev/null
+++ b/libnetutil/UDPHeader.cc
@@ -0,0 +1,298 @@
+/***************************************************************************
+ * UDPHeader.cc -- The UDPHeader Class represents a UDP packet. It *
+ * contains methods to set the different header fields. These methods *
+ * tipically perform the necessary error checks and byte order *
+ * conversions. *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#include "UDPHeader.h"
+
+/******************************************************************************/
+/* CONTRUCTORS, DESTRUCTORS AND INITIALIZATION METHODS */
+/******************************************************************************/
+UDPHeader::UDPHeader(){
+ this->reset();
+} /* End of UDPHeader constructor */
+
+
+UDPHeader::~UDPHeader(){
+
+} /* End of UDPHeader destructor */
+
+
+/** Sets every attribute to its default value */
+void UDPHeader::reset(){
+ this->length=UDP_HEADER_LEN;
+ this->setSourcePort(UDP_DEFAULT_SPORT);
+ this->setDestinationPort(UDP_DEFAULT_DPORT);
+ this->setTotalLength(UDP_HEADER_LEN);
+ this->setSum(0);
+} /* End of reset() */
+
+
+/******************************************************************************/
+/* PacketElement:: OVERWRITTEN METHODS */
+/******************************************************************************/
+
+/** @warning This method is essential for the superclass getBinaryBuffer()
+ * method to work. Do NOT change a thing unless you know what you're doing */
+u8 * UDPHeader::getBufferPointer(){
+ return (u8*)(&h);
+} /* End of getBufferPointer() */
+
+
+/** Stores supplied packet in the internal buffer so the information
+ * can be accessed using the standard get & set methods.
+ * @warning The UDPHeader class is able to hold a maximum of 8 bytes. If the
+ * supplied buffer is longer than that, only the first 8 bytes will be stored
+ * in the internal buffer.
+ * @warning Supplied len MUST be at least 8 bytes (UDP header length).
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error */
+int UDPHeader::storeRecvData(const u8 *buf, size_t len){
+ if(buf==NULL || len<UDP_HEADER_LEN){
+ return OP_FAILURE;
+ }else{
+ this->reset(); /* Re-init the object, just in case the caller had used it already */
+ this->length=UDP_HEADER_LEN;
+ memcpy(&(this->h), buf, UDP_HEADER_LEN);
+ }
+ return OP_SUCCESS;
+} /* End of storeRecvData() */
+
+
+/* Returns a protocol identifier. This is used by packet parsing funtions
+ * that return linked lists of PacketElement objects, to determine the protocol
+ * the object represents. */
+int UDPHeader::protocol_id() const {
+ return HEADER_TYPE_UDP;
+} /* End of protocol_id() */
+
+
+/** Determines if the data stored in the object after an storeRecvData() call
+ * is valid and safe to use. This mainly checks the length of the data but may
+ * also test the value of certain protocol fields to ensure their correctness.
+ * @return the length, in bytes, of the header, if its found to be valid or
+ * OP_FAILURE (-1) otherwise. */
+int UDPHeader::validate(){
+ if( this->length!=UDP_HEADER_LEN)
+ return OP_FAILURE;
+ else
+ return UDP_HEADER_LEN;
+} /* End of validate() */
+
+
+/** Prints the contents of the header and calls print() on the next protocol
+ * header in the chain (if there is any).
+ * @return OP_SUCCESS on success and OP_FAILURE in case of error. */
+int UDPHeader::print(FILE *output, int detail) const {
+ fprintf(output, "UDP[");
+ fprintf(output, "%d", this->getSourcePort());
+ fprintf(output, " >");
+ fprintf(output, " %d", this->getDestinationPort());
+ if(detail>=PRINT_DETAIL_HIGH)
+ fprintf(output, " len=%d", (int)this->getTotalLength() );
+ if(detail>=PRINT_DETAIL_MED)
+ fprintf(output, " csum=0x%04X", ntohs( this->getSum() ));
+ fprintf(output, "]");
+ if(this->next!=NULL){
+ print_separator(output, detail);
+ next->print(output, detail);
+ }
+ return OP_SUCCESS;
+} /* End of print() */
+
+
+/******************************************************************************/
+/* PROTOCOL-SPECIFIC METHODS */
+/******************************************************************************/
+
+/** Sets source port.
+ * @warning Port must be supplied in host byte order. This method performs
+ * byte order conversion using htons() */
+int UDPHeader::setSourcePort(u16 p){
+ h.uh_sport = htons(p);
+ return OP_SUCCESS;
+} /* End of setSrcPort() */
+
+
+/** Returns source port in HOST byte order */
+u16 UDPHeader::getSourcePort() const {
+ return ntohs(h.uh_sport);
+} /* End of getSrcPort() */
+
+
+/** Sets destination port.
+ * @warning Port must be supplied in host byte order. This method performs
+ * byte order conversion using htons() */
+int UDPHeader::setDestinationPort(u16 p){
+ h.uh_dport = htons(p);
+ return OP_SUCCESS;
+} /* End of setDstPort() */
+
+
+/** Returns destination port in HOST byte order */
+u16 UDPHeader::getDestinationPort() const {
+ return ntohs(h.uh_dport);
+} /* End of getDstPort() */
+
+
+int UDPHeader::setSum(struct in_addr src, struct in_addr dst){
+ int bufflen;
+ u8 aux[ 65535-8 ];
+ /* FROM: RFC 5405 Unicast UDP Usage Guidelines, November 2008
+ * "A UDP datagram is carried in a single IP packet and is hence limited to
+ * a maximum payload of 65,507 bytes for IPv4 and 65,527 bytes for IPv6"
+ *
+ * So, UDP is supposed to be able to carry 65535-8 bytes but in fact it can
+ * only carry 65,507 or 65,527. However, we are not taking that into account
+ * here because UDP is supposed to be independent of IPv4, IPv6 or
+ * whatever other network layer protocol is used to carry the UDP datagrams.*/
+ h.uh_sum = 0;
+
+ /* Copy packet contents to a buffer */
+ bufflen=dumpToBinaryBuffer(aux, 65536-8 );
+
+ /* Compute checksum */
+ h.uh_sum = ipv4_pseudoheader_cksum(&src, &dst, IPPROTO_UDP,bufflen, (char *) aux);
+
+ return OP_SUCCESS;
+} /* End of setSum() */
+
+
+/** @warning Sum is set to supplied value with NO byte ordering conversion
+ * performed. */
+int UDPHeader::setSum(u16 s){
+ h.uh_sum = s;
+ return OP_SUCCESS;
+} /* End of setSum() */
+
+
+int UDPHeader::setSum(){
+ this->h.uh_sum=0;
+ this->h.uh_sum = this->compute_checksum();
+ return OP_SUCCESS;
+} /* End of setSum() */
+
+
+/** Set the UDP checksum field to a random value, which may accidentally
+ * match the correct checksum */
+int UDPHeader::setSumRandom(){
+ h.uh_sum=(1 + (get_random_u16()%(65535-1))); /* Discard value zero */
+ return OP_SUCCESS;
+} /* End of setSumRandom() */
+
+
+/** Set the UDP checksum field to a random value. It takes the source and
+ * destination address to make sure the random generated sum does not
+ * accidentally match the correct checksum. This function only handles
+ * IPv4 address. */
+int UDPHeader::setSumRandom(struct in_addr source, struct in_addr destination){
+ u16 correct_csum=0;
+ /* Compute the correct checksum */
+ this->setSum(source, destination);
+ correct_csum=this->getSum();
+ /* Generate numbers until one does not match the correct sum */
+ while( (h.uh_sum=(1 + (get_random_u16()%(65535-1))))==correct_csum);
+ return OP_SUCCESS;
+} /* End of setSumRandom() */
+
+
+u16 UDPHeader::getSum() const {
+ return h.uh_sum;
+} /* End of getSum() */
+
+
+int UDPHeader::setTotalLength(){
+ int mylen = 8;
+ int otherslen=0;
+
+ if (next!=NULL)
+ otherslen=next->getLen();
+
+ /* FROM: RFC 5405 Unicast UDP Usage Guidelines, November 2008
+ * "A UDP datagram is carried in a single IP packet and is hence limited to
+ * a maximum payload of 65,507 bytes for IPv4 and 65,527 bytes for IPv6"
+ *
+ * So, UDP is supposed to be able to carry 65535-8 bytes but in fact it can
+ * only carry 65,507 or 65,527. However, we are not taking that into account
+ * here because UDP is supposed to be independent of IPv4, IPv6 or
+ * whatever other network layer protocol is used to carry the UDP datagrams.*/
+ if (otherslen < 0 || otherslen > 65535 || (mylen+otherslen) > 65535){
+ printf("UDPHeader::setTotalLength(): Invalid length.\n");
+ return OP_FAILURE;
+ }
+
+ h.uh_ulen=htons( mylen+otherslen );
+
+ return OP_SUCCESS;
+} /* End of setTotalLength() */
+
+
+/** @warning Supplied value MUST be in HOST byte order */
+int UDPHeader::setTotalLength(u16 l){
+ this->h.uh_ulen=htons(l);
+ return OP_SUCCESS;
+} /* End of setTotalLength() */
+
+
+/** @warning Returned value is in HOST byte order */
+u16 UDPHeader::getTotalLength() const {
+ return ntohs(this->h.uh_ulen);
+} /* End of getTotalLength() */
+
+
diff --git a/libnetutil/UDPHeader.h b/libnetutil/UDPHeader.h
new file mode 100644
index 0000000..970ef84
--- /dev/null
+++ b/libnetutil/UDPHeader.h
@@ -0,0 +1,127 @@
+/***************************************************************************
+ * UDPHeader.h -- The UDPHeader Class represents a UDP packet. It contains *
+ * methods to set the different header fields. These methods tipically *
+ * perform the necessary error checks and byte order conversions. *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+/* This code was originally part of the Nping tool. */
+
+#ifndef UDPHEADER_H
+#define UDPHEADER_H 1
+
+#include "TransportLayerElement.h"
+
+#define UDP_HEADER_LEN 8
+
+/* Default header values */
+#define UDP_DEFAULT_SPORT 53
+#define UDP_DEFAULT_DPORT 53
+
+class UDPHeader : public TransportLayerElement {
+
+ private:
+ /*
+ 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
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Source Port | Destination Port |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Length | Checksum |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ struct nping_udp_hdr{
+ u16 uh_sport;
+ u16 uh_dport;
+ u16 uh_ulen;
+ u16 uh_sum;
+ }__attribute__((__packed__));
+
+ typedef struct nping_udp_hdr nping_udp_hdr_t;
+
+ nping_udp_hdr_t h;
+
+ public:
+
+ UDPHeader();
+ ~UDPHeader();
+ void reset();
+ u8 *getBufferPointer();
+ int storeRecvData(const u8 *buf, size_t len);
+ int protocol_id() const;
+ int validate();
+ int print(FILE *output, int detail) const;
+
+ int setSourcePort(u16 p);
+ u16 getSourcePort() const;
+
+ int setDestinationPort(u16 p);
+ u16 getDestinationPort() const;
+
+ int setTotalLength();
+ int setTotalLength(u16 l);
+ u16 getTotalLength() const;
+
+ int setSum(struct in_addr source, struct in_addr destination);
+ int setSum(u16 s);
+ int setSum();
+ int setSumRandom();
+ int setSumRandom(struct in_addr source, struct in_addr destination);
+ u16 getSum() const;
+
+}; /* End of class UDPHeader */
+
+
+#endif
diff --git a/libnetutil/libnetutil.vcxproj b/libnetutil/libnetutil.vcxproj
new file mode 100644
index 0000000..5decf6e
--- /dev/null
+++ b/libnetutil/libnetutil.vcxproj
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{99157C3F-39F6-4663-99D7-1D9C1484494E}</ProjectGuid>
+ <RootNamespace>libnetutil</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <PlatformToolset>v142</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>v142</PlatformToolset>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..;../mswin32;../nbase;..\..\nmap-mswin32-aux\Npcap\Include;../libdnet-stripped/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;BPF_MAJOR_VERSION;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ </ClCompile>
+ <Lib>
+ <OutputFile>$(OutDir)libnetutil.lib</OutputFile>
+ </Lib>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>MaxSpeed</Optimization>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <AdditionalIncludeDirectories>..;../mswin32;../nbase;..\..\nmap-mswin32-aux\Npcap\Include;../libdnet-stripped/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;BPF_MAJOR_VERSION;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="ARPHeader.cc" />
+ <ClCompile Include="DestOptsHeader.cc" />
+ <ClCompile Include="EthernetHeader.cc" />
+ <ClCompile Include="FragmentHeader.cc" />
+ <ClCompile Include="HopByHopHeader.cc" />
+ <ClCompile Include="ICMPv4Header.cc" />
+ <ClCompile Include="ICMPv6Header.cc" />
+ <ClCompile Include="ICMPv6Option.cc" />
+ <ClCompile Include="ICMPv6RRBody.cc" />
+ <ClCompile Include="IPv4Header.cc" />
+ <ClCompile Include="IPv6Header.cc" />
+ <ClCompile Include="netutil.cc" />
+ <ClCompile Include="NetworkLayerElement.cc" />
+ <ClCompile Include="PacketElement.cc" />
+ <ClCompile Include="PacketParser.cc" />
+ <ClCompile Include="RawData.cc" />
+ <ClCompile Include="RoutingHeader.cc" />
+ <ClCompile Include="TCPHeader.cc" />
+ <ClCompile Include="TransportLayerElement.cc" />
+ <ClCompile Include="UDPHeader.cc" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="ApplicationLayerElement.h" />
+ <ClInclude Include="ARPHeader.h" />
+ <ClInclude Include="DataLinkLayerElement.h" />
+ <ClInclude Include="DestOptsHeader.h" />
+ <ClInclude Include="EthernetHeader.h" />
+ <ClInclude Include="FragmentHeader.h" />
+ <ClInclude Include="HopByHopHeader.h" />
+ <ClInclude Include="ICMPHeader.h" />
+ <ClInclude Include="ICMPv4Header.h" />
+ <ClInclude Include="ICMPv6Header.h" />
+ <ClInclude Include="ICMPv6Option.h" />
+ <ClInclude Include="ICMPv6RRBody.h" />
+ <ClInclude Include="IPv4Header.h" />
+ <ClInclude Include="IPv6Header.h" />
+ <ClInclude Include="netutil.h" />
+ <ClInclude Include="NetworkLayerElement.h" />
+ <ClInclude Include="npacket.h" />
+ <ClInclude Include="PacketElement.h" />
+ <ClInclude Include="PacketParser.h" />
+ <ClInclude Include="RawData.h" />
+ <ClInclude Include="RoutingHeader.h" />
+ <ClInclude Include="TCPHeader.h" />
+ <ClInclude Include="TransportLayerElement.h" />
+ <ClInclude Include="UDPHeader.h" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/libnetutil/netutil.cc b/libnetutil/netutil.cc
new file mode 100644
index 0000000..ff7279e
--- /dev/null
+++ b/libnetutil/netutil.cc
@@ -0,0 +1,4777 @@
+/***************************************************************************
+ * netutil.cc *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+
+/* Since OS X 10.7, we must declare whether we expect RFC 2292 or RFC 3542
+ behavior from <netinet6/in6.h>. */
+#define __APPLE_USE_RFC_3542
+
+#if HAVE_CONFIG_H
+#include "../nmap_config.h"
+#endif
+
+#include "nbase.h"
+
+#ifndef WIN32
+#include <sys/uio.h>
+#include <sys/ioctl.h>
+#endif
+
+#include <assert.h>
+#include <errno.h>
+#include <sys/types.h>
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#if HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h> /* SIOCGIFCONF for Solaris */
+#endif
+
+/* Define CMSG_* symbols for Solaris 9 and earlier. See
+ http://wiki.opencsw.org/porting-faq#toc10. */
+#if defined(__sun) || defined(__sun__)
+# ifndef CMSG_ALIGN
+# ifdef __sun__
+# define CMSG_ALIGN(len) _CMSG_DATA_ALIGN (len)
+# else
+ /* aligning to sizeof (long) is assumed to be portable (fd.o#40235) */
+# define CMSG_ALIGN(len) (((len) + sizeof (long) - 1) & ~(sizeof (long) - 1))
+# endif
+# endif
+# ifndef CMSG_SPACE
+# define CMSG_SPACE(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + CMSG_ALIGN (len))
+# endif
+# ifndef CMSG_LEN
+# define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
+# endif
+#endif /* Solaris */
+
+#ifdef WIN32
+typedef unsigned __int32 u_int32_t;
+typedef unsigned __int16 u_int16_t;
+typedef unsigned __int8 u_int8_t;
+#endif
+
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_LINUX_RTNETLINK_H
+#include <linux/rtnetlink.h>
+#endif
+
+#ifndef NETINET_IN_SYSTM_H /* This guarding is needed for at least some versions of OpenBSD */
+#include <netinet/in_systm.h>
+#define NETINET_IN_SYSTM_H
+#endif
+
+#include "netutil.h"
+
+#if HAVE_NET_IF_H
+#ifndef NET_IF_H /* This guarding is needed for at least some versions of OpenBSD */
+#include <net/if.h>
+#define NET_IF_H
+#endif
+#endif
+#ifndef NETINET_IP_H /* This guarding is needed for at least some versions of OpenBSD */
+#include <netinet/ip.h>
+#define NETINET_IP_H
+#endif
+#include <net/if_arp.h>
+
+#if HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
+#define NBASE_MAX_ERR_STR_LEN 1024 /* Max length of an error message */
+
+#ifndef PCAP_NETMASK_UNKNOWN
+/* libpcap before 1.1.1 (e.g. WinPcap) doesn't handle this specially, so just use 0 netmask */
+#define PCAP_NETMASK_UNKNOWN 0
+#endif
+
+/** Print fatal error messages to stderr and then exits. A newline
+ character is printed automatically after the supplied text.
+ * @warning This function does not return because it calls exit() */
+void netutil_fatal(const char *str, ...){
+ va_list list;
+ char errstr[NBASE_MAX_ERR_STR_LEN];
+ memset(errstr,0, NBASE_MAX_ERR_STR_LEN);
+
+ va_start(list, str);
+
+ fflush(stdout);
+
+ /* Print error msg to strerr */
+ vfprintf(stderr, str, list);
+ fprintf(stderr,"\n");
+ va_end(list);
+
+ exit(EXIT_FAILURE);
+} /* End of fatal() */
+
+/** Print error messages to stderr and then return. A newline
+ character is printed automatically after the supplied text.*/
+int netutil_error(const char *str, ...){
+ va_list list;
+ char errstr[NBASE_MAX_ERR_STR_LEN];
+ memset(errstr,0, NBASE_MAX_ERR_STR_LEN);
+
+ va_start(list, str);
+
+ fflush(stdout);
+
+ /* Print error msg to strerr */
+ vfprintf(stderr, str, list);
+ fprintf(stderr,"\n");
+ va_end(list);
+
+ return 0;
+
+} /* End of error() */
+
+/* This function converts zero-terminated 'txt' string to binary 'data'.
+ It is used to parse user input for ip options. Some examples of possible input
+ strings and results:
+ '\x01*2\xA2' -> [0x01,0x01,0xA2] // with 'x' number is parsed in hex
+ '\01\01\255' -> [0x01,0x01,0xFF] // without 'x' its in decimal
+ '\x01\x00*2' -> [0x01,0x00,0x00] // '*' is copying char
+ 'R' -> Record Route with 9 slots
+ 'S 192.168.0.1 172.16.0.1' -> Strict Route with 2 slots
+ 'L 192.168.0.1 172.16.0.1' -> Loose Route with 2 slots
+ 'T' -> Record Timestamp with 9 slots
+ 'U' -> Record Timestamp and Ip Address with 4 slots
+ On success, the function returns the length of the final binary
+ options stored in "data". In case of error, OP_FAILURE is returned
+ and the "errstr" buffer is filled with an error message
+ (unless it's NULL). Note that the returned error message does NOT
+ contain a newline character at the end. */
+int parse_ip_options(const char *txt, u8 *data, int datalen, int* firsthopoff, int* lasthopoff, char *errstr, size_t errstrlen){
+ enum{
+ NONE = 0,
+ SLASH = 1,
+ MUL = 2,
+ RR = 3,
+ TIME = 4,
+ } s = NONE;
+ char *n, lc;
+ const char *c = txt;
+ u8 *d = data;
+ int i,j;
+ int base = 10;
+ u8 *dataend = &data[datalen];
+ u8 *len = NULL;
+ char buf[32];
+ memset(data, 0, datalen);
+ int sourcerouting = 0;
+ long strtolbyte = 0; // used to check strtol() return boundaries
+
+ for(;*c;c++){
+ switch(s){
+ case SLASH:
+ // parse \x00 string
+ if(*c == 'x'){// just ignore this char
+ base = 16;
+ break;
+ }
+ if(isxdigit(*c)){
+ strtolbyte = strtol(c, &n, base);
+ if((strtolbyte < 0) || (strtolbyte > 255)){
+ if(errstr) Snprintf(errstr, errstrlen, "invalid ipv4 address format");
+ return OP_FAILURE;
+ }
+ *d++ = (u8) strtolbyte;
+ c = n-1;
+ }else{
+ if(errstr) Snprintf(errstr, errstrlen, "not a digit after '\\'");
+ return OP_FAILURE;
+ }
+ s = NONE;
+ break;
+ case MUL:
+ if(d==data){
+ if(errstr) Snprintf(errstr, errstrlen, "nothing before '*' char");
+ return OP_FAILURE;
+ }
+ i = strtol(c, &n, 10);
+ if(i<2){
+ if(errstr) Snprintf(errstr, errstrlen, "bad number after '*'");
+ return OP_FAILURE;
+ }
+ c = n-1; // move current txt pointer
+ lc = *(d-1); // last char, we'll copy this
+ for(j=1; j<i; j++){
+ *d++ = lc;
+ if(d == dataend) // check for overflow
+ goto after;
+ }
+ s = NONE;
+ break;
+ case RR:
+ if(*c==' ' || *c==',')
+ break;
+ n = buf;
+ while((*c=='.' || (*c>='0' && *c<='9')) && n-buf <= ((int)sizeof(buf)-1))
+ *n++ = *c++;
+ *n = '\0'; c--;
+ if(d+4>=dataend){
+ if(errstr) Snprintf(errstr, errstrlen, "Buffer too small. Or input data too big :)");
+ return OP_FAILURE;
+ }
+ i = inet_pton(AF_INET, buf, d);
+ if(i<1){
+ if(errstr) Snprintf(errstr, errstrlen, "Not a valid ipv4 address '%s'",buf);
+ return OP_FAILURE;
+ }
+ // remember offset of first hop
+ if(sourcerouting && !*firsthopoff)
+ *firsthopoff = d - data;
+ d+=4;
+ if(*len<37)
+ *len += 4;
+ break;
+ case TIME:
+ if(errstr) Snprintf(errstr, errstrlen, "No more arguments allowed!");
+ return OP_FAILURE;
+ default:
+ switch(*c){
+ case '\\':s = SLASH;base=10;break;
+ case '*':s = MUL;break;
+ case 'R':
+ case 'S':
+ case 'L':
+ if(d != data){
+ if(errstr) Snprintf(errstr, errstrlen, "This option can't be used in that way");
+ return OP_FAILURE;
+ }
+ *d++ = '\x01';//NOP
+ switch(*c){
+ case 'R':*d++ = 7;break;
+ case 'S':*d++ = 137; sourcerouting=1; break;
+ case 'L':*d++ = 131; sourcerouting=1; break;
+ }
+ len = d;
+ *d++ = (*c=='R')? 39 : 3; // length: 3+4*9 bytes
+ *d++ = 4; //pointer
+ s = RR;
+ break;
+ case 'T':
+ case 'U':
+ if(d != data){
+ if(errstr) Snprintf(errstr, errstrlen, "This option can't be used in that way");
+ return OP_FAILURE;
+ }
+ *d++ = 68; // option type
+ len = d;
+ *d++ = (*c=='U') ? 36 : 40; // length: 3+4*9 bytes or 4+4*9 bytes
+ *d++ = 5; // pointer
+ *d++ = (*c=='U') ? 1 : 0; // flag: address and Time fields
+ s = TIME;
+ break;
+ default://*d++ = *c;
+ if(errstr) Snprintf(errstr, errstrlen, "Bad character in ip option '%c'",*c);
+ return OP_FAILURE;
+ }
+ }
+ if(d == dataend)
+ break;
+ assert(d<dataend);
+ }
+ if(sourcerouting){
+ if(*len<37){
+ *len+=4;
+ *lasthopoff = d - data;
+ *d++ = 0;*d++ = 0;*d++ = 0;*d++ = 0;
+ }else{
+ if(errstr) Snprintf(errstr, errstrlen, "When using source routing you must leave at least one slot for target's ip.");
+ return OP_FAILURE;
+ }
+ }
+ if(s == RR)
+ return(*len+1); // because we inject NOP before
+ if(s == TIME)
+ return(*len);
+after:
+ return(d - data);
+}
+
+/* Internal helper for resolve and resolve_numeric. addl_flags is ored into
+ hints.ai_flags, so you can add AI_NUMERICHOST. */
+static int resolve_internal(const char *hostname, unsigned short port,
+ struct sockaddr_storage *ss, size_t *sslen, int af, int addl_flags) {
+ struct addrinfo hints;
+ struct addrinfo *result;
+ char portbuf[16];
+ char *servname = NULL;
+ int rc;
+
+ assert(hostname);
+ assert(ss);
+ assert(sslen);
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = af;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags |= addl_flags;
+
+ /* Make the port number a string to give to getaddrinfo. */
+ if (port != 0) {
+ rc = Snprintf(portbuf, sizeof(portbuf), "%hu", port);
+ assert(rc >= 0 && (size_t) rc < sizeof(portbuf));
+ servname = portbuf;
+ }
+
+ rc = getaddrinfo(hostname, servname, &hints, &result);
+ if (rc != 0)
+ return rc;
+ if (result == NULL)
+ return EAI_NONAME;
+ assert(result->ai_addrlen > 0 && result->ai_addrlen <= (int) sizeof(struct sockaddr_storage));
+ *sslen = result->ai_addrlen;
+ memcpy(ss, result->ai_addr, *sslen);
+ freeaddrinfo(result);
+
+ return 0;
+}
+
+/* Resolves the given hostname or IP address with getaddrinfo, and stores the
+ first result (if any) in *ss and *sslen. The value of port will be set in the
+ appropriate place in *ss; set to 0 if you don't care. af may be AF_UNSPEC, in
+ which case getaddrinfo may return e.g. both IPv4 and IPv6 results; which one
+ is first depends on the system configuration. Returns 0 on success, or a
+ getaddrinfo return code (suitable for passing to gai_strerror) on failure.
+ *ss and *sslen are always defined when this function returns 0. */
+int resolve(const char *hostname, unsigned short port,
+ struct sockaddr_storage *ss, size_t *sslen, int af) {
+ return resolve_internal(hostname, port, ss, sslen, af, 0);
+}
+
+/* As resolve, but do not do DNS resolution of hostnames; the first argument
+ must be the string representation of a numeric IP address. */
+int resolve_numeric(const char *ip, unsigned short port,
+ struct sockaddr_storage *ss, size_t *sslen, int af) {
+ return resolve_internal(ip, port, ss, sslen, af, AI_NUMERICHOST);
+}
+
+/*
+ * Returns 1 if this is a reserved IP address, where "reserved" means
+ * either a private address, non-routable address, or even a non-reserved
+ * but unassigned address which has an extremely high probability of being
+ * black-holed.
+ *
+ * We try to optimize speed when ordering the tests. This optimization
+ * assumes that all byte values are equally likely in the input.
+ *
+ * Check
+ * <http://www.iana.org/assignments/ipv4-address-space/ipv4-address-space.txt>
+ * for the most recent assigments and
+ * <http://www.cymru.com/Documents/bogon-bn-nonagg.txt> for bogon
+ * netblocks.
+ */
+int ip_is_reserved(struct in_addr *ip)
+{
+ char *ipc = (char *) &(ip->s_addr);
+ unsigned char i1 = ipc[0], i2 = ipc[1], i3 = ipc[2]; /* i4 not currently used - , i4 = ipc[3]; */
+
+ /* do all the /7's and /8's with a big switch statement, hopefully the
+ * compiler will be able to optimize this a little better using a jump table
+ * or what have you
+ */
+ switch (i1)
+ {
+ case 0: /* 000/8 is IANA reserved */
+ case 10: /* the infamous 10.0.0.0/8 */
+ case 127: /* 127/8 is reserved for loopback */
+ return 1;
+ default:
+ break;
+ }
+
+ /* 172.16.0.0/12 is reserved for private nets by RFC1918 */
+ if (i1 == 172 && i2 >= 16 && i2 <= 31)
+ return 1;
+
+ /* 192.0.2.0/24 is reserved for documentation and examples (RFC5737) */
+ /* 192.88.99.0/24 is used as 6to4 Relay anycast prefix by RFC3068 */
+ /* 192.168.0.0/16 is reserved for private nets by RFC1918 */
+ if (i1 == 192) {
+ if (i2 == 0 && i3 == 2)
+ return 1;
+ if (i2 == 88 && i3 == 99)
+ return 1;
+ if (i2 == 168)
+ return 1;
+ }
+
+ /* 198.18.0.0/15 is used for benchmark tests by RFC2544 */
+ /* 198.51.100.0/24 is reserved for documentation (RFC5737) */
+ if (i1 == 198) {
+ if (i2 == 18 || i2 == 19)
+ return 1;
+ if (i2 == 51 && i3 == 100)
+ return 1;
+ }
+
+ /* 169.254.0.0/16 is reserved for DHCP clients seeking addresses - RFC3927 */
+ if (i1 == 169 && i2 == 254)
+ return 1;
+
+ /* 203.0.113.0/24 is reserved for documentation (RFC5737) */
+ if (i1 == 203 && i2 == 0 && i3 == 113)
+ return 1;
+
+ /* 224-239/8 is all multicast stuff */
+ /* 240-255/8 is IANA reserved */
+ if (i1 >= 224)
+ return 1;
+
+ return 0;
+}
+
+/* A trivial functon that maintains a cache of IP to MAC Address
+ entries. If the command is MACCACHE_GET, this func looks for the
+ IPv4 address in ss and fills in the 'mac' parameter and returns
+ true if it is found. Otherwise (not found), the function returns
+ false. If the command is MACCACHE_SET, the function adds an entry
+ with the given ip (ss) and mac address. An existing entry for the
+ IP ss will be overwritten with the new MAC address. true is always
+ returned for the set command. */
+#define MACCACHE_GET 1
+#define MACCACHE_SET 2
+static int do_mac_cache(int command, const struct sockaddr_storage *ss, u8 *mac) {
+ struct MacCache {
+ struct sockaddr_storage ip;
+ u8 mac[6];
+ };
+ static struct MacCache *Cache = NULL;
+ static int MacCapacity = 0;
+ static int MacCacheSz = 0;
+ int i;
+
+ if (command == MACCACHE_GET) {
+ for (i = 0; i < MacCacheSz; i++) {
+ if (sockaddr_storage_cmp(&Cache[i].ip, ss) == 0) {
+ memcpy(mac, Cache[i].mac, 6);
+ return 1;
+ }
+ }
+ return 0;
+ }
+ assert(command == MACCACHE_SET);
+ if (MacCacheSz == MacCapacity) {
+ if (MacCapacity == 0)
+ MacCapacity = 32;
+ else
+ MacCapacity <<= 2;
+ Cache = (struct MacCache *) safe_realloc(Cache, MacCapacity * sizeof(struct MacCache));
+ }
+
+ /* Ensure that it isn't already there ... */
+ for (i = 0; i < MacCacheSz; i++) {
+ if (sockaddr_storage_cmp(&Cache[i].ip, ss) == 0) {
+ memcpy(Cache[i].mac, mac, 6);
+ return 1;
+ }
+ }
+
+ /* Add it to the end of the list */
+ memcpy(&Cache[i].ip, ss, sizeof(struct sockaddr_storage));
+ memcpy(Cache[i].mac, mac, 6);
+ MacCacheSz++;
+ return 1;
+}
+
+/* A couple of trivial functions that maintain a cache of IP to MAC
+ * Address entries. Function mac_cache_get() looks for the IPv4 address
+ * in ss and fills in the 'mac' parameter and returns true if it is
+ * found. Otherwise (not found), the function returns false.
+ * Function mac_cache_set() adds an entry with the given ip (ss) and
+ * mac address. An existing entry for the IP ss will be overwritten
+ * with the new MAC address. mac_cache_set() always returns true.
+ * WARNING: The caller must ensure that the supplied "ss" is of family
+ * AF_INET. Otherwise the function will return 0 and there would be
+ * no way for the caller to tell tell the difference between an error
+ * or a cache miss.*/
+int mac_cache_get(const struct sockaddr_storage *ss, u8 *mac){
+ return do_mac_cache(MACCACHE_GET, ss, mac);
+}
+int mac_cache_set(const struct sockaddr_storage *ss, u8 *mac){
+ return do_mac_cache(MACCACHE_SET, ss, mac);
+}
+
+/* Standard BSD internet checksum routine. Uses libdnet helper functions. */
+unsigned short in_cksum(u16 *ptr,int nbytes) {
+ int sum;
+
+ sum = ip_cksum_add(ptr, nbytes, 0);
+
+ return ip_cksum_carry(sum);
+
+ return 0;
+}
+
+
+/* Return true iff this Next Header type is an extension header we must skip to
+ get to the upper-layer header. Types for which neither this function nor
+ ipv6_is_upperlayer return true are unknown and could be either. */
+static int ipv6_is_extension_header(u8 type)
+{
+ switch (type) {
+ case IP_PROTO_HOPOPTS:
+ case IP_PROTO_DSTOPTS:
+ case IP_PROTO_ROUTING:
+ case IP_PROTO_FRAGMENT:
+ /*
+ case IP_PROTO_ESP:
+ case IP_PROTO_AH:
+ */
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/* Return true iff this Next Header type is a known upper-layer protocol, one
+ that isn't followed by any more headers. Types for which neither this
+ function nor ipv6_is_upperlayer return true are unknown and could be
+ either. */
+static int ipv6_is_upperlayer(u8 type)
+{
+ switch (type) {
+ case IP_PROTO_NONE:
+ case IP_PROTO_TCP:
+ case IP_PROTO_UDP:
+ case IP_PROTO_ICMP:
+ case IP_PROTO_ICMPV6:
+ case IP_PROTO_SCTP:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/* upperlayer_only controls whether we require a known upper-layer protocol at
+ the end of the chain, or return the last readable header even if it is not an
+ upper-layer protocol (may even be another extension header). */
+static const void *ipv6_get_data_primitive(const struct ip6_hdr *ip6,
+ unsigned int *len, u8 *nxt, bool upperlayer_only)
+{
+ const unsigned char *p, *end;
+
+ if (*len < sizeof(*ip6))
+ return NULL;
+
+ p = (unsigned char *) ip6;
+ end = p + *len;
+
+ *nxt = ip6->ip6_nxt;
+ p += sizeof(*ip6);
+ while (p < end && ipv6_is_extension_header(*nxt)) {
+ if (p + 2 > end)
+ return NULL;
+ *nxt = *p;
+ p += (*(p + 1) + 1) * 8;
+ }
+
+ *len = end - p;
+ if (upperlayer_only && !ipv6_is_upperlayer(*nxt))
+ return NULL;
+
+ return (char *) p;
+}
+
+static const void *ip_get_data_primitive(const void *packet, unsigned int *len,
+ struct abstract_ip_hdr *hdr, bool upperlayer_only) {
+ const struct ip *ip;
+
+ ip = (struct ip *) packet;
+ if (*len >= 20 && ip->ip_v == 4) {
+ struct sockaddr_in *sin;
+
+ hdr->version = 4;
+
+ sin = (struct sockaddr_in *) &hdr->src;
+ memset(&hdr->src, 0, sizeof(hdr->src));
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = ip->ip_src.s_addr;
+
+ sin = (struct sockaddr_in *) &hdr->dst;
+ memset(&hdr->dst, 0, sizeof(hdr->dst));
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = ip->ip_dst.s_addr;
+
+ hdr->proto = ip->ip_p;
+ hdr->ttl = ip->ip_ttl;
+ hdr->ipid = ntohs(ip->ip_id);
+ return ipv4_get_data(ip, len);
+ } else if (*len >= 40 && ip->ip_v == 6) {
+ const struct ip6_hdr *ip6 = (struct ip6_hdr *) ip;
+ struct sockaddr_in6 *sin6;
+
+ hdr->version = 6;
+
+ sin6 = (struct sockaddr_in6 *) &hdr->src;
+ memset(&hdr->src, 0, sizeof(hdr->src));
+ sin6->sin6_family = AF_INET6;
+ memcpy(&sin6->sin6_addr, &ip6->ip6_src, IP6_ADDR_LEN);
+
+ sin6 = (struct sockaddr_in6 *) &hdr->dst;
+ memset(&hdr->dst, 0, sizeof(hdr->dst));
+ sin6->sin6_family = AF_INET6;
+ memcpy(&sin6->sin6_addr, &ip6->ip6_dst, IP6_ADDR_LEN);
+
+ hdr->ttl = ip6->ip6_hlim;
+ hdr->ipid = ntohl(ip6->ip6_flow & IP6_FLOWLABEL_MASK);
+ return ipv6_get_data_primitive(ip6, len, &hdr->proto, upperlayer_only);
+ }
+
+ return NULL;
+}
+
+/* Find the beginning of the data payload in the IP packet beginning at packet.
+ Returns the beginning of the payload, updates *len to be the length of the
+ payload, and fills in hdr if successful. Otherwise returns NULL and *hdr is
+ undefined. */
+const void *ip_get_data(const void *packet, unsigned int *len,
+ struct abstract_ip_hdr *hdr) {
+ return ip_get_data_primitive(packet, len, hdr, true);
+}
+
+/* As ip_get_data, except that it doesn't insist that the payload be a known
+ upper-layer protocol. This can matter in IPv6 where the last element of a nh
+ chain may be a protocol we don't know about. */
+const void *ip_get_data_any(const void *packet, unsigned int *len,
+ struct abstract_ip_hdr *hdr) {
+ return ip_get_data_primitive(packet, len, hdr, false);
+}
+
+/* Get the upper-layer protocol from an IPv4 packet. */
+const void *ipv4_get_data(const struct ip *ip, unsigned int *len)
+{
+ unsigned int header_len;
+
+ if (*len < 20)
+ return NULL;
+ header_len = ip->ip_hl * 4;
+ if (header_len < sizeof(*ip))
+ return NULL;
+ if (header_len > *len)
+ return NULL;
+ *len -= header_len;
+
+ return (char *) ip + header_len;
+}
+
+/* Get the upper-layer protocol from an IPv6 packet. This skips over known
+ extension headers. The length of the upper-layer payload is stored in *len.
+ The protocol is stored in *nxt. Returns NULL in case of error. */
+const void *ipv6_get_data(const struct ip6_hdr *ip6, unsigned int *len, u8 *nxt)
+{
+ return ipv6_get_data_primitive(ip6, len, nxt, true);
+}
+
+/* Get the protocol payload from an IPv6 packet. This skips over known extension
+ headers. It differs from ipv6_get_data in that it will return a result even
+ if the final header is not a known upper-layer protocol. */
+const void *ipv6_get_data_any(const struct ip6_hdr *ip6, unsigned int *len, u8 *nxt)
+{
+ return ipv6_get_data_primitive(ip6, len, nxt, false);
+}
+
+const void *icmp_get_data(const struct icmp_hdr *icmp, unsigned int *len)
+{
+ unsigned int header_len;
+
+ if (icmp->icmp_type == ICMP_TIMEXCEED || icmp->icmp_type == ICMP_UNREACH)
+ header_len = 8;
+ else
+ netutil_fatal("%s passed ICMP packet with unhandled type %d", __func__, icmp->icmp_type);
+ if (header_len > *len)
+ return NULL;
+ *len -= header_len;
+
+ return (char *) icmp + header_len;
+}
+
+const void *icmpv6_get_data(const struct icmpv6_hdr *icmpv6, unsigned int *len)
+{
+ unsigned int header_len;
+
+ if (icmpv6->icmpv6_type == ICMPV6_TIMEXCEED || icmpv6->icmpv6_type == ICMPV6_UNREACH)
+ header_len = 8;
+ else
+ netutil_fatal("%s passed ICMPv6 packet with unhandled type %d", __func__, icmpv6->icmpv6_type);
+ if (header_len > *len)
+ return NULL;
+ *len -= header_len;
+
+ return (char *) icmpv6 + header_len;
+}
+
+
+/* Calculate the Internet checksum of some given data concatentated with the
+ IPv4 pseudo-header. See RFC 1071 and TCP/IP Illustrated sections 3.2, 11.3,
+ and 17.3. */
+unsigned short ipv4_pseudoheader_cksum(const struct in_addr *src,
+ const struct in_addr *dst, u8 proto, u16 len, const void *hstart) {
+ struct pseudo {
+ struct in_addr src;
+ struct in_addr dst;
+ u8 zero;
+ u8 proto;
+ u16 length;
+ } hdr;
+ int sum;
+
+ hdr.src = *src;
+ hdr.dst = *dst;
+ hdr.zero = 0;
+ hdr.proto = proto;
+ hdr.length = htons(len);
+
+ /* Get the ones'-complement sum of the pseudo-header. */
+ sum = ip_cksum_add(&hdr, sizeof(hdr), 0);
+ /* Add it to the sum of the packet. */
+ sum = ip_cksum_add(hstart, len, sum);
+
+ /* Fold in the carry, take the complement, and return. */
+ sum = ip_cksum_carry(sum);
+ /* RFC 768: "If the computed checksum is zero, it is transmitted as all
+ * ones (the equivalent in one's complement arithmetic). An all zero
+ * transmitted checksum value means that the transmitter generated no
+ * checksum" */
+ if (proto == IP_PROTO_UDP && sum == 0)
+ sum = 0xFFFF;
+
+ return sum;
+}
+
+/* Calculate the Internet checksum of some given data concatenated with the
+ IPv6 pseudo-header. See RFC 2460 section 8.1. */
+u16 ipv6_pseudoheader_cksum(const struct in6_addr *src,
+ const struct in6_addr *dst, u8 nxt, u32 len, const void *hstart) {
+ struct {
+ struct in6_addr src;
+ struct in6_addr dst;
+ u32 length;
+ u8 z0, z1, z2;
+ u8 nxt;
+ } hdr;
+ int sum;
+
+ hdr.src = *src;
+ hdr.dst = *dst;
+ hdr.z0 = hdr.z1 = hdr.z2 = 0;
+ hdr.length = htonl(len);
+ hdr.nxt = nxt;
+
+ sum = ip_cksum_add(&hdr, sizeof(hdr), 0);
+ sum = ip_cksum_add(hstart, len, sum);
+ sum = ip_cksum_carry(sum);
+ /* RFC 2460: "Unlike IPv4, when UDP packets are originated by an IPv6 node,
+ the UDP checksum is not optional. That is, whenever originating a UDP
+ packet, an IPv6 node must compute a UDP checksum over the packet and the
+ pseudo-header, and, if that computation yields a result of zero, it must be
+ changed to hex FFFF for placement in the UDP header." */
+ if (nxt == IP_PROTO_UDP && sum == 0)
+ sum = 0xFFFF;
+
+ return sum;
+}
+
+void sethdrinclude(int sd) {
+#ifdef IP_HDRINCL
+ int one = 1;
+ setsockopt(sd, IPPROTO_IP, IP_HDRINCL, (const char *) &one, sizeof(one));
+#endif
+}
+
+void set_ipoptions(int sd, void *opts, size_t optslen) {
+#ifdef IP_OPTIONS
+ if (sd == -1)
+ return;
+
+ setsockopt(sd, IPPROTO_IP, IP_OPTIONS, (const char *) opts, optslen);
+#endif
+}
+
+void set_ttl(int sd, int ttl) {
+#ifdef IP_TTL
+ if (sd == -1)
+ return;
+
+ setsockopt(sd, IPPROTO_IP, IP_TTL, (const char *) &ttl, sizeof ttl);
+#endif
+}
+
+/* Other than WIN32, what these systems have in common is that they use BPF for
+ packet capture. (Solaris 10 and earlier used DLPI and had valid selectable
+ fds.) */
+#if defined(WIN32) || defined(MACOSX) || (defined(FREEBSD) && (__FreeBSD_version < 500000)) || defined(SOLARIS_BPF_PCAP_CAPTURE) || defined(OPENBSD)
+/* Returns whether the system supports pcap_get_selectable_fd() properly */
+int pcap_selectable_fd_valid() {
+ return 0;
+}
+
+/* Call this instead of pcap_get_selectable_fd directly (or your code
+ won't compile on Windows). On systems which don't seem to support
+ the pcap_get_selectable_fd() function properly, returns -1,
+ otherwise simply calls pcap_selectable_fd and returns the
+ results. If you just want to test whether the function is supported,
+ use pcap_selectable_fd_valid() instead. */
+int my_pcap_get_selectable_fd(pcap_t *p) {
+ return -1;
+}
+#else
+int pcap_selectable_fd_valid() {
+ return 1;
+}
+int my_pcap_get_selectable_fd(pcap_t *p) {
+ return pcap_get_selectable_fd(p);
+}
+#endif
+
+/* Are we guaranteed to be able to read exactly one frame for each time the pcap
+ fd is selectable? If not, it's possible for the fd to become selectable, then
+ for pcap_dispatch to buffer two or more frames, and return only the first one
+ Because select doesn't know about pcap's buffer, the fd does not become
+ selectable again, even though another pcap_next_ex would succeed. On these
+ platforms, we must do a non-blocking read from the fd before doing a select
+ on the fd.
+
+ It is guaranteed that if pcap_selectable_fd_valid() is false, then so is the
+ return value of this function. */
+int pcap_selectable_fd_one_to_one() {
+#ifdef SOLARIS
+ return 0;
+#endif
+ return pcap_selectable_fd_valid();
+}
+
+
+/* returns -1 if we can't use select() on the pcap device, 0 for timeout, and
+ * >0 for success. If select() fails we bail out because it couldn't work with
+ * the file descriptor we got from my_pcap_get_selectable_fd()
+ */
+int pcap_select(pcap_t *p, struct timeval *timeout) {
+ int ret;
+#ifdef WIN32
+ DWORD msec_timeout = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
+ HANDLE event = pcap_getevent(p);
+ DWORD result = WaitForSingleObject(event, msec_timeout);
+
+ switch(result) {
+ case WAIT_OBJECT_0:
+ ret = 1;
+ break;
+ case WAIT_TIMEOUT:
+ ret = 0;
+ break;
+ case WAIT_FAILED:
+ ret = -1;
+ netutil_error("%s: WaitForSingleObject failed: %d", __func__, GetLastError());
+ break;
+ default:
+ ret = -1;
+ netutil_fatal("%s: WaitForSingleObject returned unknown result: %x", __func__, result);
+ break;
+ }
+
+#else
+ int fd;
+ fd_set rfds;
+
+ if ((fd = my_pcap_get_selectable_fd(p)) == -1)
+ return -1;
+
+ FD_ZERO(&rfds);
+ checked_fd_set(fd, &rfds);
+
+ do {
+ errno = 0;
+ ret = select(fd + 1, &rfds, NULL, NULL, timeout);
+ if (ret == -1) {
+ if (errno == EINTR)
+ netutil_error("%s: %s", __func__, strerror(errno));
+ else
+ netutil_fatal("Your system does not support select()ing on pcap devices (%s). PLEASE REPORT THIS ALONG WITH DETAILED SYSTEM INFORMATION TO THE nmap-dev MAILING LIST!", strerror(errno));
+ }
+ } while (ret == -1);
+
+#endif
+ return ret;
+}
+
+int pcap_select(pcap_t *p, long usecs) {
+ struct timeval tv;
+
+ tv.tv_sec = usecs / 1000000;
+ tv.tv_usec = usecs % 1000000;
+
+ return pcap_select(p, &tv);
+}
+
+
+/* These two are for eth_open_cached() and eth_close_cached() */
+static char etht_cache_device_name[64];
+static eth_t *etht_cache_device = NULL;
+
+/* A simple function that caches the eth_t from dnet for one device,
+ to avoid opening, closing, and re-opening it thousands of tims. If
+ you give a different device, this function will close the first
+ one. Thus this should never be used by programs that need to deal
+ with multiple devices at once. In addition, you MUST NEVER
+ eth_close() A DEVICE OBTAINED FROM THIS FUNCTION. Instead, you can
+ call eth_close_cached() to close whichever device (if any) is
+ cached. Returns NULL if it fails to open the device. */
+eth_t *eth_open_cached(const char *device) {
+ if (!device)
+ netutil_fatal("%s() called with NULL device name!", __func__);
+ if (!*device)
+ netutil_fatal("%s() called with empty device name!", __func__);
+
+ if (strcmp(device, etht_cache_device_name) == 0) {
+ /* Yay, we have it cached. */
+ return etht_cache_device;
+ }
+
+ if (*etht_cache_device_name) {
+ eth_close(etht_cache_device);
+ etht_cache_device_name[0] = '\0';
+ etht_cache_device = NULL;
+ }
+
+ etht_cache_device = eth_open(device);
+ if (etht_cache_device)
+ Strncpy(etht_cache_device_name, device,
+ sizeof(etht_cache_device_name));
+
+ return etht_cache_device;
+}
+
+/* See the description for eth_open_cached */
+void eth_close_cached() {
+ if (etht_cache_device) {
+ eth_close(etht_cache_device);
+ etht_cache_device = NULL;
+ etht_cache_device_name[0] = '\0';
+ }
+ return;
+}
+
+/* Takes a protocol number like IPPROTO_TCP, IPPROTO_UDP, IPPROTO_IP,
+ * etc, and returns an ASCII representation (or the string "unknown" if
+ * it doesn't recognize the number). If uppercase is non zero, the
+ * returned value will be in uppercase letters, otherwise it'll be
+ * in lowercase */
+const char *proto2ascii_case(u8 proto, int uppercase) {
+ switch (proto) {
+
+ case IPPROTO_TCP:
+ return uppercase ? "TCP" : "tcp";
+ break;
+ case IPPROTO_UDP:
+ return uppercase ? "UDP" : "udp";
+ break;
+ case IPPROTO_SCTP:
+ return uppercase ? "SCTP" : "sctp";
+ break;
+ case IPPROTO_IP:
+ return uppercase ? "IP" : "ip";
+ break;
+#ifdef IPPROTO_ICMP
+ case IPPROTO_ICMP:
+ return uppercase ? "ICMP" : "icmp";
+ break;
+#endif
+#ifdef IPPROTO_IPV6
+ case IPPROTO_IPV6:
+ return uppercase ? "IPv6" : "ipv6";
+ break;
+#endif
+#ifdef IPPROTO_ICMPV6
+ case IPPROTO_ICMPV6:
+ return uppercase ? "ICMPv6" : "icmpv6";
+ break;
+#endif
+#ifdef IPPROTO_GRE
+ case IPPROTO_GRE: // Generic Routing Encapsulation
+ return uppercase ? "GRE" : "gre";
+ break;
+#endif
+#ifdef IPPROTO_ESP
+ case IPPROTO_ESP: // Encapsulating Security Payload (IPSec)
+ return uppercase ? "IPSec/ESP" : "ipsec/esp";
+ break;
+#endif
+#ifdef IPPROTO_AH
+ case IPPROTO_AH: // Authentication Header (IPSec)
+ return uppercase ? "IPSec/AH" : "ipsec/ah";
+ break;
+#endif
+ default:
+ return uppercase ? "UNKNOWN" : "unknown";
+ }
+
+ return NULL; // Unreached
+}
+
+const char *proto2ascii_lowercase(u8 proto) {
+ return proto2ascii_case(proto, 0);
+}
+const char *proto2ascii_uppercase(u8 proto) {
+ return proto2ascii_case(proto, 1);
+}
+
+/* Get an ASCII information about a tcp option which is pointed by
+ optp, with a length of len. The result is stored in the result
+ buffer. The result may look like "<mss 1452,sackOK,timestamp
+ 45848914 0,nop,wscale 7>" */
+void tcppacketoptinfo(u8 *optp, int len, char *result, int bufsize) {
+ assert(optp);
+ assert(result);
+ char *p, ch;
+ u8 *q;
+ int opcode;
+ u16 tmpshort;
+ u32 tmpword1, tmpword2;
+ unsigned int i=0;
+
+ p = result;
+ *p = '\0';
+ q = optp;
+ ch = '<';
+
+ while (len > 0 && bufsize > 2) {
+ Snprintf(p, bufsize, "%c", ch);
+ bufsize--;
+ p++;
+ opcode = *q++;
+ if (!opcode) { /* End of List */
+
+ Snprintf(p, bufsize, "eol");
+ bufsize -= strlen(p);
+ p += strlen(p);
+
+ len--;
+
+ } else if (opcode == 1) { /* No Op */
+ Snprintf(p, bufsize, "nop");
+ bufsize -= strlen(p);
+ p += strlen(p);
+
+ len--;
+ } else if (opcode == 2) { /* MSS */
+ if (len < 4)
+ break; /* MSS has 4 bytes */
+
+ q++;
+ memcpy(&tmpshort, q, 2);
+
+ Snprintf(p, bufsize, "mss %hu", (unsigned short) ntohs(tmpshort));
+ bufsize -= strlen(p);
+ p += strlen(p);
+
+ q += 2;
+ len -= 4;
+ } else if (opcode == 3) { /* Window Scale */
+ if (len < 3)
+ break; /* Window Scale option has 3 bytes */
+
+ q++;
+
+ Snprintf(p, bufsize, "wscale %u", *q);
+ bufsize -= strlen(p);
+ p += strlen(p);
+
+ q++;
+ len -= 3;
+ } else if (opcode == 4) { /* SACK permitted */
+ if (len < 2)
+ break; /* SACK permitted option has 2 bytes */
+
+ Snprintf(p, bufsize, "sackOK");
+ bufsize -= strlen(p);
+ p += strlen(p);
+
+ q++;
+ len -= 2;
+ } else if (opcode == 5) { /* SACK */
+ unsigned sackoptlen = *q;
+ if ((unsigned) len < sackoptlen)
+ break;
+
+ /* This would break parsing, so it's best to just give up */
+ if (sackoptlen < 2)
+ break;
+
+ q++;
+
+ if ((sackoptlen - 2) == 0 || ((sackoptlen - 2) % 8 != 0)) {
+ Snprintf(p, bufsize, "malformed sack");
+ bufsize -= strlen(p);
+ p += strlen(p);
+ } else {
+ Snprintf(p, bufsize, "sack %d ", (sackoptlen - 2) / 8);
+ bufsize -= strlen(p);
+ p += strlen(p);
+ for (i = 0; i < sackoptlen - 2; i += 8) {
+ memcpy(&tmpword1, q + i, 4);
+ memcpy(&tmpword2, q + i + 4, 4);
+ Snprintf(p, bufsize, "{%u:%u}", tmpword1, tmpword2);
+ bufsize -= strlen(p);
+ p += strlen(p);
+ }
+ }
+
+ q += sackoptlen - 2;
+ len -= sackoptlen;
+ } else if (opcode == 8) { /* Timestamp */
+ if (len < 10)
+ break; /* Timestamp option has 10 bytes */
+
+ q++;
+ memcpy(&tmpword1, q, 4);
+ memcpy(&tmpword2, q + 4, 4);
+
+ Snprintf(p, bufsize, "timestamp %lu %lu", (unsigned long) ntohl(tmpword1),
+ (unsigned long) ntohl(tmpword2));
+ bufsize -= strlen(p);
+ p += strlen(p);
+
+ q += 8;
+ len -= 10;
+ }
+
+ ch = ',';
+ }
+
+ if (len > 0) {
+ *result = '\0';
+ return;
+ }
+
+ Snprintf(p, bufsize, ">");
+}
+
+
+
+/* A trivial function used with qsort to sort the routes by netmask and metric */
+static int routecmp(const void *a, const void *b) {
+ struct sys_route *r1 = (struct sys_route *) a;
+ struct sys_route *r2 = (struct sys_route *) b;
+ if (r1->dest.ss_family < r2->dest.ss_family)
+ return -1;
+ else if (r1->dest.ss_family > r2->dest.ss_family)
+ return 1;
+
+ if (r1->netmask_bits < r2->netmask_bits)
+ return 1;
+ else if (r1->netmask_bits > r2->netmask_bits)
+ return -1;
+
+ if (r1->metric < r2->metric)
+ return -1;
+ else if (r1->metric > r2->metric)
+ return 1;
+
+ /* Compare addresses of equal elements to make the sort stable, as suggested
+ by the Glibc manual. */
+ if (a < b)
+ return -1;
+ else if (a > b)
+ return 1;
+ else
+ return 0;
+}
+
+
+
+/* Convert an address to a string and back again. The first parsing step
+ eliminates magical OS-specific syntax, for example on OS X, fe80:4::X:X:X:X
+ becomes "fe80::X:X:X:X" (the "4" in this case is another way of writing the
+ zone ID, like "%en0"; i.e., in this case en0 is interface number 4). This
+ must be done before e.g. comparing addresses by netmask. */
+static int canonicalize_address(const struct sockaddr_storage *ss,
+ struct sockaddr_storage *output) {
+ char canonical_ip_string[NI_MAXHOST];
+ struct addrinfo hints;
+ struct addrinfo *ai;
+ int rc;
+
+ /* Convert address to string. */
+ rc = getnameinfo((struct sockaddr *) ss, sizeof(*ss),
+ canonical_ip_string, sizeof(canonical_ip_string), NULL, 0, NI_NUMERICHOST);
+ if (rc != 0) {
+ /* Don't care. */
+ *output = *ss;
+ return 0;
+ }
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = ss->ss_family;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags |= AI_NUMERICHOST;
+
+ rc = getaddrinfo(canonical_ip_string, NULL, &hints, &ai);
+ if (rc != 0 || ai == NULL)
+ return -1;
+ assert(ai->ai_addrlen > 0 && ai->ai_addrlen <= (int) sizeof(*output));
+ memcpy(output, ai->ai_addr, ai->ai_addrlen);
+ freeaddrinfo(ai);
+
+ return 0;
+}
+
+static int collect_dnet_interfaces(const struct intf_entry *entry, void *arg) {
+ struct dnet_collector_route_nfo *dcrn = (struct dnet_collector_route_nfo *) arg;
+ bool primary_done;
+ unsigned int num_aliases_done;
+ struct sockaddr_storage tmpss;
+ int rc;
+
+ primary_done = false;
+ num_aliases_done = 0;
+ while (!primary_done || num_aliases_done < entry->intf_alias_num) {
+ /* Make sure we have room for the new route */
+ if (dcrn->numifaces >= dcrn->capacity) {
+ dcrn->capacity <<= 2;
+ dcrn->ifaces = (struct interface_info *) safe_realloc(dcrn->ifaces,
+ dcrn->capacity * sizeof(struct interface_info));
+ }
+
+ /* The first time through the loop we add the primary interface record.
+ After that we add the aliases one at a time. */
+ if (!primary_done) {
+ if ( (addr_ntos(&entry->intf_addr, (struct sockaddr *) &tmpss) == -1)
+#ifdef AF_LINK
+ || (tmpss.ss_family == AF_LINK)
+#endif
+ ) {
+ dcrn->ifaces[dcrn->numifaces].addr.ss_family = 0;
+ } else {
+ rc = canonicalize_address(&tmpss, &dcrn->ifaces[dcrn->numifaces].addr);
+ assert(rc == 0);
+ }
+ dcrn->ifaces[dcrn->numifaces].netmask_bits = entry->intf_addr.addr_bits;
+ primary_done = true;
+ } else if (num_aliases_done < entry->intf_alias_num) {
+ if ( (addr_ntos(&entry->intf_alias_addrs[num_aliases_done], (struct sockaddr *) &tmpss) == -1)
+#ifdef AF_LINK
+ || (tmpss.ss_family == AF_LINK)
+#endif
+ ) {
+ dcrn->ifaces[dcrn->numifaces].addr.ss_family = 0;
+ } else {
+ rc = canonicalize_address(&tmpss, &dcrn->ifaces[dcrn->numifaces].addr);
+ assert(rc == 0);
+ }
+ dcrn->ifaces[dcrn->numifaces].netmask_bits = entry->intf_alias_addrs[num_aliases_done].addr_bits;
+ num_aliases_done++;
+ }
+
+ /* OK, address/netmask found. Let's get the name */
+ Strncpy(dcrn->ifaces[dcrn->numifaces].devname, entry->intf_name,
+ sizeof(dcrn->ifaces[dcrn->numifaces].devname));
+ Strncpy(dcrn->ifaces[dcrn->numifaces].devfullname, entry->intf_name,
+ sizeof(dcrn->ifaces[dcrn->numifaces].devfullname));
+
+ /* Interface type */
+ if (entry->intf_type == INTF_TYPE_ETH && (entry->intf_flags & INTF_FLAG_NOARP) == 0) {
+ dcrn->ifaces[dcrn->numifaces].device_type = devt_ethernet;
+ /* Collect the MAC address since this is ethernet */
+ memcpy(dcrn->ifaces[dcrn->numifaces].mac, &entry->intf_link_addr.addr_eth.data, 6);
+ } else if (entry->intf_type == INTF_TYPE_LOOPBACK) {
+ dcrn->ifaces[dcrn->numifaces].device_type = devt_loopback;
+ } else if (entry->intf_type == INTF_TYPE_TUN) {
+ dcrn->ifaces[dcrn->numifaces].device_type = devt_p2p;
+ } else {
+ dcrn->ifaces[dcrn->numifaces].device_type = devt_other;
+ }
+
+ dcrn->ifaces[dcrn->numifaces].ifindex = entry->intf_index;
+
+ dcrn->ifaces[dcrn->numifaces].mtu = entry->intf_mtu;
+
+ /* Is the interface up and running? */
+ dcrn->ifaces[dcrn->numifaces].device_up = (entry->intf_flags & INTF_FLAG_UP) ? true : false;
+
+ /* For the rest of the information, we must open the interface directly ... */
+ dcrn->numifaces++;
+ }
+
+ return 0;
+}
+
+/* Get a list of interfaces using dnet and intf_loop. */
+static struct interface_info *getinterfaces_dnet(int *howmany, char *errstr, size_t errstrlen) {
+ struct dnet_collector_route_nfo dcrn;
+ intf_t *it;
+
+ dcrn.routes = NULL;
+ dcrn.numroutes = 0;
+ dcrn.numifaces = 0;
+
+ assert(howmany);
+
+ /* Initialize the interface array. */
+ dcrn.capacity = 16;
+ dcrn.ifaces = (struct interface_info *) safe_zalloc(sizeof(struct interface_info) * dcrn.capacity);
+
+ it = intf_open();
+ if (!it){
+ if(errstr) Snprintf(errstr, errstrlen, "%s: intf_open() failed", __func__);
+ *howmany=-1;
+ return NULL;
+ }
+ if (intf_loop(it, collect_dnet_interfaces, &dcrn) != 0){
+ if(errstr) Snprintf(errstr, errstrlen, "%s: intf_loop() failed", __func__);
+ *howmany=-1;
+ return NULL;
+ }
+ intf_close(it);
+
+ *howmany = dcrn.numifaces;
+ return dcrn.ifaces;
+}
+
+static struct interface_info *mydevs = NULL;
+/* Returns an allocated array of struct interface_info representing the
+ available interfaces. The number of interfaces is returned in *howmany. This
+ function just does caching of results; the real work is done in
+ getinterfaces_dnet().
+ On error, NULL is returned, howmany is set to -1 and the supplied
+ error buffer "errstr", if not NULL, will contain an error message. */
+struct interface_info *getinterfaces(int *howmany, char *errstr, size_t errstrlen) {
+ static int numifaces = 0;
+
+ if (mydevs == NULL) {
+ mydevs = getinterfaces_dnet(&numifaces, errstr, errstrlen);
+ }
+
+ /* These will propagate any error produced in getinterfaces_xxxx() to
+ * the caller. */
+ if (howmany)
+ *howmany = numifaces;
+ return mydevs;
+}
+
+void freeinterfaces(void) {
+ free(mydevs);
+ mydevs = NULL;
+}
+
+/* The 'dev' passed in must be at least 32 bytes long. Returns 0 on success. */
+int ipaddr2devname(char *dev, const struct sockaddr_storage *addr) {
+ struct interface_info *ifaces;
+ int numifaces;
+ int i;
+
+ ifaces = getinterfaces(&numifaces, NULL, 0);
+
+ if (ifaces == NULL)
+ return -1;
+
+ for (i = 0; i < numifaces; i++) {
+ if (sockaddr_storage_cmp(&ifaces[i].addr, addr) == 0) {
+ Strncpy(dev, ifaces[i].devname, 32);
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+int devname2ipaddr(char *dev, struct sockaddr_storage *addr) {
+ struct interface_info *ifaces;
+ int numifaces;
+ int i;
+ ifaces = getinterfaces(&numifaces, NULL, 0);
+
+ if (ifaces == NULL)
+ return -1;
+
+ for (i = 0; i < numifaces; i++) {
+ if (!strcmp(dev, ifaces[i].devfullname)) {
+ *addr = ifaces[i].addr;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+/* Looks for an interface with the given name (iname) and address
+ family type, and returns the corresponding interface_info if found.
+ Will accept a match of devname or devfullname. Returns NULL if
+ none found */
+struct interface_info *getInterfaceByName(const char *iname, int af) {
+ struct interface_info *ifaces;
+ int numifaces = 0;
+ int ifnum;
+
+ ifaces = getinterfaces(&numifaces, NULL, 0);
+
+ for (ifnum = 0; ifnum < numifaces; ifnum++) {
+ if ((strcmp(ifaces[ifnum].devfullname, iname) == 0 ||
+ strcmp(ifaces[ifnum].devname, iname) == 0) &&
+ ifaces[ifnum].addr.ss_family == af)
+ return &ifaces[ifnum];
+ }
+
+ return NULL;
+}
+
+
+int sockaddr_equal(const struct sockaddr_storage *a,
+ const struct sockaddr_storage *b) {
+
+ if (a->ss_family == AF_INET && b->ss_family == AF_INET) {
+ struct sockaddr_in *sa, *sb;
+
+ sa = (struct sockaddr_in *) a;
+ sb = (struct sockaddr_in *) b;
+
+ return sa->sin_addr.s_addr == sb->sin_addr.s_addr;
+ } if (a->ss_family == AF_INET6 && b->ss_family == AF_INET6) {
+ struct sockaddr_in6 *sa, *sb;
+
+ sa = (struct sockaddr_in6 *) a;
+ sb = (struct sockaddr_in6 *) b;
+
+ return memcmp(sa->sin6_addr.s6_addr, sb->sin6_addr.s6_addr, sizeof(sa->sin6_addr.s6_addr)) == 0;
+ }
+
+ return 0;
+}
+
+int sockaddr_equal_netmask(const struct sockaddr_storage *a,
+ const struct sockaddr_storage *b, u16 nbits) {
+ unsigned char netmask[IP6_ADDR_LEN];
+
+ addr_btom(nbits, netmask, sizeof(netmask));
+
+ if (a->ss_family == AF_INET && b->ss_family == AF_INET) {
+ struct in_addr *sa, *sb, *sn;
+
+ sa = &((struct sockaddr_in *) a)->sin_addr;
+ sb = &((struct sockaddr_in *) b)->sin_addr;
+ sn = (struct in_addr *) netmask;
+
+ return (sa->s_addr & sn->s_addr) == (sb->s_addr & sn->s_addr);
+ } else if (a->ss_family == AF_INET6 && b->ss_family == AF_INET6) {
+ struct in6_addr *sa, *sb, *sn;
+ unsigned int i;
+
+ sa = &((struct sockaddr_in6 *) a)->sin6_addr;
+ sb = &((struct sockaddr_in6 *) b)->sin6_addr;
+ sn = (struct in6_addr *) netmask;
+
+ for (i = 0; i < sizeof(sa->s6_addr); i++) {
+ if ((sa->s6_addr[i] & sn->s6_addr[i]) != (sb->s6_addr[i] & sn->s6_addr[i])) {
+ return 0;
+ }
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+int sockaddr_equal_zero(const struct sockaddr_storage *s) {
+ if (s->ss_family == AF_INET) {
+ const struct sockaddr_in *sin;
+
+ sin = (struct sockaddr_in *) s;
+ return sin->sin_addr.s_addr == 0;
+ } if (s->ss_family == AF_INET6) {
+ const struct sockaddr_in6 *sin6;
+
+ sin6 = (struct sockaddr_in6 *) s;
+ return memcmp(sin6->sin6_addr.s6_addr, IP6_ADDR_UNSPEC, IP6_ADDR_LEN) == 0;
+ }
+
+ return 0;
+}
+
+/* This is a helper for getsysroutes_dnet. Once the table of routes is in
+ place, this function assigns each to an interface and removes any routes
+ that can't be assigned. */
+static struct dnet_collector_route_nfo *sysroutes_dnet_find_interfaces(struct dnet_collector_route_nfo *dcrn)
+{
+ struct interface_info *ifaces;
+ int numifaces = 0;
+ int i, j;
+ int changed=0;
+
+ if( (ifaces=getinterfaces(&numifaces, NULL, 0))==NULL )
+ return NULL;
+ for (i = 0; i < dcrn->numroutes; i++) {
+ if (dcrn->routes[i].device != NULL)
+ continue;
+
+ /* First we match up routes whose gateway or destination address
+ directly matches the address of an interface. */
+ struct sys_route *route = &dcrn->routes[i];
+ struct sockaddr_storage *routeaddr;
+
+ /* First see if the gateway was set */
+ if (sockaddr_equal_zero(&route->gw))
+ routeaddr = &dcrn->routes[i].dest;
+ else
+ routeaddr = &dcrn->routes[i].gw;
+
+ for (j = 0; j < numifaces; j++) {
+ if (sockaddr_equal_netmask(&ifaces[j].addr, routeaddr, ifaces[j].netmask_bits)) {
+ dcrn->routes[i].device = &ifaces[j];
+ break;
+ }
+ }
+ }
+
+ /* Find any remaining routes that don't yet have an interface, and try to
+ match them up with the interface of another route. This handles "two-step"
+ routes like sometimes exist with PPP, where the gateway address of the
+ default route doesn't match an interface address, but the gateway address
+ goes through another route that does have an interface. */
+
+ do {
+ changed = 0;
+ for (i = 0; i < dcrn->numroutes; i++) {
+ if (dcrn->routes[i].device != NULL)
+ continue;
+ /* Does this route's gateway go through another route with an assigned
+ interface? */
+ for (j = 0; j < dcrn->numroutes; j++) {
+ if (sockaddr_equal(&dcrn->routes[i].gw, &dcrn->routes[j].dest)
+ && dcrn->routes[j].device != NULL) {
+ dcrn->routes[i].device = dcrn->routes[j].device;
+ changed = 1;
+ }
+ }
+ }
+ } while (changed);
+
+ /* Cull any routes that still don't have an interface. */
+ i = 0;
+ while (i < dcrn->numroutes) {
+ if (dcrn->routes[i].device == NULL) {
+ char destbuf[INET6_ADDRSTRLEN];
+ char gwbuf[INET6_ADDRSTRLEN];
+
+ Strncpy(destbuf, inet_ntop_ez(&dcrn->routes[i].dest, sizeof(dcrn->routes[i].dest)), sizeof(destbuf));
+ Strncpy(gwbuf, inet_ntop_ez(&dcrn->routes[i].gw, sizeof(dcrn->routes[i].gw)), sizeof(gwbuf));
+ /*
+ netutil_error("WARNING: Unable to find appropriate interface for system route to %s/%u gw %s",
+ destbuf, dcrn->routes[i].netmask_bits, gwbuf);
+ */
+ /* Remove this entry from the table. */
+ memmove(dcrn->routes + i, dcrn->routes + i + 1, sizeof(dcrn->routes[0]) * (dcrn->numroutes - i - 1));
+ dcrn->numroutes--;
+ } else {
+ i++;
+ }
+ }
+
+ return dcrn;
+}
+
+
+/* This is the callback for the call to route_loop in getsysroutes_dnet. It
+ takes a route entry and adds it into the dnet_collector_route_nfo struct. */
+static int collect_dnet_routes(const struct route_entry *entry, void *arg) {
+ struct dnet_collector_route_nfo *dcrn = (struct dnet_collector_route_nfo *) arg;
+
+ /* Make sure we have room for the new route */
+ if (dcrn->numroutes >= dcrn->capacity) {
+ dcrn->capacity <<= 2;
+ dcrn->routes = (struct sys_route *) safe_realloc(dcrn->routes, dcrn->capacity * sizeof(struct sys_route));
+ }
+
+ /* Now for the important business */
+ addr_ntos(&entry->route_dst, (struct sockaddr *) &dcrn->routes[dcrn->numroutes].dest);
+ dcrn->routes[dcrn->numroutes].netmask_bits = entry->route_dst.addr_bits;
+ addr_ntos(&entry->route_gw, (struct sockaddr *) &dcrn->routes[dcrn->numroutes].gw);
+ dcrn->routes[dcrn->numroutes].metric = entry->metric;
+ dcrn->routes[dcrn->numroutes].device = getInterfaceByName(entry->intf_name, dcrn->routes[dcrn->numroutes].dest.ss_family);
+ dcrn->numroutes++;
+
+ return 0;
+}
+
+
+/* Read system routes via libdnet. */
+static struct sys_route *getsysroutes_dnet(int *howmany, char *errstr, size_t errstrlen) {
+ struct dnet_collector_route_nfo dcrn;
+
+ dcrn.capacity = 128;
+ dcrn.routes = (struct sys_route *) safe_zalloc(dcrn.capacity * sizeof(struct sys_route));
+ dcrn.numroutes = 0;
+ dcrn.ifaces = NULL;
+ dcrn.numifaces = 0;
+ assert(howmany);
+ route_t *dr = route_open();
+
+ if (!dr){
+ if(errstr) Snprintf(errstr, errstrlen, "%s: route_open() failed", __func__);
+ *howmany=-1;
+ return NULL;
+ }
+ if (route_loop(dr, collect_dnet_routes, &dcrn) != 0) {
+ if(errstr) Snprintf(errstr, errstrlen, "%s: route_loop() failed", __func__);
+ *howmany=-1;
+ return NULL;
+ }
+ route_close(dr);
+
+ /* Now match up the routes to interfaces. */
+ if( sysroutes_dnet_find_interfaces(&dcrn) == NULL ){
+ if(errstr) Snprintf(errstr, errstrlen, "%s: sysroutes_dnet_find_interfaces() failed", __func__);
+ return NULL;
+ }
+
+ *howmany = dcrn.numroutes;
+ return dcrn.routes;
+}
+
+
+/* Parse the system routing table, converting each route into a
+ sys_route entry. Returns an array of sys_routes. numroutes is set
+ to the number of routes in the array. The routing table is only
+ read the first time this is called -- later results are cached.
+ The returned route array is sorted by netmask with the most
+ specific matches first.
+ On error, NULL is returned, howmany is set to -1 and the supplied
+ error buffer "errstr", if not NULL, will contain an error message. */
+struct sys_route *getsysroutes(int *howmany, char *errstr, size_t errstrlen) {
+ static struct sys_route *routes = NULL;
+ static int numroutes = 0;
+ assert(howmany);
+
+ if (routes != NULL) {
+ /* We have it cached. */
+ *howmany = numroutes;
+ return routes;
+ }
+
+ routes = getsysroutes_dnet(howmany, errstr, errstrlen);
+
+ /* Check if we managed to get the routes and sort them if we did */
+ if(routes==NULL){
+ *howmany=-1;
+ return NULL;
+ }else{
+ numroutes = *howmany;
+ /* Ensure that the route array is sorted by netmask and metric */
+ qsort(routes, numroutes, sizeof(routes[0]), routecmp);
+ }
+ return routes;
+}
+
+
+/* Tries to determine whether the supplied address corresponds to
+ * localhost. (eg: the address is something like 127.x.x.x, the address
+ * matches one of the local network interfaces' address, etc).
+ * Returns 1 if the address is thought to be localhost and 0 otherwise */
+int islocalhost(const struct sockaddr_storage *ss) {
+ char dev[128];
+ struct sockaddr_in *sin = NULL;
+ struct sockaddr_in6 *sin6 = NULL;
+
+ if (ss->ss_family == AF_INET){
+ sin = (struct sockaddr_in *) ss;
+ /* If it is 0.0.0.0 or starts with 127 then it is probably localhost. */
+ if ((sin->sin_addr.s_addr & htonl(0xFF000000)) == htonl(0x7F000000))
+ return 1;
+
+ if (!(sin->sin_addr.s_addr))
+ return 1;
+ } else {
+ sin6 = (struct sockaddr_in6 *) ss;
+ /* If it is ::0 or ::1 then it is probably localhost. */
+ if (memcmp(&(sin6->sin6_addr), IP6_ADDR_UNSPEC, IP6_ADDR_LEN) == 0)
+ return 1;
+ if (memcmp(&(sin6->sin6_addr), IP6_ADDR_LOOPBACK, IP6_ADDR_LEN) == 0)
+ return 1;
+ }
+
+ /* If it is the same addy as a local interface, then it is
+ probably localhost */
+ if (ipaddr2devname(dev, ss) != -1)
+ return 1;
+
+ /* OK, so to a first approximation, this addy is probably not
+ localhost */
+ return 0;
+}
+
+
+/* Determines whether the supplied address corresponds to a private,
+ * non-Internet-routable address. See RFC1918 for details.
+ *
+ * Also checks for link-local addressing per RFC3927.
+ *
+ * Returns 1 if the address is private or 0 otherwise. */
+int isipprivate(const struct sockaddr_storage *addr) {
+ const struct sockaddr_in *sin;
+ char *ipc;
+ unsigned char i1, i2;
+
+ if (!addr)
+ return 0;
+ if (addr->ss_family != AF_INET)
+ return 0;
+ sin = (struct sockaddr_in *) addr;
+
+ ipc = (char *) &(sin->sin_addr.s_addr);
+ i1 = ipc[0];
+ i2 = ipc[1];
+
+ /* 10.0.0.0/8 */
+ if (i1 == 10)
+ return 1;
+
+ /* 172.16.0.0/12 */
+ if (i1 == 172 && i2 >= 16 && i2 <= 31)
+ return 1;
+
+ /* 169.254.0.0/16 - RFC 3927 */
+ if (i1 == 169 && i2 == 254)
+ return 1;
+
+ /* 192.168.0.0/16 */
+ if (i1 == 192 && i2 == 168)
+ return 1;
+
+ return 0;
+}
+
+
+char *nexthdrtoa(u8 nextheader, int acronym){
+
+static char buffer[129];
+memset(buffer, 0, 129);
+
+#define HDRTOA(num, short_name, long_name) \
+ case num: \
+ strncpy(buffer, acronym ? short_name : long_name, 128);\
+ break;
+
+switch(nextheader){
+ /* Generate these lines from nmap-protocols using the following perl command:
+ perl -lne'if(/^(\S+)\s*(\d+)\s*\#?\s*(.*)/){my$l=$3||$1;print qq{HDRTOA($2, "$1", "$l")}}'
+ */
+ HDRTOA(0, "hopopt", "IPv6 Hop-by-Hop Option")
+ HDRTOA(1, "icmp", "Internet Control Message")
+ HDRTOA(2, "igmp", "Internet Group Management")
+ HDRTOA(3, "ggp", "Gateway-to-Gateway")
+ HDRTOA(4, "ipv4", "IP in IP (encapsulation)")
+ HDRTOA(5, "st", "Stream")
+ HDRTOA(6, "tcp", "Transmission Control")
+ HDRTOA(7, "cbt", "CBT")
+ HDRTOA(8, "egp", "Exterior Gateway Protocol")
+ HDRTOA(9, "igp", "any private interior gateway")
+ HDRTOA(10, "bbn-rcc-mon", "BBN RCC Monitoring")
+ HDRTOA(11, "nvp-ii", "Network Voice Protocol")
+ HDRTOA(12, "pup", "PARC universal packet protocol")
+ HDRTOA(13, "argus", "ARGUS")
+ HDRTOA(14, "emcon", "EMCON")
+ HDRTOA(15, "xnet", "Cross Net Debugger")
+ HDRTOA(16, "chaos", "Chaos")
+ HDRTOA(17, "udp", "User Datagram")
+ HDRTOA(18, "mux", "Multiplexing")
+ HDRTOA(19, "dcn-meas", "DCN Measurement Subsystems")
+ HDRTOA(20, "hmp", "Host Monitoring")
+ HDRTOA(21, "prm", "Packet Radio Measurement")
+ HDRTOA(22, "xns-idp", "XEROX NS IDP")
+ HDRTOA(23, "trunk-1", "Trunk-1")
+ HDRTOA(24, "trunk-2", "Trunk-2")
+ HDRTOA(25, "leaf-1", "Leaf-1")
+ HDRTOA(26, "leaf-2", "Leaf-2")
+ HDRTOA(27, "rdp", "Reliable Data Protocol")
+ HDRTOA(28, "irtp", "Internet Reliable Transaction")
+ HDRTOA(29, "iso-tp4", "ISO Transport Protocol Class 4")
+ HDRTOA(30, "netblt", "Bulk Data Transfer Protocol")
+ HDRTOA(31, "mfe-nsp", "MFE Network Services Protocol")
+ HDRTOA(32, "merit-inp", "MERIT Internodal Protocol")
+ HDRTOA(33, "dccp", "Datagram Congestion Control Protocol")
+ HDRTOA(34, "3pc", "Third Party Connect Protocol")
+ HDRTOA(35, "idpr", "Inter-Domain Policy Routing Protocol")
+ HDRTOA(36, "xtp", "XTP")
+ HDRTOA(37, "ddp", "Datagram Delivery Protocol")
+ HDRTOA(38, "idpr-cmtp", "IDPR Control Message Transport Proto")
+ HDRTOA(39, "tp++", "TP+")
+ HDRTOA(40, "il", "IL Transport Protocol")
+ HDRTOA(41, "ipv6", "Ipv6")
+ HDRTOA(42, "sdrp", "Source Demand Routing Protocol")
+ HDRTOA(43, "ipv6-route", "Routing Header for IPv6")
+ HDRTOA(44, "ipv6-frag", "Fragment Header for IPv6")
+ HDRTOA(45, "idrp", "Inter-Domain Routing Protocol")
+ HDRTOA(46, "rsvp", "Reservation Protocol")
+ HDRTOA(47, "gre", "General Routing Encapsulation")
+ HDRTOA(48, "dsp", "Dynamic Source Routing Protocol. Historically MHRP")
+ HDRTOA(49, "bna", "BNA")
+ HDRTOA(50, "esp", "Encap Security Payload")
+ HDRTOA(51, "ah", "Authentication Header")
+ HDRTOA(52, "i-nlsp", "Integrated Net Layer Security TUBA")
+ HDRTOA(53, "swipe", "IP with Encryption")
+ HDRTOA(54, "narp", "NBMA Address Resolution Protocol")
+ HDRTOA(55, "mobile", "IP Mobility")
+ HDRTOA(56, "tlsp", "Transport Layer Security Protocol using Kryptonet key management")
+ HDRTOA(57, "skip", "SKIP")
+ HDRTOA(58, "ipv6-icmp", "ICMP for IPv6")
+ HDRTOA(59, "ipv6-nonxt", "No Next Header for IPv6")
+ HDRTOA(60, "ipv6-opts", "Destination Options for IPv6")
+ HDRTOA(61, "anyhost", "any host internal protocol")
+ HDRTOA(62, "cftp", "CFTP")
+ HDRTOA(63, "anylocalnet", "any local network")
+ HDRTOA(64, "sat-expak", "SATNET and Backroom EXPAK")
+ HDRTOA(65, "kryptolan", "Kryptolan")
+ HDRTOA(66, "rvd", "MIT Remote Virtual Disk Protocol")
+ HDRTOA(67, "ippc", "Internet Pluribus Packet Core")
+ HDRTOA(68, "anydistribfs", "any distributed file system")
+ HDRTOA(69, "sat-mon", "SATNET Monitoring")
+ HDRTOA(70, "visa", "VISA Protocol")
+ HDRTOA(71, "ipcv", "Internet Packet Core Utility")
+ HDRTOA(72, "cpnx", "Computer Protocol Network Executive")
+ HDRTOA(73, "cphb", "Computer Protocol Heart Beat")
+ HDRTOA(74, "wsn", "Wang Span Network")
+ HDRTOA(75, "pvp", "Packet Video Protocol")
+ HDRTOA(76, "br-sat-mon", "Backroom SATNET Monitoring")
+ HDRTOA(77, "sun-nd", "SUN ND PROTOCOL-Temporary")
+ HDRTOA(78, "wb-mon", "WIDEBAND Monitoring")
+ HDRTOA(79, "wb-expak", "WIDEBAND EXPAK")
+ HDRTOA(80, "iso-ip", "ISO Internet Protocol")
+ HDRTOA(81, "vmtp", "VMTP")
+ HDRTOA(82, "secure-vmtp", "SECURE-VMTP")
+ HDRTOA(83, "vines", "VINES")
+ HDRTOA(84, "iptm", "Internet Protocol Traffic Manager. Historically TTP")
+ HDRTOA(85, "nsfnet-igp", "NSFNET-IGP")
+ HDRTOA(86, "dgp", "Dissimilar Gateway Protocol")
+ HDRTOA(87, "tcf", "TCF")
+ HDRTOA(88, "eigrp", "EIGRP")
+ HDRTOA(89, "ospfigp", "OSPFIGP")
+ HDRTOA(90, "sprite-rpc", "Sprite RPC Protocol")
+ HDRTOA(91, "larp", "Locus Address Resolution Protocol")
+ HDRTOA(92, "mtp", "Multicast Transport Protocol")
+ HDRTOA(93, "ax.25", "AX.")
+ HDRTOA(94, "ipip", "IP-within-IP Encapsulation Protocol")
+ HDRTOA(95, "micp", "Mobile Internetworking Control Pro.")
+ HDRTOA(96, "scc-sp", "Semaphore Communications Sec.")
+ HDRTOA(97, "etherip", "Ethernet-within-IP Encapsulation")
+ HDRTOA(98, "encap", "Encapsulation Header")
+ HDRTOA(99, "anyencrypt", "any private encryption scheme")
+ HDRTOA(100, "gmtp", "GMTP")
+ HDRTOA(101, "ifmp", "Ipsilon Flow Management Protocol")
+ HDRTOA(102, "pnni", "PNNI over IP")
+ HDRTOA(103, "pim", "Protocol Independent Multicast")
+ HDRTOA(104, "aris", "ARIS")
+ HDRTOA(105, "scps", "SCPS")
+ HDRTOA(106, "qnx", "QNX")
+ HDRTOA(107, "a/n", "Active Networks")
+ HDRTOA(108, "ipcomp", "IP Payload Compression Protocol")
+ HDRTOA(109, "snp", "Sitara Networks Protocol")
+ HDRTOA(110, "compaq-peer", "Compaq Peer Protocol")
+ HDRTOA(111, "ipx-in-ip", "IPX in IP")
+ HDRTOA(112, "vrrp", "Virtual Router Redundancy Protocol")
+ HDRTOA(113, "pgm", "PGM Reliable Transport Protocol")
+ HDRTOA(114, "any0hop", "any 0-hop protocol")
+ HDRTOA(115, "l2tp", "Layer Two Tunneling Protocol")
+ HDRTOA(116, "ddx", "D-II Data Exchange")
+ HDRTOA(117, "iatp", "Interactive Agent Transfer Protocol")
+ HDRTOA(118, "stp", "Schedule Transfer Protocol")
+ HDRTOA(119, "srp", "SpectraLink Radio Protocol")
+ HDRTOA(120, "uti", "UTI")
+ HDRTOA(121, "smp", "Simple Message Protocol")
+ HDRTOA(122, "sm", "Simple Multicast Protocol")
+ HDRTOA(123, "ptp", "Performance Transparency Protocol")
+ HDRTOA(124, "isis-ipv4", "ISIS over IPv4")
+ HDRTOA(125, "fire", "fire")
+ HDRTOA(126, "crtp", "Combat Radio Transport Protocol")
+ HDRTOA(127, "crudp", "Combat Radio User Datagram")
+ HDRTOA(128, "sscopmce", "sscopmce")
+ HDRTOA(129, "iplt", "iplt")
+ HDRTOA(130, "sps", "Secure Packet Shield")
+ HDRTOA(131, "pipe", "Private IP Encapsulation within IP")
+ HDRTOA(132, "sctp", "Stream Control Transmission Protocol")
+ HDRTOA(133, "fc", "Fibre Channel")
+ HDRTOA(134, "rsvp-e2e-ignore", "rsvp-e2e-ignore")
+ HDRTOA(135, "mobility-hdr", "Mobility Header")
+ HDRTOA(136, "udplite", "UDP-Lite [RFC3828]")
+ HDRTOA(137, "mpls-in-ip", "MPLS-in-IP [RFC4023]")
+ HDRTOA(138, "manet", "MANET Protocols [RFC5498]")
+ HDRTOA(139, "hip", "Host Identity Protocol")
+ HDRTOA(140, "shim6", "Shim6 Protocol [RFC5533]")
+ HDRTOA(141, "wesp", "Wrapped Encapsulating Security Payload")
+ HDRTOA(142, "rohc", "Robust Header Compression")
+ HDRTOA(143, "ethernet", "RFC 8986 Ethernet next-header")
+ HDRTOA(144, "aggfrag", "AGGFRAG encapsulation payload for ESP [draft-ietf-ipsecme-iptfs-18]")
+ HDRTOA(253, "experimental1", "Use for experimentation and testing")
+ HDRTOA(254, "experimental2", "Use for experimentation and testing")
+ default:
+ strncpy(buffer, acronym ? "unknown" : "Unknown protocol", 128);\
+ break;
+
+ } /* End of switch */
+
+
+ return buffer;
+
+} /* End of nexthdrtoa() */
+
+
+/* TODO: Needs refactoring */
+static inline char* STRAPP(const char *fmt, ...) {
+ static char buf[256];
+ static int bp;
+ int left = (int)sizeof(buf)-bp;
+ if(!fmt){
+ bp = 0;
+ return(buf);
+ }
+ if (left <= 0)
+ return buf;
+ va_list ap;
+ va_start(ap, fmt);
+ bp += Vsnprintf (buf+bp, left, fmt, ap);
+ va_end(ap);
+
+ return(buf);
+}
+
+/* TODO: Needs refactoring */
+#define HEXDUMP -2
+#define UNKNOWN -1
+
+#define BREAK() \
+ {option_type = HEXDUMP; break;}
+#define CHECK(tt) \
+ if(tt >= option_end) \
+ {option_type = HEXDUMP; break;}
+
+/* Takes binary data found in the IP Options field of an IPv4 packet
+ * and returns a string containing an ASCII description of the options
+ * found. The function returns a pointer to a static buffer that
+ * subsequent calls will overwrite. On error, NULL is returned. */
+char *format_ip_options(const u8* ipopt, int ipoptlen) {
+ char ipstring[32];
+ int option_type = UNKNOWN;// option type
+ int option_len = 0; // option length
+ int option_pt = 0; // option pointer
+ int option_fl = 0; // option flag
+ const u8 *tptr; // temp pointer
+ u32 *tint; // temp int
+
+ int option_sta = 0; // option start offset
+ int option_end = 0; // option end offset
+ int pt = 0; // current offset
+
+ // clear buffer
+ STRAPP(NULL,NULL);
+
+ if(!ipoptlen)
+ return(NULL);
+
+ while(pt<ipoptlen){ // for every char in ipopt
+ // read ip option header
+ if(option_type == UNKNOWN) {
+ option_sta = pt;
+ option_type = ipopt[pt++];
+ if(option_type != 0 && option_type != 1) { // should we be interested in length field?
+ if(pt >= ipoptlen) // no more chars
+ {option_type = HEXDUMP;pt--; option_end = 255; continue;} // no length field, hex dump to the end
+ option_len = ipopt[pt++];
+ // end must not be greater than length
+ option_end = MIN(option_sta + option_len, ipoptlen);
+ // end must not be smaller than current position
+ option_end = MAX(option_end, option_sta+2);
+ }
+ }
+ switch(option_type) {
+ case 0: // IPOPT_END
+ STRAPP(" EOL", NULL);
+ option_type = UNKNOWN;
+ break;
+ case 1: // IPOPT_NOP
+ STRAPP(" NOP", NULL);
+ option_type = UNKNOWN;
+ break;
+/* case 130: // IPOPT_SECURITY
+ option_type=-1;
+ break;*/
+ case 131: // IPOPT_LSRR -> Loose Source and Record Route
+ case 137: // IPOPT_SSRR -> Strict Source and Record Route
+ case 7: // IPOPT_RR -> Record Route
+ if(pt - option_sta == 2) {
+ STRAPP(" %s%s{", (option_type==131)?"LS":(option_type==137)?"SS":"", "RR");
+ // option pointer
+ CHECK(pt);
+ option_pt = ipopt[pt++];
+ if(option_pt%4 != 0 || (option_sta + option_pt-1)>option_end || option_pt<4) //bad or too big pointer
+ STRAPP(" [bad ptr=%02i]", option_pt);
+ }
+ if(pt - option_sta > 2) { // ip's
+ int i, s = (option_pt)%4;
+ // if pointer is mangled, fix it. it's max 3 bytes wrong
+ CHECK(pt+3);
+ for(i=0; i<s; i++)
+ STRAPP("\\x%02x", ipopt[pt++]);
+ option_pt -= i;
+ // okay, now we can start printing ip's
+ CHECK(pt+3);
+ tptr = &ipopt[pt]; pt+=4;
+ if(inet_ntop(AF_INET, (char *) tptr, ipstring, sizeof(ipstring)) == NULL){
+ return NULL;
+ }
+ STRAPP("%c%s",(pt-3-option_sta)==option_pt?'#':' ', ipstring);
+ if(pt == option_end)
+ STRAPP("%s",(pt-option_sta)==(option_pt-1)?"#":""); // pointer in the end?
+ }else BREAK();
+ break;
+ case 68: // IPOPT_TS -> Internet Timestamp
+ if(pt - option_sta == 2){
+ STRAPP(" TM{");
+ // pointer
+ CHECK(pt);
+ option_pt = ipopt[pt++];
+ // bad or too big pointer
+ if(option_pt%4 != 1 || (option_sta + option_pt-1)>option_end || option_pt<5)
+ STRAPP(" [bad ptr=%02i]", option_pt);
+ // flags + overflow
+ CHECK(pt);
+ option_fl = ipopt[pt++];
+ if((option_fl&0x0C) || (option_fl&0x03)==2)
+ STRAPP(" [bad flags=\\x%01hhx]", option_fl&0x0F);
+ STRAPP("[%i hosts not recorded]", option_fl>>4);
+ option_fl &= 0x03;
+ }
+ if(pt - option_sta > 2) {// ip's
+ int i, s = (option_pt+3)%(option_fl==0?4:8);
+ // if pointer is mangled, fix it. it's max 3 bytes wrong
+ CHECK(pt+(option_fl==0?3:7));
+ for(i=0; i<s; i++)
+ STRAPP("\\x%02x", ipopt[pt++]);
+ option_pt-=i;
+
+ // print pt
+ STRAPP("%c",(pt+1-option_sta)==option_pt?'#':' ');
+ // okay, first grab ip.
+ if(option_fl!=0){
+ CHECK(pt+3);
+ tptr = &ipopt[pt]; pt+=4;
+ if(inet_ntop(AF_INET, (char *) tptr, ipstring, sizeof(ipstring)) == NULL){
+ return NULL;
+ }
+ STRAPP("%s@", ipstring);
+ }
+ CHECK(pt+3);
+ tint = (u32*)&ipopt[pt]; pt+=4;
+ STRAPP("%lu", (unsigned long) ntohl(*tint));
+
+ if(pt == option_end)
+ STRAPP("%s",(pt-option_sta)==(option_pt-1)?"#":" ");
+ }else BREAK();
+ break;
+ case 136: // IPOPT_SATID -> (SANET) Stream Identifier
+ if(pt - option_sta == 2){
+ u16 *sh;
+ STRAPP(" SI{",NULL);
+ // length
+ if(option_sta+option_len > ipoptlen || option_len!=4)
+ STRAPP("[bad len %02i]", option_len);
+
+ // stream id
+ CHECK(pt+1);
+ sh = (u16*) &ipopt[pt]; pt+=2;
+ option_pt = ntohs(*sh);
+ STRAPP("id=%hu", (unsigned short) option_pt);
+ if(pt != option_end)
+ BREAK();
+ }else BREAK();
+ break;
+ case UNKNOWN:
+ default:
+ // we read option_type and option_len, print them.
+ STRAPP(" ??{\\x%02hhx\\x%02hhx", option_type, option_len);
+ // check option_end once more:
+ if(option_len < ipoptlen)
+ option_end = MIN(MAX(option_sta+option_len, option_sta+2),ipoptlen);
+ else
+ option_end = 255;
+ option_type = HEXDUMP;
+ break;
+ case HEXDUMP:
+ assert(pt<=option_end);
+ if(pt == option_end){
+ STRAPP("}",NULL);
+ option_type=-1;
+ break;
+ }
+ STRAPP("\\x%02hhx", ipopt[pt++]);
+ break;
+ }
+ if(pt == option_end && option_type != UNKNOWN) {
+ STRAPP("}",NULL);
+ option_type = UNKNOWN;
+ }
+ } // while
+ if(option_type != UNKNOWN)
+ STRAPP("}");
+
+ return(STRAPP("",NULL));
+}
+#undef CHECK
+#undef BREAK
+#undef UNKNOWN
+#undef HEXDUMP
+
+
+
+/* Returns a buffer of ASCII information about an IP packet that may
+ * look like "TCP 127.0.0.1:50923 > 127.0.0.1:3 S ttl=61 id=39516
+ * iplen=40 seq=625950769" or "ICMP PING (0/1) ttl=61 id=39516 iplen=40".
+ * Returned buffer is static so it is NOT safe to call this in
+ * multi-threaded environments without appropriate sync protection, or
+ * call it twice in the same sentence (eg: as two printf parameters).
+ * Obviously, the caller should never attempt to free() the buffer. The
+ * returned buffer is guaranteed to be NULL-terminated but no
+ * assumptions should be made concerning its length.
+ *
+ * The function knows IPv4, IPv6, TCP, UDP, SCTP, ICMP, and ICMPv6.
+ *
+ * The output has three different levels of detail. Parameter "detail"
+ * determines how verbose the output should be. It should take one of
+ * the following values:
+ *
+ * LOW_DETAIL (0x01): Traditional output.
+ * MEDIUM_DETAIL (0x02): More verbose than traditional.
+ * HIGH_DETAIL (0x03): Contents of virtually every field of the
+ * protocol headers .
+ */
+const char *ippackethdrinfo(const u8 *packet, u32 len, int detail) {
+ struct abstract_ip_hdr hdr;
+ const u8 *data;
+ unsigned int datalen;
+
+ struct tcp_hdr *tcp = NULL; /* TCP header structure. */
+ struct udp_hdr *udp = NULL; /* UDP header structure. */
+ struct sctp_hdr *sctp = NULL; /* SCTP header structure. */
+ static char protoinfo[1024] = ""; /* Stores final info string. */
+ char ipinfo[512] = ""; /* Temp info about IP. */
+ char icmpinfo[512] = ""; /* Temp info about ICMP. */
+ char icmptype[128] = ""; /* Temp info about ICMP type & code */
+ char icmpfields[256] = ""; /* Temp info for various ICMP fields */
+ char fragnfo[64] = ""; /* Temp info about fragmentation. */
+ char srchost[INET6_ADDRSTRLEN] = ""; /* Src IP in dot-decimal notation. */
+ char dsthost[INET6_ADDRSTRLEN] = ""; /* Dst IP in dot-decimal notation. */
+ char *p = NULL; /* Aux pointer. */
+ int frag_off = 0; /* To compute IP fragment offset. */
+ int more_fragments = 0; /* True if IP MF flag is set. */
+ int dont_fragment = 0; /* True if IP DF flag is set. */
+ int reserved_flag = 0; /* True if IP Reserved flag is set. */
+
+ datalen = len;
+ data = (u8 *) ip_get_data_any(packet, &datalen, &hdr);
+ if (data == NULL)
+ return "BOGUS! Can't parse supposed IP packet";
+
+
+ /* Ensure we end up with a valid detail number */
+ if (detail != LOW_DETAIL && detail != MEDIUM_DETAIL && detail != HIGH_DETAIL)
+ detail = LOW_DETAIL;
+
+ /* IP INFORMATION ************************************************************/
+ if (hdr.version == 4) { /* IPv4 */
+ const struct ip *ip;
+ const struct sockaddr_in *sin;
+
+ ip = (struct ip *) packet;
+
+ /* Obtain IP source and destination info */
+ sin = (struct sockaddr_in *) &hdr.src;
+ inet_ntop(AF_INET, (void *)&sin->sin_addr.s_addr, srchost, sizeof(srchost));
+ sin = (struct sockaddr_in *) &hdr.dst;
+ inet_ntop(AF_INET, (void *)&sin->sin_addr.s_addr, dsthost, sizeof(dsthost));
+
+ /* Compute fragment offset and check if flags are set */
+ frag_off = 8 * (ntohs(ip->ip_off) & 8191) /* 2^13 - 1 */;
+ more_fragments = ntohs(ip->ip_off) & IP_MF;
+ dont_fragment = ntohs(ip->ip_off) & IP_DF;
+ reserved_flag = ntohs(ip->ip_off) & IP_RF;
+
+ /* Is this a fragmented packet? is it the last fragment? */
+ if (frag_off || more_fragments) {
+ Snprintf(fragnfo, sizeof(fragnfo), " frag offset=%d%s", frag_off, more_fragments ? "+" : "");
+ }
+
+ /* Create a string with information relevant to the specified level of detail */
+ if (detail == LOW_DETAIL) {
+ Snprintf(ipinfo, sizeof(ipinfo), "ttl=%d id=%hu iplen=%hu%s %s%s%s",
+ ip->ip_ttl, (unsigned short) ntohs(ip->ip_id), (unsigned short) ntohs(ip->ip_len), fragnfo,
+ ip->ip_hl==5?"":"ipopts={",
+ ip->ip_hl==5?"":format_ip_options((u8*) ip + sizeof(struct ip), MIN((unsigned)(ip->ip_hl-5)*4,len-sizeof(struct ip))),
+ ip->ip_hl==5?"":"}");
+ } else if (detail == MEDIUM_DETAIL) {
+ Snprintf(ipinfo, sizeof(ipinfo), "ttl=%d id=%hu proto=%d csum=0x%04x iplen=%hu%s %s%s%s",
+ ip->ip_ttl, (unsigned short) ntohs(ip->ip_id),
+ ip->ip_p, ntohs(ip->ip_sum),
+ (unsigned short) ntohs(ip->ip_len), fragnfo,
+ ip->ip_hl==5?"":"ipopts={",
+ ip->ip_hl==5?"":format_ip_options((u8*) ip + sizeof(struct ip), MIN((unsigned)(ip->ip_hl-5)*4,len-sizeof(struct ip))),
+ ip->ip_hl==5?"":"}");
+ } else if (detail == HIGH_DETAIL) {
+ Snprintf(ipinfo, sizeof(ipinfo), "ver=%d ihl=%d tos=0x%02x iplen=%hu id=%hu%s%s%s%s foff=%d%s ttl=%d proto=%d csum=0x%04x%s%s%s",
+ ip->ip_v, ip->ip_hl,
+ ip->ip_tos, (unsigned short) ntohs(ip->ip_len),
+ (unsigned short) ntohs(ip->ip_id),
+ (reserved_flag||dont_fragment||more_fragments) ? " flg=" : "",
+ (reserved_flag)? "x" : "",
+ (dont_fragment)? "D" : "",
+ (more_fragments)? "M": "",
+ frag_off, (more_fragments) ? "+" : "",
+ ip->ip_ttl, ip->ip_p,
+ ntohs(ip->ip_sum),
+ ip->ip_hl==5?"":" ipopts={",
+ ip->ip_hl==5?"":format_ip_options((u8*) ip + sizeof(struct ip), MIN((unsigned)(ip->ip_hl-5)*4,len-sizeof(struct ip))),
+ ip->ip_hl==5?"":"}");
+ }
+ } else { /* IPv6 */
+ const struct ip6_hdr *ip6;
+ const struct sockaddr_in6 *sin6;
+
+ ip6 = (struct ip6_hdr *) packet;
+
+ /* Obtain IP source and destination info */
+ sin6 = (struct sockaddr_in6 *) &hdr.src;
+ inet_ntop(AF_INET6, (void *)sin6->sin6_addr.s6_addr, srchost, sizeof(srchost));
+ sin6 = (struct sockaddr_in6 *) &hdr.dst;
+ inet_ntop(AF_INET6, (void *)sin6->sin6_addr.s6_addr, dsthost, sizeof(dsthost));
+
+ /* Obtain flow label and traffic class */
+ u32 flow = ntohl(ip6->ip6_flow);
+ u32 ip6_fl = flow & 0x000fffff;
+ u32 ip6_tc = (flow & 0x0ff00000) >> 20;
+
+ /* Create a string with information relevant to the specified level of detail */
+ if (detail == LOW_DETAIL) {
+ Snprintf(ipinfo, sizeof(ipinfo), "hopl=%d flow=%x payloadlen=%hu",
+ ip6->ip6_hlim, ip6_fl, (unsigned short) ntohs(ip6->ip6_plen));
+ } else if (detail == MEDIUM_DETAIL) {
+ Snprintf(ipinfo, sizeof(ipinfo), "hopl=%d tclass=%d flow=%x payloadlen=%hu",
+ ip6->ip6_hlim, ip6_tc, ip6_fl, (unsigned short) ntohs(ip6->ip6_plen));
+ } else if (detail==HIGH_DETAIL) {
+ Snprintf(ipinfo, sizeof(ipinfo), "ver=6, tclass=%x flow=%x payloadlen=%hu nh=%s hopl=%d ",
+ ip6_tc, ip6_fl, (unsigned short) ntohs(ip6->ip6_plen),
+ nexthdrtoa(ip6->ip6_nxt, 1), ip6->ip6_hlim);
+ }
+ }
+
+
+ /* TCP INFORMATION ***********************************************************/
+ if (hdr.proto == IPPROTO_TCP) {
+ char tflags[10];
+ char tcpinfo[64] = "";
+ char buf[32];
+ char tcpoptinfo[256] = "";
+ tcp = (struct tcp_hdr *) data;
+
+ /* Let's parse the TCP header. The following code is very ugly because we
+ * have to deal with a lot of different situations. We don't want to
+ * segfault so we have to check every length and every bound to ensure we
+ * don't read past the packet. We cannot even trust the contents of the
+ * received packet because, for example, an IPv4 header may state it
+ * carries a TCP packet but may actually carry nothing at all.
+ *
+ * So we distinguish 4 situations. I know the first two are weird but they
+ * were there when I modified this code so I left them there just in
+ * case.
+ * 1. IP datagram is very small or is a fragment where we are missing
+ * the first part of the TCP header
+ * 2. IP datagram is a fragment and although we are missing the first
+ * 8 bytes of the TCP header, we have the rest of it (or some of
+ * the rest of it)
+ * 3. IP datagram is NOT a fragment but we don't have the full TCP
+ * header, we are missing some bytes.
+ * 4. IP datagram is NOT a fragment and we have at least a full 20
+ * byte TCP header.
+ */
+
+ /* CASE 1: where we don't have the first 8 bytes of the TCP header because
+ * either the fragment belongs to somewhere past that or the IP contains
+ * less than 8 bytes. This also includes empty IP packets that say they
+ * contain a TCP packet. */
+ if (frag_off > 8 || datalen < 8) {
+ Snprintf(protoinfo, sizeof(protoinfo), "TCP %s:?? > %s:?? ?? %s (incomplete)",
+ srchost, dsthost, ipinfo);
+ }
+ /* For all cases after this, datalen is necessarily >= 8 and frag_off is <= 8 */
+
+ /* CASE 2: where we are missing the first 8 bytes of the TCP header but we
+ * have, at least, the next 8 bytes so we can see the ACK number, the
+ * flags and window size. */
+ else if (frag_off > 0) {
+ /* Fragmentation is on 8-byte boundaries, so 8 is the only legal value here. */
+ assert(frag_off == 8);
+ tcp = (struct tcp_hdr *)((u8 *) tcp - frag_off); // ugly?
+
+ /* TCP Flags */
+ p = tflags;
+ /* These are basically in tcpdump order */
+ if (tcp->th_flags & TH_SYN)
+ *p++ = 'S';
+ if (tcp->th_flags & TH_FIN)
+ *p++ = 'F';
+ if (tcp->th_flags & TH_RST)
+ *p++ = 'R';
+ if (tcp->th_flags & TH_PUSH)
+ *p++ = 'P';
+ if (tcp->th_flags & TH_ACK) {
+ *p++ = 'A';
+ Snprintf(tcpinfo, sizeof(tcpinfo), " ack=%lu",
+ (unsigned long) ntohl(tcp->th_ack));
+ }
+ if (tcp->th_flags & TH_URG)
+ *p++ = 'U';
+ if (tcp->th_flags & TH_ECE)
+ *p++ = 'E'; /* rfc 2481/3168 */
+ if (tcp->th_flags & TH_CWR)
+ *p++ = 'C'; /* rfc 2481/3168 */
+ *p++ = '\0';
+
+ /* TCP Options */
+ if ((u32) tcp->th_off * 4 > sizeof(struct tcp_hdr)) {
+ if (datalen < (u32) tcp->th_off * 4 - frag_off) {
+ Snprintf(tcpoptinfo, sizeof(tcpoptinfo), "option incomplete");
+ } else {
+ tcppacketoptinfo((u8*) tcp + sizeof(struct tcp_hdr),
+ tcp->th_off*4 - sizeof(struct tcp_hdr),
+ tcpoptinfo, sizeof(tcpoptinfo));
+ }
+ }
+
+ /* Create a string with TCP information relevant to the specified level of detail */
+ if (detail == LOW_DETAIL) { Snprintf(protoinfo, sizeof(protoinfo), "TCP %s:?? > %s:?? %s %s %s %s",
+ srchost, dsthost, tflags, ipinfo, tcpinfo, tcpoptinfo);
+ } else if (detail == MEDIUM_DETAIL) {
+ Snprintf(protoinfo, sizeof(protoinfo), "TCP %s:?? > %s:?? %s ack=%lu win=%hu %s IP [%s]",
+ srchost, dsthost, tflags,
+ (unsigned long) ntohl(tcp->th_ack), (unsigned short) ntohs(tcp->th_win),
+ tcpoptinfo, ipinfo);
+ } else if (detail == HIGH_DETAIL) {
+ if (datalen >= 12) { /* We have at least bytes 8-20 */
+ Snprintf(protoinfo, sizeof(protoinfo), "TCP [%s:?? > %s:?? %s seq=%lu ack=%lu off=%d res=%d win=%hu csum=0x%04X urp=%hu%s%s] IP [%s]",
+ srchost, dsthost, tflags,
+ (unsigned long) ntohl(tcp->th_seq),
+ (unsigned long) ntohl(tcp->th_ack),
+ (u8)tcp->th_off, (u8)tcp->th_x2, (unsigned short) ntohs(tcp->th_win),
+ ntohs(tcp->th_sum), (unsigned short) ntohs(tcp->th_urp),
+ (tcpoptinfo[0]!='\0') ? " " : "",
+ tcpoptinfo, ipinfo);
+ } else { /* We only have bytes 8-16 */
+ Snprintf(protoinfo, sizeof(protoinfo), "TCP %s:?? > %s:?? %s ack=%lu win=%hu %s IP [%s]",
+ srchost, dsthost, tflags,
+ (unsigned long) ntohl(tcp->th_ack), (unsigned short) ntohs(tcp->th_win),
+ tcpoptinfo, ipinfo);
+ }
+ }
+ }
+ /* For all cases after this, frag_off is necessarily 0 */
+
+ /* CASE 3: where the IP packet is not a fragment but for some reason, we
+ * don't have the entire TCP header, just part of it.*/
+ else if (datalen < 20) {
+ /* We know we have the first 8 bytes, so what's left? */
+ /* We only have the first 64 bits: ports and seq number */
+ if (datalen < 12) {
+ Snprintf(tcpinfo, sizeof(tcpinfo), "TCP %s:%hu > %s:%hu ?? seq=%lu (incomplete) %s",
+ srchost, (unsigned short) ntohs(tcp->th_sport), dsthost,
+ (unsigned short) ntohs(tcp->th_dport), (unsigned long) ntohl(tcp->th_seq), ipinfo);
+ }
+
+ /* We only have the first 96 bits: ports, seq and ack number */
+ else if (datalen < 16) {
+ if (detail == LOW_DETAIL) { /* We don't print ACK in low detail */
+ Snprintf(tcpinfo, sizeof(tcpinfo), "TCP %s:%hu > %s:%hu seq=%lu (incomplete), %s",
+ srchost, (unsigned short) ntohs(tcp->th_sport), dsthost,
+ (unsigned short) ntohs(tcp->th_dport), (unsigned long) ntohl(tcp->th_seq), ipinfo);
+ } else {
+ Snprintf(tcpinfo, sizeof(tcpinfo), "TCP [%s:%hu > %s:%hu seq=%lu ack=%lu (incomplete)] IP [%s]",
+ srchost, (unsigned short) ntohs(tcp->th_sport), dsthost,
+ (unsigned short) ntohs(tcp->th_dport), (unsigned long) ntohl(tcp->th_seq),
+ (unsigned long) ntohl(tcp->th_ack), ipinfo);
+ }
+ }
+
+ /* We are missing some part of the last 32 bits (checksum and urgent pointer) */
+ else {
+ p = tflags;
+ /* These are basically in tcpdump order */
+ if (tcp->th_flags & TH_SYN)
+ *p++ = 'S';
+ if (tcp->th_flags & TH_FIN)
+ *p++ = 'F';
+ if (tcp->th_flags & TH_RST)
+ *p++ = 'R';
+ if (tcp->th_flags & TH_PUSH)
+ *p++ = 'P';
+ if (tcp->th_flags & TH_ACK) {
+ *p++ = 'A';
+ Snprintf(buf, sizeof(buf), " ack=%lu",
+ (unsigned long) ntohl(tcp->th_ack));
+ strncat(tcpinfo, buf, sizeof(tcpinfo) - strlen(tcpinfo) - 1);
+ }
+ if (tcp->th_flags & TH_URG)
+ *p++ = 'U';
+ if (tcp->th_flags & TH_ECE)
+ *p++ = 'E'; /* rfc 2481/3168 */
+ if (tcp->th_flags & TH_CWR)
+ *p++ = 'C'; /* rfc 2481/3168 */
+ *p++ = '\0';
+
+
+ /* Create a string with TCP information relevant to the specified level of detail */
+ if (detail == LOW_DETAIL) { /* We don't print ACK in low detail */
+ Snprintf(protoinfo, sizeof(protoinfo), "TCP %s:%hu > %s:%hu %s %s seq=%lu win=%hu (incomplete)",
+ srchost, (unsigned short) ntohs(tcp->th_sport), dsthost, (unsigned short) ntohs(tcp->th_dport),
+ tflags, ipinfo, (unsigned long) ntohl(tcp->th_seq),
+ (unsigned short) ntohs(tcp->th_win));
+ } else if (detail == MEDIUM_DETAIL) {
+ Snprintf(protoinfo, sizeof(protoinfo), "TCP [%s:%hu > %s:%hu %s seq=%lu ack=%lu win=%hu (incomplete)] IP [%s]",
+ srchost, (unsigned short) ntohs(tcp->th_sport), dsthost, (unsigned short) ntohs(tcp->th_dport),
+ tflags, (unsigned long) ntohl(tcp->th_seq),
+ (unsigned long) ntohl(tcp->th_ack),
+ (unsigned short) ntohs(tcp->th_win), ipinfo);
+ } else if (detail == HIGH_DETAIL) {
+ Snprintf(protoinfo, sizeof(protoinfo), "TCP [%s:%hu > %s:%hu %s seq=%lu ack=%lu off=%d res=%d win=%hu (incomplete)] IP [%s]",
+ srchost, (unsigned short) ntohs(tcp->th_sport),
+ dsthost, (unsigned short) ntohs(tcp->th_dport),
+ tflags, (unsigned long) ntohl(tcp->th_seq),
+ (unsigned long) ntohl(tcp->th_ack),
+ (u8)tcp->th_off, (u8)tcp->th_x2, (unsigned short) ntohs(tcp->th_win),
+ ipinfo);
+ }
+ }
+ }
+
+ /* CASE 4: where we (finally!) have a full 20 byte TCP header so we can
+ * safely print all fields */
+ else { /* if (datalen >= 20) */
+
+ /* TCP Flags */
+ p = tflags;
+ /* These are basically in tcpdump order */
+ if (tcp->th_flags & TH_SYN)
+ *p++ = 'S';
+ if (tcp->th_flags & TH_FIN)
+ *p++ = 'F';
+ if (tcp->th_flags & TH_RST)
+ *p++ = 'R';
+ if (tcp->th_flags & TH_PUSH)
+ *p++ = 'P';
+ if (tcp->th_flags & TH_ACK) {
+ *p++ = 'A';
+ Snprintf(buf, sizeof(buf), " ack=%lu",
+ (unsigned long) ntohl(tcp->th_ack));
+ strncat(tcpinfo, buf, sizeof(tcpinfo) - strlen(tcpinfo) - 1);
+ }
+ if (tcp->th_flags & TH_URG)
+ *p++ = 'U';
+ if (tcp->th_flags & TH_ECE)
+ *p++ = 'E'; /* rfc 2481/3168 */
+ if (tcp->th_flags & TH_CWR)
+ *p++ = 'C'; /* rfc 2481/3168 */
+ *p++ = '\0';
+
+ /* TCP Options */
+ if ((u32) tcp->th_off * 4 > sizeof(struct tcp_hdr)) {
+ if (datalen < (unsigned int) tcp->th_off * 4) {
+ Snprintf(tcpoptinfo, sizeof(tcpoptinfo), "option incomplete");
+ } else {
+ tcppacketoptinfo((u8*) tcp + sizeof(struct tcp_hdr),
+ tcp->th_off*4 - sizeof(struct tcp_hdr),
+ tcpoptinfo, sizeof(tcpoptinfo));
+ }
+ }
+
+ /* Rest of header fields */
+ if (detail == LOW_DETAIL) {
+ Snprintf(protoinfo, sizeof(protoinfo), "TCP %s:%hu > %s:%hu %s %s seq=%lu win=%hu %s",
+ srchost, (unsigned short) ntohs(tcp->th_sport), dsthost, (unsigned short) ntohs(tcp->th_dport),
+ tflags, ipinfo, (unsigned long) ntohl(tcp->th_seq),
+ (unsigned short) ntohs(tcp->th_win), tcpoptinfo);
+ } else if (detail == MEDIUM_DETAIL) {
+ Snprintf(protoinfo, sizeof(protoinfo), "TCP [%s:%hu > %s:%hu %s seq=%lu win=%hu csum=0x%04X%s%s] IP [%s]",
+ srchost, (unsigned short) ntohs(tcp->th_sport), dsthost, (unsigned short) ntohs(tcp->th_dport),
+ tflags, (unsigned long) ntohl(tcp->th_seq),
+ (unsigned short) ntohs(tcp->th_win), (unsigned short) ntohs(tcp->th_sum),
+ (tcpoptinfo[0]!='\0') ? " " : "",
+ tcpoptinfo, ipinfo);
+ } else if (detail == HIGH_DETAIL) {
+ Snprintf(protoinfo, sizeof(protoinfo), "TCP [%s:%hu > %s:%hu %s seq=%lu ack=%lu off=%d res=%d win=%hu csum=0x%04X urp=%hu%s%s] IP [%s]",
+ srchost, (unsigned short) ntohs(tcp->th_sport),
+ dsthost, (unsigned short) ntohs(tcp->th_dport),
+ tflags, (unsigned long) ntohl(tcp->th_seq),
+ (unsigned long) ntohl(tcp->th_ack),
+ (u8)tcp->th_off, (u8)tcp->th_x2, (unsigned short) ntohs(tcp->th_win),
+ ntohs(tcp->th_sum), (unsigned short) ntohs(tcp->th_urp),
+ (tcpoptinfo[0]!='\0') ? " " : "",
+ tcpoptinfo, ipinfo);
+ }
+ }
+
+ /* UDP INFORMATION ***********************************************************/
+ } else if (hdr.proto == IPPROTO_UDP && frag_off) {
+ Snprintf(protoinfo, sizeof(protoinfo), "UDP %s:?? > %s:?? fragment %s (incomplete)",
+ srchost, dsthost, ipinfo);
+ } else if (hdr.proto == IPPROTO_UDP) {
+ udp = (struct udp_hdr *) data;
+ /* TODO: See if we can segfault if we receive a fragmented packet whose IP packet does not say a thing about fragmentation */
+
+ if (detail == LOW_DETAIL) {
+ Snprintf(protoinfo, sizeof(protoinfo), "UDP %s:%hu > %s:%hu %s",
+ srchost, (unsigned short) ntohs(udp->uh_sport), dsthost, (unsigned short) ntohs(udp->uh_dport),
+ ipinfo);
+ } else if (detail == MEDIUM_DETAIL) {
+ Snprintf(protoinfo, sizeof(protoinfo), "UDP [%s:%hu > %s:%hu csum=0x%04X] IP [%s]",
+ srchost, (unsigned short) ntohs(udp->uh_sport), dsthost, (unsigned short) ntohs(udp->uh_dport), ntohs(udp->uh_sum),
+ ipinfo);
+ } else if (detail == HIGH_DETAIL) {
+ Snprintf(protoinfo, sizeof(protoinfo), "UDP [%s:%hu > %s:%hu len=%hu csum=0x%04X] IP [%s]",
+ srchost, (unsigned short) ntohs(udp->uh_sport), dsthost, (unsigned short) ntohs(udp->uh_dport),
+ (unsigned short) ntohs(udp->uh_ulen), ntohs(udp->uh_sum),
+ ipinfo);
+ }
+
+ /* SCTP INFORMATION **********************************************************/
+ } else if (hdr.proto == IPPROTO_SCTP && frag_off) {
+ Snprintf(protoinfo, sizeof(protoinfo), "SCTP %s:?? > %s:?? fragment %s (incomplete)",
+ srchost, dsthost, ipinfo);
+ } else if (hdr.proto == IPPROTO_SCTP) {
+ sctp = (struct sctp_hdr *) data;
+
+ if (detail == LOW_DETAIL) {
+ Snprintf(protoinfo, sizeof(protoinfo), "SCTP %s:%hu > %s:%hu %s",
+ srchost, (unsigned short) ntohs(sctp->sh_sport), dsthost, (unsigned short) ntohs(sctp->sh_dport),
+ ipinfo);
+ } else if (detail == MEDIUM_DETAIL) {
+ Snprintf(protoinfo, sizeof(protoinfo), "SCTP [%s:%hu > %s:%hu csum=0x%08x] IP [%s]",
+ srchost, (unsigned short) ntohs(sctp->sh_sport), dsthost, (unsigned short) ntohs(sctp->sh_dport), ntohl(sctp->sh_sum),
+ ipinfo);
+ } else if (detail == HIGH_DETAIL) {
+ Snprintf(protoinfo, sizeof(protoinfo), "SCTP [%s:%hu > %s:%hu vtag=%lu csum=0x%08x] IP [%s]",
+ srchost, (unsigned short) ntohs(sctp->sh_sport), dsthost, (unsigned short) ntohs(sctp->sh_dport),
+ (unsigned long) ntohl(sctp->sh_vtag), ntohl(sctp->sh_sum),
+ ipinfo);
+ }
+
+ /* ICMP INFORMATION **********************************************************/
+ } else if (hdr.proto == IPPROTO_ICMP && frag_off) {
+ Snprintf(protoinfo, sizeof(protoinfo), "ICMP %s > %s fragment %s (incomplete)",
+ srchost, dsthost, ipinfo);
+ } else if (hdr.proto == IPPROTO_ICMP) {
+ struct ip *ip2; /* Points to the IP datagram carried by some ICMP messages */
+ char *ip2dst; /* Dest IP in caried IP datagram */
+ char auxbuff[128]; /* Aux buffer */
+ struct icmp_packet{ /* Generic ICMP struct */
+ u8 type;
+ u8 code;
+ u16 checksum;
+ u8 data[128];
+ }*icmppkt;
+ struct ppkt { /* Beginning of ICMP Echo/Timestamp header */
+ u8 type;
+ u8 code;
+ u16 checksum;
+ u16 id;
+ u16 seq;
+ } *ping = NULL;
+ struct icmp_redir{
+ u8 type;
+ u8 code;
+ u16 checksum;
+ u32 addr;
+ } *icmpredir = NULL;
+ struct icmp_router{
+ u8 type;
+ u8 code;
+ u16 checksum;
+ u8 addrs;
+ u8 addrlen;
+ u16 lifetime;
+ } *icmprouter = NULL;
+ struct icmp_param{
+ u8 type;
+ u8 code;
+ u16 checksum;
+ u8 pnt;
+ u8 unused;
+ u16 unused2;
+ } *icmpparam = NULL;
+ struct icmp_tstamp{
+ u8 type;
+ u8 code;
+ u16 checksum;
+ u16 id;
+ u16 seq;
+ u32 orig;
+ u32 recv;
+ u32 trans;
+ } *icmptstamp = NULL;
+ struct icmp_amask{
+ u8 type;
+ u8 code;
+ u16 checksum;
+ u16 id;
+ u16 seq;
+ u32 mask;
+ } *icmpmask = NULL;
+
+ /* Compute the ICMP minimum length. */
+ unsigned pktlen = 8;
+
+ /* We need the ICMP packet to be at least 8 bytes long */
+ if (pktlen > datalen)
+ goto icmpbad;
+
+ ping = (struct ppkt *) data;
+ icmppkt = (struct icmp_packet *) data;
+
+ switch(icmppkt->type) {
+ /* Echo Reply **************************/
+ case 0:
+ strcpy(icmptype, "Echo reply");
+ Snprintf(icmpfields, sizeof(icmpfields), "id=%hu seq=%hu", (unsigned short) ntohs(ping->id), (unsigned short) ntohs(ping->seq));
+ break;
+
+ /* Destination Unreachable *************/
+ case 3:
+ /* Point to the start of the original datagram */
+ ip2 = (struct ip *) (data + 8);
+
+ /* Check we have a full IP datagram included in the ICMP message */
+ pktlen += MAX( (ip2->ip_hl * 4), 20);
+ if (pktlen > datalen) {
+ if (datalen == 8) {
+ Snprintf(icmptype, sizeof icmptype, "Destination unreachable%s",
+ (detail!=LOW_DETAIL)? " (original datagram missing)" : "");
+ } else {
+ Snprintf(icmptype, sizeof icmptype, "Destination unreachable%s",
+ (detail!=LOW_DETAIL)? " (part of original datagram missing)" : "");
+ }
+ goto icmpbad;
+ }
+
+ /* Basic check to ensure we have an IPv4 datagram attached */
+ /* TODO: We should actually check the datagram checksum to
+ * see if it validates because just checking the version number
+ * is not enough. On average, if we get random data 1 out of
+ * 16 (2^4bits) times we will have value 4. */
+ if ((ip2->ip_v != 4) || ((ip2->ip_hl * 4) < 20) || ((ip2->ip_hl * 4) > 60)) {
+ Snprintf(icmptype, sizeof icmptype, "Destination unreachable (bogus original datagram)");
+ goto icmpbad;
+ } else {
+ /* We have the original datagram + the first 8 bytes of the
+ * transport layer header */
+ if (pktlen + 8 < datalen) {
+ tcp = (struct tcp_hdr *) ((char *) ip2 + (ip2->ip_hl * 4));
+ udp = (struct udp_hdr *) ((char *) ip2 + (ip2->ip_hl * 4));
+ sctp = (struct sctp_hdr *) ((char *) ip2 + (ip2->ip_hl * 4));
+ }
+ }
+
+ /* Determine the IP the original datagram was sent to */
+ ip2dst = inet_ntoa(ip2->ip_dst);
+
+ /* Determine type of Destination unreachable from the code value */
+ switch (icmppkt->code) {
+ case 0:
+ Snprintf(icmptype, sizeof icmptype, "Network %s unreachable", ip2dst);
+ break;
+
+ case 1:
+ Snprintf(icmptype, sizeof icmptype, "Host %s unreachable", ip2dst);
+ break;
+
+ case 2:
+ Snprintf(icmptype, sizeof icmptype, "Protocol %u unreachable", ip2->ip_p);
+ break;
+
+ case 3:
+ if (pktlen + 8 < datalen) {
+ if (ip2->ip_p == IPPROTO_UDP && udp)
+ Snprintf(icmptype, sizeof icmptype, "Port %hu unreachable", (unsigned short) ntohs(udp->uh_dport));
+ else if (ip2->ip_p == IPPROTO_TCP && tcp)
+ Snprintf(icmptype, sizeof icmptype, "Port %hu unreachable", (unsigned short) ntohs(tcp->th_dport));
+ else if (ip2->ip_p == IPPROTO_SCTP && sctp)
+ Snprintf(icmptype, sizeof icmptype, "Port %hu unreachable", (unsigned short) ntohs(sctp->sh_dport));
+ else
+ Snprintf(icmptype, sizeof icmptype, "Port unreachable (unknown protocol %u)", ip2->ip_p);
+ }
+ else
+ strcpy(icmptype, "Port unreachable");
+ break;
+
+ case 4:
+ strcpy(icmptype, "Fragmentation required");
+ Snprintf(icmpfields, sizeof(icmpfields), "Next-Hop-MTU=%d", icmppkt->data[2]<<8 | icmppkt->data[3]);
+ break;
+
+ case 5:
+ strcpy(icmptype, "Source route failed");
+ break;
+
+ case 6:
+ Snprintf(icmptype, sizeof icmptype, "Destination network %s unknown", ip2dst);
+ break;
+
+ case 7:
+ Snprintf(icmptype, sizeof icmptype, "Destination host %s unknown", ip2dst);
+ break;
+
+ case 8:
+ strcpy(icmptype, "Source host isolated");
+ break;
+
+ case 9:
+ Snprintf(icmptype, sizeof icmptype, "Destination network %s administratively prohibited", ip2dst);
+ break;
+
+ case 10:
+ Snprintf(icmptype, sizeof icmptype, "Destination host %s administratively prohibited", ip2dst);
+ break;
+
+ case 11:
+ Snprintf(icmptype, sizeof icmptype, "Network %s unreachable for TOS", ip2dst);
+ break;
+
+ case 12:
+ Snprintf(icmptype, sizeof icmptype, "Host %s unreachable for TOS", ip2dst);
+ break;
+
+ case 13:
+ strcpy(icmptype, "Communication administratively prohibited by filtering");
+ break;
+
+ case 14:
+ strcpy(icmptype, "Host precedence violation");
+ break;
+
+ case 15:
+ strcpy(icmptype, "Precedence cutoff in effect");
+ break;
+
+ default:
+ strcpy(icmptype, "Destination unreachable (unknown code)");
+ break;
+ } /* End of ICMP Code switch */
+ break;
+
+
+ /* Source Quench ***********************/
+ case 4:
+ strcpy(icmptype, "Source quench");
+ break;
+
+ /* Redirect ****************************/
+ case 5:
+ if (ping->code == 0)
+ strcpy(icmptype, "Network redirect");
+ else if (ping->code == 1)
+ strcpy(icmptype, "Host redirect");
+ else
+ strcpy(icmptype, "Redirect (unknown code)");
+ icmpredir = (struct icmp_redir *) icmppkt;
+ inet_ntop(AF_INET, &icmpredir->addr, auxbuff, sizeof(auxbuff));
+ Snprintf(icmpfields, sizeof(icmpfields), "addr=%s", auxbuff);
+ break;
+
+ /* Echo Request ************************/
+ case 8:
+ strcpy(icmptype, "Echo request");
+ Snprintf(icmpfields, sizeof(icmpfields), "id=%hu seq=%hu", (unsigned short) ntohs(ping->id), (unsigned short) ntohs(ping->seq));
+ break;
+
+ /* Router Advertisement ****************/
+ case 9:
+ if (icmppkt->code == 16)
+ strcpy(icmptype, "Router advertisement (Mobile Agent Only)");
+ else
+ strcpy(icmptype, "Router advertisement");
+ icmprouter = (struct icmp_router *) icmppkt;
+ Snprintf(icmpfields, sizeof(icmpfields), "addrs=%u addrlen=%u lifetime=%hu",
+ icmprouter->addrs,
+ icmprouter->addrlen,
+ (unsigned short) ntohs(icmprouter->lifetime));
+ break;
+
+ /* Router Solicitation *****************/
+ case 10:
+ strcpy(icmptype, "Router solicitation");
+ break;
+
+ /* Time Exceeded ***********************/
+ case 11:
+ if (icmppkt->code == 0)
+ strcpy(icmptype, "TTL=0 during transit");
+ else if (icmppkt->code == 1)
+ strcpy(icmptype, "TTL=0 during reassembly");
+ else
+ strcpy(icmptype, "TTL exceeded (unknown code)");
+ break;
+
+ /* Parameter Problem *******************/
+ case 12:
+ if (ping->code == 0)
+ strcpy(icmptype, "Parameter problem (pointer indicates error)");
+ else if (ping->code == 1)
+ strcpy(icmptype, "Parameter problem (option missing)");
+ else if (ping->code == 2)
+ strcpy(icmptype, "Parameter problem (bad length)");
+ else
+ strcpy(icmptype, "Parameter problem (unknown code)");
+ icmpparam = (struct icmp_param *) icmppkt;
+ Snprintf(icmpfields, sizeof(icmpfields), "pointer=%d", icmpparam->pnt);
+ break;
+
+ /* Timestamp Request/Reply *************/
+ case 13:
+ case 14:
+ Snprintf(icmptype, sizeof(icmptype), "Timestamp %s", (icmppkt->type == 13)? "request" : "reply");
+ icmptstamp = (struct icmp_tstamp *) icmppkt;
+ Snprintf(icmpfields, sizeof(icmpfields), "id=%hu seq=%hu orig=%lu recv=%lu trans=%lu",
+ (unsigned short) ntohs(icmptstamp->id), (unsigned short) ntohs(icmptstamp->seq),
+ (unsigned long) ntohl(icmptstamp->orig),
+ (unsigned long) ntohl(icmptstamp->recv),
+ (unsigned long) ntohl(icmptstamp->trans));
+ break;
+
+ /* Information Request *****************/
+ case 15:
+ strcpy(icmptype, "Information request");
+ Snprintf(icmpfields, sizeof(icmpfields), "id=%hu seq=%hu", (unsigned short) ntohs(ping->id), (unsigned short) ntohs(ping->seq));
+ break;
+
+ /* Information Reply *******************/
+ case 16:
+ strcpy(icmptype, "Information reply");
+ Snprintf(icmpfields, sizeof(icmpfields), "id=%hu seq=%hu", (unsigned short) ntohs(ping->id), (unsigned short) ntohs(ping->seq));
+ break;
+
+ /* Netmask Request/Reply ***************/
+ case 17:
+ case 18:
+ Snprintf(icmptype, sizeof(icmptype), "Address mask %s", (icmppkt->type == 17)? "request" : "reply");
+ icmpmask = (struct icmp_amask *) icmppkt;
+ inet_ntop(AF_INET, &icmpmask->mask, auxbuff, sizeof(auxbuff));
+ Snprintf(icmpfields, sizeof(icmpfields), "id=%u seq=%u mask=%s",
+ (unsigned short) ntohs(ping->id), (unsigned short) ntohs(ping->seq), auxbuff);
+ break;
+
+ /* Traceroute **************************/
+ case 30:
+ strcpy(icmptype, "Traceroute");
+ break;
+
+ /* Domain Name Request *****************/
+ case 37:
+ strcpy(icmptype, "Domain name request");
+ break;
+
+ /* Domain Name Reply *******************/
+ case 38:
+ strcpy(icmptype, "Domain name reply");
+ break;
+
+ /* Security ****************************/
+ case 40:
+ strcpy(icmptype, "Security failures"); /* rfc 2521 */
+ break;
+
+ default:
+ strcpy(icmptype, "Unknown type"); break;
+ break;
+ } /* End of ICMP Type switch */
+
+ if (pktlen > datalen) {
+icmpbad:
+ if (ping) {
+ /* We still have this information */
+ Snprintf(protoinfo, sizeof(protoinfo), "ICMP %s > %s %s (type=%d/code=%d) %s",
+ srchost, dsthost, icmptype, ping->type, ping->code, ipinfo);
+ } else {
+ Snprintf(protoinfo, sizeof(protoinfo), "ICMP %s > %s [??] %s",
+ srchost, dsthost, ipinfo);
+ }
+ } else {
+ if (ping)
+ sprintf(icmpinfo,"type=%d/code=%d", ping->type, ping->code);
+ else
+ strncpy(icmpinfo,"type=?/code=?", sizeof(icmpinfo));
+
+ Snprintf(protoinfo, sizeof(protoinfo), "ICMP [%s > %s %s (%s) %s] IP [%s]",
+ srchost, dsthost, icmptype, icmpinfo, icmpfields, ipinfo);
+ }
+
+ } else if (hdr.proto == IPPROTO_ICMPV6) {
+ if (datalen > sizeof(struct icmpv6_hdr)) {
+ const struct icmpv6_hdr *icmpv6;
+
+ icmpv6 = (struct icmpv6_hdr *) data;
+ Snprintf(protoinfo, sizeof(protoinfo), "ICMPv6 (%d) %s > %s (type=%d/code=%d) %s",
+ hdr.proto, srchost, dsthost,
+ icmpv6->icmpv6_type, icmpv6->icmpv6_code, ipinfo);
+ }
+ else {
+ Snprintf(protoinfo, sizeof(protoinfo), "ICMPv6 (%d) %s > %s (type=?/code=?) %s",
+ hdr.proto, srchost, dsthost, ipinfo);
+ }
+ } else {
+ /* UNKNOWN PROTOCOL **********************************************************/
+ const char *hdrstr;
+
+ hdrstr = nexthdrtoa(hdr.proto, 1);
+ if (hdrstr == NULL || *hdrstr == '\0') {
+ Snprintf(protoinfo, sizeof(protoinfo), "Unknown protocol (%d) %s > %s: %s",
+ hdr.proto, srchost, dsthost, ipinfo);
+ } else {
+ Snprintf(protoinfo, sizeof(protoinfo), "%s (%d) %s > %s: %s",
+ hdrstr, hdr.proto, srchost, dsthost, ipinfo);
+ }
+ }
+
+ return protoinfo;
+}
+
+
+#ifdef HAVE_LINUX_RTNETLINK_H
+/* Fill in a sockaddr_storage given an address family and raw address. */
+static int set_sockaddr(struct sockaddr_storage *ss, int af, void *data) {
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
+
+ ss->ss_family = af;
+ if (af == AF_INET) {
+ sin = (struct sockaddr_in *) ss;
+ memcpy(&sin->sin_addr.s_addr, data, IP_ADDR_LEN);
+ } else if (af == AF_INET6) {
+ sin6 = (struct sockaddr_in6 *) ss;
+ memcpy(sin6->sin6_addr.s6_addr, data, IP6_ADDR_LEN);
+ } else {
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Add rtattrs to a netlink message specifying a source or destination address.
+ rta_type must be RTA_SRC or RTA_DST. This function adds either 1 or 2
+ rtattrs: it always adds either an RTA_SRC or RTA_DST, depending on rta_type.
+ If ifindex is not 0, it is the index of the interface to use. The function
+ adds either RTA_OIF if rta_type is RTA_DST, and either of ifindex and
+ sin6_scope_id is nonzero. */
+static void add_rtattr_addr(struct nlmsghdr *nlmsg,
+ struct rtattr **rtattr, unsigned int *len,
+ unsigned char rta_type,
+ const struct sockaddr_storage *ss,
+ int ifindex) {
+ struct rtmsg *rtmsg;
+ const void *addr;
+ size_t addrlen;
+
+ assert(rta_type == RTA_SRC || rta_type == RTA_DST);
+
+ if (rta_type == RTA_SRC) {
+ /* Ignore the interface specification if we are setting an RTA_SRC attribute
+ (it may still get set by the scope_id below). */
+ ifindex = 0;
+ }
+
+ if (ss->ss_family == AF_INET) {
+ addr = &((struct sockaddr_in *) ss)->sin_addr.s_addr;
+ addrlen = IP_ADDR_LEN;
+ } else if (ss->ss_family == AF_INET6) {
+ const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) ss;
+
+ addr = sin6->sin6_addr.s6_addr;
+ addrlen = IP6_ADDR_LEN;
+ if (ifindex == 0)
+ ifindex = sin6->sin6_scope_id;
+ } else {
+ netutil_fatal("%s: unknown address family %d", __func__, ss->ss_family);
+ }
+
+ rtmsg = (struct rtmsg *) (nlmsg + 1);
+ if (rta_type == RTA_SRC)
+ rtmsg->rtm_src_len = addrlen * 8;
+ else
+ rtmsg->rtm_dst_len = addrlen * 8;
+
+ /* Add an rtattr for the address. */
+ (*rtattr)->rta_type = rta_type;
+ (*rtattr)->rta_len = RTA_LENGTH(addrlen);
+ assert(RTA_OK(*rtattr, *len));
+ memcpy(RTA_DATA(*rtattr), addr, addrlen);
+ nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + (*rtattr)->rta_len;
+ *rtattr = RTA_NEXT(*rtattr, *len);
+
+ /* Specific interface (sin6_scope_id) requested? */
+ if (ifindex > 0) {
+ /* Add an rtattr for the interface. */
+ if (rta_type == RTA_SRC)
+ (*rtattr)->rta_type = RTA_IIF;
+ else
+ (*rtattr)->rta_type = RTA_OIF;
+ (*rtattr)->rta_len = RTA_LENGTH(sizeof(uint32_t));
+ assert(RTA_OK(*rtattr, *len));
+ *(uint32_t *) RTA_DATA(*rtattr) = ifindex;
+ nlmsg->nlmsg_len = NLMSG_ALIGN(nlmsg->nlmsg_len) + (*rtattr)->rta_len;
+ *rtattr = RTA_NEXT(*rtattr, *len);
+ }
+}
+
+/* Does route_dst using the Linux-specific rtnetlink interface. See rtnetlink(3)
+ and rtnetlink(7). */
+static int route_dst_netlink(const struct sockaddr_storage *dst,
+ struct route_nfo *rnfo, const char *device,
+ const struct sockaddr_storage *spoofss) {
+ struct sockaddr_nl snl;
+ struct msghdr msg;
+ struct iovec iov;
+ struct nlmsghdr *nlmsg;
+ struct rtmsg *rtmsg;
+ struct rtattr *rtattr;
+ int intf_index;
+ unsigned char buf[512];
+ unsigned int len;
+ int fd, rc;
+
+ fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (fd == -1)
+ netutil_fatal("%s: cannot create AF_NETLINK socket: %s", __func__, strerror(errno));
+
+ memset(&snl, 0, sizeof(snl));
+ snl.nl_family = AF_NETLINK;
+
+ rc = bind(fd, (struct sockaddr *) &snl, sizeof(snl));
+ if (rc == -1)
+ netutil_fatal("%s: cannot bind AF_NETLINK socket: %s", __func__, strerror(errno));
+
+ struct interface_info *ii;
+ ii = NULL;
+ intf_index = 0;
+ if (device != NULL && device[0] != '\0') {
+ ii = getInterfaceByName(device, dst->ss_family);
+ if (ii == NULL)
+ netutil_fatal("Could not find interface %s which was specified by -e", device);
+ intf_index = ii->ifindex;
+ }
+
+ memset(buf, 0, sizeof(buf));
+
+ nlmsg = (struct nlmsghdr *) buf;
+
+ nlmsg->nlmsg_len = NLMSG_LENGTH(sizeof(*rtmsg));
+ assert(nlmsg->nlmsg_len <= sizeof(buf));
+ nlmsg->nlmsg_flags = NLM_F_REQUEST;
+ nlmsg->nlmsg_type = RTM_GETROUTE;
+
+ rtmsg = (struct rtmsg *) (nlmsg + 1);
+ rtmsg->rtm_family = dst->ss_family;
+
+ rtattr = RTM_RTA(rtmsg);
+ len = sizeof(buf) - ((unsigned char *) RTM_RTA(rtmsg) - buf);
+
+ /* Add rtattrs for destination address and interface. */
+ add_rtattr_addr(nlmsg, &rtattr, &len, RTA_DST, dst, intf_index);
+ if (spoofss != NULL) {
+ /* Add rtattrs for source address and interface. */
+ add_rtattr_addr(nlmsg, &rtattr, &len, RTA_SRC, spoofss, intf_index);
+ }
+
+ iov.iov_base = nlmsg;
+ iov.iov_len = nlmsg->nlmsg_len;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_name = &snl;
+ msg.msg_namelen = sizeof(snl);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ rc = sendmsg(fd, &msg, 0);
+ if (rc == -1)
+ netutil_fatal("%s: cannot sendmsg: %s", __func__, strerror(errno));
+
+ iov.iov_base = buf;
+ iov.iov_len = sizeof(buf);
+
+ len = recvmsg(fd, &msg, 0);
+ if (len <= 0)
+ netutil_fatal("%s: cannot recvmsg: %s", __func__, strerror(errno));
+
+ close(fd);
+
+ if (nlmsg->nlmsg_len < sizeof(*nlmsg) || (unsigned int) len < NLMSG_LENGTH(sizeof(*nlmsg)))
+ netutil_fatal("%s: wrong size reply in recvmsg", __func__);
+ len -= NLMSG_LENGTH(sizeof(*nlmsg));
+
+ /* See rtnetlink(7). Anything matching this route is actually unroutable. */
+ if (rtmsg->rtm_type == RTN_UNREACHABLE || rtmsg->rtm_type == RTN_UNSPEC
+ || rtmsg->rtm_type == RTN_BLACKHOLE || rtmsg->rtm_type == RTN_PROHIBIT)
+ return 0;
+
+ /* Default values to be possibly overridden. */
+ rnfo->direct_connect = 1;
+ rnfo->nexthop.ss_family = AF_UNSPEC;
+ rnfo->srcaddr.ss_family = AF_UNSPEC;
+ if (spoofss != NULL)
+ rnfo->srcaddr = *spoofss;
+
+ for (rtattr = RTM_RTA(rtmsg); RTA_OK(rtattr, len); rtattr = RTA_NEXT(rtattr, len)) {
+ if (rtattr->rta_type == RTA_GATEWAY) {
+ rc = set_sockaddr(&rnfo->nexthop, dst->ss_family, RTA_DATA(rtattr));
+ assert(rc != -1);
+ /* Don't consider it directly connected if nexthop != dst. */
+ if (!sockaddr_storage_equal(dst, &rnfo->nexthop))
+ rnfo->direct_connect = 0;
+ } else if (rtattr->rta_type == RTA_OIF && ii == NULL) {
+ char namebuf[IFNAMSIZ];
+ char *p;
+ int intf_index;
+
+ intf_index = *(int *) RTA_DATA(rtattr);
+ p = if_indextoname(intf_index, namebuf);
+ if (p == NULL)
+ netutil_fatal("%s: if_indextoname(%d) failed: %d (%s)", __func__, intf_index, errno, strerror(errno));
+ ii = getInterfaceByName(namebuf, dst->ss_family);
+ if (ii == NULL)
+ ii = getInterfaceByName(namebuf, AF_UNSPEC);
+ if (ii == NULL)
+ netutil_fatal("%s: can't find interface \"%s\"", __func__, namebuf);
+ } else if (rtattr->rta_type == RTA_PREFSRC && rnfo->srcaddr.ss_family == AF_UNSPEC) {
+ rc = set_sockaddr(&rnfo->srcaddr, dst->ss_family, RTA_DATA(rtattr));
+ assert(rc != -1);
+ }
+ }
+
+ if (ii != NULL) {
+ rnfo->ii = *ii;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+#else
+
+static struct interface_info *find_loopback_iface(struct interface_info *ifaces,
+ int numifaces) {
+ int i;
+
+ for (i = 0; i < numifaces; i++) {
+ if (ifaces[i].device_type == devt_loopback)
+ return &ifaces[i];
+ }
+
+ return NULL;
+}
+
+/* Get the source address for routing to dst by creating a socket and asking the
+ operating system for the local address. */
+static int get_srcaddr(const struct sockaddr_storage *dst,
+ struct sockaddr_storage *src)
+{
+ static const unsigned short DUMMY_PORT = 1234;
+ struct sockaddr_storage dst_dummy;
+ size_t dst_dummy_len;
+ socklen_t len;
+ int fd, rc;
+
+ fd = socket(dst->ss_family, SOCK_DGRAM, 0);
+ if (fd == -1)
+ netutil_fatal("%s: can't create socket: %s", __func__, socket_strerror(socket_errno()));
+
+ dst_dummy = *dst;
+ if (dst_dummy.ss_family == AF_INET) {
+ struct sockaddr_in *sin = (struct sockaddr_in *) &dst_dummy;
+ sin->sin_port = htons(DUMMY_PORT);
+ dst_dummy_len = sizeof(*sin);
+ } else if (dst_dummy.ss_family == AF_INET6) {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &dst_dummy;
+ sin6->sin6_port = htons(DUMMY_PORT);
+ dst_dummy_len = sizeof(*sin6);
+ } else {
+ goto bail;
+ }
+
+ rc = connect(fd, (struct sockaddr *) &dst_dummy, dst_dummy_len);
+ if (rc == -1) {
+ netutil_error("%s: can't connect socket: %s", __func__, socket_strerror(socket_errno()));
+ if (dst->ss_family == AF_INET6) {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &dst_dummy;
+ if (sin6->sin6_scope_id == 0)
+ netutil_error("Do you need an IPv6 zone ID suffix (e.g. %%eth0 or %%1)?");
+ }
+ goto bail;
+ }
+
+ len = sizeof(*src);
+ rc = getsockname(fd, (struct sockaddr *) src, &len);
+ if (rc == -1)
+ netutil_fatal("%s: can't getsockname: %s", __func__, socket_strerror(socket_errno()));
+
+ close(fd);
+ return 0;
+
+bail:
+ close(fd);
+ return -1;
+}
+
+static char *lookup_ifindex(unsigned int index, int af, char *namebuf, size_t len) {
+ intf_t *it;
+ struct intf_entry entry;
+ int rc;
+
+ it = intf_open();
+ assert(it != NULL);
+ entry.intf_len = sizeof(entry);
+ rc = intf_get_index(it, &entry, af, index);
+ intf_close(it);
+ if (rc == -1)
+ return NULL;
+
+ Strncpy(namebuf, entry.intf_name, len);
+ return namebuf;
+}
+
+static int route_dst_generic(const struct sockaddr_storage *dst,
+ struct route_nfo *rnfo, const char *device,
+ const struct sockaddr_storage *spoofss) {
+ struct interface_info *ifaces;
+ struct interface_info *iface;
+ int numifaces = 0;
+ struct sys_route *routes;
+ int numroutes = 0;
+ int i;
+ char namebuf[32];
+ char errstr[256];
+ errstr[0]='\0';
+
+ if (!dst)
+ netutil_fatal("%s passed a NULL dst address", __func__);
+
+ if(spoofss!=NULL){
+ /* Throughout the rest of this function we only change rnfo->srcaddr if the source isn't spoofed */
+ memcpy(&rnfo->srcaddr, spoofss, sizeof(rnfo->srcaddr));
+ /* The device corresponding to this spoofed address should already have been set elsewhere. */
+ assert(device!=NULL && device[0]!='\0');
+ }
+
+ if (device == NULL || device[0] == '\0') {
+ /* Check if there is an interface scope on the address which we must use. */
+ if (dst->ss_family == AF_INET6) {
+ const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) dst;
+ if (sin6->sin6_scope_id > 0) {
+ device = lookup_ifindex(sin6->sin6_scope_id, sin6->sin6_family, namebuf, sizeof(namebuf));
+ if (device == NULL) {
+ netutil_error("Could not find interface with index %u", (unsigned int) sin6->sin6_scope_id);
+ return 0;
+ }
+ }
+ }
+ }
+
+ if (device!=NULL && device[0]!='\0'){
+ iface = getInterfaceByName(device, dst->ss_family);
+ if (!iface)
+ netutil_fatal("Could not find interface %s", device);
+ } else {
+ iface = NULL;
+ }
+
+ if((routes=getsysroutes(&numroutes, errstr, sizeof(errstr)))==NULL)
+ netutil_fatal("%s: Failed to obtain system routes: %s", __func__, errstr);
+ if((ifaces=getinterfaces(&numifaces, errstr, sizeof(errstr)))==NULL)
+ netutil_fatal("%s: Failed to obtain system interfaces: %s", __func__, errstr);
+
+ /* First check if dst is one of the localhost's own addresses. We need to use
+ a localhost device for these. */
+ for (i = 0; i < numifaces; i++) {
+ struct interface_info *loopback;
+
+ if (!sockaddr_equal(dst, &ifaces[i].addr))
+ continue;
+
+ if (ifaces[i].device_type == devt_loopback)
+ loopback = &ifaces[i];
+ else
+ loopback = find_loopback_iface(ifaces, numifaces);
+ if (loopback == NULL)
+ /* Hmmm ... no localhost -- move on to the routing table. */
+ break;
+
+ if (iface != NULL && strcmp(loopback->devname, iface->devname) != 0)
+ continue;
+
+ if (iface == NULL && !loopback->device_up)
+ continue;
+
+ rnfo->ii = *loopback;
+ rnfo->direct_connect = 1;
+ /* But the source address we want to use is the target address. */
+ if (!spoofss) {
+ if (get_srcaddr(dst, &rnfo->srcaddr) == -1)
+ rnfo->srcaddr = rnfo->ii.addr;
+ }
+
+ return 1;
+ }
+
+ /* Go through the routing table and take the first match. getsysroutes sorts
+ so more-specific routes come first. */
+ for (i = 0; i < numroutes; i++) {
+ if (!sockaddr_equal_netmask(dst, &routes[i].dest, routes[i].netmask_bits))
+ continue;
+ /* Ignore routes that aren't on the device we specified. */
+ if (iface != NULL && strcmp(routes[i].device->devname, iface->devname) != 0)
+ continue;
+
+ if (iface == NULL && !routes[i].device->device_up)
+ continue;
+
+ rnfo->ii = *routes[i].device;
+ /* At this point we don't whether this route is direct or indirect ("G" flag
+ in netstat). We guess that a route is direct when the gateway address is
+ 0.0.0.0 or ::, when it exactly matches the interface address, or when it
+ exactly matches the destination address. */
+ rnfo->direct_connect = (sockaddr_equal_zero(&routes[i].gw) ||
+ sockaddr_equal(&routes[i].gw, &routes[i].device->addr) ||
+ sockaddr_equal(&routes[i].gw, dst));
+ if (!spoofss) {
+ if (get_srcaddr(dst, &rnfo->srcaddr) == -1)
+ rnfo->srcaddr = rnfo->ii.addr;
+ }
+ rnfo->nexthop = routes[i].gw;
+
+ return 1;
+ }
+
+ /* No match on routes. Try interfaces directly. */
+ for (i = 0; i < numifaces; i++) {
+ if (!sockaddr_equal_netmask(dst, &ifaces[i].addr, ifaces[i].netmask_bits))
+ continue;
+ if (iface != NULL && strcmp(ifaces[i].devname, iface->devname) != 0)
+ continue;
+
+ if (iface == NULL && !ifaces[i].device_up)
+ continue;
+
+ rnfo->ii = ifaces[i];
+ rnfo->direct_connect = 1;
+ if (!spoofss) {
+ if (get_srcaddr(dst, &rnfo->srcaddr) == -1)
+ rnfo->srcaddr = rnfo->ii.addr;
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+#endif
+
+/* Takes a destination address (dst) and tries to determine the
+ * source address and interface necessary to route to this address.
+ * If no route is found, 0 is returned and "rnfo" is undefined. If
+ * a route is found, 1 is returned and "rnfo" is filled in with all
+ * of the routing details. If the source address needs to be spoofed,
+ * it should be passed through "spoofss" (otherwise NULL should be
+ * specified), along with a suitable network device (parameter "device").
+ * Even if spoofss is NULL, if user specified a network device with -e,
+ * it should still be passed. Note that it's OK to pass either NULL or
+ * an empty string as the "device", as long as spoofss==NULL. */
+int route_dst(const struct sockaddr_storage *dst, struct route_nfo *rnfo,
+ const char *device, const struct sockaddr_storage *spoofss) {
+#ifdef HAVE_LINUX_RTNETLINK_H
+ return route_dst_netlink(dst, rnfo, device, spoofss);
+#else
+ return route_dst_generic(dst, rnfo, device, spoofss);
+#endif
+}
+
+/* Wrapper for system function sendto(), which retries a few times when
+ * the call fails. It also prints informational messages about the
+ * errors encountered. It returns the number of bytes sent or -1 in
+ * case of error. */
+int Sendto(const char *functionname, int sd,
+ const unsigned char *packet, int len, unsigned int flags,
+ struct sockaddr *to, int tolen) {
+
+ int res;
+ int retries = 0;
+ int sleeptime = 0;
+ static int numerrors = 0;
+
+ do {
+ if ((res = sendto(sd, (const char *) packet, len, flags, to, tolen)) == -1) {
+ int err = socket_errno();
+
+ numerrors++;
+ if(numerrors <= 10) {
+ netutil_error("sendto in %s: sendto(%d, packet, %d, 0, %s, %d) => %s",
+ functionname, sd, len, inet_ntop_ez((struct sockaddr_storage *) to, sizeof(struct sockaddr_storage)), tolen,
+ strerror(err));
+ netutil_error("Offending packet: %s", ippackethdrinfo(packet, len, LOW_DETAIL));
+ if (numerrors == 10) {
+ netutil_error("Omitting future %s error messages now that %d have been shown. Use -d2 if you really want to see them.", __func__, numerrors);
+ }
+ }
+#if WIN32
+ return -1;
+#else
+ if (retries > 2)
+ return -1;
+ /* For these enumerated errors, we sleep and try again. */
+ if (!(err == ENOBUFS || err == ENOMEM))
+ return -1;
+ sleeptime = 15 * (1 << (2 * retries));
+ netutil_error("Sleeping %d seconds then retrying", sleeptime);
+ fflush(stderr);
+ sleep(sleeptime);
+#endif
+ }
+ retries++;
+ } while (res == -1);
+
+ return res;
+}
+
+
+
+/* Send an IP packet over an ethernet handle. */
+int send_ip_packet_eth(const struct eth_nfo *eth, const u8 *packet, unsigned int packetlen) {
+ eth_t *ethsd;
+ u8 *eth_frame;
+ int res;
+
+ eth_frame = (u8 *) safe_malloc(14 + packetlen);
+ memcpy(eth_frame + 14, packet, packetlen);
+ eth_pack_hdr(eth_frame, eth->dstmac, eth->srcmac, ETH_TYPE_IP);
+ if (!eth->ethsd) {
+ ethsd = eth_open_cached(eth->devname);
+ if (!ethsd)
+ netutil_fatal("%s: Failed to open ethernet device (%s)", __func__, eth->devname);
+ } else {
+ ethsd = eth->ethsd;
+ }
+ res = eth_send(ethsd, eth_frame, 14 + packetlen);
+ /* No need to close ethsd due to caching */
+ free(eth_frame);
+
+ return res;
+}
+
+
+/* Send an IP packet over a raw socket. */
+int send_ip_packet_sd(int sd, const struct sockaddr_in *dst,
+ const u8 *packet, unsigned int packetlen) {
+ struct sockaddr_in sock;
+ struct ip *ip = (struct ip *) packet;
+ struct tcp_hdr *tcp;
+ struct udp_hdr *udp;
+ int res;
+
+ assert(sd >= 0);
+ sock = *dst;
+
+ /* It is bogus that I need the address and port info when sending a RAW IP
+ packet, but it doesn't seem to work w/o them */
+ if (packetlen >= 20) {
+ if (ip->ip_p == IPPROTO_TCP
+ && packetlen >= (unsigned int) ip->ip_hl * 4 + 20) {
+ tcp = (struct tcp_hdr *) ((u8 *) ip + ip->ip_hl * 4);
+ sock.sin_port = tcp->th_dport;
+ } else if (ip->ip_p == IPPROTO_UDP
+ && packetlen >= (unsigned int) ip->ip_hl * 4 + 8) {
+ udp = (struct udp_hdr *) ((u8 *) ip + ip->ip_hl * 4);
+ sock.sin_port = udp->uh_dport;
+ }
+ }
+
+ /* Equally bogus is that the IP total len and IP fragment offset
+ fields need to be in host byte order on certain BSD variants. I
+ must deal with it here rather than when building the packet,
+ because they should be in NBO when I'm sending over raw
+ ethernet */
+#if (defined(FREEBSD) && (__FreeBSD_version < 1100030)) || BSDI || NETBSD || DEC || MACOSX
+ ip->ip_len = ntohs(ip->ip_len);
+ ip->ip_off = ntohs(ip->ip_off);
+#endif
+
+ res = Sendto("send_ip_packet_sd", sd, packet, packetlen, 0,
+ (struct sockaddr *) &sock,
+ (int) sizeof(struct sockaddr_in));
+
+ /* Undo the byte order switching. */
+#if (defined(FREEBSD) && (__FreeBSD_version < 1100030)) || BSDI || NETBSD || DEC || MACOSX
+ ip->ip_len = htons(ip->ip_len);
+ ip->ip_off = htons(ip->ip_off);
+#endif
+
+ return res;
+}
+
+
+
+/* Sends the supplied pre-built IPv4 packet. The packet is sent through
+ * the raw socket "sd" if "eth" is NULL. Otherwise, it gets sent at raw
+ * ethernet level. */
+int send_ip_packet_eth_or_sd(int sd, const struct eth_nfo *eth,
+ const struct sockaddr_in *dst,
+ const u8 *packet, unsigned int packetlen) {
+ if(eth)
+ return send_ip_packet_eth(eth, packet, packetlen);
+ else
+ return send_ip_packet_sd(sd, dst, packet, packetlen);
+}
+
+
+
+/* Create and send all fragments of a pre-built IPv4 packet
+ * Minimal MTU for IPv4 is 68 and maximal IPv4 header size is 60
+ * which gives us a right to cut TCP header after 8th byte
+ * (shouldn't we inflate the header to 60 bytes too?) */
+int send_frag_ip_packet(int sd, const struct eth_nfo *eth,
+ const struct sockaddr_in *dst,
+ const u8 *packet, unsigned int packetlen, u32 mtu) {
+ struct ip *ip = (struct ip *) packet;
+ int headerlen = ip->ip_hl * 4; // better than sizeof(struct ip)
+ u32 datalen = packetlen - headerlen;
+ int fdatalen = 0, res = 0;
+ int fragment=0;
+
+ assert(headerlen <= (int) packetlen);
+ assert(headerlen >= 20 && headerlen <= 60); // sanity check (RFC791)
+ assert(mtu > 0 && mtu % 8 == 0); // otherwise, we couldn't set Fragment offset (ip->ip_off) correctly
+
+ if (datalen <= mtu) {
+ netutil_error("Warning: fragmentation (mtu=%lu) requested but the payload is too small already (%lu)", (unsigned long)mtu, (unsigned long)datalen);
+ return send_ip_packet_eth_or_sd(sd, eth, dst, packet, packetlen);
+ }
+
+ u8 *fpacket = (u8 *) safe_malloc(headerlen + mtu);
+ memcpy(fpacket, packet, headerlen + mtu);
+ ip = (struct ip *) fpacket;
+
+ // create fragments and send them
+ for (fragment = 1; fragment * mtu < datalen + mtu; fragment++) {
+ fdatalen = (fragment * mtu <= datalen ? mtu : datalen % mtu);
+ ip->ip_len = htons(headerlen + fdatalen);
+ ip->ip_off = htons((fragment - 1) * mtu / 8);
+ if ((fragment - 1) * mtu + fdatalen < datalen)
+ ip->ip_off |= htons(IP_MF);
+#if HAVE_IP_IP_SUM
+ ip->ip_sum = 0;
+ ip->ip_sum = in_cksum((unsigned short *) ip, headerlen);
+#endif
+ if (fragment > 1) // copy data payload
+ memcpy(fpacket + headerlen,
+ packet + headerlen + (fragment - 1) * mtu, fdatalen);
+ res = send_ip_packet_eth_or_sd(sd, eth, dst, fpacket, ntohs(ip->ip_len));
+ if (res == -1)
+ break;
+ }
+ free(fpacket);
+ return res;
+}
+
+/* There are three ways to send a raw IPv6 packet.
+
+ send_ipv6_eth works when the device is Ethernet. (Unfortunately IPv6-in-IPv4
+ tunnels are not.) We can control all header fields and extension headers.
+
+ send_ipv6_ipproto_raw must be used when IPPROTO_RAW sockets include the IP
+ header, like IP_HDRINCL for IPv4. This is non-standard but is the case on
+ Linux. (On other platforms, IPPROTO_RAW has no special meaning and just
+ stands for protocol 255.) We can control all header fields and extension
+ headers. This method uses only one raw socket for all sends.
+
+ send_ipv6_ip must be used when IPPROTO_RAW sockets do not include the IP
+ header. Through standard function calls we can control all header fields
+ except for the flow label. This method needs one raw socket for every
+ protocol. (More precisely, one socket per distinct Next Header value.)
+*/
+
+/* Send an IPv6 packet over an Ethernet handle. */
+static int send_ipv6_eth(const struct eth_nfo *eth, const u8 *packet, unsigned int packetlen) {
+ eth_t *ethsd;
+ struct eth_hdr *eth_frame;
+ u8 *copy;
+ int res;
+
+ copy = (u8 *) safe_malloc(packetlen + sizeof(*eth_frame));
+ memcpy(copy + sizeof(*eth_frame), packet, packetlen);
+ eth_frame = (struct eth_hdr *) copy;
+ eth_pack_hdr(eth_frame, eth->dstmac, eth->srcmac, ETH_TYPE_IPV6);
+ if (!eth->ethsd) {
+ ethsd = eth_open_cached(eth->devname);
+ if (!ethsd)
+ netutil_fatal("%s: Failed to open ethernet device (%s)", __func__, eth->devname);
+ } else {
+ ethsd = eth->ethsd;
+ }
+ res = eth_send(ethsd, eth_frame, sizeof(*eth_frame) + packetlen);
+ /* No need to close ethsd due to caching */
+ free(eth_frame);
+
+ return res;
+}
+
+#if HAVE_IPV6_IPPROTO_RAW
+
+/* Send an IPv6 packet over a raw socket, on platforms where IPPROTO_RAW implies
+ IP_HDRINCL-like behavior. */
+static int send_ipv6_ipproto_raw(const struct sockaddr_in6 *dst,
+ const unsigned char *packet, unsigned int packetlen) {
+ int sd, n;
+
+ sd = -1;
+ n = -1;
+
+ sd = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW);
+ if (sd == -1) {
+ perror("socket");
+ goto bail;
+ }
+
+ n = Sendto(__func__, sd, packet, packetlen, 0, (struct sockaddr *) dst, sizeof(*dst));
+
+bail:
+ if (sd != -1)
+ close(sd);
+
+ return n;
+}
+
+#elif !WIN32
+
+/* Add an ancillary cmsghdr data block to the list of blocks in a msghdr.
+ The list is stored in msg->msg_control, which is dynamically allocated
+ and reallocated as needed. It must be freed after this function returns.
+ msg->msg_controllen is also modified by this function. Returns -1 in case of
+ error or 0 otherwise. */
+static int add_ancillary(struct msghdr *msg, int level, int type,
+ const void *data, size_t len)
+{
+ struct cmsghdr *cm;
+ void *p;
+
+ p = realloc(msg->msg_control, msg->msg_controllen + CMSG_SPACE(len));
+ if (p == NULL)
+ return -1;
+ msg->msg_control = p;
+
+ cm = (struct cmsghdr *) ((char *) msg->msg_control + msg->msg_controllen);
+ msg->msg_controllen += CMSG_SPACE(len);
+
+ cm->cmsg_len = CMSG_LEN(len);
+ cm->cmsg_level = level;
+ cm->cmsg_type = type;
+
+ memcpy(CMSG_DATA(cm), data, len);
+
+ return 0;
+}
+
+static int exthdr_type_to_cmsg_type(uint8_t type) {
+ switch (type) {
+ /* These are the only extension headers we can set directly through a
+ msghdr. */
+ case 0:
+ return IPV6_HOPOPTS;
+ case 43:
+ return IPV6_RTHDR;
+ case 60:
+ return IPV6_DSTOPTS;
+ default:
+ return -1;
+ }
+}
+
+static const unsigned char *add_exthdr_ancillary(struct msghdr *msg,
+ const unsigned char *p, size_t len, unsigned char *proto) {
+ unsigned char nxt;
+ size_t extlen;
+ int cmsg_type;
+
+ cmsg_type = exthdr_type_to_cmsg_type(*proto);
+ if (cmsg_type == -1)
+ return NULL;
+
+ if (len < 2)
+ return NULL;
+ nxt = *p;
+ extlen = (*(p + 1) + 1) * 8;
+ if (len < extlen)
+ return NULL;
+ if (add_ancillary(msg, IPPROTO_IPV6, cmsg_type, p, extlen) == -1)
+ return NULL;
+
+ *proto = nxt;
+
+ return p + extlen;
+}
+
+/* Send an IPv6 packet over a raw socket. This function can control all header
+ fields except the flow label (and the payload length can only be controlled
+ indirectly through the length of the payload).
+
+ For most extension header types, we initialize the socket with the given
+ protocol, which causes the Next Header field to match when the packet is set.
+ This allows stuffing arbitrary data into extension headers. However, for a
+ few well-known headers (like Destination and Routing options), this fails
+ with EPROTOTYPE because there are specialized functions to add these headers
+ using the IPv6 socket API. These do not offer as much control because they
+ are controlled by the OS, and may be reordered, for example. */
+static int send_ipv6_ip(const struct sockaddr_in6 *dst,
+ const unsigned char *packet, size_t packetlen) {
+ struct msghdr msg;
+ struct iovec iov;
+
+ const unsigned char *end;
+ struct ip6_hdr *hdr;
+ unsigned char nxt;
+#ifdef IPV6_TCLASS
+ int tclass;
+#endif
+ int hoplimit;
+
+ int sd;
+ int n;
+
+ sd = -1;
+ n = -1;
+
+ /* Set up sendmsg data structure. iov is filled in below. */
+ msg.msg_name = (void *) dst;
+ msg.msg_namelen = sizeof(*dst);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_flags = 0;
+
+ if (packetlen < sizeof(*hdr))
+ return -1;
+ hdr = (struct ip6_hdr *) packet;
+
+ /* This can also be set with setsockopt(IPPROTO_IPV6, IPV6_TCLASS). */
+#ifdef IPV6_TCLASS
+ tclass = ntohl(hdr->ip6_flow & IP6_FLOWINFO_MASK) >> 20;
+ if (add_ancillary(&msg, IPPROTO_IPV6,
+ IPV6_TCLASS, &tclass, sizeof(tclass)) == -1) {
+ goto bail;
+ }
+#endif
+ /* This can also be set with setsockopt(IPPROTO_IPV6, IPV6_UNICAST_HOPS). */
+ hoplimit = hdr->ip6_hlim;
+ if (add_ancillary(&msg, IPPROTO_IPV6,
+ IPV6_HOPLIMIT, &hoplimit, sizeof(hoplimit)) == -1) {
+ goto bail;
+ }
+ /* The Next Header field is set when the socket is created. The payload
+ length is set in the call to sendmsg. There's no way to set the flow
+ label. */
+
+ /* We must loop until we find a nh value acceptable to the operating system
+ (one that can be passed as the third parameter to socket). In my tests on
+ OS X, you get EPROTOTYPE "Protocol wrong type for socket" for
+ 43 routing
+ 44 fragment
+ 50 ESP
+ 51 AH
+ 60 DSTOPT
+ 108 IPcomp
+ Some of these we are able to handle with ancillary data. When that's
+ possible, we skip over the header, add the ancillary data, and try again
+ with the next header. */
+ end = packet + packetlen;
+ packet += sizeof(*hdr);
+ nxt = hdr->ip6_nxt;
+ for (;;) {
+ errno = 0;
+ sd = socket(AF_INET6, SOCK_RAW, nxt);
+ if (!(sd == -1 && errno == EPROTOTYPE))
+ break;
+ packet = add_exthdr_ancillary(&msg, packet, end - packet, &nxt);
+ if (packet == NULL) {
+ netutil_error("Can't add extension header %u as ancillary data", nxt);
+ goto bail;
+ }
+ }
+ if (sd == -1) {
+ perror("socket");
+ goto bail;
+ }
+
+ assert(packet <= end);
+ iov.iov_base = (unsigned char *) packet;
+ iov.iov_len = end - packet;
+
+ n = sendmsg(sd, &msg, 0);
+ if (n == -1)
+ perror("sendmsg");
+
+bail:
+ free(msg.msg_control);
+ if (sd != -1)
+ close(sd);
+
+ return n;
+}
+
+#endif
+
+/* For now, the sd argument is ignored. */
+int send_ipv6_packet_eth_or_sd(int sd, const struct eth_nfo *eth,
+ const struct sockaddr_in6 *dst, const u8 *packet, unsigned int packetlen) {
+ if (eth != NULL) {
+ return send_ipv6_eth(eth, packet, packetlen);
+ } else {
+#if HAVE_IPV6_IPPROTO_RAW
+ return send_ipv6_ipproto_raw(dst, packet, packetlen);
+#elif !WIN32
+ return send_ipv6_ip(dst, packet, packetlen);
+#endif
+ }
+
+ return -1;
+}
+
+
+
+#ifdef WIN32
+/* Convert a dnet interface name into the long pcap style. This also caches the
+ data to speed things up. Fills out pcapdev (up to pcapdevlen) and returns
+ true if it finds anything. Otherwise returns false. This is only necessary
+ on Windows. */
+int DnetName2PcapName(const char *dnetdev, char *pcapdev, int pcapdevlen) {
+ static struct NameCorrelationCache {
+ char dnetd[64];
+ char pcapd[128];
+ } *NCC = NULL;
+ static int NCCsz = 0;
+ static int NCCcapacity = 0;
+ static struct NameNotFoundCache {
+ char dnetd[64];
+ } *NNFC = NULL;
+ static int NNFCsz = 0;
+ static int NNFCcapacity = 0;
+ int i;
+ char tmpdev[128];
+
+ // Init the cache if not done yet
+ if (!NCC) {
+ NCCcapacity = 5;
+ NCC =
+ (struct NameCorrelationCache *) safe_zalloc(NCCcapacity *
+ sizeof(*NCC));
+ NCCsz = 0;
+ }
+ if (!NNFC) {
+ NNFCcapacity = 5;
+ NNFC =
+ (struct NameNotFoundCache *) safe_zalloc(NNFCcapacity *
+ sizeof(*NNFC));
+ NNFCsz = 0;
+ }
+ // First check if the name is already in the cache
+ for (i = 0; i < NCCsz; i++) {
+ if (strcmp(NCC[i].dnetd, dnetdev) == 0) {
+ Strncpy(pcapdev, NCC[i].pcapd, pcapdevlen);
+ return 1;
+ }
+ }
+ // Check if the name is already in the name not found cache
+ for (i = 0; i < NNFCsz; i++) {
+ if (strcmp(NNFC[i].dnetd, dnetdev) == 0) {
+ return 0;
+ }
+ }
+ // OK, so it isn't in the cache. Let's ask dnet for it.
+ /* Converts a dnet interface name (ifname) to its pcap equivalent, which is stored in
+ pcapdev (up to a length of pcapdevlen). Returns 1 and fills in pcapdev if successful. */
+ if (eth_get_pcap_devname(dnetdev, tmpdev, sizeof(tmpdev)) != 0) {
+ // We've got it. Let's add it to the not found cache
+ if (NNFCsz >= NNFCcapacity) {
+ NNFCcapacity <<= 2;
+ NNFC =
+ (struct NameNotFoundCache *) safe_realloc(NNFC,
+ NNFCcapacity *
+ sizeof(*NNFC));
+ }
+ Strncpy(NNFC[NNFCsz].dnetd, dnetdev, sizeof(NNFC[0].dnetd));
+ NNFCsz++;
+ return 0;
+ }
+
+ // We've got it. Let's add it to the cache
+ if (NCCsz >= NCCcapacity) {
+ NCCcapacity <<= 2;
+ NCC =
+ (struct NameCorrelationCache *) safe_realloc(NCC,
+ NCCcapacity *
+ sizeof(*NCC));
+ }
+ Strncpy(NCC[NCCsz].dnetd, dnetdev, sizeof(NCC[0].dnetd));
+ Strncpy(NCC[NCCsz].pcapd, tmpdev, sizeof(NCC[0].pcapd));
+ NCCsz++;
+ Strncpy(pcapdev, tmpdev, pcapdevlen);
+ return 1;
+}
+#endif
+
+
+/* This function is used to obtain a packet capture handle to look at
+ * packets on the network. It is actually a wrapper for libpcap's
+ * pcap_open_live() that takes care of compatibility issues and error
+ * checking. The function attempts to open the device up to three times.
+ * If the call does not succeed the third time, NULL is returned. */
+pcap_t *my_pcap_open_live(const char *device, int snaplen, int promisc, int to_ms){
+ char err0r[PCAP_ERRBUF_SIZE];
+ pcap_t *pt;
+ char pcapdev[128];
+ int failed = 0;
+
+ assert(device != NULL);
+
+#ifdef WIN32
+ /* Nmap normally uses device names obtained through dnet for interfaces, but
+ Pcap has its own naming system. So the conversion is done here */
+ if (!DnetName2PcapName(device, pcapdev, sizeof(pcapdev))) {
+ /* Oh crap -- couldn't find the corresponding dev apparently. Let's just go
+ with what we have then ... */
+ Strncpy(pcapdev, device, sizeof(pcapdev));
+ }
+#else
+ Strncpy(pcapdev, device, sizeof(pcapdev));
+#endif
+
+#ifdef __amigaos__
+ // Amiga doesn't have pcap_create
+ // TODO: Does Nmap still work on Amiga?
+ pt = pcap_open_live(pcapdev, snaplen, promisc, to_ms, err0r);
+ if (!pt) {
+ netutil_error("pcap_open_live(%s, %d, %d, %d) FAILED. Reported error: %s.", pcapdev, snaplen, promisc, to_ms, err0r);
+ return NULL;
+ }
+#else
+ pt = pcap_create(pcapdev, err0r);
+ if (!pt) {
+ netutil_error("pcap_create(%s) FAILED: %s.", pcapdev, err0r);
+ return NULL;
+ }
+
+#define MY_PCAP_SET(func, p_t, val) do {\
+ failed = func(p_t, val);\
+ if (failed) {\
+ netutil_error(#func "(%d) FAILED: %d.", val, failed);\
+ pcap_close(p_t);\
+ return NULL;\
+ }\
+} while(0);
+
+ MY_PCAP_SET(pcap_set_snaplen, pt, snaplen);
+ MY_PCAP_SET(pcap_set_promisc, pt, promisc);
+ MY_PCAP_SET(pcap_set_timeout, pt, to_ms);
+#ifdef HAVE_PCAP_SET_IMMEDIATE_MODE
+ MY_PCAP_SET(pcap_set_immediate_mode, pt, 1);
+#endif
+
+ failed = pcap_activate(pt);
+ if (failed < 0) {
+ // PCAP error
+ netutil_error("pcap_activate(%s) FAILED: %s.", pcapdev, pcap_geterr(pt));
+ pcap_close(pt);
+ return NULL;
+ }
+ else if (failed > 0) {
+ // PCAP warning, report but assume it'll still work
+ netutil_error("pcap_activate(%s) WARNING: %s.", pcapdev, pcap_geterr(pt));
+ }
+#endif /* not __amigaos__ */
+
+#ifdef WIN32
+ /* We want any responses back ASAP */
+ /* This is unnecessary with Npcap since libpcap calls PacketSetMinToCopy(0)
+ * based on immediate mode. Have not determined if it is needed for WinPcap
+ * or not, but it's not hurting anything. */
+ pcap_setmintocopy(pt, 0);
+ /* Npcap sets kernel buffer size to 1MB, but user buffer size to 256KB.
+ * Memory is pretty cheap these days, so lets match the kernel buffer size
+ * for better performance. */
+ pcap_setuserbuffer(pt, 1000000);
+#endif
+
+ return pt;
+}
+
+
+/* Set a pcap filter */
+void set_pcap_filter(const char *device, pcap_t *pd, const char *bpf, ...) {
+ va_list ap;
+ int size;
+ char buf[3072];
+ struct bpf_program fcode;
+
+ va_start(ap, bpf);
+ size = Vsnprintf(buf, sizeof(buf), bpf, ap);
+ va_end(ap);
+ if (size >= (int) sizeof(buf))
+ netutil_fatal("%s called with too-large filter arg\n", __func__);
+
+ if (pcap_compile(pd, &fcode, buf, 1, PCAP_NETMASK_UNKNOWN) < 0)
+ netutil_fatal("Error compiling our pcap filter: %s", pcap_geterr(pd));
+ if (pcap_setfilter(pd, &fcode) < 0)
+ netutil_fatal("Failed to set the pcap filter: %s\n", pcap_geterr(pd));
+ pcap_freecode(&fcode);
+}
+
+
+/* Return the data offset for the given datalink. This function understands the
+ datalink types DLT_EN10MB and DLT_LINUX_SLL. Returns -1 on error. */
+int datalink_offset(int datalink)
+{
+ int offset = -1;
+ /* NOTE: IF A NEW OFFSET EVER EXCEEDS THE CURRENT MAX (24), ADJUST
+ MAX_LINK_HEADERSZ in libnetutil/netutil.h */
+ switch (datalink) {
+ case DLT_EN10MB:
+ offset = ETH_HDR_LEN;
+ break;
+ case DLT_IEEE802:
+ offset = 22;
+ break;
+#ifdef __amigaos__
+ case DLT_MIAMI:
+ offset = 16;
+ break;
+#endif
+#ifdef DLT_LOOP
+ case DLT_LOOP:
+#endif
+ case DLT_NULL:
+ offset = 4;
+ break;
+ case DLT_SLIP:
+#ifdef DLT_SLIP_BSDOS
+ case DLT_SLIP_BSDOS:
+#endif
+#if (FREEBSD || OPENBSD || NETBSD || BSDI || MACOSX)
+ offset = 16;
+#else
+ offset = 24; /* Anyone use this??? */
+#endif
+ break;
+ case DLT_PPP:
+#ifdef DLT_PPP_BSDOS
+ case DLT_PPP_BSDOS:
+#endif
+#ifdef DLT_PPP_SERIAL
+ case DLT_PPP_SERIAL:
+#endif
+#ifdef DLT_PPP_ETHER
+ case DLT_PPP_ETHER:
+#endif
+#if (FREEBSD || OPENBSD || NETBSD || BSDI || MACOSX)
+ offset = 4;
+#else
+#ifdef SOLARIS
+ offset = 8;
+#else
+ offset = 24; /* Anyone use this? */
+#endif /* ifdef solaris */
+#endif /* if freebsd || openbsd || netbsd || bsdi */
+ break;
+ case DLT_RAW:
+ offset = 0;
+ break;
+ case DLT_FDDI:
+ offset = 21;
+ break;
+#ifdef DLT_ENC
+ case DLT_ENC:
+ offset = 12;
+ break;
+#endif /* DLT_ENC */
+#ifdef DLT_LINUX_SLL
+ case DLT_LINUX_SLL:
+ offset = 16;
+ break;
+#endif
+#ifdef DLT_IPNET
+ case DLT_IPNET:
+ offset = 24;
+ break;
+#endif
+ default:
+ offset = -1;
+ break;
+ }
+ return offset;
+}
+
+/* Common subroutine for reading ARP and NS responses. Input parameters are pd,
+ to_usec, and accept_callback. If a received frame passes accept_callback,
+ then the output parameters p, head, rcvdtime, datalink, and offset are filled
+ in, and the function returns 1. If no frame passes before the timeout, then
+ the function returns 0 and the output parameters are undefined. */
+int read_reply_pcap(pcap_t *pd, long to_usec,
+ bool (*accept_callback)(const unsigned char *, const struct pcap_pkthdr *, int, size_t),
+ const unsigned char **p, struct pcap_pkthdr **head, struct timeval *rcvdtime,
+ int *datalink, size_t *offset)
+{
+ static int warning = 0;
+ int timedout = 0;
+ int badcounter = 0;
+ struct timeval tv_start, tv_end;
+ int ioffset;
+
+ if (!pd)
+ netutil_fatal("NULL packet device passed to %s", __func__);
+
+ if (to_usec < 0) {
+ if (!warning) {
+ warning = 1;
+ netutil_error("WARNING: Negative timeout value (%lu) passed to %s() -- using 0", to_usec, __func__);
+ }
+ to_usec = 0;
+ }
+
+ /* New packet capture device, need to recompute offset */
+ if ((*datalink = pcap_datalink(pd)) < 0)
+ netutil_fatal("Cannot obtain datalink information: %s", pcap_geterr(pd));
+ ioffset = datalink_offset(*datalink);
+ if (ioffset < 0)
+ netutil_fatal("datalink_offset failed for type %d (DLT_EN10MB = %d, DLT_LINUX_SLL = %d)", *datalink, DLT_EN10MB, DLT_LINUX_SLL);
+ *offset = (unsigned int) ioffset;
+
+ if (to_usec > 0) {
+ gettimeofday(&tv_start, NULL);
+ }
+
+ do {
+
+ *p = NULL;
+ int pcap_status = 0;
+ /* It may be that protecting this with !pcap_selectable_fd_one_to_one is not
+ necessary, that it is always safe to do a nonblocking read in this way on
+ all platforms. But I have only tested it on Solaris. */
+ if (!pcap_selectable_fd_one_to_one()) {
+ int rc, nonblock;
+
+ nonblock = pcap_getnonblock(pd, NULL);
+ assert(nonblock == 0);
+ rc = pcap_setnonblock(pd, 1, NULL);
+ assert(rc == 0);
+ pcap_status = pcap_next_ex(pd, head, p);
+ rc = pcap_setnonblock(pd, nonblock, NULL);
+ assert(rc == 0);
+ }
+
+ if (pcap_status == PCAP_ERROR) {
+ // TODO: Gracefully end the scan.
+ netutil_fatal("Error from pcap_next_ex: %s\n", pcap_geterr(pd));
+ }
+
+ if (pcap_status == 0 || *p == NULL) {
+ /* Nonblocking pcap_next_ex didn't get anything. */
+ if (pcap_select(pd, to_usec) == 0)
+ timedout = 1;
+ else
+ pcap_status = pcap_next_ex(pd, head, p);
+ }
+
+ if (pcap_status == PCAP_ERROR) {
+ // TODO: Gracefully end the scan.
+ netutil_fatal("Error from pcap_next_ex: %s\n", pcap_geterr(pd));
+ }
+
+ if (pcap_status == 1 && *p != NULL && accept_callback(*p, *head, *datalink, *offset)) {
+ break;
+ } else if (pcap_status == 0 || *p == NULL) {
+ /* Should we timeout? */
+ if (to_usec == 0) {
+ timedout = 1;
+ } else if (to_usec > 0) {
+ gettimeofday(&tv_end, NULL);
+ if (TIMEVAL_SUBTRACT(tv_end, tv_start) >= to_usec) {
+ timedout = 1;
+ }
+ }
+ } else {
+ /* We'll be a bit patient if we're getting actual packets back, but
+ not indefinitely so */
+ if (badcounter++ > 50)
+ timedout = 1;
+ }
+ } while (!timedout);
+
+ if (timedout)
+ return 0;
+
+ if (rcvdtime) {
+ // TODO: come up with a better way to synchronize pcap with gettimeofday.
+ // Npcap and WinPcap both suffer from clock drift relative to gettimeofday().
+ // We hope to fix this with better time sources for Npcap ( http://issues.nmap.org/1407 )
+ // and for Nmap ( http://issues.nmap.org/180 )
+ // For now, we use gettimeofday() for Windows in this case.
+ // Sometimes the time from the pcap header is a
+ // COUPLE SECONDS before the gettimeofday() results :(.
+#if defined(WIN32) || defined(__amigaos__)
+ gettimeofday(&tv_end, NULL);
+ *rcvdtime = tv_end;
+#else
+ rcvdtime->tv_sec = (*head)->ts.tv_sec;
+ rcvdtime->tv_usec = (*head)->ts.tv_usec;
+ assert((*head)->ts.tv_sec);
+#endif
+ }
+
+ return 1;
+}
+
+static bool accept_arp(const unsigned char *p, const struct pcap_pkthdr *head,
+ int datalink, size_t offset)
+{
+ if (head->caplen < offset + 28)
+ return false;
+
+ /* hw type eth (0x0001), prot ip (0x0800),
+ hw size (0x06), prot size (0x04) */
+ if (memcmp(p + offset, "\x00\x01\x08\x00\x06\x04\x00\x02", 8) != 0)
+ return false;
+
+ if (datalink == DLT_EN10MB) {
+ return ntohs(*((u16 *) (p + 12))) == ETH_TYPE_ARP;
+ } else if (datalink == DLT_LINUX_SLL) {
+ return ntohs(*((u16 *) (p + 2))) == ARPHRD_ETHER && /* sll_hatype */
+ ntohs(*((u16 *) (p + 4))) == 6 && /* sll_halen */
+ ntohs(*((u16 *) (p + 14))) == ETH_TYPE_ARP; /* sll_protocol */
+ } else {
+ return false;
+ }
+}
+
+/* Attempts to read one IPv4/Ethernet ARP reply packet from the pcap
+ descriptor pd. If it receives one, fills in sendermac (must pass
+ in 6 bytes), senderIP, and rcvdtime (can be NULL if you don't care)
+ and returns 1. If it times out and reads no arp requests, returns
+ 0. to_usec is the timeout period in microseconds. Use 0 to avoid
+ blocking to the extent possible. Returns -1 or exits if there is
+ an error. The last parameter is a pointer to a callback function
+ that can be used for packet tracing. This is intended to be used
+ by Nmap only. Any other calling this should pass NULL instead. */
+int read_arp_reply_pcap(pcap_t *pd, u8 *sendermac,
+ struct in_addr *senderIP, long to_usec,
+ struct timeval *rcvdtime,
+ void (*trace_callback)(int, const u8 *, u32, struct timeval *)) {
+ const unsigned char *p;
+ struct pcap_pkthdr *head;
+ int datalink;
+ size_t offset;
+ int rc;
+
+ rc = read_reply_pcap(pd, to_usec, accept_arp, &p, &head, rcvdtime, &datalink, &offset);
+ if (rc == 0)
+ return 0;
+
+ memcpy(sendermac, p + offset + 8, 6);
+ /* I think alignment should allow this ... */
+ memcpy(&senderIP->s_addr, p + offset + 14, 4);
+
+ if (trace_callback != NULL) {
+ /* TODO: First parameter "2" is a hardcoded value for Nmap's PacketTrace::RECV. */
+ trace_callback(2, (u8 *) p + offset, ARP_HDR_LEN + ARP_ETHIP_LEN, rcvdtime);
+ }
+
+ return 1;
+}
+
+static bool accept_ns(const unsigned char *p, const struct pcap_pkthdr *head,
+ int datalink, size_t offset)
+{
+ struct icmpv6_hdr *icmp6_header;
+
+ if (head->caplen < offset + IP6_HDR_LEN + ICMPV6_HDR_LEN)
+ return false;
+
+ icmp6_header = (struct icmpv6_hdr *)(p + offset + IP6_HDR_LEN);
+ return icmp6_header->icmpv6_type == ICMPV6_NEIGHBOR_ADVERTISEMENT &&
+ icmp6_header->icmpv6_code == 0;
+}
+
+/* Attempts to read one IPv6/Ethernet Neighbor Solicitation reply packet from the pcap
+ descriptor pd. If it receives one, fills in sendermac (must pass
+ in 6 bytes), senderIP, and rcvdtime (can be NULL if you don't care)
+ and returns 1. If it times out and reads no Neighbor Advertisement, returns
+ 0. to_usec is the timeout period in microseconds. Use 0 to avoid
+ blocking to the extent possible. Returns -1 or exits if there is
+ an error. The last parameter is a pointer to a callback function
+ that can be used for packet tracing. This is intended to be used
+ by Nmap only. Any other calling this should pass NULL instead. */
+int read_ns_reply_pcap(pcap_t *pd, u8 *sendermac,
+ struct sockaddr_in6 *senderIP, long to_usec,
+ struct timeval *rcvdtime, bool *has_mac,
+ void (*trace_callback)(int, const u8 *, u32, struct timeval *)) {
+ const unsigned char *p;
+ struct pcap_pkthdr *head;
+ int datalink;
+ size_t offset;
+ int rc;
+ struct icmpv6_msg_nd *na;
+
+ rc = read_reply_pcap(pd, to_usec, accept_ns, &p, &head, rcvdtime, &datalink, &offset);
+ if (rc == 0)
+ return 0;
+
+ na = (struct icmpv6_msg_nd *)(p + offset + IP6_HDR_LEN + ICMPV6_HDR_LEN);
+ if (head->caplen >= ((unsigned char *)na - p) + sizeof(struct icmpv6_msg_nd) &&
+ na->icmpv6_option_type == 2 &&
+ na->icmpv6_option_length == 1) {
+ *has_mac = true;
+ memcpy(sendermac, &na->icmpv6_mac, 6);
+ }
+ else {
+ *has_mac = false;
+ }
+ senderIP->sin6_family = AF_INET6;
+ memcpy(&senderIP->sin6_addr.s6_addr, &na->icmpv6_target, 16);
+
+ if (trace_callback != NULL) {
+ /* TODO: First parameter "2" is a hardcoded value for Nmap's PacketTrace::RECV. */
+ trace_callback(2, (u8 *) p + offset, IP6_HDR_LEN + ICMPV6_HDR_LEN + 4 + 16 + 8, rcvdtime);
+ }
+
+ return 1;
+}
+
+
+/* Issues an Neighbor Solicitation for the MAC of targetss (which will be placed
+ in targetmac if obtained) from the source IP (srcip) and source mac
+ (srcmac) given. "The request is ussued using device dev to the
+ multicast MAC address. The transmission is attempted up to 3
+ times. If none of these elicit a response, false will be returned.
+ If the mac is determined, true is returned. The last parameter is
+ a pointer to a callback function that can be used for packet tracing.
+ This is intended to be used by Nmap only. Any other calling this
+ should pass NULL instead. */
+bool doND(const char *dev, const u8 *srcmac,
+ const struct sockaddr_storage *srcip,
+ const struct sockaddr_storage *targetip,
+ u8 *targetmac,
+ void (*traceND_callback)(int, const u8 *, u32 , struct timeval *)
+ ) {
+ /* timeouts in microseconds ... the first ones are retransmit times, while
+ the final one is when we give up */
+ int timeouts[] = { 100000, 400000, 800000 };
+ int max_sends = 3;
+ int num_sends = 0; // How many we have sent so far
+ eth_t *ethsd;
+ u8 frame[ETH_HDR_LEN + IP6_HDR_LEN + ICMPV6_HDR_LEN + 4 + 16 + 8];
+ struct timeval start, now, rcvdtime;
+ int timeleft;
+ int listenrounds;
+ int rc;
+ bool has_mac;
+ pcap_t *pd;
+ struct sockaddr_storage rcvdIP;
+ rcvdIP.ss_family = AF_INET6;
+ bool foundit = false;
+ char filterstr[256];
+ struct sockaddr_in6 *target_sin6, *src_sin6;
+ struct sockaddr_in6 ns_dst_ip6;
+
+ if (targetip->ss_family != AF_INET6 || srcip->ss_family != AF_INET6)
+ netutil_fatal("%s can only handle IPv6 addresses", __func__);
+
+ target_sin6 = (struct sockaddr_in6 *) targetip;
+ src_sin6 = (struct sockaddr_in6 *) srcip;
+
+ unsigned char ns_dst_mac[6] = {0x33, 0x33, 0xff};
+ ns_dst_mac[3] = target_sin6->sin6_addr.s6_addr[13];
+ ns_dst_mac[4] = target_sin6->sin6_addr.s6_addr[14];
+ ns_dst_mac[5] = target_sin6->sin6_addr.s6_addr[15];
+
+ ns_dst_ip6 = *target_sin6;
+ unsigned char multicast_prefix[13] = {0};
+ multicast_prefix[0] = 0xff;
+ multicast_prefix[1] = 0x02;
+ multicast_prefix[11] = 0x1;
+ multicast_prefix[12] = 0xff;
+ memcpy(ns_dst_ip6.sin6_addr.s6_addr, multicast_prefix, sizeof(multicast_prefix));
+
+ /* Start listening */
+ if((pd=my_pcap_open_live(dev, 100, 1, 25))==NULL)
+ netutil_fatal("my_pcap_open_live(%s, 50, 1, 25) failed three times.", dev);
+ /* Libpcap: IPv6 upper-layer protocol is not supported by proto[x] */
+ /* Grab the ICMPv6 type using ip6[X:Y] syntax. This works only if there are no
+ extension headers (top-level nh is IPPROTO_ICMPV6). */
+ Snprintf(filterstr, 256, "ether dst %02X%02X%02X%02X%02X%02X and icmp6 and ip6[6:1] = %u and ip6[40:1] = %u",
+ srcmac[0], srcmac[1], srcmac[2], srcmac[3], srcmac[4], srcmac[5],
+ IPPROTO_ICMPV6, ICMPV6_NEIGHBOR_ADVERTISEMENT);
+ set_pcap_filter(dev, pd, filterstr);
+
+ /* Prepare probe and sending stuff */
+ ethsd = eth_open_cached(dev);
+ if (!ethsd)
+ netutil_fatal("%s: failed to open device %s", __func__, dev);
+ eth_pack_hdr(frame, *ns_dst_mac, *srcmac, ETH_TYPE_IPV6);
+ ip6_pack_hdr(frame + ETH_HDR_LEN, 0, 0, 32, 0x3a, 255, *src_sin6->sin6_addr.s6_addr, *ns_dst_ip6.sin6_addr.s6_addr);
+ icmpv6_pack_hdr_ns_mac(frame + ETH_HDR_LEN + IP6_HDR_LEN, target_sin6->sin6_addr.s6_addr, *srcmac);
+ ip6_checksum(frame + ETH_HDR_LEN, IP6_HDR_LEN + ICMPV6_HDR_LEN + 4 + 16 + 8);
+
+ gettimeofday(&start, NULL);
+ gettimeofday(&now, NULL);
+
+ while (!foundit && num_sends < max_sends) {
+ /* Send the sucker */
+ rc = eth_send(ethsd, frame, sizeof(frame));
+ if (rc != sizeof(frame)) {
+ netutil_error("WARNING: %s: eth_send of Neighbor Solicitation packet returned %u rather than expected %d bytes", __func__, rc, (int) sizeof(frame));
+ }
+ if(traceND_callback!=NULL){
+ /* TODO: First parameter "1" is a hardcoded value for Nmap's PacketTrace::SENT*/
+ traceND_callback(1, (u8 *) frame + ETH_HDR_LEN, IP6_HDR_LEN + ICMPV6_HDR_LEN + 4 + 16 + 8, &now);
+ }
+ num_sends++;
+
+ listenrounds = 0;
+ while (!foundit) {
+ gettimeofday(&now, NULL);
+ timeleft = timeouts[num_sends - 1] - TIMEVAL_SUBTRACT(now, start);
+ if (timeleft < 0) {
+ if (listenrounds > 0)
+ break;
+ else
+ timeleft = 25000;
+ }
+ listenrounds++;
+ /* Now listen until we reach our next timeout or get an answer */
+ rc = read_ns_reply_pcap(pd, targetmac, (struct sockaddr_in6 *) &rcvdIP, timeleft,
+ &rcvdtime, &has_mac, traceND_callback);
+ if (rc == -1)
+ netutil_fatal("%s: Received -1 response from read_ns_reply_pcap", __func__);
+ if (rc == 1) {
+ /* Yay, I got one! But is it the right one? */
+ if (sockaddr_storage_cmp(&rcvdIP,targetip) != 0)
+ continue; /* D'oh! */
+ foundit = true; /* WOOHOO! */
+ }
+ }
+ }
+
+ /* OK - let's close up shop ... */
+ pcap_close(pd);
+ /* No need to close ethsd due to caching */
+ return foundit;
+}
+
+/* Issues an ARP request for the MAC of targetss (which will be placed
+ in targetmac if obtained) from the source IP (srcip) and source mac
+ (srcmac) given. "The request is ussued using device dev to the
+ broadcast MAC address. The transmission is attempted up to 3
+ times. If none of these elicit a response, false will be returned.
+ If the mac is determined, true is returned. The last parameter is
+ a pointer to a callback function that can be used for packet tracing.
+ This is intended to be used by Nmap only. Any other calling this
+ should pass NULL instead. */
+bool doArp(const char *dev, const u8 *srcmac,
+ const struct sockaddr_storage *srcip,
+ const struct sockaddr_storage *targetip,
+ u8 *targetmac,
+ void (*traceArp_callback)(int, const u8 *, u32 , struct timeval *)
+ ) {
+ /* timeouts in microseconds ... the first ones are retransmit times, while
+ the final one is when we give up */
+ int timeouts[] = { 100000, 400000, 800000 };
+ int max_sends = 3;
+ int num_sends = 0; // How many we have sent so far
+ eth_t *ethsd;
+ u8 frame[ETH_HDR_LEN + ARP_HDR_LEN + ARP_ETHIP_LEN];
+ const struct sockaddr_in *targetsin = (struct sockaddr_in *) targetip;
+ const struct sockaddr_in *srcsin = (struct sockaddr_in *) srcip;
+ struct timeval start, now, rcvdtime;
+ int timeleft;
+ int listenrounds;
+ int rc;
+ pcap_t *pd;
+ struct in_addr rcvdIP;
+ bool foundit = false;
+ char filterstr[256];
+
+ if (targetsin->sin_family != AF_INET || srcsin->sin_family != AF_INET)
+ netutil_fatal("%s can only handle IPv4 addresses", __func__);
+
+ /* Start listening */
+ if((pd=my_pcap_open_live(dev, 50, 1, 25))==NULL)
+ netutil_fatal("my_pcap_open_live(%s, 50, 1, 25) failed three times.", dev);
+ Snprintf(filterstr, 256, "arp and arp[18:4] = 0x%02X%02X%02X%02X and arp[22:2] = 0x%02X%02X",
+ srcmac[0], srcmac[1], srcmac[2], srcmac[3], srcmac[4], srcmac[5]);
+ set_pcap_filter(dev, pd, filterstr);
+
+ /* Prepare probe and sending stuff */
+ ethsd = eth_open_cached(dev);
+ if (!ethsd)
+ netutil_fatal("%s: failed to open device %s", __func__, dev);
+ eth_pack_hdr(frame, ETH_ADDR_BROADCAST, *srcmac, ETH_TYPE_ARP);
+ arp_pack_hdr_ethip(frame + ETH_HDR_LEN, ARP_OP_REQUEST, *srcmac,
+ srcsin->sin_addr, ETH_ADDR_BROADCAST,
+ targetsin->sin_addr);
+ gettimeofday(&start, NULL);
+ gettimeofday(&now, NULL);
+
+ while (!foundit && num_sends < max_sends) {
+ /* Send the sucker */
+ rc = eth_send(ethsd, frame, sizeof(frame));
+ if (rc != sizeof(frame)) {
+ netutil_error("WARNING: %s: eth_send of ARP packet returned %u rather than expected %d bytes", __func__, rc, (int) sizeof(frame));
+ }
+ if(traceArp_callback!=NULL){
+ /* TODO: First parameter "1" is a hardcoded value for Nmap's PacketTrace::SENT*/
+ traceArp_callback(1, (u8 *) frame + ETH_HDR_LEN, ARP_HDR_LEN + ARP_ETHIP_LEN, &now);
+ }
+ num_sends++;
+
+ listenrounds = 0;
+ while (!foundit) {
+ gettimeofday(&now, NULL);
+ timeleft = timeouts[num_sends - 1] - TIMEVAL_SUBTRACT(now, start);
+ if (timeleft < 0) {
+ if (listenrounds > 0)
+ break;
+ else
+ timeleft = 25000;
+ }
+ listenrounds++;
+ /* Now listen until we reach our next timeout or get an answer */
+ rc = read_arp_reply_pcap(pd, targetmac, &rcvdIP, timeleft,
+ &rcvdtime, traceArp_callback);
+ if (rc == -1)
+ netutil_fatal("%s: Received -1 response from readarp_reply_pcap", __func__);
+ if (rc == 1) {
+ /* Yay, I got one! But is it the right one? */
+ if (rcvdIP.s_addr != targetsin->sin_addr.s_addr)
+ continue; /* D'oh! */
+ foundit = true; /* WOOHOO! */
+ }
+ }
+ }
+
+ /* OK - let's close up shop ... */
+ pcap_close(pd);
+ /* No need to close ethsd due to caching */
+ return foundit;
+}
+
+
+
+static inline bool is_host_separator(int c) {
+ return c == ' ' || c == '\r' || c == '\n' || c == '\t' || c == '\0';
+}
+
+/* Read a single host specification from a file, as for -iL and --excludefile.
+ It returns the length of the string read; an overflow is indicated when the
+ return value is >= n. Returns 0 if there was no specification to be read. The
+ buffer is always null-terminated. */
+size_t read_host_from_file(FILE *fp, char *buf, size_t n)
+{
+ int ch;
+ size_t i;
+
+ i = 0;
+ ch = getc(fp);
+ while (is_host_separator(ch) || ch == '#') {
+ if (ch == '#') {
+ /* Skip comments to the end of the line. */
+ while ((ch = getc(fp)) != EOF && ch != '\n')
+ ;
+ } else {
+ ch = getc(fp);
+ }
+ }
+ while (ch != EOF && !(is_host_separator(ch) || ch == '#')) {
+ if (i < n)
+ buf[i] = ch;
+ i++;
+ ch = getc(fp);
+ }
+ if (ch != EOF)
+ ungetc(ch, fp);
+ if (i < n)
+ buf[i] = '\0';
+ else if (n > 0)
+ /* Null-terminate even though it was too long. */
+ buf[n - 1] = '\0';
+
+ return i;
+}
+
+
+/* Return next target host specification from the supplied stream.
+ * if parameter "random" is set to true, then the function will
+ * return a random, non-reserved, IP address in decimal-dot notation */
+const char *grab_next_host_spec(FILE *inputfd, bool random, int argc, const char **argv) {
+ static char host_spec[1024];
+ struct in_addr ip;
+ size_t n;
+
+ if (random) {
+ do {
+ ip.s_addr = get_random_unique_u32();
+ } while (ip_is_reserved(&ip));
+ Strncpy(host_spec, inet_ntoa(ip), sizeof(host_spec));
+ } else if (!inputfd) {
+ return( (optind < argc)? argv[optind++] : NULL);
+ } else {
+ n = read_host_from_file(inputfd, host_spec, sizeof(host_spec));
+ if (n == 0)
+ return NULL;
+ else if (n >= sizeof(host_spec))
+ netutil_fatal("One of the host specifications from your input file is too long (>= %u chars)", (unsigned int) sizeof(host_spec));
+ }
+ return host_spec;
+}
+
+
+
+/** Tries to increase the open file descriptor limit for this process.
+ * @param "desired" is the number of desired max open descriptors. Pass a
+ * negative value to set the maximum allowed.
+ * @return the number of max open descriptors that could be set, or 0 in case
+ * of failure.
+ * @warning if "desired" is less than the current limit, no action is
+ * performed. This function may only be used to increase the limit, not to
+ * decrease it. */
+int set_max_open_descriptors(int desired_max) {
+ #ifndef WIN32
+ struct rlimit r;
+ int maxfds=-1;
+ int flag=0;
+
+ #if (defined(RLIMIT_OFILE) || defined(RLIMIT_NOFILE))
+
+ #ifdef RLIMIT_NOFILE
+ flag=RLIMIT_NOFILE; /* Linux */
+ #else
+ flag=RLIMIT_OFILE; /* BSD */
+ #endif
+
+ if (!getrlimit(flag, &r)) {
+ /* If current limit is less than the desired, try to increase it */
+ if(r.rlim_cur < (rlim_t)desired_max){
+ if(desired_max<0){
+ r.rlim_cur=r.rlim_max; /* Set maximum */
+ }else{
+ r.rlim_cur = MIN( (int)r.rlim_max, desired_max );
+ }
+ if (setrlimit(flag, &r))
+ ; // netutil_debug("setrlimit(%d, %p) failed", flag, r);
+ if (!getrlimit(flag, &r)) {
+ maxfds = r.rlim_cur;
+ return maxfds;
+ }else {
+ return 0;
+ }
+ }
+ }
+
+ #endif /* (defined(RLIMIT_OFILE) || defined(RLIMIT_NOFILE)) */
+ #endif /* !WIN32 */
+ return 0;
+}
+
+
+/** Returns the open file descriptor limit for this process.
+ * @return the number of max open descriptors or 0 in case of failure. */
+int get_max_open_descriptors() {
+ #ifndef WIN32
+ struct rlimit r;
+ int flag=0;
+
+ #if (defined(RLIMIT_OFILE) || defined(RLIMIT_NOFILE))
+
+ #ifdef RLIMIT_NOFILE
+ flag=RLIMIT_NOFILE; /* Linux */
+ #else
+ flag=RLIMIT_OFILE; /* BSD */
+ #endif
+
+ if (!getrlimit(flag, &r)) {
+ return (int)r.rlim_cur;
+ }
+
+ #endif /* (defined(RLIMIT_OFILE) || defined(RLIMIT_NOFILE)) */
+ #endif /* !WIN32 */
+ return 0;
+}
+
+
+/* Maximize the open file descriptor limit for this process go up to the
+ max allowed */
+int max_sd() {
+ return set_max_open_descriptors(-1);
+}
diff --git a/libnetutil/netutil.h b/libnetutil/netutil.h
new file mode 100644
index 0000000..f88241b
--- /dev/null
+++ b/libnetutil/netutil.h
@@ -0,0 +1,565 @@
+/***************************************************************************
+ * netutil.h -- The main include file exposing the external API for *
+ * libnetutil, a library that provides network-related functions or *
+ * classes that make it easier to handle things like network interfaces, *
+ * routing tables, raw packet manipulation, etc. The lib was originally *
+ * written for use in the Nmap Security Scanner ( https://nmap.org ). *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+
+/* $Id: netutil.h 18098 2010-06-14 11:50:12Z luis $ */
+
+#ifndef _NETUTIL_H_
+#define _NETUTIL_H_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <pcap.h>
+#ifdef __cplusplus
+}
+#endif
+
+#include "dnet.h"
+#include <nbase.h>
+
+/* It is VERY important to never change the value of these two constants.
+ * Specially, OP_FAILURE should never be positive, as some pieces of code take
+ * that for granted. */
+enum { OP_FAILURE = -1, OP_SUCCESS = 0 };
+
+
+/* For systems without SCTP in netinet/in.h, such as MacOS X or Win */
+#ifndef IPPROTO_SCTP
+#define IPPROTO_SCTP 132
+#endif
+
+/* Container used for information common to IPv4 and IPv6 headers, used by
+ ip_get_data. */
+struct abstract_ip_hdr {
+ u8 version; /* 4 or 6. */
+ struct sockaddr_storage src;
+ struct sockaddr_storage dst;
+ u8 proto; /* IPv4 proto or IPv6 next header. */
+ u8 ttl; /* IPv4 TTL or IPv6 hop limit. */
+ u32 ipid; /* IPv4 IP ID or IPv6 flow label. */
+};
+
+#if defined(__GNUC__)
+#define NORETURN __attribute__((noreturn))
+#elif defined(_MSC_VER)
+#define NORETURN __declspec(noreturn)
+#else
+#define NORETURN
+#endif
+
+NORETURN void netutil_fatal(const char *str, ...)
+ __attribute__ ((format (printf, 1, 2)));
+
+int netutil_error(const char *str, ...)
+ __attribute__ ((format (printf, 1, 2)));
+
+/* This function converts zero-terminated 'txt' string to binary 'data'.
+ It is used to parse user input for ip options. Some examples of possible input
+ strings and results:
+ '\x01*2\xA2' -> [0x01,0x01,0xA2] // with 'x' number is parsed in hex
+ '\01\01\255' -> [0x01,0x01,0xFF] // without 'x' its in decimal
+ '\x01\x00*2' -> [0x01,0x00,0x00] // '*' is copying char
+ 'R' -> Record Route with 9 slots
+ 'S 192.168.0.1 172.16.0.1' -> Strict Route with 2 slots
+ 'L 192.168.0.1 172.16.0.1' -> Loose Route with 2 slots
+ 'T' -> Record Timestamp with 9 slots
+ 'U' -> Record Timestamp and Ip Address with 4 slots
+ On success, the function returns the length of the final binary
+ options stored in "data". In case of error, OP_FAILURE is returned
+ and the "errstr" buffer is filled with an error message
+ (unless it's NULL). Note that the returned error message does NOT
+ contain a newline character at the end. */
+int parse_ip_options(const char *txt, u8 *data, int datalen, int* firsthopoff, int* lasthopoff, char *errstr, size_t errstrlen);
+
+/* Resolves the given hostname or IP address with getaddrinfo, and stores the
+ first result (if any) in *ss and *sslen. The value of port will be set in the
+ appropriate place in *ss; set to 0 if you don't care. af may be AF_UNSPEC, in
+ which case getaddrinfo may return e.g. both IPv4 and IPv6 results; which one
+ is first depends on the system configuration. Returns 0 on success, or a
+ getaddrinfo return code (suitable for passing to gai_strerror) on failure.
+ *ss and *sslen are always defined when this function returns 0. */
+int resolve(const char *hostname, unsigned short port,
+ struct sockaddr_storage *ss, size_t *sslen, int af);
+
+/* As resolve, but do not do DNS resolution of hostnames; the first argument
+ must be the string representation of a numeric IP address. */
+int resolve_numeric(const char *ip, unsigned short port,
+ struct sockaddr_storage *ss, size_t *sslen, int af);
+
+/*
+ * Returns 1 if this is a reserved IP address, where "reserved" means
+ * either a private address, non-routable address, or even a non-reserved
+ * but unassigned address which has an extremely high probability of being
+ * black-holed.
+ *
+ * We try to optimize speed when ordering the tests. This optimization
+ * assumes that all byte values are equally likely in the input.
+ *
+ * Warning: This function needs frequent attention because IANA has been
+ * allocating address blocks many times per year (although it's questionable
+ * how much longer this trend can be kept up).
+ *
+ * Check
+ * <http://www.iana.org/assignments/ipv4-address-space/ipv4-address-space.txt>
+ * for the most recent assigments and
+ * <http://www.cymru.com/Documents/bogon-bn-nonagg.txt> for bogon
+ * netblocks.
+ */
+int ip_is_reserved(struct in_addr *ip);
+
+
+/* A couple of trivial functions that maintain a cache of IP to MAC
+ * Address entries. Function mac_cache_get() looks for the IPv4 address
+ * in ss and fills in the 'mac' parameter and returns true if it is
+ * found. Otherwise (not found), the function returns false.
+ * Function mac_cache_set() adds an entry with the given ip (ss) and
+ * mac address. An existing entry for the IP ss will be overwritten
+ * with the new MAC address. mac_cache_set() always returns true. */
+int mac_cache_get(const struct sockaddr_storage *ss, u8 *mac);
+int mac_cache_set(const struct sockaddr_storage *ss, u8 *mac);
+
+const void *ip_get_data(const void *packet, unsigned int *len,
+ struct abstract_ip_hdr *hdr);
+const void *ip_get_data_any(const void *packet, unsigned int *len,
+ struct abstract_ip_hdr *hdr);
+/* Get the upper-layer protocol from an IPv4 packet. */
+const void *ipv4_get_data(const struct ip *ip, unsigned int *len);
+/* Get the upper-layer protocol from an IPv6 packet. This skips over known
+ extension headers. The length of the upper-layer payload is stored in *len.
+ The protocol is stored in *nxt. Returns NULL in case of error. */
+const void *ipv6_get_data(const struct ip6_hdr *ip6, unsigned int *len, u8 *nxt);
+const void *ipv6_get_data_any(const struct ip6_hdr *ip6, unsigned int *len, u8 *nxt);
+const void *icmp_get_data(const struct icmp_hdr *icmp, unsigned int *len);
+const void *icmpv6_get_data(const struct icmpv6_hdr *icmpv6, unsigned int *len);
+
+/* Standard BSD internet checksum routine. */
+unsigned short in_cksum(u16 *ptr, int nbytes);
+
+/* Calculate the Internet checksum of some given data concatentated with the
+ IPv4 pseudo-header. See RFC 1071 and TCP/IP Illustrated sections 3.2, 11.3,
+ and 17.3. */
+unsigned short ipv4_pseudoheader_cksum(const struct in_addr *src,
+ const struct in_addr *dst, u8 proto, u16 len, const void *hstart);
+
+/* Calculate the Internet checksum of some given data concatenated with the
+ IPv6 pseudo-header. See RFC 2460 section 8.1. */
+u16 ipv6_pseudoheader_cksum(const struct in6_addr *src,
+ const struct in6_addr *dst, u8 nxt, u32 len, const void *hstart);
+
+void sethdrinclude(int sd);
+void set_ipoptions(int sd, void *opts, size_t optslen);
+void set_ttl(int sd, int ttl);
+
+/* Returns whether the system supports pcap_get_selectable_fd() properly */
+int pcap_selectable_fd_valid();
+int pcap_selectable_fd_one_to_one();
+
+/* Call this instead of pcap_get_selectable_fd directly (or your code
+ won't compile on Windows). On systems which don't seem to support
+ the pcap_get_selectable_fd() function properly, returns -1,
+ otherwise simply calls pcap_selectable_fd and returns the
+ results. If you just want to test whether the function is supported,
+ use pcap_selectable_fd_valid() instead. */
+int my_pcap_get_selectable_fd(pcap_t *p);
+
+
+/* These two function return -1 if we can't use select() on the pcap
+ * device, 0 for timeout, and >0 for success. If select() fails we bail
+ * out because it couldn't work with the file descriptor we got from
+ * my_pcap_get_selectable_fd() */
+int pcap_select(pcap_t *p, struct timeval *timeout);
+int pcap_select(pcap_t *p, long usecs);
+
+typedef enum { devt_ethernet, devt_loopback, devt_p2p, devt_other } devtype;
+
+#define MAX_LINK_HEADERSZ 24
+struct link_header {
+ int datalinktype; /* pcap_datalink(), such as DLT_EN10MB */
+ int headerlen; /* 0 if header was too big or unavailaable */
+ u8 header[MAX_LINK_HEADERSZ];
+};
+
+/* Relevant (to Nmap) information about an interface */
+struct interface_info {
+ char devname[16];
+ char devfullname[16]; /* can include alias info, such as eth0:2. */
+ struct sockaddr_storage addr;
+ u16 netmask_bits; /* CIDR-style. So 24 means class C (255.255.255.0)*/
+ devtype device_type; /* devt_ethernet, devt_loopback, devt_p2p, devt_other */
+ unsigned int ifindex; /* index (as used by if_indextoname and sin6_scope_id) */
+ int device_up; /* True if the device is up (enabled) */
+ int mtu; /* Interface's MTU size */
+ u8 mac[6]; /* Interface MAC address if device_type is devt_ethernet */
+};
+
+struct route_nfo {
+ struct interface_info ii;
+
+/* true if the target is directly connected on the network (no routing
+ required). */
+ int direct_connect;
+
+/* This is the source address that should be used by the packets. It
+ may be different than ii.addr if you are using localhost interface
+ to scan the IP of another interface on the machine */
+ struct sockaddr_storage srcaddr;
+
+ /* If direct_connect is 0, this is filled in with the next hop
+ required to route to the target */
+ struct sockaddr_storage nexthop;
+};
+
+struct sys_route {
+ struct interface_info *device;
+ struct sockaddr_storage dest;
+ u16 netmask_bits;
+ struct sockaddr_storage gw; /* gateway - 0 if none */
+ int metric;
+};
+
+struct eth_nfo {
+ char srcmac[6];
+ char dstmac[6];
+ eth_t *ethsd; // Optional, but improves performance. Set to NULL if unavail
+ char devname[16]; // Only needed if ethsd is NULL.
+};
+
+/* A simple function that caches the eth_t from dnet for one device,
+ to avoid opening, closing, and re-opening it thousands of tims. If
+ you give a different device, this function will close the first
+ one. Thus this should never be used by programs that need to deal
+ with multiple devices at once. In addition, you MUST NEVER
+ eth_close() A DEVICE OBTAINED FROM THIS FUNCTION. Instead, you can
+ call eth_close_cached() to close whichever device (if any) is
+ cached. Returns NULL if it fails to open the device. */
+eth_t *eth_open_cached(const char *device);
+
+/* See the description for eth_open_cached */
+void eth_close_cached();
+
+/* Takes a protocol number like IPPROTO_TCP, IPPROTO_UDP, or
+ * IPPROTO_IP and returns a ascii representation (or "unknown" if it
+ * doesn't recognize the number). Returned string is in lowercase. */
+const char *proto2ascii_lowercase(u8 proto) ;
+
+/* Same as proto2ascii() but returns a string in uppercase. */
+const char *proto2ascii_uppercase(u8 proto);
+
+/* Get an ASCII information about a tcp option which is pointed by
+ optp, with a length of len. The result is stored in the result
+ buffer. The result may look like "<mss 1452,sackOK,timestamp
+ 45848914 0,nop,wscale 7>" */
+void tcppacketoptinfo(u8 *optp, int len, char *result, int bufsize);
+
+/* Convert an IP address to the device (IE ppp0 eth0) using that
+ * address. Supplied "dev" must be able to hold at least 32 bytes.
+ * Returns 0 on success or -1 in case of error. */
+int ipaddr2devname( char *dev, const struct sockaddr_storage *addr );
+
+/* Convert a network interface name (IE ppp0 eth0) to an IP address.
+ * Returns 0 on success or -1 in case of error. */
+int devname2ipaddr(char *dev, struct sockaddr_storage *addr);
+
+int sockaddr_equal(const struct sockaddr_storage *a,
+ const struct sockaddr_storage *b);
+
+int sockaddr_equal_netmask(const struct sockaddr_storage *a,
+ const struct sockaddr_storage *b, u16 nbits);
+
+int sockaddr_equal_zero(const struct sockaddr_storage *s);
+
+/* Returns an allocated array of struct interface_info representing the
+ available interfaces. The number of interfaces is returned in *howmany. This
+ function just does caching of results; the real work is done in
+ getinterfaces_dnet() or getinterfaces_siocgifconf().
+ On error, NULL is returned, howmany is set to -1 and the supplied
+ error buffer "errstr", if not NULL, will contain an error message. */
+struct interface_info *getinterfaces(int *howmany, char *errstr, size_t errstrlen);
+/* Frees the array of cached struct interface_info used by getinterfaces. Can
+ be used to force a refresh or to release memory. */
+void freeinterfaces(void);
+
+/* This struct is abused to carry either routes or interfaces, depending on the
+ function it's used in. */
+struct dnet_collector_route_nfo {
+ struct sys_route *routes;
+ int numroutes;
+ int capacity; /* Capacity of routes or ifaces, depending on context */
+ struct interface_info *ifaces;
+ int numifaces;
+};
+
+/* Looks for an interface with the given name (iname) and address
+ family type, and returns the corresponding interface_info if found.
+ Will accept a match of devname or devfullname. Returns NULL if
+ none found */
+struct interface_info *getInterfaceByName(const char *iname, int af);
+
+/* Parse the system routing table, converting each route into a
+ sys_route entry. Returns an array of sys_routes. numroutes is set
+ to the number of routes in the array. The routing table is only
+ read the first time this is called -- later results are cached.
+ The returned route array is sorted by netmask with the most
+ specific matches first.
+ On error, NULL is returned, howmany is set to -1 and the supplied
+ error buffer "errstr", if not NULL, will contain an error message. */
+struct sys_route *getsysroutes(int *howmany, char *errstr, size_t errstrlen);
+
+/* Tries to determine whether the supplied address corresponds to
+ * localhost. (eg: the address is something like 127.x.x.x, the address
+ * matches one of the local network interfaces' address, etc).
+ * Returns 1 if the address is thought to be localhost and 0 otherwise */
+int islocalhost(const struct sockaddr_storage *ss);
+
+/* Determines whether the supplied address corresponds to a private,
+ * non-Internet-routable address. See RFC1918 for details.
+ * Also checks for link-local addresses per RFC3927.
+ * Returns 1 if the address is private or 0 otherwise. */
+int isipprivate(const struct sockaddr_storage *addr);
+
+/* Takes binary data found in the IP Options field of an IPv4 packet
+ * and returns a string containing an ASCII description of the options
+ * found. The function returns a pointer to a static buffer that
+ * subsequent calls will overwrite. On error, NULL is returned. */
+char *format_ip_options(const u8* ipopt, int ipoptlen);
+
+/* Returns a buffer of ASCII information about an IP packet that may
+ * look like "TCP 127.0.0.1:50923 > 127.0.0.1:3 S ttl=61 id=39516
+ * iplen=40 seq=625950769" or "ICMP PING (0/1) ttl=61 id=39516 iplen=40".
+ * Returned buffer is static so it is NOT safe to call this in
+ * multi-threaded environments without appropriate sync protection, or
+ * call it twice in the same sentence (eg: as two printf parameters).
+ * Obviously, the caller should never attempt to free() the buffer. The
+ * returned buffer is guaranteed to be NULL-terminated but no
+ * assumptions should be made concerning its length.
+ *
+ * The function provides full support for IPv4,TCP,UDP,SCTP and ICMPv4.
+ * It also provides support for standard IPv6 but not for its extension
+ * headers. If an IPv6 packet contains an ICMPv6 Header, the output will
+ * reflect this but no parsing of ICMPv6 contents will be performed.
+ *
+ * The output has three different levels of detail. Parameter "detail"
+ * determines how verbose the output should be. It should take one of
+ * the following values:
+ *
+ * LOW_DETAIL (0x01): Traditional output.
+ * MEDIUM_DETAIL (0x02): More verbose than traditional.
+ * HIGH_DETAIL (0x03): Contents of virtually every field of the
+ * protocol headers .
+ */
+#define LOW_DETAIL 1
+#define MEDIUM_DETAIL 2
+#define HIGH_DETAIL 3
+const char *ippackethdrinfo(const u8 *packet, u32 len, int detail);
+
+
+/* Takes an IPv4 destination address (dst) and tries to determine the
+ * source address and interface necessary to route to this address.
+ * If no route is found, 0 is returned and "rnfo" is undefined. If
+ * a route is found, 1 is returned and "rnfo" is filled in with all
+ * of the routing details. If the source address needs to be spoofed,
+ * it should be passed through "spoofss" (otherwise NULL should be
+ * specified), along with a suitable network device (parameter "device").
+ * Even if spoofss is NULL, if user specified a network device with -e,
+ * it should still be passed. Note that it's OK to pass either NULL or
+ * an empty string as the "device", as long as spoofss==NULL. */
+int route_dst(const struct sockaddr_storage *dst, struct route_nfo *rnfo,
+ const char *device, const struct sockaddr_storage *spoofss);
+
+/* Send an IP packet over a raw socket. */
+int send_ip_packet_sd(int sd, const struct sockaddr_in *dst, const u8 *packet, unsigned int packetlen);
+
+/* Send an IP packet over an ethernet handle. */
+int send_ip_packet_eth(const struct eth_nfo *eth, const u8 *packet, unsigned int packetlen);
+
+/* Sends the supplied pre-built IPv4 packet. The packet is sent through
+ * the raw socket "sd" if "eth" is NULL. Otherwise, it gets sent at raw
+ * ethernet level. */
+int send_ip_packet_eth_or_sd(int sd, const struct eth_nfo *eth,
+ const struct sockaddr_in *dst, const u8 *packet, unsigned int packetlen);
+
+/* Sends an IPv4 packet. */
+int send_ipv6_packet_eth_or_sd(int sd, const struct eth_nfo *eth,
+ const struct sockaddr_in6 *dst, const u8 *packet, unsigned int packetlen);
+
+/* Create and send all fragments of a pre-built IPv4 packet.
+ * Minimal MTU for IPv4 is 68 and maximal IPv4 header size is 60
+ * which gives us a right to cut TCP header after 8th byte */
+int send_frag_ip_packet(int sd, const struct eth_nfo *eth,
+ const struct sockaddr_in *dst,
+ const u8 *packet, unsigned int packetlen, u32 mtu);
+
+/* Wrapper for system function sendto(), which retries a few times when
+ * the call fails. It also prints informational messages about the
+ * errors encountered. It returns the number of bytes sent or -1 in
+ * case of error. */
+int Sendto(const char *functionname, int sd, const unsigned char *packet,
+ int len, unsigned int flags, struct sockaddr *to, int tolen);
+
+/* This function is used to obtain a packet capture handle to look at
+ * packets on the network. It is actually a wrapper for libpcap's
+ * pcap_open_live() that takes care of compatibility issues and error
+ * checking. Prints an error and fatal()s if the call fails, so a
+ * valid pcap_t will always be returned. */
+pcap_t *my_pcap_open_live(const char *device, int snaplen, int promisc, int to_ms);
+
+/* Set a pcap filter */
+void set_pcap_filter(const char *device, pcap_t *pd, const char *bpf, ...);
+
+/* Issues an ARP request for the MAC of targetss (which will be placed
+ in targetmac if obtained) from the source IP (srcip) and source mac
+ (srcmac) given. "The request is ussued using device dev to the
+ broadcast MAC address. The transmission is attempted up to 3
+ times. If none of these elicit a response, false will be returned.
+ If the mac is determined, true is returned. The last parameter is
+ a pointer to a callback function that can be used for packet traceing.
+ This is intended to be used by Nmap only. Any other calling this
+ should pass NULL instead. */
+bool doArp(const char *dev, const u8 *srcmac,
+ const struct sockaddr_storage *srcip,
+ const struct sockaddr_storage *targetip,
+ u8 *targetmac,
+ void (*traceArp_callback)(int, const u8 *, u32 , struct timeval *));
+
+
+/* Issues an Neighbor Solicitation for the MAC of targetss (which will be placed
+ in targetmac if obtained) from the source IP (srcip) and source mac
+ (srcmac) given. "The request is ussued using device dev to the
+ multicast MAC address. The transmission is attempted up to 3
+ times. If none of these elicit a response, false will be returned.
+ If the mac is determined, true is returned. The last parameter is
+ a pointer to a callback function that can be used for packet tracing.
+ This is intended to be used by Nmap only. Any other calling this
+ should pass NULL instead. */
+bool doND(const char *dev, const u8 *srcmac,
+ const struct sockaddr_storage *srcip,
+ const struct sockaddr_storage *targetip,
+ u8 *targetmac,
+ void (*traceArp_callback)(int, const u8 *, u32 , struct timeval *)
+ ) ;
+
+/* Attempts to read one IPv4/Ethernet ARP reply packet from the pcap
+ descriptor pd. If it receives one, fills in sendermac (must pass
+ in 6 bytes), senderIP, and rcvdtime (can be NULL if you don't care)
+ and returns 1. If it times out and reads no arp requests, returns
+ 0. to_usec is the timeout period in microseconds. Use 0 to avoid
+ blocking to the extent possible. Returns -1 or exits if there is
+ an error. The last parameter is a pointer to a callback function
+ that can be used for packet tracing. This is intended to be used
+ by Nmap only. Any other calling this should pass NULL instead. */
+int read_arp_reply_pcap(pcap_t *pd, u8 *sendermac,
+ struct in_addr *senderIP, long to_usec,
+ struct timeval *rcvdtime,
+ void (*traceArp_callback)(int, const u8 *, u32 , struct timeval *));
+int read_ns_reply_pcap(pcap_t *pd, u8 *sendermac,
+ struct sockaddr_in6 *senderIP, long to_usec,
+ struct timeval *rcvdtime, bool *has_mac,
+ void (*traceArp_callback)(int, const u8 *, u32 , struct timeval *));
+
+/* Attempts to read one IP packet from the pcap descriptor pd. Input parameters are pd,
+ to_usec, and accept_callback. If a received frame passes accept_callback,
+ then the output parameters p, head, rcvdtime, datalink, and offset are filled
+ in, and the function returns 1. If no frame passes before the timeout, then
+ the function returns 0 and the output parameters are undefined. */
+int read_reply_pcap(pcap_t *pd, long to_usec,
+ bool (*accept_callback)(const unsigned char *, const struct pcap_pkthdr *, int, size_t),
+ const unsigned char **p, struct pcap_pkthdr **head, struct timeval *rcvdtime,
+ int *datalink, size_t *offset);
+
+/* Read a single host specification from a file, as for -iL and --excludefile.
+ It returns the length of the string read; an overflow is indicated when the
+ return value is >= n. Returns 0 if there was no specification to be read. The
+ buffer is always null-terminated. */
+size_t read_host_from_file(FILE *fp, char *buf, size_t n);
+
+/* Return next target host specification from the supplied stream.
+ * if parameter "random" is set to true, then the function will
+ * return a random, non-reserved, IP address in decimal-dot notation */
+const char *grab_next_host_spec(FILE *inputfd, bool random, int argc, const char **fakeargv);
+
+#ifdef WIN32
+/* Convert a dnet interface name into the long pcap style. This also caches the
+ data to speed things up. Fills out pcapdev (up to pcapdevlen) and returns
+ true if it finds anything. Otherwise returns false. This is only necessary
+ on Windows. */
+int DnetName2PcapName(const char *dnetdev, char *pcapdev, int pcapdevlen);
+#endif
+
+/** Tries to increase the open file descriptor limit for this process.
+ * @param "desired" is the number of desired max open descriptors. Pass a
+ * negative value to set the maximum allowed.
+ * @return the number of max open descriptors that could be set, or 0 in case
+ * of failure.
+ * @warning if "desired" is less than the current limit, no action is
+ * performed. This function may only be used to increase the limit, not to
+ * decrease it. */
+int set_max_open_descriptors(int desired_max);
+
+/** Returns the open file descriptor limit for this process.
+ * @return the number of max open descriptors or 0 in case of failure. */
+int get_max_open_descriptors();
+
+/* Maximize the open file descriptor limit for this process go up to the
+ max allowed */
+int max_sd();
+
+#endif /* _NETUTIL_H_ */
diff --git a/libnetutil/npacket.h b/libnetutil/npacket.h
new file mode 100644
index 0000000..49663ef
--- /dev/null
+++ b/libnetutil/npacket.h
@@ -0,0 +1,93 @@
+/***************************************************************************
+ * netutil.h -- The main include file exposing the external API for *
+ * libnetutil, a library that provides network-related functions or *
+ * classes that make it easier to handle things like network interfaces, *
+ * routing tables, raw packet manipulation, etc. The lib was originally *
+ * written for use in the Nmap Security Scanner ( https://nmap.org ). *
+ * *
+ ***********************IMPORTANT NMAP LICENSE TERMS************************
+ *
+ * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap
+ * Project"). Nmap is also a registered trademark of the Nmap Project.
+ *
+ * This program is distributed under the terms of the Nmap Public Source
+ * License (NPSL). The exact license text applying to a particular Nmap
+ * release or source code control revision is contained in the LICENSE
+ * file distributed with that version of Nmap or source code control
+ * revision. More Nmap copyright/legal information is available from
+ * https://nmap.org/book/man-legal.html, and further information on the
+ * NPSL license itself can be found at https://nmap.org/npsl/ . This
+ * header summarizes some key points from the Nmap license, but is no
+ * substitute for the actual license text.
+ *
+ * Nmap is generally free for end users to download and use themselves,
+ * including commercial use. It is available from https://nmap.org.
+ *
+ * The Nmap license generally prohibits companies from using and
+ * redistributing Nmap in commercial products, but we sell a special Nmap
+ * OEM Edition with a more permissive license and special features for
+ * this purpose. See https://nmap.org/oem/
+ *
+ * If you have received a written Nmap license agreement or contract
+ * stating terms other than these (such as an Nmap OEM license), you may
+ * choose to use and redistribute Nmap under those terms instead.
+ *
+ * The official Nmap Windows builds include the Npcap software
+ * (https://npcap.com) for packet capture and transmission. It is under
+ * separate license terms which forbid redistribution without special
+ * permission. So the official Nmap Windows builds may not be redistributed
+ * without special permission (such as an Nmap OEM license).
+ *
+ * Source is provided to this software because we believe users have a
+ * right to know exactly what a program is going to do before they run it.
+ * This also allows you to audit the software for security holes.
+ *
+ * Source code also allows you to port Nmap to new platforms, fix bugs, and add
+ * new features. You are highly encouraged to submit your changes as a Github PR
+ * or by email to the dev@nmap.org mailing list for possible incorporation into
+ * the main distribution. Unless you specify otherwise, it is understood that
+ * you are offering us very broad rights to use your submissions as described in
+ * the Nmap Public Source License Contributor Agreement. This is important
+ * because we fund the project by selling licenses with various terms, and also
+ * because the inability to relicense code has caused devastating problems for
+ * other Free Software projects (such as KDE and NASM).
+ *
+ * The free version of Nmap is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,
+ * indemnification and commercial support are all available through the
+ * Npcap OEM program--see https://nmap.org/oem/
+ *
+ ***************************************************************************/
+
+/* $Id: npacket.h 18098 2010-06-14 11:50:12Z luis $ */
+
+#ifndef __NPACKET_H__
+#define __NPACKET_H__ 1
+
+
+#include "ApplicationLayerElement.h"
+#include "ARPHeader.h"
+#include "DataLinkLayerElement.h"
+#include "EthernetHeader.h"
+#include "ICMPHeader.h"
+#include "ICMPv4Header.h"
+#include "ICMPv6Header.h"
+#include "ICMPv6Option.h"
+#include "ICMPv6RRBody.h"
+#include "IPv4Header.h"
+#include "IPv6Header.h"
+#include "NetworkLayerElement.h"
+#include "PacketElement.h"
+#include "RawData.h"
+#include "TCPHeader.h"
+#include "TransportLayerElement.h"
+#include "UDPHeader.h"
+#include "HopByHopHeader.h"
+#include "DestOptsHeader.h"
+#include "FragmentHeader.h"
+#include "RoutingHeader.h"
+#include "PacketParser.h"
+
+#endif /* __NPACKET_H__ */
+