print-ip.c revision 172686
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 172686 2007-10-16 02:31:48Z mlaier $ 2217680Spst */ 2317680Spst 2417680Spst#ifndef lint 25127675Sbmsstatic const char rcsid[] _U_ = 26172686Smlaier "@(#) $Header: /tcpdump/master/tcpdump/print-ip.c,v 1.149.2.9 2007/09/14 01:30:02 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" }, 55172686Smlaier { IPOPT_RFC1393, "traceroute" }, 56146778Ssam { 0, NULL } 57146778Ssam}; 58146778Ssam 5917680Spst/* 6017680Spst * print the recorded route in an IP RR, LSRR or SSRR option. 6117680Spst */ 6217680Spststatic void 63146778Ssamip_printroute(register const u_char *cp, u_int length) 6417680Spst{ 65127675Sbms register u_int ptr; 6617680Spst register u_int len; 6717680Spst 68127675Sbms if (length < 3) { 69127675Sbms printf(" [bad length %u]", length); 70127675Sbms return; 71127675Sbms } 7217680Spst if ((length + 1) & 3) 73127675Sbms printf(" [bad length %u]", length); 74127675Sbms ptr = cp[2] - 1; 7517680Spst if (ptr < 3 || ((ptr + 1) & 3) || ptr > length + 1) 76127675Sbms printf(" [bad ptr %u]", cp[2]); 7717680Spst 7817680Spst for (len = 3; len < length; len += 4) { 79172686Smlaier printf(" %s", ipaddr_string(&cp[len])); 80146778Ssam if (ptr > len) 81172686Smlaier printf(","); 8217680Spst } 8317680Spst} 8417680Spst 85127675Sbms/* 86146778Ssam * If source-routing is present and valid, return the final destination. 87127675Sbms * Otherwise, return IP destination. 88127675Sbms * 89127675Sbms * This is used for UDP and TCP pseudo-header in the checksum 90127675Sbms * calculation. 91127675Sbms */ 92127675Sbmsu_int32_t 93127675Sbmsip_finddst(const struct ip *ip) 94127675Sbms{ 95127675Sbms int length; 96127675Sbms int len; 97127675Sbms const u_char *cp; 98127675Sbms u_int32_t retval; 99127675Sbms 100127675Sbms cp = (const u_char *)(ip + 1); 101127675Sbms length = (IP_HL(ip) << 2) - sizeof(struct ip); 102127675Sbms 103127675Sbms for (; length > 0; cp += len, length -= len) { 104127675Sbms int tt; 105127675Sbms 106127675Sbms TCHECK(*cp); 107127675Sbms tt = *cp; 108146778Ssam if (tt == IPOPT_EOL) 109146778Ssam break; 110146778Ssam else if (tt == IPOPT_NOP) 111127675Sbms len = 1; 112127675Sbms else { 113127675Sbms TCHECK(cp[1]); 114127675Sbms len = cp[1]; 115146778Ssam if (len < 2) 116146778Ssam break; 117127675Sbms } 118127675Sbms TCHECK2(*cp, len); 119127675Sbms switch (tt) { 120127675Sbms 121127675Sbms case IPOPT_SSRR: 122127675Sbms case IPOPT_LSRR: 123127675Sbms if (len < 7) 124146778Ssam break; 125127675Sbms memcpy(&retval, cp + len - 4, 4); 126127675Sbms return retval; 127127675Sbms } 128127675Sbms } 129127675Sbmstrunc: 130146778Ssam memcpy(&retval, &ip->ip_dst.s_addr, sizeof(u_int32_t)); 131146778Ssam return retval; 132127675Sbms} 133127675Sbms 13456896Sfennerstatic void 13556896Sfennerip_printts(register const u_char *cp, u_int length) 13656896Sfenner{ 137127675Sbms register u_int ptr; 138127675Sbms register u_int len; 13956896Sfenner int hoplen; 140127675Sbms const char *type; 14156896Sfenner 142127675Sbms if (length < 4) { 143172686Smlaier printf("[bad length %u]", length); 144127675Sbms return; 145127675Sbms } 14656896Sfenner printf(" TS{"); 14756896Sfenner hoplen = ((cp[3]&0xF) != IPOPT_TS_TSONLY) ? 8 : 4; 14856896Sfenner if ((length - 4) & (hoplen-1)) 149172686Smlaier printf("[bad length %u]", length); 150127675Sbms ptr = cp[2] - 1; 151127675Sbms len = 0; 15256896Sfenner if (ptr < 4 || ((ptr - 4) & (hoplen-1)) || ptr > length + 1) 153172686Smlaier printf("[bad ptr %u]", cp[2]); 15456896Sfenner switch (cp[3]&0xF) { 15556896Sfenner case IPOPT_TS_TSONLY: 15656896Sfenner printf("TSONLY"); 15756896Sfenner break; 15856896Sfenner case IPOPT_TS_TSANDADDR: 15956896Sfenner printf("TS+ADDR"); 16056896Sfenner break; 16156896Sfenner /* 16256896Sfenner * prespecified should really be 3, but some ones might send 2 16356896Sfenner * instead, and the IPOPT_TS_PRESPEC constant can apparently 16456896Sfenner * have both values, so we have to hard-code it here. 16556896Sfenner */ 16656896Sfenner 16756896Sfenner case 2: 16856896Sfenner printf("PRESPEC2.0"); 16956896Sfenner break; 17056896Sfenner case 3: /* IPOPT_TS_PRESPEC */ 17156896Sfenner printf("PRESPEC"); 17256896Sfenner break; 173127675Sbms default: 17456896Sfenner printf("[bad ts type %d]", cp[3]&0xF); 17556896Sfenner goto done; 17656896Sfenner } 17756896Sfenner 17856896Sfenner type = " "; 17956896Sfenner for (len = 4; len < length; len += hoplen) { 18056896Sfenner if (ptr == len) 18156896Sfenner type = " ^ "; 18256896Sfenner printf("%s%d@%s", type, EXTRACT_32BITS(&cp[len+hoplen-4]), 18356896Sfenner hoplen!=8 ? "" : ipaddr_string(&cp[len])); 18456896Sfenner type = " "; 18556896Sfenner } 18656896Sfenner 18756896Sfennerdone: 18856896Sfenner printf("%s", ptr == len ? " ^ " : ""); 18956896Sfenner 19056896Sfenner if (cp[3]>>4) 19156896Sfenner printf(" [%d hops not recorded]} ", cp[3]>>4); 19256896Sfenner else 19356896Sfenner printf("}"); 19456896Sfenner} 19556896Sfenner 19617680Spst/* 19717680Spst * print IP options. 19817680Spst */ 19917680Spststatic void 20017680Spstip_optprint(register const u_char *cp, u_int length) 20117680Spst{ 202146778Ssam register u_int option_len; 203172686Smlaier const char *sep = ""; 20417680Spst 205146778Ssam for (; length > 0; cp += option_len, length -= option_len) { 206146778Ssam u_int option_code; 20717680Spst 208172686Smlaier printf("%s", sep); 209172686Smlaier sep = ","; 210172686Smlaier 211127675Sbms TCHECK(*cp); 212146778Ssam option_code = *cp; 213146778Ssam 214172686Smlaier printf("%s", 215172686Smlaier tok2str(ip_option_values,"unknown %u",option_code)); 216172686Smlaier 217146778Ssam if (option_code == IPOPT_NOP || 218146778Ssam option_code == IPOPT_EOL) 219146778Ssam option_len = 1; 220146778Ssam 22175118Sfenner else { 222127675Sbms TCHECK(cp[1]); 223172686Smlaier option_len = cp[1]; 224172686Smlaier if (option_len < 2) { 225172686Smlaier printf(" [bad length %u]", option_len); 226172686Smlaier return; 227172686Smlaier } 22875118Sfenner } 22917680Spst 230172686Smlaier if (option_len > length) { 231172686Smlaier printf(" [bad length %u]", option_len); 232172686Smlaier return; 233172686Smlaier } 234146778Ssam 235146778Ssam TCHECK2(*cp, option_len); 236146778Ssam 237146778Ssam switch (option_code) { 23817680Spst case IPOPT_EOL: 23917680Spst return; 24017680Spst 24117680Spst case IPOPT_TS: 242146778Ssam ip_printts(cp, option_len); 24317680Spst break; 24417680Spst 245146778Ssam case IPOPT_RR: /* fall through */ 24617680Spst case IPOPT_SSRR: 24717680Spst case IPOPT_LSRR: 248172686Smlaier ip_printroute(cp, option_len); 24917680Spst break; 25017680Spst 25117691Spst case IPOPT_RA: 252172686Smlaier if (option_len < 4) { 253172686Smlaier printf(" [bad length %u]", option_len); 254172686Smlaier break; 255172686Smlaier } 256146778Ssam TCHECK(cp[3]); 257146778Ssam if (EXTRACT_16BITS(&cp[2]) != 0) 258172686Smlaier printf(" value %u", EXTRACT_16BITS(&cp[2])); 25998527Sfenner break; 26017691Spst 261146778Ssam case IPOPT_NOP: /* nothing to print - fall through */ 262146778Ssam case IPOPT_SECURITY: 26317680Spst default: 26417680Spst break; 26517680Spst } 26617680Spst } 267127675Sbms return; 268127675Sbms 269127675Sbmstrunc: 270127675Sbms printf("[|ip]"); 27117680Spst} 27217680Spst 27317680Spst/* 27417680Spst * compute an IP header checksum. 27517680Spst * don't modifiy the packet. 27617680Spst */ 27756896Sfenneru_short 27898527Sfennerin_cksum(const u_short *addr, register u_int len, int csum) 27917680Spst{ 28056896Sfenner int nleft = len; 28156896Sfenner const u_short *w = addr; 28256896Sfenner u_short answer; 28356896Sfenner int sum = csum; 28417680Spst 285127675Sbms /* 28656896Sfenner * Our algorithm is simple, using a 32 bit accumulator (sum), 28756896Sfenner * we add sequential 16 bit words to it, and at the end, fold 28856896Sfenner * back all the carry bits from the top 16 bits into the lower 28956896Sfenner * 16 bits. 290127675Sbms */ 29156896Sfenner while (nleft > 1) { 29256896Sfenner sum += *w++; 29356896Sfenner nleft -= 2; 29456896Sfenner } 29556896Sfenner if (nleft == 1) 29656896Sfenner sum += htons(*(u_char *)w<<8); 29756896Sfenner 29817680Spst /* 29956896Sfenner * add back carry outs from top 16 bits to low 16 bits 30017680Spst */ 30156896Sfenner sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 30256896Sfenner sum += (sum >> 16); /* add carry */ 30356896Sfenner answer = ~sum; /* truncate to 16 bits */ 30456896Sfenner return (answer); 30517680Spst} 30617680Spst 30717680Spst/* 308127675Sbms * Given the host-byte-order value of the checksum field in a packet 309127675Sbms * header, and the network-byte-order computed checksum of the data 310127675Sbms * that the checksum covers (including the checksum itself), compute 311127675Sbms * what the checksum field *should* have been. 312127675Sbms */ 313127675Sbmsu_int16_t 314127675Sbmsin_cksum_shouldbe(u_int16_t sum, u_int16_t computed_sum) 315127675Sbms{ 316127675Sbms u_int32_t shouldbe; 317127675Sbms 318127675Sbms /* 319127675Sbms * The value that should have gone into the checksum field 320127675Sbms * is the negative of the value gotten by summing up everything 321127675Sbms * *but* the checksum field. 322127675Sbms * 323127675Sbms * We can compute that by subtracting the value of the checksum 324127675Sbms * field from the sum of all the data in the packet, and then 325127675Sbms * computing the negative of that value. 326127675Sbms * 327127675Sbms * "sum" is the value of the checksum field, and "computed_sum" 328127675Sbms * is the negative of the sum of all the data in the packets, 329127675Sbms * so that's -(-computed_sum - sum), or (sum + computed_sum). 330127675Sbms * 331127675Sbms * All the arithmetic in question is one's complement, so the 332127675Sbms * addition must include an end-around carry; we do this by 333127675Sbms * doing the arithmetic in 32 bits (with no sign-extension), 334127675Sbms * and then adding the upper 16 bits of the sum, which contain 335127675Sbms * the carry, to the lower 16 bits of the sum, and then do it 336127675Sbms * again in case *that* sum produced a carry. 337127675Sbms * 338127675Sbms * As RFC 1071 notes, the checksum can be computed without 339127675Sbms * byte-swapping the 16-bit words; summing 16-bit words 340127675Sbms * on a big-endian machine gives a big-endian checksum, which 341127675Sbms * can be directly stuffed into the big-endian checksum fields 342127675Sbms * in protocol headers, and summing words on a little-endian 343127675Sbms * machine gives a little-endian checksum, which must be 344127675Sbms * byte-swapped before being stuffed into a big-endian checksum 345127675Sbms * field. 346127675Sbms * 347127675Sbms * "computed_sum" is a network-byte-order value, so we must put 348127675Sbms * it in host byte order before subtracting it from the 349127675Sbms * host-byte-order value from the header; the adjusted checksum 350127675Sbms * will be in host byte order, which is what we'll return. 351127675Sbms */ 352127675Sbms shouldbe = sum; 353127675Sbms shouldbe += ntohs(computed_sum); 354127675Sbms shouldbe = (shouldbe & 0xFFFF) + (shouldbe >> 16); 355127675Sbms shouldbe = (shouldbe & 0xFFFF) + (shouldbe >> 16); 356127675Sbms return shouldbe; 357127675Sbms} 358127675Sbms 359127675Sbms#define IP_RES 0x8000 360127675Sbms 361127675Sbmsstatic struct tok ip_frag_values[] = { 362127675Sbms { IP_MF, "+" }, 363127675Sbms { IP_DF, "DF" }, 364127675Sbms { IP_RES, "rsvd" }, /* The RFC3514 evil ;-) bit */ 365127675Sbms { 0, NULL } 366127675Sbms}; 367127675Sbms 368146778Ssamstruct ip_print_demux_state { 369146778Ssam const struct ip *ip; 370146778Ssam const u_char *cp; 371146778Ssam u_int len, off; 372146778Ssam u_char nh; 373146778Ssam int advance; 374146778Ssam}; 375146778Ssam 376146778Ssamstatic void 377146778Ssamip_print_demux(netdissect_options *ndo, 378146778Ssam struct ip_print_demux_state *ipds) 379146778Ssam{ 380146778Ssam struct protoent *proto; 381146778Ssam 382146778Ssamagain: 383146778Ssam switch (ipds->nh) { 384146778Ssam 385146778Ssam case IPPROTO_AH: 386146778Ssam ipds->nh = *ipds->cp; 387146778Ssam ipds->advance = ah_print(ipds->cp); 388146778Ssam if (ipds->advance <= 0) 389146778Ssam break; 390146778Ssam ipds->cp += ipds->advance; 391146778Ssam ipds->len -= ipds->advance; 392146778Ssam goto again; 393146778Ssam 394146778Ssam case IPPROTO_ESP: 395146778Ssam { 396146778Ssam int enh, padlen; 397146778Ssam ipds->advance = esp_print(ndo, ipds->cp, ipds->len, 398146778Ssam (const u_char *)ipds->ip, 399146778Ssam &enh, &padlen); 400146778Ssam if (ipds->advance <= 0) 401146778Ssam break; 402146778Ssam ipds->cp += ipds->advance; 403146778Ssam ipds->len -= ipds->advance + padlen; 404146778Ssam ipds->nh = enh & 0xff; 405146778Ssam goto again; 406146778Ssam } 407146778Ssam 408146778Ssam case IPPROTO_IPCOMP: 409146778Ssam { 410146778Ssam int enh; 411146778Ssam ipds->advance = ipcomp_print(ipds->cp, &enh); 412146778Ssam if (ipds->advance <= 0) 413146778Ssam break; 414146778Ssam ipds->cp += ipds->advance; 415146778Ssam ipds->len -= ipds->advance; 416146778Ssam ipds->nh = enh & 0xff; 417146778Ssam goto again; 418146778Ssam } 419146778Ssam 420146778Ssam case IPPROTO_SCTP: 421146778Ssam sctp_print(ipds->cp, (const u_char *)ipds->ip, ipds->len); 422146778Ssam break; 423162021Ssam 424162021Ssam case IPPROTO_DCCP: 425162021Ssam dccp_print(ipds->cp, (const u_char *)ipds->ip, ipds->len); 426162021Ssam break; 427146778Ssam 428146778Ssam case IPPROTO_TCP: 429172686Smlaier /* pass on the MF bit plus the offset to detect fragments */ 430146778Ssam tcp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip, 431172686Smlaier ipds->off & (IP_MF|IP_OFFMASK)); 432146778Ssam break; 433146778Ssam 434146778Ssam case IPPROTO_UDP: 435172686Smlaier /* pass on the MF bit plus the offset to detect fragments */ 436146778Ssam udp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip, 437172686Smlaier ipds->off & (IP_MF|IP_OFFMASK)); 438146778Ssam break; 439146778Ssam 440146778Ssam case IPPROTO_ICMP: 441146778Ssam /* pass on the MF bit plus the offset to detect fragments */ 442146778Ssam icmp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip, 443172686Smlaier ipds->off & (IP_MF|IP_OFFMASK)); 444146778Ssam break; 445146778Ssam 446146778Ssam case IPPROTO_PIGP: 447146778Ssam /* 448146778Ssam * XXX - the current IANA protocol number assignments 449146778Ssam * page lists 9 as "any private interior gateway 450146778Ssam * (used by Cisco for their IGRP)" and 88 as 451146778Ssam * "EIGRP" from Cisco. 452146778Ssam * 453146778Ssam * Recent BSD <netinet/in.h> headers define 454146778Ssam * IP_PROTO_PIGP as 9 and IP_PROTO_IGRP as 88. 455146778Ssam * We define IP_PROTO_PIGP as 9 and 456146778Ssam * IP_PROTO_EIGRP as 88; those names better 457146778Ssam * match was the current protocol number 458146778Ssam * assignments say. 459146778Ssam */ 460146778Ssam igrp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip); 461146778Ssam break; 462146778Ssam 463146778Ssam case IPPROTO_EIGRP: 464146778Ssam eigrp_print(ipds->cp, ipds->len); 465146778Ssam break; 466146778Ssam 467146778Ssam case IPPROTO_ND: 468146778Ssam ND_PRINT((ndo, " nd %d", ipds->len)); 469146778Ssam break; 470146778Ssam 471146778Ssam case IPPROTO_EGP: 472146778Ssam egp_print(ipds->cp, ipds->len); 473146778Ssam break; 474146778Ssam 475146778Ssam case IPPROTO_OSPF: 476146778Ssam ospf_print(ipds->cp, ipds->len, (const u_char *)ipds->ip); 477146778Ssam break; 478146778Ssam 479146778Ssam case IPPROTO_IGMP: 480146778Ssam igmp_print(ipds->cp, ipds->len); 481146778Ssam break; 482146778Ssam 483146778Ssam case IPPROTO_IPV4: 484146778Ssam /* DVMRP multicast tunnel (ip-in-ip encapsulation) */ 485146778Ssam ip_print(gndo, ipds->cp, ipds->len); 486146778Ssam if (! vflag) { 487146778Ssam ND_PRINT((ndo, " (ipip-proto-4)")); 488146778Ssam return; 489146778Ssam } 490146778Ssam break; 491146778Ssam 492146778Ssam#ifdef INET6 493146778Ssam case IPPROTO_IPV6: 494146778Ssam /* ip6-in-ip encapsulation */ 495146778Ssam ip6_print(ipds->cp, ipds->len); 496146778Ssam break; 497146778Ssam#endif /*INET6*/ 498146778Ssam 499146778Ssam case IPPROTO_RSVP: 500146778Ssam rsvp_print(ipds->cp, ipds->len); 501146778Ssam break; 502146778Ssam 503146778Ssam case IPPROTO_GRE: 504146778Ssam /* do it */ 505146778Ssam gre_print(ipds->cp, ipds->len); 506146778Ssam break; 507146778Ssam 508146778Ssam case IPPROTO_MOBILE: 509146778Ssam mobile_print(ipds->cp, ipds->len); 510146778Ssam break; 511146778Ssam 512146778Ssam case IPPROTO_PIM: 513146778Ssam pim_print(ipds->cp, ipds->len); 514146778Ssam break; 515146778Ssam 516146778Ssam case IPPROTO_VRRP: 517146778Ssam vrrp_print(ipds->cp, ipds->len, ipds->ip->ip_ttl); 518146778Ssam break; 519146778Ssam 520147904Ssam case IPPROTO_PGM: 521147904Ssam pgm_print(ipds->cp, ipds->len, (const u_char *)ipds->ip); 522147904Ssam break; 523147904Ssam 524146778Ssam default: 525146778Ssam if ((proto = getprotobynumber(ipds->nh)) != NULL) 526146778Ssam ND_PRINT((ndo, " %s", proto->p_name)); 527146778Ssam else 528146778Ssam ND_PRINT((ndo, " ip-proto-%d", ipds->nh)); 529146778Ssam ND_PRINT((ndo, " %d", ipds->len)); 530146778Ssam break; 531146778Ssam } 532146778Ssam} 533146778Ssam 534146778Ssamvoid 535146778Ssamip_print_inner(netdissect_options *ndo, 536146778Ssam const u_char *bp, 537146778Ssam u_int length, u_int nh, 538146778Ssam const u_char *bp2) 539146778Ssam{ 540146778Ssam struct ip_print_demux_state ipd; 541146778Ssam 542146778Ssam ipd.ip = (const struct ip *)bp2; 543146778Ssam ipd.cp = bp; 544146778Ssam ipd.len = length; 545146778Ssam ipd.off = 0; 546146778Ssam ipd.nh = nh; 547146778Ssam ipd.advance = 0; 548146778Ssam 549146778Ssam ip_print_demux(ndo, &ipd); 550146778Ssam} 551146778Ssam 552146778Ssam 553127675Sbms/* 55417680Spst * print an IP datagram. 55517680Spst */ 55617680Spstvoid 557146778Ssamip_print(netdissect_options *ndo, 558146778Ssam const u_char *bp, 559146778Ssam u_int length) 56017680Spst{ 561146778Ssam struct ip_print_demux_state ipd; 562146778Ssam struct ip_print_demux_state *ipds=&ipd; 563127675Sbms const u_char *ipend; 564146778Ssam u_int hlen; 565146778Ssam u_int16_t sum, ip_sum; 566111729Sfenner struct protoent *proto; 56717680Spst 568146778Ssam ipds->ip = (const struct ip *)bp; 569146778Ssam if (IP_V(ipds->ip) != 4) { /* print version if != 4 */ 570146778Ssam printf("IP%u ", IP_V(ipds->ip)); 571146778Ssam if (IP_V(ipds->ip) == 6) 572127675Sbms printf(", wrong link-layer encapsulation"); 573127675Sbms } 574146778Ssam else if (!eflag) 575127675Sbms printf("IP "); 57617680Spst 577146778Ssam if ((u_char *)(ipds->ip + 1) > snapend) { 57817680Spst printf("[|ip]"); 57917680Spst return; 58017680Spst } 58117680Spst if (length < sizeof (struct ip)) { 582146778Ssam (void)printf("truncated-ip %u", length); 58317680Spst return; 58417680Spst } 585146778Ssam hlen = IP_HL(ipds->ip) * 4; 58675118Sfenner if (hlen < sizeof (struct ip)) { 587127675Sbms (void)printf("bad-hlen %u", hlen); 58875118Sfenner return; 58975118Sfenner } 59017680Spst 591146778Ssam ipds->len = EXTRACT_16BITS(&ipds->ip->ip_len); 592146778Ssam if (length < ipds->len) 593127675Sbms (void)printf("truncated-ip - %u bytes missing! ", 594146778Ssam ipds->len - length); 595146778Ssam if (ipds->len < hlen) { 596146778Ssam#ifdef GUESS_TSO 597146778Ssam if (ipds->len) { 598146778Ssam (void)printf("bad-len %u", ipds->len); 599146778Ssam return; 600146778Ssam } 601146778Ssam else { 602146778Ssam /* we guess that it is a TSO send */ 603146778Ssam ipds->len = length; 604146778Ssam } 605146778Ssam#else 606146778Ssam (void)printf("bad-len %u", ipds->len); 607146778Ssam return; 608146778Ssam#endif /* GUESS_TSO */ 609127675Sbms } 610127675Sbms 611127675Sbms /* 612127675Sbms * Cut off the snapshot length to the end of the IP payload. 613127675Sbms */ 614146778Ssam ipend = bp + ipds->len; 615127675Sbms if (ipend < snapend) 616127675Sbms snapend = ipend; 617127675Sbms 618146778Ssam ipds->len -= hlen; 61917680Spst 620146778Ssam ipds->off = EXTRACT_16BITS(&ipds->ip->ip_off); 621127675Sbms 622127675Sbms if (vflag) { 623146778Ssam (void)printf("(tos 0x%x", (int)ipds->ip->ip_tos); 624127675Sbms /* ECN bits */ 625146778Ssam if (ipds->ip->ip_tos & 0x03) { 626146778Ssam switch (ipds->ip->ip_tos & 0x03) { 627127675Sbms case 1: 628127675Sbms (void)printf(",ECT(1)"); 629127675Sbms break; 630127675Sbms case 2: 631127675Sbms (void)printf(",ECT(0)"); 632127675Sbms break; 633127675Sbms case 3: 634127675Sbms (void)printf(",CE"); 635127675Sbms } 636127675Sbms } 637127675Sbms 638146778Ssam if (ipds->ip->ip_ttl >= 1) 639172686Smlaier (void)printf(", ttl %u", ipds->ip->ip_ttl); 640127675Sbms 641127675Sbms /* 642127675Sbms * for the firewall guys, print id, offset. 643127675Sbms * On all but the last stick a "+" in the flags portion. 644127675Sbms * For unfragmented datagrams, note the don't fragment flag. 645127675Sbms */ 646127675Sbms 647172686Smlaier (void)printf(", id %u, offset %u, flags [%s], proto %s (%u)", 648146778Ssam EXTRACT_16BITS(&ipds->ip->ip_id), 649146778Ssam (ipds->off & 0x1fff) * 8, 650172686Smlaier bittok2str(ip_frag_values, "none", ipds->off&0xe000), 651146778Ssam tok2str(ipproto_values,"unknown",ipds->ip->ip_p), 652146778Ssam ipds->ip->ip_p); 653127675Sbms 654172686Smlaier (void)printf(", length %u", EXTRACT_16BITS(&ipds->ip->ip_len)); 655127675Sbms 656127675Sbms if ((hlen - sizeof(struct ip)) > 0) { 657172686Smlaier printf(", options ("); 658146778Ssam ip_optprint((u_char *)(ipds->ip + 1), hlen - sizeof(struct ip)); 659172686Smlaier printf(")"); 660127675Sbms } 661127675Sbms 662146778Ssam if ((u_char *)ipds->ip + hlen <= snapend) { 663146778Ssam sum = in_cksum((const u_short *)ipds->ip, hlen, 0); 664127675Sbms if (sum != 0) { 665146778Ssam ip_sum = EXTRACT_16BITS(&ipds->ip->ip_sum); 666127675Sbms (void)printf(", bad cksum %x (->%x)!", ip_sum, 667127675Sbms in_cksum_shouldbe(ip_sum, sum)); 668127675Sbms } 669127675Sbms } 670127675Sbms 671127675Sbms printf(") "); 672127675Sbms } 673127675Sbms 67417680Spst /* 67517680Spst * If this is fragment zero, hand it to the next higher 67617680Spst * level protocol. 67717680Spst */ 678146778Ssam if ((ipds->off & 0x1fff) == 0) { 679146778Ssam ipds->cp = (const u_char *)ipds->ip + hlen; 680146778Ssam ipds->nh = ipds->ip->ip_p; 68117680Spst 682146778Ssam if (ipds->nh != IPPROTO_TCP && ipds->nh != IPPROTO_UDP && 683162021Ssam ipds->nh != IPPROTO_SCTP && ipds->nh != IPPROTO_DCCP) { 684146778Ssam (void)printf("%s > %s: ", 685146778Ssam ipaddr_string(&ipds->ip->ip_src), 686146778Ssam ipaddr_string(&ipds->ip->ip_dst)); 68756896Sfenner } 688146778Ssam ip_print_demux(ndo, ipds); 689127675Sbms } else { 690127675Sbms /* Ultra quiet now means that all this stuff should be suppressed */ 691127675Sbms if (qflag > 1) return; 69256896Sfenner 693127675Sbms /* 694127675Sbms * if this isn't the first frag, we're missing the 695127675Sbms * next level protocol header. print the ip addr 696127675Sbms * and the protocol. 697127675Sbms */ 698146778Ssam if (ipds->off & 0x1fff) { 699146778Ssam (void)printf("%s > %s:", ipaddr_string(&ipds->ip->ip_src), 700146778Ssam ipaddr_string(&ipds->ip->ip_dst)); 701146778Ssam if ((proto = getprotobynumber(ipds->ip->ip_p)) != NULL) 702127675Sbms (void)printf(" %s", proto->p_name); 703127675Sbms else 704146778Ssam (void)printf(" ip-proto-%d", ipds->ip->ip_p); 705127675Sbms } 70656896Sfenner } 70717680Spst} 70875118Sfenner 70975118Sfennervoid 71075118SfenneripN_print(register const u_char *bp, register u_int length) 71175118Sfenner{ 71275118Sfenner struct ip *ip, hdr; 71375118Sfenner 71475118Sfenner ip = (struct ip *)bp; 71575118Sfenner if (length < 4) { 71675118Sfenner (void)printf("truncated-ip %d", length); 71775118Sfenner return; 71875118Sfenner } 71975118Sfenner memcpy (&hdr, (char *)ip, 4); 72075118Sfenner switch (IP_V(&hdr)) { 72175118Sfenner case 4: 722146778Ssam ip_print (gndo, bp, length); 72398527Sfenner return; 72475118Sfenner#ifdef INET6 72575118Sfenner case 6: 72698527Sfenner ip6_print (bp, length); 72798527Sfenner return; 72875118Sfenner#endif 72975118Sfenner default: 73098527Sfenner (void)printf("unknown ip %d", IP_V(&hdr)); 73198527Sfenner return; 73275118Sfenner } 73375118Sfenner} 734127675Sbms 735146778Ssam/* 736146778Ssam * Local Variables: 737146778Ssam * c-style: whitesmith 738146778Ssam * c-basic-offset: 8 739146778Ssam * End: 740146778Ssam */ 741127675Sbms 742127675Sbms 743