From: Alan T. DeKok Date: Wed, 16 Mar 2022 13:37:01 +0000 (-0400) Subject: add fr_dhcpv4_attr_sizes[] and fr_dhcpv4_option_len() X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=023237db13e2278515e41d728fbbfd3c2aa53d7b;p=thirdparty%2Ffreeradius-server.git add fr_dhcpv4_attr_sizes[] and fr_dhcpv4_option_len() --- diff --git a/src/protocols/dhcpv4/base.c b/src/protocols/dhcpv4/base.c index 00a0a9b2096..724b4a13b1e 100644 --- a/src/protocols/dhcpv4/base.c +++ b/src/protocols/dhcpv4/base.c @@ -97,6 +97,31 @@ fr_dict_attr_autoload_t dhcpv4_dict_attr[] = { { NULL } }; +size_t const fr_dhcpv4_attr_sizes[FR_TYPE_MAX + 1][2] = { + [FR_TYPE_NULL] = {~0, 0}, + + [FR_TYPE_STRING] = {0, ~0}, + [FR_TYPE_OCTETS] = {0, ~0}, + + [FR_TYPE_IPV4_ADDR] = {4, 4}, + [FR_TYPE_IPV4_PREFIX] = {1, 5}, //!< Zero length prefix still requires one byte for prefix len. + [FR_TYPE_IPV6_ADDR] = {16, 16}, + [FR_TYPE_IPV6_PREFIX] = {1, 17}, //!< Zero length prefix still requires one byte for prefix len. + [FR_TYPE_IFID] = {8, 8}, + [FR_TYPE_ETHERNET] = {6, 6}, + + [FR_TYPE_BOOL] = {1, 1}, + [FR_TYPE_UINT8] = {1, 1}, + [FR_TYPE_UINT16] = {2, 2}, + [FR_TYPE_UINT32] = {4, 4}, + [FR_TYPE_UINT64] = {8, 8}, + + [FR_TYPE_TLV] = {2, ~0}, + [FR_TYPE_STRUCT] = {1, ~0}, + + [FR_TYPE_MAX] = {~0, 0} //!< Ensure array covers all types. +}; + /* * INADDR_ANY : 68 -> INADDR_BROADCAST : 67 DISCOVER * INADDR_BROADCAST : 68 <- SERVER_IP : 67 OFFER @@ -201,6 +226,48 @@ int8_t fr_dhcpv4_attr_cmp(void const *a, void const *b) return fr_pair_cmp_by_parent_num(my_a, my_b); } +/** Return the on-the-wire length of an attribute value + * + * @param[in] vp to return the length of. + * @return the length of the attribute. + */ +size_t fr_dhcpv4_option_len(fr_pair_t const *vp) +{ + switch (vp->vp_type) { + case FR_TYPE_VARIABLE_SIZE: +#ifndef NDEBUG + if (!vp->da->flags.extra && + (vp->da->flags.subtype == FLAG_ENCODE_DNS_LABEL)) { + fr_assert_fail("DNS labels MUST be encoded/decoded with their own function, and not with generic 'string' functions"); + return 0; + } +#endif + + if (vp->da->flags.length) return vp->da->flags.length; /* Variable type with fixed length */ + + /* + * Arrays get maxed at 2^8 - 1 + */ + if (vp->da->flags.array && ((vp->vp_type == FR_TYPE_STRING) || (vp->vp_type == FR_TYPE_OCTETS))) { + if (vp->vp_length > 255) return 255; + } + + return vp->vp_length; + + case FR_TYPE_DATE: + case FR_TYPE_TIME_DELTA: + if (vp->data.enumv->flags.length) return vp->data.enumv->flags.length; + return sizeof(uint32_t); + + case FR_TYPE_STRUCTURAL: + fr_assert_fail(NULL); + return 0; + + default: + return fr_dhcpv4_attr_sizes[vp->vp_type][0]; + } +} + /** Check received DHCP request is valid and build fr_radius_packet_t structure if it is * * @param data pointer to received packet. diff --git a/src/protocols/dhcpv4/dhcpv4.h b/src/protocols/dhcpv4/dhcpv4.h index 7bf7cdd5d69..b2ed1b159c5 100644 --- a/src/protocols/dhcpv4/dhcpv4.h +++ b/src/protocols/dhcpv4/dhcpv4.h @@ -34,6 +34,8 @@ extern "C" { #include #include +extern size_t const fr_dhcpv4_attr_sizes[FR_TYPE_MAX + 1][2]; + #define DHCP_CHADDR_LEN (16) #define DHCP_SNAME_LEN (64) #define DHCP_FILE_LEN (128) @@ -151,6 +153,7 @@ typedef struct { */ int8_t fr_dhcpv4_attr_cmp(void const *a, void const *b); +size_t fr_dhcpv4_option_len(fr_pair_t const *vp); bool fr_dhcpv4_ok(uint8_t const *data, ssize_t data_len, uint8_t *message_type, uint32_t *xid); fr_radius_packet_t *fr_dhcpv4_packet_alloc(uint8_t const *data, ssize_t data_len); bool fr_dhcpv4_is_encodable(void const *item, void const *uctx);