]> git.saurik.com Git - apple/network_cmds.git/blob - tcpdump.tproj/print-ip.c
6c0c31cea4e1397d079234d7df7ce341e110d35b
[apple/network_cmds.git] / tcpdump.tproj / print-ip.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24 /*
25 * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996
26 * The Regents of the University of California. All rights reserved.
27 *
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that: (1) source code distributions
30 * retain the above copyright notice and this paragraph in its entirety, (2)
31 * distributions including binary code include the above copyright notice and
32 * this paragraph in its entirety in the documentation or other materials
33 * provided with the distribution, and (3) all advertising materials mentioning
34 * features or use of this software display the following acknowledgement:
35 * ``This product includes software developed by the University of California,
36 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
37 * the University nor the names of its contributors may be used to endorse
38 * or promote products derived from this software without specific prior
39 * written permission.
40 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
41 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
42 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
43 */
44
45 #ifndef lint
46 static const char rcsid[] =
47 "@(#) $Header: /cvs/Darwin/Commands/NeXT/network_cmds/tcpdump.tproj/print-ip.c,v 1.1.1.1 1999/05/02 03:58:33 wsanchez Exp $ (LBL)";
48 #endif
49
50 #include <sys/param.h>
51 #include <sys/time.h>
52 #include <sys/socket.h>
53
54 #include <netinet/in.h>
55 #include <netinet/in_systm.h>
56 #include <netinet/ip.h>
57 #include <netinet/ip_var.h>
58 #include <netinet/udp.h>
59 #include <netinet/udp_var.h>
60 #include <netinet/tcp.h>
61 #include <netinet/tcpip.h>
62
63 #include <stdio.h>
64 #include <stdlib.h>
65 #include <string.h>
66 #include <unistd.h>
67
68 #include "addrtoname.h"
69 #include "interface.h"
70 #include "extract.h" /* must come after interface.h */
71
72 /* Compatibility */
73 #ifndef IPPROTO_ND
74 #define IPPROTO_ND 77
75 #endif
76
77 #ifndef IN_CLASSD
78 #define IN_CLASSD(i) (((int32_t)(i) & 0xf0000000) == 0xe0000000)
79 #endif
80
81 /* (following from ipmulti/mrouted/prune.h) */
82
83 /*
84 * The packet format for a traceroute request.
85 */
86 struct tr_query {
87 u_int tr_src; /* traceroute source */
88 u_int tr_dst; /* traceroute destination */
89 u_int tr_raddr; /* traceroute response address */
90 #ifdef WORDS_BIGENDIAN
91 struct {
92 u_int ttl : 8; /* traceroute response ttl */
93 u_int qid : 24; /* traceroute query id */
94 } q;
95 #else
96 struct {
97 u_int qid : 24; /* traceroute query id */
98 u_int ttl : 8; /* traceroute response ttl */
99 } q;
100 #endif
101 };
102
103 #define tr_rttl q.ttl
104 #define tr_qid q.qid
105
106 /*
107 * Traceroute response format. A traceroute response has a tr_query at the
108 * beginning, followed by one tr_resp for each hop taken.
109 */
110 struct tr_resp {
111 u_int tr_qarr; /* query arrival time */
112 u_int tr_inaddr; /* incoming interface address */
113 u_int tr_outaddr; /* outgoing interface address */
114 u_int tr_rmtaddr; /* parent address in source tree */
115 u_int tr_vifin; /* input packet count on interface */
116 u_int tr_vifout; /* output packet count on interface */
117 u_int tr_pktcnt; /* total incoming packets for src-grp */
118 u_char tr_rproto; /* routing proto deployed on router */
119 u_char tr_fttl; /* ttl required to forward on outvif */
120 u_char tr_smask; /* subnet mask for src addr */
121 u_char tr_rflags; /* forwarding error codes */
122 };
123
124 /* defs within mtrace */
125 #define TR_QUERY 1
126 #define TR_RESP 2
127
128 /* fields for tr_rflags (forwarding error codes) */
129 #define TR_NO_ERR 0
130 #define TR_WRONG_IF 1
131 #define TR_PRUNED 2
132 #define TR_OPRUNED 3
133 #define TR_SCOPED 4
134 #define TR_NO_RTE 5
135 #define TR_NO_FWD 7
136 #define TR_NO_SPACE 0x81
137 #define TR_OLD_ROUTER 0x82
138
139 /* fields for tr_rproto (routing protocol) */
140 #define TR_PROTO_DVMRP 1
141 #define TR_PROTO_MOSPF 2
142 #define TR_PROTO_PIM 3
143 #define TR_PROTO_CBT 4
144
145 static void print_mtrace(register const u_char *bp, register u_int len)
146 {
147 register struct tr_query *tr = (struct tr_query *)(bp + 8);
148
149 printf("mtrace %d: %s to %s reply-to %s", tr->tr_qid,
150 ipaddr_string(&tr->tr_src), ipaddr_string(&tr->tr_dst),
151 ipaddr_string(&tr->tr_raddr));
152 if (IN_CLASSD(ntohl(tr->tr_raddr)))
153 printf(" with-ttl %d", tr->tr_rttl);
154 }
155
156 static void print_mresp(register const u_char *bp, register u_int len)
157 {
158 register struct tr_query *tr = (struct tr_query *)(bp + 8);
159
160 printf("mresp %d: %s to %s reply-to %s", tr->tr_qid,
161 ipaddr_string(&tr->tr_src), ipaddr_string(&tr->tr_dst),
162 ipaddr_string(&tr->tr_raddr));
163 if (IN_CLASSD(ntohl(tr->tr_raddr)))
164 printf(" with-ttl %d", tr->tr_rttl);
165 }
166
167 static void
168 igmp_print(register const u_char *bp, register u_int len,
169 register const u_char *bp2)
170 {
171 register const struct ip *ip;
172
173 ip = (const struct ip *)bp2;
174 (void)printf("%s > %s: ",
175 ipaddr_string(&ip->ip_src),
176 ipaddr_string(&ip->ip_dst));
177
178 TCHECK2(bp[0], 8);
179 switch (bp[0]) {
180 case 0x11:
181 (void)printf("igmp query");
182 if (*(int *)&bp[4])
183 (void)printf(" [gaddr %s]", ipaddr_string(&bp[4]));
184 if (len != 8)
185 (void)printf(" [len %d]", len);
186 break;
187 case 0x12:
188 (void)printf("igmp report %s", ipaddr_string(&bp[4]));
189 if (len != 8)
190 (void)printf(" [len %d]", len);
191 break;
192 case 0x16:
193 (void)printf("igmp nreport %s", ipaddr_string(&bp[4]));
194 break;
195 case 0x17:
196 (void)printf("igmp leave %s", ipaddr_string(&bp[4]));
197 break;
198 case 0x13:
199 (void)printf("igmp dvmrp");
200 if (len < 8)
201 (void)printf(" [len %d]", len);
202 else
203 dvmrp_print(bp, len);
204 break;
205 case 0x14:
206 (void)printf("igmp pim");
207 pim_print(bp, len);
208 break;
209 case 0x1e:
210 print_mresp(bp, len);
211 break;
212 case 0x1f:
213 print_mtrace(bp, len);
214 break;
215 default:
216 (void)printf("igmp-%d", bp[0] & 0xf);
217 break;
218 }
219 if ((bp[0] >> 4) != 1)
220 (void)printf(" [v%d]", bp[0] >> 4);
221
222 TCHECK2(bp[0], len);
223 if (vflag) {
224 /* Check the IGMP checksum */
225 u_int32_t sum = 0;
226 int count;
227 const u_short *sp = (u_short *)bp;
228
229 for (count = len / 2; --count >= 0; )
230 sum += *sp++;
231 if (len & 1)
232 sum += ntohs(*(u_char *) sp << 8);
233 while (sum >> 16)
234 sum = (sum & 0xffff) + (sum >> 16);
235 sum = 0xffff & ~sum;
236 if (sum != 0)
237 printf(" bad igmp cksum %x!", EXTRACT_16BITS(&bp[2]));
238 }
239 return;
240 trunc:
241 fputs("[|igmp]", stdout);
242 }
243
244 /*
245 * print the recorded route in an IP RR, LSRR or SSRR option.
246 */
247 static void
248 ip_printroute(const char *type, register const u_char *cp, u_int length)
249 {
250 register u_int ptr = cp[2] - 1;
251 register u_int len;
252
253 printf(" %s{", type);
254 if ((length + 1) & 3)
255 printf(" [bad length %d]", length);
256 if (ptr < 3 || ((ptr + 1) & 3) || ptr > length + 1)
257 printf(" [bad ptr %d]", cp[2]);
258
259 type = "";
260 for (len = 3; len < length; len += 4) {
261 if (ptr == len)
262 type = "#";
263 printf("%s%s", type, ipaddr_string(&cp[len]));
264 type = " ";
265 }
266 printf("%s}", ptr == len? "#" : "");
267 }
268
269 /*
270 * print IP options.
271 */
272 static void
273 ip_optprint(register const u_char *cp, u_int length)
274 {
275 register u_int len;
276
277 for (; length > 0; cp += len, length -= len) {
278 int tt = *cp;
279
280 len = (tt == IPOPT_NOP || tt == IPOPT_EOL) ? 1 : cp[1];
281 if (len <= 0) {
282 printf("[|ip op len %d]", len);
283 return;
284 }
285 if (&cp[1] >= snapend || cp + len > snapend) {
286 printf("[|ip]");
287 return;
288 }
289 switch (tt) {
290
291 case IPOPT_EOL:
292 printf(" EOL");
293 if (length > 1)
294 printf("-%d", length - 1);
295 return;
296
297 case IPOPT_NOP:
298 printf(" NOP");
299 break;
300
301 case IPOPT_TS:
302 printf(" TS{%d}", len);
303 break;
304
305 case IPOPT_SECURITY:
306 printf(" SECURITY{%d}", len);
307 break;
308
309 case IPOPT_RR:
310 printf(" RR{%d}=", len);
311 ip_printroute("RR", cp, len);
312 break;
313
314 case IPOPT_SSRR:
315 ip_printroute("SSRR", cp, len);
316 break;
317
318 case IPOPT_LSRR:
319 ip_printroute("LSRR", cp, len);
320 break;
321
322 default:
323 printf(" IPOPT-%d{%d}", cp[0], len);
324 break;
325 }
326 }
327 }
328
329 /*
330 * compute an IP header checksum.
331 * don't modifiy the packet.
332 */
333 static int
334 in_cksum(const struct ip *ip)
335 {
336 register const u_short *sp = (u_short *)ip;
337 register u_int32_t sum = 0;
338 register int count;
339
340 /*
341 * No need for endian conversions.
342 */
343 for (count = ip->ip_hl * 2; --count >= 0; )
344 sum += *sp++;
345 while (sum > 0xffff)
346 sum = (sum & 0xffff) + (sum >> 16);
347 sum = ~sum & 0xffff;
348
349 return (sum);
350 }
351
352 /*
353 * print an IP datagram.
354 */
355 void
356 ip_print(register const u_char *bp, register u_int length)
357 {
358 register const struct ip *ip;
359 register u_int hlen, len, off;
360 register const u_char *cp;
361
362 ip = (const struct ip *)bp;
363 #ifdef LBL_ALIGN
364 /*
365 * If the IP header is not aligned, copy into abuf.
366 * This will never happen with BPF. It does happen raw packet
367 * dumps from -r.
368 */
369 if ((long)ip & 3) {
370 static u_char *abuf = NULL;
371 static int didwarn = 0;
372
373 if (abuf == NULL) {
374 abuf = (u_char *)malloc(snaplen);
375 if (abuf == NULL)
376 error("ip_print: malloc");
377 }
378 memcpy((char *)abuf, (char *)ip, min(length, snaplen));
379 snapend += abuf - (u_char *)ip;
380 packetp = abuf;
381 ip = (struct ip *)abuf;
382 /* We really want libpcap to give us aligned packets */
383 if (!didwarn) {
384 warning("compensating for unaligned libpcap packets");
385 ++didwarn;
386 }
387 }
388 #endif
389 if ((u_char *)(ip + 1) > snapend) {
390 printf("[|ip]");
391 return;
392 }
393 if (length < sizeof (struct ip)) {
394 (void)printf("truncated-ip %d", length);
395 return;
396 }
397 hlen = ip->ip_hl * 4;
398
399 len = ntohs(ip->ip_len);
400 if (length < len)
401 (void)printf("truncated-ip - %d bytes missing!",
402 len - length);
403 len -= hlen;
404
405 /*
406 * If this is fragment zero, hand it to the next higher
407 * level protocol.
408 */
409 off = ntohs(ip->ip_off);
410 if ((off & 0x1fff) == 0) {
411 cp = (const u_char *)ip + hlen;
412 switch (ip->ip_p) {
413
414 case IPPROTO_TCP:
415 tcp_print(cp, len, (const u_char *)ip);
416 break;
417
418 case IPPROTO_UDP:
419 udp_print(cp, len, (const u_char *)ip);
420 break;
421
422 case IPPROTO_ICMP:
423 icmp_print(cp, (const u_char *)ip);
424 break;
425
426 #ifndef IPPROTO_IGRP
427 #define IPPROTO_IGRP 9
428 #endif
429 case IPPROTO_IGRP:
430 igrp_print(cp, len, (const u_char *)ip);
431 break;
432
433 case IPPROTO_ND:
434 (void)printf("%s > %s:", ipaddr_string(&ip->ip_src),
435 ipaddr_string(&ip->ip_dst));
436 (void)printf(" nd %d", len);
437 break;
438
439 case IPPROTO_EGP:
440 egp_print(cp, len, (const u_char *)ip);
441 break;
442
443 #ifndef IPPROTO_OSPF
444 #define IPPROTO_OSPF 89
445 #endif
446 case IPPROTO_OSPF:
447 ospf_print(cp, len, (const u_char *)ip);
448 break;
449
450 #ifndef IPPROTO_IGMP
451 #define IPPROTO_IGMP 2
452 #endif
453 case IPPROTO_IGMP:
454 igmp_print(cp, len, (const u_char *)ip);
455 break;
456
457 #ifndef IPPROTO_ENCAP
458 #define IPPROTO_ENCAP 4
459 #endif
460 case IPPROTO_ENCAP:
461 /* ip-in-ip encapsulation */
462 if (vflag)
463 (void)printf("%s > %s: ",
464 ipaddr_string(&ip->ip_src),
465 ipaddr_string(&ip->ip_dst));
466 ip_print(cp, len);
467 if (! vflag) {
468 printf(" (encap)");
469 return;
470 }
471 break;
472
473 #ifndef IPPROTO_GRE
474 #define IPPROTO_GRE 47
475 #endif
476 case IPPROTO_GRE:
477 if (vflag)
478 (void)printf("gre %s > %s: ",
479 ipaddr_string(&ip->ip_src),
480 ipaddr_string(&ip->ip_dst));
481 /* do it */
482 gre_print(cp, len);
483 if (! vflag) {
484 printf(" (gre encap)");
485 return;
486 }
487 break;
488
489 default:
490 (void)printf("%s > %s:", ipaddr_string(&ip->ip_src),
491 ipaddr_string(&ip->ip_dst));
492 (void)printf(" ip-proto-%d %d", ip->ip_p, len);
493 break;
494 }
495 }
496 /*
497 * for fragmented datagrams, print id:size@offset. On all
498 * but the last stick a "+". For unfragmented datagrams, note
499 * the don't fragment flag.
500 */
501 if (off & 0x3fff) {
502 /*
503 * if this isn't the first frag, we're missing the
504 * next level protocol header. print the ip addr.
505 */
506 if (off & 0x1fff)
507 (void)printf("%s > %s:", ipaddr_string(&ip->ip_src),
508 ipaddr_string(&ip->ip_dst));
509 (void)printf(" (frag %d:%d@%d%s)", ntohs(ip->ip_id), len,
510 (off & 0x1fff) * 8,
511 (off & IP_MF)? "+" : "");
512 } else if (off & IP_DF)
513 (void)printf(" (DF)");
514
515 if (ip->ip_tos)
516 (void)printf(" [tos 0x%x]", (int)ip->ip_tos);
517 if (ip->ip_ttl <= 1)
518 (void)printf(" [ttl %d]", (int)ip->ip_ttl);
519
520 if (vflag) {
521 int sum;
522 char *sep = "";
523
524 printf(" (");
525 if (ip->ip_ttl > 1) {
526 (void)printf("%sttl %d", sep, (int)ip->ip_ttl);
527 sep = ", ";
528 }
529 if ((off & 0x3fff) == 0) {
530 (void)printf("%sid %d", sep, (int)ntohs(ip->ip_id));
531 sep = ", ";
532 }
533 if ((u_char *)ip + hlen <= snapend) {
534 sum = in_cksum(ip);
535 if (sum != 0) {
536 (void)printf("%sbad cksum %x!", sep,
537 ntohs(ip->ip_sum));
538 sep = ", ";
539 }
540 }
541 if ((hlen -= sizeof(struct ip)) > 0) {
542 (void)printf("%soptlen=%d", sep, hlen);
543 ip_optprint((u_char *)(ip + 1), hlen);
544 }
545 printf(")");
546 }
547 }