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