print-icmp6.c revision 146773
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_ = 24146773Ssam "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.79 2005/01/14 10:41:50 hannes 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 3875115Sfenner#include "ip6.h" 3975115Sfenner#include "icmp6.h" 40127668Sbms#include "ipproto.h" 4156893Sfenner 4256893Sfenner#include "interface.h" 4356893Sfenner#include "addrtoname.h" 44127668Sbms#include "extract.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"}, 72146773Ssam { MLD6_LISTENER_QUERY, "multicast listener query "}, 73146773Ssam { MLD6_LISTENER_REPORT, "multicast listener report "}, 74146773Ssam { MLD6_LISTENER_DONE, "multicast listener done "}, 75146773Ssam { ND_ROUTER_SOLICIT, "router solicitation "}, 76146773Ssam { ND_ROUTER_ADVERT, "router advertisement"}, 77146773Ssam { ND_NEIGHBOR_SOLICIT, "neighbor solicitation"}, 78146773Ssam { ND_NEIGHBOR_ADVERT, "neighbor advertisment"}, 79146773Ssam { ND_REDIRECT, "redirect"}, 80146773Ssam { ICMP6_ROUTER_RENUMBERING, "router renumbering"}, 81146773Ssam { IND_SOLICIT, "inverse neighbor solicitation"}, 82146773Ssam { IND_ADVERT, "inverse neighbor advertisement"}, 83146773Ssam { 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"}, 134146773Ssam { ND_OPT_ADVINTERVAL, "advertisment 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 char *str; 24198524Sfenner const struct ip6_hdr *oip; 24298524Sfenner const struct udphdr *ouh; 24398524Sfenner int dport; 24498524Sfenner const u_char *ep; 24556893Sfenner char buf[256]; 246127668Sbms u_int prot; 24756893Sfenner 24856893Sfenner dp = (struct icmp6_hdr *)bp; 24956893Sfenner ip = (struct ip6_hdr *)bp2; 25056893Sfenner oip = (struct ip6_hdr *)(dp + 1); 25156893Sfenner str = buf; 25275115Sfenner /* 'ep' points to the end of available data. */ 25356893Sfenner ep = snapend; 25456893Sfenner 255127668Sbms TCHECK(dp->icmp6_cksum); 256127668Sbms 257127668Sbms if (vflag && !fragmented) { 258127668Sbms int sum = dp->icmp6_cksum; 259127668Sbms 260127668Sbms if (TTEST2(bp[0], length)) { 261127668Sbms sum = icmp6_cksum(ip, dp, length); 262127668Sbms if (sum != 0) 263127668Sbms (void)printf("[bad icmp6 cksum %x!] ", sum); 264127668Sbms else 265127668Sbms (void)printf("[icmp6 sum ok] "); 266127668Sbms } 267127668Sbms } 268127668Sbms 269146773Ssam printf("ICMP6, %s", tok2str(icmp6_type_values,"unknown icmp6 type (%u)",dp->icmp6_type)); 270146773Ssam 271146773Ssam /* display cosmetics: print the packet length for printer that use the vflag now */ 272146773Ssam if (vflag && (dp->icmp6_type == 273146773Ssam ND_ROUTER_SOLICIT || 274146773Ssam ND_ROUTER_ADVERT || 275146773Ssam ND_NEIGHBOR_ADVERT || 276146773Ssam ND_NEIGHBOR_SOLICIT || 277146773Ssam ND_REDIRECT || 278146773Ssam ICMP6_HADISCOV_REPLY || 279146773Ssam ICMP6_MOBILEPREFIX_ADVERT )) 280146773Ssam printf(", length %u", length); 281146773Ssam 28275115Sfenner switch (dp->icmp6_type) { 28356893Sfenner case ICMP6_DST_UNREACH: 28456893Sfenner TCHECK(oip->ip6_dst); 285146773Ssam printf(", %s", tok2str(icmp6_dst_unreach_code_values,"unknown unreach code (%u)",dp->icmp6_code)); 28656893Sfenner switch (dp->icmp6_code) { 287146773Ssam 288146773Ssam case ICMP6_DST_UNREACH_NOROUTE: /* fall through */ 28956893Sfenner case ICMP6_DST_UNREACH_ADMIN: 290146773Ssam case ICMP6_DST_UNREACH_ADDR: 291146773Ssam printf(" %s",ip6addr_string(&oip->ip6_dst)); 292146773Ssam break; 29356893Sfenner case ICMP6_DST_UNREACH_BEYONDSCOPE: 294146773Ssam printf(" %s, source address %s", 29556893Sfenner ip6addr_string(&oip->ip6_dst), 29656893Sfenner ip6addr_string(&oip->ip6_src)); 29756893Sfenner break; 29856893Sfenner case ICMP6_DST_UNREACH_NOPORT: 29975115Sfenner if ((ouh = get_upperlayer((u_char *)oip, &prot)) 30075115Sfenner == NULL) 30175115Sfenner goto trunc; 30275115Sfenner 303127668Sbms dport = EXTRACT_16BITS(&ouh->uh_dport); 30475115Sfenner switch (prot) { 30556893Sfenner case IPPROTO_TCP: 306146773Ssam printf(", %s tcp port %s", 30756893Sfenner ip6addr_string(&oip->ip6_dst), 30856893Sfenner tcpport_string(dport)); 30956893Sfenner break; 31056893Sfenner case IPPROTO_UDP: 311146773Ssam printf(", %s udp port %s", 31256893Sfenner ip6addr_string(&oip->ip6_dst), 31356893Sfenner udpport_string(dport)); 31456893Sfenner break; 31556893Sfenner default: 316146773Ssam printf(", %s protocol %d port %d unreachable", 31756893Sfenner ip6addr_string(&oip->ip6_dst), 31856893Sfenner oip->ip6_nxt, dport); 31956893Sfenner break; 32056893Sfenner } 32156893Sfenner break; 32256893Sfenner default: 323146773Ssam if (vflag <= 1) { 324146773Ssam print_unknown_data(bp,"\n\t",length); 325146773Ssam return; 326146773Ssam } 327146773Ssam break; 32856893Sfenner } 32956893Sfenner break; 33056893Sfenner case ICMP6_PACKET_TOO_BIG: 33156893Sfenner TCHECK(dp->icmp6_mtu); 332146773Ssam printf(", mtu %u", EXTRACT_32BITS(&dp->icmp6_mtu)); 33356893Sfenner break; 33456893Sfenner case ICMP6_TIME_EXCEEDED: 33556893Sfenner TCHECK(oip->ip6_dst); 33656893Sfenner switch (dp->icmp6_code) { 33756893Sfenner case ICMP6_TIME_EXCEED_TRANSIT: 338146773Ssam printf(" for %s", 33956893Sfenner ip6addr_string(&oip->ip6_dst)); 34056893Sfenner break; 34156893Sfenner case ICMP6_TIME_EXCEED_REASSEMBLY: 342146773Ssam printf(" (reassembly)"); 34356893Sfenner break; 34456893Sfenner default: 345146773Ssam printf(", unknown code (%u)", dp->icmp6_code); 34656893Sfenner break; 34756893Sfenner } 34856893Sfenner break; 34956893Sfenner case ICMP6_PARAM_PROB: 35056893Sfenner TCHECK(oip->ip6_dst); 35156893Sfenner switch (dp->icmp6_code) { 35256893Sfenner case ICMP6_PARAMPROB_HEADER: 353146773Ssam printf(", errorneous - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)); 35456893Sfenner break; 35556893Sfenner case ICMP6_PARAMPROB_NEXTHEADER: 356146773Ssam printf(", next header - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)); 35756893Sfenner break; 35856893Sfenner case ICMP6_PARAMPROB_OPTION: 359146773Ssam printf(", option - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)); 36056893Sfenner break; 36156893Sfenner default: 362146773Ssam printf(", code-#%d", 36356893Sfenner dp->icmp6_code); 36456893Sfenner break; 36556893Sfenner } 36656893Sfenner break; 36756893Sfenner case ICMP6_ECHO_REQUEST: 36856893Sfenner case ICMP6_ECHO_REPLY: 369127668Sbms TCHECK(dp->icmp6_seq); 370146773Ssam printf(", seq %u", EXTRACT_16BITS(&dp->icmp6_seq)); 37156893Sfenner break; 37256893Sfenner case ICMP6_MEMBERSHIP_QUERY: 373146773Ssam if (length == MLD_MINLEN) { 374146773Ssam mld6_print((const u_char *)dp); 375146773Ssam } else if (length >= MLDV2_MINLEN) { 376146773Ssam printf("v2 "); 377146773Ssam mldv2_query_print((const u_char *)dp, length); 378146773Ssam } else { 379146773Ssam printf(" unknown-version (len %u) ", length); 380146773Ssam } 38156893Sfenner break; 38256893Sfenner case ICMP6_MEMBERSHIP_REPORT: 38356893Sfenner mld6_print((const u_char *)dp); 38456893Sfenner break; 38556893Sfenner case ICMP6_MEMBERSHIP_REDUCTION: 38656893Sfenner mld6_print((const u_char *)dp); 38756893Sfenner break; 38856893Sfenner case ND_ROUTER_SOLICIT: 389146773Ssam#define RTSOLLEN 8 39056893Sfenner if (vflag) { 39175115Sfenner icmp6_opt_print((const u_char *)dp + RTSOLLEN, 392127668Sbms length - RTSOLLEN); 39356893Sfenner } 39456893Sfenner break; 39556893Sfenner case ND_ROUTER_ADVERT: 396146773Ssam#define RTADVLEN 16 39756893Sfenner if (vflag) { 39856893Sfenner struct nd_router_advert *p; 39956893Sfenner 40056893Sfenner p = (struct nd_router_advert *)dp; 40156893Sfenner TCHECK(p->nd_ra_retransmit); 402146773Ssam printf("\n\thop limit %u, Flags [%s]" \ 403146773Ssam ", pref %s, router lifetime %us, reachable time %us, retrans time %us", 404146773Ssam (u_int)p->nd_ra_curhoplimit, 405146773Ssam bittok2str(icmp6_opt_ra_flag_values,"none",(p->nd_ra_flags_reserved)), 406146773Ssam get_rtpref(p->nd_ra_flags_reserved), 407146773Ssam EXTRACT_16BITS(&p->nd_ra_router_lifetime), 408146773Ssam EXTRACT_32BITS(&p->nd_ra_reachable), 409146773Ssam EXTRACT_32BITS(&p->nd_ra_retransmit)); 41098524Sfenner 41175115Sfenner icmp6_opt_print((const u_char *)dp + RTADVLEN, 412127668Sbms length - RTADVLEN); 41356893Sfenner } 41456893Sfenner break; 41556893Sfenner case ND_NEIGHBOR_SOLICIT: 41656893Sfenner { 41756893Sfenner struct nd_neighbor_solicit *p; 41856893Sfenner p = (struct nd_neighbor_solicit *)dp; 41956893Sfenner TCHECK(p->nd_ns_target); 420146773Ssam printf(", who has %s", ip6addr_string(&p->nd_ns_target)); 42156893Sfenner if (vflag) { 42256893Sfenner#define NDSOLLEN 24 42375115Sfenner icmp6_opt_print((const u_char *)dp + NDSOLLEN, 424127668Sbms length - NDSOLLEN); 42556893Sfenner } 42656893Sfenner } 42756893Sfenner break; 42856893Sfenner case ND_NEIGHBOR_ADVERT: 42956893Sfenner { 43056893Sfenner struct nd_neighbor_advert *p; 43156893Sfenner 43256893Sfenner p = (struct nd_neighbor_advert *)dp; 43356893Sfenner TCHECK(p->nd_na_target); 434146773Ssam printf(", tgt is %s", 43556893Sfenner ip6addr_string(&p->nd_na_target)); 43675115Sfenner if (vflag) { 437146773Ssam printf(", Flags [%s]", 438146773Ssam bittok2str(icmp6_nd_na_flag_values, 439146773Ssam "none", 440146773Ssam EXTRACT_32BITS(&p->nd_na_flags_reserved))); 44156893Sfenner#define NDADVLEN 24 44275115Sfenner icmp6_opt_print((const u_char *)dp + NDADVLEN, 443127668Sbms length - NDADVLEN); 44475115Sfenner#undef NDADVLEN 44556893Sfenner } 44656893Sfenner } 44756893Sfenner break; 44856893Sfenner case ND_REDIRECT: 44956893Sfenner#define RDR(i) ((struct nd_redirect *)(i)) 45056893Sfenner TCHECK(RDR(dp)->nd_rd_dst); 451146773Ssam printf(", %s", getname6((const u_char *)&RDR(dp)->nd_rd_dst)); 452127668Sbms TCHECK(RDR(dp)->nd_rd_target); 45375115Sfenner printf(" to %s", 45475115Sfenner getname6((const u_char*)&RDR(dp)->nd_rd_target)); 45556893Sfenner#define REDIRECTLEN 40 45656893Sfenner if (vflag) { 45756893Sfenner icmp6_opt_print((const u_char *)dp + REDIRECTLEN, 458127668Sbms length - REDIRECTLEN); 45956893Sfenner } 46056893Sfenner break; 46175115Sfenner#undef REDIRECTLEN 46275115Sfenner#undef RDR 46356893Sfenner case ICMP6_ROUTER_RENUMBERING: 464127668Sbms icmp6_rrenum_print(bp, ep); 46556893Sfenner break; 46675115Sfenner case ICMP6_NI_QUERY: 46775115Sfenner case ICMP6_NI_REPLY: 468127668Sbms icmp6_nodeinfo_print(length, bp, ep); 46956893Sfenner break; 470146773Ssam case IND_SOLICIT: 471146773Ssam case IND_ADVERT: 472146773Ssam break; 473146773Ssam case ICMP6_V2_MEMBERSHIP_REPORT: 474146773Ssam mldv2_report_print((const u_char *) dp, length); 475146773Ssam break; 476146773Ssam case ICMP6_MOBILEPREFIX_SOLICIT: /* fall through */ 477127668Sbms case ICMP6_HADISCOV_REQUEST: 478146773Ssam TCHECK(dp->icmp6_data16[0]); 479146773Ssam printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])); 480146773Ssam break; 481127668Sbms case ICMP6_HADISCOV_REPLY: 482127668Sbms if (vflag) { 483127668Sbms struct in6_addr *in6; 484127668Sbms u_char *cp; 485127668Sbms 486127668Sbms TCHECK(dp->icmp6_data16[0]); 487146773Ssam printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])); 488127668Sbms cp = (u_char *)dp + length; 489127668Sbms in6 = (struct in6_addr *)(dp + 1); 490127668Sbms for (; (u_char *)in6 < cp; in6++) { 491127668Sbms TCHECK(*in6); 492127668Sbms printf(", %s", ip6addr_string(in6)); 493127668Sbms } 494127668Sbms } 495127668Sbms break; 496127668Sbms case ICMP6_MOBILEPREFIX_ADVERT: 497127668Sbms if (vflag) { 498127668Sbms TCHECK(dp->icmp6_data16[0]); 499146773Ssam printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])); 500127668Sbms if (dp->icmp6_data16[1] & 0xc0) 501127668Sbms printf(" "); 502127668Sbms if (dp->icmp6_data16[1] & 0x80) 503127668Sbms printf("M"); 504127668Sbms if (dp->icmp6_data16[1] & 0x40) 505127668Sbms printf("O"); 506127668Sbms#define MPADVLEN 8 507127668Sbms icmp6_opt_print((const u_char *)dp + MPADVLEN, 508127668Sbms length - MPADVLEN); 509127668Sbms } 510127668Sbms break; 51156893Sfenner default: 512146773Ssam printf(", length %u", length); 513146773Ssam if (vflag <= 1) 514146773Ssam print_unknown_data(bp,"\n\t", length); 515146773Ssam return; 516146773Ssam } 517146773Ssam if (!vflag) 518146773Ssam printf(", length %u", length); 51956893Sfenner return; 52056893Sfennertrunc: 52156893Sfenner fputs("[|icmp6]", stdout); 52256893Sfenner} 52356893Sfenner 52475115Sfennerstatic struct udphdr * 525127668Sbmsget_upperlayer(u_char *bp, u_int *prot) 52675115Sfenner{ 52798524Sfenner const u_char *ep; 52875115Sfenner struct ip6_hdr *ip6 = (struct ip6_hdr *)bp; 52975115Sfenner struct udphdr *uh; 53075115Sfenner struct ip6_hbh *hbh; 53175115Sfenner struct ip6_frag *fragh; 53275115Sfenner struct ah *ah; 533127668Sbms u_int nh; 534127668Sbms int hlen; 53575115Sfenner 53675115Sfenner /* 'ep' points to the end of available data. */ 53775115Sfenner ep = snapend; 53875115Sfenner 539127668Sbms if (!TTEST(ip6->ip6_nxt)) 54075115Sfenner return NULL; 54175115Sfenner 54275115Sfenner nh = ip6->ip6_nxt; 54375115Sfenner hlen = sizeof(struct ip6_hdr); 54475115Sfenner 54575115Sfenner while (bp < snapend) { 54675115Sfenner bp += hlen; 54775115Sfenner 54875115Sfenner switch(nh) { 54975115Sfenner case IPPROTO_UDP: 55075115Sfenner case IPPROTO_TCP: 55175115Sfenner uh = (struct udphdr *)bp; 55275115Sfenner if (TTEST(uh->uh_dport)) { 55375115Sfenner *prot = nh; 55475115Sfenner return(uh); 55575115Sfenner } 55675115Sfenner else 55775115Sfenner return(NULL); 55875115Sfenner /* NOTREACHED */ 55975115Sfenner 56075115Sfenner case IPPROTO_HOPOPTS: 56175115Sfenner case IPPROTO_DSTOPTS: 56275115Sfenner case IPPROTO_ROUTING: 56375115Sfenner hbh = (struct ip6_hbh *)bp; 564127668Sbms if (!TTEST(hbh->ip6h_len)) 56575115Sfenner return(NULL); 56675115Sfenner nh = hbh->ip6h_nxt; 56775115Sfenner hlen = (hbh->ip6h_len + 1) << 3; 56875115Sfenner break; 56975115Sfenner 57075115Sfenner case IPPROTO_FRAGMENT: /* this should be odd, but try anyway */ 57175115Sfenner fragh = (struct ip6_frag *)bp; 572127668Sbms if (!TTEST(fragh->ip6f_offlg)) 57375115Sfenner return(NULL); 57475115Sfenner /* fragments with non-zero offset are meaningless */ 575127668Sbms if ((EXTRACT_16BITS(&fragh->ip6f_offlg) & IP6F_OFF_MASK) != 0) 57675115Sfenner return(NULL); 57775115Sfenner nh = fragh->ip6f_nxt; 57875115Sfenner hlen = sizeof(struct ip6_frag); 57975115Sfenner break; 58075115Sfenner 58175115Sfenner case IPPROTO_AH: 58275115Sfenner ah = (struct ah *)bp; 583127668Sbms if (!TTEST(ah->ah_len)) 58475115Sfenner return(NULL); 58575115Sfenner nh = ah->ah_nxt; 58675115Sfenner hlen = (ah->ah_len + 2) << 2; 58775115Sfenner break; 58875115Sfenner 58975115Sfenner default: /* unknown or undecodable header */ 59075115Sfenner *prot = nh; /* meaningless, but set here anyway */ 59175115Sfenner return(NULL); 59275115Sfenner } 59375115Sfenner } 59475115Sfenner 59575115Sfenner return(NULL); /* should be notreached, though */ 59675115Sfenner} 59775115Sfenner 598127668Sbmsstatic void 59998524Sfennericmp6_opt_print(const u_char *bp, int resid) 60056893Sfenner{ 60198524Sfenner const struct nd_opt_hdr *op; 60298524Sfenner const struct nd_opt_hdr *opl; /* why there's no struct? */ 60398524Sfenner const struct nd_opt_prefix_info *opp; 60498524Sfenner const struct icmp6_opts_redirect *opr; 60598524Sfenner const struct nd_opt_mtu *opm; 60698524Sfenner const struct nd_opt_advinterval *opa; 607127668Sbms const struct nd_opt_homeagent_info *oph; 60898524Sfenner const struct nd_opt_route_info *opri; 60998524Sfenner const u_char *cp, *ep; 61098524Sfenner struct in6_addr in6, *in6p; 61198524Sfenner size_t l; 61256893Sfenner 61356893Sfenner#define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return 61456893Sfenner 61598524Sfenner cp = bp; 61675115Sfenner /* 'ep' points to the end of available data. */ 61756893Sfenner ep = snapend; 61856893Sfenner 61998524Sfenner while (cp < ep) { 62098524Sfenner op = (struct nd_opt_hdr *)cp; 62198524Sfenner 62298524Sfenner ECHECK(op->nd_opt_len); 62398524Sfenner if (resid <= 0) 62498524Sfenner return; 62598524Sfenner if (op->nd_opt_len == 0) 62656893Sfenner goto trunc; 62798524Sfenner if (cp + (op->nd_opt_len << 3) > ep) 62856893Sfenner goto trunc; 62998524Sfenner 630146773Ssam printf("\n\t %s option (%u), length %u (%u): ", 631146773Ssam tok2str(icmp6_opt_values, "unknown", op->nd_opt_type), 632146773Ssam op->nd_opt_type, 633146773Ssam op->nd_opt_len << 3, 634146773Ssam op->nd_opt_len); 635146773Ssam 63698524Sfenner switch (op->nd_opt_type) { 63798524Sfenner case ND_OPT_SOURCE_LINKADDR: 63898524Sfenner opl = (struct nd_opt_hdr *)op; 63998524Sfenner l = (op->nd_opt_len << 3) - 2; 64098524Sfenner print_lladdr(cp + 2, l); 64198524Sfenner break; 64298524Sfenner case ND_OPT_TARGET_LINKADDR: 64398524Sfenner opl = (struct nd_opt_hdr *)op; 64498524Sfenner l = (op->nd_opt_len << 3) - 2; 64598524Sfenner print_lladdr(cp + 2, l); 64698524Sfenner break; 64798524Sfenner case ND_OPT_PREFIX_INFORMATION: 64898524Sfenner opp = (struct nd_opt_prefix_info *)op; 64998524Sfenner TCHECK(opp->nd_opt_pi_prefix); 650146773Ssam printf("%s/%u%s, Flags [%s], valid time %ss", 651146773Ssam ip6addr_string(&opp->nd_opt_pi_prefix), 652146773Ssam opp->nd_opt_pi_prefix_len, 653146773Ssam (op->nd_opt_len != 4) ? "badlen" : "", 654146773Ssam bittok2str(icmp6_opt_pi_flag_values, "none", opp->nd_opt_pi_flags_reserved), 655146773Ssam get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_valid_time))); 656146773Ssam printf(", pref. time %ss", get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_preferred_time))); 65798524Sfenner break; 65898524Sfenner case ND_OPT_REDIRECTED_HEADER: 65998524Sfenner opr = (struct icmp6_opts_redirect *)op; 660146773Ssam print_unknown_data(bp,"\n\t ",op->nd_opt_len<<3); 66198524Sfenner /* xxx */ 66298524Sfenner break; 66398524Sfenner case ND_OPT_MTU: 66498524Sfenner opm = (struct nd_opt_mtu *)op; 66598524Sfenner TCHECK(opm->nd_opt_mtu_mtu); 666146773Ssam printf(" %u%s", 667146773Ssam EXTRACT_32BITS(&opm->nd_opt_mtu_mtu), 668146773Ssam (op->nd_opt_len != 1) ? "bad option length" : "" ); 669146773Ssam break; 67098524Sfenner case ND_OPT_ADVINTERVAL: 67198524Sfenner opa = (struct nd_opt_advinterval *)op; 67298524Sfenner TCHECK(opa->nd_opt_adv_interval); 673146773Ssam printf(" %us", EXTRACT_32BITS(&opa->nd_opt_adv_interval)); 674127668Sbms break; 675127668Sbms case ND_OPT_HOMEAGENT_INFO: 676127668Sbms oph = (struct nd_opt_homeagent_info *)op; 677127668Sbms TCHECK(oph->nd_opt_hai_lifetime); 678146773Ssam printf(" preference %u, lifetime %u", 679146773Ssam EXTRACT_16BITS(&oph->nd_opt_hai_preference), 680146773Ssam EXTRACT_16BITS(&oph->nd_opt_hai_lifetime)); 681127668Sbms break; 68298524Sfenner case ND_OPT_ROUTE_INFO: 68398524Sfenner opri = (struct nd_opt_route_info *)op; 68498524Sfenner TCHECK(opri->nd_opt_rti_lifetime); 68598524Sfenner memset(&in6, 0, sizeof(in6)); 68698524Sfenner in6p = (struct in6_addr *)(opri + 1); 68798524Sfenner switch (op->nd_opt_len) { 68898524Sfenner case 1: 68998524Sfenner break; 69098524Sfenner case 2: 69198524Sfenner TCHECK2(*in6p, 8); 69298524Sfenner memcpy(&in6, opri + 1, 8); 69398524Sfenner break; 69498524Sfenner case 3: 69598524Sfenner TCHECK(*in6p); 69698524Sfenner memcpy(&in6, opri + 1, sizeof(in6)); 69798524Sfenner break; 69898524Sfenner default: 69998524Sfenner goto trunc; 70098524Sfenner } 70198524Sfenner printf(" %s/%u", ip6addr_string(&in6), 70298524Sfenner opri->nd_opt_rti_prefixlen); 70398524Sfenner printf(", pref=%s", get_rtpref(opri->nd_opt_rti_flags)); 70498524Sfenner printf(", lifetime=%s", 705127668Sbms get_lifetime(EXTRACT_32BITS(&opri->nd_opt_rti_lifetime))); 70698524Sfenner break; 70798524Sfenner default: 708146773Ssam if (vflag <= 1) { 709146773Ssam print_unknown_data(cp+2,"\n\t ", (op->nd_opt_len << 3) - 2); /* skip option header */ 710146773Ssam return; 711146773Ssam } 712146773Ssam break; 71356893Sfenner } 714146773Ssam /* do we want to see an additional hexdump ? */ 715146773Ssam if (vflag> 1) 716146773Ssam print_unknown_data(cp+2,"\n\t ", (op->nd_opt_len << 3) - 2); /* skip option header */ 71798524Sfenner 71898524Sfenner cp += op->nd_opt_len << 3; 71998524Sfenner resid -= op->nd_opt_len << 3; 72056893Sfenner } 72156893Sfenner return; 72298524Sfenner 72356893Sfenner trunc: 72456893Sfenner fputs("[ndp opt]", stdout); 72556893Sfenner return; 72656893Sfenner#undef ECHECK 72756893Sfenner} 72856893Sfenner 729127668Sbmsstatic void 73098524Sfennermld6_print(const u_char *bp) 73156893Sfenner{ 73298524Sfenner struct mld6_hdr *mp = (struct mld6_hdr *)bp; 73398524Sfenner const u_char *ep; 73456893Sfenner 73575115Sfenner /* 'ep' points to the end of available data. */ 73656893Sfenner ep = snapend; 73756893Sfenner 73856893Sfenner if ((u_char *)mp + sizeof(*mp) > ep) 73956893Sfenner return; 74056893Sfenner 741127668Sbms printf("max resp delay: %d ", EXTRACT_16BITS(&mp->mld6_maxdelay)); 74256893Sfenner printf("addr: %s", ip6addr_string(&mp->mld6_addr)); 74375115Sfenner} 74456893Sfenner 74575115Sfennerstatic void 746146773Ssammldv2_report_print(const u_char *bp, u_int len) 747146773Ssam{ 748146773Ssam struct icmp6_hdr *icp = (struct icmp6_hdr *) bp; 749146773Ssam u_int group, nsrcs, ngroups; 750146773Ssam u_int i, j; 751146773Ssam 752146773Ssam /* Minimum len is 8 */ 753146773Ssam if (len < 8) { 754146773Ssam printf(" [invalid len %d]", len); 755146773Ssam return; 756146773Ssam } 757146773Ssam 758146773Ssam TCHECK(icp->icmp6_data16[1]); 759146773Ssam ngroups = ntohs(icp->icmp6_data16[1]); 760146773Ssam printf(", %d group record(s)", ngroups); 761146773Ssam if (vflag > 0) { 762146773Ssam /* Print the group records */ 763146773Ssam group = 8; 764146773Ssam for (i = 0; i < ngroups; i++) { 765146773Ssam /* type(1) + auxlen(1) + numsrc(2) + grp(16) */ 766146773Ssam if (len < group + 20) { 767146773Ssam printf(" [invalid number of groups]"); 768146773Ssam return; 769146773Ssam } 770146773Ssam TCHECK2(bp[group + 4], 16); 771146773Ssam printf(" [gaddr %s", ip6addr_string(&bp[group + 4])); 772146773Ssam printf(" %s", tok2str(mldv2report2str, " [v2-report-#%d]", 773146773Ssam bp[group])); 774146773Ssam nsrcs = (bp[group + 2] << 8) + bp[group + 3]; 775146773Ssam /* Check the number of sources and print them */ 776146773Ssam if (len < group + 20 + (nsrcs * 16)) { 777146773Ssam printf(" [invalid number of sources %d]", nsrcs); 778146773Ssam return; 779146773Ssam } 780146773Ssam if (vflag == 1) 781146773Ssam printf(", %d source(s)", nsrcs); 782146773Ssam else { 783146773Ssam /* Print the sources */ 784146773Ssam (void)printf(" {"); 785146773Ssam for (j = 0; j < nsrcs; j++) { 786146773Ssam TCHECK2(bp[group + 20 + j * 16], 16); 787146773Ssam printf(" %s", ip6addr_string(&bp[group + 20 + j * 16])); 788146773Ssam } 789146773Ssam (void)printf(" }"); 790146773Ssam } 791146773Ssam /* Next group record */ 792146773Ssam group += 20 + nsrcs * 16; 793146773Ssam printf("]"); 794146773Ssam } 795146773Ssam } 796146773Ssam return; 797146773Ssamtrunc: 798146773Ssam (void)printf("[|icmp6]"); 799146773Ssam return; 800146773Ssam} 801146773Ssam 802146773Ssamstatic void 803146773Ssammldv2_query_print(const u_char *bp, u_int len) 804146773Ssam{ 805146773Ssam struct icmp6_hdr *icp = (struct icmp6_hdr *) bp; 806146773Ssam u_int mrc; 807146773Ssam int mrt, qqi; 808146773Ssam u_int nsrcs; 809146773Ssam register u_int i; 810146773Ssam 811146773Ssam /* Minimum len is 28 */ 812146773Ssam if (len < 28) { 813146773Ssam printf(" [invalid len %d]", len); 814146773Ssam return; 815146773Ssam } 816146773Ssam TCHECK(icp->icmp6_data16[0]); 817146773Ssam mrc = ntohs(icp->icmp6_data16[0]); 818146773Ssam if (mrc < 32768) { 819146773Ssam mrt = mrc; 820146773Ssam } else { 821146773Ssam mrt = ((mrc & 0x0fff) | 0x1000) << (((mrc & 0x7000) >> 12) + 3); 822146773Ssam } 823146773Ssam if (vflag) { 824146773Ssam (void)printf(" [max resp delay=%d]", mrt); 825146773Ssam } 826146773Ssam TCHECK2(bp[8], 16); 827146773Ssam printf(" [gaddr %s", ip6addr_string(&bp[8])); 828146773Ssam 829146773Ssam if (vflag) { 830146773Ssam TCHECK(bp[25]); 831146773Ssam if (bp[24] & 0x08) { 832146773Ssam printf(" sflag"); 833146773Ssam } 834146773Ssam if (bp[24] & 0x07) { 835146773Ssam printf(" robustness=%d", bp[24] & 0x07); 836146773Ssam } 837146773Ssam if (bp[25] < 128) { 838146773Ssam qqi = bp[25]; 839146773Ssam } else { 840146773Ssam qqi = ((bp[25] & 0x0f) | 0x10) << (((bp[25] & 0x70) >> 4) + 3); 841146773Ssam } 842146773Ssam printf(" qqi=%d", qqi); 843146773Ssam } 844146773Ssam 845146773Ssam TCHECK2(bp[26], 2); 846146773Ssam nsrcs = ntohs(*(u_short *)&bp[26]); 847146773Ssam if (nsrcs > 0) { 848146773Ssam if (len < 28 + nsrcs * 16) 849146773Ssam printf(" [invalid number of sources]"); 850146773Ssam else if (vflag > 1) { 851146773Ssam printf(" {"); 852146773Ssam for (i = 0; i < nsrcs; i++) { 853146773Ssam TCHECK2(bp[28 + i * 16], 16); 854146773Ssam printf(" %s", ip6addr_string(&bp[28 + i * 16])); 855146773Ssam } 856146773Ssam printf(" }"); 857146773Ssam } else 858146773Ssam printf(", %d source(s)", nsrcs); 859146773Ssam } 860146773Ssam printf("]"); 861146773Ssam return; 862146773Ssamtrunc: 863146773Ssam (void)printf("[|icmp6]"); 864146773Ssam return; 865146773Ssam} 866146773Ssam 867146773Ssamvoid 86875115Sfennerdnsname_print(const u_char *cp, const u_char *ep) 86975115Sfenner{ 87075115Sfenner int i; 87175115Sfenner 87275115Sfenner /* DNS name decoding - no decompression */ 87375115Sfenner printf(", \""); 87475115Sfenner while (cp < ep) { 87575115Sfenner i = *cp++; 87675115Sfenner if (i) { 87775115Sfenner if (i > ep - cp) { 87875115Sfenner printf("???"); 87975115Sfenner break; 88075115Sfenner } 88175115Sfenner while (i-- && cp < ep) { 88275115Sfenner safeputchar(*cp); 88375115Sfenner cp++; 88475115Sfenner } 88575115Sfenner if (cp + 1 < ep && *cp) 88675115Sfenner printf("."); 88775115Sfenner } else { 88875115Sfenner if (cp == ep) { 88975115Sfenner /* FQDN */ 89075115Sfenner printf("."); 89175115Sfenner } else if (cp + 1 == ep && *cp == '\0') { 89275115Sfenner /* truncated */ 89375115Sfenner } else { 89475115Sfenner /* invalid */ 89575115Sfenner printf("???"); 89675115Sfenner } 89775115Sfenner break; 89875115Sfenner } 89975115Sfenner } 90075115Sfenner printf("\""); 90175115Sfenner} 90275115Sfenner 903127668Sbmsstatic void 904127668Sbmsicmp6_nodeinfo_print(u_int icmp6len, const u_char *bp, const u_char *ep) 90575115Sfenner{ 90675115Sfenner struct icmp6_nodeinfo *ni6; 90775115Sfenner struct icmp6_hdr *dp; 90875115Sfenner const u_char *cp; 909127668Sbms size_t siz, i; 91075115Sfenner int needcomma; 91175115Sfenner 912127668Sbms if (ep < bp) 913127668Sbms return; 91475115Sfenner dp = (struct icmp6_hdr *)bp; 91575115Sfenner ni6 = (struct icmp6_nodeinfo *)bp; 91675115Sfenner siz = ep - bp; 91775115Sfenner 91875115Sfenner switch (ni6->ni_type) { 91975115Sfenner case ICMP6_NI_QUERY: 92075115Sfenner if (siz == sizeof(*dp) + 4) { 92175115Sfenner /* KAME who-are-you */ 922146773Ssam printf(" who-are-you request"); 92375115Sfenner break; 92475115Sfenner } 925146773Ssam printf(" node information query"); 92675115Sfenner 92775115Sfenner TCHECK2(*dp, sizeof(*ni6)); 92875115Sfenner ni6 = (struct icmp6_nodeinfo *)dp; 92975115Sfenner printf(" ("); /*)*/ 930127668Sbms switch (EXTRACT_16BITS(&ni6->ni_qtype)) { 93175115Sfenner case NI_QTYPE_NOOP: 93275115Sfenner printf("noop"); 93375115Sfenner break; 93475115Sfenner case NI_QTYPE_SUPTYPES: 93575115Sfenner printf("supported qtypes"); 936127668Sbms i = EXTRACT_16BITS(&ni6->ni_flags); 93775115Sfenner if (i) 93875115Sfenner printf(" [%s]", (i & 0x01) ? "C" : ""); 93975115Sfenner break; 94075115Sfenner break; 94175115Sfenner case NI_QTYPE_FQDN: 94275115Sfenner printf("DNS name"); 94375115Sfenner break; 94475115Sfenner case NI_QTYPE_NODEADDR: 94575115Sfenner printf("node addresses"); 94675115Sfenner i = ni6->ni_flags; 94775115Sfenner if (!i) 94875115Sfenner break; 94975115Sfenner /* NI_NODEADDR_FLAG_TRUNCATE undefined for query */ 95075115Sfenner printf(" [%s%s%s%s%s%s]", 95175115Sfenner (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "", 95275115Sfenner (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "", 95375115Sfenner (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "", 95475115Sfenner (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "", 95575115Sfenner (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "", 95675115Sfenner (i & NI_NODEADDR_FLAG_ALL) ? "A" : ""); 95775115Sfenner break; 95875115Sfenner default: 95975115Sfenner printf("unknown"); 96075115Sfenner break; 96175115Sfenner } 96275115Sfenner 96375115Sfenner if (ni6->ni_qtype == NI_QTYPE_NOOP || 96475115Sfenner ni6->ni_qtype == NI_QTYPE_SUPTYPES) { 96575115Sfenner if (siz != sizeof(*ni6)) 96675115Sfenner if (vflag) 96775115Sfenner printf(", invalid len"); 96875115Sfenner /*(*/ 96975115Sfenner printf(")"); 97075115Sfenner break; 97175115Sfenner } 97275115Sfenner 97375115Sfenner 97475115Sfenner /* XXX backward compat, icmp-name-lookup-03 */ 97575115Sfenner if (siz == sizeof(*ni6)) { 97675115Sfenner printf(", 03 draft"); 97775115Sfenner /*(*/ 97875115Sfenner printf(")"); 97975115Sfenner break; 98075115Sfenner } 98175115Sfenner 98275115Sfenner switch (ni6->ni_code) { 98375115Sfenner case ICMP6_NI_SUBJ_IPV6: 98475115Sfenner if (!TTEST2(*dp, 98575115Sfenner sizeof(*ni6) + sizeof(struct in6_addr))) 98675115Sfenner break; 98775115Sfenner if (siz != sizeof(*ni6) + sizeof(struct in6_addr)) { 98875115Sfenner if (vflag) 98975115Sfenner printf(", invalid subject len"); 99075115Sfenner break; 99175115Sfenner } 99275115Sfenner printf(", subject=%s", 99375115Sfenner getname6((const u_char *)(ni6 + 1))); 99475115Sfenner break; 99575115Sfenner case ICMP6_NI_SUBJ_FQDN: 99675115Sfenner printf(", subject=DNS name"); 99775115Sfenner cp = (const u_char *)(ni6 + 1); 99875115Sfenner if (cp[0] == ep - cp - 1) { 99975115Sfenner /* icmp-name-lookup-03, pascal string */ 100075115Sfenner if (vflag) 100175115Sfenner printf(", 03 draft"); 100275115Sfenner cp++; 100375115Sfenner printf(", \""); 100475115Sfenner while (cp < ep) { 100575115Sfenner safeputchar(*cp); 100675115Sfenner cp++; 100775115Sfenner } 100875115Sfenner printf("\""); 100975115Sfenner } else 101075115Sfenner dnsname_print(cp, ep); 101175115Sfenner break; 101275115Sfenner case ICMP6_NI_SUBJ_IPV4: 101375115Sfenner if (!TTEST2(*dp, sizeof(*ni6) + sizeof(struct in_addr))) 101475115Sfenner break; 101575115Sfenner if (siz != sizeof(*ni6) + sizeof(struct in_addr)) { 101675115Sfenner if (vflag) 101775115Sfenner printf(", invalid subject len"); 101875115Sfenner break; 101975115Sfenner } 102075115Sfenner printf(", subject=%s", 102175115Sfenner getname((const u_char *)(ni6 + 1))); 102275115Sfenner break; 102375115Sfenner default: 102475115Sfenner printf(", unknown subject"); 102575115Sfenner break; 102675115Sfenner } 102775115Sfenner 102875115Sfenner /*(*/ 102975115Sfenner printf(")"); 103075115Sfenner break; 103175115Sfenner 103275115Sfenner case ICMP6_NI_REPLY: 103375115Sfenner if (icmp6len > siz) { 103475115Sfenner printf("[|icmp6: node information reply]"); 103575115Sfenner break; 103675115Sfenner } 103775115Sfenner 103875115Sfenner needcomma = 0; 103975115Sfenner 104075115Sfenner ni6 = (struct icmp6_nodeinfo *)dp; 1041146773Ssam printf(" node information reply"); 104275115Sfenner printf(" ("); /*)*/ 104375115Sfenner switch (ni6->ni_code) { 104475115Sfenner case ICMP6_NI_SUCCESS: 104575115Sfenner if (vflag) { 104675115Sfenner printf("success"); 104775115Sfenner needcomma++; 104875115Sfenner } 104975115Sfenner break; 105075115Sfenner case ICMP6_NI_REFUSED: 105175115Sfenner printf("refused"); 105275115Sfenner needcomma++; 105375115Sfenner if (siz != sizeof(*ni6)) 105475115Sfenner if (vflag) 105575115Sfenner printf(", invalid length"); 105675115Sfenner break; 105775115Sfenner case ICMP6_NI_UNKNOWN: 105875115Sfenner printf("unknown"); 105975115Sfenner needcomma++; 106075115Sfenner if (siz != sizeof(*ni6)) 106175115Sfenner if (vflag) 106275115Sfenner printf(", invalid length"); 106375115Sfenner break; 106475115Sfenner } 106575115Sfenner 106675115Sfenner if (ni6->ni_code != ICMP6_NI_SUCCESS) { 106775115Sfenner /*(*/ 106875115Sfenner printf(")"); 106975115Sfenner break; 107075115Sfenner } 107175115Sfenner 1072127668Sbms switch (EXTRACT_16BITS(&ni6->ni_qtype)) { 107375115Sfenner case NI_QTYPE_NOOP: 107475115Sfenner if (needcomma) 107575115Sfenner printf(", "); 107675115Sfenner printf("noop"); 107775115Sfenner if (siz != sizeof(*ni6)) 107875115Sfenner if (vflag) 107975115Sfenner printf(", invalid length"); 108075115Sfenner break; 108175115Sfenner case NI_QTYPE_SUPTYPES: 108275115Sfenner if (needcomma) 108375115Sfenner printf(", "); 108475115Sfenner printf("supported qtypes"); 1085127668Sbms i = EXTRACT_16BITS(&ni6->ni_flags); 108675115Sfenner if (i) 108775115Sfenner printf(" [%s]", (i & 0x01) ? "C" : ""); 108875115Sfenner break; 108975115Sfenner case NI_QTYPE_FQDN: 109075115Sfenner if (needcomma) 109175115Sfenner printf(", "); 109275115Sfenner printf("DNS name"); 109375115Sfenner cp = (const u_char *)(ni6 + 1) + 4; 109475115Sfenner if (cp[0] == ep - cp - 1) { 109575115Sfenner /* icmp-name-lookup-03, pascal string */ 109675115Sfenner if (vflag) 109775115Sfenner printf(", 03 draft"); 109875115Sfenner cp++; 109975115Sfenner printf(", \""); 110075115Sfenner while (cp < ep) { 110175115Sfenner safeputchar(*cp); 110275115Sfenner cp++; 110375115Sfenner } 110475115Sfenner printf("\""); 110575115Sfenner } else 110675115Sfenner dnsname_print(cp, ep); 1107127668Sbms if ((EXTRACT_16BITS(&ni6->ni_flags) & 0x01) != 0) 110875115Sfenner printf(" [TTL=%u]", *(u_int32_t *)(ni6 + 1)); 110975115Sfenner break; 111075115Sfenner case NI_QTYPE_NODEADDR: 111175115Sfenner if (needcomma) 111275115Sfenner printf(", "); 111375115Sfenner printf("node addresses"); 111475115Sfenner i = sizeof(*ni6); 111575115Sfenner while (i < siz) { 111675115Sfenner if (i + sizeof(struct in6_addr) + sizeof(int32_t) > siz) 111775115Sfenner break; 111875115Sfenner printf(" %s", getname6(bp + i)); 111975115Sfenner i += sizeof(struct in6_addr); 1120127668Sbms printf("(%d)", (int32_t)EXTRACT_32BITS(bp + i)); 112175115Sfenner i += sizeof(int32_t); 112275115Sfenner } 112375115Sfenner i = ni6->ni_flags; 112475115Sfenner if (!i) 112575115Sfenner break; 112675115Sfenner printf(" [%s%s%s%s%s%s%s]", 112775115Sfenner (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "", 112875115Sfenner (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "", 112975115Sfenner (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "", 113075115Sfenner (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "", 113175115Sfenner (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "", 113275115Sfenner (i & NI_NODEADDR_FLAG_ALL) ? "A" : "", 113375115Sfenner (i & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : ""); 113475115Sfenner break; 113575115Sfenner default: 113675115Sfenner if (needcomma) 113775115Sfenner printf(", "); 113875115Sfenner printf("unknown"); 113975115Sfenner break; 114075115Sfenner } 114175115Sfenner 114275115Sfenner /*(*/ 114375115Sfenner printf(")"); 114475115Sfenner break; 114575115Sfenner } 114656893Sfenner return; 114775115Sfenner 114875115Sfennertrunc: 114975115Sfenner fputs("[|icmp6]", stdout); 115056893Sfenner} 115175115Sfenner 1152127668Sbmsstatic void 1153127668Sbmsicmp6_rrenum_print(const u_char *bp, const u_char *ep) 115475115Sfenner{ 115575115Sfenner struct icmp6_router_renum *rr6; 115675115Sfenner struct icmp6_hdr *dp; 115775115Sfenner size_t siz; 115875115Sfenner const char *cp; 115975115Sfenner struct rr_pco_match *match; 116075115Sfenner struct rr_pco_use *use; 116175115Sfenner char hbuf[NI_MAXHOST]; 116275115Sfenner int n; 116375115Sfenner 1164127668Sbms if (ep < bp) 1165127668Sbms return; 116675115Sfenner dp = (struct icmp6_hdr *)bp; 116775115Sfenner rr6 = (struct icmp6_router_renum *)bp; 116875115Sfenner siz = ep - bp; 116975115Sfenner cp = (const char *)(rr6 + 1); 117075115Sfenner 117175115Sfenner TCHECK(rr6->rr_reserved); 117275115Sfenner switch (rr6->rr_code) { 117375115Sfenner case ICMP6_ROUTER_RENUMBERING_COMMAND: 117475115Sfenner printf("router renum: command"); 117575115Sfenner break; 117675115Sfenner case ICMP6_ROUTER_RENUMBERING_RESULT: 117775115Sfenner printf("router renum: result"); 117875115Sfenner break; 117975115Sfenner case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET: 118075115Sfenner printf("router renum: sequence number reset"); 118175115Sfenner break; 118275115Sfenner default: 118375115Sfenner printf("router renum: code-#%d", rr6->rr_code); 118475115Sfenner break; 118575115Sfenner } 118675115Sfenner 1187127668Sbms printf(", seq=%u", EXTRACT_32BITS(&rr6->rr_seqnum)); 118875115Sfenner 118975115Sfenner if (vflag) { 119075115Sfenner#define F(x, y) ((rr6->rr_flags) & (x) ? (y) : "") 119175115Sfenner printf("["); /*]*/ 119275115Sfenner if (rr6->rr_flags) { 119375115Sfenner printf("%s%s%s%s%s,", F(ICMP6_RR_FLAGS_TEST, "T"), 119475115Sfenner F(ICMP6_RR_FLAGS_REQRESULT, "R"), 119598524Sfenner F(ICMP6_RR_FLAGS_FORCEAPPLY, "A"), 119675115Sfenner F(ICMP6_RR_FLAGS_SPECSITE, "S"), 119775115Sfenner F(ICMP6_RR_FLAGS_PREVDONE, "P")); 119875115Sfenner } 119975115Sfenner printf("seg=%u,", rr6->rr_segnum); 120075115Sfenner printf("maxdelay=%u", rr6->rr_maxdelay); 120175115Sfenner if (rr6->rr_reserved) 1202127668Sbms printf("rsvd=0x%x", EXTRACT_16BITS(&rr6->rr_reserved)); 120375115Sfenner /*[*/ 120475115Sfenner printf("]"); 120575115Sfenner#undef F 120675115Sfenner } 120775115Sfenner 120875115Sfenner if (rr6->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) { 120975115Sfenner match = (struct rr_pco_match *)cp; 121075115Sfenner cp = (const char *)(match + 1); 121175115Sfenner 121275115Sfenner TCHECK(match->rpm_prefix); 121375115Sfenner 121498524Sfenner if (vflag > 1) 121575115Sfenner printf("\n\t"); 121675115Sfenner else 121775115Sfenner printf(" "); 121875115Sfenner printf("match("); /*)*/ 121975115Sfenner switch (match->rpm_code) { 122075115Sfenner case RPM_PCO_ADD: printf("add"); break; 122175115Sfenner case RPM_PCO_CHANGE: printf("change"); break; 122275115Sfenner case RPM_PCO_SETGLOBAL: printf("setglobal"); break; 122375115Sfenner default: printf("#%u", match->rpm_code); break; 122475115Sfenner } 122575115Sfenner 122675115Sfenner if (vflag) { 122775115Sfenner printf(",ord=%u", match->rpm_ordinal); 122875115Sfenner printf(",min=%u", match->rpm_minlen); 122975115Sfenner printf(",max=%u", match->rpm_maxlen); 123075115Sfenner } 123175115Sfenner if (inet_ntop(AF_INET6, &match->rpm_prefix, hbuf, sizeof(hbuf))) 123275115Sfenner printf(",%s/%u", hbuf, match->rpm_matchlen); 123375115Sfenner else 123475115Sfenner printf(",?/%u", match->rpm_matchlen); 123575115Sfenner /*(*/ 123675115Sfenner printf(")"); 123775115Sfenner 123875115Sfenner n = match->rpm_len - 3; 123975115Sfenner if (n % 4) 124075115Sfenner goto trunc; 124175115Sfenner n /= 4; 124275115Sfenner while (n-- > 0) { 124375115Sfenner use = (struct rr_pco_use *)cp; 124475115Sfenner cp = (const char *)(use + 1); 124575115Sfenner 124675115Sfenner TCHECK(use->rpu_prefix); 124775115Sfenner 124898524Sfenner if (vflag > 1) 124975115Sfenner printf("\n\t"); 125075115Sfenner else 125175115Sfenner printf(" "); 125275115Sfenner printf("use("); /*)*/ 125375115Sfenner if (use->rpu_flags) { 125475115Sfenner#define F(x, y) ((use->rpu_flags) & (x) ? (y) : "") 125575115Sfenner printf("%s%s,", 125675115Sfenner F(ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, "V"), 125775115Sfenner F(ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, "P")); 125875115Sfenner#undef F 125975115Sfenner } 126075115Sfenner if (vflag) { 126175115Sfenner printf("mask=0x%x,", use->rpu_ramask); 126275115Sfenner printf("raflags=0x%x,", use->rpu_raflags); 126375115Sfenner if (~use->rpu_vltime == 0) 126475115Sfenner printf("vltime=infty,"); 126575115Sfenner else 126675115Sfenner printf("vltime=%u,", 1267127668Sbms EXTRACT_32BITS(&use->rpu_vltime)); 126875115Sfenner if (~use->rpu_pltime == 0) 126975115Sfenner printf("pltime=infty,"); 127075115Sfenner else 127175115Sfenner printf("pltime=%u,", 1272127668Sbms EXTRACT_32BITS(&use->rpu_pltime)); 127375115Sfenner } 127475115Sfenner if (inet_ntop(AF_INET6, &use->rpu_prefix, hbuf, 127575115Sfenner sizeof(hbuf))) 127675115Sfenner printf("%s/%u/%u", hbuf, use->rpu_uselen, 127775115Sfenner use->rpu_keeplen); 127875115Sfenner else 127975115Sfenner printf("?/%u/%u", use->rpu_uselen, 128075115Sfenner use->rpu_keeplen); 128175115Sfenner /*(*/ 128275115Sfenner printf(")"); 128375115Sfenner } 128475115Sfenner } 128575115Sfenner 128675115Sfenner return; 128775115Sfenner 128875115Sfennertrunc: 128975115Sfenner fputs("[|icmp6]", stdout); 129075115Sfenner} 129175115Sfenner 129256893Sfenner#endif /* INET6 */ 1293