Compare commits

...
5 Commits
7 changed files with 151 additions and 182 deletions

No files matched your search

+7 -96
View File
@@ -25,7 +25,7 @@ struct iface_param {
};
static int complete_context6(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);
static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm);
@@ -182,7 +182,7 @@ 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 scope, int if_index, int flags, int preferred,
int valid, void *vparam)
{
struct dhcp_context *context;
@@ -190,7 +190,7 @@ static int complete_context6(struct in6_addr *local, int prefix,
struct iname *tmp;
(void)scope; /* warning */
(void)dad;
(void)flags;
(void)preferred;
(void)valid;
@@ -479,7 +479,7 @@ struct cparam {
};
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 +487,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;
@@ -549,19 +551,6 @@ static int construct_worker(struct in6_addr *local, int prefix,
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;
@@ -607,84 +596,6 @@ void dhcp_construct_contexts(time_t now)
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
+7 -7
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();
+10 -4
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;
};
@@ -680,7 +685,6 @@ struct dhcp_context {
int prefix, if_index;
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 +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
@@ -1151,7 +1158,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 */
+2 -2
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;
+34 -33
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)
{
@@ -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_newinterface(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_newinterface(now);
}
static int nl_async(struct nlmsghdr *h)
@@ -410,7 +390,28 @@ static int nl_async(struct nlmsghdr *h)
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
+60 -3
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->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)
+31 -37
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);
@@ -211,6 +212,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;
@@ -265,7 +267,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 +295,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 +327,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 +344,7 @@ 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;
unsigned int time = 0xffffffff;
int calc_valid = 0, calc_preferred = 0;
struct dhcp_context *context;
for (context = daemon->dhcp6; context; context = context->next)
@@ -376,17 +373,6 @@ 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 */
if (time > context->lease_time)
time = context->lease_time;
@@ -417,10 +403,23 @@ static int add_prefixes(struct in6_addr *local, int prefix,
param->found_context = 1;
}
if (!found_constructed)
/* configured time is ceiling */
if (valid > time)
valid = time;
if ((flags & IFACE_DEPRECATED) || deprecate)
preferred = 0;
else
{
calc_valid = time;
calc_preferred = deprecate ? 0 : time;
/* 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)
@@ -432,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(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 +521,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 +543,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)