From: Nick Porter Date: Tue, 15 Sep 2020 12:00:14 +0000 (+0100) Subject: Determine the address to be used to identify client subnet X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=aedfb5d3bddad5036f2c19dc0c7b177fb4acdb7a;p=thirdparty%2Ffreeradius-server.git Determine the address to be used to identify client subnet After parsing the DHCP packet, check Relay-Link-Selection option, Subnet-Selection-Option option then giaddr and finally ciaddr to determine address to lookup client's subnet. --- diff --git a/src/protocols/dhcpv4/attrs.h b/src/protocols/dhcpv4/attrs.h index 6a0686b8e87..f05fbe211a2 100644 --- a/src/protocols/dhcpv4/attrs.h +++ b/src/protocols/dhcpv4/attrs.h @@ -49,3 +49,6 @@ extern fr_dict_attr_t const *attr_dhcp_message_type; extern fr_dict_attr_t const *attr_dhcp_parameter_request_list; extern fr_dict_attr_t const *attr_dhcp_overload; extern fr_dict_attr_t const *attr_dhcp_vendor_class_identifier; +extern fr_dict_attr_t const *attr_dhcp_relay_link_selection; +extern fr_dict_attr_t const *attr_dhcp_subnet_selection_option; +extern fr_dict_attr_t const *attr_dhcp_network_ip_address; diff --git a/src/protocols/dhcpv4/base.c b/src/protocols/dhcpv4/base.c index e1e7b7d56b1..080e4f22b6d 100644 --- a/src/protocols/dhcpv4/base.c +++ b/src/protocols/dhcpv4/base.c @@ -66,6 +66,9 @@ fr_dict_attr_t const *attr_dhcp_message_type; fr_dict_attr_t const *attr_dhcp_parameter_request_list; fr_dict_attr_t const *attr_dhcp_overload; fr_dict_attr_t const *attr_dhcp_vendor_class_identifier; +fr_dict_attr_t const *attr_dhcp_relay_link_selection; +fr_dict_attr_t const *attr_dhcp_subnet_selection_option; +fr_dict_attr_t const *attr_dhcp_network_ip_address; extern fr_dict_attr_autoload_t dhcpv4_dict_attr[]; fr_dict_attr_autoload_t dhcpv4_dict_attr[] = { @@ -89,6 +92,9 @@ fr_dict_attr_autoload_t dhcpv4_dict_attr[] = { { .out = &attr_dhcp_parameter_request_list, .name = "DHCP-Parameter-Request-List", .type = FR_TYPE_UINT8, .dict = &dict_dhcpv4 }, { .out = &attr_dhcp_overload, .name = "DHCP-Overload", .type = FR_TYPE_UINT8, .dict = &dict_dhcpv4 }, { .out = &attr_dhcp_vendor_class_identifier, .name = "DHCP-Vendor-Class-Identifier", .type = FR_TYPE_OCTETS, .dict = &dict_dhcpv4 }, + { .out = &attr_dhcp_relay_link_selection, .name = "DHCP-Relay-Link-Selection", .type = FR_TYPE_IPV4_ADDR, .dict = &dict_dhcpv4 }, + { .out = &attr_dhcp_subnet_selection_option, .name = "DHCP-Subnet-Selection-Option", .type = FR_TYPE_IPV4_ADDR, .dict = &dict_dhcpv4 }, + { .out = &attr_dhcp_network_ip_address, .name = "DHCP-Network-IP-Address", .type = FR_TYPE_IPV4_ADDR, .dict = &dict_dhcpv4 }, { NULL } }; diff --git a/src/protocols/dhcpv4/packet.c b/src/protocols/dhcpv4/packet.c index d8dd63ff6cc..2bd1f504de2 100644 --- a/src/protocols/dhcpv4/packet.c +++ b/src/protocols/dhcpv4/packet.c @@ -110,7 +110,7 @@ int fr_dhcpv4_decode(TALLOC_CTX *ctx, uint8_t const *data, size_t data_len, VALU uint32_t giaddr; fr_cursor_t cursor; VALUE_PAIR *head = NULL, *vp; - VALUE_PAIR *maxms, *mtu; + VALUE_PAIR *maxms, *mtu, *netaddr; fr_cursor_init(&cursor, &head); @@ -298,6 +298,46 @@ int fr_dhcpv4_decode(TALLOC_CTX *ctx, uint8_t const *data, size_t data_len, VALU } } + /* + * Determine the address to use in looking up which subnet the + * client belongs to based on packet data. The sequence here + * is based on ISC DHCP behaviour and RFCs 3527 and 3011. We + * store the found address in an internal attribute of + * DHCP-Network-IP-Address. + */ + vp = fr_pair_afrom_da(ctx, attr_dhcp_network_ip_address); + /* + * First look for Relay-Link-Selection + */ + netaddr = fr_pair_find_by_da(head, attr_dhcp_relay_link_selection); + if (!netaddr) { + /* + * Next try Subnet-Selection-Option + */ + netaddr = fr_pair_find_by_da(head, attr_dhcp_subnet_selection_option); + } + if (!netaddr) { + if (giaddr != htonl(INADDR_ANY)) { + /* + * Gateway address is set - use that one + */ + fr_value_box_from_network(vp, &vp->data, vp->vp_type, vp->da, + data + 24, 4, true); + } else { + /* + * else, store client address whatever it is + */ + fr_value_box_from_network(vp, &vp->data, vp->vp_type, vp->da, + data + 12, 4, true); + } + } else { + /* + * Store whichever address we found from options + */ + fr_value_box_copy(vp, &vp->data, &netaddr->data); + } + fr_cursor_append(&cursor, vp); + /* * Client can request a LARGER size, but not a smaller * one. They also cannot request a size larger than MTU.