summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrancis Dupont <fdupont@isc.org>2016-02-23 10:49:25 +0100
committerFrancis Dupont <fdupont@isc.org>2016-02-23 10:49:25 +0100
commit52fac07044c76b97994eab51daf66bbdd256a03d (patch)
treeddff9704b50fb6eb32f6170b741dd5d94814bd4a
parent785c1a519e88bfebb70bd3384589de36bee02dd2 (diff)
downloadisc-dhcp-52fac07044c76b97994eab51daf66bbdd256a03d.tar.gz
Merged rt35711c (DHCPv4-over-DHCPv6 support) (new files)
-rw-r--r--common/dhcp4o6.c116
-rw-r--r--doc/DHCPv4-over-DHCPv6113
2 files changed, 229 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..de232d73
--- /dev/null
+++ b/doc/DHCPv4-over-DHCPv6
@@ -0,0 +1,113 @@
+Short notice about DHCPv4 over DHCPv6 aka RFC 7341
+--------------------------------------------------
+Note well: this code is still somewhat experimental and any user
+should take care when trying to use it.
+
+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.