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. 2017680Spst */ 2117680Spst 22313537Sglebius/* \summary: IP printer */ 23313537Sglebius 2456896Sfenner#ifdef HAVE_CONFIG_H 2556896Sfenner#include "config.h" 2656896Sfenner#endif 2756896Sfenner 28313537Sglebius#include <netdissect-stdinc.h> 2917680Spst 3017680Spst#include <string.h> 3117680Spst 32313537Sglebius#include "netdissect.h" 3317680Spst#include "addrtoname.h" 34313537Sglebius#include "extract.h" 3517680Spst 3675118Sfenner#include "ip.h" 37127675Sbms#include "ipproto.h" 3875118Sfenner 39276788Sdelphijstatic const char tstr[] = "[|ip]"; 40276788Sdelphij 41276788Sdelphijstatic const struct tok ip_option_values[] = { 42146778Ssam { IPOPT_EOL, "EOL" }, 43146778Ssam { IPOPT_NOP, "NOP" }, 44146778Ssam { IPOPT_TS, "timestamp" }, 45146778Ssam { IPOPT_SECURITY, "security" }, 46146778Ssam { IPOPT_RR, "RR" }, 47146778Ssam { IPOPT_SSRR, "SSRR" }, 48146778Ssam { IPOPT_LSRR, "LSRR" }, 49146778Ssam { IPOPT_RA, "RA" }, 50172686Smlaier { IPOPT_RFC1393, "traceroute" }, 51146778Ssam { 0, NULL } 52146778Ssam}; 53146778Ssam 5417680Spst/* 5517680Spst * print the recorded route in an IP RR, LSRR or SSRR option. 5617680Spst */ 57327234Semastestatic int 58276788Sdelphijip_printroute(netdissect_options *ndo, 59276788Sdelphij register const u_char *cp, u_int length) 6017680Spst{ 61127675Sbms register u_int ptr; 6217680Spst register u_int len; 6317680Spst 64127675Sbms if (length < 3) { 65276788Sdelphij ND_PRINT((ndo, " [bad length %u]", length)); 66327234Semaste return (0); 67127675Sbms } 6817680Spst if ((length + 1) & 3) 69276788Sdelphij ND_PRINT((ndo, " [bad length %u]", length)); 70327234Semaste ND_TCHECK(cp[2]); 71127675Sbms ptr = cp[2] - 1; 7217680Spst if (ptr < 3 || ((ptr + 1) & 3) || ptr > length + 1) 73276788Sdelphij ND_PRINT((ndo, " [bad ptr %u]", cp[2])); 7417680Spst 7517680Spst for (len = 3; len < length; len += 4) { 76327234Semaste ND_TCHECK2(cp[len], 4); 77276788Sdelphij ND_PRINT((ndo, " %s", ipaddr_string(ndo, &cp[len]))); 78276788Sdelphij if (ptr > len) 79276788Sdelphij ND_PRINT((ndo, ",")); 8017680Spst } 81327234Semaste return (0); 82327234Semaste 83327234Semastetrunc: 84327234Semaste return (-1); 8517680Spst} 8617680Spst 87127675Sbms/* 88146778Ssam * If source-routing is present and valid, return the final destination. 89127675Sbms * Otherwise, return IP destination. 90127675Sbms * 91127675Sbms * This is used for UDP and TCP pseudo-header in the checksum 92127675Sbms * calculation. 93127675Sbms */ 94276788Sdelphijstatic uint32_t 95276788Sdelphijip_finddst(netdissect_options *ndo, 96276788Sdelphij const struct ip *ip) 97127675Sbms{ 98127675Sbms int length; 99127675Sbms int len; 100127675Sbms const u_char *cp; 101276788Sdelphij uint32_t retval; 102127675Sbms 103127675Sbms cp = (const u_char *)(ip + 1); 104127675Sbms length = (IP_HL(ip) << 2) - sizeof(struct ip); 105127675Sbms 106127675Sbms for (; length > 0; cp += len, length -= len) { 107127675Sbms int tt; 108127675Sbms 109276788Sdelphij ND_TCHECK(*cp); 110127675Sbms tt = *cp; 111146778Ssam if (tt == IPOPT_EOL) 112146778Ssam break; 113146778Ssam else if (tt == IPOPT_NOP) 114127675Sbms len = 1; 115127675Sbms else { 116276788Sdelphij ND_TCHECK(cp[1]); 117127675Sbms len = cp[1]; 118146778Ssam if (len < 2) 119146778Ssam break; 120127675Sbms } 121276788Sdelphij ND_TCHECK2(*cp, len); 122127675Sbms switch (tt) { 123127675Sbms 124127675Sbms case IPOPT_SSRR: 125127675Sbms case IPOPT_LSRR: 126127675Sbms if (len < 7) 127146778Ssam break; 128276788Sdelphij UNALIGNED_MEMCPY(&retval, cp + len - 4, 4); 129127675Sbms return retval; 130127675Sbms } 131127675Sbms } 132127675Sbmstrunc: 133313537Sglebius UNALIGNED_MEMCPY(&retval, &ip->ip_dst, sizeof(uint32_t)); 134146778Ssam return retval; 135127675Sbms} 136127675Sbms 137235530Sdelphij/* 138235530Sdelphij * Compute a V4-style checksum by building a pseudoheader. 139235530Sdelphij */ 140235530Sdelphijint 141276788Sdelphijnextproto4_cksum(netdissect_options *ndo, 142276788Sdelphij const struct ip *ip, const uint8_t *data, 143276788Sdelphij u_int len, u_int covlen, u_int next_proto) 144235530Sdelphij{ 145235530Sdelphij struct phdr { 146276788Sdelphij uint32_t src; 147276788Sdelphij uint32_t dst; 148235530Sdelphij u_char mbz; 149235530Sdelphij u_char proto; 150276788Sdelphij uint16_t len; 151235530Sdelphij } ph; 152235530Sdelphij struct cksum_vec vec[2]; 153235530Sdelphij 154235530Sdelphij /* pseudo-header.. */ 155276788Sdelphij ph.len = htons((uint16_t)len); 156235530Sdelphij ph.mbz = 0; 157235530Sdelphij ph.proto = next_proto; 158313537Sglebius UNALIGNED_MEMCPY(&ph.src, &ip->ip_src, sizeof(uint32_t)); 159235530Sdelphij if (IP_HL(ip) == 5) 160313537Sglebius UNALIGNED_MEMCPY(&ph.dst, &ip->ip_dst, sizeof(uint32_t)); 161235530Sdelphij else 162276788Sdelphij ph.dst = ip_finddst(ndo, ip); 163235530Sdelphij 164276788Sdelphij vec[0].ptr = (const uint8_t *)(void *)&ph; 165235530Sdelphij vec[0].len = sizeof(ph); 166235530Sdelphij vec[1].ptr = data; 167276788Sdelphij vec[1].len = covlen; 168235530Sdelphij return (in_cksum(vec, 2)); 169235530Sdelphij} 170235530Sdelphij 171327234Semastestatic int 172276788Sdelphijip_printts(netdissect_options *ndo, 173276788Sdelphij register const u_char *cp, u_int length) 17456896Sfenner{ 175127675Sbms register u_int ptr; 176127675Sbms register u_int len; 17756896Sfenner int hoplen; 178127675Sbms const char *type; 17956896Sfenner 180127675Sbms if (length < 4) { 181276788Sdelphij ND_PRINT((ndo, "[bad length %u]", length)); 182327234Semaste return (0); 183127675Sbms } 184276788Sdelphij ND_PRINT((ndo, " TS{")); 18556896Sfenner hoplen = ((cp[3]&0xF) != IPOPT_TS_TSONLY) ? 8 : 4; 18656896Sfenner if ((length - 4) & (hoplen-1)) 187276788Sdelphij ND_PRINT((ndo, "[bad length %u]", length)); 188327234Semaste ND_TCHECK(cp[2]); 189127675Sbms ptr = cp[2] - 1; 190127675Sbms len = 0; 19156896Sfenner if (ptr < 4 || ((ptr - 4) & (hoplen-1)) || ptr > length + 1) 192276788Sdelphij ND_PRINT((ndo, "[bad ptr %u]", cp[2])); 193327234Semaste ND_TCHECK(cp[3]); 19456896Sfenner switch (cp[3]&0xF) { 19556896Sfenner case IPOPT_TS_TSONLY: 196276788Sdelphij ND_PRINT((ndo, "TSONLY")); 19756896Sfenner break; 19856896Sfenner case IPOPT_TS_TSANDADDR: 199276788Sdelphij ND_PRINT((ndo, "TS+ADDR")); 20056896Sfenner break; 20156896Sfenner /* 20256896Sfenner * prespecified should really be 3, but some ones might send 2 20356896Sfenner * instead, and the IPOPT_TS_PRESPEC constant can apparently 20456896Sfenner * have both values, so we have to hard-code it here. 20556896Sfenner */ 20656896Sfenner 20756896Sfenner case 2: 208276788Sdelphij ND_PRINT((ndo, "PRESPEC2.0")); 20956896Sfenner break; 21056896Sfenner case 3: /* IPOPT_TS_PRESPEC */ 211276788Sdelphij ND_PRINT((ndo, "PRESPEC")); 21256896Sfenner break; 213127675Sbms default: 214276788Sdelphij ND_PRINT((ndo, "[bad ts type %d]", cp[3]&0xF)); 21556896Sfenner goto done; 21656896Sfenner } 21756896Sfenner 21856896Sfenner type = " "; 21956896Sfenner for (len = 4; len < length; len += hoplen) { 22056896Sfenner if (ptr == len) 22156896Sfenner type = " ^ "; 222327234Semaste ND_TCHECK2(cp[len], hoplen); 223276788Sdelphij ND_PRINT((ndo, "%s%d@%s", type, EXTRACT_32BITS(&cp[len+hoplen-4]), 224276788Sdelphij hoplen!=8 ? "" : ipaddr_string(ndo, &cp[len]))); 22556896Sfenner type = " "; 22656896Sfenner } 22756896Sfenner 22856896Sfennerdone: 229276788Sdelphij ND_PRINT((ndo, "%s", ptr == len ? " ^ " : "")); 23056896Sfenner 23156896Sfenner if (cp[3]>>4) 232276788Sdelphij ND_PRINT((ndo, " [%d hops not recorded]} ", cp[3]>>4)); 23356896Sfenner else 234276788Sdelphij ND_PRINT((ndo, "}")); 235327234Semaste return (0); 236327234Semaste 237327234Semastetrunc: 238327234Semaste return (-1); 23956896Sfenner} 24056896Sfenner 24117680Spst/* 24217680Spst * print IP options. 24317680Spst */ 24417680Spststatic void 245276788Sdelphijip_optprint(netdissect_options *ndo, 246276788Sdelphij register const u_char *cp, u_int length) 24717680Spst{ 248146778Ssam register u_int option_len; 249172686Smlaier const char *sep = ""; 25017680Spst 251146778Ssam for (; length > 0; cp += option_len, length -= option_len) { 252146778Ssam u_int option_code; 25317680Spst 254276788Sdelphij ND_PRINT((ndo, "%s", sep)); 255172686Smlaier sep = ","; 256172686Smlaier 257276788Sdelphij ND_TCHECK(*cp); 258146778Ssam option_code = *cp; 259146778Ssam 260276788Sdelphij ND_PRINT((ndo, "%s", 261276788Sdelphij tok2str(ip_option_values,"unknown %u",option_code))); 262172686Smlaier 263146778Ssam if (option_code == IPOPT_NOP || 264146778Ssam option_code == IPOPT_EOL) 265146778Ssam option_len = 1; 266146778Ssam 26775118Sfenner else { 268276788Sdelphij ND_TCHECK(cp[1]); 269172686Smlaier option_len = cp[1]; 270172686Smlaier if (option_len < 2) { 271276788Sdelphij ND_PRINT((ndo, " [bad length %u]", option_len)); 272172686Smlaier return; 273172686Smlaier } 27475118Sfenner } 27517680Spst 276172686Smlaier if (option_len > length) { 277276788Sdelphij ND_PRINT((ndo, " [bad length %u]", option_len)); 278172686Smlaier return; 279172686Smlaier } 280146778Ssam 281276788Sdelphij ND_TCHECK2(*cp, option_len); 282146778Ssam 283146778Ssam switch (option_code) { 28417680Spst case IPOPT_EOL: 28517680Spst return; 28617680Spst 28717680Spst case IPOPT_TS: 288327234Semaste if (ip_printts(ndo, cp, option_len) == -1) 289327234Semaste goto trunc; 29017680Spst break; 29117680Spst 292146778Ssam case IPOPT_RR: /* fall through */ 29317680Spst case IPOPT_SSRR: 29417680Spst case IPOPT_LSRR: 295327234Semaste if (ip_printroute(ndo, cp, option_len) == -1) 296327234Semaste goto trunc; 29717680Spst break; 29817680Spst 29917691Spst case IPOPT_RA: 300172686Smlaier if (option_len < 4) { 301276788Sdelphij ND_PRINT((ndo, " [bad length %u]", option_len)); 302172686Smlaier break; 303172686Smlaier } 304276788Sdelphij ND_TCHECK(cp[3]); 305276788Sdelphij if (EXTRACT_16BITS(&cp[2]) != 0) 306276788Sdelphij ND_PRINT((ndo, " value %u", EXTRACT_16BITS(&cp[2]))); 30798527Sfenner break; 30817691Spst 309146778Ssam case IPOPT_NOP: /* nothing to print - fall through */ 310146778Ssam case IPOPT_SECURITY: 31117680Spst default: 31217680Spst break; 31317680Spst } 31417680Spst } 315127675Sbms return; 316127675Sbms 317127675Sbmstrunc: 318276788Sdelphij ND_PRINT((ndo, "%s", tstr)); 31917680Spst} 32017680Spst 321127675Sbms#define IP_RES 0x8000 322127675Sbms 323276788Sdelphijstatic const struct tok ip_frag_values[] = { 324127675Sbms { IP_MF, "+" }, 325127675Sbms { IP_DF, "DF" }, 326127675Sbms { IP_RES, "rsvd" }, /* The RFC3514 evil ;-) bit */ 327127675Sbms { 0, NULL } 328127675Sbms}; 329127675Sbms 330146778Ssamstruct ip_print_demux_state { 331146778Ssam const struct ip *ip; 332146778Ssam const u_char *cp; 333146778Ssam u_int len, off; 334146778Ssam u_char nh; 335146778Ssam int advance; 336146778Ssam}; 337146778Ssam 338146778Ssamstatic void 339146778Ssamip_print_demux(netdissect_options *ndo, 340146778Ssam struct ip_print_demux_state *ipds) 341146778Ssam{ 342327234Semaste const char *p_name; 343146778Ssam 344146778Ssamagain: 345146778Ssam switch (ipds->nh) { 346146778Ssam 347146778Ssam case IPPROTO_AH: 348313537Sglebius if (!ND_TTEST(*ipds->cp)) { 349313537Sglebius ND_PRINT((ndo, "[|AH]")); 350313537Sglebius break; 351313537Sglebius } 352146778Ssam ipds->nh = *ipds->cp; 353276788Sdelphij ipds->advance = ah_print(ndo, ipds->cp); 354146778Ssam if (ipds->advance <= 0) 355146778Ssam break; 356146778Ssam ipds->cp += ipds->advance; 357146778Ssam ipds->len -= ipds->advance; 358146778Ssam goto again; 359146778Ssam 360146778Ssam case IPPROTO_ESP: 361146778Ssam { 362146778Ssam int enh, padlen; 363146778Ssam ipds->advance = esp_print(ndo, ipds->cp, ipds->len, 364146778Ssam (const u_char *)ipds->ip, 365146778Ssam &enh, &padlen); 366146778Ssam if (ipds->advance <= 0) 367146778Ssam break; 368146778Ssam ipds->cp += ipds->advance; 369146778Ssam ipds->len -= ipds->advance + padlen; 370146778Ssam ipds->nh = enh & 0xff; 371146778Ssam goto again; 372146778Ssam } 373241235Sdelphij 374146778Ssam case IPPROTO_IPCOMP: 375146778Ssam { 376313537Sglebius ipcomp_print(ndo, ipds->cp); 377313537Sglebius /* 378313537Sglebius * Either this has decompressed the payload and 379313537Sglebius * printed it, in which case there's nothing more 380313537Sglebius * to do, or it hasn't, in which case there's 381313537Sglebius * nothing more to do. 382313537Sglebius */ 383313537Sglebius break; 384146778Ssam } 385146778Ssam 386146778Ssam case IPPROTO_SCTP: 387276788Sdelphij sctp_print(ndo, ipds->cp, (const u_char *)ipds->ip, ipds->len); 388146778Ssam break; 389162021Ssam 390162021Ssam case IPPROTO_DCCP: 391276788Sdelphij dccp_print(ndo, ipds->cp, (const u_char *)ipds->ip, ipds->len); 392162021Ssam break; 393241235Sdelphij 394146778Ssam case IPPROTO_TCP: 395172686Smlaier /* pass on the MF bit plus the offset to detect fragments */ 396276788Sdelphij tcp_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip, 397172686Smlaier ipds->off & (IP_MF|IP_OFFMASK)); 398146778Ssam break; 399241235Sdelphij 400146778Ssam case IPPROTO_UDP: 401172686Smlaier /* pass on the MF bit plus the offset to detect fragments */ 402276788Sdelphij udp_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip, 403172686Smlaier ipds->off & (IP_MF|IP_OFFMASK)); 404146778Ssam break; 405241235Sdelphij 406146778Ssam case IPPROTO_ICMP: 407146778Ssam /* pass on the MF bit plus the offset to detect fragments */ 408276788Sdelphij icmp_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip, 409172686Smlaier ipds->off & (IP_MF|IP_OFFMASK)); 410146778Ssam break; 411241235Sdelphij 412146778Ssam case IPPROTO_PIGP: 413146778Ssam /* 414146778Ssam * XXX - the current IANA protocol number assignments 415146778Ssam * page lists 9 as "any private interior gateway 416146778Ssam * (used by Cisco for their IGRP)" and 88 as 417146778Ssam * "EIGRP" from Cisco. 418146778Ssam * 419146778Ssam * Recent BSD <netinet/in.h> headers define 420146778Ssam * IP_PROTO_PIGP as 9 and IP_PROTO_IGRP as 88. 421146778Ssam * We define IP_PROTO_PIGP as 9 and 422146778Ssam * IP_PROTO_EIGRP as 88; those names better 423146778Ssam * match was the current protocol number 424146778Ssam * assignments say. 425146778Ssam */ 426276788Sdelphij igrp_print(ndo, ipds->cp, ipds->len); 427146778Ssam break; 428241235Sdelphij 429146778Ssam case IPPROTO_EIGRP: 430276788Sdelphij eigrp_print(ndo, ipds->cp, ipds->len); 431146778Ssam break; 432241235Sdelphij 433146778Ssam case IPPROTO_ND: 434146778Ssam ND_PRINT((ndo, " nd %d", ipds->len)); 435146778Ssam break; 436146778Ssam 437146778Ssam case IPPROTO_EGP: 438276788Sdelphij egp_print(ndo, ipds->cp, ipds->len); 439146778Ssam break; 440146778Ssam 441146778Ssam case IPPROTO_OSPF: 442276788Sdelphij ospf_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip); 443146778Ssam break; 444146778Ssam 445146778Ssam case IPPROTO_IGMP: 446276788Sdelphij igmp_print(ndo, ipds->cp, ipds->len); 447146778Ssam break; 448146778Ssam 449146778Ssam case IPPROTO_IPV4: 450146778Ssam /* DVMRP multicast tunnel (ip-in-ip encapsulation) */ 451235530Sdelphij ip_print(ndo, ipds->cp, ipds->len); 452276788Sdelphij if (! ndo->ndo_vflag) { 453146778Ssam ND_PRINT((ndo, " (ipip-proto-4)")); 454146778Ssam return; 455146778Ssam } 456146778Ssam break; 457241235Sdelphij 458146778Ssam case IPPROTO_IPV6: 459146778Ssam /* ip6-in-ip encapsulation */ 460235530Sdelphij ip6_print(ndo, ipds->cp, ipds->len); 461146778Ssam break; 462146778Ssam 463146778Ssam case IPPROTO_RSVP: 464276788Sdelphij rsvp_print(ndo, ipds->cp, ipds->len); 465146778Ssam break; 466146778Ssam 467146778Ssam case IPPROTO_GRE: 468146778Ssam /* do it */ 469276788Sdelphij gre_print(ndo, ipds->cp, ipds->len); 470146778Ssam break; 471146778Ssam 472146778Ssam case IPPROTO_MOBILE: 473276788Sdelphij mobile_print(ndo, ipds->cp, ipds->len); 474146778Ssam break; 475146778Ssam 476146778Ssam case IPPROTO_PIM: 477313537Sglebius pim_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip); 478146778Ssam break; 479146778Ssam 480146778Ssam case IPPROTO_VRRP: 481276788Sdelphij if (ndo->ndo_packettype == PT_CARP) { 482276788Sdelphij if (ndo->ndo_vflag) 483276788Sdelphij ND_PRINT((ndo, "carp %s > %s: ", 484276788Sdelphij ipaddr_string(ndo, &ipds->ip->ip_src), 485276788Sdelphij ipaddr_string(ndo, &ipds->ip->ip_dst))); 486276788Sdelphij carp_print(ndo, ipds->cp, ipds->len, ipds->ip->ip_ttl); 487235530Sdelphij } else { 488276788Sdelphij if (ndo->ndo_vflag) 489276788Sdelphij ND_PRINT((ndo, "vrrp %s > %s: ", 490276788Sdelphij ipaddr_string(ndo, &ipds->ip->ip_src), 491276788Sdelphij ipaddr_string(ndo, &ipds->ip->ip_dst))); 492276788Sdelphij vrrp_print(ndo, ipds->cp, ipds->len, 493276788Sdelphij (const u_char *)ipds->ip, ipds->ip->ip_ttl); 494235530Sdelphij } 495146778Ssam break; 496146778Ssam 497147904Ssam case IPPROTO_PGM: 498276788Sdelphij pgm_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip); 499147904Ssam break; 500147904Ssam 501257349Sglebius#if defined(HAVE_NET_PFVAR_H) 502241221Sglebius case IPPROTO_PFSYNC: 503281938Sbrooks pfsync_ip_print(ndo, ipds->cp, ipds->len); 504241221Sglebius break; 505257349Sglebius#endif 506241221Sglebius 507146778Ssam default: 508327234Semaste if (ndo->ndo_nflag==0 && (p_name = netdb_protoname(ipds->nh)) != NULL) 509327234Semaste ND_PRINT((ndo, " %s", p_name)); 510146778Ssam else 511146778Ssam ND_PRINT((ndo, " ip-proto-%d", ipds->nh)); 512146778Ssam ND_PRINT((ndo, " %d", ipds->len)); 513146778Ssam break; 514146778Ssam } 515146778Ssam} 516241235Sdelphij 517146778Ssamvoid 518146778Ssamip_print_inner(netdissect_options *ndo, 519146778Ssam const u_char *bp, 520146778Ssam u_int length, u_int nh, 521146778Ssam const u_char *bp2) 522146778Ssam{ 523146778Ssam struct ip_print_demux_state ipd; 524146778Ssam 525146778Ssam ipd.ip = (const struct ip *)bp2; 526146778Ssam ipd.cp = bp; 527146778Ssam ipd.len = length; 528146778Ssam ipd.off = 0; 529146778Ssam ipd.nh = nh; 530146778Ssam ipd.advance = 0; 531146778Ssam 532146778Ssam ip_print_demux(ndo, &ipd); 533146778Ssam} 534146778Ssam 535146778Ssam 536127675Sbms/* 53717680Spst * print an IP datagram. 53817680Spst */ 53917680Spstvoid 540146778Ssamip_print(netdissect_options *ndo, 541146778Ssam const u_char *bp, 542146778Ssam u_int length) 54317680Spst{ 544146778Ssam struct ip_print_demux_state ipd; 545146778Ssam struct ip_print_demux_state *ipds=&ipd; 546127675Sbms const u_char *ipend; 547146778Ssam u_int hlen; 548235530Sdelphij struct cksum_vec vec[1]; 549276788Sdelphij uint16_t sum, ip_sum; 550327234Semaste const char *p_name; 55117680Spst 552146778Ssam ipds->ip = (const struct ip *)bp; 553277783Spfg ND_TCHECK(ipds->ip->ip_vhl); 554313537Sglebius if (IP_V(ipds->ip) != 4) { /* print version and fail if != 4 */ 555146778Ssam if (IP_V(ipds->ip) == 6) 556285275Spkelsey ND_PRINT((ndo, "IP6, wrong link-layer encapsulation ")); 557285275Spkelsey else 558285275Spkelsey ND_PRINT((ndo, "IP%u ", IP_V(ipds->ip))); 559313537Sglebius return; 560127675Sbms } 561313537Sglebius if (!ndo->ndo_eflag) 562276788Sdelphij ND_PRINT((ndo, "IP ")); 56317680Spst 564277783Spfg ND_TCHECK(*ipds->ip); 56517680Spst if (length < sizeof (struct ip)) { 566276788Sdelphij ND_PRINT((ndo, "truncated-ip %u", length)); 56717680Spst return; 56817680Spst } 569146778Ssam hlen = IP_HL(ipds->ip) * 4; 57075118Sfenner if (hlen < sizeof (struct ip)) { 571276788Sdelphij ND_PRINT((ndo, "bad-hlen %u", hlen)); 57275118Sfenner return; 57375118Sfenner } 57417680Spst 575146778Ssam ipds->len = EXTRACT_16BITS(&ipds->ip->ip_len); 576146778Ssam if (length < ipds->len) 577276788Sdelphij ND_PRINT((ndo, "truncated-ip - %u bytes missing! ", 578276788Sdelphij ipds->len - length)); 579146778Ssam if (ipds->len < hlen) { 580146778Ssam#ifdef GUESS_TSO 581146778Ssam if (ipds->len) { 582276788Sdelphij ND_PRINT((ndo, "bad-len %u", ipds->len)); 583146778Ssam return; 584146778Ssam } 585146778Ssam else { 586146778Ssam /* we guess that it is a TSO send */ 587146778Ssam ipds->len = length; 588146778Ssam } 589146778Ssam#else 590276788Sdelphij ND_PRINT((ndo, "bad-len %u", ipds->len)); 591146778Ssam return; 592146778Ssam#endif /* GUESS_TSO */ 593127675Sbms } 594127675Sbms 595127675Sbms /* 596127675Sbms * Cut off the snapshot length to the end of the IP payload. 597127675Sbms */ 598146778Ssam ipend = bp + ipds->len; 599235530Sdelphij if (ipend < ndo->ndo_snapend) 600235530Sdelphij ndo->ndo_snapend = ipend; 601127675Sbms 602146778Ssam ipds->len -= hlen; 60317680Spst 604146778Ssam ipds->off = EXTRACT_16BITS(&ipds->ip->ip_off); 605127675Sbms 606276788Sdelphij if (ndo->ndo_vflag) { 607276788Sdelphij ND_PRINT((ndo, "(tos 0x%x", (int)ipds->ip->ip_tos)); 608127675Sbms /* ECN bits */ 609313537Sglebius switch (ipds->ip->ip_tos & 0x03) { 610313537Sglebius 611313537Sglebius case 0: 612313537Sglebius break; 613313537Sglebius 614313537Sglebius case 1: 615313537Sglebius ND_PRINT((ndo, ",ECT(1)")); 616313537Sglebius break; 617313537Sglebius 618313537Sglebius case 2: 619313537Sglebius ND_PRINT((ndo, ",ECT(0)")); 620313537Sglebius break; 621313537Sglebius 622313537Sglebius case 3: 623313537Sglebius ND_PRINT((ndo, ",CE")); 624313537Sglebius break; 625127675Sbms } 626127675Sbms 627146778Ssam if (ipds->ip->ip_ttl >= 1) 628276788Sdelphij ND_PRINT((ndo, ", ttl %u", ipds->ip->ip_ttl)); 629127675Sbms 630127675Sbms /* 631127675Sbms * for the firewall guys, print id, offset. 632127675Sbms * On all but the last stick a "+" in the flags portion. 633127675Sbms * For unfragmented datagrams, note the don't fragment flag. 634127675Sbms */ 635127675Sbms 636276788Sdelphij ND_PRINT((ndo, ", id %u, offset %u, flags [%s], proto %s (%u)", 637146778Ssam EXTRACT_16BITS(&ipds->ip->ip_id), 638146778Ssam (ipds->off & 0x1fff) * 8, 639172686Smlaier bittok2str(ip_frag_values, "none", ipds->off&0xe000), 640146778Ssam tok2str(ipproto_values,"unknown",ipds->ip->ip_p), 641276788Sdelphij ipds->ip->ip_p)); 642127675Sbms 643276788Sdelphij ND_PRINT((ndo, ", length %u", EXTRACT_16BITS(&ipds->ip->ip_len))); 644127675Sbms 645127675Sbms if ((hlen - sizeof(struct ip)) > 0) { 646276788Sdelphij ND_PRINT((ndo, ", options (")); 647313537Sglebius ip_optprint(ndo, (const u_char *)(ipds->ip + 1), hlen - sizeof(struct ip)); 648276788Sdelphij ND_PRINT((ndo, ")")); 649127675Sbms } 650127675Sbms 651313537Sglebius if (!ndo->ndo_Kflag && (const u_char *)ipds->ip + hlen <= ndo->ndo_snapend) { 652313537Sglebius vec[0].ptr = (const uint8_t *)(const void *)ipds->ip; 653235530Sdelphij vec[0].len = hlen; 654235530Sdelphij sum = in_cksum(vec, 1); 655127675Sbms if (sum != 0) { 656146778Ssam ip_sum = EXTRACT_16BITS(&ipds->ip->ip_sum); 657276788Sdelphij ND_PRINT((ndo, ", bad cksum %x (->%x)!", ip_sum, 658276788Sdelphij in_cksum_shouldbe(ip_sum, sum))); 659127675Sbms } 660127675Sbms } 661127675Sbms 662276788Sdelphij ND_PRINT((ndo, ")\n ")); 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) { 675276788Sdelphij ND_PRINT((ndo, "%s > %s: ", 676276788Sdelphij ipaddr_string(ndo, &ipds->ip->ip_src), 677276788Sdelphij ipaddr_string(ndo, &ipds->ip->ip_dst))); 67856896Sfenner } 679146778Ssam ip_print_demux(ndo, ipds); 680127675Sbms } else { 681313537Sglebius /* 682313537Sglebius * Ultra quiet now means that all this stuff should be 683313537Sglebius * suppressed. 684313537Sglebius */ 685313537Sglebius if (ndo->ndo_qflag > 1) 686313537Sglebius return; 68756896Sfenner 688313537Sglebius /* 689313537Sglebius * This isn't the first frag, so we're missing the 690313537Sglebius * next level protocol header. print the ip addr 691313537Sglebius * and the protocol. 692313537Sglebius */ 693313537Sglebius ND_PRINT((ndo, "%s > %s:", ipaddr_string(ndo, &ipds->ip->ip_src), 694313537Sglebius ipaddr_string(ndo, &ipds->ip->ip_dst))); 695327234Semaste if (!ndo->ndo_nflag && (p_name = netdb_protoname(ipds->ip->ip_p)) != NULL) 696327234Semaste ND_PRINT((ndo, " %s", p_name)); 697313537Sglebius else 698313537Sglebius ND_PRINT((ndo, " ip-proto-%d", ipds->ip->ip_p)); 69956896Sfenner } 700277783Spfg return; 701277783Spfg 702277783Spfgtrunc: 703277783Spfg ND_PRINT((ndo, "%s", tstr)); 704277783Spfg return; 70517680Spst} 70675118Sfenner 70775118Sfennervoid 708276788SdelphijipN_print(netdissect_options *ndo, register const u_char *bp, register u_int length) 70975118Sfenner{ 710313537Sglebius if (length < 1) { 711276788Sdelphij ND_PRINT((ndo, "truncated-ip %d", length)); 71275118Sfenner return; 71375118Sfenner } 714313537Sglebius 715313537Sglebius ND_TCHECK(*bp); 716313537Sglebius switch (*bp & 0xF0) { 717313537Sglebius case 0x40: 718276788Sdelphij ip_print (ndo, bp, length); 719313537Sglebius break; 720313537Sglebius case 0x60: 721276788Sdelphij ip6_print (ndo, bp, length); 722313537Sglebius break; 72375118Sfenner default: 724313537Sglebius ND_PRINT((ndo, "unknown ip %d", (*bp & 0xF0) >> 4)); 725313537Sglebius break; 72675118Sfenner } 727313537Sglebius return; 728313537Sglebius 729313537Sglebiustrunc: 730313537Sglebius ND_PRINT((ndo, "%s", tstr)); 731313537Sglebius return; 73275118Sfenner} 733127675Sbms 734146778Ssam/* 735146778Ssam * Local Variables: 736146778Ssam * c-style: whitesmith 737146778Ssam * c-basic-offset: 8 738146778Ssam * End: 739146778Ssam */ 740127675Sbms 741127675Sbms 742