From: Arran Cudbard-Bell Date: Fri, 25 Oct 2024 05:03:32 +0000 (-0600) Subject: Switch DHCPv4 to using custom flag parsers X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b432feb901c0cc80508ec0f8a046c5e9b952fcb3;p=thirdparty%2Ffreeradius-server.git Switch DHCPv4 to using custom flag parsers --- diff --git a/share/dictionary/dhcpv4/dictionary.rfc2242 b/share/dictionary/dhcpv4/dictionary.rfc2242 index e8ef68f2296..821880722c0 100644 --- a/share/dictionary/dhcpv4/dictionary.rfc2242 +++ b/share/dictionary/dhcpv4/dictionary.rfc2242 @@ -20,10 +20,10 @@ ATTRIBUTE Netware-Sub-Options 63 tlv # sub-option to be present in option 63 encoding. Each of them is # simply a type length pair with length set to zero.... # -ATTRIBUTE NWIP-Does-Not-Exist .1 bool encode=exists -ATTRIBUTE NWIP-Exist-In-Options-Area .2 bool encode=exists -ATTRIBUTE NWIP-Exist-In-Same-File .3 bool encode=exists -ATTRIBUTE NWIP-Exist-But-Too-Big .4 bool encode=exists +ATTRIBUTE NWIP-Does-Not-Exist .1 bool exists +ATTRIBUTE NWIP-Exist-In-Options-Area .2 bool exists +ATTRIBUTE NWIP-Exist-In-Same-File .3 bool exists +ATTRIBUTE NWIP-Exist-But-Too-Big .4 bool exists # Also from RFC2242: # diff --git a/share/dictionary/dhcpv4/dictionary.rfc4039 b/share/dictionary/dhcpv4/dictionary.rfc4039 index cb5cc906636..4f8ddf6e515 100644 --- a/share/dictionary/dhcpv4/dictionary.rfc4039 +++ b/share/dictionary/dhcpv4/dictionary.rfc4039 @@ -12,4 +12,4 @@ ############################################################################## # Rapid Commit -ATTRIBUTE Rapid-Commit 80 bool encode=exists +ATTRIBUTE Rapid-Commit 80 bool exists diff --git a/share/dictionary/dhcpv4/dictionary.rfc8357 b/share/dictionary/dhcpv4/dictionary.rfc8357 index 4ce2222d233..d52e8821a1a 100644 --- a/share/dictionary/dhcpv4/dictionary.rfc8357 +++ b/share/dictionary/dhcpv4/dictionary.rfc8357 @@ -7,5 +7,4 @@ # If this attribute exists, then the reply is sent to the relay agent on the UDP # source port, and not to port 67. # -ATTRIBUTE Remember-Relay-Port 82.19 bool encode=exists - +ATTRIBUTE Remember-Relay-Port 82.19 bool exists diff --git a/src/protocols/dhcpv4/base.c b/src/protocols/dhcpv4/base.c index 09c290e0ec5..9c48b5e1e31 100644 --- a/src/protocols/dhcpv4/base.c +++ b/src/protocols/dhcpv4/base.c @@ -163,6 +163,36 @@ int dhcp_header_sizes[] = { uint8_t eth_bcast[ETH_ADDR_LEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; +FR_DICT_ATTR_FLAG_FUNC(fr_dhcpv4_attr_flags_t, dns_label) +FR_DICT_ATTR_FLAG_FUNC(fr_dhcpv4_attr_flags_t, exists) + +static int dict_flag_prefix(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules) +{ + static fr_table_num_sorted_t const table[] = { + { L("bits"), DHCPV4_FLAG_PREFIX_BITS }, + { L("split"), DHCPV4_FLAG_PREFIX_SPLIT } + }; + static size_t table_len = NUM_ELEMENTS(table); + + fr_dhcpv4_attr_flags_t *flags = fr_dict_attr_ext(*da_p, FR_DICT_ATTR_EXT_PROTOCOL_SPECIFIC); + fr_dhcpv4_attr_flags_prefix_t flag; + + flag = fr_table_value_by_str(table, value, DHCPV4_FLAG_PREFIX_INVALID); + if (flag == DHCPV4_FLAG_PREFIX_INVALID) { + fr_strerror_printf("Unknown prefix type '%s'", value); + return -1; + } + flags->prefix = flag; + + return 0; +} + +static fr_dict_flag_parser_t const dhcpv4_flags[] = { + { L("dns_label"), { .func = dict_flag_dns_label } }, + { L("exists"), { .func = dict_flag_exists } }, + { L("prefix"), { .func = dict_flag_prefix } } +}; + int8_t fr_dhcpv4_attr_cmp(void const *a, void const *b) { fr_pair_t const *my_a = a, *my_b = b; @@ -295,7 +325,7 @@ void *fr_dhcpv4_next_encodable(fr_dlist_head_t *list, void *current, void *uctx) PAIR_VERIFY(c); if (c->da->dict != dict || c->da->flags.internal) continue; - if (c->vp_type == FR_TYPE_BOOL && da_is_bool_exists(c->da) && !c->vp_bool) continue; + if (c->vp_type == FR_TYPE_BOOL && fr_dhcpv4_flag_exists(c->da) && !c->vp_bool) continue; break; } @@ -675,14 +705,6 @@ void fr_dhcpv4_print_hex(FILE *fp, uint8_t const *packet, size_t packet_len) fprintf(fp, "\n"); } -static fr_table_num_ordered_t const subtype_table[] = { - { L("dns_label"), FLAG_ENCODE_DNS_LABEL }, - { L("encode=dns_label"), FLAG_ENCODE_DNS_LABEL }, - { L("prefix=split"), FLAG_ENCODE_SPLIT_PREFIX }, - { L("prefix=bits"), FLAG_ENCODE_BITS_PREFIX }, - { L("encode=exists"), FLAG_ENCODE_BOOL_EXISTS }, -}; - static bool attr_valid(fr_dict_attr_t *da) { /* @@ -709,19 +731,19 @@ static bool attr_valid(fr_dict_attr_t *da) */ if (da->flags.extra || !da->flags.subtype) return true; - if ((da->type != FR_TYPE_STRING) && (da->flags.subtype == FLAG_ENCODE_DNS_LABEL)) { + if ((da->type != FR_TYPE_STRING) && (fr_dhcpv4_flag_dns_label(da))) { fr_strerror_const("The 'dns_label' flag can only be used with attributes of type 'string'"); return false; } if ((da->type != FR_TYPE_IPV4_PREFIX) && - ((da->flags.subtype == FLAG_ENCODE_SPLIT_PREFIX) || (da->flags.subtype == FLAG_ENCODE_BITS_PREFIX))) { + (fr_dhcpv4_flag_prefix(da))) { fr_strerror_const("The 'prefix=...' flag can only be used with attributes of type 'ipv4prefix'"); return false; } - if ((da->type != FR_TYPE_BOOL) && (da->flags.subtype == FLAG_ENCODE_BOOL_EXISTS)) { - fr_strerror_const("The 'encode=exists' flag can only be used with attributes of type 'bool'"); + if ((da->type != FR_TYPE_BOOL) && fr_dhcpv4_flag_exists(da)) { + fr_strerror_const("The 'exists' flag can only be used with attributes of type 'bool'"); return false; } @@ -733,9 +755,10 @@ fr_dict_protocol_t libfreeradius_dhcpv4_dict_protocol = { .name = "dhcpv4", .default_type_size = 1, .default_type_length = 1, - .subtype_table = subtype_table, - .subtype_table_len = NUM_ELEMENTS(subtype_table), .attr = { + .flags_table = dhcpv4_flags, + .flags_table_len = NUM_ELEMENTS(dhcpv4_flags), + .flags_len = sizeof(fr_dhcpv4_attr_flags_t), .valid = attr_valid }, diff --git a/src/protocols/dhcpv4/decode.c b/src/protocols/dhcpv4/decode.c index e334d4891a0..b202fac037b 100644 --- a/src/protocols/dhcpv4/decode.c +++ b/src/protocols/dhcpv4/decode.c @@ -76,7 +76,7 @@ static ssize_t decode_value_trampoline(TALLOC_CTX *ctx, fr_pair_list_t *out, /* * @todo - we might need to limit this to only one DNS label. */ - if ((parent->type == FR_TYPE_STRING) && da_is_dns_label(parent)) { + if ((parent->type == FR_TYPE_STRING) && fr_dhcpv4_flag_dns_label(parent)) { return fr_pair_dns_labels_from_network(ctx, out, parent, data, data, data_len, NULL, false); } @@ -182,7 +182,7 @@ static ssize_t decode_value(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t * 4 octets of address * 4 octets of mask */ - if (da_is_split_prefix(da)) { + if (fr_dhcpv4_flag_prefix_split(da)) { uint32_t ipaddr, mask; if (data_len < 8) goto raw; @@ -218,7 +218,7 @@ static ssize_t decode_value(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t break; } - if (da_is_bits_prefix(vp->da)) { + if (fr_dhcpv4_flag_prefix_bits(vp->da)) { size_t needs; if ((data_len == 0) || (*p > 32)) goto raw; @@ -485,7 +485,7 @@ static ssize_t decode_option(TALLOC_CTX *ctx, fr_pair_list_t *out, slen = fr_pair_raw_from_network(ctx, out, da, data + 2, len); - } else if ((da->type == FR_TYPE_STRING) && da_is_dns_label(da)) { + } else if ((da->type == FR_TYPE_STRING) && fr_dhcpv4_flag_dns_label(da)) { slen = fr_pair_dns_labels_from_network(ctx, out, da, data + 2, data + 2, len, NULL, true); } else if (da->flags.array) { diff --git a/src/protocols/dhcpv4/dhcpv4.h b/src/protocols/dhcpv4/dhcpv4.h index c07028fbc6c..59e4080fe80 100644 --- a/src/protocols/dhcpv4/dhcpv4.h +++ b/src/protocols/dhcpv4/dhcpv4.h @@ -63,22 +63,6 @@ typedef enum { #define FR_DHCP_PACKET_CODE_VALID(_code) (((_code) > 0) && ((_code) < FR_DHCP_CODE_MAX)) -/** subtype values for DHCPv4 and DHCPv6 - * - */ -enum { - FLAG_ENCODE_NONE = 0, //!< no particular encoding for DHCPv6 strings - FLAG_ENCODE_DNS_LABEL, //!< encode as DNS label - FLAG_ENCODE_SPLIT_PREFIX, //!< encode IPv4 prefixes as Policy-Filter, split into IP/mask - FLAG_ENCODE_BITS_PREFIX, //!< encode IPv4 prefixes as prefix bits, followed by IP. - FLAG_ENCODE_BOOL_EXISTS, //!< bool as existence checks -}; - -#define da_is_dns_label(_da) (!(_da)->flags.extra && ((_da)->flags.subtype == FLAG_ENCODE_DNS_LABEL)) -#define da_is_split_prefix(_da) (!(_da)->flags.extra && ((_da)->flags.subtype == FLAG_ENCODE_SPLIT_PREFIX)) -#define da_is_bits_prefix(_da) (!(_da)->flags.extra && ((_da)->flags.subtype == FLAG_ENCODE_BITS_PREFIX)) -#define da_is_bool_exists(_da) (!(_da)->flags.extra && ((_da)->flags.subtype == FLAG_ENCODE_BOOL_EXISTS)) - typedef struct { uint8_t opcode; uint8_t htype; @@ -152,6 +136,31 @@ typedef struct { TALLOC_CTX *tmp_ctx; //!< for temporary things cleaned up during decoding } fr_dhcpv4_ctx_t; +typedef enum { + DHCPV4_FLAG_PREFIX_INVALID = -1, + DHCPV4_FLAG_PREFIX_NONE = 0, + DHCPV4_FLAG_PREFIX_BITS = 1, + DHCPV4_FLAG_PREFIX_SPLIT = 2, +} fr_dhcpv4_attr_flags_prefix_t; + +typedef struct { + bool exists; + bool dns_label; + fr_dhcpv4_attr_flags_prefix_t prefix; +} fr_dhcpv4_attr_flags_t; + +static inline fr_dhcpv4_attr_flags_t const *fr_dhcpv4_attr_flags(fr_dict_attr_t const *da) +{ + return fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_PROTOCOL_SPECIFIC); +} + +#define fr_dhcpv4_flag_dns_label(_da) (fr_dhcpv4_attr_flags(_da)->dns_label) +#define fr_dhcpv4_flag_exists(_da) (fr_dhcpv4_attr_flags(_da)->exists) + +#define fr_dhcpv4_flag_prefix(_da) fr_dhcpv4_attr_flags(_da)->prefix +#define fr_dhcpv4_flag_prefix_bits(_da) (fr_dhcpv4_attr_flags(_da)->prefix == DHCPV4_FLAG_PREFIX_BITS) +#define fr_dhcpv4_flag_prefix_split(_da) (fr_dhcpv4_attr_flags(_da)->prefix == DHCPV4_FLAG_PREFIX_SPLIT) + /* * base.c */ diff --git a/src/protocols/dhcpv4/encode.c b/src/protocols/dhcpv4/encode.c index 224d4b646bf..804aa699298 100644 --- a/src/protocols/dhcpv4/encode.c +++ b/src/protocols/dhcpv4/encode.c @@ -102,14 +102,14 @@ static ssize_t encode_value(fr_dbuff_t *dbuff, * Rapid-Commit does this. Options 19/20 require encoding as one byte of 0/1. */ case FR_TYPE_BOOL: - if (da_is_bool_exists(vp->da)) { + if (fr_dhcpv4_flag_exists(vp->da)) { break; } FR_DBUFF_IN_RETURN(&work_dbuff, (uint8_t) (vp->vp_bool == true)); break; case FR_TYPE_IPV4_PREFIX: - if (da_is_split_prefix(vp->da)) { + if (fr_dhcpv4_flag_prefix_split(vp->da)) { uint32_t mask; mask = ~((~(uint32_t) 0) >> vp->vp_ip.prefix); @@ -121,7 +121,7 @@ static ssize_t encode_value(fr_dbuff_t *dbuff, break; } - if (da_is_bits_prefix(vp->da)) { + if (fr_dhcpv4_flag_prefix_bits(vp->da)) { size_t num_bytes = (vp->vp_ip.prefix + 0x07) >> 3; FR_DBUFF_IN_RETURN(&work_dbuff, (uint8_t) vp->vp_ip.prefix); @@ -144,7 +144,7 @@ static ssize_t encode_value(fr_dbuff_t *dbuff, * * https://tools.ietf.org/html/rfc8415#section-10 */ - if (da_is_dns_label(da)) { + if (fr_dhcpv4_flag_dns_label(da)) { fr_dbuff_marker_t last_byte, src; fr_dbuff_marker(&last_byte, &work_dbuff);