diff options
Diffstat (limited to 'contrib/tcpdump/print-icmp6.c')
-rw-r--r-- | contrib/tcpdump/print-icmp6.c | 259 |
1 files changed, 183 insertions, 76 deletions
diff --git a/contrib/tcpdump/print-icmp6.c b/contrib/tcpdump/print-icmp6.c index 40d71df..88580b2 100644 --- a/contrib/tcpdump/print-icmp6.c +++ b/contrib/tcpdump/print-icmp6.c @@ -20,8 +20,8 @@ */ #ifndef lint -static const char rcsid[] = - "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.56.4.1 2002/05/31 10:08:31 guy Exp $"; +static const char rcsid[] _U_ = + "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.72.2.4 2004/03/24 00:14:09 guy Exp $"; #endif #ifdef HAVE_CONFIG_H @@ -30,27 +30,18 @@ static const char rcsid[] = #ifdef INET6 -#include <ctype.h> - -#include <sys/param.h> -#include <sys/time.h> -#include <sys/types.h> -#include <sys/socket.h> - - -#include <netinet/in.h> - -#include <arpa/inet.h> +#include <tcpdump-stdinc.h> #include <stdio.h> #include <string.h> -#include <netdb.h> #include "ip6.h" #include "icmp6.h" +#include "ipproto.h" #include "interface.h" #include "addrtoname.h" +#include "extract.h" #include "udp.h" #include "ah.h" @@ -58,12 +49,12 @@ static const char rcsid[] = static const char *get_rtpref(u_int); static const char *get_lifetime(u_int32_t); static void print_lladdr(const u_char *, size_t); -void icmp6_opt_print(const u_char *, int); -void mld6_print(const u_char *); -static struct udphdr *get_upperlayer(u_char *, int *); +static void icmp6_opt_print(const u_char *, int); +static void mld6_print(const u_char *); +static struct udphdr *get_upperlayer(u_char *, u_int *); static void dnsname_print(const u_char *, const u_char *); -void icmp6_nodeinfo_print(int, const u_char *, const u_char *); -void icmp6_rrenum_print(int, const u_char *, const u_char *); +static void icmp6_nodeinfo_print(u_int, const u_char *, const u_char *); +static void icmp6_rrenum_print(const u_char *, const u_char *); #ifndef abs #define abs(a) ((0 < (a)) ? (a) : -(a)) @@ -110,8 +101,51 @@ print_lladdr(const u_int8_t *p, size_t l) } } +static int icmp6_cksum(const struct ip6_hdr *ip6, const struct icmp6_hdr *icp, + u_int len) +{ + size_t i; + register const u_int16_t *sp; + u_int32_t sum; + union { + struct { + struct in6_addr ph_src; + struct in6_addr ph_dst; + u_int32_t ph_len; + u_int8_t ph_zero[3]; + u_int8_t ph_nxt; + } ph; + u_int16_t pa[20]; + } phu; + + /* pseudo-header */ + memset(&phu, 0, sizeof(phu)); + phu.ph.ph_src = ip6->ip6_src; + phu.ph.ph_dst = ip6->ip6_dst; + phu.ph.ph_len = htonl(len); + phu.ph.ph_nxt = IPPROTO_ICMPV6; + + sum = 0; + for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++) + sum += phu.pa[i]; + + sp = (const u_int16_t *)icp; + + for (i = 0; i < (len & ~1); i += 2) + sum += *sp++; + + if (len & 1) + sum += htons((*(const u_int8_t *)sp) << 8); + + while (sum > 0xffff) + sum = (sum & 0xffff) + (sum >> 16); + sum = ~sum & 0xffff; + + return (sum); +} + void -icmp6_print(const u_char *bp, const u_char *bp2) +icmp6_print(const u_char *bp, u_int length, const u_char *bp2, int fragmented) { const struct icmp6_hdr *dp; const struct ip6_hdr *ip; @@ -121,7 +155,7 @@ icmp6_print(const u_char *bp, const u_char *bp2) int dport; const u_char *ep; char buf[256]; - int icmp6len, prot; + u_int prot; dp = (struct icmp6_hdr *)bp; ip = (struct ip6_hdr *)bp2; @@ -129,13 +163,21 @@ icmp6_print(const u_char *bp, const u_char *bp2) str = buf; /* 'ep' points to the end of available data. */ ep = snapend; - if (ip->ip6_plen) - icmp6len = (ntohs(ip->ip6_plen) + sizeof(struct ip6_hdr) - - (bp - bp2)); - else /* XXX: jumbo payload case... */ - icmp6len = snapend - bp; - TCHECK(dp->icmp6_code); + TCHECK(dp->icmp6_cksum); + + if (vflag && !fragmented) { + int sum = dp->icmp6_cksum; + + if (TTEST2(bp[0], length)) { + sum = icmp6_cksum(ip, dp, length); + if (sum != 0) + (void)printf("[bad icmp6 cksum %x!] ", sum); + else + (void)printf("[icmp6 sum ok] "); + } + } + switch (dp->icmp6_type) { case ICMP6_DST_UNREACH: TCHECK(oip->ip6_dst); @@ -162,7 +204,7 @@ icmp6_print(const u_char *bp, const u_char *bp2) == NULL) goto trunc; - dport = ntohs(ouh->uh_dport); + dport = EXTRACT_16BITS(&ouh->uh_dport); switch (prot) { case IPPROTO_TCP: printf("icmp6: %s tcp port %s unreachable", @@ -190,7 +232,7 @@ icmp6_print(const u_char *bp, const u_char *bp2) break; case ICMP6_PACKET_TOO_BIG: TCHECK(dp->icmp6_mtu); - printf("icmp6: too big %u", (u_int32_t)ntohl(dp->icmp6_mtu)); + printf("icmp6: too big %u", EXTRACT_32BITS(&dp->icmp6_mtu)); break; case ICMP6_TIME_EXCEEDED: TCHECK(oip->ip6_dst); @@ -213,15 +255,15 @@ icmp6_print(const u_char *bp, const u_char *bp2) switch (dp->icmp6_code) { case ICMP6_PARAMPROB_HEADER: printf("icmp6: parameter problem errorneous - octet %u", - (u_int32_t)ntohl(dp->icmp6_pptr)); + EXTRACT_32BITS(&dp->icmp6_pptr)); break; case ICMP6_PARAMPROB_NEXTHEADER: printf("icmp6: parameter problem next header - octet %u", - (u_int32_t)ntohl(dp->icmp6_pptr)); + EXTRACT_32BITS(&dp->icmp6_pptr)); break; case ICMP6_PARAMPROB_OPTION: printf("icmp6: parameter problem option - octet %u", - (u_int32_t)ntohl(dp->icmp6_pptr)); + EXTRACT_32BITS(&dp->icmp6_pptr)); break; default: printf("icmp6: parameter problem code-#%d", @@ -230,10 +272,12 @@ icmp6_print(const u_char *bp, const u_char *bp2) } break; case ICMP6_ECHO_REQUEST: - printf("icmp6: echo request"); - break; case ICMP6_ECHO_REPLY: - printf("icmp6: echo reply"); + TCHECK(dp->icmp6_seq); + printf("icmp6: echo %s seq %u", + dp->icmp6_type == ICMP6_ECHO_REQUEST ? + "request" : "reply", + EXTRACT_16BITS(&dp->icmp6_seq)); break; case ICMP6_MEMBERSHIP_QUERY: printf("icmp6: multicast listener query "); @@ -252,7 +296,7 @@ icmp6_print(const u_char *bp, const u_char *bp2) if (vflag) { #define RTSOLLEN 8 icmp6_opt_print((const u_char *)dp + RTSOLLEN, - icmp6len - RTSOLLEN); + length - RTSOLLEN); } break; case ND_ROUTER_ADVERT: @@ -277,14 +321,14 @@ icmp6_print(const u_char *bp, const u_char *bp2) printf("pref=%s, ", get_rtpref(p->nd_ra_flags_reserved)); - printf("router_ltime=%d, ", ntohs(p->nd_ra_router_lifetime)); + printf("router_ltime=%d, ", EXTRACT_16BITS(&p->nd_ra_router_lifetime)); printf("reachable_time=%u, ", - (u_int32_t)ntohl(p->nd_ra_reachable)); + EXTRACT_32BITS(&p->nd_ra_reachable)); printf("retrans_time=%u)", - (u_int32_t)ntohl(p->nd_ra_retransmit)); + EXTRACT_32BITS(&p->nd_ra_retransmit)); #define RTADVLEN 16 icmp6_opt_print((const u_char *)dp + RTADVLEN, - icmp6len - RTADVLEN); + length - RTADVLEN); } break; case ND_NEIGHBOR_SOLICIT: @@ -297,7 +341,7 @@ icmp6_print(const u_char *bp, const u_char *bp2) if (vflag) { #define NDSOLLEN 24 icmp6_opt_print((const u_char *)dp + NDSOLLEN, - icmp6len - NDSOLLEN); + length - NDSOLLEN); } } break; @@ -329,7 +373,7 @@ icmp6_print(const u_char *bp, const u_char *bp2) } #define NDADVLEN 24 icmp6_opt_print((const u_char *)dp + NDADVLEN, - icmp6len - NDADVLEN); + length - NDADVLEN); #undef NDADVLEN } } @@ -339,22 +383,71 @@ icmp6_print(const u_char *bp, const u_char *bp2) TCHECK(RDR(dp)->nd_rd_dst); printf("icmp6: redirect %s", getname6((const u_char *)&RDR(dp)->nd_rd_dst)); + TCHECK(RDR(dp)->nd_rd_target); printf(" to %s", getname6((const u_char*)&RDR(dp)->nd_rd_target)); #define REDIRECTLEN 40 if (vflag) { icmp6_opt_print((const u_char *)dp + REDIRECTLEN, - icmp6len - REDIRECTLEN); + length - REDIRECTLEN); } break; #undef REDIRECTLEN #undef RDR case ICMP6_ROUTER_RENUMBERING: - icmp6_rrenum_print(icmp6len, bp, ep); + icmp6_rrenum_print(bp, ep); break; case ICMP6_NI_QUERY: case ICMP6_NI_REPLY: - icmp6_nodeinfo_print(icmp6len, bp, ep); + icmp6_nodeinfo_print(length, bp, ep); + break; + case ICMP6_HADISCOV_REQUEST: + printf("icmp6: ha discovery request"); + if (vflag) { + TCHECK(dp->icmp6_data16[0]); + printf("(id=%d)", EXTRACT_16BITS(&dp->icmp6_data16[0])); + } + break; + case ICMP6_HADISCOV_REPLY: + printf("icmp6: ha discovery reply"); + if (vflag) { + struct in6_addr *in6; + u_char *cp; + + TCHECK(dp->icmp6_data16[0]); + printf("(id=%d", EXTRACT_16BITS(&dp->icmp6_data16[0])); + cp = (u_char *)dp + length; + in6 = (struct in6_addr *)(dp + 1); + for (; (u_char *)in6 < cp; in6++) { + TCHECK(*in6); + printf(", %s", ip6addr_string(in6)); + } + printf(")"); + } + break; + case ICMP6_MOBILEPREFIX_SOLICIT: + printf("icmp6: mobile router solicitation"); + if (vflag) { + TCHECK(dp->icmp6_data16[0]); + printf("(id=%d)", EXTRACT_16BITS(&dp->icmp6_data16[0])); + } + break; + case ICMP6_MOBILEPREFIX_ADVERT: + printf("icmp6: mobile router advertisement"); + if (vflag) { + TCHECK(dp->icmp6_data16[0]); + printf("(id=%d", EXTRACT_16BITS(&dp->icmp6_data16[0])); + if (dp->icmp6_data16[1] & 0xc0) + printf(" "); + if (dp->icmp6_data16[1] & 0x80) + printf("M"); + if (dp->icmp6_data16[1] & 0x40) + printf("O"); + printf(")"); +#define MPADVLEN 8 + icmp6_opt_print((const u_char *)dp + MPADVLEN, + length - MPADVLEN); + } break; default: printf("icmp6: type-#%d", dp->icmp6_type); @@ -366,7 +459,7 @@ trunc: } static struct udphdr * -get_upperlayer(u_char *bp, int *prot) +get_upperlayer(u_char *bp, u_int *prot) { const u_char *ep; struct ip6_hdr *ip6 = (struct ip6_hdr *)bp; @@ -374,12 +467,13 @@ get_upperlayer(u_char *bp, int *prot) struct ip6_hbh *hbh; struct ip6_frag *fragh; struct ah *ah; - int nh, hlen; + u_int nh; + int hlen; /* 'ep' points to the end of available data. */ ep = snapend; - if (TTEST(ip6->ip6_nxt) == 0) + if (!TTEST(ip6->ip6_nxt)) return NULL; nh = ip6->ip6_nxt; @@ -404,7 +498,7 @@ get_upperlayer(u_char *bp, int *prot) case IPPROTO_DSTOPTS: case IPPROTO_ROUTING: hbh = (struct ip6_hbh *)bp; - if (TTEST(hbh->ip6h_len) == 0) + if (!TTEST(hbh->ip6h_len)) return(NULL); nh = hbh->ip6h_nxt; hlen = (hbh->ip6h_len + 1) << 3; @@ -412,10 +506,10 @@ get_upperlayer(u_char *bp, int *prot) case IPPROTO_FRAGMENT: /* this should be odd, but try anyway */ fragh = (struct ip6_frag *)bp; - if (TTEST(fragh->ip6f_offlg) == 0) + if (!TTEST(fragh->ip6f_offlg)) return(NULL); /* fragments with non-zero offset are meaningless */ - if ((fragh->ip6f_offlg & IP6F_OFF_MASK) != 0) + if ((EXTRACT_16BITS(&fragh->ip6f_offlg) & IP6F_OFF_MASK) != 0) return(NULL); nh = fragh->ip6f_nxt; hlen = sizeof(struct ip6_frag); @@ -423,7 +517,7 @@ get_upperlayer(u_char *bp, int *prot) case IPPROTO_AH: ah = (struct ah *)bp; - if (TTEST(ah->ah_len) == 0) + if (!TTEST(ah->ah_len)) return(NULL); nh = ah->ah_nxt; hlen = (ah->ah_len + 2) << 2; @@ -438,7 +532,7 @@ get_upperlayer(u_char *bp, int *prot) return(NULL); /* should be notreached, though */ } -void +static void icmp6_opt_print(const u_char *bp, int resid) { const struct nd_opt_hdr *op; @@ -447,6 +541,7 @@ icmp6_opt_print(const u_char *bp, int resid) const struct icmp6_opts_redirect *opr; const struct nd_opt_mtu *opm; const struct nd_opt_advinterval *opa; + const struct nd_opt_homeagent_info *oph; const struct nd_opt_route_info *opri; const u_char *cp, *ep; struct in6_addr in6, *in6p; @@ -505,9 +600,9 @@ icmp6_opt_print(const u_char *bp, int resid) if (opp->nd_opt_pi_flags_reserved) printf(" "); printf("valid_ltime=%s,", - get_lifetime((u_int32_t)ntohl(opp->nd_opt_pi_valid_time))); + get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_valid_time))); printf("preferred_ltime=%s,", - get_lifetime((u_int32_t)ntohl(opp->nd_opt_pi_preferred_time))); + get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_preferred_time))); printf("prefix=%s/%d", ip6addr_string(&opp->nd_opt_pi_prefix), opp->nd_opt_pi_prefix_len); @@ -531,7 +626,7 @@ icmp6_opt_print(const u_char *bp, int resid) printf(")"); break; } - printf(" mtu=%u", (u_int32_t)ntohl(opm->nd_opt_mtu_mtu)); + printf(" mtu=%u", EXTRACT_32BITS(&opm->nd_opt_mtu_mtu)); if (opm->nd_opt_mtu_len != 1) printf("!"); printf(")"); @@ -541,10 +636,18 @@ icmp6_opt_print(const u_char *bp, int resid) TCHECK(opa->nd_opt_adv_interval); printf("(advint:"); /*)*/ printf(" advint=%u", - (u_int32_t)ntohl(opa->nd_opt_adv_interval)); + EXTRACT_32BITS(&opa->nd_opt_adv_interval)); /*(*/ printf(")"); - break; + break; + case ND_OPT_HOMEAGENT_INFO: + oph = (struct nd_opt_homeagent_info *)op; + TCHECK(oph->nd_opt_hai_lifetime); + printf("(ha info:"); /*)*/ + printf(" pref=%d", EXTRACT_16BITS(&oph->nd_opt_hai_preference)); + printf(", lifetime=%u", EXTRACT_16BITS(&oph->nd_opt_hai_lifetime)); + printf(")"); + break; case ND_OPT_ROUTE_INFO: opri = (struct nd_opt_route_info *)op; TCHECK(opri->nd_opt_rti_lifetime); @@ -569,7 +672,7 @@ icmp6_opt_print(const u_char *bp, int resid) opri->nd_opt_rti_prefixlen); printf(", pref=%s", get_rtpref(opri->nd_opt_rti_flags)); printf(", lifetime=%s", - get_lifetime((u_int32_t)ntohl(opri->nd_opt_rti_lifetime))); + get_lifetime(EXTRACT_32BITS(&opri->nd_opt_rti_lifetime))); /*(*/ printf(")"); break; @@ -590,7 +693,7 @@ icmp6_opt_print(const u_char *bp, int resid) #undef ECHECK } -void +static void mld6_print(const u_char *bp) { struct mld6_hdr *mp = (struct mld6_hdr *)bp; @@ -602,7 +705,7 @@ mld6_print(const u_char *bp) if ((u_char *)mp + sizeof(*mp) > ep) return; - printf("max resp delay: %d ", ntohs(mp->mld6_maxdelay)); + printf("max resp delay: %d ", EXTRACT_16BITS(&mp->mld6_maxdelay)); printf("addr: %s", ip6addr_string(&mp->mld6_addr)); } @@ -642,15 +745,17 @@ dnsname_print(const u_char *cp, const u_char *ep) printf("\""); } -void -icmp6_nodeinfo_print(int icmp6len, const u_char *bp, const u_char *ep) +static void +icmp6_nodeinfo_print(u_int icmp6len, const u_char *bp, const u_char *ep) { struct icmp6_nodeinfo *ni6; struct icmp6_hdr *dp; const u_char *cp; - int siz, i; + size_t siz, i; int needcomma; + if (ep < bp) + return; dp = (struct icmp6_hdr *)bp; ni6 = (struct icmp6_nodeinfo *)bp; siz = ep - bp; @@ -667,13 +772,13 @@ icmp6_nodeinfo_print(int icmp6len, const u_char *bp, const u_char *ep) TCHECK2(*dp, sizeof(*ni6)); ni6 = (struct icmp6_nodeinfo *)dp; printf(" ("); /*)*/ - switch (ntohs(ni6->ni_qtype)) { + switch (EXTRACT_16BITS(&ni6->ni_qtype)) { case NI_QTYPE_NOOP: printf("noop"); break; case NI_QTYPE_SUPTYPES: printf("supported qtypes"); - i = ntohs(ni6->ni_flags); + i = EXTRACT_16BITS(&ni6->ni_flags); if (i) printf(" [%s]", (i & 0x01) ? "C" : ""); break; @@ -809,7 +914,7 @@ icmp6_nodeinfo_print(int icmp6len, const u_char *bp, const u_char *ep) break; } - switch (ntohs(ni6->ni_qtype)) { + switch (EXTRACT_16BITS(&ni6->ni_qtype)) { case NI_QTYPE_NOOP: if (needcomma) printf(", "); @@ -822,7 +927,7 @@ icmp6_nodeinfo_print(int icmp6len, const u_char *bp, const u_char *ep) if (needcomma) printf(", "); printf("supported qtypes"); - i = ntohs(ni6->ni_flags); + i = EXTRACT_16BITS(&ni6->ni_flags); if (i) printf(" [%s]", (i & 0x01) ? "C" : ""); break; @@ -844,7 +949,7 @@ icmp6_nodeinfo_print(int icmp6len, const u_char *bp, const u_char *ep) printf("\""); } else dnsname_print(cp, ep); - if ((ntohs(ni6->ni_flags) & 0x01) != 0) + if ((EXTRACT_16BITS(&ni6->ni_flags) & 0x01) != 0) printf(" [TTL=%u]", *(u_int32_t *)(ni6 + 1)); break; case NI_QTYPE_NODEADDR: @@ -857,7 +962,7 @@ icmp6_nodeinfo_print(int icmp6len, const u_char *bp, const u_char *ep) break; printf(" %s", getname6(bp + i)); i += sizeof(struct in6_addr); - printf("(%d)", (int32_t)ntohl(*(int32_t *)(bp + i))); + printf("(%d)", (int32_t)EXTRACT_32BITS(bp + i)); i += sizeof(int32_t); } i = ni6->ni_flags; @@ -889,8 +994,8 @@ trunc: fputs("[|icmp6]", stdout); } -void -icmp6_rrenum_print(int icmp6len, const u_char *bp, const u_char *ep) +static void +icmp6_rrenum_print(const u_char *bp, const u_char *ep) { struct icmp6_router_renum *rr6; struct icmp6_hdr *dp; @@ -901,6 +1006,8 @@ icmp6_rrenum_print(int icmp6len, const u_char *bp, const u_char *ep) char hbuf[NI_MAXHOST]; int n; + if (ep < bp) + return; dp = (struct icmp6_hdr *)bp; rr6 = (struct icmp6_router_renum *)bp; siz = ep - bp; @@ -922,7 +1029,7 @@ icmp6_rrenum_print(int icmp6len, const u_char *bp, const u_char *ep) break; } - printf(", seq=%u", (u_int32_t)ntohl(rr6->rr_seqnum)); + printf(", seq=%u", EXTRACT_32BITS(&rr6->rr_seqnum)); if (vflag) { #define F(x, y) ((rr6->rr_flags) & (x) ? (y) : "") @@ -937,7 +1044,7 @@ icmp6_rrenum_print(int icmp6len, const u_char *bp, const u_char *ep) printf("seg=%u,", rr6->rr_segnum); printf("maxdelay=%u", rr6->rr_maxdelay); if (rr6->rr_reserved) - printf("rsvd=0x%x", (u_int16_t)ntohs(rr6->rr_reserved)); + printf("rsvd=0x%x", EXTRACT_16BITS(&rr6->rr_reserved)); /*[*/ printf("]"); #undef F @@ -1002,12 +1109,12 @@ icmp6_rrenum_print(int icmp6len, const u_char *bp, const u_char *ep) printf("vltime=infty,"); else printf("vltime=%u,", - (u_int32_t)ntohl(use->rpu_vltime)); + EXTRACT_32BITS(&use->rpu_vltime)); if (~use->rpu_pltime == 0) printf("pltime=infty,"); else printf("pltime=%u,", - (u_int32_t)ntohl(use->rpu_pltime)); + EXTRACT_32BITS(&use->rpu_pltime)); } if (inet_ntop(AF_INET6, &use->rpu_prefix, hbuf, sizeof(hbuf))) |