]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
Added local-address6
authorFrancis Dupont <fdupont@isc.org>
Tue, 19 Dec 2017 20:02:51 +0000 (21:02 +0100)
committerFrancis Dupont <fdupont@isc.org>
Tue, 19 Dec 2017 20:02:51 +0000 (21:02 +0100)
RELNOTES
common/discover.c
common/socket.c
includes/dhcpd.h
server/dhcpd.c
server/dhcpd.conf.5
server/stables.c

index ceb44e9b1bbce7beb3c2ea3e4c1c7220012b104a..4f8656175ebeecf478968cbe3dc39ffa2268640b 100644 (file)
--- a/RELNOTES
+++ b/RELNOTES
@@ -296,6 +296,14 @@ dhcp-users@lists.isc.org.
   [ISC-Bugs #34097]
   [ISC-Bugs #41054]
 
+- Added to the server (-6) a new statement, local-address6, which specifies
+  the source address of packets sent by the server. An additional flag,
+  bind-local-address6, disabled by default makes the service socket to
+  be bound to local-address6. Note as for local-address this does not
+  work with direct client: a relay has to forward packets to the server
+  using the local-address6 destination.
+  [ISC-Bugs #46084]
+
                        Changes since 4.3.6 (Bugs):
 
 - Corrected an issue where the server would return a client's previously
index ab64f7cf927921c823bd1469285ca7b5bf40dbb6..f81d63f76ea054dc1d98d22130bf00a13abe701a 100644 (file)
@@ -55,6 +55,14 @@ struct in_addr limited_broadcast;
 int local_family = AF_INET;
 struct in_addr local_address;
 
+#ifdef DHCPv6
+/*
+ * Another clear abuse of the fact that undefined IP addresses are all zeroes.
+ */
+struct in6_addr local_address6;
+int bind_local_address6 = 0;
+#endif /* DHCPv6 */
+
 void (*bootp_packet_handler) (struct interface_info *,
                              struct dhcp_packet *, unsigned,
                              unsigned int,
index 89ae046babd783bcb1d8af1d1cb8805a5f517d28..9c42d45168d269cd28493ea848e239aa8c63b2a3 100644 (file)
@@ -157,10 +157,19 @@ if_register_socket(struct interface_info *info, int family,
                addr6 = (struct sockaddr_in6 *)&name; 
                addr6->sin6_family = AF_INET6;
                addr6->sin6_port = local_port;
+               /* A server feature */
+               if (bind_local_address6) {
+                       memcpy(&addr6->sin6_addr,
+                              &local_address6,
+                              sizeof(addr6->sin6_addr));
+               }
+               /* A client feature */
                if (linklocal6) {
                        memcpy(&addr6->sin6_addr,
                               linklocal6,
                               sizeof(addr6->sin6_addr));
+               }
+               if (IN6_IS_ADDR_LINKLOCAL(&addr6->sin6_addr)) {
                        addr6->sin6_scope_id = if_nametoindex(info->name);
                }
 #ifdef HAVE_SA_LEN
@@ -497,8 +506,21 @@ if_register6(struct interface_info *info, int do_multicast) {
                         * create a socket, this is just a sanity check.
                         */
                        log_fatal("Impossible condition at %s:%d", MDL);
+               } else if (bind_local_address6) {
+                       char addr6_str[INET6_ADDRSTRLEN];
+
+                       if (inet_ntop(AF_INET6,
+                                     &local_address6,
+                                     addr6_str,
+                                     sizeof(addr6_str)) == NULL) {
+                               log_fatal("inet_ntop: unable to convert "
+                                         "local-address6");
+                       }
+                       log_info("Bound to [%s]:%d",
+                                addr6_str,
+                                (int) ntohs(local_port));
                } else {
-                       log_info("Bound to *:%d", ntohs(local_port));
+                       log_info("Bound to *:%d", (int) ntohs(local_port));
                }
        }
                
@@ -828,6 +850,7 @@ ssize_t send_packet6(struct interface_info *interface,
        cmsg->cmsg_len = CMSG_LEN(sizeof(*pktinfo));
        pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
        memset(pktinfo, 0, sizeof(*pktinfo));
+       pktinfo->ipi6_addr = local_address6;
        pktinfo->ipi6_ifindex = ifindex;
 
        result = sendmsg(interface->wfdesc, &m, 0);
index 2130f21b9cb3570eea6f7d44f5b8290ce0bdc0ce..044aca93570cf208c0aac470ef245d76f8b5342f 100644 (file)
@@ -810,6 +810,8 @@ struct lease_state {
 #define SV_DDNS_GUARD_ID_MUST_MATCH    93
 #define SV_DDNS_OTHER_GUARD_IS_DYNAMIC 94
 #define SV_RELEASE_ON_ROAM             95
+#define SV_LOCAL_ADDRESS6              96
+#define SV_BIND_LOCAL_ADDRESS6         97
 
 #if !defined (DEFAULT_PING_TIMEOUT)
 # define DEFAULT_PING_TIMEOUT 1
@@ -2826,6 +2828,8 @@ void interface_trace_setup (void);
 extern struct in_addr limited_broadcast;
 extern int local_family;
 extern struct in_addr local_address;
+extern struct in6_addr local_address6;
+extern int bind_local_address6;
 
 extern u_int16_t local_port;
 extern u_int16_t remote_port;
index 68e74b5414c9479c9bc72eb479901d67149a9785..ea62d1a066a0da39108d07587f02e445cbb2003e 100644 (file)
@@ -1150,6 +1150,29 @@ void postconf_initialization (int quiet)
                         data_string_forget(&db, MDL);
                         path_dhcpd_pid = s;
                 }
+
+               oc = lookup_option(&server_universe, options,
+                                  SV_LOCAL_ADDRESS6);
+               if (oc &&
+                   evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
+                                         &global_scope, oc, MDL)) {
+                       if (db.len == 16) {
+                               memcpy(&local_address6, db.data, 16);
+                       } else
+                               log_fatal("invalid local address "
+                                         "data length");
+                       data_string_forget(&db, MDL);
+               }
+
+               oc = lookup_option(&server_universe, options,
+                                  SV_BIND_LOCAL_ADDRESS6);
+               if (oc &&
+                   evaluate_boolean_option_cache(NULL, NULL, NULL,
+                                                 NULL, options, NULL,
+                                                 &global_scope, oc, MDL)) {
+                       bind_local_address6 = 1;
+               }
+
         }
 #endif /* DHCPv6 */
 
index 0973f3095426b5f0a9255c59dd2eae6669f749cf..1ba4009f624190ebdc494d2155c0ff8080028a3a 100644 (file)
@@ -2744,6 +2744,29 @@ time.
 .RE
 .PP
 The
+.I local-address6
+and
+.I bind-local-address6
+statements
+.RS 0.25i
+.PP
+.B local-address6 \fIaddress\fB;\fR
+.PP
+.B bind-local-address6 \fIflag\fB;\fR
+.PP
+The \fIlocal-address6\fR statement causes the DHCP server to send IPv6
+packets as originating from the specified IPv6 \fIaddress\fR, rather than
+leaving the kernel to fill in the source address field.
+.PP
+When \fIbind-local-address6\fR is present and has a value of true or on,
+service sockets are bound to \fIaddress\fR too.
+.PP
+By default \fIaddress\fR is the undefined address and the
+\fIbind-local-address6\fR is disabled, both may only be set at the global
+scope.
+.RE
+.PP
+The
 .I log-facility
 statement
 .RS 0.25i
index cea24bc3633897b69677ed4fe1d4076dc01b6180..f3424c927cb3a5dd4f1535c9970d2559906dc343 100644 (file)
@@ -288,6 +288,8 @@ static struct option server_options[] = {
        { "ddns-guard-id-must-match", "f",              &server_universe,  SV_DDNS_GUARD_ID_MUST_MATCH, 1 },
        { "ddns-other-guard-is-dynamic", "f",           &server_universe,  SV_DDNS_OTHER_GUARD_IS_DYNAMIC, 1 },
        { "release-on-roam", "f",       &server_universe,  SV_RELEASE_ON_ROAM, 1 },
+       { "local-address6", "6",        &server_universe,  SV_LOCAL_ADDRESS6, 1 },
+       { "bind-local-address6", "f",   &server_universe,  SV_BIND_LOCAL_ADDRESS6, 1 },
        { NULL, NULL, NULL, 0, 0 }
 };