aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjørn Mork <bjorn@mork.no>2011-09-24 12:22:01 +0200
committerBjørn Mork <bjorn@mork.no>2011-09-25 14:31:24 +0200
commit1e2c8407b40d4060407845c6f4e81dac8e5f39de (patch)
treeff419225478655408337d5b377b12d5415b84346
parentb744aea2ce6c579d8e5c34839e51ac239d716130 (diff)
dhcrelay: Support RFC6221 Lightweight DHCPv6 Relay Agent operation
There really isn't much required for layer2 operation. Just set the link address to :: and you're basically done. Signed-off-by: Bjørn Mork <bjorn@mork.no>
-rw-r--r--relay/dhcrelay.818
-rw-r--r--relay/dhcrelay.c28
2 files changed, 35 insertions, 11 deletions
diff --git a/relay/dhcrelay.8 b/relay/dhcrelay.8
index 06408a3..c4115cb 100644
--- a/relay/dhcrelay.8
+++ b/relay/dhcrelay.8
@@ -86,7 +86,7 @@ dhcrelay - Dynamic Host Configuration Protocol Relay Agent
.PP
.B dhcrelay -6
[
-.B -dqI
+.B -dqIL
]
[
.B -p
@@ -225,6 +225,15 @@ in use, to disambiguate between them. The \fB-I\fR option causes
dhcrelay to send the option even if there is only one downstream
interface.
.TP
+-L
+Enable Lightweight DHCPv6 Relay Agent (layer 2) operation according to
+RFC6221. This forces the \fB-I\fR option on, and uses the unspecified
+address (::) as link address in all relayed packets, enabling operation
+on a layer 2 brigde with no global address at all. Note that this
+option makes both the \fB-I\fR option and the \fIaddress%\fR parameter
+of the \fB-l\fR option redundant. Any configured \fIaddress%\fR will
+be silently ignored.
+.TP
-e \fIenterprisenumber\fR
Specifies the IANA allocated enterprise number to be used in REMOTE-ID
options. Required for adding REMOTE-ID
@@ -236,9 +245,10 @@ relay agents. At least one \fB-l\fR option must be included in the command
line when running in DHCPv6 mode. The interface name \fIifname\fR is a
mandatory parameter. The link address can be specified by \fIaddress%\fR;
if it isn't, dhcrelay will use the first non-link-local address configured
-on the interface. The optional \fI#index\fR parameter specifies the
-interface index. The optional \fI!remoteid\fR parameter specifies the
-ascii remote id value (requires the \fB-e\fR option as well).
+on the interface unless configured for LDRA with the \fB-L\fR option.
+The optional \fI#index\fR parameter specifies the interface index. The
+optional \fI!remoteid\fR parameter specifies the ascii remote id value
+(requires the \fB-e\fR option as well).
.TP
-u [\fIaddress%\fR]\fIifname\fR
Specifies the ``upper'' network interface for DHCPv6 relay mode: the
diff --git a/relay/dhcrelay.c b/relay/dhcrelay.c
index 780b59a..f00aa2f 100644
--- a/relay/dhcrelay.c
+++ b/relay/dhcrelay.c
@@ -83,6 +83,7 @@ int max_hop_count = 10; /* Maximum hop count */
#ifdef DHCPv6
/* Force use of DHCPv6 interface-id option. */
isc_boolean_t use_if_id = ISC_FALSE;
+isc_boolean_t rfc6221_ldra = ISC_FALSE; /* implement RFC6221 LDRA */
#endif
/* Maximum size of a packet with agent options added. */
@@ -150,7 +151,7 @@ static const char url[] =
" [-m append|replace|forward|discard]\n" \
" [-i interface0 [ ... -i interfaceN]\n" \
" server0 [ ... serverN]\n\n" \
-" dhcrelay -6 [-d] [-q] [-I] [-c <hops>] [-p <port>]\n" \
+" dhcrelay -6 [-d] [-q] [-I] [-L] [-c <hops>] [-p <port>]\n" \
" [-pf <pid-file>] [--no-pid]\n"\
" -e <enterprisenumber>\n"\
" -l lower0 [ ... -l lowerN]\n" \
@@ -337,6 +338,14 @@ main(int argc, char **argv) {
local_family_set = 1;
local_family = AF_INET6;
use_if_id = ISC_TRUE;
+ } else if (!strcmp(argv[i], "-L")) {
+ if (local_family_set && (local_family == AF_INET)) {
+ usage();
+ }
+ local_family_set = 1;
+ local_family = AF_INET6;
+ rfc6221_ldra = ISC_TRUE;
+ use_if_id = ISC_TRUE; /* required by RFC6221 */
} else if (!strcmp(argv[i], "-e")) {
if (local_family_set && (local_family == AF_INET)) {
usage();
@@ -1223,8 +1232,9 @@ parse_downstream(char *arg) {
dp->ifp->remote_id_len = sizeof(int) + strlen(rid);
}
/* !addr case handled by setup. */
- if (addr && (inet_pton(AF_INET6, addr, &dp->link.sin6_addr) <= 0))
- log_fatal("Bad link address '%s'", addr);
+ if (!rfc6221_ldra && /* silently ignore any addr for LDRA */
+ addr && (inet_pton(AF_INET6, addr, &dp->link.sin6_addr) <= 0))
+ log_fatal("Bad link address '%s'", addr);
return dp;
}
@@ -1304,6 +1314,14 @@ setup_streams(void) {
isc_boolean_t link_is_set;
for (dp = downstreams; dp; dp = dp->next) {
+ /* Set interface-id. */
+ if (dp->id == -1)
+ dp->id = htonl(dp->ifp->index);
+
+ /* link address must be :: for LDRA according to RFC6221 */
+ if (rfc6221_ldra)
+ continue;
+
/* Check interface */
if (dp->ifp->v6address_count == 0)
log_fatal("Interface '%s' has no IPv6 addresses.",
@@ -1331,10 +1349,6 @@ setup_streams(void) {
memcpy(&dp->link.sin6_addr,
&dp->ifp->v6addresses[i],
sizeof(dp->link.sin6_addr));
-
- /* Set interface-id. */
- if (dp->id == -1)
- dp->id = htonl(dp->ifp->index);
}
for (up = upstreams; up; up = up->next) {