RFC3527 link selection sub-option is used to select the "uplink" interface of
dhcrelay in cases where the DHCP server does not know how to reach the dhcrelay
based on the DHCP range. This can happen in weird network configurations like
Mesh networks.

Signed-off-by: Bruno Randolf <b...@einfach.org>
---
 net/isc-dhcp/Makefile                              |   2 +-
 net/isc-dhcp/files/dhcrelay.config                 |   4 +
 net/isc-dhcp/files/dhcrelay.init                   |   8 ++
 .../patches/100-relay-rfc3527-link-selection.patch | 100 +++++++++++++++++++++
 4 files changed, 113 insertions(+), 1 deletion(-)
 create mode 100644 net/isc-dhcp/patches/100-relay-rfc3527-link-selection.patch

diff --git a/net/isc-dhcp/Makefile b/net/isc-dhcp/Makefile
index d3aa397..4d0bd5e 100644
--- a/net/isc-dhcp/Makefile
+++ b/net/isc-dhcp/Makefile
@@ -10,7 +10,7 @@ include $(TOPDIR)/rules.mk
 PKG_NAME:=isc-dhcp
 UPSTREAM_NAME:=dhcp
 PKG_VERSION:=4.2.4
-PKG_RELEASE:=3
+PKG_RELEASE:=4
 
 PKG_SOURCE:=$(UPSTREAM_NAME)-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=ftp://ftp.isc.org/isc/dhcp/$(PKG_VERSION)
diff --git a/net/isc-dhcp/files/dhcrelay.config 
b/net/isc-dhcp/files/dhcrelay.config
index a303a60..06111a7 100644
--- a/net/isc-dhcp/files/dhcrelay.config
+++ b/net/isc-dhcp/files/dhcrelay.config
@@ -13,3 +13,7 @@ config 'dhcrelay'
        # 'forward': Forward without changes
        # 'discard': Don't forward
        option 'relay_mode' ''
+
+       # enable RFC3527 link selection sub-option and use the IP address of
+       # the specified network interface as "uplink" IP address (e.g. wan)
+       option 'link_selection' ''
diff --git a/net/isc-dhcp/files/dhcrelay.init b/net/isc-dhcp/files/dhcrelay.init
index e66d34b..9c11a2d 100755
--- a/net/isc-dhcp/files/dhcrelay.init
+++ b/net/isc-dhcp/files/dhcrelay.init
@@ -24,6 +24,14 @@ dhcrelay_start() {
                return 0
        fi
 
+       # link selection sub-option (RFC3527)
+       local link_selection
+       config_get link_selection "$cfg" link_selection
+       if [ -n "$link_selection" ]; then
+               config_get ifname "$link_selection" ifname
+               append args "-l $ifname"
+       fi
+
        # relay mode
        local relay_mode
        config_get relay_mode "$cfg" relay_mode
diff --git a/net/isc-dhcp/patches/100-relay-rfc3527-link-selection.patch 
b/net/isc-dhcp/patches/100-relay-rfc3527-link-selection.patch
new file mode 100644
index 0000000..1f593ee
--- /dev/null
+++ b/net/isc-dhcp/patches/100-relay-rfc3527-link-selection.patch
@@ -0,0 +1,100 @@
+--- a/relay/dhcrelay.c
++++ b/relay/dhcrelay.c
+@@ -65,6 +65,7 @@ int server_packets_relayed = 0;      /* Packe
+ int client_packet_errors = 0; /* Errors sending packets to clients. */
+ 
+ int add_agent_options = 0;    /* If nonzero, add relay agent options. */
++int add_rfc3527_suboption = 0;        /* If nonzero, add RFC3527 link 
selection sub-option. */
+ 
+ int agent_option_errors = 0;    /* Number of packets forwarded without
+                                  agent options because there was no room. */
+@@ -104,6 +105,8 @@ struct server_list {
+       struct sockaddr_in to;
+ } *servers;
+ 
++struct interface_info *uplink;
++
+ #ifdef DHCPv6
+ struct stream_list {
+       struct stream_list *next;
+@@ -144,6 +147,7 @@ static const char url[] =
+ "                     [-pf <pid-file>] [--no-pid]\n"\
+ "                     [-m append|replace|forward|discard]\n" \
+ "                     [-i interface0 [ ... -i interfaceN]\n" \
++"                     [-l interface]\n" \
+ "                     server0 [ ... serverN]\n\n" \
+ "       dhcrelay -6   [-d] [-q] [-I] [-c <hops>] [-p <port>]\n" \
+ "                     [-pf <pid-file>] [--no-pid]\n"\
+@@ -157,6 +161,7 @@ static const char url[] =
+ "                [-pf <pid-file>] [--no-pid]\n"\
+ "                [-m append|replace|forward|discard]\n" \
+ "                [-i interface0 [ ... -i interfaceN]\n" \
++"                [-l interface]\n" \
+ "                server0 [ ... serverN]\n\n"
+ #endif
+ 
+@@ -314,6 +319,20 @@ main(int argc, char **argv) {
+                               agent_relay_mode = discard;
+                       } else
+                               usage();
++              } else if (!strcmp (argv [i], "-l")) {
++                      add_agent_options = 1;
++                      add_rfc3527_suboption = 1;
++                      if (++i == argc)
++                              usage();
++
++                      status = interface_allocate(&uplink, MDL);
++                      if (status != ISC_R_SUCCESS)
++                              log_fatal("%s: interface_allocate: %s",
++                                        argv[i],
++                                        isc_result_totext(status));
++                      strcpy(uplink->name, argv[i]);
++                      interface_snorf(uplink, INTERFACE_REQUESTED);
++                      //interface_dereference(&uplink, MDL);
+               } else if (!strcmp(argv[i], "-D")) {
+ #ifdef DHCPv6
+                       if (local_family_set && (local_family == AF_INET6)) {
+@@ -685,12 +704,17 @@ do_relay4(struct interface_info *ip, str
+                                              ip->addresses[0])))
+               return;
+ 
++      /* RFC3527: Replace giaddr address by uplink address. The original
++       * giaddr will be used in the link selection sub-option */
++      if (add_rfc3527_suboption)
++              packet->giaddr = uplink->addresses[0];
++
+       /* If giaddr is not already set, Set it so the server can
+          figure out what net it's from and so that we can later
+          forward the response to the correct net.    If it's already
+          set, the response will be sent directly to the relay agent
+          that set giaddr, so we won't see it. */
+-      if (!packet->giaddr.s_addr)
++      else if (!packet->giaddr.s_addr)
+               packet->giaddr = ip->addresses[0];
+       if (packet->hops < max_hop_count)
+               packet->hops = packet->hops + 1;
+@@ -1062,6 +1086,9 @@ add_relay_agent_options(struct interface
+               optlen += ip->remote_id_len + 2;    /* RAI_REMOTE_ID + len */
+       }
+ 
++      if (add_rfc3527_suboption)
++              optlen += 6;
++
+       /* We do not support relay option fragmenting(multiple options to
+        * support an option data exceeding 255 bytes).
+        */
+@@ -1093,6 +1120,14 @@ add_relay_agent_options(struct interface
+                       memcpy(sp, ip->remote_id, ip->remote_id_len);
+                       sp += ip->remote_id_len;
+               }
++
++              if (add_rfc3527_suboption) {
++                      *sp++ = RAI_LINK_SELECT;
++                      *sp++ = 4u;
++                      memcpy(sp, &giaddr.s_addr, 4);
++                      sp += 4;
++                      log_debug ("RFC3527 link selection sub-option added: 
%s", inet_ntoa(giaddr));
++              }
+       } else {
+               ++agent_option_errors;
+               log_error("No room in packet (used %d of %d) "
-- 
1.8.1.2
_______________________________________________
openwrt-devel mailing list
openwrt-devel@lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel

Reply via email to