]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Determine the address to be used to identify client subnet
authorNick Porter <nick@portercomputing.co.uk>
Tue, 15 Sep 2020 12:00:14 +0000 (13:00 +0100)
committerAlan DeKok <aland@freeradius.org>
Thu, 24 Sep 2020 14:22:07 +0000 (10:22 -0400)
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.

src/protocols/dhcpv4/attrs.h
src/protocols/dhcpv4/base.c
src/protocols/dhcpv4/packet.c

index 6a0686b8e871217f20d515f7e8ba46ee1bdca3b6..f05fbe211a215a95e1b60aadcb72de10211727f4 100644 (file)
@@ -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;
index e1e7b7d56b1a8d14391c7008700e4f0ee441c22a..080e4f22b6dc4fcfb5467889c823c01daefd429a 100644 (file)
@@ -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 }
 };
 
index d8dd63ff6cc05c20d4e6a734dd0f7a529bc8b166..2bd1f504de2a06975bd3859b79802d8524664f24 100644 (file)
@@ -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.