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