1 /*
2 * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
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 /* \summary: IP printer */
23
24 #include <config.h>
25
26 #include "netdissect-stdinc.h"
27
28 #include "netdissect.h"
29 #include "addrtoname.h"
30 #include "extract.h"
31
32 #include "ip.h"
33 #include "ipproto.h"
34
35
36 static const struct tok ip_option_values[] = {
37 { IPOPT_EOL, "EOL" },
38 { IPOPT_NOP, "NOP" },
39 { IPOPT_TS, "timestamp" },
40 { IPOPT_SECURITY, "security" },
41 { IPOPT_RR, "RR" },
42 { IPOPT_SSRR, "SSRR" },
43 { IPOPT_LSRR, "LSRR" },
44 { IPOPT_RA, "RA" },
45 { IPOPT_RFC1393, "traceroute" },
46 { 0, NULL }
47 };
48
49 /*
50 * print the recorded route in an IP RR, LSRR or SSRR option.
51 */
52 static int
ip_printroute(netdissect_options * ndo,const u_char * cp,u_int length)53 ip_printroute(netdissect_options *ndo,
54 const u_char *cp, u_int length)
55 {
56 u_int ptr;
57 u_int len;
58
59 if (length < 3) {
60 ND_PRINT(" [bad length %u]", length);
61 return (0);
62 }
63 if ((length + 1) & 3)
64 ND_PRINT(" [bad length %u]", length);
65 ptr = GET_U_1(cp + 2) - 1;
66 if (ptr < 3 || ((ptr + 1) & 3) || ptr > length + 1)
67 ND_PRINT(" [bad ptr %u]", GET_U_1(cp + 2));
68
69 for (len = 3; len < length; len += 4) {
70 ND_TCHECK_4(cp + len); /* Needed to print the IP addresses */
71 ND_PRINT(" %s", GET_IPADDR_STRING(cp + len));
72 if (ptr > len)
73 ND_PRINT(",");
74 }
75 return (0);
76
77 trunc:
78 return (-1);
79 }
80
81 /*
82 * If source-routing is present and valid, return the final destination.
83 * Otherwise, return IP destination.
84 *
85 * This is used for UDP and TCP pseudo-header in the checksum
86 * calculation.
87 */
88 static uint32_t
ip_finddst(netdissect_options * ndo,const struct ip * ip)89 ip_finddst(netdissect_options *ndo,
90 const struct ip *ip)
91 {
92 u_int length;
93 u_int len;
94 const u_char *cp;
95
96 cp = (const u_char *)(ip + 1);
97 length = IP_HL(ip) * 4;
98 if (length < sizeof(struct ip))
99 goto trunc;
100 length -= sizeof(struct ip);
101
102 for (; length != 0; cp += len, length -= len) {
103 int tt;
104
105 tt = GET_U_1(cp);
106 if (tt == IPOPT_EOL)
107 break;
108 else if (tt == IPOPT_NOP)
109 len = 1;
110 else {
111 len = GET_U_1(cp + 1);
112 if (len < 2)
113 break;
114 }
115 if (length < len)
116 goto trunc;
117 ND_TCHECK_LEN(cp, len);
118 switch (tt) {
119
120 case IPOPT_SSRR:
121 case IPOPT_LSRR:
122 if (len < 7)
123 break;
124 return (GET_IPV4_TO_NETWORK_ORDER(cp + len - 4));
125 }
126 }
127 trunc:
128 return (GET_IPV4_TO_NETWORK_ORDER(ip->ip_dst));
129 }
130
131 /*
132 * Compute a V4-style checksum by building a pseudoheader.
133 */
134 uint16_t
nextproto4_cksum(netdissect_options * ndo,const struct ip * ip,const uint8_t * data,u_int len,u_int covlen,uint8_t next_proto)135 nextproto4_cksum(netdissect_options *ndo,
136 const struct ip *ip, const uint8_t *data,
137 u_int len, u_int covlen, uint8_t next_proto)
138 {
139 struct phdr {
140 uint32_t src;
141 uint32_t dst;
142 uint8_t mbz;
143 uint8_t proto;
144 uint16_t len;
145 } ph;
146 struct cksum_vec vec[2];
147
148 /* pseudo-header.. */
149 ph.len = htons((uint16_t)len);
150 ph.mbz = 0;
151 ph.proto = next_proto;
152 ph.src = GET_IPV4_TO_NETWORK_ORDER(ip->ip_src);
153 if (IP_HL(ip) == 5)
154 ph.dst = GET_IPV4_TO_NETWORK_ORDER(ip->ip_dst);
155 else
156 ph.dst = ip_finddst(ndo, ip);
157
158 vec[0].ptr = (const uint8_t *)(void *)&ph;
159 vec[0].len = sizeof(ph);
160 vec[1].ptr = data;
161 vec[1].len = covlen;
162 return (in_cksum(vec, 2));
163 }
164
165 static int
ip_printts(netdissect_options * ndo,const u_char * cp,u_int length)166 ip_printts(netdissect_options *ndo,
167 const u_char *cp, u_int length)
168 {
169 u_int ptr;
170 u_int len;
171 u_int hoplen;
172 const char *type;
173
174 if (length < 4) {
175 ND_PRINT("[bad length %u]", length);
176 return (0);
177 }
178 ND_PRINT(" TS{");
179 hoplen = ((GET_U_1(cp + 3) & 0xF) != IPOPT_TS_TSONLY) ? 8 : 4;
180 if ((length - 4) & (hoplen-1))
181 ND_PRINT("[bad length %u]", length);
182 ptr = GET_U_1(cp + 2) - 1;
183 len = 0;
184 if (ptr < 4 || ((ptr - 4) & (hoplen-1)) || ptr > length + 1)
185 ND_PRINT("[bad ptr %u]", GET_U_1(cp + 2));
186 switch (GET_U_1(cp + 3)&0xF) {
187 case IPOPT_TS_TSONLY:
188 ND_PRINT("TSONLY");
189 break;
190 case IPOPT_TS_TSANDADDR:
191 ND_PRINT("TS+ADDR");
192 break;
193 case IPOPT_TS_PRESPEC:
194 ND_PRINT("PRESPEC");
195 break;
196 default:
197 ND_PRINT("[bad ts type %u]", GET_U_1(cp + 3)&0xF);
198 goto done;
199 }
200
201 type = " ";
202 for (len = 4; len < length; len += hoplen) {
203 if (ptr == len)
204 type = " ^ ";
205 ND_TCHECK_LEN(cp + len, hoplen);
206 ND_PRINT("%s%u@%s", type, GET_BE_U_4(cp + len + hoplen - 4),
207 hoplen!=8 ? "" : GET_IPADDR_STRING(cp + len));
208 type = " ";
209 }
210
211 done:
212 ND_PRINT("%s", ptr == len ? " ^ " : "");
213
214 if (GET_U_1(cp + 3) >> 4)
215 ND_PRINT(" [%u hops not recorded]} ", GET_U_1(cp + 3)>>4);
216 else
217 ND_PRINT("}");
218 return (0);
219
220 trunc:
221 return (-1);
222 }
223
224 /*
225 * print IP options.
226 If truncated return -1, else 0.
227 */
228 static int
ip_optprint(netdissect_options * ndo,const u_char * cp,u_int length)229 ip_optprint(netdissect_options *ndo,
230 const u_char *cp, u_int length)
231 {
232 u_int option_len;
233 const char *sep = "";
234
235 for (; length > 0; cp += option_len, length -= option_len) {
236 u_int option_code;
237
238 ND_PRINT("%s", sep);
239 sep = ",";
240
241 option_code = GET_U_1(cp);
242
243 ND_PRINT("%s",
244 tok2str(ip_option_values,"unknown %u",option_code));
245
246 if (option_code == IPOPT_NOP ||
247 option_code == IPOPT_EOL)
248 option_len = 1;
249
250 else {
251 option_len = GET_U_1(cp + 1);
252 if (option_len < 2) {
253 ND_PRINT(" [bad length %u]", option_len);
254 return 0;
255 }
256 }
257
258 if (option_len > length) {
259 ND_PRINT(" [bad length %u]", option_len);
260 return 0;
261 }
262
263 ND_TCHECK_LEN(cp, option_len);
264
265 switch (option_code) {
266 case IPOPT_EOL:
267 return 0;
268
269 case IPOPT_TS:
270 if (ip_printts(ndo, cp, option_len) == -1)
271 goto trunc;
272 break;
273
274 case IPOPT_RR: /* fall through */
275 case IPOPT_SSRR:
276 case IPOPT_LSRR:
277 if (ip_printroute(ndo, cp, option_len) == -1)
278 goto trunc;
279 break;
280
281 case IPOPT_RA:
282 if (option_len < 4) {
283 ND_PRINT(" [bad length %u]", option_len);
284 break;
285 }
286 ND_TCHECK_1(cp + 3);
287 if (GET_BE_U_2(cp + 2) != 0)
288 ND_PRINT(" value %u", GET_BE_U_2(cp + 2));
289 break;
290
291 case IPOPT_NOP: /* nothing to print - fall through */
292 case IPOPT_SECURITY:
293 default:
294 break;
295 }
296 }
297 return 0;
298
299 trunc:
300 return -1;
301 }
302
303 #define IP_RES 0x8000
304
305 static const struct tok ip_frag_values[] = {
306 { IP_MF, "+" },
307 { IP_DF, "DF" },
308 { IP_RES, "rsvd" }, /* The RFC3514 evil ;-) bit */
309 { 0, NULL }
310 };
311
312
313 /*
314 * print an IP datagram.
315 */
316 void
ip_print(netdissect_options * ndo,const u_char * bp,const u_int length)317 ip_print(netdissect_options *ndo,
318 const u_char *bp,
319 const u_int length)
320 {
321 const struct ip *ip;
322 u_int off;
323 u_int hlen;
324 u_int len;
325 struct cksum_vec vec[1];
326 uint8_t ip_tos, ip_ttl, ip_proto;
327 uint16_t sum, ip_sum;
328 const char *p_name;
329 int truncated = 0;
330 int presumed_tso = 0;
331
332 ndo->ndo_protocol = "ip";
333 ip = (const struct ip *)bp;
334
335 if (!ndo->ndo_eflag) {
336 nd_print_protocol_caps(ndo);
337 ND_PRINT(" ");
338 }
339
340 ND_ICHECK_ZU(length, <, sizeof (struct ip));
341 ND_ICHECKMSG_U("version", IP_V(ip), !=, 4);
342
343 hlen = IP_HL(ip) * 4;
344 ND_ICHECKMSG_ZU("header length", hlen, <, sizeof (struct ip));
345
346 len = GET_BE_U_2(ip->ip_len);
347 if (len > length) {
348 ND_PRINT("[total length %u > length %u]", len, length);
349 nd_print_invalid(ndo);
350 ND_PRINT(" ");
351 }
352 if (len == 0) {
353 /* we guess that it is a TSO send */
354 len = length;
355 presumed_tso = 1;
356 }
357 if (len < hlen) {
358 ND_PRINT("[total length %u < header length %u]", len, hlen);
359 goto invalid;
360 }
361
362 ND_TCHECK_SIZE(ip);
363 /*
364 * Cut off the snapshot length to the end of the IP payload
365 * or the end of the data in which it's contained, whichever
366 * comes first.
367 */
368 if (!nd_push_snaplen(ndo, bp, ND_MIN(length, len))) {
369 (*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC,
370 "%s: can't push snaplen on buffer stack", __func__);
371 }
372
373 len -= hlen;
374
375 off = GET_BE_U_2(ip->ip_off);
376
377 ip_proto = GET_U_1(ip->ip_p);
378
379 if (ndo->ndo_vflag) {
380 ip_tos = GET_U_1(ip->ip_tos);
381 ND_PRINT("(tos 0x%x", ip_tos);
382 /* ECN bits */
383 switch (ip_tos & 0x03) {
384
385 case 0:
386 break;
387
388 case 1:
389 ND_PRINT(",ECT(1)");
390 break;
391
392 case 2:
393 ND_PRINT(",ECT(0)");
394 break;
395
396 case 3:
397 ND_PRINT(",CE");
398 break;
399 }
400
401 ip_ttl = GET_U_1(ip->ip_ttl);
402 if (ip_ttl >= 1)
403 ND_PRINT(", ttl %u", ip_ttl);
404
405 /*
406 * for the firewall guys, print id, offset.
407 * On all but the last stick a "+" in the flags portion.
408 * For unfragmented datagrams, note the don't fragment flag.
409 */
410 ND_PRINT(", id %u, offset %u, flags [%s], proto %s (%u)",
411 GET_BE_U_2(ip->ip_id),
412 (off & IP_OFFMASK) * 8,
413 bittok2str(ip_frag_values, "none", off & (IP_RES|IP_DF|IP_MF)),
414 tok2str(ipproto_values, "unknown", ip_proto),
415 ip_proto);
416
417 if (presumed_tso)
418 ND_PRINT(", length %u [was 0, presumed TSO]", length);
419 else
420 ND_PRINT(", length %u", GET_BE_U_2(ip->ip_len));
421
422 if ((hlen > sizeof(struct ip))) {
423 ND_PRINT(", options (");
424 if (ip_optprint(ndo, (const u_char *)(ip + 1),
425 hlen - sizeof(struct ip)) == -1) {
426 ND_PRINT(" [truncated-option]");
427 truncated = 1;
428 }
429 ND_PRINT(")");
430 }
431
432 if (!ndo->ndo_Kflag && ND_TTEST_LEN((const u_char *)ip, hlen)) {
433 vec[0].ptr = (const uint8_t *)(const void *)ip;
434 vec[0].len = hlen;
435 sum = in_cksum(vec, 1);
436 if (sum != 0) {
437 ip_sum = GET_BE_U_2(ip->ip_sum);
438 ND_PRINT(", bad cksum %x (->%x)!", ip_sum,
439 in_cksum_shouldbe(ip_sum, sum));
440 }
441 }
442
443 if (ndo->ndo_gflag)
444 ND_PRINT(") ");
445 else
446 ND_PRINT(")\n ");
447 if (truncated) {
448 ND_PRINT("%s > %s: ",
449 GET_IPADDR_STRING(ip->ip_src),
450 GET_IPADDR_STRING(ip->ip_dst));
451 nd_print_trunc(ndo);
452 nd_pop_packet_info(ndo);
453 return;
454 }
455 }
456
457 /*
458 * If this is fragment zero, hand it to the next higher
459 * level protocol. Let them know whether there are more
460 * fragments.
461 */
462 if ((off & IP_OFFMASK) == 0) {
463 uint8_t nh = GET_U_1(ip->ip_p);
464
465 if (nh != IPPROTO_TCP && nh != IPPROTO_UDP &&
466 nh != IPPROTO_SCTP && nh != IPPROTO_DCCP) {
467 ND_PRINT("%s > %s: ",
468 GET_IPADDR_STRING(ip->ip_src),
469 GET_IPADDR_STRING(ip->ip_dst));
470 }
471 /*
472 * Do a bounds check before calling ip_demux_print().
473 * At least the header data is required.
474 */
475 if (!ND_TTEST_LEN((const u_char *)ip, hlen)) {
476 ND_PRINT(" [remaining caplen(%u) < header length(%u)]",
477 ND_BYTES_AVAILABLE_AFTER((const u_char *)ip),
478 hlen);
479 nd_trunc_longjmp(ndo);
480 }
481 ip_demux_print(ndo, (const u_char *)ip + hlen, len, 4,
482 off & IP_MF, GET_U_1(ip->ip_ttl), nh, bp);
483 } else {
484 /*
485 * Ultra quiet now means that all this stuff should be
486 * suppressed.
487 */
488 if (ndo->ndo_qflag > 1) {
489 nd_pop_packet_info(ndo);
490 return;
491 }
492
493 /*
494 * This isn't the first frag, so we're missing the
495 * next level protocol header. print the ip addr
496 * and the protocol.
497 */
498 ND_PRINT("%s > %s:", GET_IPADDR_STRING(ip->ip_src),
499 GET_IPADDR_STRING(ip->ip_dst));
500 if (!ndo->ndo_nflag && (p_name = netdb_protoname(ip_proto)) != NULL)
501 ND_PRINT(" %s", p_name);
502 else
503 ND_PRINT(" ip-proto-%u", ip_proto);
504 }
505 nd_pop_packet_info(ndo);
506 return;
507
508 trunc:
509 nd_print_trunc(ndo);
510 return;
511
512 invalid:
513 nd_print_invalid(ndo);
514 }
515
516 void
ipN_print(netdissect_options * ndo,const u_char * bp,u_int length)517 ipN_print(netdissect_options *ndo, const u_char *bp, u_int length)
518 {
519 ndo->ndo_protocol = "ipn";
520 if (length < 1) {
521 ND_PRINT("truncated-ip %u", length);
522 return;
523 }
524
525 switch (GET_U_1(bp) & 0xF0) {
526 case 0x40:
527 ip_print(ndo, bp, length);
528 break;
529 case 0x60:
530 ip6_print(ndo, bp, length);
531 break;
532 default:
533 ND_PRINT("unknown ip %u", (GET_U_1(bp) & 0xF0) >> 4);
534 break;
535 }
536 }
537