summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrancis Dupont <fdupont@isc.org>2017-12-19 21:02:51 +0100
committerFrancis Dupont <fdupont@isc.org>2017-12-19 21:02:51 +0100
commita2a0f98c21c7c9926bb8901344e939e276a6242e (patch)
tree9fb85122bc47aa360a067f8782928abdbe804d35
parentf1208e796d8e7208055a0afb848f7795f0ea2258 (diff)
downloadisc-dhcp-a2a0f98c21c7c9926bb8901344e939e276a6242e.tar.gz
Added local-address6
-rw-r--r--RELNOTES8
-rw-r--r--common/discover.c8
-rw-r--r--common/socket.c25
-rw-r--r--includes/dhcpd.h4
-rw-r--r--server/dhcpd.c23
-rw-r--r--server/dhcpd.conf.523
-rw-r--r--server/stables.c2
7 files changed, 92 insertions, 1 deletions
diff --git a/RELNOTES b/RELNOTES
index ceb44e9b..4f865617 100644
--- 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
diff --git a/common/discover.c b/common/discover.c
index ab64f7cf..f81d63f7 100644
--- a/common/discover.c
+++ b/common/discover.c
@@ -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,
diff --git a/common/socket.c b/common/socket.c
index 89ae046b..9c42d451 100644
--- a/common/socket.c
+++ b/common/socket.c
@@ -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);
diff --git a/includes/dhcpd.h b/includes/dhcpd.h
index 2130f21b..044aca93 100644
--- a/includes/dhcpd.h
+++ b/includes/dhcpd.h
@@ -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;
diff --git a/server/dhcpd.c b/server/dhcpd.c
index 68e74b54..ea62d1a0 100644
--- a/server/dhcpd.c
+++ b/server/dhcpd.c
@@ -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 */
diff --git a/server/dhcpd.conf.5 b/server/dhcpd.conf.5
index 0973f309..1ba4009f 100644
--- a/server/dhcpd.conf.5
+++ b/server/dhcpd.conf.5
@@ -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
diff --git a/server/stables.c b/server/stables.c
index cea24bc3..f3424c92 100644
--- a/server/stables.c
+++ b/server/stables.c
@@ -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 }
};