xref: /386bsd/usr/src/usr.sbin/tcpdump/print-ip.c (revision a2142627)
1 /*
2  * Copyright (c) 1988-1990 The Regents of the University of California.
3  * 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
23 static char rcsid[] =
24     "@(#) $Header: print-ip.c,v 1.23 91/06/09 17:16:10 van Exp $ (LBL)";
25 #endif
26 
27 #include <sys/param.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <netinet/in_systm.h>
32 #include <netinet/ip.h>
33 #include <netinet/ip_var.h>
34 #include <netinet/udp.h>
35 #include <netinet/udp_var.h>
36 #include <netinet/tcp.h>
37 #include <netinet/tcpip.h>
38 
39 #include "interface.h"
40 #include "addrtoname.h"
41 
42 void
igmp_print(cp,len,ip)43 igmp_print(cp, len, ip)
44 	register u_char *cp;
45 	register int len;
46 	register struct ip *ip;
47 {
48 	register u_char *ep = (u_char *)snapend;
49 
50         (void)printf("%s > %s: ",
51 		ipaddr_string(&ip->ip_src),
52 		ipaddr_string(&ip->ip_dst));
53 
54 	if (cp + 7 > ep) {
55 		(void)printf("[|igmp]");
56 		return;
57 	}
58 	switch (cp[0] & 0xf) {
59 	case 1:
60 		(void)printf("igmp query");
61 		if (*(int *)&cp[4])
62 			(void)printf(" [gaddr %s]", ipaddr_string(&cp[4]));
63 		if (len != 8)
64 			(void)printf(" [len %d]", len);
65 		break;
66 	case 2:
67 		(void)printf("igmp report %s", ipaddr_string(&cp[4]));
68 		if (len != 8)
69 			(void)printf(" [len %d]", len);
70 		break;
71 	case 3:
72 		(void)printf("igmp dvmrp", ipaddr_string(&cp[4]));
73 		if (len < 8)
74 			(void)printf(" [len %d]", len);
75 		break;
76 	default:
77 		(void)printf("igmp-%d", cp[0] & 0xf);
78 		break;
79 	}
80 	if ((cp[0] >> 4) != 1)
81 		(void)printf(" [v%d]", cp[0] >> 4);
82 	if (cp[1])
83 		(void)printf(" [b1=0x%x]", cp[1]);
84 }
85 
86 /*
87  * print the recorded route in an IP RR, LSRR or SSRR option.
88  */
89 static void
ip_printroute(type,cp,length)90 ip_printroute(type, cp, length)
91 	char *type;
92 	register u_char *cp;
93 	int length;
94 {
95 	int ptr = cp[2] - 1;
96 	int len;
97 
98 	printf(" %s{", type);
99 	if ((length + 1) & 3)
100 		printf(" [bad length %d]", length);
101 	if (ptr < 3 || ((ptr + 1) & 3) || ptr > length + 1)
102 		printf(" [bad ptr %d]", cp[2]);
103 
104 	type = "";
105 	for (len = 3; len < length; len += 4) {
106 		if (ptr == len)
107 			type = "#";
108 #ifdef ALIGN
109 		{
110 		struct in_addr addr;
111 		bcopy((char *)&cp[len], (char *)&addr, sizeof(addr));
112 		printf("%s%s", type, ipaddr_string(&addr));
113 		}
114 #else
115 		printf("%s%s", type, ipaddr_string(&cp[len]));
116 #endif
117 		type = " ";
118 	}
119 	printf("%s}", ptr == len? "#" : "");
120 }
121 
122 /*
123  * print IP options.
124  */
125 static void
ip_optprint(cp,length)126 ip_optprint(cp, length)
127 	register u_char *cp;
128 	int length;
129 {
130 	int len;
131 
132 	for (; length > 0; cp += len, length -= len) {
133 		int tt = *cp;
134 
135 		len = (tt == IPOPT_NOP || tt == IPOPT_EOL) ? 1 : cp[1];
136 		if (&cp[1] >= snapend || cp + len > snapend) {
137 			printf("[|ip]");
138 			return;
139 		}
140 		switch (tt) {
141 
142 		case IPOPT_EOL:
143 			printf(" EOL");
144 			if (length > 1)
145 				printf("-%d", length - 1);
146 			return;
147 
148 		case IPOPT_NOP:
149 			printf(" NOP");
150 			break;
151 
152 		case IPOPT_TS:
153 			printf(" TS{%d}", len);
154 			break;
155 
156 		case IPOPT_SECURITY:
157 			printf(" SECURITY{%d}", len);
158 			break;
159 
160 		case IPOPT_RR:
161 			printf(" RR{%d}=", len);
162 			ip_printroute("RR", cp, len);
163 			break;
164 
165 		case IPOPT_SSRR:
166 			ip_printroute("SSRR", cp, len);
167 			break;
168 
169 		case IPOPT_LSRR:
170 			ip_printroute("LSRR", cp, len);
171 			break;
172 
173 		default:
174 			printf(" IPOPT-%d{%d}", cp[0], len);
175 			break;
176 		}
177 	}
178 }
179 
180 /*
181  * print an IP datagram.
182  */
183 void
ip_print(ip,length)184 ip_print(ip, length)
185 	register struct ip *ip;
186 	register int length;
187 {
188 	register int hlen;
189 	register int len;
190 	register unsigned char *cp;
191 
192 #ifdef ALIGN
193 	static u_char *abuf;
194 	/*
195 	 * The IP header is not word aligned, so copy into abuf.
196 	 * This will never happen with BPF.  Maybe with should #ifdef
197 	 * on that too. XXX
198 	 */
199 	if ((int)ip & (sizeof(long)-1)) {
200 		if (abuf == 0)
201 			abuf = (u_char *)malloc(snaplen);
202 		bcopy((char *)ip, (char *)abuf, min(length, snaplen));
203 		snapend += abuf - (u_char *)ip;
204 		packetp = abuf;
205 		ip = (struct ip *)abuf;
206 	}
207 #endif
208 	if ((u_char *)(ip + 1) > snapend) {
209 		printf("[|ip]");
210 		return;
211 	}
212 	if (length < sizeof (struct ip)) {
213 		(void)printf("truncated-ip %d", length);
214 		return;
215 	}
216 	hlen = ip->ip_hl * 4;
217 
218 	NTOHS(ip->ip_len);
219 	NTOHS(ip->ip_off);
220 	NTOHS(ip->ip_id);
221 
222 	len = ip->ip_len - hlen;
223 	if (length < ip->ip_len)
224 		(void)printf("truncated-ip - %d bytes missing!",
225 			ip->ip_len - length);
226 
227 	/*
228 	 * If this is fragment zero, hand it to the next higher
229 	 * level protocol.
230 	 */
231 	if ((ip->ip_off & 0x1fff) == 0) {
232 		cp = (unsigned char *)ip + hlen;
233 		switch (ip->ip_p) {
234 
235 		case IPPROTO_TCP:
236 			tcp_print((struct tcphdr *)cp, len, ip);
237 			break;
238 		case IPPROTO_UDP:
239 			udp_print((struct udphdr *)cp, len, ip);
240 			break;
241 		case IPPROTO_ICMP:
242 			icmp_print((struct icmp *)cp, ip);
243 			break;
244 		case IPPROTO_ND:
245 			(void)printf("%s > %s:", ipaddr_string(&ip->ip_src),
246 				ipaddr_string(&ip->ip_dst));
247 			(void)printf(" nd %d", len);
248 			break;
249 		case 2:		/* XXX - IPPROTO_IGMP */
250 			igmp_print(cp, len, ip);
251 			break;
252 		default:
253 			(void)printf("%s > %s:", ipaddr_string(&ip->ip_src),
254 				ipaddr_string(&ip->ip_dst));
255 			(void)printf(" ip-proto-%d %d", ip->ip_p, len);
256 			break;
257 		}
258 	}
259 	/*
260 	 * for fragmented datagrams, print id:size@offset.  On all
261 	 * but the last stick a "+".  For unfragmented datagrams, note
262 	 * the don't fragment flag.
263 	 */
264 	if (ip->ip_off & 0x3fff) {
265 		/*
266 		 * if this isn't the first frag, we're missing the
267 		 * next level protocol header.  print the ip addr.
268 		 */
269 		if (ip->ip_off & 0x1fff)
270 			(void)printf("%s > %s:", ipaddr_string(&ip->ip_src),
271 				      ipaddr_string(&ip->ip_dst));
272 		(void)printf(" (frag %x:%d@%d%s)", ip->ip_id, len,
273 			(ip->ip_off & 0x1fff) * 8,
274 			(ip->ip_off & IP_MF)? "+" : "");
275 	} else if (ip->ip_off & IP_DF)
276 		(void)printf(" (DF)");
277 
278 	if (ip->ip_tos)
279 		(void)printf(" [tos 0x%x]", (int)ip->ip_tos);
280 	if (ip->ip_ttl <= 1)
281 		(void)printf(" [ttl %d]", (int)ip->ip_ttl);
282 
283 	if (vflag) {
284 		char *sep = "";
285 
286 		printf(" (");
287 		if (ip->ip_ttl > 1) {
288 			(void)printf("%sttl %d", sep, (int)ip->ip_ttl);
289 			sep = ", ";
290 		}
291 		if ((ip->ip_off & 0x3fff) == 0) {
292 			(void)printf("%sid %d", sep, (int)ip->ip_id);
293 			sep = ", ";
294 		}
295 		if ((hlen -= sizeof(struct ip)) > 0) {
296 			(void)printf("%soptlen=%d", sep, hlen);
297 			ip_optprint((u_char *)(ip + 1), hlen);
298 		}
299 		printf(")");
300 	}
301 }
302