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