]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
Merged rt35711c (DHCPv4-over-DHCPv6 support) (new files)
authorFrancis Dupont <fdupont@isc.org>
Tue, 23 Feb 2016 09:49:25 +0000 (10:49 +0100)
committerFrancis Dupont <fdupont@isc.org>
Tue, 23 Feb 2016 09:49:25 +0000 (10:49 +0100)
common/dhcp4o6.c [new file with mode: 0644]
doc/DHCPv4-over-DHCPv6 [new file with mode: 0644]

diff --git a/common/dhcp4o6.c b/common/dhcp4o6.c
new file mode 100644 (file)
index 0000000..4bd074c
--- /dev/null
@@ -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 (file)
index 0000000..de232d7
--- /dev/null
@@ -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.