diff options
author | Francis Dupont <fdupont@isc.org> | 2016-02-18 18:46:55 +0100 |
---|---|---|
committer | Francis Dupont <fdupont@isc.org> | 2016-02-18 18:46:55 +0100 |
commit | 51704b6a578dc67009333b2a3ef77882e0486fa6 (patch) | |
tree | 4197fc214e2b8de53a3e7c18e43792c93405d6ac | |
parent | aba2fb2c2c78f56951b9fda3c3bb972aa04172ca (diff) | |
download | isc-dhcp-51704b6a578dc67009333b2a3ef77882e0486fa6.tar.gz |
Added DHCPv4-over-DHCPv6 support (new files)
-rw-r--r-- | common/dhcp4o6.c | 116 | ||||
-rw-r--r-- | doc/DHCPv4-over-DHCPv6 | 111 |
2 files changed, 227 insertions, 0 deletions
diff --git a/common/dhcp4o6.c b/common/dhcp4o6.c new file mode 100644 index 00000000..4bd074c6 --- /dev/null +++ b/common/dhcp4o6.c @@ -0,0 +1,116 @@ +/* dhcp4o6.c + + DHCPv4 over DHCPv6 shared code... */ + +/* + * Copyright (c) 2016 by Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Internet Systems Consortium, Inc. + * 950 Charter Street + * Redwood City, CA 94063 + * <info@isc.org> + * https://www.isc.org/ + * + */ + +#include "dhcpd.h" + +#ifdef DHCP4o6 + +int dhcp4o6_fd = -1; +omapi_object_t *dhcp4o6_object = NULL; +omapi_object_type_t *dhcp4o6_type = NULL; + +static int dhcp4o6_readsocket(omapi_object_t *); + +/* + * DHCPv4 over DHCPv6 Inter Process Communication setup + * + * A UDP socket is created between ::1 port and ::1 port + 1 + * (port is given in network order, the DHCPv6 side is bound to port, + * the DHCPv4 side to port + 1. The socket descriptor is stored into + * dhcp4o6_fd and an OMAPI handler is registered. Any failure is fatal.) + */ +void dhcp4o6_setup(u_int16_t port) { + struct sockaddr_in6 local6, remote6; + int flag; + isc_result_t status; + + /* Register DHCPv4 over DHCPv6 forwarding. */ + memset(&local6, 0, sizeof(local6)); + local6.sin6_family = AF_INET6; + if (local_family == AF_INET6) + local6.sin6_port = port; + else + local6.sin6_port = htons(ntohs(port) + 1); + local6.sin6_addr.s6_addr[15] = 1; +#ifdef HAVE_SA_LEN + local6.sin6_len = sizeof(local6); +#endif + memset(&remote6, 0, sizeof(remote6)); + remote6.sin6_family = AF_INET6; + if (local_family == AF_INET6) + remote6.sin6_port = htons(ntohs(port) + 1); + else + remote6.sin6_port = port; + remote6.sin6_addr.s6_addr[15] = 1; +#ifdef HAVE_SA_LEN + remote6.sin6_len = sizeof(remote6); +#endif + + dhcp4o6_fd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (dhcp4o6_fd < 0) + log_fatal("Can't create dhcp4o6 socket: %m"); + flag = 1; + if (setsockopt(dhcp4o6_fd, SOL_SOCKET, SO_REUSEADDR, + (char *)&flag, sizeof(flag)) < 0) + log_fatal("Can't set SO_REUSEADDR option " + "on dhcp4o6 socket: %m"); + if (bind(dhcp4o6_fd, + (struct sockaddr *)&local6, + sizeof(local6)) < 0) + log_fatal("Can't bind dhcp4o6 socket: %m"); + if (connect(dhcp4o6_fd, + (struct sockaddr *)&remote6, + sizeof(remote6)) < 0) + log_fatal("Can't connect dhcp4o6 socket: %m"); + + /* Omapi stuff. */ + /* TODO: add tracing support. */ + status = omapi_object_type_register(&dhcp4o6_type, + "dhcp4o6", + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + sizeof(*dhcp4o6_object), + 0, RC_MISC); + if (status != ISC_R_SUCCESS) + log_fatal("Can't register dhcp4o6 type: %s", + isc_result_totext(status)); + status = omapi_object_allocate(&dhcp4o6_object, dhcp4o6_type, 0, MDL); + if (status != ISC_R_SUCCESS) + log_fatal("Can't allocate dhcp4o6 object: %s", + isc_result_totext(status)); + status = omapi_register_io_object(dhcp4o6_object, + dhcp4o6_readsocket, 0, + dhcpv4o6_handler, 0, 0); + if (status != ISC_R_SUCCESS) + log_fatal("Can't register dhcp4o6 handle: %s", + isc_result_totext(status)); +} + +static int dhcp4o6_readsocket(omapi_object_t *h) { + IGNORE_UNUSED(h); + return dhcp4o6_fd; +} +#endif /* DHCP4o6 */ diff --git a/doc/DHCPv4-over-DHCPv6 b/doc/DHCPv4-over-DHCPv6 new file mode 100644 index 00000000..f0adc921 --- /dev/null +++ b/doc/DHCPv4-over-DHCPv6 @@ -0,0 +1,111 @@ +Short notice about DHCPv4 over DHCPv6 aka RFC 7341 +-------------------------------------------------- + +First both the DHCPv4 over DHCPv6 client and server come with two +processes (named "side" below): + - a DHCPv6 side which performs usual DHCPv6 operations and + forwards DHCPv4-query / DHCPv4-response (eventually encapsulated + by / for DHCPv6 relay traversal) from / to the DHCPv4 side + + - a DHCPv4 side which processes encapsulated DHCPv4 messages + +Both sides support different command line arguments and configuration / +lease / process ID files even some could be common, for instance +most of the topology description. + +Second open of the hairy issues about configuring a DHCP server is +the localization, i.e., how to associate a client with a subnetwork +on a link (aka shared network). + +The topology is described in the server configuration file with +shared-network and subnet/subnet6 declarations. A subnetwork is +included in a shared-network, a shared network is created for +each orphan subnetwork. For each requested interface, a shared network +is built with all subnetworks matching its address. + +The procedure for DHCPv4 is in order: + - follow the Relay Agent Link Selection option if exists + + - follow the Subnet Selection option if exists + + - use the relay address if relayed + + - use the receiving interface + +At the exception of the last case the address must match a subnet address. + +The procedure for DHCPv6 is in order: + - when relayed, use the first relay with an usable (i.e., not unspecified + or link-local) address + + - use the receiving interface + +Note there can be multiple relays in DHCPv6, including layer 2 relays +which provide no usuable link addresses. + +The localization issue is more complex (fun!) with DHCPv4 over DHCPv6 +as explained in RFC 7341 quoted here: + Since the DHCPv4 message is encapsulated in the DHCPv6 message, it + lacks the information that is typically used by the DHCPv4 server, + implementing [RFC2131], to make address- allocation decisions, + e.g., giaddr for relayed messages and IPv4 address of the interface + that the server is using to communicate with a directly connected + client. + +In DHCPv4 over DHCPv6, there are a mixture of IPv6 and IPv4 addresses. +The DHCPv4 over DHCPv6 server externally uses only IPv6 addresses, +even at the DHCPv4 side, so shared networks associated to directly +attached interfaces are identified by subnet6 declarations. +For this reason, the DHCPv4 side should request no interface +by the command line or configuration file: all usable interfaces +will be requested (i.e., standard behavior when no interface is +specified in the command line or configuration file) and it is +not an error to have an interface with an address and no matching +subnet6 declaration, nor an error to have no usable interfaces +(i.e., fully relayed or routed topologies are accepted). + +Note also there is no involved DHCPv4 relays (DHCPv4 messages are +directly encapsulated into DHCPv6 DHCPv4-query/DHCPv4-response +messages by clients and servers as there is no cross DHCP version +relays specified by RFC 7341) so to get a Relay Agent option or +a relay address are very unlikely cases. + +So the procedure is: + - follow the Relay Agent Link Selection option if exists + + - follow the DHCPv4 Subnet Selection option if exists + + - use the DHCPv4 relay address if DHCPv4 relayed + + - when DHCPv6 relayed, use the first relay with an usable (i.e., not + unspecified or link-local) address + + - use the receiving interface + +So for more fun one can get a configuration like: + +shared-network "link1" { + subnet6 2001:db8:1:1::/64 { } + + subnet 192.168.1.0 netmask 255.255.255.0 { + range 192.168.1.100 192.168.1.199; + } +} + +So a DHCPv4 over DHCPv6 client using the 2001:db8:1:1::10 IPv6 address +will get a 192.168.1.1xy assigned. + +For more fun there is a remaining question: on which interface +a DHCPv4 over DHCPv6 client should apply the assigned IPv4 address? +RFC 7341 does not really help: + Before applying for an IPv4 address via a DHCPv4-query message, the + client must identify a suitable network interface for the address. + Once the request is acknowledged by the server, the client can + configure the address and other relevant parameters on this + interface. The mechanism for determining a suitable interface is out + of the scope of the document. + +The ISC DHCP answer is the IPv4 address is (in fact is required to be) +specified in the command line of the DHCPv4 side of the DHCPv4 over DHCPv6 +client. BTW in the usual case where the upstream interface is IPv6 only, +the IPv4 interface will be a different one. |