tcpdump  4.99.1
About: tcpdump is a tool for network monitoring and data acquisition.
  Fossies Dox: tcpdump-4.99.1.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

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