print-ip.c revision 162021
117680Spst/* 239300Sfenner * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 317680Spst * The Regents of the University of California. All rights reserved. 417680Spst * 517680Spst * Redistribution and use in source and binary forms, with or without 617680Spst * modification, are permitted provided that: (1) source code distributions 717680Spst * retain the above copyright notice and this paragraph in its entirety, (2) 817680Spst * distributions including binary code include the above copyright notice and 917680Spst * this paragraph in its entirety in the documentation or other materials 1017680Spst * provided with the distribution, and (3) all advertising materials mentioning 1117680Spst * features or use of this software display the following acknowledgement: 1217680Spst * ``This product includes software developed by the University of California, 1317680Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 1417680Spst * the University nor the names of its contributors may be used to endorse 1517680Spst * or promote products derived from this software without specific prior 1617680Spst * written permission. 1717680Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 1817680Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 1917680Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 2056896Sfenner * 2156896Sfenner * $FreeBSD: head/contrib/tcpdump/print-ip.c 162021 2006-09-04 20:25:04Z sam $ 2217680Spst */ 2317680Spst 2417680Spst#ifndef lint 25127675Sbmsstatic const char rcsid[] _U_ = 26162021Ssam "@(#) $Header: /tcpdump/master/tcpdump/print-ip.c,v 1.149.2.2 2005/09/20 06:05:38 guy Exp $ (LBL)"; 2717680Spst#endif 2817680Spst 2956896Sfenner#ifdef HAVE_CONFIG_H 3056896Sfenner#include "config.h" 3156896Sfenner#endif 3256896Sfenner 33127675Sbms#include <tcpdump-stdinc.h> 3417680Spst 3517680Spst#include <stdio.h> 3617680Spst#include <stdlib.h> 3717680Spst#include <string.h> 3817680Spst 3917680Spst#include "addrtoname.h" 4017680Spst#include "interface.h" 4117680Spst#include "extract.h" /* must come after interface.h */ 4217680Spst 4375118Sfenner#include "ip.h" 44127675Sbms#include "ipproto.h" 4575118Sfenner 46146778Ssamstruct tok ip_option_values[] = { 47146778Ssam { IPOPT_EOL, "EOL" }, 48146778Ssam { IPOPT_NOP, "NOP" }, 49146778Ssam { IPOPT_TS, "timestamp" }, 50146778Ssam { IPOPT_SECURITY, "security" }, 51146778Ssam { IPOPT_RR, "RR" }, 52146778Ssam { IPOPT_SSRR, "SSRR" }, 53146778Ssam { IPOPT_LSRR, "LSRR" }, 54146778Ssam { IPOPT_RA, "RA" }, 55146778Ssam { 0, NULL } 56146778Ssam}; 57146778Ssam 5817680Spst/* 5917680Spst * print the recorded route in an IP RR, LSRR or SSRR option. 6017680Spst */ 6117680Spststatic void 62146778Ssamip_printroute(register const u_char *cp, u_int length) 6317680Spst{ 64127675Sbms register u_int ptr; 6517680Spst register u_int len; 6617680Spst 67127675Sbms if (length < 3) { 68127675Sbms printf(" [bad length %u]", length); 69127675Sbms return; 70127675Sbms } 7117680Spst if ((length + 1) & 3) 72127675Sbms printf(" [bad length %u]", length); 73127675Sbms ptr = cp[2] - 1; 7417680Spst if (ptr < 3 || ((ptr + 1) & 3) || ptr > length + 1) 75127675Sbms printf(" [bad ptr %u]", cp[2]); 7617680Spst 7717680Spst for (len = 3; len < length; len += 4) { 78146778Ssam printf("%s", ipaddr_string(&cp[len])); 79146778Ssam if (ptr > len) 80146778Ssam printf (", "); 8117680Spst } 8217680Spst} 8317680Spst 84127675Sbms/* 85146778Ssam * If source-routing is present and valid, return the final destination. 86127675Sbms * Otherwise, return IP destination. 87127675Sbms * 88127675Sbms * This is used for UDP and TCP pseudo-header in the checksum 89127675Sbms * calculation. 90127675Sbms */ 91127675Sbmsu_int32_t 92127675Sbmsip_finddst(const struct ip *ip) 93127675Sbms{ 94127675Sbms int length; 95127675Sbms int len; 96127675Sbms const u_char *cp; 97127675Sbms u_int32_t retval; 98127675Sbms 99127675Sbms cp = (const u_char *)(ip + 1); 100127675Sbms length = (IP_HL(ip) << 2) - sizeof(struct ip); 101127675Sbms 102127675Sbms for (; length > 0; cp += len, length -= len) { 103127675Sbms int tt; 104127675Sbms 105127675Sbms TCHECK(*cp); 106127675Sbms tt = *cp; 107146778Ssam if (tt == IPOPT_EOL) 108146778Ssam break; 109146778Ssam else if (tt == IPOPT_NOP) 110127675Sbms len = 1; 111127675Sbms else { 112127675Sbms TCHECK(cp[1]); 113127675Sbms len = cp[1]; 114146778Ssam if (len < 2) 115146778Ssam break; 116127675Sbms } 117127675Sbms TCHECK2(*cp, len); 118127675Sbms switch (tt) { 119127675Sbms 120127675Sbms case IPOPT_SSRR: 121127675Sbms case IPOPT_LSRR: 122127675Sbms if (len < 7) 123146778Ssam break; 124127675Sbms memcpy(&retval, cp + len - 4, 4); 125127675Sbms return retval; 126127675Sbms } 127127675Sbms } 128127675Sbmstrunc: 129146778Ssam memcpy(&retval, &ip->ip_dst.s_addr, sizeof(u_int32_t)); 130146778Ssam return retval; 131127675Sbms} 132127675Sbms 13356896Sfennerstatic void 13456896Sfennerip_printts(register const u_char *cp, u_int length) 13556896Sfenner{ 136127675Sbms register u_int ptr; 137127675Sbms register u_int len; 13856896Sfenner int hoplen; 139127675Sbms const char *type; 14056896Sfenner 141127675Sbms if (length < 4) { 142127675Sbms printf("[bad length %d]", length); 143127675Sbms return; 144127675Sbms } 14556896Sfenner printf(" TS{"); 14656896Sfenner hoplen = ((cp[3]&0xF) != IPOPT_TS_TSONLY) ? 8 : 4; 14756896Sfenner if ((length - 4) & (hoplen-1)) 14856896Sfenner printf("[bad length %d]", length); 149127675Sbms ptr = cp[2] - 1; 150127675Sbms len = 0; 15156896Sfenner if (ptr < 4 || ((ptr - 4) & (hoplen-1)) || ptr > length + 1) 15256896Sfenner printf("[bad ptr %d]", cp[2]); 15356896Sfenner switch (cp[3]&0xF) { 15456896Sfenner case IPOPT_TS_TSONLY: 15556896Sfenner printf("TSONLY"); 15656896Sfenner break; 15756896Sfenner case IPOPT_TS_TSANDADDR: 15856896Sfenner printf("TS+ADDR"); 15956896Sfenner break; 16056896Sfenner /* 16156896Sfenner * prespecified should really be 3, but some ones might send 2 16256896Sfenner * instead, and the IPOPT_TS_PRESPEC constant can apparently 16356896Sfenner * have both values, so we have to hard-code it here. 16456896Sfenner */ 16556896Sfenner 16656896Sfenner case 2: 16756896Sfenner printf("PRESPEC2.0"); 16856896Sfenner break; 16956896Sfenner case 3: /* IPOPT_TS_PRESPEC */ 17056896Sfenner printf("PRESPEC"); 17156896Sfenner break; 172127675Sbms default: 17356896Sfenner printf("[bad ts type %d]", cp[3]&0xF); 17456896Sfenner goto done; 17556896Sfenner } 17656896Sfenner 17756896Sfenner type = " "; 17856896Sfenner for (len = 4; len < length; len += hoplen) { 17956896Sfenner if (ptr == len) 18056896Sfenner type = " ^ "; 18156896Sfenner printf("%s%d@%s", type, EXTRACT_32BITS(&cp[len+hoplen-4]), 18256896Sfenner hoplen!=8 ? "" : ipaddr_string(&cp[len])); 18356896Sfenner type = " "; 18456896Sfenner } 18556896Sfenner 18656896Sfennerdone: 18756896Sfenner printf("%s", ptr == len ? " ^ " : ""); 18856896Sfenner 18956896Sfenner if (cp[3]>>4) 19056896Sfenner printf(" [%d hops not recorded]} ", cp[3]>>4); 19156896Sfenner else 19256896Sfenner printf("}"); 19356896Sfenner} 19456896Sfenner 19517680Spst/* 19617680Spst * print IP options. 19717680Spst */ 19817680Spststatic void 19917680Spstip_optprint(register const u_char *cp, u_int length) 20017680Spst{ 201146778Ssam register u_int option_len; 20217680Spst 203146778Ssam for (; length > 0; cp += option_len, length -= option_len) { 204146778Ssam u_int option_code; 20517680Spst 206127675Sbms TCHECK(*cp); 207146778Ssam option_code = *cp; 208146778Ssam 209146778Ssam if (option_code == IPOPT_NOP || 210146778Ssam option_code == IPOPT_EOL) 211146778Ssam option_len = 1; 212146778Ssam 21375118Sfenner else { 214127675Sbms TCHECK(cp[1]); 215146778Ssam option_len = cp[1]; 21675118Sfenner } 21717680Spst 218146778Ssam printf("%s (%u) len %u", 219146778Ssam tok2str(ip_option_values,"unknown",option_code), 220146778Ssam option_code, 221146778Ssam option_len); 222146778Ssam 223146778Ssam if (option_len < 2) 224146778Ssam return; 225146778Ssam 226146778Ssam TCHECK2(*cp, option_len); 227146778Ssam 228146778Ssam switch (option_code) { 22917680Spst case IPOPT_EOL: 23017680Spst return; 23117680Spst 23217680Spst case IPOPT_TS: 233146778Ssam ip_printts(cp, option_len); 23417680Spst break; 23517680Spst 236146778Ssam case IPOPT_RR: /* fall through */ 23717680Spst case IPOPT_SSRR: 23817680Spst case IPOPT_LSRR: 239146778Ssam ip_printroute( cp, option_len); 24017680Spst break; 24117680Spst 24217691Spst case IPOPT_RA: 243146778Ssam TCHECK(cp[3]); 244146778Ssam if (EXTRACT_16BITS(&cp[2]) != 0) 245146778Ssam printf("value %u", EXTRACT_16BITS(&cp[2])); 24698527Sfenner break; 24717691Spst 248146778Ssam case IPOPT_NOP: /* nothing to print - fall through */ 249146778Ssam case IPOPT_SECURITY: 25017680Spst default: 25117680Spst break; 25217680Spst } 25317680Spst } 254127675Sbms return; 255127675Sbms 256127675Sbmstrunc: 257127675Sbms printf("[|ip]"); 25817680Spst} 25917680Spst 26017680Spst/* 26117680Spst * compute an IP header checksum. 26217680Spst * don't modifiy the packet. 26317680Spst */ 26456896Sfenneru_short 26598527Sfennerin_cksum(const u_short *addr, register u_int len, int csum) 26617680Spst{ 26756896Sfenner int nleft = len; 26856896Sfenner const u_short *w = addr; 26956896Sfenner u_short answer; 27056896Sfenner int sum = csum; 27117680Spst 272127675Sbms /* 27356896Sfenner * Our algorithm is simple, using a 32 bit accumulator (sum), 27456896Sfenner * we add sequential 16 bit words to it, and at the end, fold 27556896Sfenner * back all the carry bits from the top 16 bits into the lower 27656896Sfenner * 16 bits. 277127675Sbms */ 27856896Sfenner while (nleft > 1) { 27956896Sfenner sum += *w++; 28056896Sfenner nleft -= 2; 28156896Sfenner } 28256896Sfenner if (nleft == 1) 28356896Sfenner sum += htons(*(u_char *)w<<8); 28456896Sfenner 28517680Spst /* 28656896Sfenner * add back carry outs from top 16 bits to low 16 bits 28717680Spst */ 28856896Sfenner sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 28956896Sfenner sum += (sum >> 16); /* add carry */ 29056896Sfenner answer = ~sum; /* truncate to 16 bits */ 29156896Sfenner return (answer); 29217680Spst} 29317680Spst 29417680Spst/* 295127675Sbms * Given the host-byte-order value of the checksum field in a packet 296127675Sbms * header, and the network-byte-order computed checksum of the data 297127675Sbms * that the checksum covers (including the checksum itself), compute 298127675Sbms * what the checksum field *should* have been. 299127675Sbms */ 300127675Sbmsu_int16_t 301127675Sbmsin_cksum_shouldbe(u_int16_t sum, u_int16_t computed_sum) 302127675Sbms{ 303127675Sbms u_int32_t shouldbe; 304127675Sbms 305127675Sbms /* 306127675Sbms * The value that should have gone into the checksum field 307127675Sbms * is the negative of the value gotten by summing up everything 308127675Sbms * *but* the checksum field. 309127675Sbms * 310127675Sbms * We can compute that by subtracting the value of the checksum 311127675Sbms * field from the sum of all the data in the packet, and then 312127675Sbms * computing the negative of that value. 313127675Sbms * 314127675Sbms * "sum" is the value of the checksum field, and "computed_sum" 315127675Sbms * is the negative of the sum of all the data in the packets, 316127675Sbms * so that's -(-computed_sum - sum), or (sum + computed_sum). 317127675Sbms * 318127675Sbms * All the arithmetic in question is one's complement, so the 319127675Sbms * addition must include an end-around carry; we do this by 320127675Sbms * doing the arithmetic in 32 bits (with no sign-extension), 321127675Sbms * and then adding the upper 16 bits of the sum, which contain 322127675Sbms * the carry, to the lower 16 bits of the sum, and then do it 323127675Sbms * again in case *that* sum produced a carry. 324127675Sbms * 325127675Sbms * As RFC 1071 notes, the checksum can be computed without 326127675Sbms * byte-swapping the 16-bit words; summing 16-bit words 327127675Sbms * on a big-endian machine gives a big-endian checksum, which 328127675Sbms * can be directly stuffed into the big-endian checksum fields 329127675Sbms * in protocol headers, and summing words on a little-endian 330127675Sbms * machine gives a little-endian checksum, which must be 331127675Sbms * byte-swapped before being stuffed into a big-endian checksum 332127675Sbms * field. 333127675Sbms * 334127675Sbms * "computed_sum" is a network-byte-order value, so we must put 335127675Sbms * it in host byte order before subtracting it from the 336127675Sbms * host-byte-order value from the header; the adjusted checksum 337127675Sbms * will be in host byte order, which is what we'll return. 338127675Sbms */ 339127675Sbms shouldbe = sum; 340127675Sbms shouldbe += ntohs(computed_sum); 341127675Sbms shouldbe = (shouldbe & 0xFFFF) + (shouldbe >> 16); 342127675Sbms shouldbe = (shouldbe & 0xFFFF) + (shouldbe >> 16); 343127675Sbms return shouldbe; 344127675Sbms} 345127675Sbms 346127675Sbms#ifndef IP_MF 347127675Sbms#define IP_MF 0x2000 348127675Sbms#endif /* IP_MF */ 349127675Sbms#ifndef IP_DF 350127675Sbms#define IP_DF 0x4000 351127675Sbms#endif /* IP_DF */ 352127675Sbms#define IP_RES 0x8000 353127675Sbms 354127675Sbmsstatic struct tok ip_frag_values[] = { 355127675Sbms { IP_MF, "+" }, 356127675Sbms { IP_DF, "DF" }, 357127675Sbms { IP_RES, "rsvd" }, /* The RFC3514 evil ;-) bit */ 358127675Sbms { 0, NULL } 359127675Sbms}; 360127675Sbms 361146778Ssamstruct ip_print_demux_state { 362146778Ssam const struct ip *ip; 363146778Ssam const u_char *cp; 364146778Ssam u_int len, off; 365146778Ssam u_char nh; 366146778Ssam int advance; 367146778Ssam}; 368146778Ssam 369146778Ssamstatic void 370146778Ssamip_print_demux(netdissect_options *ndo, 371146778Ssam struct ip_print_demux_state *ipds) 372146778Ssam{ 373146778Ssam struct protoent *proto; 374146778Ssam 375146778Ssamagain: 376146778Ssam switch (ipds->nh) { 377146778Ssam 378146778Ssam case IPPROTO_AH: 379146778Ssam ipds->nh = *ipds->cp; 380146778Ssam ipds->advance = ah_print(ipds->cp); 381146778Ssam if (ipds->advance <= 0) 382146778Ssam break; 383146778Ssam ipds->cp += ipds->advance; 384146778Ssam ipds->len -= ipds->advance; 385146778Ssam goto again; 386146778Ssam 387146778Ssam case IPPROTO_ESP: 388146778Ssam { 389146778Ssam int enh, padlen; 390146778Ssam ipds->advance = esp_print(ndo, ipds->cp, ipds->len, 391146778Ssam (const u_char *)ipds->ip, 392146778Ssam &enh, &padlen); 393146778Ssam if (ipds->advance <= 0) 394146778Ssam break; 395146778Ssam ipds->cp += ipds->advance; 396146778Ssam ipds->len -= ipds->advance + padlen; 397146778Ssam ipds->nh = enh & 0xff; 398146778Ssam goto again; 399146778Ssam } 400146778Ssam 401146778Ssam case IPPROTO_IPCOMP: 402146778Ssam { 403146778Ssam int enh; 404146778Ssam ipds->advance = ipcomp_print(ipds->cp, &enh); 405146778Ssam if (ipds->advance <= 0) 406146778Ssam break; 407146778Ssam ipds->cp += ipds->advance; 408146778Ssam ipds->len -= ipds->advance; 409146778Ssam ipds->nh = enh & 0xff; 410146778Ssam goto again; 411146778Ssam } 412146778Ssam 413146778Ssam case IPPROTO_SCTP: 414146778Ssam sctp_print(ipds->cp, (const u_char *)ipds->ip, ipds->len); 415146778Ssam break; 416162021Ssam 417162021Ssam case IPPROTO_DCCP: 418162021Ssam dccp_print(ipds->cp, (const u_char *)ipds->ip, ipds->len); 419162021Ssam break; 420146778Ssam 421146778Ssam case IPPROTO_TCP: 422146778Ssam tcp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip, 423146778Ssam (ipds->off &~ 0x6000)); 424146778Ssam break; 425146778Ssam 426146778Ssam case IPPROTO_UDP: 427146778Ssam udp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip, 428146778Ssam (ipds->off &~ 0x6000)); 429146778Ssam break; 430146778Ssam 431146778Ssam case IPPROTO_ICMP: 432146778Ssam /* pass on the MF bit plus the offset to detect fragments */ 433146778Ssam icmp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip, 434146778Ssam (ipds->off & 0x3fff)); 435146778Ssam break; 436146778Ssam 437146778Ssam case IPPROTO_PIGP: 438146778Ssam /* 439146778Ssam * XXX - the current IANA protocol number assignments 440146778Ssam * page lists 9 as "any private interior gateway 441146778Ssam * (used by Cisco for their IGRP)" and 88 as 442146778Ssam * "EIGRP" from Cisco. 443146778Ssam * 444146778Ssam * Recent BSD <netinet/in.h> headers define 445146778Ssam * IP_PROTO_PIGP as 9 and IP_PROTO_IGRP as 88. 446146778Ssam * We define IP_PROTO_PIGP as 9 and 447146778Ssam * IP_PROTO_EIGRP as 88; those names better 448146778Ssam * match was the current protocol number 449146778Ssam * assignments say. 450146778Ssam */ 451146778Ssam igrp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip); 452146778Ssam break; 453146778Ssam 454146778Ssam case IPPROTO_EIGRP: 455146778Ssam eigrp_print(ipds->cp, ipds->len); 456146778Ssam break; 457146778Ssam 458146778Ssam case IPPROTO_ND: 459146778Ssam ND_PRINT((ndo, " nd %d", ipds->len)); 460146778Ssam break; 461146778Ssam 462146778Ssam case IPPROTO_EGP: 463146778Ssam egp_print(ipds->cp, ipds->len); 464146778Ssam break; 465146778Ssam 466146778Ssam case IPPROTO_OSPF: 467146778Ssam ospf_print(ipds->cp, ipds->len, (const u_char *)ipds->ip); 468146778Ssam break; 469146778Ssam 470146778Ssam case IPPROTO_IGMP: 471146778Ssam igmp_print(ipds->cp, ipds->len); 472146778Ssam break; 473146778Ssam 474146778Ssam case IPPROTO_IPV4: 475146778Ssam /* DVMRP multicast tunnel (ip-in-ip encapsulation) */ 476146778Ssam ip_print(gndo, ipds->cp, ipds->len); 477146778Ssam if (! vflag) { 478146778Ssam ND_PRINT((ndo, " (ipip-proto-4)")); 479146778Ssam return; 480146778Ssam } 481146778Ssam break; 482146778Ssam 483146778Ssam#ifdef INET6 484146778Ssam case IPPROTO_IPV6: 485146778Ssam /* ip6-in-ip encapsulation */ 486146778Ssam ip6_print(ipds->cp, ipds->len); 487146778Ssam break; 488146778Ssam#endif /*INET6*/ 489146778Ssam 490146778Ssam case IPPROTO_RSVP: 491146778Ssam rsvp_print(ipds->cp, ipds->len); 492146778Ssam break; 493146778Ssam 494146778Ssam case IPPROTO_GRE: 495146778Ssam /* do it */ 496146778Ssam gre_print(ipds->cp, ipds->len); 497146778Ssam break; 498146778Ssam 499146778Ssam case IPPROTO_MOBILE: 500146778Ssam mobile_print(ipds->cp, ipds->len); 501146778Ssam break; 502146778Ssam 503146778Ssam case IPPROTO_PIM: 504146778Ssam pim_print(ipds->cp, ipds->len); 505146778Ssam break; 506146778Ssam 507146778Ssam case IPPROTO_VRRP: 508146778Ssam vrrp_print(ipds->cp, ipds->len, ipds->ip->ip_ttl); 509146778Ssam break; 510146778Ssam 511147904Ssam case IPPROTO_PGM: 512147904Ssam pgm_print(ipds->cp, ipds->len, (const u_char *)ipds->ip); 513147904Ssam break; 514147904Ssam 515146778Ssam default: 516146778Ssam if ((proto = getprotobynumber(ipds->nh)) != NULL) 517146778Ssam ND_PRINT((ndo, " %s", proto->p_name)); 518146778Ssam else 519146778Ssam ND_PRINT((ndo, " ip-proto-%d", ipds->nh)); 520146778Ssam ND_PRINT((ndo, " %d", ipds->len)); 521146778Ssam break; 522146778Ssam } 523146778Ssam} 524146778Ssam 525146778Ssamvoid 526146778Ssamip_print_inner(netdissect_options *ndo, 527146778Ssam const u_char *bp, 528146778Ssam u_int length, u_int nh, 529146778Ssam const u_char *bp2) 530146778Ssam{ 531146778Ssam struct ip_print_demux_state ipd; 532146778Ssam 533146778Ssam ipd.ip = (const struct ip *)bp2; 534146778Ssam ipd.cp = bp; 535146778Ssam ipd.len = length; 536146778Ssam ipd.off = 0; 537146778Ssam ipd.nh = nh; 538146778Ssam ipd.advance = 0; 539146778Ssam 540146778Ssam ip_print_demux(ndo, &ipd); 541146778Ssam} 542146778Ssam 543146778Ssam 544127675Sbms/* 54517680Spst * print an IP datagram. 54617680Spst */ 54717680Spstvoid 548146778Ssamip_print(netdissect_options *ndo, 549146778Ssam const u_char *bp, 550146778Ssam u_int length) 55117680Spst{ 552146778Ssam struct ip_print_demux_state ipd; 553146778Ssam struct ip_print_demux_state *ipds=&ipd; 554127675Sbms const u_char *ipend; 555146778Ssam u_int hlen; 556146778Ssam u_int16_t sum, ip_sum; 557111729Sfenner struct protoent *proto; 55817680Spst 559146778Ssam ipds->ip = (const struct ip *)bp; 560146778Ssam if (IP_V(ipds->ip) != 4) { /* print version if != 4 */ 561146778Ssam printf("IP%u ", IP_V(ipds->ip)); 562146778Ssam if (IP_V(ipds->ip) == 6) 563127675Sbms printf(", wrong link-layer encapsulation"); 564127675Sbms } 565146778Ssam else if (!eflag) 566127675Sbms printf("IP "); 56717680Spst 568146778Ssam if ((u_char *)(ipds->ip + 1) > snapend) { 56917680Spst printf("[|ip]"); 57017680Spst return; 57117680Spst } 57217680Spst if (length < sizeof (struct ip)) { 573146778Ssam (void)printf("truncated-ip %u", length); 57417680Spst return; 57517680Spst } 576146778Ssam hlen = IP_HL(ipds->ip) * 4; 57775118Sfenner if (hlen < sizeof (struct ip)) { 578127675Sbms (void)printf("bad-hlen %u", hlen); 57975118Sfenner return; 58075118Sfenner } 58117680Spst 582146778Ssam ipds->len = EXTRACT_16BITS(&ipds->ip->ip_len); 583146778Ssam if (length < ipds->len) 584127675Sbms (void)printf("truncated-ip - %u bytes missing! ", 585146778Ssam ipds->len - length); 586146778Ssam if (ipds->len < hlen) { 587146778Ssam#ifdef GUESS_TSO 588146778Ssam if (ipds->len) { 589146778Ssam (void)printf("bad-len %u", ipds->len); 590146778Ssam return; 591146778Ssam } 592146778Ssam else { 593146778Ssam /* we guess that it is a TSO send */ 594146778Ssam ipds->len = length; 595146778Ssam } 596146778Ssam#else 597146778Ssam (void)printf("bad-len %u", ipds->len); 598146778Ssam return; 599146778Ssam#endif /* GUESS_TSO */ 600127675Sbms } 601127675Sbms 602127675Sbms /* 603127675Sbms * Cut off the snapshot length to the end of the IP payload. 604127675Sbms */ 605146778Ssam ipend = bp + ipds->len; 606127675Sbms if (ipend < snapend) 607127675Sbms snapend = ipend; 608127675Sbms 609146778Ssam ipds->len -= hlen; 61017680Spst 611146778Ssam ipds->off = EXTRACT_16BITS(&ipds->ip->ip_off); 612127675Sbms 613127675Sbms if (vflag) { 614146778Ssam (void)printf("(tos 0x%x", (int)ipds->ip->ip_tos); 615127675Sbms /* ECN bits */ 616146778Ssam if (ipds->ip->ip_tos & 0x03) { 617146778Ssam switch (ipds->ip->ip_tos & 0x03) { 618127675Sbms case 1: 619127675Sbms (void)printf(",ECT(1)"); 620127675Sbms break; 621127675Sbms case 2: 622127675Sbms (void)printf(",ECT(0)"); 623127675Sbms break; 624127675Sbms case 3: 625127675Sbms (void)printf(",CE"); 626127675Sbms } 627127675Sbms } 628127675Sbms 629146778Ssam if (ipds->ip->ip_ttl >= 1) 630146778Ssam (void)printf(", ttl %3u", ipds->ip->ip_ttl); 631127675Sbms 632127675Sbms /* 633127675Sbms * for the firewall guys, print id, offset. 634127675Sbms * On all but the last stick a "+" in the flags portion. 635127675Sbms * For unfragmented datagrams, note the don't fragment flag. 636127675Sbms */ 637127675Sbms 638146778Ssam (void)printf(", id %u, offset %u, flags [%s], proto: %s (%u)", 639146778Ssam EXTRACT_16BITS(&ipds->ip->ip_id), 640146778Ssam (ipds->off & 0x1fff) * 8, 641146778Ssam bittok2str(ip_frag_values, "none", ipds->off&0xe000 ), 642146778Ssam tok2str(ipproto_values,"unknown",ipds->ip->ip_p), 643146778Ssam ipds->ip->ip_p); 644127675Sbms 645146778Ssam (void)printf(", length: %u", EXTRACT_16BITS(&ipds->ip->ip_len)); 646127675Sbms 647127675Sbms if ((hlen - sizeof(struct ip)) > 0) { 648146778Ssam printf(", options ( "); 649146778Ssam ip_optprint((u_char *)(ipds->ip + 1), hlen - sizeof(struct ip)); 650127675Sbms printf(" )"); 651127675Sbms } 652127675Sbms 653146778Ssam if ((u_char *)ipds->ip + hlen <= snapend) { 654146778Ssam sum = in_cksum((const u_short *)ipds->ip, hlen, 0); 655127675Sbms if (sum != 0) { 656146778Ssam ip_sum = EXTRACT_16BITS(&ipds->ip->ip_sum); 657127675Sbms (void)printf(", bad cksum %x (->%x)!", ip_sum, 658127675Sbms in_cksum_shouldbe(ip_sum, sum)); 659127675Sbms } 660127675Sbms } 661127675Sbms 662127675Sbms printf(") "); 663127675Sbms } 664127675Sbms 66517680Spst /* 66617680Spst * If this is fragment zero, hand it to the next higher 66717680Spst * level protocol. 66817680Spst */ 669146778Ssam if ((ipds->off & 0x1fff) == 0) { 670146778Ssam ipds->cp = (const u_char *)ipds->ip + hlen; 671146778Ssam ipds->nh = ipds->ip->ip_p; 67217680Spst 673146778Ssam if (ipds->nh != IPPROTO_TCP && ipds->nh != IPPROTO_UDP && 674162021Ssam ipds->nh != IPPROTO_SCTP && ipds->nh != IPPROTO_DCCP) { 675146778Ssam (void)printf("%s > %s: ", 676146778Ssam ipaddr_string(&ipds->ip->ip_src), 677146778Ssam ipaddr_string(&ipds->ip->ip_dst)); 67856896Sfenner } 679146778Ssam ip_print_demux(ndo, ipds); 680127675Sbms } else { 681127675Sbms /* Ultra quiet now means that all this stuff should be suppressed */ 682127675Sbms if (qflag > 1) return; 68356896Sfenner 684127675Sbms /* 685127675Sbms * if this isn't the first frag, we're missing the 686127675Sbms * next level protocol header. print the ip addr 687127675Sbms * and the protocol. 688127675Sbms */ 689146778Ssam if (ipds->off & 0x1fff) { 690146778Ssam (void)printf("%s > %s:", ipaddr_string(&ipds->ip->ip_src), 691146778Ssam ipaddr_string(&ipds->ip->ip_dst)); 692146778Ssam if ((proto = getprotobynumber(ipds->ip->ip_p)) != NULL) 693127675Sbms (void)printf(" %s", proto->p_name); 694127675Sbms else 695146778Ssam (void)printf(" ip-proto-%d", ipds->ip->ip_p); 696127675Sbms } 69756896Sfenner } 69817680Spst} 69975118Sfenner 70075118Sfennervoid 70175118SfenneripN_print(register const u_char *bp, register u_int length) 70275118Sfenner{ 70375118Sfenner struct ip *ip, hdr; 70475118Sfenner 70575118Sfenner ip = (struct ip *)bp; 70675118Sfenner if (length < 4) { 70775118Sfenner (void)printf("truncated-ip %d", length); 70875118Sfenner return; 70975118Sfenner } 71075118Sfenner memcpy (&hdr, (char *)ip, 4); 71175118Sfenner switch (IP_V(&hdr)) { 71275118Sfenner case 4: 713146778Ssam ip_print (gndo, bp, length); 71498527Sfenner return; 71575118Sfenner#ifdef INET6 71675118Sfenner case 6: 71798527Sfenner ip6_print (bp, length); 71898527Sfenner return; 71975118Sfenner#endif 72075118Sfenner default: 72198527Sfenner (void)printf("unknown ip %d", IP_V(&hdr)); 72298527Sfenner return; 72375118Sfenner } 72475118Sfenner} 725127675Sbms 726146778Ssam/* 727146778Ssam * Local Variables: 728146778Ssam * c-style: whitesmith 729146778Ssam * c-basic-offset: 8 730146778Ssam * End: 731146778Ssam */ 732127675Sbms 733127675Sbms 734