mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 18:28:25 +00:00
[fd00::} and [fe80::] special addresses in DHCPv6 options.
This commit is contained in:
@@ -11,6 +11,12 @@ version 2.69
|
|||||||
--dhcp-option=option6:23,[::] Thanks to Tsachi Kimeldorfer
|
--dhcp-option=option6:23,[::] Thanks to Tsachi Kimeldorfer
|
||||||
for spotting the problem.
|
for spotting the problem.
|
||||||
|
|
||||||
|
Add [fd00::] and [fe80::] as special addresses in DHCPv6
|
||||||
|
options, analogous to [::]. [fd00::] is replaced with the
|
||||||
|
actual ULA of the interface on the machine running
|
||||||
|
dnsmasq, [fe80::] with the link-local address.
|
||||||
|
Thanks to Tsachi Kimeldorfer for championing this.
|
||||||
|
|
||||||
|
|
||||||
version 2.68
|
version 2.68
|
||||||
Use random addresses for DHCPv6 temporary address
|
Use random addresses for DHCPv6 temporary address
|
||||||
|
|||||||
@@ -917,9 +917,11 @@ and to set the time-server address to 192.168.0.4, do
|
|||||||
.B --dhcp-option = 42,192.168.0.4
|
.B --dhcp-option = 42,192.168.0.4
|
||||||
or
|
or
|
||||||
.B --dhcp-option = option:ntp-server, 192.168.0.4
|
.B --dhcp-option = option:ntp-server, 192.168.0.4
|
||||||
The special address 0.0.0.0 (or [::] for DHCPv6) is taken to mean "the address of the
|
The special address 0.0.0.0 is taken to mean "the address of the
|
||||||
machine running dnsmasq". Data types allowed are comma separated
|
machine running dnsmasq".
|
||||||
dotted-quad IP addresses, a decimal number, colon-separated hex digits
|
|
||||||
|
Data types allowed are comma separated
|
||||||
|
dotted-quad IPv4 addresses, []-wrapped IPv6 addresses, a decimal number, colon-separated hex digits
|
||||||
and a text string. If the optional tags are given then
|
and a text string. If the optional tags are given then
|
||||||
this option is only sent when all the tags are matched.
|
this option is only sent when all the tags are matched.
|
||||||
|
|
||||||
@@ -935,7 +937,9 @@ keyword, followed by the option number or option name. The IPv6 option
|
|||||||
name space is disjoint from the IPv4 option name space. IPv6 addresses
|
name space is disjoint from the IPv4 option name space. IPv6 addresses
|
||||||
in options must be bracketed with square brackets, eg.
|
in options must be bracketed with square brackets, eg.
|
||||||
.B --dhcp-option=option6:ntp-server,[1234::56]
|
.B --dhcp-option=option6:ntp-server,[1234::56]
|
||||||
|
For IPv6, [::] means "the global address of
|
||||||
|
the machine running dnsmasq", whilst [fd00::] is replaced with the
|
||||||
|
ULA, if it exists, and [fe80::] with the link-local address.
|
||||||
|
|
||||||
Be careful: no checking is done that the correct type of data for the
|
Be careful: no checking is done that the correct type of data for the
|
||||||
option number is sent, it is quite possible to
|
option number is sent, it is quite possible to
|
||||||
|
|||||||
11
src/dhcp6.c
11
src/dhcp6.c
@@ -23,7 +23,7 @@
|
|||||||
struct iface_param {
|
struct iface_param {
|
||||||
struct dhcp_context *current;
|
struct dhcp_context *current;
|
||||||
struct dhcp_relay *relay;
|
struct dhcp_relay *relay;
|
||||||
struct in6_addr fallback, relay_local;
|
struct in6_addr fallback, relay_local, ll_addr, ula_addr;
|
||||||
int ind, addr_match;
|
int ind, addr_match;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -158,6 +158,8 @@ void dhcp6_packet(time_t now)
|
|||||||
parm.ind = if_index;
|
parm.ind = if_index;
|
||||||
parm.addr_match = 0;
|
parm.addr_match = 0;
|
||||||
memset(&parm.fallback, 0, IN6ADDRSZ);
|
memset(&parm.fallback, 0, IN6ADDRSZ);
|
||||||
|
memset(&parm.ll_addr, 0, IN6ADDRSZ);
|
||||||
|
memset(&parm.ula_addr, 0, IN6ADDRSZ);
|
||||||
|
|
||||||
for (context = daemon->dhcp6; context; context = context->next)
|
for (context = daemon->dhcp6; context; context = context->next)
|
||||||
if (IN6_IS_ADDR_UNSPECIFIED(&context->start6) && context->prefix == 0)
|
if (IN6_IS_ADDR_UNSPECIFIED(&context->start6) && context->prefix == 0)
|
||||||
@@ -210,7 +212,7 @@ void dhcp6_packet(time_t now)
|
|||||||
lease_prune(NULL, now); /* lose any expired leases */
|
lease_prune(NULL, now); /* lose any expired leases */
|
||||||
|
|
||||||
port = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback,
|
port = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback,
|
||||||
sz, &from.sin6_addr, now);
|
&parm.ll_addr, &parm.ula_addr, sz, &from.sin6_addr, now);
|
||||||
|
|
||||||
lease_update_file(now);
|
lease_update_file(now);
|
||||||
lease_update_dns(0);
|
lease_update_dns(0);
|
||||||
@@ -309,6 +311,11 @@ static int complete_context6(struct in6_addr *local, int prefix,
|
|||||||
|
|
||||||
if (if_index == param->ind)
|
if (if_index == param->ind)
|
||||||
{
|
{
|
||||||
|
if (IN6_IS_ADDR_LINKLOCAL(local))
|
||||||
|
param->ll_addr = *local;
|
||||||
|
else if (IN6_IS_ADDR_ULA(local))
|
||||||
|
param->ula_addr = *local;
|
||||||
|
|
||||||
if (!IN6_IS_ADDR_LOOPBACK(local) &&
|
if (!IN6_IS_ADDR_LOOPBACK(local) &&
|
||||||
!IN6_IS_ADDR_LINKLOCAL(local) &&
|
!IN6_IS_ADDR_LINKLOCAL(local) &&
|
||||||
!IN6_IS_ADDR_MULTICAST(local))
|
!IN6_IS_ADDR_MULTICAST(local))
|
||||||
|
|||||||
@@ -50,6 +50,7 @@
|
|||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "ip6addr.h"
|
||||||
|
|
||||||
typedef unsigned char u8;
|
typedef unsigned char u8;
|
||||||
typedef unsigned short u16;
|
typedef unsigned short u16;
|
||||||
@@ -1314,7 +1315,8 @@ void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac,
|
|||||||
/* rfc3315.c */
|
/* rfc3315.c */
|
||||||
#ifdef HAVE_DHCP6
|
#ifdef HAVE_DHCP6
|
||||||
unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name,
|
unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name,
|
||||||
struct in6_addr *fallback, size_t sz, struct in6_addr *client_addr, time_t now);
|
struct in6_addr *fallback, struct in6_addr *ll_addr, struct in6_addr *ula_addr,
|
||||||
|
size_t sz, struct in6_addr *client_addr, time_t now);
|
||||||
void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer_address, u32 scope_id);
|
void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer_address, u32 scope_id);
|
||||||
|
|
||||||
unsigned short relay_reply6( struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface);
|
unsigned short relay_reply6( struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface);
|
||||||
|
|||||||
34
src/ip6addr.h
Normal file
34
src/ip6addr.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; version 2 dated June, 1991, or
|
||||||
|
(at your option) version 3 dated 29 June, 2007.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define IN6_IS_ADDR_ULA(a) \
|
||||||
|
((((__const uint32_t *) (a))[0] & htonl (0xff000000)) \
|
||||||
|
== htonl (0xfd000000))
|
||||||
|
|
||||||
|
#define IN6_IS_ADDR_ULA_ZERO(a) \
|
||||||
|
(((__const uint32_t *) (a))[0] == htonl (0xfd000000) \
|
||||||
|
&& ((__const uint32_t *) (a))[1] == 0 \
|
||||||
|
&& ((__const uint32_t *) (a))[2] == 0 \
|
||||||
|
&& ((__const uint32_t *) (a))[3] == 0)
|
||||||
|
|
||||||
|
#define IN6_IS_ADDR_LINK_LOCAL_ZERO(a) \
|
||||||
|
(((__const uint32_t *) (a))[0] == htonl (0xfe800000) \
|
||||||
|
&& ((__const uint32_t *) (a))[1] == 0 \
|
||||||
|
&& ((__const uint32_t *) (a))[2] == 0 \
|
||||||
|
&& ((__const uint32_t *) (a))[3] == 0)
|
||||||
|
|
||||||
108
src/radv.c
108
src/radv.c
@@ -31,8 +31,8 @@ struct ra_param {
|
|||||||
int ind, managed, other, found_context, first;
|
int ind, managed, other, found_context, first;
|
||||||
char *if_name;
|
char *if_name;
|
||||||
struct dhcp_netid *tags;
|
struct dhcp_netid *tags;
|
||||||
struct in6_addr link_local, link_global;
|
struct in6_addr link_local, link_global, ula;
|
||||||
unsigned int pref_time, adv_interval;
|
unsigned int glob_pref_time, link_pref_time, ula_pref_time, adv_interval;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct search_param {
|
struct search_param {
|
||||||
@@ -206,6 +206,7 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
|
|||||||
struct dhcp_opt *opt_cfg;
|
struct dhcp_opt *opt_cfg;
|
||||||
struct ra_interface *ra_param = find_iface_param(iface_name);
|
struct ra_interface *ra_param = find_iface_param(iface_name);
|
||||||
int done_dns = 0, old_prefix = 0;
|
int done_dns = 0, old_prefix = 0;
|
||||||
|
unsigned int min_pref_time;
|
||||||
#ifdef HAVE_LINUX_NETWORK
|
#ifdef HAVE_LINUX_NETWORK
|
||||||
FILE *f;
|
FILE *f;
|
||||||
#endif
|
#endif
|
||||||
@@ -228,7 +229,7 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
|
|||||||
parm.if_name = iface_name;
|
parm.if_name = iface_name;
|
||||||
parm.first = 1;
|
parm.first = 1;
|
||||||
parm.now = now;
|
parm.now = now;
|
||||||
parm.pref_time = 0;
|
parm.glob_pref_time = parm.link_pref_time = parm.ula_pref_time = 0;
|
||||||
parm.adv_interval = calc_interval(ra_param);
|
parm.adv_interval = calc_interval(ra_param);
|
||||||
|
|
||||||
/* set tag with name == interface */
|
/* set tag with name == interface */
|
||||||
@@ -245,6 +246,18 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
|
|||||||
if (!iface_enumerate(AF_INET6, &parm, add_prefixes))
|
if (!iface_enumerate(AF_INET6, &parm, add_prefixes))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* Find smallest preferred time within address classes,
|
||||||
|
to use as lifetime for options. This is a rather arbitrary choice. */
|
||||||
|
min_pref_time = 0xffffffff;
|
||||||
|
if (parm.glob_pref_time != 0 && parm.glob_pref_time < min_pref_time)
|
||||||
|
min_pref_time = parm.glob_pref_time;
|
||||||
|
|
||||||
|
if (parm.ula_pref_time != 0 && parm.ula_pref_time < min_pref_time)
|
||||||
|
min_pref_time = parm.ula_pref_time;
|
||||||
|
|
||||||
|
if (parm.link_pref_time != 0 && parm.link_pref_time < min_pref_time)
|
||||||
|
min_pref_time = parm.link_pref_time;
|
||||||
|
|
||||||
/* Look for constructed contexts associated with addresses which have gone,
|
/* Look for constructed contexts associated with addresses which have gone,
|
||||||
and advertise them with preferred_time == 0 RFC 6204 4.3 L-13 */
|
and advertise them with preferred_time == 0 RFC 6204 4.3 L-13 */
|
||||||
for (up = &daemon->dhcp6, context = daemon->dhcp6; context; context = tmp)
|
for (up = &daemon->dhcp6, context = daemon->dhcp6; context; context = tmp)
|
||||||
@@ -340,22 +353,48 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
|
|||||||
|
|
||||||
if (opt_cfg->opt == OPTION6_DNS_SERVER)
|
if (opt_cfg->opt == OPTION6_DNS_SERVER)
|
||||||
{
|
{
|
||||||
struct in6_addr *a = (struct in6_addr *)opt_cfg->val;
|
struct in6_addr *a;
|
||||||
|
int len;
|
||||||
|
|
||||||
done_dns = 1;
|
done_dns = 1;
|
||||||
if (opt_cfg->len == 0 || (IN6_IS_ADDR_UNSPECIFIED(a) && parm.pref_time == 0))
|
|
||||||
|
if (opt_cfg->len == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
put_opt6_char(ICMP6_OPT_RDNSS);
|
/* reduce len for any addresses we can't substitute */
|
||||||
put_opt6_char((opt_cfg->len/8) + 1);
|
for (a = (struct in6_addr *)opt_cfg->val, len = opt_cfg->len, i = 0;
|
||||||
put_opt6_short(0);
|
i < opt_cfg->len; i += IN6ADDRSZ, a++)
|
||||||
put_opt6_long(parm.pref_time);
|
if ((IN6_IS_ADDR_UNSPECIFIED(a) && parm.glob_pref_time == 0) ||
|
||||||
/* zero means "self" */
|
(IN6_IS_ADDR_ULA_ZERO(a) && parm.ula_pref_time == 0) ||
|
||||||
for (i = 0; i < opt_cfg->len; i += IN6ADDRSZ, a++)
|
(IN6_IS_ADDR_LINK_LOCAL_ZERO(a) && parm.link_pref_time == 0))
|
||||||
if (IN6_IS_ADDR_UNSPECIFIED(a))
|
len -= IN6ADDRSZ;
|
||||||
put_opt6(&parm.link_global, IN6ADDRSZ);
|
|
||||||
else
|
if (len != 0)
|
||||||
put_opt6(a, IN6ADDRSZ);
|
{
|
||||||
|
put_opt6_char(ICMP6_OPT_RDNSS);
|
||||||
|
put_opt6_char((len/8) + 1);
|
||||||
|
put_opt6_short(0);
|
||||||
|
put_opt6_long(min_pref_time);
|
||||||
|
|
||||||
|
for (a = (struct in6_addr *)opt_cfg->val, i = 0; i < opt_cfg->len; i += IN6ADDRSZ, a++)
|
||||||
|
if (IN6_IS_ADDR_UNSPECIFIED(a))
|
||||||
|
{
|
||||||
|
if (parm.glob_pref_time != 0)
|
||||||
|
put_opt6(&parm.link_global, IN6ADDRSZ);
|
||||||
|
}
|
||||||
|
else if (IN6_IS_ADDR_ULA_ZERO(a))
|
||||||
|
{
|
||||||
|
if (parm.ula_pref_time != 0)
|
||||||
|
put_opt6(&parm.ula, IN6ADDRSZ);
|
||||||
|
}
|
||||||
|
else if (IN6_IS_ADDR_LINK_LOCAL_ZERO(a))
|
||||||
|
{
|
||||||
|
if (parm.link_pref_time != 0)
|
||||||
|
put_opt6(&parm.link_local, IN6ADDRSZ);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
put_opt6(a, IN6ADDRSZ);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opt_cfg->opt == OPTION6_DOMAIN_SEARCH && opt_cfg->len != 0)
|
if (opt_cfg->opt == OPTION6_DOMAIN_SEARCH && opt_cfg->len != 0)
|
||||||
@@ -365,7 +404,7 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
|
|||||||
put_opt6_char(ICMP6_OPT_DNSSL);
|
put_opt6_char(ICMP6_OPT_DNSSL);
|
||||||
put_opt6_char(len + 1);
|
put_opt6_char(len + 1);
|
||||||
put_opt6_short(0);
|
put_opt6_short(0);
|
||||||
put_opt6_long(parm.pref_time);
|
put_opt6_long(min_pref_time);
|
||||||
put_opt6(opt_cfg->val, opt_cfg->len);
|
put_opt6(opt_cfg->val, opt_cfg->len);
|
||||||
|
|
||||||
/* pad */
|
/* pad */
|
||||||
@@ -374,13 +413,13 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (daemon->port == NAMESERVER_PORT && !done_dns && parm.pref_time != 0)
|
if (daemon->port == NAMESERVER_PORT && !done_dns && parm.link_pref_time != 0)
|
||||||
{
|
{
|
||||||
/* default == us, as long as we are supplying DNS service. */
|
/* default == us, as long as we are supplying DNS service. */
|
||||||
put_opt6_char(ICMP6_OPT_RDNSS);
|
put_opt6_char(ICMP6_OPT_RDNSS);
|
||||||
put_opt6_char(3);
|
put_opt6_char(3);
|
||||||
put_opt6_short(0);
|
put_opt6_short(0);
|
||||||
put_opt6_long(parm.pref_time);
|
put_opt6_long(min_pref_time);
|
||||||
put_opt6(&parm.link_local, IN6ADDRSZ);
|
put_opt6(&parm.link_local, IN6ADDRSZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -426,7 +465,16 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
|||||||
if (if_index == param->ind)
|
if (if_index == param->ind)
|
||||||
{
|
{
|
||||||
if (IN6_IS_ADDR_LINKLOCAL(local))
|
if (IN6_IS_ADDR_LINKLOCAL(local))
|
||||||
param->link_local = *local;
|
{
|
||||||
|
/* Can there be more than one LL address?
|
||||||
|
Select the one with the longest preferred time
|
||||||
|
if there is. */
|
||||||
|
if (preferred > param->link_pref_time)
|
||||||
|
{
|
||||||
|
param->link_pref_time = preferred;
|
||||||
|
param->link_local = *local;
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (!IN6_IS_ADDR_LOOPBACK(local) &&
|
else if (!IN6_IS_ADDR_LOOPBACK(local) &&
|
||||||
!IN6_IS_ADDR_MULTICAST(local))
|
!IN6_IS_ADDR_MULTICAST(local))
|
||||||
{
|
{
|
||||||
@@ -516,11 +564,22 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
|||||||
/* configured time is ceiling */
|
/* configured time is ceiling */
|
||||||
if (!constructed || preferred > time)
|
if (!constructed || preferred > time)
|
||||||
preferred = time;
|
preferred = time;
|
||||||
|
|
||||||
if (preferred > param->pref_time)
|
if (IN6_IS_ADDR_ULA(local))
|
||||||
{
|
{
|
||||||
param->pref_time = preferred;
|
if (preferred > param->ula_pref_time)
|
||||||
param->link_global = *local;
|
{
|
||||||
|
param->ula_pref_time = preferred;
|
||||||
|
param->ula = *local;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (preferred > param->glob_pref_time)
|
||||||
|
{
|
||||||
|
param->glob_pref_time = preferred;
|
||||||
|
param->link_global = *local;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (real_prefix != 0)
|
if (real_prefix != 0)
|
||||||
@@ -546,7 +605,6 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
|||||||
if (!option_bool(OPT_QUIET_RA))
|
if (!option_bool(OPT_QUIET_RA))
|
||||||
my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s", param->if_name, daemon->addrbuff);
|
my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s", param->if_name, daemon->addrbuff);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ struct state {
|
|||||||
int clid_len, iaid, ia_type, interface, hostname_auth, lease_allocate;
|
int clid_len, iaid, ia_type, interface, hostname_auth, lease_allocate;
|
||||||
char *client_hostname, *hostname, *domain, *send_domain;
|
char *client_hostname, *hostname, *domain, *send_domain;
|
||||||
struct dhcp_context *context;
|
struct dhcp_context *context;
|
||||||
struct in6_addr *link_address, *fallback;
|
struct in6_addr *link_address, *fallback, *ll_addr, *ula_addr;
|
||||||
unsigned int xid, fqdn_flags;
|
unsigned int xid, fqdn_flags;
|
||||||
char *iface_name;
|
char *iface_name;
|
||||||
void *packet_options, *end;
|
void *packet_options, *end;
|
||||||
@@ -73,7 +73,8 @@ static void calculate_times(struct dhcp_context *context, unsigned int *min_time
|
|||||||
|
|
||||||
|
|
||||||
unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name,
|
unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name,
|
||||||
struct in6_addr *fallback, size_t sz, struct in6_addr *client_addr, time_t now)
|
struct in6_addr *fallback, struct in6_addr *ll_addr, struct in6_addr *ula_addr,
|
||||||
|
size_t sz, struct in6_addr *client_addr, time_t now)
|
||||||
{
|
{
|
||||||
struct dhcp_vendor *vendor;
|
struct dhcp_vendor *vendor;
|
||||||
int msg_type;
|
int msg_type;
|
||||||
@@ -93,6 +94,8 @@ unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *if
|
|||||||
state.interface = interface;
|
state.interface = interface;
|
||||||
state.iface_name = iface_name;
|
state.iface_name = iface_name;
|
||||||
state.fallback = fallback;
|
state.fallback = fallback;
|
||||||
|
state.ll_addr = ll_addr;
|
||||||
|
state.ula_addr = ula_addr;
|
||||||
state.mac_len = 0;
|
state.mac_len = 0;
|
||||||
state.tags = NULL;
|
state.tags = NULL;
|
||||||
state.link_address = NULL;
|
state.link_address = NULL;
|
||||||
@@ -1269,36 +1272,59 @@ static struct dhcp_netid *add_options(struct state *state, int do_refresh)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opt_cfg->opt == OPTION6_DNS_SERVER)
|
|
||||||
{
|
|
||||||
done_dns = 1;
|
|
||||||
if (opt_cfg->len == 0)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opt_cfg->opt == OPTION6_REFRESH_TIME)
|
if (opt_cfg->opt == OPTION6_REFRESH_TIME)
|
||||||
done_refresh = 1;
|
done_refresh = 1;
|
||||||
|
|
||||||
o = new_opt6(opt_cfg->opt);
|
|
||||||
if (opt_cfg->flags & DHOPT_ADDR6)
|
if (opt_cfg->flags & DHOPT_ADDR6)
|
||||||
{
|
{
|
||||||
int j;
|
int len, j;
|
||||||
struct in6_addr *a = (struct in6_addr *)opt_cfg->val;
|
struct in6_addr *a;
|
||||||
for (j = 0; j < opt_cfg->len; j+=IN6ADDRSZ, a++)
|
|
||||||
{
|
if (opt_cfg->opt == OPTION6_DNS_SERVER)
|
||||||
/* zero means "self" (but not in vendorclass options.) */
|
done_dns = 1;
|
||||||
if (IN6_IS_ADDR_UNSPECIFIED(a))
|
|
||||||
{
|
for (a = (struct in6_addr *)opt_cfg->val, len = opt_cfg->len, j = 0;
|
||||||
if (!add_local_addrs(state->context))
|
j < opt_cfg->len; j += IN6ADDRSZ, a++)
|
||||||
put_opt6(state->fallback, IN6ADDRSZ);
|
if ((IN6_IS_ADDR_ULA_ZERO(a) && IN6_IS_ADDR_UNSPECIFIED(state->ula_addr)) ||
|
||||||
|
(IN6_IS_ADDR_LINK_LOCAL_ZERO(a) && IN6_IS_ADDR_UNSPECIFIED(state->ll_addr)))
|
||||||
|
len -= IN6ADDRSZ;
|
||||||
|
|
||||||
|
if (len != 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
o = new_opt6(opt_cfg->opt);
|
||||||
|
|
||||||
|
for (a = (struct in6_addr *)opt_cfg->val, j = 0; j < opt_cfg->len; j+=IN6ADDRSZ, a++)
|
||||||
|
{
|
||||||
|
if (IN6_IS_ADDR_UNSPECIFIED(a))
|
||||||
|
{
|
||||||
|
if (!add_local_addrs(state->context))
|
||||||
|
put_opt6(state->fallback, IN6ADDRSZ);
|
||||||
|
}
|
||||||
|
else if (IN6_IS_ADDR_ULA_ZERO(a))
|
||||||
|
{
|
||||||
|
if (!IN6_IS_ADDR_UNSPECIFIED(state->ula_addr))
|
||||||
|
put_opt6(state->ula_addr, IN6ADDRSZ);
|
||||||
|
}
|
||||||
|
else if (IN6_IS_ADDR_LINK_LOCAL_ZERO(a))
|
||||||
|
{
|
||||||
|
if (!IN6_IS_ADDR_UNSPECIFIED(state->ll_addr))
|
||||||
|
put_opt6(state->ll_addr, IN6ADDRSZ);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
put_opt6(a, IN6ADDRSZ);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
put_opt6(a, IN6ADDRSZ);
|
end_opt6(o);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
o = new_opt6(opt_cfg->opt);
|
||||||
|
if (opt_cfg->val)
|
||||||
|
put_opt6(opt_cfg->val, opt_cfg->len);
|
||||||
|
end_opt6(o);
|
||||||
}
|
}
|
||||||
else if (opt_cfg->val)
|
|
||||||
put_opt6(opt_cfg->val, opt_cfg->len);
|
|
||||||
end_opt6(o);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (daemon->port == NAMESERVER_PORT && !done_dns)
|
if (daemon->port == NAMESERVER_PORT && !done_dns)
|
||||||
|
|||||||
Reference in New Issue
Block a user