1 /*
2 * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
3 * 2002, 2003, 2004
4 * Ohio University.
5 *
6 * ---
7 *
8 * Starting with the release of tcptrace version 6 in 2001, tcptrace
9 * is licensed under the GNU General Public License (GPL). We believe
10 * that, among the available licenses, the GPL will do the best job of
11 * allowing tcptrace to continue to be a valuable, freely-available
12 * and well-maintained tool for the networking community.
13 *
14 * Previous versions of tcptrace were released under a license that
15 * was much less restrictive with respect to how tcptrace could be
16 * used in commercial products. Because of this, I am willing to
17 * consider alternate license arrangements as allowed in Section 10 of
18 * the GNU GPL. Before I would consider licensing tcptrace under an
19 * alternate agreement with a particular individual or company,
20 * however, I would have to be convinced that such an alternative
21 * would be to the greater benefit of the networking community.
22 *
23 * ---
24 *
25 * This file is part of Tcptrace.
26 *
27 * Tcptrace was originally written and continues to be maintained by
28 * Shawn Ostermann with the help of a group of devoted students and
29 * users (see the file 'THANKS'). The work on tcptrace has been made
30 * possible over the years through the generous support of NASA GRC,
31 * the National Science Foundation, and Sun Microsystems.
32 *
33 * Tcptrace is free software; you can redistribute it and/or modify it
34 * under the terms of the GNU General Public License as published by
35 * the Free Software Foundation; either version 2 of the License, or
36 * (at your option) any later version.
37 *
38 * Tcptrace is distributed in the hope that it will be useful, but
39 * WITHOUT ANY WARRANTY; without even the implied warranty of
40 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41 * General Public License for more details.
42 *
43 * You should have received a copy of the GNU General Public License
44 * along with Tcptrace (in the file 'COPYING'); if not, write to the
45 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
46 * MA 02111-1307 USA
47 *
48 * Author: Nasseef Abukamail
49 * School of Electrical Engineering and Computer Science
50 * Ohio University
51 * Athens, OH
52 * http://www.tcptrace.org/
53 */
54 #include "tcptrace.h"
55 static char const GCC_UNUSED copyright[] =
56 "@(#)Copyright (c) 2004 -- Ohio University.\n";
57 static char const GCC_UNUSED rcsid[] =
58 "@(#)$Header$";
59
60
61
62 /* the names of IPv6 extensions that we understand */
63 char *
ipv6_header_name(u_char nextheader)64 ipv6_header_name(
65 u_char nextheader)
66 {
67 switch (nextheader) {
68 case IPPROTO_DSTOPTS: return("Destinations options");
69 case IPPROTO_FRAGMENT: return("Fragment header");
70 case IPPROTO_HOPOPTS: return("Hop by hop");
71 case IPPROTO_NONE: return("No next header");
72 case IPPROTO_ROUTING: return("Routing header");
73 case IPPROTO_ICMPV6: return("IPv6 ICMP");
74 case IPPROTO_TCP: return("TCP");
75 case IPPROTO_UDP: return("UDP");
76 default: return("<unknown>");
77 }
78 }
79
80
81 /* given a next header type and a pointer to the header, return a pointer
82 to the next extension header and type */
83 struct ipv6_ext *
ipv6_nextheader(void * pheader0,u_char * pnextheader)84 ipv6_nextheader(
85 void *pheader0,
86 u_char *pnextheader)
87 {
88 struct ipv6_ext *pheader = pheader0;
89
90 switch (*pnextheader) {
91 /* nothing follows these... */
92 case IPPROTO_TCP:
93 case IPPROTO_NONE:
94 case IPPROTO_ICMPV6:
95 case IPPROTO_UDP:
96 return(NULL);
97
98 /* somebody follows these */
99 case IPPROTO_HOPOPTS:
100 case IPPROTO_ROUTING:
101 case IPPROTO_DSTOPTS:
102 *pnextheader = pheader->ip6ext_nheader;
103
104 /* sanity check, if length is 0, terminate */
105 /* As per RFC 2460 : ip6ext_len specifies the extended
106 header length, in units of 8 octets *not including* the
107 first 8 octets. So ip6ext_len can be 0 and hence,
108 we cannot perform the sanity check any more.
109
110 Hence commenting out the sanity check - Mani*/
111
112 /* if (pheader->ip6ext_len == 0)
113 return(NULL); */
114
115 return((struct ipv6_ext *)
116 ((char *)pheader + 8 + (pheader->ip6ext_len)*8));
117
118 /* I don't understand them. Just save the type and return a NULL */
119 default:
120 *pnextheader = pheader->ip6ext_nheader;
121 return(NULL);
122 }
123 }
124
125
126
127 /*
128 * findheader: find and return a pointer to a header.
129 * Skips either ip or ipv6 headers
130 * return values: 0 - found header
131 * 1 - correct protocol, invalid packet, cannot return header
132 * -1 - different protocol, cannot return header
133 */
134 static int
findheader(u_int ipproto,struct ip * pip,void ** pphdr,void ** pplast)135 findheader(
136 u_int ipproto,
137 struct ip *pip,
138 void **pphdr,
139 void **pplast)
140 {
141 struct ipv6 *pip6 = (struct ipv6 *)pip;
142 char nextheader;
143 struct ipv6_ext *pheader;
144 void *theheader;
145
146 /* IPv4 is easy */
147 if (PIP_ISV4(pip)) {
148 /* make sure it's what we want */
149 if (pip->ip_p != ipproto)
150 return (-1);
151
152 /* check the fragment field, if it's not the first fragment,
153 it's useless (offset part of field must be 0 */
154 if ((ntohs(pip->ip_off)&0x1fff) != 0) {
155 if (debug>1) {
156 printf("findheader: Skipping IPv4 non-initial fragment\n");
157 if (debug > 2) {
158 printpacket(100,100,NULL,0,pip,*pplast,NULL);
159 }
160 }
161 return (1);
162 }
163
164 /* OK, it starts here */
165 theheader = ((char *)pip + 4*IP_HL(pip));
166
167 /* adjust plast in accordance with ip_len (really short packets get garbage) */
168 if (((char *)pip + ntohs(pip->ip_len) - 1) < (char *)(*pplast)) {
169 *pplast = (char *)((char *)pip + ntohs(pip->ip_len));
170 }
171
172 #ifdef OLD
173 /* this is better verified when used, the error message is better */
174
175 /* make sure the whole header is there */
176 if ((char *)ptcp + (sizeof struct tcphdr) - 1 > (char *)*pplast) {
177 /* part of the header is missing */
178 return (1);
179 }
180 #endif
181
182 *pphdr = theheader;
183 return (0);
184 }
185
186 /* otherwise, we only understand IPv6 */
187 if (!PIP_ISV6(pip))
188 return (-1);
189
190 /* find the first header */
191 nextheader = pip6->ip6_nheader;
192 pheader = (struct ipv6_ext *)(pip6+1);
193
194 /* loop until we find the header we want or give up */
195 while (1) {
196 /* sanity check, if we're reading bogus header, the length might */
197 /* be wonky, so make sure before you dereference anything!! */
198 if ((char *)pheader < (char *)pip) {
199 if (debug>1)
200 printf("findheader: bad extension header math, skipping packet\n");
201 return (1);
202 }
203
204 /* make sure we're still within the packet */
205 /* might be truncated, or might be bad header math */
206 if ((char *)pheader > (char *)*pplast) {
207 if (debug>3)
208 printf("findheader: packet truncated before finding header\n");
209 return (1);
210 }
211
212 /* this is what we want */
213 if (nextheader == ipproto) {
214 *pphdr = pheader;
215 return (0);
216 }
217
218 switch (nextheader) {
219 case IPPROTO_TCP:
220 return (-1); /* didn't find it */
221 case IPPROTO_UDP:
222 return (-1); /* didn't find it */
223
224 /* fragmentation */
225 case IPPROTO_FRAGMENT:
226 {
227 struct ipv6_ext_frag *pfrag = (struct ipv6_ext_frag *)pheader;
228
229 /* if this isn't the FIRST fragment, there won't be a TCP header
230 anyway */
231 if ((pfrag->ip6ext_fr_offset&0xfc) != 0) {
232 /* the offset is non-zero */
233 if (debug>1)
234 printf("findheader: Skipping IPv6 non-initial fragment\n");
235 return (1);
236 }
237
238 /* otherwise it's either an entire segment or the first fragment */
239 nextheader = pfrag->ip6ext_fr_nheader;
240 /* Pass to the next octet following the fragmentation
241 header */
242 pheader = (struct ipv6_ext *)
243 ((char *)pheader + sizeof(struct ipv6_ext_frag));
244 break;
245 }
246
247 /* headers we just skip over */
248 case IPPROTO_HOPOPTS:
249 case IPPROTO_ROUTING:
250 case IPPROTO_DSTOPTS:
251 nextheader = pheader->ip6ext_nheader;
252
253 /* As per RFC 2460 : ip6ext_len specifies the extended
254 header length, in units of 8 octets *not including* the
255 first 8 octets. */
256
257 pheader = (struct ipv6_ext *)
258 ((char *)pheader + 8 + (pheader->ip6ext_len)*8);
259 break;
260 /* non-tcp protocols, so we're finished. */
261 case IPPROTO_NONE:
262 case IPPROTO_ICMPV6:
263 return (-1); /* didn't find it */
264
265 /* I "think" that we can just skip over it, but better be careful */
266 default:
267 nextheader = pheader->ip6ext_nheader;
268
269 pheader = (struct ipv6_ext *)
270 ((char *)pheader + 8 + (pheader->ip6ext_len)*8);
271 break;
272
273 } /* end switch */
274 } /* end loop */
275
276 /* shouldn't get here, but just in case :-) */
277 return (-1);
278 }
279
280 /* Added Aug 31, 2001 -- Avinash.
281 * getroutingheader: return a pointer to the routing header in an ipv6 packet.
282 * Looks through all the IPv6 extension headers for the routing header.
283 * Used while computing the IPv6 checksums.
284 */
285 int
getroutingheader(struct ip * pip,struct ipv6_ext ** ppipv6_ext,void ** pplast)286 getroutingheader(
287 struct ip *pip,
288 struct ipv6_ext **ppipv6_ext,
289 void **pplast)
290 {
291 int ret_val = findheader(IPPROTO_ROUTING, pip, (void **)ppipv6_ext, pplast);
292 return (ret_val);
293 }
294
295
296 /*
297 * gettcp: return a pointer to a tcp header.
298 * Skips either ip or ipv6 headers
299 */
300 int
gettcp(struct ip * pip,struct tcphdr ** pptcp,void ** pplast)301 gettcp(
302 struct ip *pip,
303 struct tcphdr **pptcp,
304 void **pplast)
305 {
306 int ret_val = findheader(IPPROTO_TCP, pip, (void **)pptcp, pplast);
307 return (ret_val);
308 }
309
310
311 /*
312 * getudp: return a pointer to a udp header.
313 * Skips either ip or ipv6 headers
314 */
315 int
getudp(struct ip * pip,struct udphdr ** ppudp,void ** pplast)316 getudp(
317 struct ip *pip,
318 struct udphdr **ppudp,
319 void **pplast)
320 {
321 int ret_val = findheader(IPPROTO_UDP, pip, (void **)ppudp, pplast);
322 return (ret_val);
323 }
324
325
326
327 /*
328 * gethdrlength: returns the length of the header in the case of ipv4
329 * returns the length of all the headers in the case of ipv6
330 */
gethdrlength(struct ip * pip,void * plast)331 int gethdrlength (struct ip *pip, void *plast)
332 {
333 int length, nextheader;
334 char *pheader;
335 struct ipv6 *pipv6;
336
337 if (PIP_ISV6(pip)) {
338 length = 40;
339
340 pheader = (char *) pip;
341 nextheader = *(pheader + 6);
342 pheader += 40;
343
344 pipv6 = (struct ipv6 *) pip;
345 while (1)
346 {
347 if (nextheader == IPPROTO_NONE)
348 return length;
349 if (nextheader == IPPROTO_TCP)
350 return length;
351 if (nextheader == IPPROTO_UDP)
352 return length;
353 if (nextheader == IPPROTO_FRAGMENT)
354 {
355 nextheader = *pheader;
356 pheader += 8;
357 length += 8;
358 }
359 if ((nextheader == IPPROTO_HOPOPTS) ||
360 (nextheader == IPPROTO_ROUTING) ||
361 (nextheader == IPPROTO_DSTOPTS))
362 {
363 // Thanks to patch sent by Thomas Bohnert
364 // Header length field in these IPv6 extension headers
365 // stores the length of the header in units of 8 bytes,
366 // *without* counting the mandatory 8 bytes
367
368 nextheader = *pheader;
369 length += (*(pheader+1) + 1) * 8;
370 pheader += (*(pheader+1) + 1) * 8;
371 }
372 // IPv6 encapsulated in IPv6
373 if (nextheader == IPPROTO_IPV6)
374 {
375 pheader += 40;
376 nextheader=*(pheader+6);
377 length += 40;
378 }
379
380 if (pheader > (char *)plast)
381 return -1;
382 }
383 }
384 else
385 {
386 return IP_HL(pip) * 4;
387 }
388 }
389
390 /*
391 * getpayloadlength: returns the length of the packet without the header.
392 */
getpayloadlength(struct ip * pip,void * plast)393 int getpayloadlength (struct ip *pip, void *plast)
394 {
395 struct ipv6 *pipv6;
396
397 if (PIP_ISV6(pip)) {
398 pipv6 = (struct ipv6 *) pip; /* how about all headers */
399 return ntohs(pipv6->ip6_lngth);
400 }
401 return ntohs(pip->ip_len) - (IP_HL(pip) * 4);
402 }
403
404
405
406 #ifdef OLD_THESE_MOVED_TO_TRACE_C
407 /*
408 * ipcopyaddr: copy an IPv4 or IPv6 address
409 * (note - this is obsolete in favor of the inline-able
410 * IP_COPYADDR in tcptrace.h)
411 */
ip_copyaddr(ipaddr * ptoaddr,ipaddr * pfromaddr)412 void ip_copyaddr (ipaddr *ptoaddr, ipaddr *pfromaddr)
413 {
414 if (ADDR_ISV6(pfromaddr)) {
415 memcpy(ptoaddr->un.ip6.s6_addr, pfromaddr->un.ip6.s6_addr, 16);
416 ptoaddr->addr_vers = 6;
417 } else {
418 ptoaddr->un.ip4.s_addr = pfromaddr->un.ip4.s_addr;
419 ptoaddr->addr_vers = 4;
420 }
421 }
422
423
424
425 /*
426 * ipsameaddr: test for equality of two IPv4 or IPv6 addresses
427 * (note - this is obsolete in favor of the inline-able
428 * IP_SAMEADDR in tcptrace.h)
429 */
ip_sameaddr(ipaddr * paddr1,ipaddr * paddr2)430 int ip_sameaddr (ipaddr *paddr1, ipaddr *paddr2)
431 {
432 int ret = 0;
433 if (ADDR_ISV6(paddr1)) {
434 if (ADDR_ISV6(paddr2))
435 ret = (memcmp(paddr1->un.ip6.s6_addr,
436 paddr2->un.ip6.s6_addr,16) == 0);
437 } else {
438 if (ADDR_ISV4(paddr2))
439 ret = (paddr1->un.ip4.s_addr == paddr2->un.ip4.s_addr);
440 }
441 if (debug > 3)
442 printf("SameAddr(%s(%d),%s(%d)) returns %d\n",
443 HostName(*paddr1), ADDR_VERSION(paddr1),
444 HostName(*paddr2), ADDR_VERSION(paddr2),
445 ret);
446 return ret;
447 }
448
449 /*
450 * iplowaddr: test if one IPv4 or IPv6 address is lower than the second one
451 * (note - this is obsolete in favor of the inline-able
452 * IP_LOWADDR in tcptrace.h)
453 */
ip_lowaddr(ipaddr * paddr1,ipaddr * paddr2)454 int ip_lowaddr (ipaddr *paddr1, ipaddr *paddr2)
455 {
456 int ret = 0;
457 if (ADDR_ISV6(paddr1)) {
458 if (ADDR_ISV6(paddr2))
459 ret = (memcmp(paddr1->un.ip6.s6_addr,
460 paddr2->un.ip6.s6_addr,16) < 0);
461 } else {
462 /* already know ADDR_ISV4(paddr1) */
463 if (ADDR_ISV4(paddr2))
464 ret = (paddr1->un.ip4.s_addr < paddr2->un.ip4.s_addr);
465 }
466 if (debug > 3)
467 printf("LowAddr(%s(%d),%s(%d)) returns %d\n",
468 HostName(*paddr1), ADDR_VERSION(paddr1),
469 HostName(*paddr2), ADDR_VERSION(paddr2),
470 ret);
471 return ret;
472 }
473 #endif /* OLD_THESE_MOVED_TO_TRACE_C */
474
475
476 #ifndef HAVE_INET_PTON
477 int
inet_pton(int af,const char * src,void * dst)478 inet_pton(int af, const char *src, void *dst)
479 {
480 if (af == AF_INET) {
481 /* use standard function */
482 long answer = inet_addr(src);
483 if (answer != -1) {
484 *((long *)dst) = answer;
485 return(1);
486 }
487 } else if (af == AF_INET6) {
488 /* YUCC - lazy for now, not fully supported */
489 int shorts[8];
490 if (sscanf(src,"%x:%x:%x:%x:%x:%x:%x:%x",
491 &shorts[0], &shorts[1], &shorts[2], &shorts[3],
492 &shorts[4], &shorts[5], &shorts[6], &shorts[7]) == 8) {
493 int i;
494 for (i=0; i < 8; ++i)
495 ((u_short *)dst)[i] = (u_short)shorts[i];
496 return(1);
497 }
498 }
499
500 /* else, it failed */
501 return(0);
502 }
503 #endif /* HAVE_INET_PTON */
504
505
506
507 /*
508 * my_inet_ntop: makes a string address of the 16 byte ipv6 address
509 * We use our own because various machines print them differently
510 * and I wanted them to all be the same
511 */
512 char *
my_inet_ntop(int af,const char * src,char * dst,size_t size)513 my_inet_ntop(int af, const char *src, char *dst, size_t size)
514 {
515 int i;
516 u_short *src_shorts = (u_short *)src;
517 char *ret = dst;
518 Bool did_shorthand = FALSE;
519 Bool doing_shorthand = FALSE;
520
521 /* sanity check, this isn't general, but doesn't need to be */
522 if (size != INET6_ADDRSTRLEN) {
523 fprintf(stderr,"my_inet_ntop: invalid size argument\n");
524 exit(-1);
525 }
526
527
528 /* address is 128 bits == 16 bytes == 8 shorts */
529 for (i = 0; i < 8; i++) {
530 u_short twobytes = ntohs(src_shorts[i]);
531
532 /* handle shorthand notation */
533 if (twobytes == 0) {
534 if (doing_shorthand) {
535 /* just eat it and continue (except last 2 bytes) */
536 if (i != 7)
537 continue;
538 } else if (!did_shorthand) {
539 /* start shorthand */
540 doing_shorthand = TRUE;
541 continue;
542 }
543 }
544
545 /* terminate shorthand (on non-zero or last 2 bytes) */
546 if (doing_shorthand) {
547 doing_shorthand = FALSE;
548 did_shorthand = TRUE;
549 sprintf(dst, ":");
550 dst += 1;
551 }
552
553 sprintf(dst, "%04x:", twobytes);
554 dst += 5;
555 }
556
557 /* nuke the trailing ':' */
558 *(dst-1) = '\0';
559
560 return(ret);
561 }
562
563
564
565 /* given an IPv4 IP address, return a pointer to a (static) ipaddr struct */
566 struct ipaddr *
IPV4ADDR2ADDR(struct in_addr * addr4)567 IPV4ADDR2ADDR(
568 struct in_addr *addr4)
569 {
570 static struct ipaddr addr;
571
572 addr.addr_vers = 4;
573 addr.un.ip4.s_addr = addr4->s_addr;
574
575 return(&addr);
576 }
577
578
579 /* given an IPv6 IP address, return a pointer to a (static) ipaddr struct */
580 struct ipaddr *
IPV6ADDR2ADDR(struct in6_addr * addr6)581 IPV6ADDR2ADDR(
582 struct in6_addr *addr6)
583 {
584 static struct ipaddr addr;
585
586 addr.addr_vers = 6;
587 memcpy(&addr.un.ip6.s6_addr,&addr6->s6_addr, 16);
588
589 return(&addr);
590 }
591
592
593 /* given an internet address (IPv4 dotted decimal or IPv6 hex colon),
594 return an "ipaddr" (allocated from heap) */
595 ipaddr *
str2ipaddr(char * str)596 str2ipaddr(
597 char *str)
598 {
599 ipaddr *pipaddr;
600
601 /* allocate space */
602 pipaddr = MallocZ(sizeof(ipaddr));
603
604 /* N.B. - uses standard IPv6 facility inet_pton from RFC draft */
605 if (strchr(str,'.') != NULL) {
606 /* has dots, better be IPv4 */
607 pipaddr->addr_vers = 4;
608 if (inet_pton(AF_INET, str,
609 &pipaddr->un.ip4.s_addr) != 1) {
610 if (debug)
611 fprintf(stderr,"Address string '%s' unparsable as IPv4\n",
612 str);
613 return(NULL);
614 }
615 } else if (strchr(str,':') != NULL) {
616 /* has colons, better be IPv6 */
617 pipaddr->addr_vers = 6;
618 if (inet_pton(AF_INET6, str,
619 &pipaddr->un.ip6.s6_addr) != 1) {
620 if (debug)
621 fprintf(stderr,"Address string '%s' unparsable as IPv6\n",
622 str);
623 return(NULL);
624 }
625 } else {
626 if (debug)
627 fprintf(stderr,"Address string '%s' unparsable\n", str);
628 return(NULL);
629 }
630
631 return(pipaddr);
632 }
633
634
635 /* compare two IP addresses */
636 /* result: */
637 /* -2: different address types */
638 /* -1: A < B */
639 /* 0: A = B */
640 /* 1: A > B */
IPcmp(ipaddr * pipA,ipaddr * pipB)641 int IPcmp(
642 ipaddr *pipA,
643 ipaddr *pipB)
644 {
645 int i;
646 int len = (pipA->addr_vers == 4)?4:6;
647 u_char *left = (u_char *)&pipA->un.ip4;
648 u_char *right = (u_char *)&pipB->un.ip4;
649
650 /* always returns -2 unless both same type */
651 if (pipA->addr_vers != pipB->addr_vers) {
652 if (debug>1) {
653 printf("IPcmp %s", HostAddr(*pipA));
654 printf("%s fails, different addr types\n",
655 HostAddr(*pipB));
656 }
657 return(-2);
658 }
659
660
661 for (i=0; i < len; ++i) {
662 if (left[i] < right[i]) {
663 return(-1);
664 } else if (left[i] > right[i]) {
665 return(1);
666 }
667 /* else ==, keep going */
668 }
669
670 /* if we got here, they're the same */
671 return(0);
672 }
673
674
675 /* Added Aug 31, 2001 -- Avinash
676 * computes the total length of all the extension headers
677 */
total_length_ext_headers(struct ipv6 * pip6)678 int total_length_ext_headers(
679 struct ipv6 *pip6)
680 {
681 char nextheader;
682 struct ipv6_ext *pheader;
683 u_int total_length = 0;
684
685 /* find the first header */
686 nextheader = pip6->ip6_nheader;
687 pheader = (struct ipv6_ext *)(pip6+1);
688
689
690 while(1) {
691 switch(nextheader) {
692 case IPPROTO_HOPOPTS:
693 case IPPROTO_ROUTING:
694 case IPPROTO_DSTOPTS:
695 total_length = 8 + (pheader->ip6ext_len * 8);
696 nextheader = pheader->ip6ext_nheader;
697 pheader = (struct ipv6_ext *)
698 ((char *)pheader + 8 + (pheader->ip6ext_len)*8);
699 break;
700
701 case IPPROTO_FRAGMENT:
702 total_length += 8;
703 nextheader = pheader->ip6ext_nheader;
704 pheader = (struct ipv6_ext *)((char *)pheader + 8);
705 break;
706
707 case IPPROTO_NONE: /* End of extension headers */
708 return(total_length);
709
710 case IPPROTO_TCP: /* No extension headers */
711 return(0);
712
713 default: /* Unknown type */
714 return(-1);
715 }
716 }
717 }
718
719