1 
2 /***************************************************************************
3  * IPv6Header.cc -- The IPv6Header Class represents an IPv4 datagram. It   *
4  * contains methods to set any header field. In general, these methods do  *
5  * error checkings and byte order conversion.                              *
6  *                                                                         *
7  ***********************IMPORTANT NMAP LICENSE TERMS************************
8  *                                                                         *
9  * The Nmap Security Scanner is (C) 1996-2020 Insecure.Com LLC ("The Nmap  *
10  * Project"). Nmap is also a registered trademark of the Nmap Project.     *
11  *                                                                         *
12  * This program is distributed under the terms of the Nmap Public Source   *
13  * License (NPSL). The exact license text applying to a particular Nmap    *
14  * release or source code control revision is contained in the LICENSE     *
15  * file distributed with that version of Nmap or source code control       *
16  * revision. More Nmap copyright/legal information is available from       *
17  * https://nmap.org/book/man-legal.html, and further information on the    *
18  * NPSL license itself can be found at https://nmap.org/npsl. This header  *
19  * summarizes some key points from the Nmap license, but is no substitute  *
20  * for the actual license text.                                            *
21  *                                                                         *
22  * Nmap is generally free for end users to download and use themselves,    *
23  * including commercial use. It is available from https://nmap.org.        *
24  *                                                                         *
25  * The Nmap license generally prohibits companies from using and           *
26  * redistributing Nmap in commercial products, but we sell a special Nmap  *
27  * OEM Edition with a more permissive license and special features for     *
28  * this purpose. See https://nmap.org/oem                                  *
29  *                                                                         *
30  * If you have received a written Nmap license agreement or contract       *
31  * stating terms other than these (such as an Nmap OEM license), you may   *
32  * choose to use and redistribute Nmap under those terms instead.          *
33  *                                                                         *
34  * The official Nmap Windows builds include the Npcap software             *
35  * (https://npcap.org) for packet capture and transmission. It is under    *
36  * separate license terms which forbid redistribution without special      *
37  * permission. So the official Nmap Windows builds may not be              *
38  * redistributed without special permission (such as an Nmap OEM           *
39  * license).                                                               *
40  *                                                                         *
41  * Source is provided to this software because we believe users have a     *
42  * right to know exactly what a program is going to do before they run it. *
43  * This also allows you to audit the software for security holes.          *
44  *                                                                         *
45  * Source code also allows you to port Nmap to new platforms, fix bugs,    *
46  * and add new features.  You are highly encouraged to submit your         *
47  * changes as a Github PR or by email to the dev@nmap.org mailing list     *
48  * for possible incorporation into the main distribution. Unless you       *
49  * specify otherwise, it is understood that you are offering us very       *
50  * broad rights to use your submissions as described in the Nmap Public    *
51  * Source License Contributor Agreement. This is important because we      *
52  * fund the project by selling licenses with various terms, and also       *
53  * because the inability to relicense code has caused devastating          *
54  * problems for other Free Software projects (such as KDE and NASM).       *
55  *                                                                         *
56  * The free version of Nmap is distributed in the hope that it will be     *
57  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of  *
58  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties,        *
59  * indemnification and commercial support are all available through the    *
60  * Npcap OEM program--see https://nmap.org/oem.                            *
61  *                                                                         *
62  ***************************************************************************/
63 /* This code was originally part of the Nping tool.                        */
64 
65 #include "IPv6Header.h"
66 
67 /******************************************************************************/
68 /* CONTRUCTORS, DESTRUCTORS AND INITIALIZATION METHODS                        */
69 /******************************************************************************/
IPv6Header()70 IPv6Header::IPv6Header() {
71   this->reset();
72 } /* End of IPv6Header constructor */
73 
74 
~IPv6Header()75 IPv6Header::~IPv6Header() {
76 
77 } /* End of IPv6Header destructor */
78 
79 
80 /** Sets every attribute to its default value */
reset()81 void IPv6Header::reset(){
82   memset(&this->h, 0, sizeof(nping_ipv6_hdr_t));
83   this->length=IPv6_HEADER_LEN;
84   this->setVersion();
85   this->setTrafficClass(IPv6_DEFAULT_TCLASS);
86   this->setFlowLabel(IPv6_DEFAULT_FLABEL);
87   this->setHopLimit(IPv6_DEFAULT_HOPLIM);
88   this->setNextHeader(IPv6_DEFAULT_NXTHDR); /* No next header */
89   this->setPayloadLength(0);
90 } /* End of reset() */
91 
92 
93 /******************************************************************************/
94 /* PacketElement:: OVERWRITTEN METHODS                                        */
95 /******************************************************************************/
96 
97 /** @warning This method is essential for the superclass getBinaryBuffer()
98  *  method to work. Do NOT change a thing unless you know what you're doing  */
getBufferPointer()99 u8 *IPv6Header::getBufferPointer(){
100   return (u8*)(&h);
101 } /* End of getBufferPointer() */
102 
103 
104 /** Stores supplied packet in the internal buffer so the information
105   * can be accessed using the standard get & set methods.
106   * @warning  The IPv6Header class is able to hold a maximum of 40 bytes. If the
107   * supplied buffer is longer than that, only the first 40 bytes will be stored
108   * in the internal buffer.
109   * @warning Supplied len MUST be at least 40 bytes (IPv6 header length).
110   * @return OP_SUCCESS on success and OP_FAILURE in case of error */
storeRecvData(const u8 * buf,size_t len)111 int IPv6Header::storeRecvData(const u8 *buf, size_t len){
112   if(buf==NULL || len<IPv6_HEADER_LEN){
113     return OP_FAILURE;
114   }else{
115     this->reset(); /* Re-init the object, just in case the caller had used it already */
116     this->length=IPv6_HEADER_LEN;
117     memcpy(&(this->h), buf, IPv6_HEADER_LEN);
118   }
119  return OP_SUCCESS;
120 } /* End of storeRecvData() */
121 
122 
123 /* Returns a protocol identifier. This is used by packet parsing funtions
124  * that return linked lists of PacketElement objects, to determine the protocol
125  * the object represents. */
protocol_id() const126 int IPv6Header::protocol_id() const {
127     return HEADER_TYPE_IPv6;
128 } /* End of protocol_id() */
129 
130 
131 /** Determines if the data stored in the object after an storeRecvData() call
132   * is valid and safe to use. This mainly checks the length of the data but may
133   * also test the value of certain protocol fields to ensure their correctness.
134   * @return the length, in bytes, of the header, if its found to be valid or
135   * OP_FAILURE (-1) otherwise. */
validate()136 int IPv6Header::validate(){
137   if( this->length!=IPv6_HEADER_LEN)
138       return OP_FAILURE;
139   else
140       return IPv6_HEADER_LEN;
141 } /* End of validate() */
142 
143 
144 /** Prints the contents of the header and calls print() on the next protocol
145   * header in the chain (if there is any).
146   * @return OP_SUCCESS on success and OP_FAILURE in case of error. */
print(FILE * output,int detail) const147 int IPv6Header::print(FILE *output, int detail) const {
148   static char ipstring[256];
149   memset(ipstring, 0, 256);
150   struct in6_addr addr;
151   char ipinfo[512] = "";                /* Temp info about IP.               */
152 
153   fprintf(output, "IPv6[");
154   this->getSourceAddress(&addr);
155   inet_ntop(AF_INET6, &addr, ipstring, sizeof(ipstring));
156   fprintf(output, "%s", ipstring);
157   fprintf(output, " >");
158   this->getDestinationAddress(&addr);
159   inet_ntop(AF_INET6, &addr, ipstring, sizeof(ipstring));
160   fprintf(output, " %s", ipstring);
161 
162   /* Create a string with information relevant to the specified level of detail */
163   if( detail == PRINT_DETAIL_LOW ){
164       Snprintf(ipinfo, sizeof(ipinfo), "hlim=%d", this->getHopLimit());
165   }else if( detail == PRINT_DETAIL_MED ){
166       Snprintf(ipinfo, sizeof(ipinfo), "hlim=%d tclass=%d flow=%d",
167                this->getHopLimit(), this->getTrafficClass(), this->getFlowLabel() );
168   }else if( detail>=PRINT_DETAIL_HIGH ){
169       Snprintf(ipinfo, sizeof(ipinfo), "ver=%d hlim=%d tclass=%d flow=%d plen=%d nh=%d",
170                this->getVersion(), this->getHopLimit(), this->getTrafficClass(),
171                this->getFlowLabel(), this->getPayloadLength(), this->getNextHeader() );
172   }
173   fprintf(output, " %s]", ipinfo);
174   if(this->next!=NULL){
175     print_separator(output, detail);
176     next->print(output, detail);
177   }
178   return OP_SUCCESS;
179 } /* End of print() */
180 
181 
182 /******************************************************************************/
183 /* PROTOCOL-SPECIFIC METHODS                                                  */
184 /******************************************************************************/
185 
186 /** Set Version field (4 bits).  */
setVersion(u8 val)187 int IPv6Header::setVersion(u8 val){
188   union{
189     struct firstbyte{
190         #if WORDS_BIGENDIAN
191             u8 ver:4;
192             u8 tclass:4;
193         #else
194             u8 tclass:4;
195             u8 ver:4;
196         #endif
197     }halfbyte;
198     u8 fullbyte;
199   }header1stbyte;
200 
201   header1stbyte.fullbyte = h.ip6_start[0];
202   header1stbyte.halfbyte.ver=val;
203   h.ip6_start[0]=header1stbyte.fullbyte;
204   return OP_SUCCESS;
205 } /* End of setVersion() */
206 
207 
208 /** Set Version field to value 6.  */
setVersion()209 int IPv6Header::setVersion(){
210   this->setVersion(6);
211   return OP_SUCCESS;
212 } /* End of setVersion() */
213 
214 
215 /** Returns an 8bit number containing the value of the Version field.  */
getVersion() const216 u8 IPv6Header::getVersion() const {
217   union{
218     struct firstbyte{
219         #if WORDS_BIGENDIAN
220             u8 ver:4;
221             u8 tclass:4;
222         #else
223             u8 tclass:4;
224             u8 ver:4;
225         #endif
226     }halfbyte;
227     u8 fullbyte;
228   }header1stbyte;
229 
230   header1stbyte.fullbyte = h.ip6_start[0];
231   return (u8)header1stbyte.halfbyte.ver;
232 } /* End of getVersion() */
233 
234 
setTrafficClass(u8 val)235 int IPv6Header::setTrafficClass(u8 val){
236   union{
237     struct firstbyte{
238         #if WORDS_BIGENDIAN
239             u8 ver:4;
240             u8 tclass1:4;
241         #else
242             u8 tclass1:4;
243             u8 ver:4;
244         #endif
245     }halfbyte;
246     u8 fullbyte;
247   }header1stbyte;
248   union{
249     struct firstbyte{
250         #if WORDS_BIGENDIAN
251             u8 tclass2:4;
252             u8 flow:4;
253         #else
254             u8 flow:4;
255             u8 tclass2:4;
256         #endif
257     }halfbyte;
258     u8 fullbyte;
259   }header2ndbyte;
260 
261   /* Store old contents */
262   header1stbyte.fullbyte = h.ip6_start[0];
263   header2ndbyte.fullbyte = h.ip6_start[1];
264 
265   /* Fill the two 4bit halves */
266   header1stbyte.halfbyte.tclass1=val>>4;
267   header2ndbyte.halfbyte.tclass2=val;
268 
269   /* Write the bytes back to the header */
270   h.ip6_start[0]=header1stbyte.fullbyte;
271   h.ip6_start[1]=header2ndbyte.fullbyte;
272 
273   return OP_SUCCESS;
274 } /* End of setTrafficClass() */
275 
276 
getTrafficClass() const277 u8 IPv6Header::getTrafficClass() const {
278   union{
279     struct firstbyte{
280         #if WORDS_BIGENDIAN
281             u8 ver:4;
282             u8 tclass1:4;
283         #else
284             u8 tclass1:4;
285             u8 ver:4;
286         #endif
287     }halfbyte;
288     u8 fullbyte;
289   }header1stbyte;
290   union{
291     struct firstbyte{
292         #if WORDS_BIGENDIAN
293             u8 tclass2:4;
294             u8 flow:4;
295         #else
296             u8 flow:4;
297             u8 tclass2:4;
298         #endif
299     }halfbyte;
300     u8 fullbyte;
301   }header2ndbyte;
302   union{
303     struct firstbyte{
304         #if WORDS_BIGENDIAN
305             u8 tclass1:4;
306             u8 tclass2:4;
307         #else
308             u8 tclass2:4;
309             u8 tclass1:4;
310         #endif
311     }halfbyte;
312     u8 fullbyte;
313   }finalbyte;
314 
315   header1stbyte.fullbyte = h.ip6_start[0];
316   header2ndbyte.fullbyte = h.ip6_start[1];
317   finalbyte.halfbyte.tclass1=header1stbyte.halfbyte.tclass1;
318   finalbyte.halfbyte.tclass2=header2ndbyte.halfbyte.tclass2;
319   return finalbyte.fullbyte;
320 } /* End of getTrafficClass() */
321 
322 
setFlowLabel(u32 val)323 int IPv6Header::setFlowLabel(u32 val){
324   u32 netbyte = htonl(val);
325   u8 *pnt=(u8*)&netbyte;
326   union{
327     struct firstbyte{
328         #if WORDS_BIGENDIAN
329             u8 tclass2:4;
330             u8 flow:4;
331         #else
332             u8 flow:4;
333             u8 tclass2:4;
334         #endif
335     }halfbyte;
336     u8 fullbyte;
337   }header2ndbyte;
338 
339   header2ndbyte.fullbyte = h.ip6_start[1];
340   header2ndbyte.halfbyte.flow=pnt[1];
341   h.ip6_start[1]=header2ndbyte.fullbyte;
342   h.ip6_start[2]=pnt[2];
343   h.ip6_start[3]=pnt[3];
344   return OP_SUCCESS;
345 } /* End of setFlowLabel() */
346 
347 
getFlowLabel() const348 u32 IPv6Header::getFlowLabel() const {
349   u32 hostbyte=0;
350   u8 *pnt=(u8*)&hostbyte;
351   union{
352     struct firstbyte{
353         #if WORDS_BIGENDIAN
354             u8 tclass2:4;
355             u8 flow:4;
356         #else
357             u8 flow:4;
358             u8 tclass2:4;
359         #endif
360     }halfbyte;
361     u8 fullbyte;
362   }header2ndbyte;
363 
364   header2ndbyte.fullbyte = h.ip6_start[1];
365   pnt[0]=0;
366   pnt[1]=header2ndbyte.halfbyte.flow;
367   pnt[2]=h.ip6_start[2];
368   pnt[3]=h.ip6_start[3];
369   hostbyte=ntohl(hostbyte);
370   return hostbyte;
371 } /* End of getFlowLabel() */
372 
373 
setPayloadLength(u16 val)374 int IPv6Header::setPayloadLength(u16 val){
375   this->h.ip6_len = htons(val);
376   return OP_SUCCESS;
377 } /* End of setPayloadLength() */
378 
379 
setPayloadLength()380 int IPv6Header::setPayloadLength(){
381   int otherslen=0;
382   if (next!=NULL)
383       otherslen=next->getLen();
384   setPayloadLength( otherslen );
385   return OP_SUCCESS;
386 } /* End of setTotalLength() */
387 
388 
getPayloadLength() const389 u16 IPv6Header::getPayloadLength() const {
390   return ntohs(this->h.ip6_len);
391 } /* End of getPayloadLength() */
392 
393 
setNextHeader(u8 val)394 int IPv6Header::setNextHeader(u8 val){
395   this->h.ip6_nh = val;
396   return OP_SUCCESS;
397 } /* End of setNextHeader() */
398 
399 
getNextHeader() const400 u8 IPv6Header::getNextHeader() const {
401   return this->h.ip6_nh;
402 } /* End of getNextHeader() */
403 
404 
405 /** Sets field "next header" to the number that corresponds to the supplied
406  *  protocol name. Currently only TCP, UDP and ICMP are supported. Any
407  *  help to extend this functionality would be appreciated. For a list of all
408  *  proto names and numbers check:
409  *  http://www.iana.org/assignments/protocol-numbers/                        */
setNextHeader(const char * p)410 int IPv6Header::setNextHeader(const char *p){
411 
412   if (p==NULL){
413     printf("setNextProto(): NULL pointer supplied\n");
414     return OP_FAILURE;
415   }
416   if( !strcasecmp(p, "TCP") )
417     setNextHeader(6);   /* 6=IANA number for proto TCP */
418   else if( !strcasecmp(p, "UDP") )
419     setNextHeader(17);  /* 17=IANA number for proto UDP */
420   else if( !strcasecmp(p, "ICMPv6"))
421     setNextHeader(58);  /* 58=IANA number for proto ICMPv6 */
422   else
423     netutil_fatal("setNextProto(): Invalid protocol number\n");
424   return OP_SUCCESS;
425 } /* End of setNextHeader() */
426 
427 
setHopLimit(u8 val)428 int IPv6Header::setHopLimit(u8 val){
429   this->h.ip6_hopl = val;
430   return OP_SUCCESS;
431 } /* End of setHopLimit() */
432 
433 
getHopLimit() const434 u8 IPv6Header::getHopLimit() const {
435   return this->h.ip6_hopl;
436 } /* End of getHopLimit() */
437 
438 
setSourceAddress(u8 * val)439 int IPv6Header::setSourceAddress(u8 *val){
440   if(val==NULL)
441     netutil_fatal("setSourceAddress(): NULL value supplied.");
442   memcpy(this->h.ip6_src, val, 16);
443   return OP_SUCCESS;
444 } /* End of setSourceAddress() */
445 
446 
setSourceAddress(struct in6_addr val)447 int IPv6Header::setSourceAddress(struct in6_addr val){
448   memcpy(this->h.ip6_src, val.s6_addr, 16);
449   return OP_SUCCESS;
450 } /* End of setSourceAddress() */
451 
452 
getSourceAddress() const453 const u8 *IPv6Header::getSourceAddress() const {
454   return this->h.ip6_src;
455 } /* End of getSourceAddress() */
456 
457 
458 /** Returns source IPv6 address
459  *  @warning Returned value is in NETWORK byte order. */
getSourceAddress(struct in6_addr * result) const460 struct in6_addr IPv6Header::getSourceAddress(struct in6_addr *result) const {
461   struct in6_addr myaddr;
462   memset(&myaddr, 0, sizeof(myaddr));
463   memcpy(myaddr.s6_addr, this->h.ip6_src, 16);
464 
465   if(result!=NULL)
466       *result=myaddr;
467   return myaddr;
468 } /* End of getSourceAddress() */
469 
470 
setDestinationAddress(u8 * val)471 int IPv6Header::setDestinationAddress(u8 *val){
472   if(val==NULL)
473     netutil_fatal("setDestinationAddress(): NULL value supplied.");
474   memcpy(this->h.ip6_dst, val, 16);
475   return OP_SUCCESS;
476 } /* End of setDestinationAddress() */
477 
478 
setDestinationAddress(struct in6_addr val)479 int IPv6Header::setDestinationAddress(struct in6_addr val){
480   memcpy(this->h.ip6_dst, val.s6_addr, 16);
481   return OP_SUCCESS;
482 } /* End of setDestinationAddress() */
483 
484 
485 /** Returns destination IPv6 address. */
getDestinationAddress() const486 const u8 *IPv6Header::getDestinationAddress() const {
487   return this->h.ip6_dst;
488 } /* End of getDestinationAddress() */
489 
490 
491 /** Returns destination IPv6 address
492  *  @warning Returned value is in NETWORK byte order. */
getDestinationAddress(struct in6_addr * result) const493 struct in6_addr IPv6Header::getDestinationAddress(struct in6_addr *result) const {
494   struct in6_addr myaddr;
495   memset(&myaddr, 0, sizeof(myaddr));
496   memcpy(myaddr.s6_addr, this->h.ip6_dst, 16);
497 
498   if(result!=NULL)
499       *result=myaddr;
500   return myaddr;
501 } /* End of getDestinationAddress() */
502 
503 
504 /** Returns the length of an IPv4 address. */
getAddressLength() const505 u16 IPv6Header::getAddressLength() const {
506     return 16;
507 } /* End of getAddressLength()*/
508 
509