]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
[master] Add link selection suboption support to dhcrelay (RFC 3527)
authorThomas Markwalder <tmark@isc.org>
Wed, 10 Feb 2016 12:20:03 +0000 (07:20 -0500)
committerThomas Markwalder <tmark@isc.org>
Wed, 10 Feb 2016 12:20:03 +0000 (07:20 -0500)
    Merges in rt34875.

RELNOTES
relay/dhcrelay.8
relay/dhcrelay.c

index aa7d0419ba9f29d6a6f1f4bfc024ff419c107ca9..d8c9cfba28bad6ef65f8e54b6c8a18672d62cc93 100644 (file)
--- a/RELNOTES
+++ b/RELNOTES
@@ -212,6 +212,12 @@ by Eric Young (eay@cryptsoft.com).
   feature.
   [ISC-Bugs #39262]
 
+- Add support for RFC 3527 to dhcrelay.  A new, dhcrelay command line argument,
+  "-l <interface>" enables the addition of a RFC 3527 compliant link selection
+  suboption to the agent option added for clients directly connected to the
+  relay.
+  [ISC-Bugs #34875]
+
                        Changes since 4.3.3b1
 
 - None
index d3f4593b9e6f7b2593bd3d3c5990c55959f24956..3c2a81e42c1b0477a5486d6f9298d093761ed647 100644 (file)
@@ -1,6 +1,6 @@
 .\"    dhcrelay.8
 .\"
-.\" Copyright (c) 2009-2013 by Internet Systems Consortium, Inc. ("ISC")
+.\" Copyright (c) 2009-2013,2016 by Internet Systems Consortium, Inc. ("ISC")
 .\" Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC")
 .\" Copyright (c) 1997-2003 by Internet Software Consortium
 .\"
@@ -78,6 +78,8 @@ dhcrelay - Dynamic Host Configuration Protocol Relay Agent
 .B -i
 .I interfaceN 
 ]
+.B -l
+.I interface
 ]
 .I server0
 [
@@ -215,8 +217,37 @@ in four ways:  It may \fIappend\fR its own set of relay options to the
 packet, leaving the supplied option field intact; it may \fIreplace\fR the
 existing agent option field; it may \fIforward\fR the packet unchanged; or,
 it may \fIdiscard\fR it.
+.TP
+-u \fIifname\fR
+Enables the addition of a RFC 3527 compliant link selection suboption for
+clients directly connected to the relay.  This RFC allows a relay to
+specify two different IP addresses: one for the server to use when
+communicating with the relay (giaddr) the other for choosing the subnet
+for the client (the suboption).  This can be useful if the server is
+unable to send packets to the relay via the address used for the subnet.
+
+When enabled, dhcrelay will add an agent option (as per \fB-a\fR above) that
+includes the link selection suboption to the forwarded packet.  This will only
+be done to packets received from clients that are directly connected to the
+relay (i.e. giaddr is zero).  The address used in the suboption will be that
+of the link upon which the inbound packet was received (which would otherwise
+be used for giaddr). The value of giaddr will be set to that of interface
+\fIifname\fR.
+
+Only one interface should be marked in this fashion.  Currently enabling
+this option on an interface causes the relay to process all DHCP traffic
+similar to the \fI-i\fR option, in the future we may split the two more
+completely.
+
+This option is off by default.  Note that enabling this option automatically
+enables the \fB-a\fR option.
+
+Keep in mind that using options such as \fB-m replace\fR or \fB-m discard\fR
+on relays upstream from one using \fB-u\fR can pose problems.  The upstream
+relay will wipe out the initial agent option containing the link selection
+while leaving the re-purposed giaddr value in place, causing packets to go
+astray.
 
-To use this option you must also enable the \fB-a\fR option.
 .PP
 \fIOptions available in DHCPv6 mode only:\fR
 .TP
index e50032b8a9035d99abba9460c4edc474d9be6953..88a0b47ab855978c20f52cb768550da07abd3a13 100644 (file)
@@ -61,6 +61,7 @@ int server_packets_relayed = 0;       /* Packets relayed from server to client. */
 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. */
@@ -100,6 +101,8 @@ struct server_list {
        struct sockaddr_in to;
 } *servers;
 
+struct interface_info *uplink;
+
 #ifdef DHCPv6
 struct stream_list {
        struct stream_list *next;
@@ -150,6 +153,7 @@ char *progname;
 "                     [-pf <pid-file>] [--no-pid]\n"\
 "                     [-m append|replace|forward|discard]\n" \
 "                     [-i interface0 [ ... -i interfaceN]\n" \
+"                     [-u interface]\n" \
 "                     server0 [ ... serverN]\n\n" \
 "       %s -6   [-d] [-q] [-I] [-c <hops>] [-p <port>]\n" \
 "                     [-pf <pid-file>] [--no-pid]\n" \
@@ -164,6 +168,7 @@ char *progname;
 "                [-pf <pid-file>] [--no-pid]\n" \
 "                [-m append|replace|forward|discard]\n" \
 "                [-i interface0 [ ... -i interfaceN]\n" \
+"                [-u interface]\n" \
 "                server0 [ ... serverN]\n\n"
 #endif
 
@@ -368,6 +373,23 @@ main(int argc, char **argv) {
                                agent_relay_mode = discard;
                        } else
                                usage("Unknown argument to -m: %s", argv[i]);
+               } else if (!strcmp(argv [i], "-u")) {
+                       if (++i == argc)
+                               usage(use_noarg, argv[i-1]);
+
+                       /* Allocate the uplink interface */
+                       status = interface_allocate(&uplink, MDL);
+                       if (status != ISC_R_SUCCESS) {
+                               log_fatal("%s: uplink interface_allocate: %s",
+                                        argv[i], isc_result_totext(status));
+                       }
+
+                       strcpy(uplink->name, argv[i]);
+                       interface_snorf(uplink, INTERFACE_REQUESTED);
+
+                       /* Turn on -a, in case they don't do so explicitly */
+                       add_agent_options = 1;
+                       add_rfc3527_suboption = 1;
                } else if (!strcmp(argv[i], "-D")) {
 #ifdef DHCPv6
                        if (local_family_set && (local_family == AF_INET6)) {
@@ -753,7 +775,8 @@ do_relay4(struct interface_info *ip, struct dhcp_packet *packet,
                return;
 
        /* Add relay agent options if indicated.   If something goes wrong,
-          drop the packet. */
+        * drop the packet.  Note this may set packet->giaddr if RFC3527
+        * is enabled. */
        if (!(length = add_relay_agent_options(ip, packet, length,
                                               ip->addresses[0])))
                return;
@@ -995,6 +1018,7 @@ add_relay_agent_options(struct interface_info *ip, struct dhcp_packet *packet,
        int is_dhcp = 0, mms;
        unsigned optlen;
        u_int8_t *op, *nextop, *sp, *max, *end_pad = NULL;
+       int adding_link_select;
 
        /* If we're not adding agent options to packets, we can skip
           this. */
@@ -1008,6 +1032,10 @@ add_relay_agent_options(struct interface_info *ip, struct dhcp_packet *packet,
 
        max = ((u_int8_t *)packet) + dhcp_max_agent_option_packet_length;
 
+       /* Add link selection suboption if enabled and we're the first relay */
+       adding_link_select = (add_rfc3527_suboption
+                             && (packet->giaddr.s_addr == 0));
+
        /* Commence processing after the cookie. */
        sp = op = &packet->options[4];
 
@@ -1137,6 +1165,10 @@ add_relay_agent_options(struct interface_info *ip, struct dhcp_packet *packet,
                optlen += ip->remote_id_len + 2;    /* RAI_REMOTE_ID + len */
        }
 
+       if (adding_link_select) {
+               optlen += 6;
+       }
+
        /* We do not support relay option fragmenting(multiple options to
         * support an option data exceeding 255 bytes).
         */
@@ -1168,6 +1200,19 @@ add_relay_agent_options(struct interface_info *ip, struct dhcp_packet *packet,
                        memcpy(sp, ip->remote_id, ip->remote_id_len);
                        sp += ip->remote_id_len;
                }
+
+               /* RFC3527: Use the inbound packet's interface address in
+                * the link selection suboption and set the outbound giaddr
+                * to the uplink address. */
+               if (adding_link_select) {
+                       *sp++ = RAI_LINK_SELECT;
+                       *sp++ = 4u;
+                       memcpy(sp, &giaddr.s_addr, 4);
+                       sp += 4;
+                       packet->giaddr = uplink->addresses[0];
+                       log_debug ("Adding link selection suboption"
+                                  " with addr: %s", inet_ntoa(giaddr));
+               }
        } else {
                ++agent_option_errors;
                log_error("No room in packet (used %d of %d) "