Home | History | Annotate | Download | only in tcpdump
      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 #ifndef lint
     23 static const char rcsid[] _U_ =
     24     "@(#) $Header: /tcpdump/master/tcpdump/print-ip.c,v 1.159 2007-09-14 01:29:28 guy Exp $ (LBL)";
     25 #endif
     26 
     27 #ifdef HAVE_CONFIG_H
     28 #include "config.h"
     29 #endif
     30 
     31 #include <tcpdump-stdinc.h>
     32 
     33 #include <stdio.h>
     34 #include <stdlib.h>
     35 #include <string.h>
     36 
     37 #include "addrtoname.h"
     38 #include "interface.h"
     39 #include "extract.h"			/* must come after interface.h */
     40 
     41 #include "ip.h"
     42 #include "ipproto.h"
     43 
     44 static const struct tok ip_option_values[] = {
     45     { IPOPT_EOL, "EOL" },
     46     { IPOPT_NOP, "NOP" },
     47     { IPOPT_TS, "timestamp" },
     48     { IPOPT_SECURITY, "security" },
     49     { IPOPT_RR, "RR" },
     50     { IPOPT_SSRR, "SSRR" },
     51     { IPOPT_LSRR, "LSRR" },
     52     { IPOPT_RA, "RA" },
     53     { IPOPT_RFC1393, "traceroute" },
     54     { 0, NULL }
     55 };
     56 
     57 /*
     58  * print the recorded route in an IP RR, LSRR or SSRR option.
     59  */
     60 static void
     61 ip_printroute(register const u_char *cp, u_int length)
     62 {
     63 	register u_int ptr;
     64 	register u_int len;
     65 
     66 	if (length < 3) {
     67 		printf(" [bad length %u]", length);
     68 		return;
     69 	}
     70 	if ((length + 1) & 3)
     71 		printf(" [bad length %u]", length);
     72 	ptr = cp[2] - 1;
     73 	if (ptr < 3 || ((ptr + 1) & 3) || ptr > length + 1)
     74 		printf(" [bad ptr %u]", cp[2]);
     75 
     76 	for (len = 3; len < length; len += 4) {
     77 		printf(" %s", ipaddr_string(&cp[len]));
     78                 if (ptr > len)
     79                         printf(",");
     80 	}
     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 u_int32_t
     91 ip_finddst(const struct ip *ip)
     92 {
     93 	int length;
     94 	int len;
     95 	const u_char *cp;
     96 	u_int32_t retval;
     97 
     98 	cp = (const u_char *)(ip + 1);
     99 	length = (IP_HL(ip) << 2) - sizeof(struct ip);
    100 
    101 	for (; length > 0; cp += len, length -= len) {
    102 		int tt;
    103 
    104 		TCHECK(*cp);
    105 		tt = *cp;
    106 		if (tt == IPOPT_EOL)
    107 			break;
    108 		else if (tt == IPOPT_NOP)
    109 			len = 1;
    110 		else {
    111 			TCHECK(cp[1]);
    112 			len = cp[1];
    113 			if (len < 2)
    114 				break;
    115 		}
    116 		TCHECK2(*cp, len);
    117 		switch (tt) {
    118 
    119 		case IPOPT_SSRR:
    120 		case IPOPT_LSRR:
    121 			if (len < 7)
    122 				break;
    123 			UNALIGNED_MEMCPY(&retval, cp + len - 4, 4);
    124 			return retval;
    125 		}
    126 	}
    127 trunc:
    128 	UNALIGNED_MEMCPY(&retval, &ip->ip_dst.s_addr, sizeof(u_int32_t));
    129 	return retval;
    130 }
    131 
    132 /*
    133  * Compute a V4-style checksum by building a pseudoheader.
    134  */
    135 int
    136 nextproto4_cksum(const struct ip *ip, const u_int8_t *data,
    137 		 u_int len, u_int next_proto)
    138 {
    139 	struct phdr {
    140 		u_int32_t src;
    141 		u_int32_t dst;
    142 		u_char mbz;
    143 		u_char proto;
    144 		u_int16_t len;
    145 	} ph;
    146 	struct cksum_vec vec[2];
    147 
    148 	/* pseudo-header.. */
    149 	ph.len = htons((u_int16_t)len);
    150 	ph.mbz = 0;
    151 	ph.proto = next_proto;
    152 	UNALIGNED_MEMCPY(&ph.src, &ip->ip_src.s_addr, sizeof(u_int32_t));
    153 	if (IP_HL(ip) == 5)
    154 		UNALIGNED_MEMCPY(&ph.dst, &ip->ip_dst.s_addr, sizeof(u_int32_t));
    155 	else
    156 		ph.dst = ip_finddst(ip);
    157 
    158 	vec[0].ptr = (const u_int8_t *)(void *)&ph;
    159 	vec[0].len = sizeof(ph);
    160 	vec[1].ptr = data;
    161 	vec[1].len = len;
    162 	return (in_cksum(vec, 2));
    163 }
    164 
    165 static void
    166 ip_printts(register const u_char *cp, u_int length)
    167 {
    168 	register u_int ptr;
    169 	register u_int len;
    170 	int hoplen;
    171 	const char *type;
    172 
    173 	if (length < 4) {
    174 		printf("[bad length %u]", length);
    175 		return;
    176 	}
    177 	printf(" TS{");
    178 	hoplen = ((cp[3]&0xF) != IPOPT_TS_TSONLY) ? 8 : 4;
    179 	if ((length - 4) & (hoplen-1))
    180 		printf("[bad length %u]", length);
    181 	ptr = cp[2] - 1;
    182 	len = 0;
    183 	if (ptr < 4 || ((ptr - 4) & (hoplen-1)) || ptr > length + 1)
    184 		printf("[bad ptr %u]", cp[2]);
    185 	switch (cp[3]&0xF) {
    186 	case IPOPT_TS_TSONLY:
    187 		printf("TSONLY");
    188 		break;
    189 	case IPOPT_TS_TSANDADDR:
    190 		printf("TS+ADDR");
    191 		break;
    192 	/*
    193 	 * prespecified should really be 3, but some ones might send 2
    194 	 * instead, and the IPOPT_TS_PRESPEC constant can apparently
    195 	 * have both values, so we have to hard-code it here.
    196 	 */
    197 
    198 	case 2:
    199 		printf("PRESPEC2.0");
    200 		break;
    201 	case 3:			/* IPOPT_TS_PRESPEC */
    202 		printf("PRESPEC");
    203 		break;
    204 	default:
    205 		printf("[bad ts type %d]", cp[3]&0xF);
    206 		goto done;
    207 	}
    208 
    209 	type = " ";
    210 	for (len = 4; len < length; len += hoplen) {
    211 		if (ptr == len)
    212 			type = " ^ ";
    213 		printf("%s%d@%s", type, EXTRACT_32BITS(&cp[len+hoplen-4]),
    214 		       hoplen!=8 ? "" : ipaddr_string(&cp[len]));
    215 		type = " ";
    216 	}
    217 
    218 done:
    219 	printf("%s", ptr == len ? " ^ " : "");
    220 
    221 	if (cp[3]>>4)
    222 		printf(" [%d hops not recorded]} ", cp[3]>>4);
    223 	else
    224 		printf("}");
    225 }
    226 
    227 /*
    228  * print IP options.
    229  */
    230 static void
    231 ip_optprint(register const u_char *cp, u_int length)
    232 {
    233 	register u_int option_len;
    234 	const char *sep = "";
    235 
    236 	for (; length > 0; cp += option_len, length -= option_len) {
    237 		u_int option_code;
    238 
    239 		printf("%s", sep);
    240 		sep = ",";
    241 
    242 		TCHECK(*cp);
    243 		option_code = *cp;
    244 
    245                 printf("%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 			TCHECK(cp[1]);
    254 			option_len = cp[1];
    255 			if (option_len < 2) {
    256 		                printf(" [bad length %u]", option_len);
    257 				return;
    258 			}
    259 		}
    260 
    261 		if (option_len > length) {
    262 	                printf(" [bad length %u]", option_len);
    263 			return;
    264 		}
    265 
    266                 TCHECK2(*cp, option_len);
    267 
    268 		switch (option_code) {
    269 		case IPOPT_EOL:
    270 			return;
    271 
    272 		case IPOPT_TS:
    273 			ip_printts(cp, option_len);
    274 			break;
    275 
    276 		case IPOPT_RR:       /* fall through */
    277 		case IPOPT_SSRR:
    278 		case IPOPT_LSRR:
    279 			ip_printroute(cp, option_len);
    280 			break;
    281 
    282 		case IPOPT_RA:
    283 			if (option_len < 4) {
    284 				printf(" [bad length %u]", option_len);
    285 				break;
    286 			}
    287                         TCHECK(cp[3]);
    288                         if (EXTRACT_16BITS(&cp[2]) != 0)
    289                             printf(" value %u", EXTRACT_16BITS(&cp[2]));
    290 			break;
    291 
    292 		case IPOPT_NOP:       /* nothing to print - fall through */
    293 		case IPOPT_SECURITY:
    294 		default:
    295 			break;
    296 		}
    297 	}
    298 	return;
    299 
    300 trunc:
    301 	printf("[|ip]");
    302 }
    303 
    304 #define IP_RES 0x8000
    305 
    306 static const struct tok ip_frag_values[] = {
    307         { IP_MF,        "+" },
    308         { IP_DF,        "DF" },
    309 	{ IP_RES,       "rsvd" }, /* The RFC3514 evil ;-) bit */
    310         { 0,            NULL }
    311 };
    312 
    313 struct ip_print_demux_state {
    314 	const struct ip *ip;
    315 	const u_char *cp;
    316 	u_int   len, off;
    317 	u_char  nh;
    318 	int     advance;
    319 };
    320 
    321 static void
    322 ip_print_demux(netdissect_options *ndo,
    323 	       struct ip_print_demux_state *ipds)
    324 {
    325 	struct protoent *proto;
    326 	struct cksum_vec vec[1];
    327 
    328 again:
    329 	switch (ipds->nh) {
    330 
    331 	case IPPROTO_AH:
    332 		ipds->nh = *ipds->cp;
    333 		ipds->advance = ah_print(ipds->cp);
    334 		if (ipds->advance <= 0)
    335 			break;
    336 		ipds->cp += ipds->advance;
    337 		ipds->len -= ipds->advance;
    338 		goto again;
    339 
    340 	case IPPROTO_ESP:
    341 	{
    342 		int enh, padlen;
    343 		ipds->advance = esp_print(ndo, ipds->cp, ipds->len,
    344 				    (const u_char *)ipds->ip,
    345 				    &enh, &padlen);
    346 		if (ipds->advance <= 0)
    347 			break;
    348 		ipds->cp += ipds->advance;
    349 		ipds->len -= ipds->advance + padlen;
    350 		ipds->nh = enh & 0xff;
    351 		goto again;
    352 	}
    353 
    354 	case IPPROTO_IPCOMP:
    355 	{
    356 		int enh;
    357 		ipds->advance = ipcomp_print(ipds->cp, &enh);
    358 		if (ipds->advance <= 0)
    359 			break;
    360 		ipds->cp += ipds->advance;
    361 		ipds->len -= ipds->advance;
    362 		ipds->nh = enh & 0xff;
    363 		goto again;
    364 	}
    365 
    366 	case IPPROTO_SCTP:
    367 		sctp_print(ipds->cp, (const u_char *)ipds->ip, ipds->len);
    368 		break;
    369 
    370 	case IPPROTO_DCCP:
    371 		dccp_print(ipds->cp, (const u_char *)ipds->ip, ipds->len);
    372 		break;
    373 
    374 	case IPPROTO_TCP:
    375 		/* pass on the MF bit plus the offset to detect fragments */
    376 		tcp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip,
    377 			  ipds->off & (IP_MF|IP_OFFMASK));
    378 		break;
    379 
    380 	case IPPROTO_UDP:
    381 		/* pass on the MF bit plus the offset to detect fragments */
    382 		udp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip,
    383 			  ipds->off & (IP_MF|IP_OFFMASK));
    384 		break;
    385 
    386 	case IPPROTO_ICMP:
    387 		/* pass on the MF bit plus the offset to detect fragments */
    388 		icmp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip,
    389 			   ipds->off & (IP_MF|IP_OFFMASK));
    390 		break;
    391 
    392 	case IPPROTO_PIGP:
    393 		/*
    394 		 * XXX - the current IANA protocol number assignments
    395 		 * page lists 9 as "any private interior gateway
    396 		 * (used by Cisco for their IGRP)" and 88 as
    397 		 * "EIGRP" from Cisco.
    398 		 *
    399 		 * Recent BSD <netinet/in.h> headers define
    400 		 * IP_PROTO_PIGP as 9 and IP_PROTO_IGRP as 88.
    401 		 * We define IP_PROTO_PIGP as 9 and
    402 		 * IP_PROTO_EIGRP as 88; those names better
    403 		 * match was the current protocol number
    404 		 * assignments say.
    405 		 */
    406 		igrp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip);
    407 		break;
    408 
    409 	case IPPROTO_EIGRP:
    410 		eigrp_print(ipds->cp, ipds->len);
    411 		break;
    412 
    413 	case IPPROTO_ND:
    414 		ND_PRINT((ndo, " nd %d", ipds->len));
    415 		break;
    416 
    417 	case IPPROTO_EGP:
    418 		egp_print(ipds->cp, ipds->len);
    419 		break;
    420 
    421 	case IPPROTO_OSPF:
    422 		ospf_print(ipds->cp, ipds->len, (const u_char *)ipds->ip);
    423 		break;
    424 
    425 	case IPPROTO_IGMP:
    426 		igmp_print(ipds->cp, ipds->len);
    427 		break;
    428 
    429 	case IPPROTO_IPV4:
    430 		/* DVMRP multicast tunnel (ip-in-ip encapsulation) */
    431 		ip_print(ndo, ipds->cp, ipds->len);
    432 		if (! vflag) {
    433 			ND_PRINT((ndo, " (ipip-proto-4)"));
    434 			return;
    435 		}
    436 		break;
    437 
    438 #ifdef INET6
    439 	case IPPROTO_IPV6:
    440 		/* ip6-in-ip encapsulation */
    441 		ip6_print(ndo, ipds->cp, ipds->len);
    442 		break;
    443 #endif /*INET6*/
    444 
    445 	case IPPROTO_RSVP:
    446 		rsvp_print(ipds->cp, ipds->len);
    447 		break;
    448 
    449 	case IPPROTO_GRE:
    450 		/* do it */
    451 		gre_print(ipds->cp, ipds->len);
    452 		break;
    453 
    454 	case IPPROTO_MOBILE:
    455 		mobile_print(ipds->cp, ipds->len);
    456 		break;
    457 
    458 	case IPPROTO_PIM:
    459 		vec[0].ptr = ipds->cp;
    460 		vec[0].len = ipds->len;
    461 		pim_print(ipds->cp, ipds->len, in_cksum(vec, 1));
    462 		break;
    463 
    464 	case IPPROTO_VRRP:
    465 		if (packettype == PT_CARP) {
    466 			if (vflag)
    467 				(void)printf("carp %s > %s: ",
    468 					     ipaddr_string(&ipds->ip->ip_src),
    469 					     ipaddr_string(&ipds->ip->ip_dst));
    470 			carp_print(ipds->cp, ipds->len, ipds->ip->ip_ttl);
    471 		} else {
    472 			if (vflag)
    473 				(void)printf("vrrp %s > %s: ",
    474 					     ipaddr_string(&ipds->ip->ip_src),
    475 					     ipaddr_string(&ipds->ip->ip_dst));
    476 			vrrp_print(ipds->cp, ipds->len, ipds->ip->ip_ttl);
    477 		}
    478 		break;
    479 
    480 	case IPPROTO_PGM:
    481 		pgm_print(ipds->cp, ipds->len, (const u_char *)ipds->ip);
    482 		break;
    483 
    484 	default:
    485 		if (ndo->ndo_nflag==0 && (proto = getprotobynumber(ipds->nh)) != NULL)
    486 			ND_PRINT((ndo, " %s", proto->p_name));
    487 		else
    488 			ND_PRINT((ndo, " ip-proto-%d", ipds->nh));
    489 		ND_PRINT((ndo, " %d", ipds->len));
    490 		break;
    491 	}
    492 }
    493 
    494 void
    495 ip_print_inner(netdissect_options *ndo,
    496 	       const u_char *bp,
    497 	       u_int length, u_int nh,
    498 	       const u_char *bp2)
    499 {
    500 	struct ip_print_demux_state  ipd;
    501 
    502 	ipd.ip = (const struct ip *)bp2;
    503 	ipd.cp = bp;
    504 	ipd.len  = length;
    505 	ipd.off  = 0;
    506 	ipd.nh   = nh;
    507 	ipd.advance = 0;
    508 
    509 	ip_print_demux(ndo, &ipd);
    510 }
    511 
    512 
    513 /*
    514  * print an IP datagram.
    515  */
    516 void
    517 ip_print(netdissect_options *ndo,
    518 	 const u_char *bp,
    519 	 u_int length)
    520 {
    521 	struct ip_print_demux_state  ipd;
    522 	struct ip_print_demux_state *ipds=&ipd;
    523 	const u_char *ipend;
    524 	u_int hlen;
    525 	struct cksum_vec vec[1];
    526 	u_int16_t sum, ip_sum;
    527 	struct protoent *proto;
    528 
    529 	ipds->ip = (const struct ip *)bp;
    530 	if (IP_V(ipds->ip) != 4) { /* print version if != 4 */
    531 	    printf("IP%u ", IP_V(ipds->ip));
    532 	    if (IP_V(ipds->ip) == 6)
    533 		printf(", wrong link-layer encapsulation");
    534 	}
    535         else if (!eflag)
    536 	    printf("IP ");
    537 
    538 	if ((u_char *)(ipds->ip + 1) > ndo->ndo_snapend) {
    539 		printf("[|ip]");
    540 		return;
    541 	}
    542 	if (length < sizeof (struct ip)) {
    543 		(void)printf("truncated-ip %u", length);
    544 		return;
    545 	}
    546 	hlen = IP_HL(ipds->ip) * 4;
    547 	if (hlen < sizeof (struct ip)) {
    548 		(void)printf("bad-hlen %u", hlen);
    549 		return;
    550 	}
    551 
    552 	ipds->len = EXTRACT_16BITS(&ipds->ip->ip_len);
    553 	if (length < ipds->len)
    554 		(void)printf("truncated-ip - %u bytes missing! ",
    555 			ipds->len - length);
    556 	if (ipds->len < hlen) {
    557 #ifdef GUESS_TSO
    558             if (ipds->len) {
    559                 (void)printf("bad-len %u", ipds->len);
    560                 return;
    561             }
    562             else {
    563                 /* we guess that it is a TSO send */
    564                 ipds->len = length;
    565             }
    566 #else
    567             (void)printf("bad-len %u", ipds->len);
    568             return;
    569 #endif /* GUESS_TSO */
    570 	}
    571 
    572 	/*
    573 	 * Cut off the snapshot length to the end of the IP payload.
    574 	 */
    575 	ipend = bp + ipds->len;
    576 	if (ipend < ndo->ndo_snapend)
    577 		ndo->ndo_snapend = ipend;
    578 
    579 	ipds->len -= hlen;
    580 
    581 	ipds->off = EXTRACT_16BITS(&ipds->ip->ip_off);
    582 
    583         if (vflag) {
    584             (void)printf("(tos 0x%x", (int)ipds->ip->ip_tos);
    585             /* ECN bits */
    586             if (ipds->ip->ip_tos & 0x03) {
    587                 switch (ipds->ip->ip_tos & 0x03) {
    588                 case 1:
    589                     (void)printf(",ECT(1)");
    590                     break;
    591                 case 2:
    592                     (void)printf(",ECT(0)");
    593                     break;
    594                 case 3:
    595                     (void)printf(",CE");
    596                 }
    597             }
    598 
    599             if (ipds->ip->ip_ttl >= 1)
    600                 (void)printf(", ttl %u", ipds->ip->ip_ttl);
    601 
    602 	    /*
    603 	     * for the firewall guys, print id, offset.
    604              * On all but the last stick a "+" in the flags portion.
    605 	     * For unfragmented datagrams, note the don't fragment flag.
    606 	     */
    607 
    608 	    (void)printf(", id %u, offset %u, flags [%s], proto %s (%u)",
    609                          EXTRACT_16BITS(&ipds->ip->ip_id),
    610                          (ipds->off & 0x1fff) * 8,
    611                          bittok2str(ip_frag_values, "none", ipds->off&0xe000),
    612                          tok2str(ipproto_values,"unknown",ipds->ip->ip_p),
    613                          ipds->ip->ip_p);
    614 
    615             (void)printf(", length %u", EXTRACT_16BITS(&ipds->ip->ip_len));
    616 
    617             if ((hlen - sizeof(struct ip)) > 0) {
    618                 printf(", options (");
    619                 ip_optprint((u_char *)(ipds->ip + 1), hlen - sizeof(struct ip));
    620                 printf(")");
    621             }
    622 
    623 	    if (!Kflag && (u_char *)ipds->ip + hlen <= ndo->ndo_snapend) {
    624 	        vec[0].ptr = (const u_int8_t *)(void *)ipds->ip;
    625 	        vec[0].len = hlen;
    626 	        sum = in_cksum(vec, 1);
    627 		if (sum != 0) {
    628 		    ip_sum = EXTRACT_16BITS(&ipds->ip->ip_sum);
    629 		    (void)printf(", bad cksum %x (->%x)!", ip_sum,
    630 			     in_cksum_shouldbe(ip_sum, sum));
    631 		}
    632 	    }
    633 
    634             printf(")\n    ");
    635 	}
    636 
    637 	/*
    638 	 * If this is fragment zero, hand it to the next higher
    639 	 * level protocol.
    640 	 */
    641 	if ((ipds->off & 0x1fff) == 0) {
    642 		ipds->cp = (const u_char *)ipds->ip + hlen;
    643 		ipds->nh = ipds->ip->ip_p;
    644 
    645 		if (ipds->nh != IPPROTO_TCP && ipds->nh != IPPROTO_UDP &&
    646 		    ipds->nh != IPPROTO_SCTP && ipds->nh != IPPROTO_DCCP) {
    647 			(void)printf("%s > %s: ",
    648 				     ipaddr_string(&ipds->ip->ip_src),
    649 				     ipaddr_string(&ipds->ip->ip_dst));
    650 		}
    651 		ip_print_demux(ndo, ipds);
    652 	} else {
    653 	    /* Ultra quiet now means that all this stuff should be suppressed */
    654 	    if (qflag > 1) return;
    655 
    656 	    /*
    657 	     * if this isn't the first frag, we're missing the
    658 	     * next level protocol header.  print the ip addr
    659 	     * and the protocol.
    660 	     */
    661 	    if (ipds->off & 0x1fff) {
    662 	        (void)printf("%s > %s:", ipaddr_string(&ipds->ip->ip_src),
    663 			     ipaddr_string(&ipds->ip->ip_dst));
    664 		if (!ndo->ndo_nflag && (proto = getprotobynumber(ipds->ip->ip_p)) != NULL)
    665 		    (void)printf(" %s", proto->p_name);
    666 		else
    667 		    (void)printf(" ip-proto-%d", ipds->ip->ip_p);
    668 	    }
    669 	}
    670 }
    671 
    672 void
    673 ipN_print(register const u_char *bp, register u_int length)
    674 {
    675 	struct ip hdr;
    676 
    677 	if (length < 4) {
    678 		(void)printf("truncated-ip %d", length);
    679 		return;
    680 	}
    681 	memcpy (&hdr, bp, 4);
    682 	switch (IP_V(&hdr)) {
    683 	case 4:
    684 		ip_print (gndo, bp, length);
    685 		return;
    686 #ifdef INET6
    687 	case 6:
    688 		ip6_print (gndo, bp, length);
    689 		return;
    690 #endif
    691 	default:
    692 		(void)printf("unknown ip %d", IP_V(&hdr));
    693 		return;
    694 	}
    695 }
    696 
    697 /*
    698  * Local Variables:
    699  * c-style: whitesmith
    700  * c-basic-offset: 8
    701  * End:
    702  */
    703 
    704 
    705