Commit ff1b41dc authored by Simon Kelley's avatar Simon Kelley

Merge branch 'master' of ssh://thekelleys.org.uk/var/cache/git/dnsmasq

Conflicts:
	CHANGELOG
parents 3953dcc7 fc4c4fda
...@@ -63,6 +63,27 @@ version 2.67 ...@@ -63,6 +63,27 @@ version 2.67
Fix crash with empty DHCP string options when adding zero Fix crash with empty DHCP string options when adding zero
terminator. Thanks to Patrick McLean for the bug report. terminator. Thanks to Patrick McLean for the bug report.
Allow hostnames to start with a number, as allowed in
RFC-1123. Thanks to Kyle Mestery for the patch.
Fixes to DHCP FQDN option handling: don't terminate FQDN
if domain not known and allow a FQDN option with blank
name to request that a FQDN option is returned in the
reply. Thanks to Roy Marples for the patch.
Make --clear-on-reload apply to setting upstream servers
via DBus too.
When the address which triggered the construction of an
advertised IPv6 prefix disappears, continue to advertise
the prefix for up to 2 hours, with the preferred lifetime
set to zero. This satisfies RFC 6204 4.3 L-13 and makes
things work better if a prefix disappears without being
deprecated first. Thanks to Uwe Schindler for persuasively
arguing for this.
Fix MAC address enumeration on *BSD. Thanks to Brad Smith
for the bug report.
version 2.66 version 2.66
Add the ability to act as an authoritative DNS Add the ability to act as an authoritative DNS
......
...@@ -338,7 +338,8 @@ by '/', like the --server syntax, eg. ...@@ -338,7 +338,8 @@ by '/', like the --server syntax, eg.
Don't poll /etc/resolv.conf for changes. Don't poll /etc/resolv.conf for changes.
.TP .TP
.B --clear-on-reload .B --clear-on-reload
Whenever /etc/resolv.conf is re-read, clear the DNS cache. Whenever /etc/resolv.conf is re-read or the upstream servers are set
via DBus, clear the DNS cache.
This is useful when new nameservers may have different This is useful when new nameservers may have different
data than that held in cache. data than that held in cache.
.TP .TP
......
...@@ -111,7 +111,8 @@ int iface_enumerate(int family, void *parm, int (*callback)()) ...@@ -111,7 +111,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
{ {
int iface_index = if_nametoindex(addrs->ifa_name); int iface_index = if_nametoindex(addrs->ifa_name);
if (iface_index == 0 || !addrs->ifa_addr || !addrs->ifa_netmask) if (iface_index == 0 || !addrs->ifa_addr ||
(!addrs->ifa_netmask && family != AF_LINK))
continue; continue;
if (family == AF_INET) if (family == AF_INET)
......
...@@ -305,8 +305,6 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings) ...@@ -305,8 +305,6 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
const char *addr_err; const char *addr_err;
char *dup = NULL; char *dup = NULL;
my_syslog(LOG_INFO, _("setting upstream servers from DBus"));
if (!dbus_message_iter_init(message, &iter)) if (!dbus_message_iter_init(message, &iter))
{ {
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
...@@ -478,6 +476,7 @@ DBusHandlerResult message_handler(DBusConnection *connection, ...@@ -478,6 +476,7 @@ DBusHandlerResult message_handler(DBusConnection *connection,
{ {
char *method = (char *)dbus_message_get_member(message); char *method = (char *)dbus_message_get_member(message);
DBusMessage *reply = NULL; DBusMessage *reply = NULL;
int clear_cache = 0, new_servers = 0;
if (dbus_message_is_method_call(message, DBUS_INTERFACE_INTROSPECTABLE, "Introspect")) if (dbus_message_is_method_call(message, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
{ {
...@@ -501,24 +500,34 @@ DBusHandlerResult message_handler(DBusConnection *connection, ...@@ -501,24 +500,34 @@ DBusHandlerResult message_handler(DBusConnection *connection,
} }
else if (strcmp(method, "SetServers") == 0) else if (strcmp(method, "SetServers") == 0)
{ {
my_syslog(LOG_INFO, _("setting upstream servers from DBus"));
dbus_read_servers(message); dbus_read_servers(message);
check_servers(); new_servers = 1;
} }
else if (strcmp(method, "SetServersEx") == 0) else if (strcmp(method, "SetServersEx") == 0)
{ {
reply = dbus_read_servers_ex(message, 0); reply = dbus_read_servers_ex(message, 0);
check_servers(); new_servers = 1;
} }
else if (strcmp(method, "SetDomainServers") == 0) else if (strcmp(method, "SetDomainServers") == 0)
{ {
reply = dbus_read_servers_ex(message, 1); reply = dbus_read_servers_ex(message, 1);
check_servers(); new_servers = 1;
} }
else if (strcmp(method, "ClearCache") == 0) else if (strcmp(method, "ClearCache") == 0)
clear_cache_and_reload(dnsmasq_time()); clear_cache = 1;
else else
return (DBUS_HANDLER_RESULT_NOT_YET_HANDLED); return (DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
if (new_servers)
{
my_syslog(LOG_INFO, _("setting upstream servers from DBus"));
check_servers();
if (option_bool(OPT_RELOAD))
clear_cache = 1;
}
if (clear_cache)
clear_cache_and_reload(dnsmasq_time());
method = user_data; /* no warning */ method = user_data; /* no warning */
......
...@@ -720,7 +720,7 @@ void log_context(int family, struct dhcp_context *context) ...@@ -720,7 +720,7 @@ void log_context(int family, struct dhcp_context *context)
p += sprintf(p, ", "); p += sprintf(p, ", ");
if (indextoname(daemon->doing_dhcp6 ? daemon->dhcp6fd : daemon->icmp6fd, context->if_index, ifrn_name)) if (indextoname(daemon->doing_dhcp6 ? daemon->dhcp6fd : daemon->icmp6fd, context->if_index, ifrn_name))
sprintf(p, "constructed for %s", ifrn_name); sprintf(p, "%s for %s", (context->flags & CONTEXT_OLD) ? "old prefix" : "constructed", ifrn_name);
} }
else if (context->flags & CONTEXT_TEMPLATE) else if (context->flags & CONTEXT_TEMPLATE)
{ {
...@@ -731,7 +731,8 @@ void log_context(int family, struct dhcp_context *context) ...@@ -731,7 +731,8 @@ void log_context(int family, struct dhcp_context *context)
} }
#endif #endif
if ((context->flags & CONTEXT_DHCP) || family == AF_INET) if (!(context->flags & CONTEXT_OLD) &&
((context->flags & CONTEXT_DHCP) || family == AF_INET))
{ {
inet_ntop(family, start, daemon->dhcp_buff, 256); inet_ntop(family, start, daemon->dhcp_buff, 256);
inet_ntop(family, end, daemon->dhcp_buff3, 256); inet_ntop(family, end, daemon->dhcp_buff3, 256);
...@@ -748,9 +749,9 @@ void log_context(int family, struct dhcp_context *context) ...@@ -748,9 +749,9 @@ void log_context(int family, struct dhcp_context *context)
} }
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
if (context->flags & CONTEXT_RA_NAME) if ((context->flags & CONTEXT_RA_NAME) && !(context->flags & CONTEXT_OLD))
my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s%s"), daemon->addrbuff, template); my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s%s"), daemon->addrbuff, template);
if ((context->flags & CONTEXT_RA) || (option_bool(OPT_RA) && (context->flags & CONTEXT_DHCP) && family == AF_INET6)) if ((context->flags & CONTEXT_RA) || (option_bool(OPT_RA) && (context->flags & CONTEXT_DHCP) && family == AF_INET6))
my_syslog(MS_DHCP | LOG_INFO, _("router advertisement on %s%s"), daemon->addrbuff, template); my_syslog(MS_DHCP | LOG_INFO, _("router advertisement on %s%s"), daemon->addrbuff, template);
#endif #endif
......
...@@ -220,7 +220,7 @@ static int complete_context6(struct in6_addr *local, int prefix, ...@@ -220,7 +220,7 @@ static int complete_context6(struct in6_addr *local, int prefix,
for (context = daemon->dhcp6; context; context = context->next) for (context = daemon->dhcp6; context; context = context->next)
{ {
if ((context->flags & CONTEXT_DHCP) && if ((context->flags & CONTEXT_DHCP) &&
!(context->flags & CONTEXT_TEMPLATE) && !(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
prefix == context->prefix && prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) && is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix)) is_same_net6(local, &context->end6, prefix))
...@@ -552,7 +552,10 @@ static int construct_worker(struct in6_addr *local, int prefix, ...@@ -552,7 +552,10 @@ static int construct_worker(struct in6_addr *local, int prefix,
IN6_ARE_ADDR_EQUAL(&start6, &context->start6) && IN6_ARE_ADDR_EQUAL(&start6, &context->start6) &&
IN6_ARE_ADDR_EQUAL(&end6, &context->end6)) IN6_ARE_ADDR_EQUAL(&end6, &context->end6))
{ {
context->flags &= ~CONTEXT_GC; int flags = context->flags;
context->flags &= ~(CONTEXT_GC | CONTEXT_OLD);
if (flags & CONTEXT_OLD)
log_context(AF_INET6, context);
break; break;
} }
...@@ -565,6 +568,7 @@ static int construct_worker(struct in6_addr *local, int prefix, ...@@ -565,6 +568,7 @@ static int construct_worker(struct in6_addr *local, int prefix,
context->flags |= CONTEXT_CONSTRUCTED; context->flags |= CONTEXT_CONSTRUCTED;
context->if_index = if_index; context->if_index = if_index;
context->local6 = *local; context->local6 = *local;
context->saved_valid = 0;
context->next = daemon->dhcp6; context->next = daemon->dhcp6;
daemon->dhcp6 = context; daemon->dhcp6 = context;
...@@ -587,35 +591,53 @@ static int construct_worker(struct in6_addr *local, int prefix, ...@@ -587,35 +591,53 @@ static int construct_worker(struct in6_addr *local, int prefix,
void dhcp_construct_contexts(time_t now) void dhcp_construct_contexts(time_t now)
{ {
struct dhcp_context *tmp, *context, **up; struct dhcp_context *context, *tmp, **up;
struct cparam param; struct cparam param;
param.newone = 0; param.newone = 0;
param.newname = 0; param.newname = 0;
param.now = now; param.now = now;
for (context = daemon->dhcp6; context; context = context->next) for (context = daemon->dhcp6; context; context = context->next)
{ if (context->flags & CONTEXT_CONSTRUCTED)
context->if_index = 0; context->flags |= CONTEXT_GC;
if (context->flags & CONTEXT_CONSTRUCTED)
context->flags |= CONTEXT_GC;
}
iface_enumerate(AF_INET6, &param, construct_worker); iface_enumerate(AF_INET6, &param, construct_worker);
for (up = &daemon->dhcp6, context = daemon->dhcp6; context; context = tmp) for (up = &daemon->dhcp6, context = daemon->dhcp6; context; context = tmp)
{ {
tmp = context->next;
if (context->flags & CONTEXT_GC) tmp = context->next;
if (context->flags & CONTEXT_GC && !(context->flags & CONTEXT_OLD))
{ {
*up = context->next;
param.newone = 1; /* include deletion */ if ((context->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)) ||
if (context->flags & CONTEXT_RA_NAME) option_bool(OPT_RA))
param.newname = 1; {
free(context); /* previously constructed context has gone. advertise it's demise */
context->flags |= CONTEXT_OLD;
context->address_lost_time = now;
if (context->saved_valid > 7200) /* 2 hours */
context->saved_valid = 7200;
ra_start_unsolicted(now, context);
param.newone = 1; /* include deletion */
if (context->flags & CONTEXT_RA_NAME)
param.newname = 1;
log_context(AF_INET6, context);
up = &context->next;
}
else
{
/* we were never doing RA for this, so free now */
*up = context->next;
free(context);
}
} }
else else
up = &context->next; up = &context->next;
} }
if (param.newone) if (param.newone)
......
...@@ -706,8 +706,8 @@ struct dhcp_context { ...@@ -706,8 +706,8 @@ struct dhcp_context {
struct in6_addr start6, end6; /* range of available addresses */ struct in6_addr start6, end6; /* range of available addresses */
struct in6_addr local6; struct in6_addr local6;
int prefix, if_index; int prefix, if_index;
unsigned int valid, preferred; unsigned int valid, preferred, saved_valid;
time_t ra_time, ra_short_period_start; time_t ra_time, ra_short_period_start, address_lost_time;
char *template_interface; char *template_interface;
#endif #endif
int flags; int flags;
...@@ -732,6 +732,8 @@ struct dhcp_context { ...@@ -732,6 +732,8 @@ struct dhcp_context {
#define CONTEXT_CONF_USED 16384 #define CONTEXT_CONF_USED 16384
#define CONTEXT_USED 32768 #define CONTEXT_USED 32768
#define CONTEXT_NOAUTH 65536 #define CONTEXT_NOAUTH 65536
#define CONTEXT_OLD 131072
struct ping_result { struct ping_result {
struct in_addr addr; struct in_addr addr;
......
...@@ -47,6 +47,7 @@ static int iface_search(struct in6_addr *local, int prefix, ...@@ -47,6 +47,7 @@ static int iface_search(struct in6_addr *local, int prefix,
int scope, int if_index, int flags, int scope, int if_index, int flags,
int prefered, int valid, void *vparam); int prefered, int valid, void *vparam);
static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm); static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm);
static void new_timeout(struct dhcp_context *context, time_t now);
static int hop_limit; static int hop_limit;
...@@ -187,9 +188,8 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de ...@@ -187,9 +188,8 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
{ {
struct ra_packet *ra; struct ra_packet *ra;
struct ra_param parm; struct ra_param parm;
struct ifreq ifr;
struct sockaddr_in6 addr; struct sockaddr_in6 addr;
struct dhcp_context *context; struct dhcp_context *context, *tmp, **up;
struct dhcp_netid iface_id; struct dhcp_netid iface_id;
struct dhcp_opt *opt_cfg; struct dhcp_opt *opt_cfg;
int done_dns = 0; int done_dns = 0;
...@@ -228,12 +228,66 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de ...@@ -228,12 +228,66 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
context->netid.next = &context->netid; context->netid.next = &context->netid;
} }
if (!iface_enumerate(AF_INET6, &parm, add_prefixes) || if (!iface_enumerate(AF_INET6, &parm, add_prefixes))
!parm.found_context)
return; return;
strncpy(ifr.ifr_name, iface_name, IF_NAMESIZE); /* Look for constructed contexts associated with addresses which have gone,
and advertise them with preferred_time == 0 RFC 6204 4.3 L-13 */
for (up = &daemon->dhcp6, context = daemon->dhcp6; context; context = tmp)
{
tmp = context->next;
if (context->if_index == iface && (context->flags & CONTEXT_OLD))
{
unsigned int old = difftime(now, context->address_lost_time);
if (old > context->saved_valid)
{
/* We've advertised this enough, time to go */
*up = context->next;
free(context);
}
else
{
struct prefix_opt *opt;
struct in6_addr local = context->start6;
int do_slaac = 0;
parm.found_context = 1;
/* zero net part of address */
setaddr6part(&local, addr6part(&local) & ~((context->prefix == 64) ? (u64)-1LL : (1LLU << (128 - context->prefix)) - 1LLU));
if ((context->flags &
(CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
do_slaac = 1;
if ((opt = expand(sizeof(struct prefix_opt))))
{
opt->type = ICMP6_OPT_PREFIX;
opt->len = 4;
opt->prefix_len = context->prefix;
/* autonomous only if we're not doing dhcp, always set "on-link" */
opt->flags = do_slaac ? 0xC0 : 0x80;
opt->valid_lifetime = htonl(context->saved_valid - old);
opt->preferred_lifetime = htonl(0);
opt->reserved = 0;
opt->prefix = local;
inet_ntop(AF_INET6, &local, daemon->addrbuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s old prefix", iface_name, daemon->addrbuff);
}
up = &context->next;
}
}
else
up = &context->next;
}
if (!parm.found_context)
return;
#ifdef HAVE_LINUX_NETWORK #ifdef HAVE_LINUX_NETWORK
/* Note that IPv6 MTU is not necessarilly the same as the IPv4 MTU /* Note that IPv6 MTU is not necessarilly the same as the IPv4 MTU
available from SIOCGIFMTU */ available from SIOCGIFMTU */
...@@ -291,7 +345,7 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de ...@@ -291,7 +345,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(1800); /* lifetime - twice RA retransmit */ put_opt6_long(RA_INTERVAL * 2); /* lifetime - twice RA retransmit */
put_opt6(opt_cfg->val, opt_cfg->len); put_opt6(opt_cfg->val, opt_cfg->len);
/* pad */ /* pad */
...@@ -361,11 +415,13 @@ static int add_prefixes(struct in6_addr *local, int prefix, ...@@ -361,11 +415,13 @@ static int add_prefixes(struct in6_addr *local, int prefix,
struct dhcp_context *context; struct dhcp_context *context;
for (context = daemon->dhcp6; context; context = context->next) for (context = daemon->dhcp6; context; context = context->next)
if (!(context->flags & CONTEXT_TEMPLATE) && if (!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
prefix == context->prefix && prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) && is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix)) is_same_net6(local, &context->end6, prefix))
{ {
context->saved_valid = valid;
if ((context->flags & if ((context->flags &
(CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS))) (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
{ {
...@@ -386,12 +442,12 @@ static int add_prefixes(struct in6_addr *local, int prefix, ...@@ -386,12 +442,12 @@ static int add_prefixes(struct in6_addr *local, int prefix,
param->other = 1; param->other = 1;
} }
/* find floor time, don't reduce below RA interval. */ /* find floor time, don't reduce below 3 * RA interval. */
if (time > context->lease_time) if (time > context->lease_time)
{ {
time = context->lease_time; time = context->lease_time;
if (time < ((unsigned int)RA_INTERVAL)) if (time < ((unsigned int)(3 * RA_INTERVAL)))
time = RA_INTERVAL; time = 3 * RA_INTERVAL;
} }
if (context->flags & CONTEXT_DEPRECATE) if (context->flags & CONTEXT_DEPRECATE)
...@@ -466,6 +522,7 @@ static int add_prefixes(struct in6_addr *local, int prefix, ...@@ -466,6 +522,7 @@ static int add_prefixes(struct in6_addr *local, int prefix,
inet_ntop(AF_INET6, local, daemon->addrbuff, ADDRSTRLEN); inet_ntop(AF_INET6, local, daemon->addrbuff, ADDRSTRLEN);
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);
} }
} }
} }
} }
...@@ -520,16 +577,25 @@ time_t periodic_ra(time_t now) ...@@ -520,16 +577,25 @@ time_t periodic_ra(time_t now)
if (!context) if (!context)
break; break;
/* There's a context overdue, but we can't find an interface if ((context->flags & CONTEXT_OLD) && context->if_index != 0)
associated with it, because it's for a subnet we dont {
have an interface on. Probably we're doing DHCP on /* A context for an old address. We'll not find the interface by
a remote subnet via a relay. Zero the timer, since we won't looking for addresses, but we know it anyway, as long as we
ever be able to send ra's and satistfy it. */ sent at least one RA whilst the address was current. */
if (iface_enumerate(AF_INET6, &param, iface_search)) param.iface = context->if_index;
new_timeout(context, now);
}
else if (iface_enumerate(AF_INET6, &param, iface_search))
/* There's a context overdue, but we can't find an interface
associated with it, because it's for a subnet we dont
have an interface on. Probably we're doing DHCP on
a remote subnet via a relay. Zero the timer, since we won't
ever be able to send ra's and satistfy it. */
context->ra_time = 0; context->ra_time = 0;
else if (param.iface != 0 &&
indextoname(daemon->icmp6fd, param.iface, interface) && if (param.iface != 0 &&
iface_check(AF_LOCAL, NULL, interface, NULL)) indextoname(daemon->icmp6fd, param.iface, interface) &&
iface_check(AF_LOCAL, NULL, interface, NULL))
{ {
struct iname *tmp; struct iname *tmp;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next) for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
...@@ -554,7 +620,7 @@ static int iface_search(struct in6_addr *local, int prefix, ...@@ -554,7 +620,7 @@ static int iface_search(struct in6_addr *local, int prefix,
(void)valid; (void)valid;
for (context = daemon->dhcp6; context; context = context->next) for (context = daemon->dhcp6; context; context = context->next)
if (!(context->flags & CONTEXT_TEMPLATE) && if (!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
prefix == context->prefix && prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) && is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix) && is_same_net6(local, &context->end6, prefix) &&
...@@ -568,12 +634,7 @@ static int iface_search(struct in6_addr *local, int prefix, ...@@ -568,12 +634,7 @@ static int iface_search(struct in6_addr *local, int prefix,
if (!(flags & IFACE_TENTATIVE)) if (!(flags & IFACE_TENTATIVE))
param->iface = if_index; param->iface = if_index;
if (difftime(param->now, context->ra_short_period_start) < 60.0) new_timeout(context, param->now);
/* range 5 - 20 */
context->ra_time = param->now + 5 + (rand16()/4400);
else
/* range 3/4 - 1 times RA_INTERVAL */
context->ra_time = param->now + (3 * RA_INTERVAL)/4 + ((RA_INTERVAL * (unsigned int)rand16()) >> 18);
/* zero timers for other contexts on the same subnet, so they don't timeout /* zero timers for other contexts on the same subnet, so they don't timeout
independently */ independently */
...@@ -588,6 +649,15 @@ static int iface_search(struct in6_addr *local, int prefix, ...@@ -588,6 +649,15 @@ static int iface_search(struct in6_addr *local, int prefix,
return 1; /* keep searching */ return 1; /* keep searching */
} }
static void new_timeout(struct dhcp_context *context, time_t now)
{
if (difftime(now, context->ra_short_period_start) < 60.0)
/* range 5 - 20 */
context->ra_time = now + 5 + (rand16()/4400);
else
/* range 3/4 - 1 times RA_INTERVAL */
context->ra_time = now + (3 * RA_INTERVAL)/4 + ((RA_INTERVAL * (unsigned int)rand16()) >> 18);
}
#endif #endif
...@@ -615,7 +615,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index, ...@@ -615,7 +615,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
return message ? 0 : dhcp_packet_size(mess, agent_id, real_end); return message ? 0 : dhcp_packet_size(mess, agent_id, real_end);
} }
if ((opt = option_find(mess, sz, OPTION_CLIENT_FQDN, 4))) if ((opt = option_find(mess, sz, OPTION_CLIENT_FQDN, 3)))
{ {
/* http://tools.ietf.org/wg/dhc/draft-ietf-dhc-fqdn-option/draft-ietf-dhc-fqdn-option-10.txt */ /* http://tools.ietf.org/wg/dhc/draft-ietf-dhc-fqdn-option/draft-ietf-dhc-fqdn-option-10.txt */
int len = option_len(opt); int len = option_len(opt);
...@@ -645,7 +645,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index, ...@@ -645,7 +645,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
} }
if (fqdn_flags & 0x04) if (fqdn_flags & 0x04)
while (*op != 0 && ((op + (*op) + 1) - pp) < len) while (*op != 0 && ((op + (*op)) - pp) < len)
{ {
memcpy(pq, op+1, *op); memcpy(pq, op+1, *op);
pq += *op; pq += *op;
...@@ -2290,7 +2290,9 @@ static void do_options(struct dhcp_context *context, ...@@ -2290,7 +2290,9 @@ static void do_options(struct dhcp_context *context,
if (domain) if (domain)
len += strlen(domain) + 1; len += strlen(domain) + 1;
else if (fqdn_flags & 0x04)
len--;
if ((p = free_space(mess, end, OPTION_CLIENT_FQDN, len))) if ((p = free_space(mess, end, OPTION_CLIENT_FQDN, len)))
{ {
*(p++) = fqdn_flags & 0x0f; /* MBZ bits to zero */ *(p++) = fqdn_flags & 0x0f; /* MBZ bits to zero */
...@@ -2301,8 +2303,10 @@ static void do_options(struct dhcp_context *context, ...@@ -2301,8 +2303,10 @@ static void do_options(struct dhcp_context *context,
{ {
p = do_rfc1035_name(p, hostname); p = do_rfc1035_name(p, hostname);
if (domain) if (domain)
p = do_rfc1035_name(p, domain); {
*p++ = 0; p = do_rfc1035_name(p, domain);
*p++ = 0;
}
} }
else else
{ {
......
...@@ -120,7 +120,7 @@ static int dhcp6_maybe_relay(struct in6_addr *link_address, struct dhcp_netid ** ...@@ -120,7 +120,7 @@ static int dhcp6_maybe_relay(struct in6_addr *link_address, struct dhcp_netid **
!IN6_IS_ADDR_MULTICAST(link_address)) !IN6_IS_ADDR_MULTICAST(link_address))
for (c = daemon->dhcp6; c; c = c->next) for (c = daemon->dhcp6; c; c = c->next)
if ((c->flags & CONTEXT_DHCP) && if ((c->flags & CONTEXT_DHCP) &&
!(c->flags & CONTEXT_TEMPLATE) && !(c->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
is_same_net6(link_address, &c->start6, c->prefix) && is_same_net6(link_address, &c->start6, c->prefix) &&
is_same_net6(link_address, &c->end6, c->prefix)) is_same_net6(link_address, &c->end6, c->prefix))
{ {
...@@ -1299,16 +1299,18 @@ struct dhcp_netid *add_options(struct state *state, struct in6_addr *fallback, s ...@@ -1299,16 +1299,18 @@ struct dhcp_netid *add_options(struct state *state, struct in6_addr *fallback, s
size_t len = strlen(state->hostname); size_t len = strlen(state->hostname);
if (state->send_domain) if (state->send_domain)
len += strlen(state->send_domain) + 1; len += strlen(state->send_domain) + 2;
o = new_opt6(OPTION6_FQDN); o = new_opt6(OPTION6_FQDN);
if ((p = expand(len + 3))) if ((p = expand(len + 2)))
{ {
*(p++) = state->fqdn_flags; *(p++) = state->fqdn_flags;
p = do_rfc1035_name(p, state->hostname); p = do_rfc1035_name(p, state->hostname);
if (state->send_domain) if (state->send_domain)
p = do_rfc1035_name(p, state->send_domain); {
*p = 0; p = do_rfc1035_name(p, state->send_domain);
*p = 0;
}
} }
end_opt6(o); end_opt6(o);
} }
......
...@@ -38,7 +38,9 @@ void slaac_add_addrs(struct dhcp_lease *lease, time_t now, int force) ...@@ -38,7 +38,9 @@ void slaac_add_addrs(struct dhcp_lease *lease, time_t now, int force)
lease->slaac_address = NULL; lease->slaac_address = NULL;
for (context = daemon->dhcp6; context; context = context->next) for (context = daemon->dhcp6; context; context = context->next)
if ((context->flags & CONTEXT_RA_NAME) && lease->last_interface == context->if_index) if ((context->flags & CONTEXT_RA_NAME) &&
!(context->flags & CONTEXT_OLD) &&
lease->last_interface == context->if_index)
{ {
struct in6_addr addr = context->start6; struct in6_addr addr = context->start6;
if (lease->hwaddr_len == 6 && if (lease->hwaddr_len == 6 &&
...@@ -123,7 +125,7 @@ time_t periodic_slaac(time_t now, struct dhcp_lease *leases) ...@@ -123,7 +125,7 @@ time_t periodic_slaac(time_t now, struct dhcp_lease *leases)
time_t next_event = 0; time_t next_event = 0;
for (context = daemon->dhcp6; context; context = context->next) for (context = daemon->dhcp6; context; context = context->next)
if ((context->flags & CONTEXT_RA_NAME)) if ((context->flags & CONTEXT_RA_NAME) && !(context->flags & CONTEXT_OLD))
break; break;
/* nothing configured */ /* nothing configured */
......
...@@ -151,14 +151,13 @@ int legal_hostname(char *name) ...@@ -151,14 +151,13 @@ int legal_hostname(char *name)
/* check for legal char a-z A-Z 0-9 - _ . */ /* check for legal char a-z A-Z 0-9 - _ . */
{ {
if ((c >= 'A' && c <= 'Z') || if ((c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z')) (c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9'))
continue; continue;
if (!first && if (!first && (c == '-' || c == '_'))
((c >= '0' && c <= '9') ||
c == '-' || c == '_'))
continue; continue;
/* end of hostname part */ /* end of hostname part */
if (c == '.') if (c == '.')
return 1; return 1;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment