print-ip.c revision 26183
1292932Sdim/*
2292932Sdim * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996
3353358Sdim *	The Regents of the University of California.  All rights reserved.
4353358Sdim *
5353358Sdim * Redistribution and use in source and binary forms, with or without
6292932Sdim * modification, are permitted provided that: (1) source code distributions
7292932Sdim * retain the above copyright notice and this paragraph in its entirety, (2)
8292932Sdim * distributions including binary code include the above copyright notice and
9292932Sdim * this paragraph in its entirety in the documentation or other materials
10292932Sdim * provided with the distribution, and (3) all advertising materials mentioning
11292932Sdim * features or use of this software display the following acknowledgement:
12353358Sdim * ``This product includes software developed by the University of California,
13341825Sdim * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14321369Sdim * the University nor the names of its contributors may be used to endorse
15321369Sdim * or promote products derived from this software without specific prior
16321369Sdim * written permission.
17292932Sdim * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18309124Sdim * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19309124Sdim * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20292932Sdim */
21292932Sdim
22292932Sdim#ifndef lint
23292932Sdimstatic const char rcsid[] =
24292932Sdim    "@(#) $Header: print-ip.c,v 1.62 96/12/10 23:20:31 leres Exp $ (LBL)";
25314564Sdim#endif
26360784Sdim
27292932Sdim#include <sys/param.h>
28314564Sdim#include <sys/time.h>
29314564Sdim#include <sys/socket.h>
30314564Sdim
31292932Sdim#include <netinet/in.h>
32292932Sdim#include <netinet/in_systm.h>
33314564Sdim#include <netinet/ip.h>
34353358Sdim#include <netinet/ip_var.h>
35314564Sdim#include <netinet/udp.h>
36314564Sdim#include <netinet/udp_var.h>
37314564Sdim#include <netinet/tcp.h>
38314564Sdim#include <netinet/tcpip.h>
39292932Sdim
40292932Sdim#include <stdio.h>
41314564Sdim#include <stdlib.h>
42314564Sdim#include <string.h>
43314564Sdim#include <unistd.h>
44314564Sdim
45360784Sdim#include "addrtoname.h"
46360784Sdim#include "interface.h"
47314564Sdim#include "extract.h"			/* must come after interface.h */
48360784Sdim
49360784Sdim/* Compatibility */
50314564Sdim#ifndef	IPPROTO_ND
51314564Sdim#define	IPPROTO_ND	77
52360784Sdim#endif
53360784Sdim
54360784Sdim#ifndef IN_CLASSD
55360784Sdim#define IN_CLASSD(i) (((int32_t)(i) & 0xf0000000) == 0xe0000000)
56360784Sdim#endif
57360784Sdim
58360784Sdim/* (following from ipmulti/mrouted/prune.h) */
59360784Sdim
60360784Sdim/*
61360784Sdim * The packet format for a traceroute request.
62360784Sdim */
63360784Sdimstruct tr_query {
64314564Sdim	u_int  tr_src;			/* traceroute source */
65292932Sdim	u_int  tr_dst;			/* traceroute destination */
66292932Sdim	u_int  tr_raddr;		/* traceroute response address */
67353358Sdim#ifdef WORDS_BIGENDIAN
68353358Sdim	struct {
69353358Sdim		u_int   ttl : 8;	/* traceroute response ttl */
70360784Sdim		u_int   qid : 24;	/* traceroute query id */
71360784Sdim	} q;
72360784Sdim#else
73360784Sdim	struct {
74360784Sdim		u_int	qid : 24;	/* traceroute query id */
75360784Sdim		u_int	ttl : 8;	/* traceroute response ttl */
76360784Sdim	} q;
77360784Sdim#endif
78360784Sdim};
79353358Sdim
80353358Sdim#define tr_rttl q.ttl
81353358Sdim#define tr_qid  q.qid
82353358Sdim
83353358Sdim/*
84360784Sdim * Traceroute response format.  A traceroute response has a tr_query at the
85360784Sdim * beginning, followed by one tr_resp for each hop taken.
86360784Sdim */
87360784Sdimstruct tr_resp {
88314564Sdim	u_int tr_qarr;			/* query arrival time */
89314564Sdim	u_int tr_inaddr;		/* incoming interface address */
90314564Sdim	u_int tr_outaddr;		/* outgoing interface address */
91360784Sdim	u_int tr_rmtaddr;		/* parent address in source tree */
92360784Sdim	u_int tr_vifin;			/* input packet count on interface */
93360784Sdim	u_int tr_vifout;		/* output packet count on interface */
94309124Sdim	u_int tr_pktcnt;		/* total incoming packets for src-grp */
95314564Sdim	u_char  tr_rproto;		/* routing proto deployed on router */
96292932Sdim	u_char  tr_fttl;		/* ttl required to forward on outvif */
97292932Sdim	u_char  tr_smask;		/* subnet mask for src addr */
98309124Sdim	u_char  tr_rflags;		/* forwarding error codes */
99353358Sdim};
100360784Sdim
101292932Sdim/* 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		if (len != 8)
179			(void)printf(" [len %d]", len);
180		if (bp[1])
181			(void)printf(" [b1=0x%x]", bp[1]);
182		break;
183	case 0x13:
184		(void)printf("igmp dvmrp");
185		if (len < 8)
186			(void)printf(" [len %d]", len);
187		else
188			dvmrp_print(bp, len);
189		break;
190	case 0x14:
191		(void)printf("igmp pim");
192		pim_print(bp, len);
193  		break;
194	case 0x1e:
195		print_mresp(bp, len);
196		break;
197	case 0x1f:
198		print_mtrace(bp, len);
199		break;
200	default:
201		(void)printf("igmp-%d", bp[0] & 0xf);
202		if (bp[1])
203			(void)printf(" [b1=0x%02x]", bp[1]);
204		break;
205	}
206
207	TCHECK2(bp[0], len);
208	if (vflag) {
209		/* Check the IGMP checksum */
210		u_int32_t sum = 0;
211		int count;
212		const u_short *sp = (u_short *)bp;
213
214		for (count = len / 2; --count >= 0; )
215			sum += *sp++;
216		if (len & 1)
217			sum += ntohs(*(u_char *) sp << 8);
218		while (sum >> 16)
219			sum = (sum & 0xffff) + (sum >> 16);
220		sum = 0xffff & ~sum;
221		if (sum != 0)
222			printf(" bad igmp cksum %x!", EXTRACT_16BITS(&bp[2]));
223	}
224	return;
225trunc:
226	fputs("[|igmp]", stdout);
227}
228
229/*
230 * print the recorded route in an IP RR, LSRR or SSRR option.
231 */
232static void
233ip_printroute(const char *type, register const u_char *cp, u_int length)
234{
235	register u_int ptr = cp[2] - 1;
236	register u_int len;
237
238	printf(" %s{", type);
239	if ((length + 1) & 3)
240		printf(" [bad length %d]", length);
241	if (ptr < 3 || ((ptr + 1) & 3) || ptr > length + 1)
242		printf(" [bad ptr %d]", cp[2]);
243
244	type = "";
245	for (len = 3; len < length; len += 4) {
246		if (ptr == len)
247			type = "#";
248		printf("%s%s", type, ipaddr_string(&cp[len]));
249		type = " ";
250	}
251	printf("%s}", ptr == len? "#" : "");
252}
253
254/*
255 * print IP options.
256 */
257static void
258ip_optprint(register const u_char *cp, u_int length)
259{
260	register u_int len;
261
262	for (; length > 0; cp += len, length -= len) {
263		int tt = *cp;
264
265		len = (tt == IPOPT_NOP || tt == IPOPT_EOL) ? 1 : cp[1];
266		if (len <= 0) {
267			printf("[|ip op len %d]", len);
268			return;
269		}
270		if (&cp[1] >= snapend || cp + len > snapend) {
271			printf("[|ip]");
272			return;
273		}
274		switch (tt) {
275
276		case IPOPT_EOL:
277			printf(" EOL");
278			if (length > 1)
279				printf("-%d", length - 1);
280			return;
281
282		case IPOPT_NOP:
283			printf(" NOP");
284			break;
285
286		case IPOPT_TS:
287			printf(" TS{%d}", len);
288			break;
289
290		case IPOPT_SECURITY:
291			printf(" SECURITY{%d}", len);
292			break;
293
294		case IPOPT_RR:
295			printf(" RR{%d}=", len);
296			ip_printroute("RR", cp, len);
297			break;
298
299		case IPOPT_SSRR:
300			ip_printroute("SSRR", cp, len);
301			break;
302
303		case IPOPT_LSRR:
304			ip_printroute("LSRR", cp, len);
305			break;
306
307		case IPOPT_RA:
308			printf(" RA{%d}", len);
309			if (cp[2] != 0 || cp[3] != 0)
310				printf(" [b23=0x04%x]", cp[2] << 8 | cp[3]);
311			break;
312
313		default:
314			printf(" IPOPT-%d{%d}", cp[0], len);
315			break;
316		}
317	}
318}
319
320/*
321 * compute an IP header checksum.
322 * don't modifiy the packet.
323 */
324static int
325in_cksum(const struct ip *ip)
326{
327	register const u_short *sp = (u_short *)ip;
328	register u_int32_t sum = 0;
329	register int count;
330
331	/*
332	 * No need for endian conversions.
333	 */
334	for (count = ip->ip_hl * 2; --count >= 0; )
335		sum += *sp++;
336	while (sum > 0xffff)
337		sum = (sum & 0xffff) + (sum >> 16);
338	sum = ~sum & 0xffff;
339
340	return (sum);
341}
342
343/*
344 * print an IP datagram.
345 */
346void
347ip_print(register const u_char *bp, register u_int length)
348{
349	register const struct ip *ip;
350	register u_int hlen, len, off;
351	register const u_char *cp;
352
353	ip = (const struct ip *)bp;
354#ifdef LBL_ALIGN
355	/*
356	 * If the IP header is not aligned, copy into abuf.
357	 * This will never happen with BPF.  It does happen raw packet
358	 * dumps from -r.
359	 */
360	if ((long)ip & 3) {
361		static u_char *abuf = NULL;
362		static int didwarn = 0;
363
364		if (abuf == NULL) {
365			abuf = (u_char *)malloc(snaplen);
366			if (abuf == NULL)
367				error("ip_print: malloc");
368		}
369		memcpy((char *)abuf, (char *)ip, min(length, snaplen));
370		snapend += abuf - (u_char *)ip;
371		packetp = abuf;
372		ip = (struct ip *)abuf;
373		/* We really want libpcap to give us aligned packets */
374		if (!didwarn) {
375			warning("compensating for unaligned libpcap packets");
376			++didwarn;
377		}
378	}
379#endif
380	if ((u_char *)(ip + 1) > snapend) {
381		printf("[|ip]");
382		return;
383	}
384	if (length < sizeof (struct ip)) {
385		(void)printf("truncated-ip %d", length);
386		return;
387	}
388	hlen = ip->ip_hl * 4;
389
390	len = ntohs(ip->ip_len);
391	if (length < len)
392		(void)printf("truncated-ip - %d bytes missing!",
393			len - length);
394	len -= hlen;
395
396	/*
397	 * If this is fragment zero, hand it to the next higher
398	 * level protocol.
399	 */
400	off = ntohs(ip->ip_off);
401	if ((off & 0x1fff) == 0) {
402		cp = (const u_char *)ip + hlen;
403		switch (ip->ip_p) {
404
405		case IPPROTO_TCP:
406			tcp_print(cp, len, (const u_char *)ip);
407			break;
408
409		case IPPROTO_UDP:
410			udp_print(cp, len, (const u_char *)ip);
411			break;
412
413		case IPPROTO_ICMP:
414			icmp_print(cp, (const u_char *)ip);
415			break;
416
417#ifndef IPPROTO_IGRP
418#define IPPROTO_IGRP 9
419#endif
420		case IPPROTO_IGRP:
421			igrp_print(cp, len, (const u_char *)ip);
422			break;
423
424		case IPPROTO_ND:
425			(void)printf("%s > %s:", ipaddr_string(&ip->ip_src),
426				ipaddr_string(&ip->ip_dst));
427			(void)printf(" nd %d", len);
428			break;
429
430		case IPPROTO_EGP:
431			egp_print(cp, len, (const u_char *)ip);
432			break;
433
434#ifndef IPPROTO_OSPF
435#define IPPROTO_OSPF 89
436#endif
437		case IPPROTO_OSPF:
438			ospf_print(cp, len, (const u_char *)ip);
439			break;
440
441#ifndef IPPROTO_IGMP
442#define IPPROTO_IGMP 2
443#endif
444		case IPPROTO_IGMP:
445			igmp_print(cp, len, (const u_char *)ip);
446			break;
447
448#ifndef IPPROTO_IPIP
449#define IPPROTO_IPIP 4
450#endif
451		case IPPROTO_IPIP:
452			/* ip-in-ip encapsulation */
453			if (vflag)
454				(void)printf("%s > %s: ",
455					     ipaddr_string(&ip->ip_src),
456					     ipaddr_string(&ip->ip_dst));
457			ip_print(cp, len);
458			if (! vflag) {
459				printf(" (encap)");
460				return;
461			}
462			break;
463
464#ifndef IPPROTO_GRE
465#define IPPROTO_GRE 47
466#endif
467		case IPPROTO_GRE:
468			if (vflag)
469				(void)printf("gre %s > %s: ",
470					     ipaddr_string(&ip->ip_src),
471					     ipaddr_string(&ip->ip_dst));
472			/* do it */
473			gre_print(cp, len);
474			if (! vflag) {
475				printf(" (gre encap)");
476				return;
477  			}
478  			break;
479
480		default:
481			(void)printf("%s > %s:", ipaddr_string(&ip->ip_src),
482				ipaddr_string(&ip->ip_dst));
483			(void)printf(" ip-proto-%d %d", ip->ip_p, len);
484			break;
485		}
486	}
487	/*
488	 * for fragmented datagrams, print id:size@offset.  On all
489	 * but the last stick a "+".  For unfragmented datagrams, note
490	 * the don't fragment flag.
491	 */
492	if (off & 0x3fff) {
493		/*
494		 * if this isn't the first frag, we're missing the
495		 * next level protocol header.  print the ip addr.
496		 */
497		if (off & 0x1fff)
498			(void)printf("%s > %s:", ipaddr_string(&ip->ip_src),
499				      ipaddr_string(&ip->ip_dst));
500		(void)printf(" (frag %d:%d@%d%s)", ntohs(ip->ip_id), len,
501			(off & 0x1fff) * 8,
502			(off & IP_MF)? "+" : "");
503	} else if (off & IP_DF)
504		(void)printf(" (DF)");
505
506	if (ip->ip_tos)
507		(void)printf(" [tos 0x%x]", (int)ip->ip_tos);
508	if (ip->ip_ttl <= 1)
509		(void)printf(" [ttl %d]", (int)ip->ip_ttl);
510
511	if (vflag) {
512		int sum;
513		char *sep = "";
514
515		printf(" (");
516		if (ip->ip_ttl > 1) {
517			(void)printf("%sttl %d", sep, (int)ip->ip_ttl);
518			sep = ", ";
519		}
520		if ((off & 0x3fff) == 0) {
521			(void)printf("%sid %d", sep, (int)ntohs(ip->ip_id));
522			sep = ", ";
523		}
524		if ((u_char *)ip + hlen <= snapend) {
525			sum = in_cksum(ip);
526			if (sum != 0) {
527				(void)printf("%sbad cksum %x!", sep,
528					     ntohs(ip->ip_sum));
529				sep = ", ";
530			}
531		}
532		if ((hlen -= sizeof(struct ip)) > 0) {
533			(void)printf("%soptlen=%d", sep, hlen);
534			ip_optprint((u_char *)(ip + 1), hlen);
535		}
536		printf(")");
537	}
538}
539