print-icmp6.c revision 190207
156893Sfenner/* 256893Sfenner * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994 356893Sfenner * The Regents of the University of California. All rights reserved. 456893Sfenner * 556893Sfenner * Redistribution and use in source and binary forms, with or without 656893Sfenner * modification, are permitted provided that: (1) source code distributions 756893Sfenner * retain the above copyright notice and this paragraph in its entirety, (2) 856893Sfenner * distributions including binary code include the above copyright notice and 956893Sfenner * this paragraph in its entirety in the documentation or other materials 1056893Sfenner * provided with the distribution, and (3) all advertising materials mentioning 1156893Sfenner * features or use of this software display the following acknowledgement: 1256893Sfenner * ``This product includes software developed by the University of California, 1356893Sfenner * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 1456893Sfenner * the University nor the names of its contributors may be used to endorse 1556893Sfenner * or promote products derived from this software without specific prior 1656893Sfenner * written permission. 1756893Sfenner * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 1856893Sfenner * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 1956893Sfenner * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 2056893Sfenner */ 2156893Sfenner 2256893Sfenner#ifndef lint 23127668Sbmsstatic const char rcsid[] _U_ = 24190207Srpaulo "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.85.2.1 2008-02-05 19:36:58 guy Exp $"; 2556893Sfenner#endif 2656893Sfenner 2756893Sfenner#ifdef HAVE_CONFIG_H 2856893Sfenner#include "config.h" 2956893Sfenner#endif 3056893Sfenner 3156893Sfenner#ifdef INET6 3256893Sfenner 33127668Sbms#include <tcpdump-stdinc.h> 3456893Sfenner 3556893Sfenner#include <stdio.h> 3698524Sfenner#include <string.h> 3756893Sfenner 38147899Ssam#include "interface.h" 39147899Ssam#include "addrtoname.h" 40147899Ssam#include "extract.h" 41147899Ssam 4275115Sfenner#include "ip6.h" 4375115Sfenner#include "icmp6.h" 44127668Sbms#include "ipproto.h" 4556893Sfenner 4675115Sfenner#include "udp.h" 4775115Sfenner#include "ah.h" 4875115Sfenner 4998524Sfennerstatic const char *get_rtpref(u_int); 5098524Sfennerstatic const char *get_lifetime(u_int32_t); 5198524Sfennerstatic void print_lladdr(const u_char *, size_t); 52127668Sbmsstatic void icmp6_opt_print(const u_char *, int); 53127668Sbmsstatic void mld6_print(const u_char *); 54146773Ssamstatic void mldv2_report_print(const u_char *, u_int); 55146773Ssamstatic void mldv2_query_print(const u_char *, u_int); 56127668Sbmsstatic struct udphdr *get_upperlayer(u_char *, u_int *); 5775115Sfennerstatic void dnsname_print(const u_char *, const u_char *); 58127668Sbmsstatic void icmp6_nodeinfo_print(u_int, const u_char *, const u_char *); 59127668Sbmsstatic void icmp6_rrenum_print(const u_char *, const u_char *); 6056893Sfenner 6175115Sfenner#ifndef abs 6275115Sfenner#define abs(a) ((0 < (a)) ? (a) : -(a)) 6375115Sfenner#endif 6475115Sfenner 65146773Ssamstatic struct tok icmp6_type_values[] = { 66146773Ssam { ICMP6_DST_UNREACH, "destination unreachable"}, 67146773Ssam { ICMP6_PACKET_TOO_BIG, "packet too big"}, 68146773Ssam { ICMP6_TIME_EXCEEDED, "time exceeded in-transit"}, 69146773Ssam { ICMP6_PARAM_PROB, "parameter problem"}, 70146773Ssam { ICMP6_ECHO_REQUEST, "echo request"}, 71146773Ssam { ICMP6_ECHO_REPLY, "echo reply"}, 72147899Ssam { MLD6_LISTENER_QUERY, "multicast listener query"}, 73147899Ssam { MLD6_LISTENER_REPORT, "multicast listener report"}, 74147899Ssam { MLD6_LISTENER_DONE, "multicast listener done"}, 75147899Ssam { ND_ROUTER_SOLICIT, "router solicitation"}, 76146773Ssam { ND_ROUTER_ADVERT, "router advertisement"}, 77146773Ssam { ND_NEIGHBOR_SOLICIT, "neighbor solicitation"}, 78162017Ssam { ND_NEIGHBOR_ADVERT, "neighbor advertisement"}, 79146773Ssam { ND_REDIRECT, "redirect"}, 80146773Ssam { ICMP6_ROUTER_RENUMBERING, "router renumbering"}, 81146773Ssam { IND_SOLICIT, "inverse neighbor solicitation"}, 82146773Ssam { IND_ADVERT, "inverse neighbor advertisement"}, 83147899Ssam { MLDV2_LISTENER_REPORT, "multicast listener report v2"}, 84146773Ssam { ICMP6_HADISCOV_REQUEST, "ha discovery request"}, 85146773Ssam { ICMP6_HADISCOV_REPLY, "ha discovery reply"}, 86146773Ssam { ICMP6_MOBILEPREFIX_SOLICIT, "mobile router solicitation"}, 87146773Ssam { ICMP6_MOBILEPREFIX_ADVERT, "mobile router advertisement"}, 88146773Ssam { ICMP6_WRUREQUEST, "who-are-you request"}, 89146773Ssam { ICMP6_WRUREPLY, "who-are-you reply"}, 90146773Ssam { ICMP6_NI_QUERY, "node information query"}, 91146773Ssam { ICMP6_NI_REPLY, "node information reply"}, 92146773Ssam { MLD6_MTRACE, "mtrace message"}, 93146773Ssam { MLD6_MTRACE_RESP, "mtrace response"}, 94146773Ssam { 0, NULL } 95146773Ssam}; 96146773Ssam 97146773Ssamstatic struct tok icmp6_dst_unreach_code_values[] = { 98146773Ssam { ICMP6_DST_UNREACH_NOROUTE, "unreachable route" }, 99146773Ssam { ICMP6_DST_UNREACH_ADMIN, " unreachable prohibited"}, 100146773Ssam { ICMP6_DST_UNREACH_BEYONDSCOPE, "beyond scope"}, 101146773Ssam { ICMP6_DST_UNREACH_ADDR, "unreachable address"}, 102146773Ssam { ICMP6_DST_UNREACH_NOPORT, "unreachable port"}, 103146773Ssam { 0, NULL } 104146773Ssam}; 105146773Ssam 106146773Ssamstatic struct tok icmp6_opt_pi_flag_values[] = { 107146773Ssam { ND_OPT_PI_FLAG_ONLINK, "onlink" }, 108146773Ssam { ND_OPT_PI_FLAG_AUTO, "auto" }, 109146773Ssam { ND_OPT_PI_FLAG_ROUTER, "router" }, 110146773Ssam { 0, NULL } 111146773Ssam}; 112146773Ssam 113146773Ssamstatic struct tok icmp6_opt_ra_flag_values[] = { 114146773Ssam { ND_RA_FLAG_MANAGED, "managed" }, 115146773Ssam { ND_RA_FLAG_OTHER, "other stateful"}, 116146773Ssam { ND_RA_FLAG_HOME_AGENT, "home agent"}, 117146773Ssam { 0, NULL } 118146773Ssam}; 119146773Ssam 120146773Ssamstatic struct tok icmp6_nd_na_flag_values[] = { 121146773Ssam { ND_NA_FLAG_ROUTER, "router" }, 122146773Ssam { ND_NA_FLAG_SOLICITED, "solicited" }, 123146773Ssam { ND_NA_FLAG_OVERRIDE, "override" }, 124146773Ssam { 0, NULL } 125146773Ssam}; 126146773Ssam 127146773Ssam 128146773Ssamstatic struct tok icmp6_opt_values[] = { 129146773Ssam { ND_OPT_SOURCE_LINKADDR, "source link-address"}, 130146773Ssam { ND_OPT_TARGET_LINKADDR, "destination link-address"}, 131146773Ssam { ND_OPT_PREFIX_INFORMATION, "prefix info"}, 132146773Ssam { ND_OPT_REDIRECTED_HEADER, "redirected header"}, 133146773Ssam { ND_OPT_MTU, "mtu"}, 134162017Ssam { ND_OPT_ADVINTERVAL, "advertisement interval"}, 135146773Ssam { ND_OPT_HOMEAGENT_INFO, "homeagent information"}, 136146773Ssam { ND_OPT_ROUTE_INFO, "route info"}, 137146773Ssam { 0, NULL } 138146773Ssam}; 139146773Ssam 140146773Ssam/* mldv2 report types */ 141146773Ssamstatic struct tok mldv2report2str[] = { 142146773Ssam { 1, "is_in" }, 143146773Ssam { 2, "is_ex" }, 144146773Ssam { 3, "to_in" }, 145146773Ssam { 4, "to_ex" }, 146146773Ssam { 5, "allow" }, 147146773Ssam { 6, "block" }, 148146773Ssam { 0, NULL } 149146773Ssam}; 150146773Ssam 15198524Sfennerstatic const char * 15298524Sfennerget_rtpref(u_int v) 15398524Sfenner{ 15498524Sfenner static const char *rtpref_str[] = { 15598524Sfenner "medium", /* 00 */ 15698524Sfenner "high", /* 01 */ 15798524Sfenner "rsv", /* 10 */ 15898524Sfenner "low" /* 11 */ 15998524Sfenner }; 16098524Sfenner 16198524Sfenner return rtpref_str[((v & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff]; 16298524Sfenner} 16398524Sfenner 16498524Sfennerstatic const char * 16598524Sfennerget_lifetime(u_int32_t v) 16698524Sfenner{ 16798524Sfenner static char buf[20]; 16898524Sfenner 16998524Sfenner if (v == (u_int32_t)~0UL) 17098524Sfenner return "infinity"; 17198524Sfenner else { 17298524Sfenner snprintf(buf, sizeof(buf), "%u", v); 17398524Sfenner return buf; 17498524Sfenner } 17598524Sfenner} 17698524Sfenner 17798524Sfennerstatic void 17898524Sfennerprint_lladdr(const u_int8_t *p, size_t l) 17998524Sfenner{ 18098524Sfenner const u_int8_t *ep, *q; 18198524Sfenner 18298524Sfenner q = p; 18398524Sfenner ep = p + l; 18498524Sfenner while (l > 0 && q < ep) { 18598524Sfenner if (q > p) 18698524Sfenner printf(":"); 18798524Sfenner printf("%02x", *q++); 18898524Sfenner l--; 18998524Sfenner } 19098524Sfenner} 19198524Sfenner 192127668Sbmsstatic int icmp6_cksum(const struct ip6_hdr *ip6, const struct icmp6_hdr *icp, 193127668Sbms u_int len) 194127668Sbms{ 195127668Sbms size_t i; 196127668Sbms register const u_int16_t *sp; 197127668Sbms u_int32_t sum; 198127668Sbms union { 199127668Sbms struct { 200127668Sbms struct in6_addr ph_src; 201127668Sbms struct in6_addr ph_dst; 202127668Sbms u_int32_t ph_len; 203127668Sbms u_int8_t ph_zero[3]; 204127668Sbms u_int8_t ph_nxt; 205127668Sbms } ph; 206127668Sbms u_int16_t pa[20]; 207127668Sbms } phu; 208127668Sbms 209127668Sbms /* pseudo-header */ 210127668Sbms memset(&phu, 0, sizeof(phu)); 211127668Sbms phu.ph.ph_src = ip6->ip6_src; 212127668Sbms phu.ph.ph_dst = ip6->ip6_dst; 213127668Sbms phu.ph.ph_len = htonl(len); 214127668Sbms phu.ph.ph_nxt = IPPROTO_ICMPV6; 215127668Sbms 216127668Sbms sum = 0; 217127668Sbms for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++) 218127668Sbms sum += phu.pa[i]; 219127668Sbms 220127668Sbms sp = (const u_int16_t *)icp; 221127668Sbms 222127668Sbms for (i = 0; i < (len & ~1); i += 2) 223127668Sbms sum += *sp++; 224127668Sbms 225127668Sbms if (len & 1) 226127668Sbms sum += htons((*(const u_int8_t *)sp) << 8); 227127668Sbms 228127668Sbms while (sum > 0xffff) 229127668Sbms sum = (sum & 0xffff) + (sum >> 16); 230127668Sbms sum = ~sum & 0xffff; 231127668Sbms 232127668Sbms return (sum); 233127668Sbms} 234127668Sbms 23556893Sfennervoid 236127668Sbmsicmp6_print(const u_char *bp, u_int length, const u_char *bp2, int fragmented) 23756893Sfenner{ 23875115Sfenner const struct icmp6_hdr *dp; 23998524Sfenner const struct ip6_hdr *ip; 24098524Sfenner const struct ip6_hdr *oip; 24198524Sfenner const struct udphdr *ouh; 24298524Sfenner int dport; 24398524Sfenner const u_char *ep; 244127668Sbms u_int prot; 24556893Sfenner 24656893Sfenner dp = (struct icmp6_hdr *)bp; 24756893Sfenner ip = (struct ip6_hdr *)bp2; 24856893Sfenner oip = (struct ip6_hdr *)(dp + 1); 24975115Sfenner /* 'ep' points to the end of available data. */ 25056893Sfenner ep = snapend; 25156893Sfenner 252127668Sbms TCHECK(dp->icmp6_cksum); 253127668Sbms 254127668Sbms if (vflag && !fragmented) { 255127668Sbms int sum = dp->icmp6_cksum; 256127668Sbms 257127668Sbms if (TTEST2(bp[0], length)) { 258127668Sbms sum = icmp6_cksum(ip, dp, length); 259127668Sbms if (sum != 0) 260127668Sbms (void)printf("[bad icmp6 cksum %x!] ", sum); 261127668Sbms else 262127668Sbms (void)printf("[icmp6 sum ok] "); 263127668Sbms } 264127668Sbms } 265127668Sbms 266146773Ssam printf("ICMP6, %s", tok2str(icmp6_type_values,"unknown icmp6 type (%u)",dp->icmp6_type)); 267146773Ssam 268146773Ssam /* display cosmetics: print the packet length for printer that use the vflag now */ 269146773Ssam if (vflag && (dp->icmp6_type == 270146773Ssam ND_ROUTER_SOLICIT || 271146773Ssam ND_ROUTER_ADVERT || 272146773Ssam ND_NEIGHBOR_ADVERT || 273146773Ssam ND_NEIGHBOR_SOLICIT || 274146773Ssam ND_REDIRECT || 275146773Ssam ICMP6_HADISCOV_REPLY || 276146773Ssam ICMP6_MOBILEPREFIX_ADVERT )) 277146773Ssam printf(", length %u", length); 278146773Ssam 27975115Sfenner switch (dp->icmp6_type) { 28056893Sfenner case ICMP6_DST_UNREACH: 28156893Sfenner TCHECK(oip->ip6_dst); 282146773Ssam printf(", %s", tok2str(icmp6_dst_unreach_code_values,"unknown unreach code (%u)",dp->icmp6_code)); 28356893Sfenner switch (dp->icmp6_code) { 284146773Ssam 285146773Ssam case ICMP6_DST_UNREACH_NOROUTE: /* fall through */ 28656893Sfenner case ICMP6_DST_UNREACH_ADMIN: 287146773Ssam case ICMP6_DST_UNREACH_ADDR: 288146773Ssam printf(" %s",ip6addr_string(&oip->ip6_dst)); 289146773Ssam break; 29056893Sfenner case ICMP6_DST_UNREACH_BEYONDSCOPE: 291146773Ssam printf(" %s, source address %s", 29256893Sfenner ip6addr_string(&oip->ip6_dst), 29356893Sfenner ip6addr_string(&oip->ip6_src)); 29456893Sfenner break; 29556893Sfenner case ICMP6_DST_UNREACH_NOPORT: 29675115Sfenner if ((ouh = get_upperlayer((u_char *)oip, &prot)) 29775115Sfenner == NULL) 29875115Sfenner goto trunc; 29975115Sfenner 300127668Sbms dport = EXTRACT_16BITS(&ouh->uh_dport); 30175115Sfenner switch (prot) { 30256893Sfenner case IPPROTO_TCP: 303146773Ssam printf(", %s tcp port %s", 30456893Sfenner ip6addr_string(&oip->ip6_dst), 30556893Sfenner tcpport_string(dport)); 30656893Sfenner break; 30756893Sfenner case IPPROTO_UDP: 308146773Ssam printf(", %s udp port %s", 30956893Sfenner ip6addr_string(&oip->ip6_dst), 31056893Sfenner udpport_string(dport)); 31156893Sfenner break; 31256893Sfenner default: 313146773Ssam printf(", %s protocol %d port %d unreachable", 31456893Sfenner ip6addr_string(&oip->ip6_dst), 31556893Sfenner oip->ip6_nxt, dport); 31656893Sfenner break; 31756893Sfenner } 31856893Sfenner break; 31956893Sfenner default: 320146773Ssam if (vflag <= 1) { 321146773Ssam print_unknown_data(bp,"\n\t",length); 322146773Ssam return; 323146773Ssam } 324146773Ssam break; 32556893Sfenner } 32656893Sfenner break; 32756893Sfenner case ICMP6_PACKET_TOO_BIG: 32856893Sfenner TCHECK(dp->icmp6_mtu); 329146773Ssam printf(", mtu %u", EXTRACT_32BITS(&dp->icmp6_mtu)); 33056893Sfenner break; 33156893Sfenner case ICMP6_TIME_EXCEEDED: 33256893Sfenner TCHECK(oip->ip6_dst); 33356893Sfenner switch (dp->icmp6_code) { 33456893Sfenner case ICMP6_TIME_EXCEED_TRANSIT: 335146773Ssam printf(" for %s", 33656893Sfenner ip6addr_string(&oip->ip6_dst)); 33756893Sfenner break; 33856893Sfenner case ICMP6_TIME_EXCEED_REASSEMBLY: 339146773Ssam printf(" (reassembly)"); 34056893Sfenner break; 34156893Sfenner default: 342146773Ssam printf(", unknown code (%u)", dp->icmp6_code); 34356893Sfenner break; 34456893Sfenner } 34556893Sfenner break; 34656893Sfenner case ICMP6_PARAM_PROB: 34756893Sfenner TCHECK(oip->ip6_dst); 34856893Sfenner switch (dp->icmp6_code) { 34956893Sfenner case ICMP6_PARAMPROB_HEADER: 350146773Ssam printf(", errorneous - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)); 35156893Sfenner break; 35256893Sfenner case ICMP6_PARAMPROB_NEXTHEADER: 353146773Ssam printf(", next header - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)); 35456893Sfenner break; 35556893Sfenner case ICMP6_PARAMPROB_OPTION: 356146773Ssam printf(", option - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)); 35756893Sfenner break; 35856893Sfenner default: 359146773Ssam printf(", code-#%d", 36056893Sfenner dp->icmp6_code); 36156893Sfenner break; 36256893Sfenner } 36356893Sfenner break; 36456893Sfenner case ICMP6_ECHO_REQUEST: 36556893Sfenner case ICMP6_ECHO_REPLY: 366127668Sbms TCHECK(dp->icmp6_seq); 367146773Ssam printf(", seq %u", EXTRACT_16BITS(&dp->icmp6_seq)); 36856893Sfenner break; 36956893Sfenner case ICMP6_MEMBERSHIP_QUERY: 370146773Ssam if (length == MLD_MINLEN) { 371146773Ssam mld6_print((const u_char *)dp); 372146773Ssam } else if (length >= MLDV2_MINLEN) { 373146773Ssam printf("v2 "); 374146773Ssam mldv2_query_print((const u_char *)dp, length); 375146773Ssam } else { 376146773Ssam printf(" unknown-version (len %u) ", length); 377146773Ssam } 37856893Sfenner break; 37956893Sfenner case ICMP6_MEMBERSHIP_REPORT: 38056893Sfenner mld6_print((const u_char *)dp); 38156893Sfenner break; 38256893Sfenner case ICMP6_MEMBERSHIP_REDUCTION: 38356893Sfenner mld6_print((const u_char *)dp); 38456893Sfenner break; 38556893Sfenner case ND_ROUTER_SOLICIT: 386146773Ssam#define RTSOLLEN 8 38756893Sfenner if (vflag) { 38875115Sfenner icmp6_opt_print((const u_char *)dp + RTSOLLEN, 389127668Sbms length - RTSOLLEN); 39056893Sfenner } 39156893Sfenner break; 39256893Sfenner case ND_ROUTER_ADVERT: 393146773Ssam#define RTADVLEN 16 39456893Sfenner if (vflag) { 39556893Sfenner struct nd_router_advert *p; 39656893Sfenner 39756893Sfenner p = (struct nd_router_advert *)dp; 39856893Sfenner TCHECK(p->nd_ra_retransmit); 399146773Ssam printf("\n\thop limit %u, Flags [%s]" \ 400146773Ssam ", pref %s, router lifetime %us, reachable time %us, retrans time %us", 401146773Ssam (u_int)p->nd_ra_curhoplimit, 402146773Ssam bittok2str(icmp6_opt_ra_flag_values,"none",(p->nd_ra_flags_reserved)), 403146773Ssam get_rtpref(p->nd_ra_flags_reserved), 404146773Ssam EXTRACT_16BITS(&p->nd_ra_router_lifetime), 405146773Ssam EXTRACT_32BITS(&p->nd_ra_reachable), 406146773Ssam EXTRACT_32BITS(&p->nd_ra_retransmit)); 40798524Sfenner 40875115Sfenner icmp6_opt_print((const u_char *)dp + RTADVLEN, 409127668Sbms length - RTADVLEN); 41056893Sfenner } 41156893Sfenner break; 41256893Sfenner case ND_NEIGHBOR_SOLICIT: 41356893Sfenner { 41456893Sfenner struct nd_neighbor_solicit *p; 41556893Sfenner p = (struct nd_neighbor_solicit *)dp; 41656893Sfenner TCHECK(p->nd_ns_target); 417146773Ssam printf(", who has %s", ip6addr_string(&p->nd_ns_target)); 41856893Sfenner if (vflag) { 41956893Sfenner#define NDSOLLEN 24 42075115Sfenner icmp6_opt_print((const u_char *)dp + NDSOLLEN, 421127668Sbms length - NDSOLLEN); 42256893Sfenner } 42356893Sfenner } 42456893Sfenner break; 42556893Sfenner case ND_NEIGHBOR_ADVERT: 42656893Sfenner { 42756893Sfenner struct nd_neighbor_advert *p; 42856893Sfenner 42956893Sfenner p = (struct nd_neighbor_advert *)dp; 43056893Sfenner TCHECK(p->nd_na_target); 431146773Ssam printf(", tgt is %s", 43256893Sfenner ip6addr_string(&p->nd_na_target)); 43375115Sfenner if (vflag) { 434146773Ssam printf(", Flags [%s]", 435146773Ssam bittok2str(icmp6_nd_na_flag_values, 436146773Ssam "none", 437146773Ssam EXTRACT_32BITS(&p->nd_na_flags_reserved))); 43856893Sfenner#define NDADVLEN 24 43975115Sfenner icmp6_opt_print((const u_char *)dp + NDADVLEN, 440127668Sbms length - NDADVLEN); 44175115Sfenner#undef NDADVLEN 44256893Sfenner } 44356893Sfenner } 44456893Sfenner break; 44556893Sfenner case ND_REDIRECT: 44656893Sfenner#define RDR(i) ((struct nd_redirect *)(i)) 44756893Sfenner TCHECK(RDR(dp)->nd_rd_dst); 448146773Ssam printf(", %s", getname6((const u_char *)&RDR(dp)->nd_rd_dst)); 449127668Sbms TCHECK(RDR(dp)->nd_rd_target); 45075115Sfenner printf(" to %s", 45175115Sfenner getname6((const u_char*)&RDR(dp)->nd_rd_target)); 45256893Sfenner#define REDIRECTLEN 40 45356893Sfenner if (vflag) { 45456893Sfenner icmp6_opt_print((const u_char *)dp + REDIRECTLEN, 455127668Sbms length - REDIRECTLEN); 45656893Sfenner } 45756893Sfenner break; 45875115Sfenner#undef REDIRECTLEN 45975115Sfenner#undef RDR 46056893Sfenner case ICMP6_ROUTER_RENUMBERING: 461127668Sbms icmp6_rrenum_print(bp, ep); 46256893Sfenner break; 46375115Sfenner case ICMP6_NI_QUERY: 46475115Sfenner case ICMP6_NI_REPLY: 465127668Sbms icmp6_nodeinfo_print(length, bp, ep); 46656893Sfenner break; 467146773Ssam case IND_SOLICIT: 468146773Ssam case IND_ADVERT: 469146773Ssam break; 470146773Ssam case ICMP6_V2_MEMBERSHIP_REPORT: 471146773Ssam mldv2_report_print((const u_char *) dp, length); 472146773Ssam break; 473146773Ssam case ICMP6_MOBILEPREFIX_SOLICIT: /* fall through */ 474127668Sbms case ICMP6_HADISCOV_REQUEST: 475146773Ssam TCHECK(dp->icmp6_data16[0]); 476146773Ssam printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])); 477146773Ssam break; 478127668Sbms case ICMP6_HADISCOV_REPLY: 479127668Sbms if (vflag) { 480127668Sbms struct in6_addr *in6; 481127668Sbms u_char *cp; 482127668Sbms 483127668Sbms TCHECK(dp->icmp6_data16[0]); 484146773Ssam printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])); 485127668Sbms cp = (u_char *)dp + length; 486127668Sbms in6 = (struct in6_addr *)(dp + 1); 487127668Sbms for (; (u_char *)in6 < cp; in6++) { 488127668Sbms TCHECK(*in6); 489127668Sbms printf(", %s", ip6addr_string(in6)); 490127668Sbms } 491127668Sbms } 492127668Sbms break; 493127668Sbms case ICMP6_MOBILEPREFIX_ADVERT: 494127668Sbms if (vflag) { 495127668Sbms TCHECK(dp->icmp6_data16[0]); 496146773Ssam printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])); 497127668Sbms if (dp->icmp6_data16[1] & 0xc0) 498127668Sbms printf(" "); 499127668Sbms if (dp->icmp6_data16[1] & 0x80) 500127668Sbms printf("M"); 501127668Sbms if (dp->icmp6_data16[1] & 0x40) 502127668Sbms printf("O"); 503127668Sbms#define MPADVLEN 8 504127668Sbms icmp6_opt_print((const u_char *)dp + MPADVLEN, 505127668Sbms length - MPADVLEN); 506127668Sbms } 507127668Sbms break; 50856893Sfenner default: 509146773Ssam printf(", length %u", length); 510146773Ssam if (vflag <= 1) 511146773Ssam print_unknown_data(bp,"\n\t", length); 512146773Ssam return; 513146773Ssam } 514146773Ssam if (!vflag) 515146773Ssam printf(", length %u", length); 51656893Sfenner return; 51756893Sfennertrunc: 51856893Sfenner fputs("[|icmp6]", stdout); 51956893Sfenner} 52056893Sfenner 52175115Sfennerstatic struct udphdr * 522127668Sbmsget_upperlayer(u_char *bp, u_int *prot) 52375115Sfenner{ 52498524Sfenner const u_char *ep; 52575115Sfenner struct ip6_hdr *ip6 = (struct ip6_hdr *)bp; 52675115Sfenner struct udphdr *uh; 52775115Sfenner struct ip6_hbh *hbh; 52875115Sfenner struct ip6_frag *fragh; 52975115Sfenner struct ah *ah; 530127668Sbms u_int nh; 531127668Sbms int hlen; 53275115Sfenner 53375115Sfenner /* 'ep' points to the end of available data. */ 53475115Sfenner ep = snapend; 53575115Sfenner 536127668Sbms if (!TTEST(ip6->ip6_nxt)) 53775115Sfenner return NULL; 53875115Sfenner 53975115Sfenner nh = ip6->ip6_nxt; 54075115Sfenner hlen = sizeof(struct ip6_hdr); 54175115Sfenner 542147899Ssam while (bp < ep) { 54375115Sfenner bp += hlen; 54475115Sfenner 54575115Sfenner switch(nh) { 54675115Sfenner case IPPROTO_UDP: 54775115Sfenner case IPPROTO_TCP: 54875115Sfenner uh = (struct udphdr *)bp; 54975115Sfenner if (TTEST(uh->uh_dport)) { 55075115Sfenner *prot = nh; 55175115Sfenner return(uh); 55275115Sfenner } 55375115Sfenner else 55475115Sfenner return(NULL); 55575115Sfenner /* NOTREACHED */ 55675115Sfenner 55775115Sfenner case IPPROTO_HOPOPTS: 55875115Sfenner case IPPROTO_DSTOPTS: 55975115Sfenner case IPPROTO_ROUTING: 56075115Sfenner hbh = (struct ip6_hbh *)bp; 561127668Sbms if (!TTEST(hbh->ip6h_len)) 56275115Sfenner return(NULL); 56375115Sfenner nh = hbh->ip6h_nxt; 56475115Sfenner hlen = (hbh->ip6h_len + 1) << 3; 56575115Sfenner break; 56675115Sfenner 56775115Sfenner case IPPROTO_FRAGMENT: /* this should be odd, but try anyway */ 56875115Sfenner fragh = (struct ip6_frag *)bp; 569127668Sbms if (!TTEST(fragh->ip6f_offlg)) 57075115Sfenner return(NULL); 57175115Sfenner /* fragments with non-zero offset are meaningless */ 572127668Sbms if ((EXTRACT_16BITS(&fragh->ip6f_offlg) & IP6F_OFF_MASK) != 0) 57375115Sfenner return(NULL); 57475115Sfenner nh = fragh->ip6f_nxt; 57575115Sfenner hlen = sizeof(struct ip6_frag); 57675115Sfenner break; 57775115Sfenner 57875115Sfenner case IPPROTO_AH: 57975115Sfenner ah = (struct ah *)bp; 580127668Sbms if (!TTEST(ah->ah_len)) 58175115Sfenner return(NULL); 58275115Sfenner nh = ah->ah_nxt; 58375115Sfenner hlen = (ah->ah_len + 2) << 2; 58475115Sfenner break; 58575115Sfenner 58675115Sfenner default: /* unknown or undecodable header */ 58775115Sfenner *prot = nh; /* meaningless, but set here anyway */ 58875115Sfenner return(NULL); 58975115Sfenner } 59075115Sfenner } 59175115Sfenner 59275115Sfenner return(NULL); /* should be notreached, though */ 59375115Sfenner} 59475115Sfenner 595127668Sbmsstatic void 59698524Sfennericmp6_opt_print(const u_char *bp, int resid) 59756893Sfenner{ 59898524Sfenner const struct nd_opt_hdr *op; 59998524Sfenner const struct nd_opt_hdr *opl; /* why there's no struct? */ 60098524Sfenner const struct nd_opt_prefix_info *opp; 60198524Sfenner const struct icmp6_opts_redirect *opr; 60298524Sfenner const struct nd_opt_mtu *opm; 60398524Sfenner const struct nd_opt_advinterval *opa; 604127668Sbms const struct nd_opt_homeagent_info *oph; 60598524Sfenner const struct nd_opt_route_info *opri; 60698524Sfenner const u_char *cp, *ep; 60798524Sfenner struct in6_addr in6, *in6p; 60898524Sfenner size_t l; 60956893Sfenner 61056893Sfenner#define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return 61156893Sfenner 61298524Sfenner cp = bp; 61375115Sfenner /* 'ep' points to the end of available data. */ 61456893Sfenner ep = snapend; 61556893Sfenner 61698524Sfenner while (cp < ep) { 61798524Sfenner op = (struct nd_opt_hdr *)cp; 61898524Sfenner 61998524Sfenner ECHECK(op->nd_opt_len); 62098524Sfenner if (resid <= 0) 62198524Sfenner return; 62298524Sfenner if (op->nd_opt_len == 0) 62356893Sfenner goto trunc; 62498524Sfenner if (cp + (op->nd_opt_len << 3) > ep) 62556893Sfenner goto trunc; 62698524Sfenner 627146773Ssam printf("\n\t %s option (%u), length %u (%u): ", 628146773Ssam tok2str(icmp6_opt_values, "unknown", op->nd_opt_type), 629146773Ssam op->nd_opt_type, 630146773Ssam op->nd_opt_len << 3, 631146773Ssam op->nd_opt_len); 632146773Ssam 63398524Sfenner switch (op->nd_opt_type) { 63498524Sfenner case ND_OPT_SOURCE_LINKADDR: 63598524Sfenner opl = (struct nd_opt_hdr *)op; 63698524Sfenner l = (op->nd_opt_len << 3) - 2; 63798524Sfenner print_lladdr(cp + 2, l); 63898524Sfenner break; 63998524Sfenner case ND_OPT_TARGET_LINKADDR: 64098524Sfenner opl = (struct nd_opt_hdr *)op; 64198524Sfenner l = (op->nd_opt_len << 3) - 2; 64298524Sfenner print_lladdr(cp + 2, l); 64398524Sfenner break; 64498524Sfenner case ND_OPT_PREFIX_INFORMATION: 64598524Sfenner opp = (struct nd_opt_prefix_info *)op; 64698524Sfenner TCHECK(opp->nd_opt_pi_prefix); 647146773Ssam printf("%s/%u%s, Flags [%s], valid time %ss", 648146773Ssam ip6addr_string(&opp->nd_opt_pi_prefix), 649146773Ssam opp->nd_opt_pi_prefix_len, 650146773Ssam (op->nd_opt_len != 4) ? "badlen" : "", 651146773Ssam bittok2str(icmp6_opt_pi_flag_values, "none", opp->nd_opt_pi_flags_reserved), 652146773Ssam get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_valid_time))); 653146773Ssam printf(", pref. time %ss", get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_preferred_time))); 65498524Sfenner break; 65598524Sfenner case ND_OPT_REDIRECTED_HEADER: 65698524Sfenner opr = (struct icmp6_opts_redirect *)op; 657146773Ssam print_unknown_data(bp,"\n\t ",op->nd_opt_len<<3); 65898524Sfenner /* xxx */ 65998524Sfenner break; 66098524Sfenner case ND_OPT_MTU: 66198524Sfenner opm = (struct nd_opt_mtu *)op; 66298524Sfenner TCHECK(opm->nd_opt_mtu_mtu); 663146773Ssam printf(" %u%s", 664146773Ssam EXTRACT_32BITS(&opm->nd_opt_mtu_mtu), 665146773Ssam (op->nd_opt_len != 1) ? "bad option length" : "" ); 666146773Ssam break; 66798524Sfenner case ND_OPT_ADVINTERVAL: 66898524Sfenner opa = (struct nd_opt_advinterval *)op; 66998524Sfenner TCHECK(opa->nd_opt_adv_interval); 670146773Ssam printf(" %us", EXTRACT_32BITS(&opa->nd_opt_adv_interval)); 671127668Sbms break; 672127668Sbms case ND_OPT_HOMEAGENT_INFO: 673127668Sbms oph = (struct nd_opt_homeagent_info *)op; 674127668Sbms TCHECK(oph->nd_opt_hai_lifetime); 675146773Ssam printf(" preference %u, lifetime %u", 676146773Ssam EXTRACT_16BITS(&oph->nd_opt_hai_preference), 677146773Ssam EXTRACT_16BITS(&oph->nd_opt_hai_lifetime)); 678127668Sbms break; 67998524Sfenner case ND_OPT_ROUTE_INFO: 68098524Sfenner opri = (struct nd_opt_route_info *)op; 68198524Sfenner TCHECK(opri->nd_opt_rti_lifetime); 68298524Sfenner memset(&in6, 0, sizeof(in6)); 68398524Sfenner in6p = (struct in6_addr *)(opri + 1); 68498524Sfenner switch (op->nd_opt_len) { 68598524Sfenner case 1: 68698524Sfenner break; 68798524Sfenner case 2: 68898524Sfenner TCHECK2(*in6p, 8); 68998524Sfenner memcpy(&in6, opri + 1, 8); 69098524Sfenner break; 69198524Sfenner case 3: 69298524Sfenner TCHECK(*in6p); 69398524Sfenner memcpy(&in6, opri + 1, sizeof(in6)); 69498524Sfenner break; 69598524Sfenner default: 69698524Sfenner goto trunc; 69798524Sfenner } 69898524Sfenner printf(" %s/%u", ip6addr_string(&in6), 69998524Sfenner opri->nd_opt_rti_prefixlen); 70098524Sfenner printf(", pref=%s", get_rtpref(opri->nd_opt_rti_flags)); 70198524Sfenner printf(", lifetime=%s", 702127668Sbms get_lifetime(EXTRACT_32BITS(&opri->nd_opt_rti_lifetime))); 70398524Sfenner break; 70498524Sfenner default: 705146773Ssam if (vflag <= 1) { 706146773Ssam print_unknown_data(cp+2,"\n\t ", (op->nd_opt_len << 3) - 2); /* skip option header */ 707146773Ssam return; 708146773Ssam } 709146773Ssam break; 71056893Sfenner } 711146773Ssam /* do we want to see an additional hexdump ? */ 712146773Ssam if (vflag> 1) 713146773Ssam print_unknown_data(cp+2,"\n\t ", (op->nd_opt_len << 3) - 2); /* skip option header */ 71498524Sfenner 71598524Sfenner cp += op->nd_opt_len << 3; 71698524Sfenner resid -= op->nd_opt_len << 3; 71756893Sfenner } 71856893Sfenner return; 71998524Sfenner 72056893Sfenner trunc: 72156893Sfenner fputs("[ndp opt]", stdout); 72256893Sfenner return; 72356893Sfenner#undef ECHECK 72456893Sfenner} 72556893Sfenner 726127668Sbmsstatic void 72798524Sfennermld6_print(const u_char *bp) 72856893Sfenner{ 72998524Sfenner struct mld6_hdr *mp = (struct mld6_hdr *)bp; 73098524Sfenner const u_char *ep; 73156893Sfenner 73275115Sfenner /* 'ep' points to the end of available data. */ 73356893Sfenner ep = snapend; 73456893Sfenner 73556893Sfenner if ((u_char *)mp + sizeof(*mp) > ep) 73656893Sfenner return; 73756893Sfenner 738127668Sbms printf("max resp delay: %d ", EXTRACT_16BITS(&mp->mld6_maxdelay)); 73956893Sfenner printf("addr: %s", ip6addr_string(&mp->mld6_addr)); 74075115Sfenner} 74156893Sfenner 74275115Sfennerstatic void 743146773Ssammldv2_report_print(const u_char *bp, u_int len) 744146773Ssam{ 745146773Ssam struct icmp6_hdr *icp = (struct icmp6_hdr *) bp; 746146773Ssam u_int group, nsrcs, ngroups; 747146773Ssam u_int i, j; 748146773Ssam 749146773Ssam /* Minimum len is 8 */ 750146773Ssam if (len < 8) { 751146773Ssam printf(" [invalid len %d]", len); 752146773Ssam return; 753146773Ssam } 754146773Ssam 755146773Ssam TCHECK(icp->icmp6_data16[1]); 756146773Ssam ngroups = ntohs(icp->icmp6_data16[1]); 757146773Ssam printf(", %d group record(s)", ngroups); 758146773Ssam if (vflag > 0) { 759146773Ssam /* Print the group records */ 760146773Ssam group = 8; 761146773Ssam for (i = 0; i < ngroups; i++) { 762146773Ssam /* type(1) + auxlen(1) + numsrc(2) + grp(16) */ 763146773Ssam if (len < group + 20) { 764146773Ssam printf(" [invalid number of groups]"); 765146773Ssam return; 766146773Ssam } 767162017Ssam TCHECK2(bp[group + 4], sizeof(struct in6_addr)); 768146773Ssam printf(" [gaddr %s", ip6addr_string(&bp[group + 4])); 769146773Ssam printf(" %s", tok2str(mldv2report2str, " [v2-report-#%d]", 770146773Ssam bp[group])); 771146773Ssam nsrcs = (bp[group + 2] << 8) + bp[group + 3]; 772146773Ssam /* Check the number of sources and print them */ 773162017Ssam if (len < group + 20 + (nsrcs * sizeof(struct in6_addr))) { 774146773Ssam printf(" [invalid number of sources %d]", nsrcs); 775146773Ssam return; 776146773Ssam } 777146773Ssam if (vflag == 1) 778146773Ssam printf(", %d source(s)", nsrcs); 779146773Ssam else { 780146773Ssam /* Print the sources */ 781146773Ssam (void)printf(" {"); 782146773Ssam for (j = 0; j < nsrcs; j++) { 783162017Ssam TCHECK2(bp[group + 20 + j * sizeof(struct in6_addr)], 784162017Ssam sizeof(struct in6_addr)); 785162017Ssam printf(" %s", ip6addr_string(&bp[group + 20 + j * sizeof(struct in6_addr)])); 786146773Ssam } 787146773Ssam (void)printf(" }"); 788146773Ssam } 789146773Ssam /* Next group record */ 790162017Ssam group += 20 + nsrcs * sizeof(struct in6_addr); 791146773Ssam printf("]"); 792146773Ssam } 793146773Ssam } 794146773Ssam return; 795146773Ssamtrunc: 796146773Ssam (void)printf("[|icmp6]"); 797146773Ssam return; 798146773Ssam} 799146773Ssam 800146773Ssamstatic void 801146773Ssammldv2_query_print(const u_char *bp, u_int len) 802146773Ssam{ 803146773Ssam struct icmp6_hdr *icp = (struct icmp6_hdr *) bp; 804146773Ssam u_int mrc; 805146773Ssam int mrt, qqi; 806146773Ssam u_int nsrcs; 807146773Ssam register u_int i; 808146773Ssam 809146773Ssam /* Minimum len is 28 */ 810146773Ssam if (len < 28) { 811146773Ssam printf(" [invalid len %d]", len); 812146773Ssam return; 813146773Ssam } 814146773Ssam TCHECK(icp->icmp6_data16[0]); 815146773Ssam mrc = ntohs(icp->icmp6_data16[0]); 816146773Ssam if (mrc < 32768) { 817146773Ssam mrt = mrc; 818146773Ssam } else { 819146773Ssam mrt = ((mrc & 0x0fff) | 0x1000) << (((mrc & 0x7000) >> 12) + 3); 820146773Ssam } 821146773Ssam if (vflag) { 822146773Ssam (void)printf(" [max resp delay=%d]", mrt); 823146773Ssam } 824162017Ssam TCHECK2(bp[8], sizeof(struct in6_addr)); 825146773Ssam printf(" [gaddr %s", ip6addr_string(&bp[8])); 826146773Ssam 827146773Ssam if (vflag) { 828146773Ssam TCHECK(bp[25]); 829146773Ssam if (bp[24] & 0x08) { 830146773Ssam printf(" sflag"); 831146773Ssam } 832146773Ssam if (bp[24] & 0x07) { 833146773Ssam printf(" robustness=%d", bp[24] & 0x07); 834146773Ssam } 835146773Ssam if (bp[25] < 128) { 836146773Ssam qqi = bp[25]; 837146773Ssam } else { 838146773Ssam qqi = ((bp[25] & 0x0f) | 0x10) << (((bp[25] & 0x70) >> 4) + 3); 839146773Ssam } 840146773Ssam printf(" qqi=%d", qqi); 841146773Ssam } 842146773Ssam 843146773Ssam TCHECK2(bp[26], 2); 844146773Ssam nsrcs = ntohs(*(u_short *)&bp[26]); 845146773Ssam if (nsrcs > 0) { 846162017Ssam if (len < 28 + nsrcs * sizeof(struct in6_addr)) 847146773Ssam printf(" [invalid number of sources]"); 848146773Ssam else if (vflag > 1) { 849146773Ssam printf(" {"); 850146773Ssam for (i = 0; i < nsrcs; i++) { 851162017Ssam TCHECK2(bp[28 + i * sizeof(struct in6_addr)], 852162017Ssam sizeof(struct in6_addr)); 853162017Ssam printf(" %s", ip6addr_string(&bp[28 + i * sizeof(struct in6_addr)])); 854146773Ssam } 855146773Ssam printf(" }"); 856146773Ssam } else 857146773Ssam printf(", %d source(s)", nsrcs); 858146773Ssam } 859146773Ssam printf("]"); 860146773Ssam return; 861146773Ssamtrunc: 862146773Ssam (void)printf("[|icmp6]"); 863146773Ssam return; 864146773Ssam} 865146773Ssam 866146773Ssamvoid 86775115Sfennerdnsname_print(const u_char *cp, const u_char *ep) 86875115Sfenner{ 86975115Sfenner int i; 87075115Sfenner 87175115Sfenner /* DNS name decoding - no decompression */ 87275115Sfenner printf(", \""); 87375115Sfenner while (cp < ep) { 87475115Sfenner i = *cp++; 87575115Sfenner if (i) { 87675115Sfenner if (i > ep - cp) { 87775115Sfenner printf("???"); 87875115Sfenner break; 87975115Sfenner } 88075115Sfenner while (i-- && cp < ep) { 88175115Sfenner safeputchar(*cp); 88275115Sfenner cp++; 88375115Sfenner } 88475115Sfenner if (cp + 1 < ep && *cp) 88575115Sfenner printf("."); 88675115Sfenner } else { 88775115Sfenner if (cp == ep) { 88875115Sfenner /* FQDN */ 88975115Sfenner printf("."); 89075115Sfenner } else if (cp + 1 == ep && *cp == '\0') { 89175115Sfenner /* truncated */ 89275115Sfenner } else { 89375115Sfenner /* invalid */ 89475115Sfenner printf("???"); 89575115Sfenner } 89675115Sfenner break; 89775115Sfenner } 89875115Sfenner } 89975115Sfenner printf("\""); 90075115Sfenner} 90175115Sfenner 902127668Sbmsstatic void 903127668Sbmsicmp6_nodeinfo_print(u_int icmp6len, const u_char *bp, const u_char *ep) 90475115Sfenner{ 90575115Sfenner struct icmp6_nodeinfo *ni6; 90675115Sfenner struct icmp6_hdr *dp; 90775115Sfenner const u_char *cp; 908127668Sbms size_t siz, i; 90975115Sfenner int needcomma; 91075115Sfenner 911127668Sbms if (ep < bp) 912127668Sbms return; 91375115Sfenner dp = (struct icmp6_hdr *)bp; 91475115Sfenner ni6 = (struct icmp6_nodeinfo *)bp; 91575115Sfenner siz = ep - bp; 91675115Sfenner 91775115Sfenner switch (ni6->ni_type) { 91875115Sfenner case ICMP6_NI_QUERY: 91975115Sfenner if (siz == sizeof(*dp) + 4) { 92075115Sfenner /* KAME who-are-you */ 921146773Ssam printf(" who-are-you request"); 92275115Sfenner break; 92375115Sfenner } 924146773Ssam printf(" node information query"); 92575115Sfenner 92675115Sfenner TCHECK2(*dp, sizeof(*ni6)); 92775115Sfenner ni6 = (struct icmp6_nodeinfo *)dp; 92875115Sfenner printf(" ("); /*)*/ 929127668Sbms switch (EXTRACT_16BITS(&ni6->ni_qtype)) { 93075115Sfenner case NI_QTYPE_NOOP: 93175115Sfenner printf("noop"); 93275115Sfenner break; 93375115Sfenner case NI_QTYPE_SUPTYPES: 93475115Sfenner printf("supported qtypes"); 935127668Sbms i = EXTRACT_16BITS(&ni6->ni_flags); 93675115Sfenner if (i) 93775115Sfenner printf(" [%s]", (i & 0x01) ? "C" : ""); 93875115Sfenner break; 93975115Sfenner break; 94075115Sfenner case NI_QTYPE_FQDN: 94175115Sfenner printf("DNS name"); 94275115Sfenner break; 94375115Sfenner case NI_QTYPE_NODEADDR: 94475115Sfenner printf("node addresses"); 94575115Sfenner i = ni6->ni_flags; 94675115Sfenner if (!i) 94775115Sfenner break; 94875115Sfenner /* NI_NODEADDR_FLAG_TRUNCATE undefined for query */ 94975115Sfenner printf(" [%s%s%s%s%s%s]", 95075115Sfenner (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "", 95175115Sfenner (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "", 95275115Sfenner (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "", 95375115Sfenner (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "", 95475115Sfenner (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "", 95575115Sfenner (i & NI_NODEADDR_FLAG_ALL) ? "A" : ""); 95675115Sfenner break; 95775115Sfenner default: 95875115Sfenner printf("unknown"); 95975115Sfenner break; 96075115Sfenner } 96175115Sfenner 96275115Sfenner if (ni6->ni_qtype == NI_QTYPE_NOOP || 96375115Sfenner ni6->ni_qtype == NI_QTYPE_SUPTYPES) { 96475115Sfenner if (siz != sizeof(*ni6)) 96575115Sfenner if (vflag) 96675115Sfenner printf(", invalid len"); 96775115Sfenner /*(*/ 96875115Sfenner printf(")"); 96975115Sfenner break; 97075115Sfenner } 97175115Sfenner 97275115Sfenner 97375115Sfenner /* XXX backward compat, icmp-name-lookup-03 */ 97475115Sfenner if (siz == sizeof(*ni6)) { 97575115Sfenner printf(", 03 draft"); 97675115Sfenner /*(*/ 97775115Sfenner printf(")"); 97875115Sfenner break; 97975115Sfenner } 98075115Sfenner 98175115Sfenner switch (ni6->ni_code) { 98275115Sfenner case ICMP6_NI_SUBJ_IPV6: 98375115Sfenner if (!TTEST2(*dp, 98475115Sfenner sizeof(*ni6) + sizeof(struct in6_addr))) 98575115Sfenner break; 98675115Sfenner if (siz != sizeof(*ni6) + sizeof(struct in6_addr)) { 98775115Sfenner if (vflag) 98875115Sfenner printf(", invalid subject len"); 98975115Sfenner break; 99075115Sfenner } 99175115Sfenner printf(", subject=%s", 99275115Sfenner getname6((const u_char *)(ni6 + 1))); 99375115Sfenner break; 99475115Sfenner case ICMP6_NI_SUBJ_FQDN: 99575115Sfenner printf(", subject=DNS name"); 99675115Sfenner cp = (const u_char *)(ni6 + 1); 99775115Sfenner if (cp[0] == ep - cp - 1) { 99875115Sfenner /* icmp-name-lookup-03, pascal string */ 99975115Sfenner if (vflag) 100075115Sfenner printf(", 03 draft"); 100175115Sfenner cp++; 100275115Sfenner printf(", \""); 100375115Sfenner while (cp < ep) { 100475115Sfenner safeputchar(*cp); 100575115Sfenner cp++; 100675115Sfenner } 100775115Sfenner printf("\""); 100875115Sfenner } else 100975115Sfenner dnsname_print(cp, ep); 101075115Sfenner break; 101175115Sfenner case ICMP6_NI_SUBJ_IPV4: 101275115Sfenner if (!TTEST2(*dp, sizeof(*ni6) + sizeof(struct in_addr))) 101375115Sfenner break; 101475115Sfenner if (siz != sizeof(*ni6) + sizeof(struct in_addr)) { 101575115Sfenner if (vflag) 101675115Sfenner printf(", invalid subject len"); 101775115Sfenner break; 101875115Sfenner } 101975115Sfenner printf(", subject=%s", 102075115Sfenner getname((const u_char *)(ni6 + 1))); 102175115Sfenner break; 102275115Sfenner default: 102375115Sfenner printf(", unknown subject"); 102475115Sfenner break; 102575115Sfenner } 102675115Sfenner 102775115Sfenner /*(*/ 102875115Sfenner printf(")"); 102975115Sfenner break; 103075115Sfenner 103175115Sfenner case ICMP6_NI_REPLY: 103275115Sfenner if (icmp6len > siz) { 103375115Sfenner printf("[|icmp6: node information reply]"); 103475115Sfenner break; 103575115Sfenner } 103675115Sfenner 103775115Sfenner needcomma = 0; 103875115Sfenner 103975115Sfenner ni6 = (struct icmp6_nodeinfo *)dp; 1040146773Ssam printf(" node information reply"); 104175115Sfenner printf(" ("); /*)*/ 104275115Sfenner switch (ni6->ni_code) { 104375115Sfenner case ICMP6_NI_SUCCESS: 104475115Sfenner if (vflag) { 104575115Sfenner printf("success"); 104675115Sfenner needcomma++; 104775115Sfenner } 104875115Sfenner break; 104975115Sfenner case ICMP6_NI_REFUSED: 105075115Sfenner printf("refused"); 105175115Sfenner needcomma++; 105275115Sfenner if (siz != sizeof(*ni6)) 105375115Sfenner if (vflag) 105475115Sfenner printf(", invalid length"); 105575115Sfenner break; 105675115Sfenner case ICMP6_NI_UNKNOWN: 105775115Sfenner printf("unknown"); 105875115Sfenner needcomma++; 105975115Sfenner if (siz != sizeof(*ni6)) 106075115Sfenner if (vflag) 106175115Sfenner printf(", invalid length"); 106275115Sfenner break; 106375115Sfenner } 106475115Sfenner 106575115Sfenner if (ni6->ni_code != ICMP6_NI_SUCCESS) { 106675115Sfenner /*(*/ 106775115Sfenner printf(")"); 106875115Sfenner break; 106975115Sfenner } 107075115Sfenner 1071127668Sbms switch (EXTRACT_16BITS(&ni6->ni_qtype)) { 107275115Sfenner case NI_QTYPE_NOOP: 107375115Sfenner if (needcomma) 107475115Sfenner printf(", "); 107575115Sfenner printf("noop"); 107675115Sfenner if (siz != sizeof(*ni6)) 107775115Sfenner if (vflag) 107875115Sfenner printf(", invalid length"); 107975115Sfenner break; 108075115Sfenner case NI_QTYPE_SUPTYPES: 108175115Sfenner if (needcomma) 108275115Sfenner printf(", "); 108375115Sfenner printf("supported qtypes"); 1084127668Sbms i = EXTRACT_16BITS(&ni6->ni_flags); 108575115Sfenner if (i) 108675115Sfenner printf(" [%s]", (i & 0x01) ? "C" : ""); 108775115Sfenner break; 108875115Sfenner case NI_QTYPE_FQDN: 108975115Sfenner if (needcomma) 109075115Sfenner printf(", "); 109175115Sfenner printf("DNS name"); 109275115Sfenner cp = (const u_char *)(ni6 + 1) + 4; 109375115Sfenner if (cp[0] == ep - cp - 1) { 109475115Sfenner /* icmp-name-lookup-03, pascal string */ 109575115Sfenner if (vflag) 109675115Sfenner printf(", 03 draft"); 109775115Sfenner cp++; 109875115Sfenner printf(", \""); 109975115Sfenner while (cp < ep) { 110075115Sfenner safeputchar(*cp); 110175115Sfenner cp++; 110275115Sfenner } 110375115Sfenner printf("\""); 110475115Sfenner } else 110575115Sfenner dnsname_print(cp, ep); 1106127668Sbms if ((EXTRACT_16BITS(&ni6->ni_flags) & 0x01) != 0) 110775115Sfenner printf(" [TTL=%u]", *(u_int32_t *)(ni6 + 1)); 110875115Sfenner break; 110975115Sfenner case NI_QTYPE_NODEADDR: 111075115Sfenner if (needcomma) 111175115Sfenner printf(", "); 111275115Sfenner printf("node addresses"); 111375115Sfenner i = sizeof(*ni6); 111475115Sfenner while (i < siz) { 111575115Sfenner if (i + sizeof(struct in6_addr) + sizeof(int32_t) > siz) 111675115Sfenner break; 111775115Sfenner printf(" %s", getname6(bp + i)); 111875115Sfenner i += sizeof(struct in6_addr); 1119127668Sbms printf("(%d)", (int32_t)EXTRACT_32BITS(bp + i)); 112075115Sfenner i += sizeof(int32_t); 112175115Sfenner } 112275115Sfenner i = ni6->ni_flags; 112375115Sfenner if (!i) 112475115Sfenner break; 112575115Sfenner printf(" [%s%s%s%s%s%s%s]", 112675115Sfenner (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "", 112775115Sfenner (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "", 112875115Sfenner (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "", 112975115Sfenner (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "", 113075115Sfenner (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "", 113175115Sfenner (i & NI_NODEADDR_FLAG_ALL) ? "A" : "", 113275115Sfenner (i & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : ""); 113375115Sfenner break; 113475115Sfenner default: 113575115Sfenner if (needcomma) 113675115Sfenner printf(", "); 113775115Sfenner printf("unknown"); 113875115Sfenner break; 113975115Sfenner } 114075115Sfenner 114175115Sfenner /*(*/ 114275115Sfenner printf(")"); 114375115Sfenner break; 114475115Sfenner } 114556893Sfenner return; 114675115Sfenner 114775115Sfennertrunc: 114875115Sfenner fputs("[|icmp6]", stdout); 114956893Sfenner} 115075115Sfenner 1151127668Sbmsstatic void 1152127668Sbmsicmp6_rrenum_print(const u_char *bp, const u_char *ep) 115375115Sfenner{ 115475115Sfenner struct icmp6_router_renum *rr6; 115575115Sfenner const char *cp; 115675115Sfenner struct rr_pco_match *match; 115775115Sfenner struct rr_pco_use *use; 115875115Sfenner char hbuf[NI_MAXHOST]; 115975115Sfenner int n; 116075115Sfenner 1161127668Sbms if (ep < bp) 1162127668Sbms return; 116375115Sfenner rr6 = (struct icmp6_router_renum *)bp; 116475115Sfenner cp = (const char *)(rr6 + 1); 116575115Sfenner 116675115Sfenner TCHECK(rr6->rr_reserved); 116775115Sfenner switch (rr6->rr_code) { 116875115Sfenner case ICMP6_ROUTER_RENUMBERING_COMMAND: 116975115Sfenner printf("router renum: command"); 117075115Sfenner break; 117175115Sfenner case ICMP6_ROUTER_RENUMBERING_RESULT: 117275115Sfenner printf("router renum: result"); 117375115Sfenner break; 117475115Sfenner case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET: 117575115Sfenner printf("router renum: sequence number reset"); 117675115Sfenner break; 117775115Sfenner default: 117875115Sfenner printf("router renum: code-#%d", rr6->rr_code); 117975115Sfenner break; 118075115Sfenner } 118175115Sfenner 1182127668Sbms printf(", seq=%u", EXTRACT_32BITS(&rr6->rr_seqnum)); 118375115Sfenner 118475115Sfenner if (vflag) { 118575115Sfenner#define F(x, y) ((rr6->rr_flags) & (x) ? (y) : "") 118675115Sfenner printf("["); /*]*/ 118775115Sfenner if (rr6->rr_flags) { 118875115Sfenner printf("%s%s%s%s%s,", F(ICMP6_RR_FLAGS_TEST, "T"), 118975115Sfenner F(ICMP6_RR_FLAGS_REQRESULT, "R"), 119098524Sfenner F(ICMP6_RR_FLAGS_FORCEAPPLY, "A"), 119175115Sfenner F(ICMP6_RR_FLAGS_SPECSITE, "S"), 119275115Sfenner F(ICMP6_RR_FLAGS_PREVDONE, "P")); 119375115Sfenner } 119475115Sfenner printf("seg=%u,", rr6->rr_segnum); 1195190207Srpaulo printf("maxdelay=%u", EXTRACT_16BITS(&rr6->rr_maxdelay)); 119675115Sfenner if (rr6->rr_reserved) 1197190207Srpaulo printf("rsvd=0x%x", EXTRACT_32BITS(&rr6->rr_reserved)); 119875115Sfenner /*[*/ 119975115Sfenner printf("]"); 120075115Sfenner#undef F 120175115Sfenner } 120275115Sfenner 120375115Sfenner if (rr6->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) { 120475115Sfenner match = (struct rr_pco_match *)cp; 120575115Sfenner cp = (const char *)(match + 1); 120675115Sfenner 120775115Sfenner TCHECK(match->rpm_prefix); 120875115Sfenner 120998524Sfenner if (vflag > 1) 121075115Sfenner printf("\n\t"); 121175115Sfenner else 121275115Sfenner printf(" "); 121375115Sfenner printf("match("); /*)*/ 121475115Sfenner switch (match->rpm_code) { 121575115Sfenner case RPM_PCO_ADD: printf("add"); break; 121675115Sfenner case RPM_PCO_CHANGE: printf("change"); break; 121775115Sfenner case RPM_PCO_SETGLOBAL: printf("setglobal"); break; 121875115Sfenner default: printf("#%u", match->rpm_code); break; 121975115Sfenner } 122075115Sfenner 122175115Sfenner if (vflag) { 122275115Sfenner printf(",ord=%u", match->rpm_ordinal); 122375115Sfenner printf(",min=%u", match->rpm_minlen); 122475115Sfenner printf(",max=%u", match->rpm_maxlen); 122575115Sfenner } 122675115Sfenner if (inet_ntop(AF_INET6, &match->rpm_prefix, hbuf, sizeof(hbuf))) 122775115Sfenner printf(",%s/%u", hbuf, match->rpm_matchlen); 122875115Sfenner else 122975115Sfenner printf(",?/%u", match->rpm_matchlen); 123075115Sfenner /*(*/ 123175115Sfenner printf(")"); 123275115Sfenner 123375115Sfenner n = match->rpm_len - 3; 123475115Sfenner if (n % 4) 123575115Sfenner goto trunc; 123675115Sfenner n /= 4; 123775115Sfenner while (n-- > 0) { 123875115Sfenner use = (struct rr_pco_use *)cp; 123975115Sfenner cp = (const char *)(use + 1); 124075115Sfenner 124175115Sfenner TCHECK(use->rpu_prefix); 124275115Sfenner 124398524Sfenner if (vflag > 1) 124475115Sfenner printf("\n\t"); 124575115Sfenner else 124675115Sfenner printf(" "); 124775115Sfenner printf("use("); /*)*/ 124875115Sfenner if (use->rpu_flags) { 124975115Sfenner#define F(x, y) ((use->rpu_flags) & (x) ? (y) : "") 125075115Sfenner printf("%s%s,", 125175115Sfenner F(ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, "V"), 125275115Sfenner F(ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, "P")); 125375115Sfenner#undef F 125475115Sfenner } 125575115Sfenner if (vflag) { 125675115Sfenner printf("mask=0x%x,", use->rpu_ramask); 125775115Sfenner printf("raflags=0x%x,", use->rpu_raflags); 125875115Sfenner if (~use->rpu_vltime == 0) 125975115Sfenner printf("vltime=infty,"); 126075115Sfenner else 126175115Sfenner printf("vltime=%u,", 1262127668Sbms EXTRACT_32BITS(&use->rpu_vltime)); 126375115Sfenner if (~use->rpu_pltime == 0) 126475115Sfenner printf("pltime=infty,"); 126575115Sfenner else 126675115Sfenner printf("pltime=%u,", 1267127668Sbms EXTRACT_32BITS(&use->rpu_pltime)); 126875115Sfenner } 126975115Sfenner if (inet_ntop(AF_INET6, &use->rpu_prefix, hbuf, 127075115Sfenner sizeof(hbuf))) 127175115Sfenner printf("%s/%u/%u", hbuf, use->rpu_uselen, 127275115Sfenner use->rpu_keeplen); 127375115Sfenner else 127475115Sfenner printf("?/%u/%u", use->rpu_uselen, 127575115Sfenner use->rpu_keeplen); 127675115Sfenner /*(*/ 127775115Sfenner printf(")"); 127875115Sfenner } 127975115Sfenner } 128075115Sfenner 128175115Sfenner return; 128275115Sfenner 128375115Sfennertrunc: 128475115Sfenner fputs("[|icmp6]", stdout); 128575115Sfenner} 128675115Sfenner 128756893Sfenner#endif /* INET6 */ 1288