diff options
-rw-r--r-- | .gitignore | 16 | ||||
-rw-r--r-- | relay/dhcrelay.8 | 28 | ||||
-rw-r--r-- | relay/dhcrelay.c | 147 |
3 files changed, 142 insertions, 49 deletions
@@ -6,7 +6,19 @@ *.la *.so *.lai +*.tmp +*.log .libs -.depends -config.log +.deps config.status +Makefile +stamp-h1 +includes/config.h +bind/bind-9.8.0-P4 +bind/include +client/dhclient +dhcpctl/cltest +dhcpctl/omshell +omapip/svtest +relay/dhcrelay +server/dhcpd diff --git a/relay/dhcrelay.8 b/relay/dhcrelay.8 index a087d14..1a0e90f 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 @@ -103,6 +103,10 @@ dhcrelay - Dynamic Host Configuration Protocol Relay Agent [ .B --no-pid ] +[ +.B -e +.I enterprisenumber +] .B -l .I lower0 [ @@ -221,15 +225,31 @@ 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 [\fIaddress%\fR]\fIifname\fR[\fI#index\fR] +-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 +.TP +-l [\fIaddress%\fR]\fIifname\fR[\fI#index\fR][\fI!remoteid\fR][\fI&subscriberid\fR] Specifies the ``lower'' network interface for DHCPv6 relay mode: the interface on which queries will be received from clients or from other 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. +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). The optional \fI&subscriberid\fR +parameter enables adding a subscriber-id option. .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 7b3909e..812f838 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. */ @@ -105,6 +106,11 @@ struct server_list { } *servers; #ifdef DHCPv6 +int enterprise_number = 0; /* enterprise-number for use with remote-id */ +struct remote_id { + int enterprise; + char id[]; +}; struct stream_list { struct stream_list *next; struct interface_info *ifp; @@ -145,11 +151,12 @@ 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" \ " -u upper0 [ ... -u upperN]\n" \ -" lower (client link): [address%%]interface[#index]\n" \ +" lower (client link): [address%%]interface[#index][!remoteid][&subscriberid]\n" \ " upper (server link): [address%%]interface" #else #define DHCRELAY_USAGE \ @@ -331,6 +338,23 @@ 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(); + } + local_family_set = 1; + local_family = AF_INET6; + if (++i == argc) + usage(); + enterprise_number = atoi(argv[i]); } else if (!strcmp(argv[i], "-l")) { if (local_family_set && (local_family == AF_INET)) { usage(); @@ -1123,13 +1147,13 @@ add_relay_agent_options(struct interface_info *ip, struct dhcp_packet *packet, #ifdef DHCPv6 /* - * Parse a downstream argument: [address%]interface[#index]. + * Parse a downstream argument: [address%]interface[#index][!remoteid][&subscriberid]. */ static struct stream_list * parse_downstream(char *arg) { struct stream_list *dp, *up; struct interface_info *ifp = NULL; - char *ifname, *addr, *iid; + char *ifname, *addr, *iid, *rid, *sid; isc_result_t status; if (!supports_multiple_interfaces(ifp) && @@ -1145,6 +1169,14 @@ parse_downstream(char *arg) { *ifname++ = '\0'; addr = arg; } + sid = strchr(ifname, '&'); + if (sid != NULL) { + *sid++ = '\0'; + } + rid = strchr(ifname, '!'); + if (rid != NULL) { + *rid++ = '\0'; + } iid = strchr(ifname, '#'); if (iid != NULL) { *iid++ = '\0'; @@ -1192,13 +1224,26 @@ parse_downstream(char *arg) { log_fatal("No memory for downstream."); dp->ifp = ifp; if (iid != NULL) { - dp->id = atoi(iid); + dp->id = htonl(atoi(iid)); } else { dp->id = -1; } + if ((rid != NULL) && ((rid - sizeof(int)) >= arg)) { + struct remote_id *remote_id; + remote_id = (struct remote_id *) (rid - sizeof(int)); + remote_id->enterprise = htonl(enterprise_number); + dp->ifp->remote_id = (u_int8_t *) remote_id; + dp->ifp->remote_id_len = sizeof(int) + strlen(rid); + } + /* we're overloading the circuit_id option */ + if (sid != NULL) { + ifp->circuit_id = (u_int8_t *) sid; + ifp->circuit_id_len = strlen(sid); + } /* !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; } @@ -1262,6 +1307,10 @@ parse_upstream(char *arg) { up->ifp = ifp; + /* RFC6221 requires dst = All_DHCP_Relay_Agents_and_Servers. ignore any configured address */ + if (rfc6221_ldra) + addr = All_DHCP_Relay_Agents_and_Servers; + if (inet_pton(AF_INET6, addr, &up->link.sin6_addr) <= 0) log_fatal("Bad address %s", addr); @@ -1278,6 +1327,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.", @@ -1305,10 +1362,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 = dp->ifp->index; } for (up = upstreams; up; up = up->next) { @@ -1329,6 +1382,8 @@ setup_streams(void) { */ static const int required_forw_opts[] = { D6O_INTERFACE_ID, + D6O_REMOTE_ID, + D6O_SUBSCRIBER_ID, D6O_RELAY_MSG, 0 }; @@ -1414,40 +1469,46 @@ process_up6(struct packet *packet, struct stream_list *dp) { if (!option_state_allocate(&opts, MDL)) { log_fatal("No memory for upwards options."); } - - /* Add an interface-id (if used). */ - if (use_if_id) { - int if_id; - if (dp) { - if_id = dp->id; - } else if (!downstreams->next) { - if_id = downstreams->id; - } else { - log_info("Don't know the interface."); - option_state_dereference(&opts, MDL); - return; - } + /* we need a specific interface for relay options */ + if (!dp && !downstreams->next) /* only one downstream? */ + dp = downstreams; - if (!save_option_buffer(&dhcpv6_universe, opts, - NULL, (unsigned char *) &if_id, - sizeof(int), - D6O_INTERFACE_ID, 0)) { - log_error("Can't save interface-id."); - option_state_dereference(&opts, MDL); - return; - } + if (!dp && use_if_id) { +opt_error: + log_info("Can't save option."); + option_state_dereference(&opts, MDL); + return; } + /* Add an interface-id (if used). */ + if (use_if_id && !save_option_buffer(&dhcpv6_universe, opts, + NULL, (unsigned char *) &dp->id, + sizeof(int), + D6O_INTERFACE_ID, 0)) + goto opt_error; + + /* add remote id */ + if (dp->ifp->remote_id && !save_option_buffer(&dhcpv6_universe, opts, + NULL, dp->ifp->remote_id, + dp->ifp->remote_id_len, + D6O_REMOTE_ID, 0)) + goto opt_error; + + /* add subscriber id */ + if (dp->ifp->circuit_id && + !save_option_buffer(&dhcpv6_universe, opts, + NULL, dp->ifp->circuit_id, + dp->ifp->circuit_id_len, + D6O_SUBSCRIBER_ID, 0)) + goto opt_error; + /* Add the relay-msg carrying the packet. */ if (!save_option_buffer(&dhcpv6_universe, opts, NULL, (unsigned char *) packet->raw, packet->packet_length, - D6O_RELAY_MSG, 0)) { - log_error("Can't save relay-msg."); - option_state_dereference(&opts, MDL); - return; - } + D6O_RELAY_MSG, 0)) + goto opt_error; /* Finish the relay-forward message. */ cursor += store_options6(forw_data + cursor, @@ -1571,10 +1632,10 @@ process_down6(struct packet *packet) { case DHCPV6_RECONFIGURE: case DHCPV6_RELAY_FORW: case DHCPV6_LEASEQUERY_REPLY: - log_info("Relaying %s to %s port %d down.", + log_info("Relaying %s to %s port %d down on %s.", dhcpv6_type_names[msg->msg_type], piaddr(peer), - ntohs(to.sin6_port)); + ntohs(to.sin6_port), dp->ifp->name); break; case DHCPV6_SOLICIT: @@ -1586,17 +1647,17 @@ process_down6(struct packet *packet) { case DHCPV6_DECLINE: case DHCPV6_INFORMATION_REQUEST: case DHCPV6_LEASEQUERY: - log_info("Discarding %s to %s port %d down.", + log_info("Discarding %s to %s port %d down on %s.", dhcpv6_type_names[msg->msg_type], piaddr(peer), - ntohs(to.sin6_port)); + ntohs(to.sin6_port), dp->ifp->name); goto cleanup; default: - log_info("Unknown %d type to %s port %d down.", + log_info("Unknown %d type to %s port %d down on %s.", msg->msg_type, piaddr(peer), - ntohs(to.sin6_port)); + ntohs(to.sin6_port), dp->ifp->name); goto cleanup; } |