X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/75b7aeef9cc990ab705759884a725c1cad9924d0..1fb50928ce27360c1c987312774f686b23c69b51:/print-hncp.c diff --git a/print-hncp.c b/print-hncp.c index cca45f54..87ee8bbb 100644 --- a/print-hncp.c +++ b/print-hncp.c @@ -26,6 +26,8 @@ * SUCH DAMAGE. */ +/* \summary: Home Networking Control Protocol (HNCP) printer */ + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -134,6 +136,25 @@ static const struct tok dh6opt_str[] = { { 0, NULL } }; +/* + * For IPv4-mapped IPv6 addresses, length of the prefix that precedes + * the 4 bytes of IPv4 address at the end of the IPv6 address. + */ +#define IPV4_MAPPED_HEADING_LEN 12 + +/* + * Is an IPv6 address an IPv4-mapped address? + */ +static inline int +is_ipv4_mapped_address(const u_char *addr) +{ + /* The value of the prefix */ + static const u_char ipv4_mapped_heading[IPV4_MAPPED_HEADING_LEN] = + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF }; + + return memcmp(addr, ipv4_mapped_heading, IPV4_MAPPED_HEADING_LEN) == 0; +} + static const char * format_nid(const u_char *data) { @@ -151,7 +172,7 @@ format_256(const u_char *data) static char buf[4][64+5]; static int i = 0; i = (i + 1) % 4; - snprintf(buf[i], 28, "%016lx%016lx%016lx%016lx", + snprintf(buf[i], 28, "%016" PRIx64 "%016" PRIx64 "%016" PRIx64 "%016" PRIx64, EXTRACT_64BITS(data), EXTRACT_64BITS(data + 8), EXTRACT_64BITS(data + 16), @@ -161,22 +182,20 @@ format_256(const u_char *data) } static const char * -format_interval(const uint16_t n) +format_interval(const uint32_t n) { - static char buf[4][sizeof("000.00s")]; + static char buf[4][sizeof("0000000.000s")]; static int i = 0; i = (i + 1) % 4; - if (n == 0) - return "0.0s (bogus)"; - snprintf(buf[i], sizeof(buf[i]), "%u.%02us", n / 100, n % 100); + snprintf(buf[i], sizeof(buf[i]), "%u.%03us", n / 1000, n % 1000); return buf[i]; } static const char * format_ip6addr(netdissect_options *ndo, const u_char *cp) { - if (EXTRACT_64BITS(cp) == 0x0 && EXTRACT_32BITS(cp+8) == 0xffff) - return ipaddr_string(ndo, cp + 12); + if (is_ipv4_mapped_address(cp)) + return ipaddr_string(ndo, cp + IPV4_MAPPED_HEADING_LEN); else return ip6addr_string(ndo, cp); } @@ -185,20 +204,34 @@ static int print_prefix(netdissect_options *ndo, const u_char *prefix, u_int max_length) { int plenbytes; - static char buf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx::/128")]; - static u_char prefix_v4[5]; - if (prefix[0] >= 96 && max_length >= 13 && EXTRACT_64BITS(prefix+1) == 0x0 && EXTRACT_32BITS(prefix+9) == 0xffff) { - prefix_v4[0] = prefix[0]-96; - prefix_v4[1] = prefix[13]; - prefix_v4[2] = prefix[14]; - prefix_v4[3] = prefix[15]; - prefix_v4[4] = prefix[16]; - plenbytes = 12 + decode_prefix4(ndo, (const u_char *)prefix_v4, max_length-12, buf, 45); + char buf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx::/128")]; + + if (prefix[0] >= 96 && max_length >= IPV4_MAPPED_HEADING_LEN + 1 && + is_ipv4_mapped_address(&prefix[1])) { + struct in_addr addr; + u_int plen; + + plen = prefix[0]-96; + if (32 < plen) + return -1; + max_length -= 1; + + memset(&addr, 0, sizeof(addr)); + plenbytes = (plen + 7) / 8; + if (max_length < (u_int)plenbytes + IPV4_MAPPED_HEADING_LEN) + return -3; + memcpy(&addr, &prefix[1 + IPV4_MAPPED_HEADING_LEN], plenbytes); + if (plen % 8) { + ((u_char *)&addr)[plenbytes - 1] &= + ((0xff00 >> (plen % 8)) & 0xff); + } + snprintf(buf, sizeof(buf), "%s/%d", ipaddr_string(ndo, &addr), plen); + plenbytes += 1 + IPV4_MAPPED_HEADING_LEN; } else { - plenbytes = decode_prefix6(ndo, prefix, max_length, buf, 45); + plenbytes = decode_prefix6(ndo, prefix, max_length, buf, sizeof(buf)); } - safeputs(ndo, (const u_char*)buf, 45); + ND_PRINT((ndo, "%s", buf)); return plenbytes; } @@ -364,7 +397,7 @@ hncp_print_rec(netdissect_options *ndo, u_int i, t; - uint32_t last_type_mask = -1; + uint32_t last_type_mask = 0xffffffffU; int last_type_count = -1; const u_char *tlv, *value; @@ -441,8 +474,10 @@ hncp_print_rec(netdissect_options *ndo, case DNCP_REQUEST_NODE_STATE: { const char *node_identifier; - if (bodylen != 4) - goto invalid; + if (bodylen != 4) { + ND_PRINT((ndo, " %s", istr)); + break; + } node_identifier = format_nid(value); ND_PRINT((ndo, " NID: %s", node_identifier)); } @@ -451,8 +486,10 @@ hncp_print_rec(netdissect_options *ndo, case DNCP_NODE_ENDPOINT: { const char *node_identifier; uint32_t endpoint_identifier; - if (bodylen != 8) - goto invalid; + if (bodylen != 8) { + ND_PRINT((ndo, " %s", istr)); + break; + } node_identifier = format_nid(value); endpoint_identifier = EXTRACT_32BITS(value + 4); ND_PRINT((ndo, " NID: %s EPID: %08x", @@ -464,27 +501,31 @@ hncp_print_rec(netdissect_options *ndo, case DNCP_NETWORK_STATE: { uint64_t hash; - if (bodylen != 8) - goto invalid; + if (bodylen != 8) { + ND_PRINT((ndo, " %s", istr)); + break; + } hash = EXTRACT_64BITS(value); - ND_PRINT((ndo, " hash: %016lx", hash)); + ND_PRINT((ndo, " hash: %016" PRIx64, hash)); } break; case DNCP_NODE_STATE: { - const char *node_identifier, *time; + const char *node_identifier, *interval; uint32_t sequence_number; uint64_t hash; - if (bodylen < 20) - goto invalid; + if (bodylen < 20) { + ND_PRINT((ndo, " %s", istr)); + break; + } node_identifier = format_nid(value); sequence_number = EXTRACT_32BITS(value + 4); - time = format_interval(EXTRACT_32BITS(value + 8)); + interval = format_interval(EXTRACT_32BITS(value + 8)); hash = EXTRACT_64BITS(value + 12); - ND_PRINT((ndo, " NID: %s seqno: %u %s hash: %016lx", + ND_PRINT((ndo, " NID: %s seqno: %u %s hash: %016" PRIx64, node_identifier, sequence_number, - time, + interval, hash )); hncp_print_rec(ndo, value+20, bodylen-20, indent+1); @@ -494,8 +535,10 @@ hncp_print_rec(netdissect_options *ndo, case DNCP_PEER: { const char *peer_node_identifier; uint32_t peer_endpoint_identifier, endpoint_identifier; - if (bodylen != 12) - goto invalid; + if (bodylen != 12) { + ND_PRINT((ndo, " %s", istr)); + break; + } peer_node_identifier = format_nid(value); peer_endpoint_identifier = EXTRACT_32BITS(value + 4); endpoint_identifier = EXTRACT_32BITS(value + 8); @@ -510,8 +553,10 @@ hncp_print_rec(netdissect_options *ndo, case DNCP_KEEP_ALIVE_INTERVAL: { uint32_t endpoint_identifier; const char *interval; - if (bodylen < 8) - goto invalid; + if (bodylen < 8) { + ND_PRINT((ndo, " %s", istr)); + break; + } endpoint_identifier = EXTRACT_32BITS(value); interval = format_interval(EXTRACT_32BITS(value + 4)); ND_PRINT((ndo, " EPID: %08x Interval: %s", @@ -522,8 +567,10 @@ hncp_print_rec(netdissect_options *ndo, break; case DNCP_TRUST_VERDICT: { - if (bodylen <= 36) - goto invalid; + if (bodylen <= 36) { + ND_PRINT((ndo, " %s", istr)); + break; + } ND_PRINT((ndo, " Verdict: %u Fingerprint: %s Common Name: ", *value, format_256(value + 4))); @@ -534,8 +581,10 @@ hncp_print_rec(netdissect_options *ndo, case HNCP_HNCP_VERSION: { uint16_t capabilities; uint8_t M, P, H, L; - if (bodylen < 5) - goto invalid; + if (bodylen < 5) { + ND_PRINT((ndo, " %s", istr)); + break; + } capabilities = EXTRACT_16BITS(value + 2); M = (uint8_t)((capabilities >> 12) & 0xf); P = (uint8_t)((capabilities >> 8) & 0xf); @@ -556,14 +605,32 @@ hncp_print_rec(netdissect_options *ndo, case HNCP_DELEGATED_PREFIX: { int l; - if (bodylen < 9 || bodylen < 9 + (value[8] + 7) / 8) - goto invalid; + if (bodylen < 9 || bodylen < 9 + (value[8] + 7) / 8) { + ND_PRINT((ndo, " %s", istr)); + break; + } ND_PRINT((ndo, " VLSO: %s PLSO: %s Prefix: ", format_interval(EXTRACT_32BITS(value)), format_interval(EXTRACT_32BITS(value + 4)) )); - if ((l = print_prefix(ndo, value + 8, bodylen - 8)) < 0) - goto invalid; + l = print_prefix(ndo, value + 8, bodylen - 8); + if (l == -1) { + ND_PRINT((ndo, "(length is invalid)")); + break; + } + if (l < 0) { + /* + * We've already checked that we've captured the + * entire TLV, based on its length, so this will + * either be -1, meaning "the prefix length is + * greater than the longest possible address of + * that type" (i.e., > 32 for IPv4 or > 128 for + * IPv6", or -3, meaning "the prefix runs past + * the end of the TLV". + */ + ND_PRINT((ndo, " %s", istr)); + break; + } l += 8 + (-l & 3); if (bodylen >= l) @@ -573,17 +640,39 @@ hncp_print_rec(netdissect_options *ndo, case HNCP_PREFIX_POLICY: { uint8_t policy; - if (bodylen < 1) - goto invalid; + int l; + if (bodylen < 1) { + ND_PRINT((ndo, " %s", istr)); + break; + } policy = value[0]; ND_PRINT((ndo, " type: ")); if (policy == 0) { - if (bodylen != 1) - goto invalid; + if (bodylen != 1) { + ND_PRINT((ndo, " %s", istr)); + break; + } ND_PRINT((ndo, "Internet connectivity")); } else if (policy >= 1 && policy <= 128) { ND_PRINT((ndo, "Dest-Prefix: ")); - print_prefix(ndo, value, bodylen); + l = print_prefix(ndo, value, bodylen); + if (l == -1) { + ND_PRINT((ndo, "(length is invalid)")); + break; + } + if (l < 0) { + /* + * We've already checked that we've captured the + * entire TLV, based on its length, so this will + * either be -1, meaning "the prefix length is + * greater than the longest possible address of + * that type" (i.e., > 32 for IPv4 or > 128 for + * IPv6", or -3, meaning "the prefix runs past + * the end of the TLV". + */ + ND_PRINT((ndo, " %s", istr)); + break; + } } else if (policy == 129) { ND_PRINT((ndo, "DNS domain: ")); print_dns_label(ndo, value+1, bodylen-1, 1); @@ -591,8 +680,10 @@ hncp_print_rec(netdissect_options *ndo, ND_PRINT((ndo, "Opaque UTF-8: ")); safeputs(ndo, value + 1, bodylen - 1); } else if (policy == 131) { - if (bodylen != 1) - goto invalid; + if (bodylen != 1) { + ND_PRINT((ndo, " %s", istr)); + break; + } ND_PRINT((ndo, "Restrictive assignment")); } else if (policy >= 132) { ND_PRINT((ndo, "Unknown (%u)", policy)); /* Reserved for future additions */ @@ -601,34 +692,44 @@ hncp_print_rec(netdissect_options *ndo, break; case HNCP_DHCPV4_DATA: { - if (bodylen == 0) - goto invalid; + if (bodylen == 0) { + ND_PRINT((ndo, " %s", istr)); + break; + } if (dhcpv4_print(ndo, value, bodylen, indent+1) != 0) goto invalid; } break; case HNCP_DHCPV6_DATA: { - if (bodylen == 0) - goto invalid; - if (dhcpv6_print(ndo, value, bodylen, indent+1) != 0) - goto invalid; + if (bodylen == 0) { + ND_PRINT((ndo, " %s", istr)); + break; + } + if (dhcpv6_print(ndo, value, bodylen, indent+1) != 0) { + ND_PRINT((ndo, " %s", istr)); + break; + } } break; case HNCP_ASSIGNED_PREFIX: { uint8_t prty; int l; - if (bodylen < 6 || bodylen < 6 + (value[5] + 7) / 8) - goto invalid; + if (bodylen < 6 || bodylen < 6 + (value[5] + 7) / 8) { + ND_PRINT((ndo, " %s", istr)); + break; + } prty = (uint8_t)(value[4] & 0xf); ND_PRINT((ndo, " EPID: %08x Prty: %u", EXTRACT_32BITS(value), prty )); ND_PRINT((ndo, " Prefix: ")); - if ((l = print_prefix(ndo, value + 5, bodylen - 5)) < 0) - goto invalid; + if ((l = print_prefix(ndo, value + 5, bodylen - 5)) < 0) { + ND_PRINT((ndo, " %s", istr)); + break; + } l += 5; l += -l & 3; @@ -640,8 +741,10 @@ hncp_print_rec(netdissect_options *ndo, case HNCP_NODE_ADDRESS: { uint32_t endpoint_identifier; const char *ip_address; - if (bodylen < 20) - goto invalid; + if (bodylen < 20) { + ND_PRINT((ndo, " %s", istr)); + break; + } endpoint_identifier = EXTRACT_32BITS(value); ip_address = format_ip6addr(ndo, value + 4); ND_PRINT((ndo, " EPID: %08x IP Address: %s", @@ -656,8 +759,10 @@ hncp_print_rec(netdissect_options *ndo, case HNCP_DNS_DELEGATED_ZONE: { const char *ip_address; int len; - if (bodylen < 17) - goto invalid; + if (bodylen < 17) { + ND_PRINT((ndo, " %s", istr)); + break; + } ip_address = format_ip6addr(ndo, value); ND_PRINT((ndo, " IP-Address: %s %c%c%c ", ip_address, @@ -666,8 +771,10 @@ hncp_print_rec(netdissect_options *ndo, (value[16] & 1) ? 's' : '-' )); len = print_dns_label(ndo, value+17, bodylen-17, 1); - if (len < 0) - goto invalid; + if (len < 0) { + ND_PRINT((ndo, " %s", istr)); + break; + } len += 17; len += -len & 3; if (bodylen >= len) @@ -676,8 +783,10 @@ hncp_print_rec(netdissect_options *ndo, break; case HNCP_DOMAIN_NAME: { - if (bodylen == 0) - goto invalid; + if (bodylen == 0) { + ND_PRINT((ndo, " %s", istr)); + break; + } ND_PRINT((ndo, " Domain: ")); print_dns_label(ndo, value, bodylen, 1); } @@ -685,11 +794,15 @@ hncp_print_rec(netdissect_options *ndo, case HNCP_NODE_NAME: { u_int l; - if (bodylen < 17) - goto invalid; + if (bodylen < 17) { + ND_PRINT((ndo, " %s", istr)); + break; + } l = value[16]; - if (bodylen < 17 + l) - goto invalid; + if (bodylen < 17 + l) { + ND_PRINT((ndo, " %s", istr)); + break; + } ND_PRINT((ndo, " IP-Address: %s Name: ", format_ip6addr(ndo, value) )); @@ -708,8 +821,10 @@ hncp_print_rec(netdissect_options *ndo, break; case HNCP_MANAGED_PSK: { - if (bodylen < 32) - goto invalid; + if (bodylen < 32) { + ND_PRINT((ndo, " %s", istr)); + break; + } ND_PRINT((ndo, " PSK: %s", format_256(value))); hncp_print_rec(ndo, value + 32, bodylen - 32, indent+1); }