Compare commits

...

16 Commits

Author SHA1 Message Date
Simon Kelley
3b43646a08 Use /proc/sys/net/ipv6/conf/<iface>/mtu for RA advertised MTU. 2012-12-28 11:55:45 +00:00
Simon Kelley
3bc0d932d0 More work on lease and router lifetime calculation. 2012-12-28 11:31:44 +00:00
Simon Kelley
60225f4e75 Allow constructed prefixes in auth zones. 2012-12-28 11:29:01 +00:00
Simon Kelley
1962446269 Join multicast groups only on IPv6 addresses! 2012-12-28 11:18:09 +00:00
Simon Kelley
be37986a0f Better error checking in DHCPv6 dhcp-range option parsing. 2012-12-23 12:01:39 +00:00
Simon Kelley
d7346a1e8c Tweak context-construct logic. 2012-12-22 22:45:54 +00:00
Simon Kelley
87d346f6a7 saner function name 2012-12-22 22:35:11 +00:00
Simon Kelley
f0dd7f807d Fix new-address logic and ordering for first address on new interface. 2012-12-22 22:31:58 +00:00
Simon Kelley
0c0502426f Check for new SLAAC addresses when we add new prefixes. 2012-12-22 22:13:19 +00:00
Simon Kelley
7f035f58c6 Don't cap prefx lifetimes below RA retransmit interval. 2012-12-22 21:27:08 +00:00
Simon Kelley
81e84f8dac preferred and valid times in bpf.c 2012-12-21 20:54:00 +00:00
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
11 changed files with 276 additions and 213 deletions

View File

@@ -46,6 +46,21 @@ static struct subnet *filter_zone(struct auth_zone *zone, int flag, struct all_a
return NULL;
}
static int filter_constructed_dhcp(int flag, struct all_addr *addr_u)
{
#ifdef HAVE_DHCP6
struct dhcp_context *context;
if (flag | F_IPV6)
for (context = daemon->dhcp6; context; context = context->next)
if ((context->flags & CONTEXT_CONSTRUCTED) &&
is_same_net6(&(addr_u->addr.addr6), &context->start6, context->prefix))
return 1;
#endif
return 0;
}
static int in_zone(struct auth_zone *zone, char *name, char **cut)
{
size_t namelen = strlen(name);
@@ -415,7 +430,8 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
do
{
nxdomain = 0;
if ((crecp->flags & flag) && filter_zone(zone, flag, &(crecp->addr.addr)))
if ((crecp->flags & flag) &&
(filter_zone(zone, flag, &(crecp->addr.addr)) || filter_constructed_dhcp(flag, &(crecp->addr.addr))))
{
*cut = '.'; /* restore domain part */
log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid));

View File

@@ -147,7 +147,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
addr->s6_addr[3] = 0;
}
if (!((*callback)(addr, prefix, scope_id, iface_index, 0, 0, 0, parm)))
/* preferred and valid times == forever until we known how to dtermine them. */
if (!((*callback)(addr, prefix, scope_id, iface_index, 0, -1, -1, parm)))
goto err;
}
#endif

View File

@@ -25,8 +25,8 @@ struct iface_param {
};
static int complete_context6(struct in6_addr *local, int prefix,
int scope, int if_index, int dad,
int preferred, int valid, void *vparam);
int scope, int if_index, int flags,
unsigned int preferred, unsigned int valid, void *vparam);
static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm);
@@ -182,18 +182,15 @@ void dhcp6_packet(time_t now)
}
static int complete_context6(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, int preferred,
int valid, void *vparam)
int scope, int if_index, int flags, unsigned int preferred,
unsigned int valid, void *vparam)
{
struct dhcp_context *context;
struct iface_param *param = vparam;
struct iname *tmp;
(void)scope; /* warning */
(void)dad;
(void)preferred;
(void)valid;
if (if_index == param->ind &&
!IN6_IS_ADDR_LOOPBACK(local) &&
!IN6_IS_ADDR_LINKLOCAL(local) &&
@@ -219,12 +216,32 @@ static int complete_context6(struct in6_addr *local, int prefix,
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
{
/* link it onto the current chain if we've not seen it before */
if (context->current == context)
{
context->current = param->current;
param->current = context;
struct dhcp_context *tmp, **up;
/* use interface values only for contructed contexts */
if (!(context->flags & CONTEXT_CONSTRUCTED))
preferred = valid = 0xffffffff;
else if (flags & IFACE_DEPRECATED)
preferred = 0;
if (context->flags & CONTEXT_DEPRECATE)
preferred = 0;
/* order chain, longest preferred time first */
for (up = &param->current, tmp = param->current; tmp; tmp = tmp->current)
if (tmp->preferred <= preferred)
break;
context->current = *up;
*up = context;
context->local6 = *local;
context->preferred = preferred;
context->valid = valid;
}
}
}
@@ -475,11 +492,11 @@ static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, vo
struct cparam {
time_t now;
int newone;
int newone, newname;
};
static int construct_worker(struct in6_addr *local, int prefix,
int scope, int if_index, int dad,
int scope, int if_index, int flags,
int preferred, int valid, void *vparam)
{
char ifrn_name[IFNAMSIZ];
@@ -487,7 +504,9 @@ static int construct_worker(struct in6_addr *local, int prefix,
struct dhcp_context *template, *context;
(void)scope;
(void)dad;
(void)flags;
(void)valid;
(void)preferred;
struct cparam *param = vparam;
@@ -546,22 +565,13 @@ static int construct_worker(struct in6_addr *local, int prefix,
/* we created a new one, need to call
lease_update_file to get periodic functions called */
param->newone = 1;
/* Will need to add new putative SLAAC addresses to existing leases */
if (context->flags & CONTEXT_RA_NAME)
param->newname = 1;
log_context(AF_INET6, context);
}
if (context)
{
if (valid == -1)
context->valid = valid;
else
context->valid = valid + param->now;
if (preferred == -1)
context->preferred = preferred;
else
context->preferred = preferred + param->now;
}
}
return 1;
@@ -572,14 +582,15 @@ void dhcp_construct_contexts(time_t now)
struct dhcp_context *tmp, *context, **up;
struct cparam param;
param.newone = 0;
param.newname = 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;
}
{
context->if_index = 0;
if (context->flags & CONTEXT_CONSTRUCTED)
context->flags |= CONTEXT_GC;
}
iface_enumerate(AF_INET6, &param, construct_worker);
@@ -589,10 +600,11 @@ void dhcp_construct_contexts(time_t now)
if (context->flags & CONTEXT_GC)
{
if (daemon->dhcp6 == context)
daemon->dhcp6 = context->next;
*up = context->next;
free(context);
param.newone = 1; /* include deletion */
if (context->flags & CONTEXT_RA_NAME)
param.newname = 1;
}
else
up = &context->next;
@@ -601,90 +613,16 @@ void dhcp_construct_contexts(time_t now)
if (param.newone)
{
if (daemon->dhcp || daemon->doing_dhcp6)
lease_update_file(now);
{
if (param.newname)
lease_update_slaac(now);
lease_update_file(now);
}
else
/* Not doing DHCP, so no lease system, manage alarms for ra only */
send_alarm(periodic_ra(now), now);
}
}
static int join_multicast_worker(struct in6_addr *local, int prefix,
int scope, int if_index, int dad,
int preferred, int valid, 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;
(void)preferred;
(void)valid;
/* 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->doing_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->doing_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->doing_ra &&
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

View File

@@ -183,7 +183,7 @@ int main (int argc, char **argv)
daemon->doing_ra = 1;
#ifndef HAVE_LINUX_NETWORK
if (context->flags & CONTEXT_TEMPLATE)
die (_("dhcp-range contructor not available on this platform"), NULL, EC_BADCONF);
die (_("dhcp-range constructor not available on this platform"), NULL, EC_BADCONF);
#endif
}
}
@@ -220,12 +220,6 @@ int main (int argc, char **argv)
die(_("cannot set --bind-interfaces and --bind-dynamic"), NULL, EC_BADCONF);
#endif
#ifdef HAVE_DHCP6
/* after netlink_init */
if (daemon->doing_dhcp6 || daemon->doing_ra)
join_multicast();
#endif
if (!enumerate_interfaces())
die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
@@ -255,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();

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;
};
@@ -678,9 +683,9 @@ struct dhcp_context {
struct in6_addr start6, end6; /* range of available addresses */
struct in6_addr local6;
int prefix, if_index;
unsigned int valid, preferred;
time_t ra_time, ra_short_period_start;
char *template_interface;
int valid, preferred; /* times from address for constructed contexts */
#endif
int flags;
struct dhcp_netid netid, *filter;
@@ -1001,6 +1006,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
@@ -1040,6 +1048,7 @@ void lease6_filter(int lease_type, int iaid, struct dhcp_context *context);
struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr);
u64 lease_find_max_addr6(struct dhcp_context *context);
void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface);
void lease_update_slaac(time_t now);
#endif
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
unsigned char *clid, int hw_len, int hw_type, int clid_len, time_t now, int force);
@@ -1151,7 +1160,6 @@ struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct
int prefix, u64 addr);
void make_duid(time_t now);
void dhcp_construct_contexts(time_t now);
void join_multicast(void);
#endif
/* rfc3315.c */

View File

@@ -363,13 +363,13 @@ 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,
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;
@@ -389,6 +389,18 @@ void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *inte
slaac_ping_reply(sender, packet, interface, leases);
}
void lease_update_slaac(time_t now)
{
/* Called when we contruct a new RA-names context, to add putative
new SLAAC addresses to existing leases. */
struct dhcp_lease *lease;
if (daemon->dhcp)
for (lease = leases; lease; lease = lease->next)
slaac_add_addrs(lease, now, 0);
}
#endif

View File

@@ -39,6 +39,7 @@ static struct iovec iov;
static u32 netlink_pid;
static int nl_async(struct nlmsghdr *h);
static void nl_newaddress(time_t now);
void netlink_init(void)
{
@@ -199,23 +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)
{
time_t now = dnsmasq_time();
nl_newaddress(dnsmasq_time());
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);
if (daemon->doing_dhcp6)
lease_find_interfaces(now);
#endif
}
return callback_ok;
}
else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC && family != AF_LOCAL)
@@ -253,6 +239,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
{
struct in6_addr *addrp = NULL;
u32 valid = 0, preferred = 0;
int flags = 0;
while (RTA_OK(rta, len1))
{
if (rta->rta_type == IFA_ADDRESS)
@@ -266,9 +254,15 @@ int iface_enumerate(int family, void *parm, int (*callback)())
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),
(int)(ifa->ifa_index), flags,
(int) preferred, (int)valid, parm)))
callback_ok = 0;
}
@@ -346,23 +340,9 @@ void netlink_multicast(time_t now)
/* restore non-blocking status */
fcntl(daemon->netlinkfd, F_SETFL, flags);
if (newaddr)
{
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);
if (daemon->doing_dhcp6)
lease_find_interfaces(now);
#endif
}
nl_newaddress(now);
}
static int nl_async(struct nlmsghdr *h)
@@ -410,7 +390,28 @@ static int nl_async(struct nlmsghdr *h)
return 0;
}
static void nl_newaddress(time_t now)
{
if (option_bool(OPT_CLEVERBIND) || daemon->doing_dhcp6 || daemon->doing_ra)
enumerate_interfaces();
if (option_bool(OPT_CLEVERBIND))
create_bound_listeners(0);
#ifdef HAVE_DHCP6
if (daemon->doing_dhcp6 || daemon->doing_ra)
{
join_multicast(0);
dhcp_construct_contexts(now);
}
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,7 @@ 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,
int scope, int if_index, int flags,
int preferred, int valid, void *vparam)
{
union mysockaddr addr;
@@ -310,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
@@ -587,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->addr.sa.sa_family == AF_INET6 && 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

@@ -2371,6 +2371,13 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
a[leasepos][strlen(a[leasepos]) - 1] = 0;
}
for (cp = a[leasepos]; *cp; cp++)
if (!(*cp >= '0' && *cp <= '9'))
break;
if (!cp || (leasepos+1 < k))
ret_err(_("bad dhcp-range"));
new->lease_time = atoi(a[leasepos]) * fac;
/* Leases of a minute or less confuse
some clients, notably Apple's */

View File

@@ -31,7 +31,8 @@ struct ra_param {
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 {
@@ -40,10 +41,10 @@ struct search_param {
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,
int preferred, int valid, 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,
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);
@@ -192,7 +193,10 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
struct dhcp_netid iface_id;
struct dhcp_opt *opt_cfg;
int done_dns = 0;
#ifdef HAVE_LINUX_NETWORK
FILE *f;
#endif
save_counter(0);
ra = expand(sizeof(struct ra_packet));
@@ -211,6 +215,7 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
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;
@@ -228,14 +233,23 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
return;
strncpy(ifr.ifr_name, iface_name, IF_NAMESIZE);
if (ioctl(daemon->icmp6fd, SIOCGIFMTU, &ifr) != -1)
#ifdef HAVE_LINUX_NETWORK
/* Note that IPv6 MTU is not necessarilly the same as the IPv4 MTU
available from SIOCGIFMTU */
sprintf(daemon->namebuff, "/proc/sys/net/ipv6/conf/%s/mtu", iface_name);
if ((f = fopen(daemon->namebuff, "r")))
{
put_opt6_char(ICMP6_OPT_MTU);
put_opt6_char(1);
put_opt6_short(0);
put_opt6_long(ifr.ifr_mtu);
if (fgets(daemon->namebuff, MAXDNAME, f))
{
put_opt6_char(ICMP6_OPT_MTU);
put_opt6_char(1);
put_opt6_short(0);
put_opt6_long(atoi(daemon->namebuff));
}
fclose(f);
}
#endif
iface_enumerate(AF_LOCAL, &iface, add_lla);
@@ -265,7 +279,7 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
/* 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);
}
@@ -293,7 +307,7 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
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 */
@@ -325,16 +339,13 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
}
static int add_prefixes(struct in6_addr *local, int prefix,
int scope, int if_index, int dad,
int preferred, int valid, 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;
(void)preferred;
(void)valid;
if (if_index == param->ind)
{
if (IN6_IS_ADDR_LINKLOCAL(local))
@@ -345,9 +356,8 @@ static int add_prefixes(struct in6_addr *local, int prefix,
int do_prefix = 0;
int do_slaac = 0;
int deprecate = 0;
int found_constructed = 0;
int constructed = 0;
unsigned int time = 0xffffffff;
int calc_valid = 0, calc_preferred = 0;
struct dhcp_context *context;
for (context = daemon->dhcp6; context; context = context->next)
@@ -376,23 +386,20 @@ static int add_prefixes(struct in6_addr *local, int prefix,
param->other = 1;
}
if (context->flags & CONTEXT_CONSTRUCTED)
{
found_constructed = 1;
calc_valid = context->valid;
calc_preferred = context->preferred;
if (context->valid != -1)
calc_valid -= (int)param->now;
if (context->preferred != -1)
calc_preferred -= (int)param->now;
}
/* find floor time */
/* find floor time, don't reduce below RA interval. */
if (time > context->lease_time)
time = context->lease_time;
{
time = context->lease_time;
if (time < 600u)
time = 600;
}
if (context->flags & CONTEXT_DEPRECATE)
deprecate = 1;
if (context->flags & CONTEXT_CONSTRUCTED)
constructed = 1;
/* collect dhcp-range tags */
if (context->netid.next == &context->netid && context->netid.net)
@@ -417,10 +424,24 @@ static int add_prefixes(struct in6_addr *local, int prefix,
param->found_context = 1;
}
if (!found_constructed)
/* configured time is ceiling */
if (!constructed || valid > time)
valid = time;
if (flags & IFACE_DEPRECATED)
preferred = 0;
if (deprecate)
time = 0;
/* configured time is ceiling */
if (!constructed || preferred > time)
preferred = time;
if (preferred > param->pref_time)
{
calc_valid = time;
calc_preferred = deprecate ? 0 : time;
param->pref_time = preferred;
param->link_global = *local;
}
if (do_prefix)
@@ -432,17 +453,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(calc_valid);
opt->preferred_lifetime = htonl(calc_preferred);
opt->valid_lifetime = htonl(valid);
opt->preferred_lifetime = htonl(preferred);
opt->reserved = 0;
opt->prefix = *local;
@@ -526,14 +543,13 @@ time_t periodic_ra(time_t now)
}
static int iface_search(struct in6_addr *local, int prefix,
int scope, int if_index, int dad,
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;
@@ -549,7 +565,7 @@ static int iface_search(struct in6_addr *local, int prefix,
timeout value and arrange for RA to be sent unless interface is
still doing DAD.*/
if (!dad)
if (!(flags & IFACE_TENTATIVE))
param->iface = if_index;
if (difftime(param->now, context->ra_short_period_start) < 60.0)

View File

@@ -625,10 +625,16 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
hostname = NULL;
}
}
if (have_config(valid_config, CONFIG_TIME))
lease_time = valid_config->lease_time;
else
lease_time = this_context->lease_time;
lease_time = have_config(valid_config, CONFIG_TIME) ? valid_config->lease_time : this_context->lease_time;
if (this_context->valid < lease_time)
lease_time = this_context->valid;
if (ia_option)
if (ia_option)
{
if (requested_time < 120u )
requested_time = 120u; /* sanity */
@@ -740,7 +746,8 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
o1 = new_opt6(OPTION6_IAADDR);
put_opt6(addrp, sizeof(*addrp));
/* preferred lifetime */
put_opt6_long(this_context && (this_context->flags & CONTEXT_DEPRECATE) ? 0 : lease_time);
put_opt6_long(this_context && (this_context->preferred < lease_time) ?
this_context->preferred : lease_time);
put_opt6_long(lease_time); /* valid lifetime */
end_opt6(o1);