X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/47b1a4a09bf1df61fb3b8cc75ead086fddb4ae5f..47fc89d711eec0a073d9b3b293a1af901b5bd791:/print-babel.c diff --git a/print-babel.c b/print-babel.c index a8108fc5..4f128b32 100644 --- a/print-babel.c +++ b/print-babel.c @@ -37,6 +37,9 @@ #include "addrtoname.h" #include "interface.h" +#include "extract.h" + +static const char tstr[] = "[|babel]"; static void babel_print_v2(const u_char *cp, u_int length); @@ -65,27 +68,11 @@ babel_print(const u_char *cp, u_int length) { return; trunc: - printf(" [|babel]"); + printf(" %s", tstr); return; } -#if defined __GNUC__ -struct __us { unsigned short x __attribute__((packed)); }; -#define DO_NTOHS(_d, _s) \ - do { _d = ntohs(((const struct __us*)(_s))->x); } while(0) -#define DO_HTONS(_d, _s) \ - do { ((struct __us*)(_d))->x = htons(_s); } while(0) -#else -#define DO_NTOHS(_d, _s) \ - do { short _dd; \ - memcpy(&(_dd), (_s), 2); \ - _d = ntohs(_dd); } while(0) -#define DO_HTONS(_d, _s) \ - do { unsigned short _dd; \ - _dd = htons(_s); \ - memcpy((_d), &(_dd), 2); } while(0) -#endif - +/* TLVs */ #define MESSAGE_PAD1 0 #define MESSAGE_PADN 1 #define MESSAGE_ACK_REQ 2 @@ -97,6 +84,20 @@ struct __us { unsigned short x __attribute__((packed)); }; #define MESSAGE_UPDATE 8 #define MESSAGE_REQUEST 9 #define MESSAGE_MH_REQUEST 10 +#define MESSAGE_TSPC 11 +#define MESSAGE_HMAC 12 + +/* sub-TLVs */ +#define MESSAGE_SUB_PAD1 0 +#define MESSAGE_SUB_PADN 1 +#define MESSAGE_SUB_DIVERSITY 2 + +/* Diversity sub-TLV channel codes */ +static const struct tok diversity_str[] = { + { 0, "reserved" }, + { 255, "all" }, + { 0, NULL } +}; static const char * format_id(const u_char *id) @@ -118,7 +119,11 @@ format_prefix(const u_char *prefix, unsigned char plen) if(plen >= 96 && memcmp(prefix, v4prefix, 12) == 0) snprintf(buf, 50, "%s/%u", ipaddr_string(prefix + 12), plen - 96); else +#ifdef INET6 snprintf(buf, 50, "%s/%u", ip6addr_string(prefix), plen); +#else + snprintf(buf, 50, "IPv6 addresses not supported"); +#endif buf[49] = '\0'; return buf; } @@ -129,9 +134,32 @@ format_address(const u_char *prefix) if(memcmp(prefix, v4prefix, 12) == 0) return ipaddr_string(prefix + 12); else +#ifdef INET6 return ip6addr_string(prefix); +#else + return "IPv6 addresses not supported"; +#endif +} + +static const char * +format_interval(const u_int16_t i) +{ + static char buf[sizeof("0000.0s")]; + + if (i == 0) + return "0.0s (bogus)"; + snprintf(buf, sizeof(buf), "%u.%us", i / 10, i % 10); + return buf; +} + +static const char * +format_interval_update(const u_int16_t i) +{ + return i == 0xFFFF ? "infinity" : format_interval(i); } +/* Return number of octets consumed from the input buffer (not the prefix length + * in bytes), or -1 for encoding error. */ static int network_prefix(int ae, int plen, unsigned int omitted, const unsigned char *p, const unsigned char *dp, @@ -139,6 +167,7 @@ network_prefix(int ae, int plen, unsigned int omitted, { unsigned pb; unsigned char prefix[16]; + int consumed = 0; if(plen >= 0) pb = (plen + 7) / 8; @@ -162,7 +191,10 @@ network_prefix(int ae, int plen, unsigned int omitted, if (dp == NULL) return -1; memcpy(prefix, dp, 12 + omitted); } - if(pb > omitted) memcpy(prefix + 12 + omitted, p, pb - omitted); + if(pb > omitted) { + memcpy(prefix + 12 + omitted, p, pb - omitted); + consumed = pb - omitted; + } break; case 2: if(omitted > 16 || (pb > omitted && len < pb - omitted)) @@ -171,20 +203,26 @@ network_prefix(int ae, int plen, unsigned int omitted, if (dp == NULL) return -1; memcpy(prefix, dp, omitted); } - if(pb > omitted) memcpy(prefix + omitted, p, pb - omitted); + if(pb > omitted) { + memcpy(prefix + omitted, p, pb - omitted); + consumed = pb - omitted; + } break; case 3: if(pb > 8 && len < pb - 8) return -1; prefix[0] = 0xfe; prefix[1] = 0x80; - if(pb > 8) memcpy(prefix + 8, p, pb - 8); + if(pb > 8) { + memcpy(prefix + 8, p, pb - 8); + consumed = pb - 8; + } break; default: return -1; } memcpy(p_r, prefix, 16); - return 1; + return consumed; } static int @@ -194,39 +232,111 @@ network_address(int ae, const unsigned char *a, unsigned int len, return network_prefix(ae, -1, 0, a, NULL, len, a_r); } +/* + * Sub-TLVs consume the "extra data" of Babel TLVs (see Section 4.3 of RFC6126), + * their encoding is similar to the encoding of TLVs, but the type namespace is + * different: + * + * o Type 0 stands for Pad1 sub-TLV with the same encoding as the Pad1 TLV. + * o Type 1 stands for PadN sub-TLV with the same encoding as the PadN TLV. + * o Type 2 stands for Diversity sub-TLV, which propagates diversity routing + * data. Its body is a variable-length sequence of 8-bit unsigned integers, + * each representing per-hop number of interferring radio channel for the + * prefix. Channel 0 is invalid and must not be used in the sub-TLV, channel + * 255 interferes with any other channel. + * + * Sub-TLV types 0 and 1 are valid for any TLV type, whether sub-TLV type 2 is + * only valid for TLV type 8 (Update). Note that within an Update TLV a missing + * Diversity sub-TLV is not the same as a Diversity sub-TLV with an empty body. + * The former would mean a lack of any claims about the interference, and the + * latter would state that interference is definitely absent. */ +static void +subtlvs_print(const u_char *cp, const u_char *ep, const uint8_t tlv_type) { + uint8_t subtype, sublen; + const char *sep; + + while (cp < ep) { + subtype = *cp++; + if(subtype == MESSAGE_SUB_PAD1) { + printf(" sub-pad1"); + continue; + } + if(cp == ep) + goto corrupt; + sublen = *cp++; + if(cp + sublen > ep) + goto corrupt; + + switch(subtype) { + case MESSAGE_SUB_PADN: + printf(" sub-padn"); + cp += sublen; + break; + case MESSAGE_SUB_DIVERSITY: + printf(" sub-diversity"); + if (sublen == 0) { + printf(" empty"); + break; + } + sep = " "; + while(sublen--) { + printf("%s%s", sep, tok2str(diversity_str, "%u", *cp++)); + sep = "-"; + } + if(tlv_type != MESSAGE_UPDATE) + printf(" (bogus)"); + break; + default: + printf(" sub-unknown-0x%02x", subtype); + cp += sublen; + } /* switch */ + } /* while */ + return; + + corrupt: + printf(" (corrupt)"); +} + +#define ICHECK(i, l) \ + if ((i) + (l) > bodylen || (i) + (l) > length) goto corrupt; + static void babel_print_v2(const u_char *cp, u_int length) { - int i; + u_int i; u_short bodylen; u_char v4_prefix[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 }; u_char v6_prefix[16] = {0}; - DO_NTOHS(bodylen, cp + 2); - printf(" (%d)", bodylen); + TCHECK2(*cp, 4); + if (length < 4) + goto corrupt; + bodylen = EXTRACT_16BITS(cp + 2); + printf(" (%u)", bodylen); + /* Process the TLVs in the body */ i = 0; while(i < bodylen) { const u_char *message; - u_char type, len; - - TCHECK2(*cp, 4 + i); + u_int type, len; message = cp + 4 + i; - type = message[0]; + + TCHECK2(*message, 1); + if((type = message[0]) == MESSAGE_PAD1) { + printf(vflag ? "\n\tPad 1" : " pad1"); + i += 1; + continue; + } + + TCHECK2(*message, 2); + ICHECK(i, 2); len = message[1]; - TCHECK2(*cp, 4 + i + 2 + len); + TCHECK2(*message, 2 + len); + ICHECK(i, 2 + len); switch(type) { - case MESSAGE_PAD1: { - if(!vflag) - printf(" pad1"); - else - printf("\n\tPad 1"); - } - break; - case MESSAGE_PADN: { if(!vflag) printf(" padN"); @@ -242,9 +352,9 @@ babel_print_v2(const u_char *cp, u_int length) { else { printf("\n\tAcknowledgment Request "); if(len < 6) goto corrupt; - DO_NTOHS(nonce, message + 4); - DO_NTOHS(interval, message + 6); - printf("%04x %d", nonce, interval); + nonce = EXTRACT_16BITS(message + 4); + interval = EXTRACT_16BITS(message + 6); + printf("%04x %s", nonce, format_interval(interval)); } } break; @@ -256,7 +366,7 @@ babel_print_v2(const u_char *cp, u_int length) { else { printf("\n\tAcknowledgment "); if(len < 2) goto corrupt; - DO_NTOHS(nonce, message + 2); + nonce = EXTRACT_16BITS(message + 2); printf("%04x", nonce); } } @@ -269,9 +379,9 @@ babel_print_v2(const u_char *cp, u_int length) { else { printf("\n\tHello "); if(len < 6) goto corrupt; - DO_NTOHS(seqno, message + 4); - DO_NTOHS(interval, message + 6); - printf("seqno %u interval %u", seqno, interval); + seqno = EXTRACT_16BITS(message + 4); + interval = EXTRACT_16BITS(message + 6); + printf("seqno %u interval %s", seqno, format_interval(interval)); } } break; @@ -285,12 +395,12 @@ babel_print_v2(const u_char *cp, u_int length) { int rc; printf("\n\tIHU "); if(len < 6) goto corrupt; - DO_NTOHS(txcost, message + 4); - DO_NTOHS(interval, message + 6); + txcost = EXTRACT_16BITS(message + 4); + interval = EXTRACT_16BITS(message + 6); rc = network_address(message[2], message + 8, len - 6, address); - if(rc < 0) { printf("[|babel]"); break; } - printf("%s txcost %u interval %d", - format_address(address), txcost, interval); + if(rc < 0) { printf("%s", tstr); break; } + printf("%s txcost %u interval %s", + format_address(address), txcost, format_interval(interval)); } } break; @@ -344,21 +454,24 @@ babel_print_v2(const u_char *cp, u_int length) { message[2] == 1 ? v4_prefix : v6_prefix, len - 10, prefix); if(rc < 0) goto corrupt; - DO_NTOHS(interval, message + 6); - DO_NTOHS(seqno, message + 8); - DO_NTOHS(metric, message + 10); - printf("%s%s%s %s metric %u seqno %u interval %u", + interval = EXTRACT_16BITS(message + 6); + seqno = EXTRACT_16BITS(message + 8); + metric = EXTRACT_16BITS(message + 10); + printf("%s%s%s %s metric %u seqno %u interval %s", (message[3] & 0x80) ? "/prefix": "", (message[3] & 0x40) ? "/id" : "", (message[3] & 0x3f) ? "/unknown" : "", format_prefix(prefix, plen), - metric, seqno, interval); + metric, seqno, format_interval_update(interval)); if(message[3] & 0x80) { if(message[2] == 1) memcpy(v4_prefix, prefix, 16); else memcpy(v6_prefix, prefix, 16); } + /* extra data? */ + if((u_int)rc < len - 10) + subtlvs_print(message + 12 + rc, message + 2 + len, type); } } break; @@ -391,7 +504,7 @@ babel_print_v2(const u_char *cp, u_int length) { u_char prefix[16], plen; printf("\n\tMH-Request "); if(len < 14) goto corrupt; - DO_NTOHS(seqno, message + 4); + seqno = EXTRACT_16BITS(message + 4); rc = network_prefix(message[2], message[3], 0, message + 16, NULL, len - 14, prefix); if(rc < 0) goto corrupt; @@ -402,6 +515,29 @@ babel_print_v2(const u_char *cp, u_int length) { } } break; + case MESSAGE_TSPC : + if(!vflag) + printf(" tspc"); + else { + printf("\n\tTS/PC "); + if(len < 6) goto corrupt; + printf("timestamp %u packetcounter %u", EXTRACT_32BITS (message + 4), + EXTRACT_16BITS(message + 2)); + } + break; + case MESSAGE_HMAC : { + if(!vflag) + printf(" hmac"); + else { + unsigned j; + printf("\n\tHMAC "); + if(len < 18) goto corrupt; + printf("key-id %u digest-%u ", EXTRACT_16BITS(message + 2), len - 2); + for (j = 0; j < len - 2; j++) + printf ("%02X", message[4 + j]); + } + } + break; default: if(!vflag) printf(" unknown"); @@ -413,7 +549,7 @@ babel_print_v2(const u_char *cp, u_int length) { return; trunc: - printf(" [|babel]"); + printf(" %s", tstr); return; corrupt: