X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/ea0d29f7436f5a919d16009790c9b38c2c86e96f..2db7c32de1a1c3e7f940e8275a285bbf44c658ad:/print-bootp.c diff --git a/print-bootp.c b/print-bootp.c index f84b77ca..0e47ef50 100644 --- a/print-bootp.c +++ b/print-bootp.c @@ -21,14 +21,13 @@ /* \summary: BOOTP and IPv4 DHCP printer */ -#ifdef HAVE_CONFIG_H #include -#endif #include "netdissect-stdinc.h" #include +#define ND_LONGJMP_FROM_TCHECK #include "netdissect.h" #include "addrtoname.h" #include "extract.h" @@ -147,7 +146,7 @@ struct bootp { #define TAG_NIS_P_DOMAIN ((uint8_t) 64) #define TAG_NIS_P_SERVERS ((uint8_t) 65) #define TAG_MOBILE_HOME ((uint8_t) 68) -#define TAG_SMPT_SERVER ((uint8_t) 69) +#define TAG_SMTP_SERVER ((uint8_t) 69) #define TAG_POP3_SERVER ((uint8_t) 70) #define TAG_NNTP_SERVER ((uint8_t) 71) #define TAG_WWW_SERVER ((uint8_t) 72) @@ -180,10 +179,12 @@ struct bootp { /* RFC 2485 */ #define TAG_OPEN_GROUP_UAP ((uint8_t) 98) /* RFC 2563 */ -#define TAG_DISABLE_AUTOCONF ((uint8_t) 116) +#define TAG_AUTO_CONFIGURE ((uint8_t) 116) /* RFC 2610 */ #define TAG_SLP_DA ((uint8_t) 78) #define TAG_SLP_SCOPE ((uint8_t) 79) +/* RFC 8925 */ +#define TAG_IPV6_ONLY_PREFERRED ((uint8_t) 108) /* RFC 2937 */ #define TAG_NS_SEARCH ((uint8_t) 117) /* RFC 3004 - The User Class Option for DHCP */ @@ -193,6 +194,8 @@ struct bootp { /* RFC 3442 */ #define TAG_CLASSLESS_STATIC_RT ((uint8_t) 121) #define TAG_CLASSLESS_STA_RT_MS ((uint8_t) 249) +/* RFC8572 */ +#define TAG_SZTP_REDIRECT ((uint8_t) 143) /* RFC 5859 - TFTP Server Address Option for DHCPv4 */ #define TAG_TFTP_SERVER_ADDRESS ((uint8_t) 150) /* https://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xhtml */ @@ -210,8 +213,8 @@ struct bootp { #define TAG_CLIENT_GUID ((uint8_t) 97) #define TAG_LDAP_URL ((uint8_t) 95) /* RFC 4833, TZ codes */ -#define TAG_TZ_PCODE ((uint8_t) 100) -#define TAG_TZ_TCODE ((uint8_t) 101) +#define TAG_TZ_PCODE ((uint8_t) 100) +#define TAG_TZ_TCODE ((uint8_t) 101) #define TAG_NETINFO_PARENT ((uint8_t) 112) #define TAG_NETINFO_PARENT_TAG ((uint8_t) 113) #define TAG_URL ((uint8_t) 114) @@ -260,9 +263,16 @@ struct cmu_vend { #define CLIENT_FQDN_FLAGS_N 0x08 /* end of original bootp.h */ +static const struct tok fqdn_flags_bm[] = { + { CLIENT_FQDN_FLAGS_S, "S" }, + { CLIENT_FQDN_FLAGS_O, "O" }, + { CLIENT_FQDN_FLAGS_E, "E" }, + { CLIENT_FQDN_FLAGS_N, "N" }, + { 0, NULL } +}; + static void rfc1048_print(netdissect_options *, const u_char *); static void cmu_print(netdissect_options *, const u_char *); -static char *client_fqdn_flags(u_int flags); static const struct tok bootp_flag_values[] = { { 0x8000, "Broadcast" }, @@ -295,8 +305,8 @@ bootp_print(netdissect_options *ndo, bp_htype = GET_U_1(bp->bp_htype); bp_hlen = GET_U_1(bp->bp_hlen); - if (bp_htype == 1 && bp_hlen == MAC_ADDR_LEN && bp_op == BOOTPREQUEST) { - ND_PRINT(" from %s", GET_ETHERADDR_STRING(bp->bp_chaddr)); + if (bp_htype == 1 && bp_hlen == MAC48_LEN && bp_op == BOOTPREQUEST) { + ND_PRINT(" from %s", GET_MAC48_STRING(bp->bp_chaddr)); } ND_PRINT(", length %u", length); @@ -311,7 +321,7 @@ bootp_print(netdissect_options *ndo, ND_PRINT(", htype %u", bp_htype); /* The usual length for 10Mb Ethernet address is 6 bytes */ - if (bp_htype != 1 || bp_hlen != MAC_ADDR_LEN) + if (bp_htype != 1 || bp_hlen != MAC48_LEN) ND_PRINT(", hlen %u", bp_hlen); /* Only print interesting fields */ @@ -344,27 +354,27 @@ bootp_print(netdissect_options *ndo, ND_PRINT("\n\t Gateway-IP %s", GET_IPADDR_STRING(bp->bp_giaddr)); /* Client's Ethernet address */ - if (bp_htype == 1 && bp_hlen == MAC_ADDR_LEN) { - ND_PRINT("\n\t Client-Ethernet-Address %s", GET_ETHERADDR_STRING(bp->bp_chaddr)); + if (bp_htype == 1 && bp_hlen == MAC48_LEN) { + ND_PRINT("\n\t Client-Ethernet-Address %s", GET_MAC48_STRING(bp->bp_chaddr)); } if (GET_U_1(bp->bp_sname)) { /* get first char only */ ND_PRINT("\n\t sname \""); if (nd_printztn(ndo, bp->bp_sname, (u_int)sizeof(bp->bp_sname), - ndo->ndo_snapend) == 0) { + NULL) == 0) { + /* Within the buffer, but not NUL-terminated. */ ND_PRINT("\""); - nd_print_trunc(ndo); - return; + goto invalid; } ND_PRINT("\""); } if (GET_U_1(bp->bp_file)) { /* get first char only */ ND_PRINT("\n\t file \""); if (nd_printztn(ndo, bp->bp_file, (u_int)sizeof(bp->bp_file), - ndo->ndo_snapend) == 0) { + NULL) == 0) { + /* Ditto. */ ND_PRINT("\""); - nd_print_trunc(ndo); - return; + goto invalid; } ND_PRINT("\""); } @@ -384,19 +394,18 @@ bootp_print(netdissect_options *ndo, if (ul != 0) ND_PRINT("\n\t Vendor-#0x%x", ul); } - return; -trunc: - nd_print_trunc(ndo); +invalid: + nd_print_invalid(ndo); } /* * The first character specifies the format to print: * i - ip address (32 bits) * p - ip address pairs (32 bits + 32 bits) - * l - long (32 bits) - * L - unsigned long (32 bits) - * s - short (16 bits) + * l - unsigned longs (32 bits) + * L - longs (32 bits) + * s - unsigned shorts (16 bits) * b - period-separated decimal bytes (variable length) * x - colon-separated hex bytes (variable length) * a - ASCII string (variable length) @@ -461,7 +470,7 @@ static const struct tok tag2str[] = { { TAG_NIS_P_DOMAIN, "sN+D" }, { TAG_NIS_P_SERVERS, "iN+S" }, { TAG_MOBILE_HOME, "iMH" }, - { TAG_SMPT_SERVER, "iSMTP" }, + { TAG_SMTP_SERVER, "iSMTP" }, { TAG_POP3_SERVER, "iPOP3" }, { TAG_NNTP_SERVER, "iNNTP" }, { TAG_WWW_SERVER, "iWWW" }, @@ -486,7 +495,7 @@ static const struct tok tag2str[] = { /* RFC 2485 */ { TAG_OPEN_GROUP_UAP, "aUAP" }, /* RFC 2563 */ - { TAG_DISABLE_AUTOCONF, "BNOAUTO" }, + { TAG_AUTO_CONFIGURE, "BAuto-Configure" }, /* RFC 2610 */ { TAG_SLP_DA, "bSLP-DA" }, /*"b" is a little wrong */ { TAG_SLP_SCOPE, "bSLP-SCOPE" }, /*"b" is a little wrong */ @@ -499,6 +508,8 @@ static const struct tok tag2str[] = { /* RFC 3442 */ { TAG_CLASSLESS_STATIC_RT, "$Classless-Static-Route" }, { TAG_CLASSLESS_STA_RT_MS, "$Classless-Static-Route-Microsoft" }, +/* RFC 8572 */ + { TAG_SZTP_REDIRECT, "$SZTP-Redirect" }, /* RFC 5859 - TFTP Server Address Option for DHCPv4 */ { TAG_TFTP_SERVER_ADDRESS, "iTFTP-Server-Address" }, /* https://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xhtml#options */ @@ -509,18 +520,19 @@ static const struct tok tag2str[] = { { TAG_TZ_STRING, "aTZSTR" }, { TAG_FQDN_OPTION, "bFQDNS" }, /* XXX 'b' */ { TAG_AUTH, "bAUTH" }, /* XXX 'b' */ - { TAG_CLIENT_LAST_TRANSACTION_TIME, "LLast-Transaction-Time" }, + { TAG_CLIENT_LAST_TRANSACTION_TIME, "lLast-Transaction-Time" }, { TAG_ASSOCIATED_IP, "iAssociated-IP" }, { TAG_CLIENT_ARCH, "sARCH" }, { TAG_CLIENT_NDI, "bNDI" }, /* XXX 'b' */ { TAG_CLIENT_GUID, "bGUID" }, /* XXX 'b' */ { TAG_LDAP_URL, "aLDAP" }, - { TAG_TZ_PCODE, "aPOSIX-TZ" }, - { TAG_TZ_TCODE, "aTZ-Name" }, + { TAG_TZ_PCODE, "aPOSIX-TZ" }, + { TAG_TZ_TCODE, "aTZ-Name" }, { TAG_NETINFO_PARENT, "iNI" }, { TAG_NETINFO_PARENT_TAG, "aNITAG" }, { TAG_URL, "aURL" }, { TAG_MUDURL, "aMUD-URL" }, + { TAG_IPV6_ONLY_PREFERRED, "$IPv6-Only-Preferred" }, { 0, NULL } }; @@ -640,7 +652,7 @@ rfc1048_print(netdissect_options *ndo, if (tag == TAG_PARM_REQUEST) { idx = 0; - while (len > 0) { + while (len != 0) { uint8_t innertag = GET_U_1(bp); bp++; len--; @@ -671,10 +683,7 @@ rfc1048_print(netdissect_options *ndo, case 'a': /* ASCII strings */ ND_PRINT("\""); - if (nd_printn(ndo, bp, len, ndo->ndo_snapend)) { - ND_PRINT("\""); - goto trunc; - } + nd_printjn(ndo, bp, len); ND_PRINT("\""); bp += len; len = 0; @@ -701,6 +710,14 @@ rfc1048_print(netdissect_options *ndo, case 'p': /* IP address pairs */ + /* this option should be N x 8 bytes long */ + if (len < 8 || len % 8 != 0) { + ND_PRINT("%s[length != N x 8 bytes]", + len == 0 ? " " : ""); + bp += len; + len = 0; + break; + } while (len >= 2*4) { if (!first) ND_PRINT(","); @@ -715,7 +732,7 @@ rfc1048_print(netdissect_options *ndo, break; case 's': - /* shorts */ + /* unsigned shorts */ while (len >= 2) { if (!first) ND_PRINT(","); @@ -728,33 +745,39 @@ rfc1048_print(netdissect_options *ndo, case 'B': /* boolean */ - while (len > 0) { - uint8_t bool_value; - if (!first) - ND_PRINT(","); - bool_value = GET_U_1(bp); - switch (bool_value) { - case 0: - ND_PRINT("N"); - break; - case 1: - ND_PRINT("Y"); - break; - default: - ND_PRINT("%u?", bool_value); - break; - } - ++bp; - --len; - first = 0; + { + /* this option should be 1 byte long */ + if (len != 1) { + ND_PRINT("[length != 1 byte]"); + nd_print_invalid(ndo); + bp += len; + len = 0; + break; } + + uint8_t bool_value; + bool_value = GET_U_1(bp); + switch (bool_value) { + case 0: + ND_PRINT("N"); + break; + case 1: + ND_PRINT("Y"); + break; + default: + ND_PRINT("%u?", bool_value); + break; + } + ++bp; + --len; break; + } case 'b': case 'x': default: /* Bytes */ - while (len > 0) { + while (len != 0) { uint8_t byte_value; if (!first) ND_PRINT(c == 'x' ? ":" : "."); @@ -776,7 +799,8 @@ rfc1048_print(netdissect_options *ndo, case TAG_NETBIOS_NODE: /* this option should be at least 1 byte long */ if (len < 1) { - ND_PRINT("[ERROR: length < 1 bytes]"); + ND_PRINT("[length < 1 byte]"); + nd_print_invalid(ndo); break; } tag = GET_U_1(bp); @@ -788,7 +812,8 @@ rfc1048_print(netdissect_options *ndo, case TAG_OPT_OVERLOAD: /* this option should be at least 1 byte long */ if (len < 1) { - ND_PRINT("[ERROR: length < 1 bytes]"); + ND_PRINT("[length < 1 byte]"); + nd_print_invalid(ndo); break; } tag = GET_U_1(bp); @@ -800,28 +825,27 @@ rfc1048_print(netdissect_options *ndo, case TAG_CLIENT_FQDN: /* this option should be at least 3 bytes long */ if (len < 3) { - ND_PRINT("[ERROR: length < 3 bytes]"); + ND_PRINT("[length < 3 bytes]"); + nd_print_invalid(ndo); bp += len; len = 0; break; } if (GET_U_1(bp) & 0xf0) { - ND_PRINT("[ERROR: MBZ nibble 0x%x != 0] ", + ND_PRINT("[MBZ nibble 0x%x != 0] ", (GET_U_1(bp) & 0xf0) >> 4); + nd_print_invalid(ndo); } if (GET_U_1(bp) & 0x0f) ND_PRINT("[%s] ", - client_fqdn_flags(GET_U_1(bp))); + bittok2str_nosep(fqdn_flags_bm, "", (GET_U_1(bp)))); bp++; if (GET_U_1(bp) || GET_U_1(bp + 1)) ND_PRINT("%u/%u ", GET_U_1(bp), GET_U_1(bp + 1)); bp += 2; ND_PRINT("\""); - if (nd_printn(ndo, bp, len - 3, ndo->ndo_snapend)) { - ND_PRINT("\""); - goto trunc; - } + nd_printjn(ndo, bp, len - 3); ND_PRINT("\""); bp += len - 3; len = 0; @@ -833,7 +857,8 @@ rfc1048_print(netdissect_options *ndo, /* this option should be at least 1 byte long */ if (len < 1) { - ND_PRINT("[ERROR: length < 1 bytes]"); + ND_PRINT("[length < 1 byte]"); + nd_print_invalid(ndo); break; } type = GET_U_1(bp); @@ -841,17 +866,14 @@ rfc1048_print(netdissect_options *ndo, len--; if (type == 0) { ND_PRINT("\""); - if (nd_printn(ndo, bp, len, ndo->ndo_snapend)) { - ND_PRINT("\""); - goto trunc; - } + nd_printjn(ndo, bp, len); ND_PRINT("\""); bp += len; len = 0; break; } else { ND_PRINT("%s ", tok2str(arp2str, "hardware-type %u,", type)); - while (len > 0) { + while (len != 0) { if (!first) ND_PRINT(":"); ND_PRINT("%02x", GET_U_1(bp)); @@ -887,8 +909,7 @@ rfc1048_print(netdissect_options *ndo, case AGENT_SUBOPTION_CIRCUIT_ID: /* fall through */ case AGENT_SUBOPTION_REMOTE_ID: case AGENT_SUBOPTION_SUBSCRIBER_ID: - if (nd_printn(ndo, bp, suboptlen, ndo->ndo_snapend)) - goto trunc; + nd_printjn(ndo, bp, suboptlen); break; default: @@ -907,12 +928,13 @@ rfc1048_print(netdissect_options *ndo, /* this option should be at least 5 bytes long */ if (len < 5) { - ND_PRINT("[ERROR: length < 5 bytes]"); + ND_PRINT("[length < 5 bytes]"); + nd_print_invalid(ndo); bp += len; len = 0; break; } - while (len > 0) { + while (len != 0) { if (!first) ND_PRINT(","); mask_width = GET_U_1(bp); @@ -920,7 +942,8 @@ rfc1048_print(netdissect_options *ndo, len--; /* mask_width <= 32 */ if (mask_width > 32) { - ND_PRINT("[ERROR: Mask width (%u) > 32]", mask_width); + ND_PRINT("[Mask width (%u) > 32]", mask_width); + nd_print_invalid(ndo); bp += len; len = 0; break; @@ -928,7 +951,8 @@ rfc1048_print(netdissect_options *ndo, significant_octets = (mask_width + 7) / 8; /* significant octets + router(4) */ if (len < significant_octets + 4) { - ND_PRINT("[ERROR: Remaining length (%u) < %u bytes]", len, significant_octets + 4); + ND_PRINT("[Remaining length (%u) < %u bytes]", len, significant_octets + 4); + nd_print_invalid(ndo); bp += len; len = 0; break; @@ -962,34 +986,35 @@ rfc1048_print(netdissect_options *ndo, first = 1; if (len < 2) { - ND_PRINT("[ERROR: length < 2 bytes]"); + ND_PRINT("[length < 2 bytes]"); + nd_print_invalid(ndo); bp += len; len = 0; break; } - while (len > 0) { + while (len != 0) { suboptlen = GET_U_1(bp); bp++; len--; ND_PRINT("\n\t "); ND_PRINT("instance#%u: ", suboptnumber); if (suboptlen == 0) { - ND_PRINT("[ERROR: suboption length must be non-zero]"); + ND_PRINT("[suboption length == 0]"); + nd_print_invalid(ndo); bp += len; len = 0; break; } if (len < suboptlen) { - ND_PRINT("[ERROR: invalid option]"); + ND_PRINT("[length %u < suboption length %u", + len, suboptlen); + nd_print_invalid(ndo); bp += len; len = 0; break; } ND_PRINT("\""); - if (nd_printn(ndo, bp, suboptlen, ndo->ndo_snapend)) { - ND_PRINT("\""); - goto trunc; - } + nd_printjn(ndo, bp, suboptlen); ND_PRINT("\""); ND_PRINT(", length %u", suboptlen); suboptnumber++; @@ -999,6 +1024,55 @@ rfc1048_print(netdissect_options *ndo, break; } + + case TAG_SZTP_REDIRECT: + /* as per https://datatracker.ietf.org/doc/html/rfc8572#section-8.3 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+-+-+-+-+-+ + | uri-length | URI | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+-+-+-+-+-+ + + * uri-length: 2 octets long; specifies the length of the URI data. + * URI: URI of the SZTP bootstrap server. + */ + while (len >= 2) { + uint16_t suboptlen2; + + suboptlen2 = GET_BE_U_2(bp); + bp += 2; + len -= 2; + ND_PRINT("\n\t "); + ND_PRINT("length %u: ", suboptlen2); + if (len < suboptlen2) { + ND_PRINT("length goes past end of option"); + bp += len; + len = 0; + break; + } + ND_PRINT("\""); + nd_printjn(ndo, bp, suboptlen2); + ND_PRINT("\""); + len -= suboptlen2; + bp += suboptlen2; + } + if (len != 0) { + ND_PRINT("[length < 2 bytes]"); + nd_print_invalid(ndo); + } + break; + + case TAG_IPV6_ONLY_PREFERRED: + /* this option should be 4 bytes long */ + if (len != 4) { + ND_PRINT("[length != 4 bytes]"); + nd_print_invalid(ndo); + bp += len; + len = 0; + } + ND_PRINT("%u", GET_BE_U_4(bp)); + bp += 4; + len -= 4; + break; + default: ND_PRINT("[unknown special tag %u, size %u]", tag, len); @@ -1014,9 +1088,6 @@ rfc1048_print(netdissect_options *ndo, bp += len; } } - return; -trunc: - nd_print_trunc(ndo); } #define PRINTCMUADDR(m, s) { ND_TCHECK_4(cmu->m); \ @@ -1046,29 +1117,6 @@ cmu_print(netdissect_options *ndo, PRINTCMUADDR(v_ins2, "IEN2"); PRINTCMUADDR(v_ts1, "TS1"); PRINTCMUADDR(v_ts2, "TS2"); - return; - -trunc: - nd_print_trunc(ndo); } #undef PRINTCMUADDR - -static char * -client_fqdn_flags(u_int flags) -{ - static char buf[8+1]; - int i = 0; - - if (flags & CLIENT_FQDN_FLAGS_S) - buf[i++] = 'S'; - if (flags & CLIENT_FQDN_FLAGS_O) - buf[i++] = 'O'; - if (flags & CLIENT_FQDN_FLAGS_E) - buf[i++] = 'E'; - if (flags & CLIENT_FQDN_FLAGS_N) - buf[i++] = 'N'; - buf[i] = '\0'; - - return buf; -}