summaryrefslogtreecommitdiff
path: root/relay
diff options
context:
space:
mode:
authorThomas Markwalder <tmark@isc.org>2016-02-10 07:20:03 -0500
committerThomas Markwalder <tmark@isc.org>2016-02-10 07:20:03 -0500
commit6e7e6637ac8d94a0f230a3dd37e1a83f7ea2847b (patch)
tree8e0616cd3b4ec62d42ba139319e71e583bf89f52 /relay
parent3c16abe68152d0e2c208ca61b84d95664b712748 (diff)
downloadisc-dhcp-6e7e6637ac8d94a0f230a3dd37e1a83f7ea2847b.tar.gz
[master] Add link selection suboption support to dhcrelay (RFC 3527)
Merges in rt34875.
Diffstat (limited to 'relay')
-rw-r--r--relay/dhcrelay.835
-rw-r--r--relay/dhcrelay.c47
2 files changed, 79 insertions, 3 deletions
diff --git a/relay/dhcrelay.8 b/relay/dhcrelay.8
index d3f4593b..3c2a81e4 100644
--- a/relay/dhcrelay.8
+++ b/relay/dhcrelay.8
@@ -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
diff --git a/relay/dhcrelay.c b/relay/dhcrelay.c
index e50032b8..88a0b47a 100644
--- a/relay/dhcrelay.c
+++ b/relay/dhcrelay.c
@@ -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) "