X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/8863fc0e5d6cc6bf64875fa4156ddfd54c6cf9c9..refs/pull/482/head:/print-pim.c diff --git a/print-pim.c b/print-pim.c index 9ac9eeb6..ce4b2afd 100644 --- a/print-pim.c +++ b/print-pim.c @@ -19,18 +19,40 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ -#define NETDISSECT_REWORKED #ifdef HAVE_CONFIG_H #include "config.h" #endif -#include +#include -#include "interface.h" +#include "netdissect.h" #include "addrtoname.h" #include "extract.h" #include "ip.h" +#include "ip6.h" +#include "ipproto.h" + +#define PIMV1_TYPE_QUERY 0 +#define PIMV1_TYPE_REGISTER 1 +#define PIMV1_TYPE_REGISTER_STOP 2 +#define PIMV1_TYPE_JOIN_PRUNE 3 +#define PIMV1_TYPE_RP_REACHABILITY 4 +#define PIMV1_TYPE_ASSERT 5 +#define PIMV1_TYPE_GRAFT 6 +#define PIMV1_TYPE_GRAFT_ACK 7 + +static const struct tok pimv1_type_str[] = { + { PIMV1_TYPE_QUERY, "Query" }, + { PIMV1_TYPE_REGISTER, "Register" }, + { PIMV1_TYPE_REGISTER_STOP, "Register-Stop" }, + { PIMV1_TYPE_JOIN_PRUNE, "Join/Prune" }, + { PIMV1_TYPE_RP_REACHABILITY, "RP-reachable" }, + { PIMV1_TYPE_ASSERT, "Assert" }, + { PIMV1_TYPE_GRAFT, "Graft" }, + { PIMV1_TYPE_GRAFT_ACK, "Graft-ACK" }, + { 0, NULL } +}; #define PIMV2_TYPE_HELLO 0 #define PIMV2_TYPE_REGISTER 1 @@ -42,6 +64,8 @@ #define PIMV2_TYPE_GRAFT_ACK 7 #define PIMV2_TYPE_CANDIDATE_RP 8 #define PIMV2_TYPE_PRUNE_REFRESH 9 +#define PIMV2_TYPE_DF_ELECTION 10 +#define PIMV2_TYPE_ECMP_REDIRECT 11 static const struct tok pimv2_type_values[] = { { PIMV2_TYPE_HELLO, "Hello" }, @@ -54,6 +78,8 @@ static const struct tok pimv2_type_values[] = { { PIMV2_TYPE_GRAFT_ACK, "Graft Acknowledgement" }, { PIMV2_TYPE_CANDIDATE_RP, "Candidate RP Advertisement" }, { PIMV2_TYPE_PRUNE_REFRESH, "Prune Refresh" }, + { PIMV2_TYPE_DF_ELECTION, "DF Election" }, + { PIMV2_TYPE_ECMP_REDIRECT, "ECMP Redirect" }, { 0, NULL} }; @@ -96,7 +122,7 @@ static const struct tok pimv2_register_flag_values[] = { */ struct pim { - u_int8_t pim_typever; + uint8_t pim_typever; /* upper 4bit: PIM version number; 2 for PIMv2 */ /* lower 4bit: the PIM message type, currently they are: * Hello, Register, Register-Stop, Join/Prune, @@ -109,7 +135,7 @@ struct pim { u_short pim_cksum; /* IP style check sum */ }; -static void pimv2_print(netdissect_options *, register const u_char *bp, register u_int len, u_int cksum); +static void pimv2_print(netdissect_options *, register const u_char *bp, register u_int len, const u_char *); static void pimv1_join_prune_print(netdissect_options *ndo, @@ -123,17 +149,17 @@ pimv1_join_prune_print(netdissect_options *ndo, ((njoin = EXTRACT_16BITS(&bp[20])) + EXTRACT_16BITS(&bp[22])) == 1) { int hold; - ND_PRINT((ndo, " RPF %s ", ipaddr_string(bp))); + ND_PRINT((ndo, " RPF %s ", ipaddr_string(ndo, bp))); hold = EXTRACT_16BITS(&bp[6]); if (hold != 180) { ND_PRINT((ndo, "Hold ")); relts_print(ndo, hold); } ND_PRINT((ndo, "%s (%s/%d, %s", njoin ? "Join" : "Prune", - ipaddr_string(&bp[26]), bp[25] & 0x3f, - ipaddr_string(&bp[12]))); + ipaddr_string(ndo, &bp[26]), bp[25] & 0x3f, + ipaddr_string(ndo, &bp[12]))); if (EXTRACT_32BITS(&bp[16]) != 0xffffffff) - ND_PRINT((ndo, "/%s", ipaddr_string(&bp[16]))); + ND_PRINT((ndo, "/%s", ipaddr_string(ndo, &bp[16]))); ND_PRINT((ndo, ") %s%s %s", (bp[24] & 0x01) ? "Sparse" : "Dense", (bp[25] & 0x80) ? " WC" : "", @@ -144,7 +170,7 @@ pimv1_join_prune_print(netdissect_options *ndo, ND_TCHECK2(bp[0], sizeof(struct in_addr)); if (ndo->ndo_vflag > 1) ND_PRINT((ndo, "\n")); - ND_PRINT((ndo, " Upstream Nbr: %s", ipaddr_string(bp))); + ND_PRINT((ndo, " Upstream Nbr: %s", ipaddr_string(ndo, bp))); ND_TCHECK2(bp[6], 2); if (ndo->ndo_vflag > 1) ND_PRINT((ndo, "\n")); @@ -165,10 +191,10 @@ pimv1_join_prune_print(netdissect_options *ndo, * mask length "maddrlen"? */ ND_TCHECK2(bp[0], sizeof(struct in_addr)); - ND_PRINT((ndo, "\n\tGroup: %s", ipaddr_string(bp))); + ND_PRINT((ndo, "\n\tGroup: %s", ipaddr_string(ndo, bp))); ND_TCHECK2(bp[4], sizeof(struct in_addr)); if (EXTRACT_32BITS(&bp[4]) != 0xffffffff) - ND_PRINT((ndo, "/%s", ipaddr_string(&bp[4]))); + ND_PRINT((ndo, "/%s", ipaddr_string(ndo, &bp[4]))); ND_TCHECK2(bp[8], 4); njoin = EXTRACT_16BITS(&bp[8]); nprune = EXTRACT_16BITS(&bp[10]); @@ -187,7 +213,7 @@ pimv1_join_prune_print(netdissect_options *ndo, (bp[0] & 0x01) ? "Sparse " : "Dense ", (bp[1] & 0x80) ? "WC " : "", (bp[1] & 0x40) ? "RP " : "SPT ", - ipaddr_string(&bp[2]), bp[1] & 0x3f)); + ipaddr_string(ndo, &bp[2]), bp[1] & 0x3f)); bp += 6; len -= 6; } @@ -212,9 +238,9 @@ pimv1_print(netdissect_options *ndo, ND_TCHECK(bp[1]); type = bp[1]; + ND_PRINT((ndo, " %s", tok2str(pimv1_type_str, "[type %u]", type))); switch (type) { - case 0: - ND_PRINT((ndo, " Query")); + case PIMV1_TYPE_QUERY: if (ND_TTEST(bp[8])) { switch (bp[8] >> 4) { case 0: @@ -239,63 +265,44 @@ pimv1_print(netdissect_options *ndo, } break; - case 1: - ND_PRINT((ndo, " Register")); + case PIMV1_TYPE_REGISTER: ND_TCHECK2(bp[8], 20); /* ip header */ - ND_PRINT((ndo, " for %s > %s", ipaddr_string(&bp[20]), - ipaddr_string(&bp[24]))); + ND_PRINT((ndo, " for %s > %s", ipaddr_string(ndo, &bp[20]), + ipaddr_string(ndo, &bp[24]))); break; - case 2: - ND_PRINT((ndo, " Register-Stop")); + case PIMV1_TYPE_REGISTER_STOP: ND_TCHECK2(bp[12], sizeof(struct in_addr)); - ND_PRINT((ndo, " for %s > %s", ipaddr_string(&bp[8]), - ipaddr_string(&bp[12]))); - break; - case 3: - ND_PRINT((ndo, " Join/Prune")); - if (ndo->ndo_vflag) - pimv1_join_prune_print(ndo, &bp[8], len - 8); + ND_PRINT((ndo, " for %s > %s", ipaddr_string(ndo, &bp[8]), + ipaddr_string(ndo, &bp[12]))); break; - case 4: - ND_PRINT((ndo, " RP-reachable")); + case PIMV1_TYPE_RP_REACHABILITY: if (ndo->ndo_vflag) { ND_TCHECK2(bp[22], 2); - ND_PRINT((ndo, " group %s", ipaddr_string(&bp[8]))); + ND_PRINT((ndo, " group %s", ipaddr_string(ndo, &bp[8]))); if (EXTRACT_32BITS(&bp[12]) != 0xffffffff) - ND_PRINT((ndo, "/%s", ipaddr_string(&bp[12]))); - ND_PRINT((ndo, " RP %s hold ", ipaddr_string(&bp[16]))); + ND_PRINT((ndo, "/%s", ipaddr_string(ndo, &bp[12]))); + ND_PRINT((ndo, " RP %s hold ", ipaddr_string(ndo, &bp[16]))); relts_print(ndo, EXTRACT_16BITS(&bp[22])); } break; - case 5: - ND_PRINT((ndo, " Assert")); + case PIMV1_TYPE_ASSERT: ND_TCHECK2(bp[16], sizeof(struct in_addr)); - ND_PRINT((ndo, " for %s > %s", ipaddr_string(&bp[16]), - ipaddr_string(&bp[8]))); + ND_PRINT((ndo, " for %s > %s", ipaddr_string(ndo, &bp[16]), + ipaddr_string(ndo, &bp[8]))); if (EXTRACT_32BITS(&bp[12]) != 0xffffffff) - ND_PRINT((ndo, "/%s", ipaddr_string(&bp[12]))); + ND_PRINT((ndo, "/%s", ipaddr_string(ndo, &bp[12]))); ND_TCHECK2(bp[24], 4); ND_PRINT((ndo, " %s pref %d metric %d", (bp[20] & 0x80) ? "RP-tree" : "SPT", EXTRACT_32BITS(&bp[20]) & 0x7fffffff, EXTRACT_32BITS(&bp[24]))); break; - case 6: - ND_PRINT((ndo, " Graft")); + case PIMV1_TYPE_JOIN_PRUNE: + case PIMV1_TYPE_GRAFT: + case PIMV1_TYPE_GRAFT_ACK: if (ndo->ndo_vflag) pimv1_join_prune_print(ndo, &bp[8], len - 8); break; - case 7: - ND_PRINT((ndo, " Graft-ACK")); - if (ndo->ndo_vflag) - pimv1_join_prune_print(ndo, &bp[8], len - 8); - break; - case 8: - ND_PRINT((ndo, " Mode")); - break; - default: - ND_PRINT((ndo, " [type %d]", type)); - break; } if ((bp[4] >> 4) != 1) ND_PRINT((ndo, " [v%d]", bp[4] >> 4)); @@ -368,7 +375,7 @@ cisco_autorp_print(netdissect_options *ndo, char s; ND_TCHECK2(bp[0], 4); - ND_PRINT((ndo, " RP %s", ipaddr_string(bp))); + ND_PRINT((ndo, " RP %s", ipaddr_string(ndo, bp))); ND_TCHECK(bp[4]); switch (bp[4] & 0x3) { case 0: ND_PRINT((ndo, " PIMv?")); @@ -389,7 +396,7 @@ cisco_autorp_print(netdissect_options *ndo, for (; nentries; nentries--) { ND_TCHECK2(bp[0], 6); ND_PRINT((ndo, "%c%s%s/%d", s, bp[0] & 1 ? "!" : "", - ipaddr_string(&bp[2]), bp[1])); + ipaddr_string(ndo, &bp[2]), bp[1])); if (bp[0] & 0x02) { ND_PRINT((ndo, " bidir")); } @@ -409,10 +416,10 @@ trunc: void pim_print(netdissect_options *ndo, - register const u_char *bp, register u_int len, u_int cksum) + register const u_char *bp, register u_int len, const u_char *bp2) { register const u_char *ep; - register struct pim *pim = (struct pim *)bp; + register const struct pim *pim = (const struct pim *)bp; ep = (const u_char *)ndo->ndo_snapend; if (bp >= ep) @@ -434,7 +441,7 @@ pim_print(netdissect_options *ndo, PIM_VER(pim->pim_typever), len, tok2str(pimv2_type_values,"Unknown Type",PIM_TYPE(pim->pim_typever)))); - pimv2_print(ndo, bp, len, cksum); + pimv2_print(ndo, bp, len, bp2); } break; default: @@ -528,12 +535,10 @@ pimv2_addr_print(netdissect_options *ndo, af = AF_INET; len = sizeof(struct in_addr); break; -#ifdef INET6 case 2: af = AF_INET6; len = sizeof(struct in6_addr); break; -#endif default: return -1; } @@ -545,11 +550,9 @@ pimv2_addr_print(netdissect_options *ndo, case sizeof(struct in_addr): af = AF_INET; break; -#ifdef INET6 case sizeof(struct in6_addr): af = AF_INET6; break; -#endif default: return -1; break; @@ -564,34 +567,30 @@ pimv2_addr_print(netdissect_options *ndo, ND_TCHECK2(bp[0], len); if (af == AF_INET) { if (!silent) - ND_PRINT((ndo, "%s", ipaddr_string(bp))); + ND_PRINT((ndo, "%s", ipaddr_string(ndo, bp))); } -#ifdef INET6 else if (af == AF_INET6) { if (!silent) - ND_PRINT((ndo, "%s", ip6addr_string(bp))); + ND_PRINT((ndo, "%s", ip6addr_string(ndo, bp))); } -#endif return hdrlen + len; case pimv2_group: case pimv2_source: ND_TCHECK2(bp[0], len + 2); if (af == AF_INET) { if (!silent) { - ND_PRINT((ndo, "%s", ipaddr_string(bp + 2))); + ND_PRINT((ndo, "%s", ipaddr_string(ndo, bp + 2))); if (bp[1] != 32) ND_PRINT((ndo, "/%u", bp[1])); } } -#ifdef INET6 else if (af == AF_INET6) { if (!silent) { - ND_PRINT((ndo, "%s", ip6addr_string(bp + 2))); + ND_PRINT((ndo, "%s", ip6addr_string(ndo, bp + 2))); if (bp[1] != 128) ND_PRINT((ndo, "/%u", bp[1])); } } -#endif if (bp[0] && !silent) { if (at == pimv2_group) { ND_PRINT((ndo, "(0x%02x)", bp[0])); @@ -614,13 +613,45 @@ trunc: return -1; } +enum checksum_status { + CORRECT, + INCORRECT, + UNVERIFIED +}; + +static enum checksum_status +pimv2_check_checksum(const u_char *bp, const u_char *bp2, u_int len) +{ + const struct ip *ip; + u_int cksum; + + ip = (const struct ip *)bp2; + if (IP_V(ip) == 4) { + struct cksum_vec vec[1]; + + vec[0].ptr = bp; + vec[0].len = len; + cksum = in_cksum(vec, 1); + return (cksum ? INCORRECT : CORRECT); + } else if (IP_V(ip) == 6) { + const struct ip6_hdr *ip6; + + ip6 = (const struct ip6_hdr *)bp2; + cksum = nextproto6_cksum(ip6, bp, len, len, IPPROTO_PIM); + return (cksum ? INCORRECT : CORRECT); + } else { + return (UNVERIFIED); + } +} + static void pimv2_print(netdissect_options *ndo, - register const u_char *bp, register u_int len, u_int cksum) + register const u_char *bp, register u_int len, const u_char *bp2) { register const u_char *ep; - register struct pim *pim = (struct pim *)bp; + register const struct pim *pim = (const struct pim *)bp; int advance; + enum checksum_status cksum_status; ep = (const u_char *)ndo->ndo_snapend; if (bp >= ep) @@ -636,13 +667,47 @@ pimv2_print(netdissect_options *ndo, if (EXTRACT_16BITS(&pim->pim_cksum) == 0) { ND_PRINT((ndo, "(unverified)")); } else { - ND_PRINT((ndo, "(%scorrect)", ND_TTEST2(bp[0], len) && cksum ? "in" : "" )); + if (PIM_TYPE(pim->pim_typever) == PIMV2_TYPE_REGISTER) { + /* + * The checksum only covers the packet header, + * not the encapsulated packet. + */ + cksum_status = pimv2_check_checksum(bp, bp2, 8); + if (cksum_status == INCORRECT) { + /* + * To quote RFC 4601, "For interoperability + * reasons, a message carrying a checksum + * calculated over the entire PIM Register + * message should also be accepted." + */ + cksum_status = pimv2_check_checksum(bp, bp2, len); + } + } else { + /* + * The checksum covers the entire packet. + */ + cksum_status = pimv2_check_checksum(bp, bp2, len); + } + switch (cksum_status) { + + case CORRECT: + ND_PRINT((ndo, "(correct)")); + break; + + case INCORRECT: + ND_PRINT((ndo, "(incorrect)")); + break; + + case UNVERIFIED: + ND_PRINT((ndo, "(unverified)")); + break; + } } switch (PIM_TYPE(pim->pim_typever)) { case PIMV2_TYPE_HELLO: { - u_int16_t otype, olen; + uint16_t otype, olen; bp += 4; while (bp < ep) { ND_TCHECK2(bp[0], 4); @@ -665,7 +730,7 @@ pimv2_print(netdissect_options *ndo, ND_PRINT((ndo, "ERROR: Option Length != 4 Bytes (%u)", olen)); } else { char t_bit; - u_int16_t lan_delay, override_interval; + uint16_t lan_delay, override_interval; lan_delay = EXTRACT_16BITS(bp); override_interval = EXTRACT_16BITS(bp+2); t_bit = (lan_delay & 0x8000)? 1 : 0; @@ -713,8 +778,6 @@ pimv2_print(netdissect_options *ndo, if (ndo->ndo_vflag > 1) { const u_char *ptr = bp; while (ptr < (bp+olen)) { - int advance; - ND_PRINT((ndo, "\n\t ")); advance = pimv2_addr_print(ndo, ptr, pimv2_unicast, 0); if (advance < 0) { @@ -740,10 +803,9 @@ pimv2_print(netdissect_options *ndo, case PIMV2_TYPE_REGISTER: { - struct ip *ip; + const struct ip *ip; - if (!ND_TTEST2(*(bp+4), PIMV2_REGISTER_FLAG_LEN)) - goto trunc; + ND_TCHECK2(*(bp + 4), PIMV2_REGISTER_FLAG_LEN); ND_PRINT((ndo, ", Flags [ %s ]\n\t", tok2str(pimv2_register_flag_values, @@ -752,22 +814,22 @@ pimv2_print(netdissect_options *ndo, bp += 8; len -= 8; /* encapsulated multicast packet */ - ip = (struct ip *)bp; + ip = (const struct ip *)bp; switch (IP_V(ip)) { case 0: /* Null header */ ND_PRINT((ndo, "IP-Null-header %s > %s", - ipaddr_string(&ip->ip_src), - ipaddr_string(&ip->ip_dst))); + ipaddr_string(ndo, &ip->ip_src), + ipaddr_string(ndo, &ip->ip_dst))); break; case 4: /* IPv4 */ ip_print(ndo, bp, len); break; -#ifdef INET6 + case 6: /* IPv6 */ ip6_print(ndo, bp, len); break; -#endif + default: ND_PRINT((ndo, "IP ver %d", IP_V(ip))); break; @@ -836,10 +898,10 @@ pimv2_print(netdissect_options *ndo, */ { - u_int8_t ngroup; - u_int16_t holdtime; - u_int16_t njoin; - u_int16_t nprune; + uint8_t ngroup; + uint16_t holdtime; + uint16_t njoin; + uint16_t nprune; int i, j; bp += 4; len -= 4; @@ -910,9 +972,9 @@ pimv2_print(netdissect_options *ndo, bp += 4; /* Fragment Tag, Hash Mask len, and BSR-priority */ - if (bp + sizeof(u_int16_t) >= ep) break; + if (bp + sizeof(uint16_t) >= ep) break; ND_PRINT((ndo, " tag=%x", EXTRACT_16BITS(bp))); - bp += sizeof(u_int16_t); + bp += sizeof(uint16_t); if (bp >= ep) break; ND_PRINT((ndo, " hashmlen=%d", bp[0])); if (bp + 1 >= ep) break;