Compare commits

...

19 Commits

Author SHA1 Message Date
Simon Kelley
55b42f6de3 Default to global, not link-local address in RA DNS field. 2012-12-21 16:53:15 +00:00
Simon Kelley
ed8b68ad06 Simplify and fix RA lifetime calculation. 2012-12-21 16:23:26 +00:00
Simon Kelley
bad7b875eb add general flag param to iface_enumerate IPv6 callback 2012-12-20 22:00:39 +00:00
Simon Kelley
5d162f20a9 Rationalise join_multicast() 2012-12-20 14:55:46 +00:00
Simon Kelley
9d29949440 typo 2012-12-18 21:48:15 +00:00
Simon Kelley
1b75c1e61f Per-context control over ra short period. 2012-12-18 19:55:25 +00:00
Simon Kelley
293fd0f700 Missed interface re-read path in netlink.c 2012-12-18 18:31:11 +00:00
Simon Kelley
c1be917782 DHCP context logging, more tweaks 2012-12-18 18:31:11 +00:00
Simon Kelley
bb86e858b6 Error dhcp constructors on platforms where no interface detection. 2012-12-18 18:31:11 +00:00
Simon Kelley
8445f5d2e2 Fix initialisation order. 2012-12-18 18:31:11 +00:00
Simon Kelley
72c9c3b11b complicated DHCP context logging. 2012-12-18 18:31:11 +00:00
Simon Kelley
6e3dba3fde Ignore template contexts where appropriate. 2012-12-18 18:31:11 +00:00
Simon Kelley
7558ecd9ac Fix periodic loop 2012-12-18 18:31:11 +00:00
Simon Kelley
1f776932a1 First checkin of interface-address constructor mode for DHCPv6 and RA. 2012-12-18 18:31:11 +00:00
Simon Kelley
4820dce97a Make authoritative stuff a compile-time option. 2012-12-18 18:30:30 +00:00
Simon Kelley
f8abe0c566 Fix crash in auth code for queries where class != C_IN 2012-12-15 11:59:25 +00:00
Simon Kelley
9def963c65 Bump debian version. 2012-12-14 11:58:56 +00:00
Simon Kelley
990123a937 Fix regexp foobar. 2012-12-14 11:56:15 +00:00
Simon Kelley
1d6c639310 Fix broken cache. 2012-12-14 11:19:36 +00:00
18 changed files with 592 additions and 413 deletions

View File

@@ -5,6 +5,8 @@ version 2.65
Fix failure to build with DHCP support excluded. Thanks to
Gustavo Zacarias for the patch.
Fix nasty regression in 2.64 which completely broke cacheing.
version 2.64

View File

@@ -17,7 +17,7 @@ elif grep '\$Format:%d\$' $1/VERSION >/dev/null 2>&1; then
# unsubstituted VERSION, but no git available.
echo UNKNOWN
else
vers=`cat $1/VERSION | sed 's/[(), ]/,/ g' | tr ',' '\n' | grep $v[0-9]`
vers=`cat $1/VERSION | sed 's/[(), ]/,/ g' | tr ',' '\n' | grep ^v[0-9]`
if [ $? -eq 0 ]; then
echo "${vers}" | sort | head -n 1 | sed 's/^v//'

8
debian/changelog vendored
View File

@@ -1,8 +1,14 @@
dnsmasq (2.66-1) unstable; urgency=low
* New upstream.
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 14 Dec 2012 11:58:41 +0000
dnsmasq (2.65-1) unstable; urgency=low
* New upstream.
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 4 Dec 2012 20:58:12 +0000
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 14 Dec 2012 11:34:12 +0000
dnsmasq (2.64-1) unstable; urgency=low

View File

@@ -16,6 +16,7 @@
#include "dnsmasq.h"
#ifdef HAVE_AUTH
static struct subnet *filter_zone(struct auth_zone *zone, int flag, struct all_addr *addr_u)
{
@@ -117,7 +118,10 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
GETSHORT(qclass, p);
if (qclass != C_IN)
continue;
{
auth = 0;
continue;
}
if (qtype == T_PTR)
{
@@ -732,7 +736,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
return ansp - (unsigned char *)header;
}
#endif

View File

@@ -147,7 +147,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
addr->s6_addr[3] = 0;
}
if (!((*callback)(addr, prefix, scope_id, iface_index, 0, parm)))
if (!((*callback)(addr, prefix, scope_id, iface_index, 0, 0, 0, parm)))
goto err;
}
#endif

View File

@@ -394,7 +394,7 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
int freed_all = flags & F_REVERSE;
int free_avail = 0;
if(daemon->max_cache_ttl < ttl)
if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl)
ttl = daemon->max_cache_ttl;
/* Don't log keys */

View File

@@ -96,12 +96,18 @@ HAVE_CONNTRACK
a build-dependency on libnetfilter_conntrack, but the resulting binary will
still run happily on a kernel without conntrack support.
HAVE_AUTH
define this to include the facility to act as an authoritative DNS
server for one or more zones.
NO_IPV6
NO_TFTP
NO_DHCP
NO_DHCP6
NO_SCRIPT
NO_LARGEFILE
NO_AUTH
these are avilable to explictly disable compile time options which would
otherwise be enabled automatically (HAVE_IPV6, >2Gb file sizes) or
which are enabled by default in the distributed source tree. Building dnsmasq
@@ -123,6 +129,7 @@ RESOLVFILE
#define HAVE_DHCP6
#define HAVE_TFTP
#define HAVE_SCRIPT
#define HAVE_AUTH
/* #define HAVE_LUASCRIPT */
/* #define HAVE_BROKEN_RTC */
/* #define HAVE_DBUS */
@@ -311,6 +318,9 @@ HAVE_SOCKADDR_SA_LEN
#define HAVE_SCRIPT
#endif
#ifdef NO_AUTH
#undef HAVE_AUTH
#endif
/* Define a string indicating which options are in use.
DNSMASQP_COMPILE_OPTS is only defined in dnsmasq.c */
@@ -369,7 +379,11 @@ static char *compile_opts =
#ifndef HAVE_CONNTRACK
"no-"
#endif
"conntrack";
"conntrack "
#ifndef HAVE_AUTH
"no-"
#endif
"auth";
#endif

View File

@@ -333,83 +333,6 @@ void dhcp_update_configs(struct dhcp_config *configs)
}
#ifdef HAVE_DHCP6
static int join_multicast_worker(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
{
char ifrn_name[IFNAMSIZ];
struct ipv6_mreq mreq;
int fd, i, max = *((int *)vparam);
struct iname *tmp;
(void)prefix;
(void)scope;
(void)dad;
/* record which interfaces we join on, so that we do it at most one per
interface, even when they have multiple addresses. Use outpacket
as an array of int, since it's always allocated here and easy
to expand for theoretical vast numbers of interfaces. */
for (i = 0; i < max; i++)
if (if_index == ((int *)daemon->outpacket.iov_base)[i])
return 1;
if ((fd = socket(PF_INET6, SOCK_DGRAM, 0)) == -1)
return 0;
if (!indextoname(fd, if_index, ifrn_name))
{
close(fd);
return 0;
}
close(fd);
/* Are we doing DHCP on this interface? */
if (!iface_check(AF_INET6, (struct all_addr *)local, ifrn_name, NULL))
return 1;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, ifrn_name) == 0))
return 1;
mreq.ipv6mr_interface = if_index;
inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &mreq.ipv6mr_multiaddr);
if (daemon->dhcp6 &&
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
return 0;
inet_pton(AF_INET6, ALL_SERVERS, &mreq.ipv6mr_multiaddr);
if (daemon->dhcp6 &&
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
return 0;
inet_pton(AF_INET6, ALL_ROUTERS, &mreq.ipv6mr_multiaddr);
if (daemon->ra_contexts &&
setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
return 0;
expand_buf(&daemon->outpacket, (max+1) * sizeof(int));
((int *)daemon->outpacket.iov_base)[max++] = if_index;
*((int *)vparam) = max;
return 1;
}
void join_multicast(void)
{
int count = 0;
if (!iface_enumerate(AF_INET6, &count, join_multicast_worker))
die(_("failed to join DHCPv6 multicast group: %s"), NULL, EC_BADNET);
}
#endif
#ifdef HAVE_LINUX_NETWORK
void bindtodevice(int fd)
{
@@ -750,4 +673,86 @@ char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len,
}
void log_context(int family, struct dhcp_context *context)
{
/* Cannot use dhcp_buff* for RA contexts */
void *start = &context->start;
void *end = &context->end;
char *n = "", *m = "", *p = daemon->namebuff;
*p = 0;
#ifdef HAVE_DHCP6
if (family == AF_INET6)
{
struct in6_addr subnet = context->start6;
if (!(context->flags & CONTEXT_TEMPLATE))
setaddr6part(&subnet, 0);
inet_ntop(AF_INET6, &subnet, daemon->addrbuff, ADDRSTRLEN);
start = &context->start6;
end = &context->end6;
}
#endif
if ((context->flags & CONTEXT_DHCP) ||
!(context->flags & (CONTEXT_CONSTRUCTED | CONTEXT_TEMPLATE)))
{
if (family != AF_INET && (context->flags & CONTEXT_DEPRECATE))
strcpy(daemon->namebuff, _(", prefix deprecated"));
else
{
p += sprintf(p, _(", lease time "));
m = p;
prettyprint_time(p, context->lease_time);
p += strlen(p);
}
}
#ifdef HAVE_DHCP6
if (context->flags & CONTEXT_CONSTRUCTED)
{
n = p;
p += sprintf(p, ", constructed for %s", context->template_interface);
}
if (context->flags & CONTEXT_TEMPLATE)
{
n = p;
p += sprintf(p, ", template for %s", context->template_interface);
}
#endif
if ((context->flags & CONTEXT_DHCP) || family == AF_INET)
{
inet_ntop(family, start, daemon->dhcp_buff, 256);
inet_ntop(family, end, daemon->dhcp_buff3, 256);
my_syslog(MS_DHCP | LOG_INFO,
(context->flags & CONTEXT_RA_STATELESS) ?
_("%s stateless on %s%.0s%.0s") :
(context->flags & CONTEXT_STATIC) ?
_("%s, static leases only on %.0s%s%s") :
(context->flags & CONTEXT_PROXY) ?
_("%s, proxy on subnet %.0s%s%.0s") :
_("%s, IP range %s -- %s%s"),
(family != AF_INET) ? "DHCPv6" : "DHCP",
daemon->dhcp_buff, daemon->dhcp_buff3, daemon->namebuff);
}
#ifdef HAVE_DHCP6
if (context->flags & CONTEXT_RA_NAME)
my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s%s"),
daemon->addrbuff, n);
if (context->flags & CONTEXT_RA)
my_syslog(MS_DHCP | LOG_INFO, _("router advertisement on %s%s%s"),
daemon->addrbuff,
(context->flags & (CONTEXT_CONSTRUCTED | CONTEXT_TEMPLATE)) ? "" : ", prefix valid ",
(context->flags & (CONTEXT_CONSTRUCTED | CONTEXT_TEMPLATE)) ? n : m);
#endif
}
#endif

View File

@@ -25,7 +25,8 @@ struct iface_param {
};
static int complete_context6(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam);
int scope, int if_index, int flags,
int preferred, int valid, void *vparam);
static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm);
@@ -181,14 +182,17 @@ void dhcp6_packet(time_t now)
}
static int complete_context6(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
int scope, int if_index, int flags, int preferred,
int valid, void *vparam)
{
struct dhcp_context *context;
struct iface_param *param = vparam;
struct iname *tmp;
(void)scope; /* warning */
(void)dad;
(void)flags;
(void)preferred;
(void)valid;
if (if_index == param->ind &&
!IN6_IS_ADDR_LOOPBACK(local) &&
@@ -210,7 +214,8 @@ static int complete_context6(struct in6_addr *local, int prefix,
for (context = daemon->dhcp6; context; context = context->next)
{
if (prefix == context->prefix &&
if (!(context->flags & CONTEXT_TEMPLATE) &&
prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
{
@@ -467,6 +472,131 @@ static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, vo
return 0;
}
struct cparam {
time_t now;
int newone;
};
static int construct_worker(struct in6_addr *local, int prefix,
int scope, int if_index, int flags,
int preferred, int valid, void *vparam)
{
char ifrn_name[IFNAMSIZ];
struct in6_addr start6, end6;
struct dhcp_context *template, *context;
(void)scope;
(void)flags;
(void)valid;
(void)preferred;
struct cparam *param = vparam;
if (IN6_IS_ADDR_LOOPBACK(local) ||
IN6_IS_ADDR_LINKLOCAL(local) ||
IN6_IS_ADDR_MULTICAST(local))
return 1;
if (!indextoname(daemon->doing_dhcp6 ? daemon->dhcp6fd : daemon->icmp6fd, if_index, ifrn_name))
return 0;
for (template = daemon->dhcp6; template; template = template->next)
if (!(template->flags & CONTEXT_TEMPLATE))
{
/* non-template entries, just fill in interface and local addresses */
if (prefix == template->prefix &&
is_same_net6(local, &template->start6, prefix) &&
is_same_net6(local, &template->end6, prefix))
{
template->if_index = if_index;
template->local6 = *local;
}
}
else if (strcmp(ifrn_name, template->template_interface) == 0 &&
addr6part(local) == addr6part(&template->start6))
{
start6 = *local;
setaddr6part(&start6, addr6part(&template->start6));
end6 = *local;
setaddr6part(&end6, addr6part(&template->end6));
for (context = daemon->dhcp6; context; context = context->next)
if ((context->flags & CONTEXT_CONSTRUCTED) &&
IN6_ARE_ADDR_EQUAL(&start6, &context->start6) &&
IN6_ARE_ADDR_EQUAL(&end6, &context->end6))
{
context->flags &= ~CONTEXT_GC;
break;
}
if (!context && (context = whine_malloc(sizeof (struct dhcp_context))))
{
*context = *template;
context->start6 = start6;
context->end6 = end6;
context->flags &= ~CONTEXT_TEMPLATE;
context->flags |= CONTEXT_CONSTRUCTED;
context->if_index = if_index;
context->local6 = *local;
context->next = daemon->dhcp6;
daemon->dhcp6 = context;
ra_start_unsolicted(param->now, context);
/* we created a new one, need to call
lease_update_file to get periodic functions called */
param->newone = 1;
log_context(AF_INET6, context);
}
}
return 1;
}
void dhcp_construct_contexts(time_t now)
{
struct dhcp_context *tmp, *context, **up;
struct cparam param;
param.newone = 0;
param.now = now;
for (context = daemon->dhcp6; context; context = context->next)
if (context->flags & CONTEXT_CONSTRUCTED)
{
context->flags |= CONTEXT_GC;
context->if_index = 0;
}
iface_enumerate(AF_INET6, &param, construct_worker);
for (up = &daemon->dhcp6, context = daemon->dhcp6; context; context = tmp)
{
tmp = context->next;
if (context->flags & CONTEXT_GC)
{
if (daemon->dhcp6 == context)
daemon->dhcp6 = context->next;
*up = context->next;
free(context);
}
else
up = &context->next;
}
if (param.newone)
{
if (daemon->dhcp || daemon->doing_dhcp6)
lease_update_file(now);
else
/* Not doing DHCP, so no lease system, manage alarms for ra only */
send_alarm(periodic_ra(now), now);
}
}
#endif

View File

@@ -51,6 +51,7 @@ int main (int argc, char **argv)
cap_user_header_t hdr = NULL;
cap_user_data_t data = NULL;
#endif
struct dhcp_context *context;
#ifdef LOCALEDIR
setlocale(LC_ALL, "");
@@ -148,6 +149,11 @@ int main (int argc, char **argv)
die(_("asychronous logging is not available under Android"), NULL, EC_BADCONF);
#endif
#ifndef HAVE_AUTH
if (daemon->authserver)
die(_("authoritative DNS not available: set HAVE_AUTH in src/config.h"), NULL, EC_BADCONF);
#endif
rand_init();
now = dnsmasq_time();
@@ -162,63 +168,58 @@ int main (int argc, char **argv)
#ifdef HAVE_DHCP
if (daemon->dhcp || daemon->dhcp6)
{
{
# ifdef HAVE_DHCP6
if (daemon->dhcp6)
{
daemon->doing_ra = option_bool(OPT_RA);
for (context = daemon->dhcp6; context; context = context->next)
{
if (context->flags & CONTEXT_DHCP)
daemon->doing_dhcp6 = 1;
if (context->flags & CONTEXT_RA)
daemon->doing_ra = 1;
#ifndef HAVE_LINUX_NETWORK
if (context->flags & CONTEXT_TEMPLATE)
die (_("dhcp-range constructor not available on this platform"), NULL, EC_BADCONF);
#endif
}
}
# endif
/* Note that order matters here, we must call lease_init before
creating any file descriptors which shouldn't be leaked
to the lease-script init process. We need to call common_init
before lease_init to allocate buffers it uses.*/
dhcp_common_init();
lease_init(now);
if (daemon->dhcp || daemon->doing_dhcp6)
{
dhcp_common_init();
lease_init(now);
}
if (daemon->dhcp)
dhcp_init();
}
# ifdef HAVE_DHCP6
/* Start RA subsystem if --enable-ra OR dhcp-range=<subnet>, ra-only */
if (daemon->ra_contexts || option_bool(OPT_RA))
{
/* link the DHCP6 contexts to the ra-only ones so we can traverse them all
from ->ra_contexts, but only the non-ra-onlies from ->dhcp6 */
struct dhcp_context *context;
if (daemon->doing_ra)
ra_init(now);
if (!daemon->ra_contexts)
daemon->ra_contexts = daemon->dhcp6;
else
{
for (context = daemon->ra_contexts; context->next; context = context->next);
context->next = daemon->dhcp6;
}
ra_init(now);
}
if (daemon->dhcp6)
dhcp6_init();
if (daemon->doing_dhcp6)
dhcp6_init();
# endif
}
#endif
#ifdef HAVE_LINUX_NETWORK
/* After lease_init */
netlink_init();
if (option_bool(OPT_NOWILD) && option_bool(OPT_CLEVERBIND))
die(_("cannot set --bind-interfaces and --bind-dynamic"), NULL, EC_BADCONF);
#endif
#ifdef HAVE_DHCP6
/* after netlink_init */
if (daemon->ra_contexts || daemon->dhcp6)
join_multicast();
#endif
#ifdef HAVE_DHCP
/* after netlink_init */
if (daemon->dhcp || daemon->dhcp6)
lease_find_interfaces(now);
#endif
if (!enumerate_interfaces())
die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
@@ -248,6 +249,12 @@ int main (int argc, char **argv)
}
else
create_wildcard_listeners();
#ifdef HAVE_DHCP6
/* after enumerate_interfaces() */
if (daemon->doing_dhcp6 || daemon->doing_ra)
join_multicast(1);
#endif
if (daemon->port != 0)
cache_init();
@@ -623,90 +630,27 @@ int main (int argc, char **argv)
if (daemon->max_logs != 0)
my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
if (daemon->ra_contexts)
my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
#ifdef HAVE_DHCP
if (daemon->dhcp || daemon->dhcp6 || daemon->ra_contexts)
{
struct dhcp_context *dhcp_tmp;
int family = AF_INET;
dhcp_tmp = daemon->dhcp;
#ifdef HAVE_DHCP6
again:
#endif
for (; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
{
void *start = &dhcp_tmp->start;
void *end = &dhcp_tmp->end;
#ifdef HAVE_DHCP6
if (family == AF_INET6)
{
start = &dhcp_tmp->start6;
end = &dhcp_tmp->end6;
struct in6_addr subnet = dhcp_tmp->start6;
setaddr6part(&subnet, 0);
inet_ntop(AF_INET6, &subnet, daemon->dhcp_buff2, 256);
}
#endif
if (family != AF_INET && (dhcp_tmp->flags & CONTEXT_DEPRECATE))
strcpy(daemon->namebuff, _("prefix deprecated"));
else
{
char *p = daemon->namebuff;
p += sprintf(p, _("lease time "));
prettyprint_time(p, dhcp_tmp->lease_time);
}
inet_ntop(family, start, daemon->dhcp_buff, 256);
inet_ntop(family, end, daemon->dhcp_buff3, 256);
if ((dhcp_tmp->flags & CONTEXT_DHCP) || family == AF_INET)
my_syslog(MS_DHCP | LOG_INFO,
(dhcp_tmp->flags & CONTEXT_RA_STATELESS) ?
_("%s stateless on %s%.0s%.0s") :
(dhcp_tmp->flags & CONTEXT_STATIC) ?
_("%s, static leases only on %.0s%s, %s") :
(dhcp_tmp->flags & CONTEXT_PROXY) ?
_("%s, proxy on subnet %.0s%s%.0s") :
_("%s, IP range %s -- %s, %s"),
(family != AF_INET) ? "DHCPv6" : "DHCP",
daemon->dhcp_buff, daemon->dhcp_buff3, daemon->namebuff);
for (context = daemon->dhcp; context; context = context->next)
log_context(AF_INET, context);
if (dhcp_tmp->flags & CONTEXT_RA_NAME)
my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s"),
daemon->dhcp_buff2);
if (dhcp_tmp->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS))
{
if (!(dhcp_tmp->flags & CONTEXT_DEPRECATE))
{
char *p = daemon->namebuff;
p += sprintf(p, _("prefix valid "));
prettyprint_time(p, dhcp_tmp->lease_time > 7200 ? dhcp_tmp->lease_time : 7200);
}
my_syslog(MS_DHCP | LOG_INFO, _("SLAAC on %s %s"),
daemon->dhcp_buff2, daemon->namebuff);
}
}
#ifdef HAVE_DHCP6
if (family == AF_INET)
{
family = AF_INET6;
if (daemon->ra_contexts)
dhcp_tmp = daemon->ra_contexts;
else
dhcp_tmp = daemon->dhcp6;
goto again;
}
#endif
# ifdef HAVE_DHCP6
for (context = daemon->dhcp6; context; context = context->next)
log_context(AF_INET6, context);
}
#endif
if (daemon->doing_dhcp6 || daemon->doing_ra)
dhcp_construct_contexts(now);
if (option_bool(OPT_RA))
my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
# endif
/* after dhcp_contruct_contexts */
if (daemon->dhcp || daemon->doing_dhcp6)
lease_find_interfaces(now);
#endif
#ifdef HAVE_TFTP
if (option_bool(OPT_TFTP))
@@ -813,13 +757,13 @@ int main (int argc, char **argv)
#endif
#ifdef HAVE_DHCP6
if (daemon->dhcp6)
if (daemon->doing_dhcp6)
{
FD_SET(daemon->dhcp6fd, &rset);
bump_maxfd(daemon->dhcp6fd, &maxfd);
}
if (daemon->ra_contexts)
if (daemon->doing_ra)
{
FD_SET(daemon->icmp6fd, &rset);
bump_maxfd(daemon->icmp6fd, &maxfd);
@@ -883,7 +827,7 @@ int main (int argc, char **argv)
#ifdef HAVE_LINUX_NETWORK
if (FD_ISSET(daemon->netlinkfd, &rset))
netlink_multicast();
netlink_multicast(now);
#endif
/* Check for changes to resolv files once per second max. */
@@ -931,11 +875,11 @@ int main (int argc, char **argv)
}
#ifdef HAVE_DHCP6
if (daemon->dhcp6 && FD_ISSET(daemon->dhcp6fd, &rset))
if (daemon->doing_dhcp6 && FD_ISSET(daemon->dhcp6fd, &rset))
dhcp6_packet(now);
if (daemon->ra_contexts && FD_ISSET(daemon->icmp6fd, &rset))
icmp6_packet();
if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
icmp6_packet(now);
#endif
# ifdef HAVE_SCRIPT
@@ -1115,13 +1059,13 @@ static void async_event(int pipe, time_t now)
case EVENT_ALARM:
#ifdef HAVE_DHCP
if (daemon->dhcp || daemon->dhcp6)
if (daemon->dhcp || daemon->doing_dhcp6)
{
lease_prune(NULL, now);
lease_update_file(now);
}
#ifdef HAVE_DHCP6
else if (daemon->ra_contexts)
else if (daemon->doing_ra)
/* Not doing DHCP, so no lease system, manage alarms for ra only */
send_alarm(periodic_ra(now), now);
#endif
@@ -1278,7 +1222,7 @@ void clear_cache_and_reload(time_t now)
cache_reload();
#ifdef HAVE_DHCP
if (daemon->dhcp || daemon->dhcp6)
if (daemon->dhcp || daemon->doing_dhcp6)
{
if (option_bool(OPT_ETHERS))
dhcp_read_ethers();
@@ -1289,7 +1233,7 @@ void clear_cache_and_reload(time_t now)
lease_update_dns(1);
}
#ifdef HAVE_DHCP6
else if (daemon->ra_contexts)
else if (daemon->doing_ra)
/* Not doing DHCP, so no lease system, manage
alarms for ra only */
send_alarm(periodic_ra(now), now);
@@ -1592,7 +1536,7 @@ int icmp_ping(struct in_addr addr)
set_log_writer(&wset, &maxfd);
#ifdef HAVE_DHCP6
if (daemon->ra_contexts)
if (daemon->doing_ra)
{
FD_SET(daemon->icmp6fd, &rset);
bump_maxfd(daemon->icmp6fd, &maxfd);
@@ -1611,8 +1555,8 @@ int icmp_ping(struct in_addr addr)
check_dns_listeners(&rset, now);
#ifdef HAVE_DHCP6
if (daemon->ra_contexts && FD_ISSET(daemon->icmp6fd, &rset))
icmp6_packet();
if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
icmp6_packet(now);
#endif
#ifdef HAVE_TFTP

View File

@@ -389,6 +389,11 @@ union mysockaddr {
#endif
};
/* bits in flag param to IPv6 callbacks from iface_enumerate() */
#define IFACE_TENTATIVE 1
#define IFACE_DEPRECATED 2
#define SERV_FROM_RESOLV 1 /* 1 for servers from resolv, 0 for command line. */
#define SERV_NO_ADDR 2 /* no server, this domain is local only */
#define SERV_LITERAL_ADDRESS 4 /* addr is the answer, not the server */
@@ -428,8 +433,8 @@ struct server {
struct irec {
union mysockaddr addr;
struct in_addr netmask; /* only valid for IPv4 */
int tftp_ok, dhcp_ok, mtu, done, dad, dns_auth;
char *name;
int tftp_ok, dhcp_ok, mtu, done, dad, dns_auth, index, multicast_done;
char *name;
struct irec *next;
};
@@ -667,7 +672,7 @@ struct cond_domain {
#endif
int is6;
struct cond_domain *next;
};
};
struct dhcp_context {
unsigned int lease_time, addr_epoch;
@@ -678,7 +683,8 @@ struct dhcp_context {
struct in6_addr start6, end6; /* range of available addresses */
struct in6_addr local6;
int prefix, if_index;
time_t ra_time;
time_t ra_time, ra_short_period_start;
char *template_interface;
#endif
int flags;
struct dhcp_netid netid, *filter;
@@ -695,6 +701,11 @@ struct dhcp_context {
#define CONTEXT_RA_STATELESS 128
#define CONTEXT_DHCP 256
#define CONTEXT_DEPRECATE 512
#define CONTEXT_TEMPLATE 1024 /* create contexts using addresses */
#define CONTEXT_CONSTRUCTED 2048
#define CONTEXT_GC 4096
#define CONTEXT_RA 8192
struct ping_result {
struct in_addr addr;
@@ -773,7 +784,7 @@ extern struct daemon {
int port, query_port, min_port;
unsigned long local_ttl, neg_ttl, max_ttl, max_cache_ttl, auth_ttl;
struct hostsfile *addn_hosts;
struct dhcp_context *dhcp, *dhcp6, *ra_contexts;
struct dhcp_context *dhcp, *dhcp6;
struct dhcp_config *dhcp_conf;
struct dhcp_opt *dhcp_opts, *dhcp_match, *dhcp_opts6, *dhcp_match6;
struct dhcp_vendor *dhcp_vendors;
@@ -784,6 +795,7 @@ extern struct daemon {
struct addr_list *override_relays;
int override;
int enable_pxe;
int doing_ra, doing_dhcp6;
struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *dhcp_gen_names;
struct dhcp_netid_list *force_broadcast, *bootp_dynamic;
struct hostsfile *dhcp_hosts_file, *dhcp_opts_file;
@@ -910,7 +922,9 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
int in_arpa_name_2_addr(char *namein, struct all_addr *addrp);
/* auth.c */
#ifdef HAVE_AUTH
size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr);
#endif
/* util.c */
void rand_init(void);
@@ -991,6 +1005,9 @@ struct in_addr get_ifaddr(char *intr);
#ifdef HAVE_IPV6
int set_ipv6pktinfo(int fd);
#endif
#ifdef HAVE_DHCP6
void join_multicast(int dienow);
#endif
/* dhcp.c */
#ifdef HAVE_DHCP
@@ -1072,7 +1089,7 @@ void poll_resolv(int force, int do_reload, time_t now);
/* netlink.c */
#ifdef HAVE_LINUX_NETWORK
void netlink_init(void);
void netlink_multicast(void);
void netlink_multicast(time_t now);
#endif
/* bpf.c */
@@ -1140,6 +1157,7 @@ struct dhcp_config *find_config6(struct dhcp_config *configs,
struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net,
int prefix, u64 addr);
void make_duid(time_t now);
void dhcp_construct_contexts(time_t now);
#endif
/* rfc3315.c */
@@ -1170,8 +1188,8 @@ void bindtodevice(int fd);
#endif
# ifdef HAVE_DHCP6
void display_opts6(void);
void join_multicast(void);
# endif
void log_context(int family, struct dhcp_context *context);
#endif
/* outpacket.c */
@@ -1190,16 +1208,14 @@ void put_opt6_string(char *s);
/* radv.c */
#ifdef HAVE_DHCP6
void ra_init(time_t now);
void icmp6_packet(void);
void icmp6_packet(time_t now);
time_t periodic_ra(time_t now);
void ra_start_unsolicted(time_t now, struct dhcp_context *context);
#endif
/* slaac.c */
#ifdef HAVE_DHCP6
void build_subnet_map(void);
void slaac_add_addrs(struct dhcp_lease *lease, time_t now, int force);
time_t periodic_slaac(time_t now, struct dhcp_lease *leases);
void slaac_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface, struct dhcp_lease *leases);
void schedule_subnet_map(void);
#endif

View File

@@ -812,6 +812,7 @@ void receive_query(struct listener *listen, time_t now)
#endif
}
#ifdef HAVE_AUTH
if (auth_dns)
{
m = answer_auth(header, ((char *) header) + PACKETSZ, (size_t)n, now, &source_addr);
@@ -820,6 +821,7 @@ void receive_query(struct listener *listen, time_t now)
(char *)header, m, &source_addr, &dst_addr, if_index);
}
else
#endif
{
m = answer_request(header, ((char *) header) + PACKETSZ, (size_t)n,
dst_addr_4, netmask, now);
@@ -903,9 +905,11 @@ unsigned char *tcp_request(int confd, time_t now,
else
dst_addr_4.s_addr = 0;
#ifdef HAVE_AUTH
if (auth_dns)
m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr);
else
#endif
{
/* m > 0 if answered from cache */
m = answer_request(header, ((char *) header) + 65536, (size_t)size,

View File

@@ -308,7 +308,7 @@ void lease_update_file(time_t now)
#ifdef HAVE_DHCP6
/* do timed RAs and determine when the next is, also pings to potential SLAAC addresses */
if (daemon->ra_contexts)
if (daemon->doing_ra)
{
time_t event;
@@ -363,12 +363,15 @@ static int find_interface_v4(struct in_addr local, int if_index,
#ifdef HAVE_DHCP6
static int find_interface_v6(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
int scope, int if_index, int flags,
int preferred, int valid, void *vparam)
{
struct dhcp_lease *lease;
(void)scope;
(void)dad;
(void)flags;
(void)preferred;
(void)valid;
for (lease = leases; lease; lease = lease->next)
if ((lease->flags & (LEASE_TA | LEASE_NA)))
@@ -395,10 +398,6 @@ void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *inte
start-time. */
void lease_find_interfaces(time_t now)
{
#ifdef HAVE_DHCP6
build_subnet_map();
#endif
iface_enumerate(AF_INET, &now, find_interface_v4);
#ifdef HAVE_DHCP6
iface_enumerate(AF_INET6, &now, find_interface_v6);

View File

@@ -39,6 +39,7 @@ static struct iovec iov;
static u32 netlink_pid;
static int nl_async(struct nlmsghdr *h);
static void nl_newinterface(time_t now);
void netlink_init(void)
{
@@ -50,10 +51,14 @@ void netlink_init(void)
addr.nl_pid = 0; /* autobind */
addr.nl_groups = RTMGRP_IPV4_ROUTE;
if (option_bool(OPT_CLEVERBIND))
addr.nl_groups |= RTMGRP_IPV4_IFADDR;
addr.nl_groups |= RTMGRP_IPV4_IFADDR;
#ifdef HAVE_IPV6
addr.nl_groups |= RTMGRP_IPV6_ROUTE;
if (daemon->ra_contexts || option_bool(OPT_CLEVERBIND))
if (option_bool(OPT_CLEVERBIND))
addr.nl_groups |= RTMGRP_IPV6_IFADDR;
#endif
#ifdef HAVE_DHCP6
if (daemon->doing_ra || daemon->doing_dhcp6)
addr.nl_groups |= RTMGRP_IPV6_IFADDR;
#endif
@@ -187,7 +192,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
if (h->nlmsg_seq != seq || h->nlmsg_pid != netlink_pid || h->nlmsg_type == NLMSG_ERROR)
{
/* May be multicast arriving async */
if (nl_async(h) && option_bool(OPT_CLEVERBIND))
if (nl_async(h))
newaddr = 1;
}
else if (h->nlmsg_type == NLMSG_DONE)
@@ -195,11 +200,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
/* handle async new interface address arrivals, these have to be done
after we complete as we're not re-entrant */
if (newaddr)
{
enumerate_interfaces();
create_bound_listeners(0);
}
nl_newinterface(dnsmasq_time());
return callback_ok;
}
else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC && family != AF_LOCAL)
@@ -236,17 +238,32 @@ int iface_enumerate(int family, void *parm, int (*callback)())
else if (ifa->ifa_family == AF_INET6)
{
struct in6_addr *addrp = NULL;
u32 valid = 0, preferred = 0;
int flags = 0;
while (RTA_OK(rta, len1))
{
if (rta->rta_type == IFA_ADDRESS)
addrp = ((struct in6_addr *)(rta+1));
else if (rta->rta_type == IFA_CACHEINFO)
{
struct ifa_cacheinfo *ifc = (struct ifa_cacheinfo *)(rta+1);
preferred = ifc->ifa_prefered;
valid = ifc->ifa_valid;
}
rta = RTA_NEXT(rta, len1);
}
if (ifa->ifa_flags & IFA_F_TENTATIVE)
flags |= IFACE_TENTATIVE;
if (ifa->ifa_flags & IFA_F_DEPRECATED)
flags |= IFACE_DEPRECATED;
if (addrp && callback_ok)
if (!((*callback)(addrp, (int)(ifa->ifa_prefixlen), (int)(ifa->ifa_scope),
(int)(ifa->ifa_index), (int)(ifa->ifa_flags & IFA_F_TENTATIVE), parm)))
(int)(ifa->ifa_index), flags,
(int) preferred, (int)valid, parm)))
callback_ok = 0;
}
#endif
@@ -305,7 +322,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
}
}
void netlink_multicast(void)
void netlink_multicast(time_t now)
{
ssize_t len;
struct nlmsghdr *h;
@@ -318,17 +335,14 @@ void netlink_multicast(void)
if ((len = netlink_recv()) != -1)
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
if (nl_async(h) && option_bool(OPT_CLEVERBIND))
if (nl_async(h))
newaddr = 1;
/* restore non-blocking status */
fcntl(daemon->netlinkfd, F_SETFL, flags);
if (newaddr)
{
enumerate_interfaces();
create_bound_listeners(0);
}
nl_newinterface(now);
}
static int nl_async(struct nlmsghdr *h)
@@ -371,25 +385,33 @@ static int nl_async(struct nlmsghdr *h)
}
return 0;
}
else if (h->nlmsg_type == RTM_NEWADDR)
{
#ifdef HAVE_DHCP6
/* force RAs to sync new network and pick up new interfaces. */
if (daemon->ra_contexts)
{
schedule_subnet_map();
ra_start_unsolicted(dnsmasq_time(), NULL);
/* cause lease_update_file to run after we return, in case we were called from
iface_enumerate and can't re-enter it now */
send_alarm(0, 0);
}
#endif
return 1; /* clever bind mode - rescan */
}
else if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
return 1; /* clever bind mode - rescan */
return 0;
}
static void nl_newinterface(time_t now)
{
if (option_bool(OPT_CLEVERBIND))
{
enumerate_interfaces();
create_bound_listeners(0);
}
#ifdef HAVE_DHCP6
if (daemon->doing_dhcp6 || daemon->doing_ra)
{
dhcp_construct_contexts(now);
join_multicast(0);
}
if (daemon->doing_dhcp6)
lease_find_interfaces(now);
#endif
}
#endif

View File

@@ -272,7 +272,8 @@ static int iface_allowed(struct irec **irecp, int if_index,
iface->dns_auth = auth_dns;
iface->mtu = mtu;
iface->dad = dad;
iface->done = 0;
iface->done = iface->multicast_done = 0;
iface->index = if_index;
if ((iface->name = whine_malloc(strlen(ifr.ifr_name)+1)))
{
strcpy(iface->name, ifr.ifr_name);
@@ -281,6 +282,7 @@ static int iface_allowed(struct irec **irecp, int if_index,
return 1;
}
free(iface);
}
errno = ENOMEM;
@@ -289,7 +291,8 @@ static int iface_allowed(struct irec **irecp, int if_index,
#ifdef HAVE_IPV6
static int iface_allowed_v6(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
int scope, int if_index, int flags,
int preferred, int valid, void *vparam)
{
union mysockaddr addr;
struct in_addr netmask; /* dummy */
@@ -297,6 +300,8 @@ static int iface_allowed_v6(struct in6_addr *local, int prefix,
(void)prefix; /* warning */
(void)scope; /* warning */
(void)preferred;
(void)valid;
memset(&addr, 0, sizeof(addr));
#ifdef HAVE_SOCKADDR_SA_LEN
@@ -307,7 +312,7 @@ static int iface_allowed_v6(struct in6_addr *local, int prefix,
addr.in6.sin6_port = htons(daemon->port);
addr.in6.sin6_scope_id = if_index;
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, dad);
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, !!(flags & IFACE_TENTATIVE));
}
#endif
@@ -584,6 +589,61 @@ int is_dad_listeners(void)
return 0;
}
#ifdef HAVE_DHCP6
void join_multicast(int dienow)
{
struct irec *iface, *tmp;
for (iface = daemon->interfaces; iface; iface = iface->next)
if (iface->dhcp_ok && !iface->multicast_done)
{
/* There's an irec per address but we only want to join for multicast
once per interface. Weed out duplicates. */
for (tmp = daemon->interfaces; tmp; tmp = tmp->next)
if (tmp->multicast_done && tmp->index == iface->index)
break;
iface->multicast_done = 1;
if (!tmp)
{
struct ipv6_mreq mreq;
int err = 0;
mreq.ipv6mr_interface = iface->index;
inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &mreq.ipv6mr_multiaddr);
if (daemon->doing_dhcp6 &&
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
err = 1;
inet_pton(AF_INET6, ALL_SERVERS, &mreq.ipv6mr_multiaddr);
if (daemon->doing_dhcp6 &&
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
err = 1;
inet_pton(AF_INET6, ALL_ROUTERS, &mreq.ipv6mr_multiaddr);
if (daemon->doing_ra &&
setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
err = 1;
if (err)
{
char *s = _("interface %s failed to join DHCPv6 multicast group: %s");
if (dienow)
die(s, iface->name, EC_BADNET);
else
my_syslog(LOG_ERR, s, iface->name, strerror(errno));
}
}
}
}
#endif
/* return a UDP socket bound to a random port, have to cope with straying into
occupied port nos and reserved ones. */
int random_sock(int family)

View File

@@ -2180,7 +2180,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
case 'F': /* --dhcp-range */
{
int k, leasepos = 2;
char *cp, *a[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
char *cp, *a[8] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
struct dhcp_context *new = opt_malloc(sizeof(struct dhcp_context));
memset (new, 0, sizeof(*new));
@@ -2227,7 +2227,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
}
}
for (k = 1; k < 7; k++)
for (k = 1; k < 8; k++)
if (!(a[k] = split(a[k-1])))
break;
@@ -2284,28 +2284,25 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
if (strcmp(a[leasepos], "static") == 0)
new->flags |= CONTEXT_STATIC | CONTEXT_DHCP;
else if (strcmp(a[leasepos], "ra-only") == 0 || strcmp(a[leasepos], "slaac") == 0 )
new->flags |= CONTEXT_RA_ONLY;
new->flags |= CONTEXT_RA_ONLY | CONTEXT_RA;
else if (strcmp(a[leasepos], "ra-names") == 0)
new->flags |= CONTEXT_RA_NAME;
new->flags |= CONTEXT_RA_NAME | CONTEXT_RA;
else if (strcmp(a[leasepos], "ra-stateless") == 0)
new->flags |= CONTEXT_RA_STATELESS | CONTEXT_DHCP;
new->flags |= CONTEXT_RA_STATELESS | CONTEXT_DHCP | CONTEXT_RA;
else if (leasepos == 1 && inet_pton(AF_INET6, a[leasepos], &new->end6))
new->flags |= CONTEXT_DHCP;
else if (strstr(a[leasepos], "constructor:") == a[leasepos])
{
new->template_interface = opt_string_alloc(a[leasepos] + 12);
new->flags |= CONTEXT_TEMPLATE;
}
else
break;
}
if (new->flags & CONTEXT_DHCP)
{
new->next = daemon->dhcp6;
daemon->dhcp6 = new;
}
else
{
new->next = daemon->ra_contexts;
daemon->ra_contexts = new;
}
new->next = daemon->dhcp6;
daemon->dhcp6 = new;
/* bare integer < 128 is prefix value */
if (leasepos < k)
{
@@ -2317,10 +2314,14 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
{
new->prefix = pref;
leasepos++;
if ((new->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)) &&
new->prefix != 64)
ret_err(_("prefix must be exactly 64 for RA subnets"));
else if (new->prefix < 64)
if (new->prefix != 64)
{
if ((new->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
ret_err(_("prefix must be exactly 64 for RA subnets"));
else if (new->template_interface)
ret_err(_("prefix must be exactly 64 for subnet constructors"));
}
if (new->prefix < 64)
ret_err(_("prefix must be at least 64"));
}
}

View File

@@ -27,25 +27,28 @@
#include <netinet/icmp6.h>
struct ra_param {
time_t now;
int ind, managed, other, found_context, first;
char *if_name;
struct dhcp_netid *tags;
struct in6_addr link_local;
struct in6_addr link_local, link_global;
unsigned int pref_time;
};
struct search_param {
time_t now; int iface;
};
static void send_ra(int iface, char *iface_name, struct in6_addr *dest);
static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest);
static int add_prefixes(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam);
int scope, int if_index, int flags,
unsigned int preferred, unsigned int valid, void *vparam);
static int iface_search(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam);
int scope, int if_index, int flags,
int prefered, int valid, void *vparam);
static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm);
static int hop_limit;
static time_t ra_short_period_start;
void ra_init(time_t now)
{
@@ -62,7 +65,7 @@ void ra_init(time_t now)
expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet));
/* See if we're guessing SLAAC addresses, if so we need to recieve ping replies */
for (context = daemon->ra_contexts; context; context = context->next)
for (context = daemon->dhcp6; context; context = context->next)
if ((context->flags & CONTEXT_RA_NAME))
break;
@@ -94,18 +97,20 @@ void ra_start_unsolicted(time_t now, struct dhcp_context *context)
if it's not appropriate to advertise those contexts.
This gets re-called on a netlink route-change to re-do the advertisement
and pick up new interfaces */
if (context)
context->ra_time = now;
context->ra_short_period_start = context->ra_time = now;
else
for (context = daemon->ra_contexts; context; context = context->next)
context->ra_time = now + (rand16()/13000); /* range 0 - 5 */
/* re-do frequently for a minute or so, in case the first gets lost. */
ra_short_period_start = now;
for (context = daemon->dhcp6; context; context = context->next)
if (!(context->flags & CONTEXT_TEMPLATE))
{
context->ra_time = now + (rand16()/13000); /* range 0 - 5 */
/* re-do frequently for a minute or so, in case the first gets lost. */
context->ra_short_period_start = now;
}
}
void icmp6_packet(void)
void icmp6_packet(time_t now)
{
char interface[IF_NAMESIZE+1];
ssize_t sz;
@@ -174,11 +179,11 @@ void icmp6_packet(void)
my_syslog(MS_DHCP | LOG_INFO, "RTR-SOLICIT(%s) %s", interface, mac);
/* source address may not be valid in solicit request. */
send_ra(if_index, interface, !IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr) ? &from.sin6_addr : NULL);
send_ra(now, if_index, interface, !IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr) ? &from.sin6_addr : NULL);
}
}
static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest)
{
struct ra_packet *ra;
struct ra_param parm;
@@ -206,13 +211,15 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
parm.found_context = 0;
parm.if_name = iface_name;
parm.first = 1;
parm.now = now;
parm.pref_time = 0;
/* set tag with name == interface */
iface_id.net = iface_name;
iface_id.next = NULL;
parm.tags = &iface_id;
for (context = daemon->ra_contexts; context; context = context->next)
for (context = daemon->dhcp6; context; context = context->next)
{
context->flags &= ~CONTEXT_RA_DONE;
context->netid.next = &context->netid;
@@ -260,7 +267,7 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
/* zero means "self" */
for (i = 0; i < opt_cfg->len; i += IN6ADDRSZ, a++)
if (IN6_IS_ADDR_UNSPECIFIED(a))
put_opt6(&parm.link_local, IN6ADDRSZ);
put_opt6(&parm.link_global, IN6ADDRSZ);
else
put_opt6(a, IN6ADDRSZ);
}
@@ -288,7 +295,7 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
put_opt6_char(3);
put_opt6_short(0);
put_opt6_long(1800); /* lifetime - twice RA retransmit */
put_opt6(&parm.link_local, IN6ADDRSZ);
put_opt6(&parm.link_global, IN6ADDRSZ);
}
/* set managed bits unless we're providing only RA on this link */
@@ -320,19 +327,18 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
}
static int add_prefixes(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
int scope, int if_index, int flags,
unsigned int preferred, unsigned int valid, void *vparam)
{
struct ra_param *param = vparam;
(void)scope; /* warning */
(void)dad;
if (if_index == param->ind)
{
if (IN6_IS_ADDR_LINKLOCAL(local))
param->link_local = *local;
else if (!IN6_IS_ADDR_LOOPBACK(local) &&
!IN6_IS_ADDR_LINKLOCAL(local) &&
!IN6_IS_ADDR_MULTICAST(local))
{
int do_prefix = 0;
@@ -341,8 +347,9 @@ static int add_prefixes(struct in6_addr *local, int prefix,
unsigned int time = 0xffffffff;
struct dhcp_context *context;
for (context = daemon->ra_contexts; context; context = context->next)
if (prefix == context->prefix &&
for (context = daemon->dhcp6; context; context = context->next)
if (!(context->flags & CONTEXT_TEMPLATE) &&
prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
{
@@ -365,7 +372,7 @@ static int add_prefixes(struct in6_addr *local, int prefix,
param->managed = 1;
param->other = 1;
}
/* find floor time */
if (time > context->lease_time)
time = context->lease_time;
@@ -395,6 +402,25 @@ static int add_prefixes(struct in6_addr *local, int prefix,
param->first = 0;
param->found_context = 1;
}
/* configured time is ceiling */
if (valid > time)
valid = time;
if ((flags & IFACE_DEPRECATED) || deprecate)
preferred = 0;
else
{
/* configured time is ceiling */
if (preferred > time)
preferred = time;
}
if (preferred > param->pref_time)
{
param->pref_time = preferred;
param->link_global = *local;
}
if (do_prefix)
{
@@ -405,17 +431,13 @@ static int add_prefixes(struct in6_addr *local, int prefix,
/* zero net part of address */
setaddr6part(local, addr6part(local) & ~((prefix == 64) ? (u64)-1LL : (1LLU << (128 - prefix)) - 1LLU));
/* lifetimes must be min 2 hrs, by RFC 2462 */
if (time < 7200)
time = 7200;
opt->type = ICMP6_OPT_PREFIX;
opt->len = 4;
opt->prefix_len = prefix;
/* autonomous only if we're not doing dhcp, always set "on-link" */
opt->flags = do_slaac ? 0xC0 : 0x80;
opt->valid_lifetime = htonl(time);
opt->preferred_lifetime = htonl(deprecate ? 0 : time);
opt->valid_lifetime = htonl(valid);
opt->preferred_lifetime = htonl(preferred);
opt->reserved = 0;
opt->prefix = *local;
@@ -462,7 +484,7 @@ time_t periodic_ra(time_t now)
while (1)
{
/* find overdue events, and time of first future event */
for (next_event = 0, context = daemon->ra_contexts; context; context = context->next)
for (next_event = 0, context = daemon->dhcp6; context; context = context->next)
if (context->ra_time != 0)
{
if (difftime(context->ra_time, now) <= 0.0)
@@ -492,51 +514,55 @@ time_t periodic_ra(time_t now)
if (tmp->name && (strcmp(tmp->name, interface) == 0))
break;
if (!tmp)
send_ra(param.iface, interface, NULL);
send_ra(now, param.iface, interface, NULL);
}
}
return next_event;
}
static int iface_search(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
int scope, int if_index, int flags,
int preferred, int valid, void *vparam)
{
struct search_param *param = vparam;
struct dhcp_context *context;
(void)scope;
(void)dad;
(void)preferred;
(void)valid;
for (context = daemon->ra_contexts; context; context = context->next)
if (prefix == context->prefix &&
for (context = daemon->dhcp6; context; context = context->next)
if (!(context->flags & CONTEXT_TEMPLATE) &&
prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
if (context->ra_time != 0 && difftime(context->ra_time, param->now) <= 0.0)
{
/* found an interface that's overdue for RA determine new
timeout value and arrange for RA to be sent unless interface is
still doing DAD.*/
if (!dad)
param->iface = if_index;
if (difftime(param->now, ra_short_period_start) < 60.0)
/* range 5 - 20 */
context->ra_time = param->now + 5 + (rand16()/4400);
else
/* range 450 - 600 */
context->ra_time = param->now + 450 + (rand16()/440);
/* zero timers for other contexts on the same subnet, so they don't timeout
independently */
for (context = context->next; context; context = context->next)
if (prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
context->ra_time = 0;
return 0; /* found, abort */
}
is_same_net6(local, &context->end6, prefix) &&
context->ra_time != 0 &&
difftime(context->ra_time, param->now) <= 0.0)
{
/* found an interface that's overdue for RA determine new
timeout value and arrange for RA to be sent unless interface is
still doing DAD.*/
if (!(flags & IFACE_TENTATIVE))
param->iface = if_index;
if (difftime(param->now, context->ra_short_period_start) < 60.0)
/* range 5 - 20 */
context->ra_time = param->now + 5 + (rand16()/4400);
else
/* range 450 - 600 */
context->ra_time = param->now + 450 + (rand16()/440);
/* zero timers for other contexts on the same subnet, so they don't timeout
independently */
for (context = context->next; context; context = context->next)
if (prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
context->ra_time = 0;
return 0; /* found, abort */
}
return 1; /* keep searching */
}

View File

@@ -20,7 +20,6 @@
#include <netinet/icmp6.h>
static int map_rebuild = 0;
static int ping_id = 0;
void slaac_add_addrs(struct dhcp_lease *lease, time_t now, int force)
@@ -38,7 +37,7 @@ void slaac_add_addrs(struct dhcp_lease *lease, time_t now, int force)
old = lease->slaac_address;
lease->slaac_address = NULL;
for (context = daemon->ra_contexts; context; context = context->next)
for (context = daemon->dhcp6; context; context = context->next)
if ((context->flags & CONTEXT_RA_NAME) && lease->last_interface == context->if_index)
{
struct in6_addr addr = context->start6;
@@ -123,7 +122,7 @@ time_t periodic_slaac(time_t now, struct dhcp_lease *leases)
struct slaac_address *slaac;
time_t next_event = 0;
for (context = daemon->ra_contexts; context; context = context->next)
for (context = daemon->dhcp6; context; context = context->next)
if ((context->flags & CONTEXT_RA_NAME))
break;
@@ -134,12 +133,6 @@ time_t periodic_slaac(time_t now, struct dhcp_lease *leases)
while (ping_id == 0)
ping_id = rand16();
if (map_rebuild)
{
map_rebuild = 0;
build_subnet_map();
}
for (lease = leases; lease; lease = lease->next)
for (slaac = lease->slaac_address; slaac; slaac = slaac->next)
{
@@ -211,51 +204,4 @@ void slaac_ping_reply(struct in6_addr *sender, unsigned char *packet, char *inte
lease_update_dns(gotone);
}
/* Build a map from ra-names subnets to corresponding interfaces. This
is used to go from DHCPv4 leases to SLAAC addresses,
interface->IPv6-subnet, IPv6-subnet + MAC address -> SLAAC.
*/
static int add_subnet(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
{
struct dhcp_context *context;
(void)scope;
(void)dad;
(void)vparam;
for (context = daemon->ra_contexts; context; context = context->next)
if ((context->flags & CONTEXT_RA_NAME) &&
prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
{
context->if_index = if_index;
context->local6 = *local;
}
return 1;
}
void build_subnet_map(void)
{
struct dhcp_context *context;
int ok = 0;
for (context = daemon->ra_contexts; context; context = context->next)
{
context->if_index = 0;
if ((context->flags & CONTEXT_RA_NAME))
ok = 1;
}
/* ra-names configured */
if (ok)
iface_enumerate(AF_INET6, NULL, add_subnet);
}
void schedule_subnet_map(void)
{
map_rebuild = 1;
}
#endif