diff options
-rw-r--r-- | RELNOTES | 8 | ||||
-rw-r--r-- | common/discover.c | 8 | ||||
-rw-r--r-- | common/socket.c | 25 | ||||
-rw-r--r-- | includes/dhcpd.h | 4 | ||||
-rw-r--r-- | server/dhcpd.c | 23 | ||||
-rw-r--r-- | server/dhcpd.conf.5 | 23 | ||||
-rw-r--r-- | server/stables.c | 2 |
7 files changed, 92 insertions, 1 deletions
@@ -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 } }; |