summaryrefslogtreecommitdiffstats
path: root/libnetutil/ICMPv4Header.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libnetutil/ICMPv4Header.cc')
-rw-r--r--libnetutil/ICMPv4Header.cc1187
1 files changed, 1187 insertions, 0 deletions
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() */