1/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
2
3   This program is free software; you can redistribute it and/or modify
4   it under the terms of the GNU General Public License as published by
5   the Free Software Foundation; version 2 dated June, 1991, or
6   (at your option) version 3 dated 29 June, 2007.
7
8   This program is distributed in the hope that it will be useful,
9   but WITHOUT ANY WARRANTY; without even the implied warranty of
10   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11   GNU General Public License for more details.
12
13   You should have received a copy of the GNU General Public License
14   along with this program.  If not, see <http://www.gnu.org/licenses/>.
15*/
16
17
18/* NB. This code may be called during a DHCPv4 or transaction which is in ping-wait
19   It therefore cannot use any DHCP buffer resources except outpacket, which is
20   not used by DHCPv4 code. This code may also be called when DHCP 4 or 6 isn't
21   active, so we ensure that outpacket is allocated here too */
22
23#include "dnsmasq.h"
24
25#ifdef HAVE_DHCP6
26
27#include <netinet/icmp6.h>
28
29struct ra_param {
30  time_t now;
31  int ind, managed, other, found_context, first, adv_router;
32  char *if_name;
33  struct dhcp_netid *tags;
34  struct in6_addr link_local, link_global, ula;
35  unsigned int glob_pref_time, link_pref_time, ula_pref_time, adv_interval, prio;
36};
37
38struct search_param {
39  time_t now; int iface;
40  char name[IF_NAMESIZE+1];
41};
42
43struct alias_param {
44  int iface;
45  struct dhcp_bridge *bridge;
46  int num_alias_ifs;
47  int max_alias_ifs;
48  int *alias_ifs;
49};
50
51static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest);
52static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_addr *dest,
53                    int send_iface);
54static int send_ra_to_aliases(int index, unsigned int type, char *mac, size_t maclen, void *parm);
55static int add_prefixes(struct in6_addr *local,  int prefix,
56			int scope, int if_index, int flags,
57			unsigned int preferred, unsigned int valid, void *vparam);
58static int iface_search(struct in6_addr *local,  int prefix,
59			int scope, int if_index, int flags,
60			int prefered, int valid, void *vparam);
61static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm);
62static void new_timeout(struct dhcp_context *context, char *iface_name, time_t now);
63static unsigned int calc_lifetime(struct ra_interface *ra);
64static unsigned int calc_interval(struct ra_interface *ra);
65static unsigned int calc_prio(struct ra_interface *ra);
66static struct ra_interface *find_iface_param(char *iface);
67
68static int hop_limit;
69
70void ra_init(time_t now)
71{
72  struct icmp6_filter filter;
73  int fd;
74#if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
75  int class = IPTOS_CLASS_CS6;
76#endif
77  int val = 255; /* radvd uses this value */
78  socklen_t len = sizeof(int);
79  struct dhcp_context *context;
80
81  /* ensure this is around even if we're not doing DHCPv6 */
82  expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet));
83
84  /* See if we're guessing SLAAC addresses, if so we need to recieve ping replies */
85  for (context = daemon->dhcp6; context; context = context->next)
86    if ((context->flags & CONTEXT_RA_NAME))
87      break;
88
89  /* Need ICMP6 socket for transmission for DHCPv6 even when not doing RA. */
90
91  ICMP6_FILTER_SETBLOCKALL(&filter);
92  if (daemon->doing_ra)
93    {
94      ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
95      if (context)
96	ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filter);
97    }
98
99  if ((fd = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1 ||
100      getsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hop_limit, &len) ||
101#if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
102      setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &class, sizeof(class)) == -1 ||
103#endif
104      !fix_fd(fd) ||
105      !set_ipv6pktinfo(fd) ||
106      setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val)) ||
107      setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val)) ||
108      setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter)) == -1)
109    die (_("cannot create ICMPv6 socket: %s"), NULL, EC_BADNET);
110
111   daemon->icmp6fd = fd;
112
113   if (daemon->doing_ra)
114     ra_start_unsolicted(now, NULL);
115}
116
117void ra_start_unsolicted(time_t now, struct dhcp_context *context)
118{
119   /* init timers so that we do ra's for some/all soon. some ra_times will end up zeroed
120     if it's not appropriate to advertise those contexts.
121     This gets re-called on a netlink route-change to re-do the advertisement
122     and pick up new interfaces */
123
124  if (context)
125    context->ra_short_period_start = context->ra_time = now;
126  else
127    for (context = daemon->dhcp6; context; context = context->next)
128      if (!(context->flags & CONTEXT_TEMPLATE))
129	{
130	  context->ra_time = now + (rand16()/13000); /* range 0 - 5 */
131	  /* re-do frequently for a minute or so, in case the first gets lost. */
132	  context->ra_short_period_start = now;
133	}
134}
135
136void icmp6_packet(time_t now)
137{
138  char interface[IF_NAMESIZE+1];
139  ssize_t sz;
140  int if_index = 0;
141  struct cmsghdr *cmptr;
142  struct msghdr msg;
143  union {
144    struct cmsghdr align; /* this ensures alignment */
145    char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
146  } control_u;
147  struct sockaddr_in6 from;
148  unsigned char *packet;
149  struct iname *tmp;
150
151  /* Note: use outpacket for input buffer */
152  msg.msg_control = control_u.control6;
153  msg.msg_controllen = sizeof(control_u);
154  msg.msg_flags = 0;
155  msg.msg_name = &from;
156  msg.msg_namelen = sizeof(from);
157  msg.msg_iov = &daemon->outpacket;
158  msg.msg_iovlen = 1;
159
160  if ((sz = recv_dhcp_packet(daemon->icmp6fd, &msg)) == -1 || sz < 8)
161    return;
162
163  packet = (unsigned char *)daemon->outpacket.iov_base;
164
165  for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
166    if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
167      {
168	union {
169	  unsigned char *c;
170	  struct in6_pktinfo *p;
171	} p;
172	p.c = CMSG_DATA(cmptr);
173
174	if_index = p.p->ipi6_ifindex;
175      }
176
177  if (!indextoname(daemon->icmp6fd, if_index, interface))
178    return;
179
180  if (!iface_check(AF_LOCAL, NULL, interface, NULL))
181    return;
182
183  for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
184    if (tmp->name && wildcard_match(tmp->name, interface))
185      return;
186
187  if (packet[1] != 0)
188    return;
189
190  if (packet[0] == ICMP6_ECHO_REPLY)
191    lease_ping_reply(&from.sin6_addr, packet, interface);
192  else if (packet[0] == ND_ROUTER_SOLICIT)
193    {
194      char *mac = "";
195      struct dhcp_bridge *bridge, *alias;
196
197      /* look for link-layer address option for logging */
198      if (sz >= 16 && packet[8] == ICMP6_OPT_SOURCE_MAC && (packet[9] * 8) + 8 <= sz)
199	{
200	  print_mac(daemon->namebuff, &packet[10], (packet[9] * 8) - 2);
201	  mac = daemon->namebuff;
202	}
203
204      if (!option_bool(OPT_QUIET_RA))
205	my_syslog(MS_DHCP | LOG_INFO, "RTR-SOLICIT(%s) %s", interface, mac);
206
207      /* If the incoming interface is an alias of some other one (as
208         specified by the --bridge-interface option), send an RA using
209         the context of the aliased interface. */
210      for (bridge = daemon->bridges; bridge; bridge = bridge->next)
211        {
212          int bridge_index = if_nametoindex(bridge->iface);
213          if (bridge_index)
214	    {
215	      for (alias = bridge->alias; alias; alias = alias->next)
216		if (wildcard_matchn(alias->iface, interface, IF_NAMESIZE))
217		  {
218		    /* Send an RA on if_index with information from
219		       bridge_index. */
220		    send_ra_alias(now, bridge_index, bridge->iface, NULL, if_index);
221		    break;
222		  }
223	      if (alias)
224		break;
225	    }
226        }
227
228      /* If the incoming interface wasn't an alias, send an RA using
229	 the context of the incoming interface. */
230      if (!bridge)
231	/* source address may not be valid in solicit request. */
232	send_ra(now, if_index, interface, !IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr) ? &from.sin6_addr : NULL);
233    }
234}
235
236static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_addr *dest, int send_iface)
237{
238  struct ra_packet *ra;
239  struct ra_param parm;
240  struct sockaddr_in6 addr;
241  struct dhcp_context *context, *tmp,  **up;
242  struct dhcp_netid iface_id;
243  struct dhcp_opt *opt_cfg;
244  struct ra_interface *ra_param = find_iface_param(iface_name);
245  int done_dns = 0, old_prefix = 0;
246  unsigned int min_pref_time;
247#ifdef HAVE_LINUX_NETWORK
248  FILE *f;
249#endif
250
251  parm.ind = iface;
252  parm.managed = 0;
253  parm.other = 0;
254  parm.found_context = 0;
255  parm.adv_router = 0;
256  parm.if_name = iface_name;
257  parm.first = 1;
258  parm.now = now;
259  parm.glob_pref_time = parm.link_pref_time = parm.ula_pref_time = 0;
260  parm.adv_interval = calc_interval(ra_param);
261  parm.prio = calc_prio(ra_param);
262
263  save_counter(0);
264  ra = expand(sizeof(struct ra_packet));
265
266  ra->type = ND_ROUTER_ADVERT;
267  ra->code = 0;
268  ra->hop_limit = hop_limit;
269  ra->flags = parm.prio;
270  ra->lifetime = htons(calc_lifetime(ra_param));
271  ra->reachable_time = 0;
272  ra->retrans_time = 0;
273
274  /* set tag with name == interface */
275  iface_id.net = iface_name;
276  iface_id.next = NULL;
277  parm.tags = &iface_id;
278
279  for (context = daemon->dhcp6; context; context = context->next)
280    {
281      context->flags &= ~CONTEXT_RA_DONE;
282      context->netid.next = &context->netid;
283    }
284
285  if (!iface_enumerate(AF_INET6, &parm, add_prefixes))
286    return;
287
288  /* Find smallest preferred time within address classes,
289     to use as lifetime for options. This is a rather arbitrary choice. */
290  min_pref_time = 0xffffffff;
291  if (parm.glob_pref_time != 0 && parm.glob_pref_time < min_pref_time)
292    min_pref_time = parm.glob_pref_time;
293
294  if (parm.ula_pref_time != 0 && parm.ula_pref_time < min_pref_time)
295    min_pref_time = parm.ula_pref_time;
296
297  if (parm.link_pref_time != 0 && parm.link_pref_time < min_pref_time)
298    min_pref_time = parm.link_pref_time;
299
300  /* Look for constructed contexts associated with addresses which have gone,
301     and advertise them with preferred_time == 0  RFC 6204 4.3 L-13 */
302  for (up = &daemon->dhcp6, context = daemon->dhcp6; context; context = tmp)
303    {
304      tmp = context->next;
305
306      if (context->if_index == iface && (context->flags & CONTEXT_OLD))
307	{
308	  unsigned int old = difftime(now, context->address_lost_time);
309
310	  if (old > context->saved_valid)
311	    {
312	      /* We've advertised this enough, time to go */
313	      *up = context->next;
314	      free(context);
315	    }
316	  else
317	    {
318	      struct prefix_opt *opt;
319	      struct in6_addr local = context->start6;
320	      int do_slaac = 0;
321
322	      old_prefix = 1;
323
324	      /* zero net part of address */
325	      setaddr6part(&local, addr6part(&local) & ~((context->prefix == 64) ? (u64)-1LL : (1LLU << (128 - context->prefix)) - 1LLU));
326
327
328	      if (context->flags & CONTEXT_RA)
329		{
330		  do_slaac = 1;
331		  if (context->flags & CONTEXT_DHCP)
332		    {
333		      parm.other = 1;
334		      if (!(context->flags & CONTEXT_RA_STATELESS))
335			parm.managed = 1;
336		    }
337		}
338	      else
339		{
340		  /* don't do RA for non-ra-only unless --enable-ra is set */
341		  if (option_bool(OPT_RA))
342		    {
343		      parm.managed = 1;
344		      parm.other = 1;
345		    }
346		}
347
348	      if ((opt = expand(sizeof(struct prefix_opt))))
349		{
350		  opt->type = ICMP6_OPT_PREFIX;
351		  opt->len = 4;
352		  opt->prefix_len = context->prefix;
353		  /* autonomous only if we're not doing dhcp, set
354                     "on-link" unless "off-link" was specified */
355		  opt->flags = (do_slaac ? 0x40 : 0) |
356                    ((context->flags & CONTEXT_RA_OFF_LINK) ? 0 : 0x80);
357		  opt->valid_lifetime = htonl(context->saved_valid - old);
358		  opt->preferred_lifetime = htonl(0);
359		  opt->reserved = 0;
360		  opt->prefix = local;
361
362		  inet_ntop(AF_INET6, &local, daemon->addrbuff, ADDRSTRLEN);
363		  if (!option_bool(OPT_QUIET_RA))
364		    my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s old prefix", iface_name, daemon->addrbuff);
365		}
366
367	      up = &context->next;
368	    }
369	}
370      else
371	up = &context->next;
372    }
373
374  /* If we're advertising only old prefixes, set router lifetime to zero. */
375  if (old_prefix && !parm.found_context)
376    ra->lifetime = htons(0);
377
378  /* No prefixes to advertise. */
379  if (!old_prefix && !parm.found_context)
380    return;
381
382  /* If we're sending router address instead of prefix in at least on prefix,
383     include the advertisement interval option. */
384  if (parm.adv_router)
385    {
386      put_opt6_char(ICMP6_OPT_ADV_INTERVAL);
387      put_opt6_char(1);
388      put_opt6_short(0);
389      /* interval value is in milliseconds */
390      put_opt6_long(1000 * calc_interval(find_iface_param(iface_name)));
391    }
392
393#ifdef HAVE_LINUX_NETWORK
394  /* Note that IPv6 MTU is not necessarilly the same as the IPv4 MTU
395     available from SIOCGIFMTU */
396  sprintf(daemon->namebuff, "/proc/sys/net/ipv6/conf/%s/mtu", iface_name);
397  if ((f = fopen(daemon->namebuff, "r")))
398    {
399      if (fgets(daemon->namebuff, MAXDNAME, f))
400	{
401	  put_opt6_char(ICMP6_OPT_MTU);
402	  put_opt6_char(1);
403	  put_opt6_short(0);
404	  put_opt6_long(atoi(daemon->namebuff));
405	}
406      fclose(f);
407    }
408#endif
409
410  iface_enumerate(AF_LOCAL, &send_iface, add_lla);
411
412  /* RDNSS, RFC 6106, use relevant DHCP6 options */
413  (void)option_filter(parm.tags, NULL, daemon->dhcp_opts6);
414
415  for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
416    {
417      int i;
418
419      /* netids match and not encapsulated? */
420      if (!(opt_cfg->flags & DHOPT_TAGOK))
421        continue;
422
423      if (opt_cfg->opt == OPTION6_DNS_SERVER)
424        {
425	  struct in6_addr *a;
426	  int len;
427
428	  done_dns = 1;
429
430          if (opt_cfg->len == 0)
431	    continue;
432
433	  /* reduce len for any addresses we can't substitute */
434	  for (a = (struct in6_addr *)opt_cfg->val, len = opt_cfg->len, i = 0;
435	       i < opt_cfg->len; i += IN6ADDRSZ, a++)
436	    if ((IN6_IS_ADDR_UNSPECIFIED(a) && parm.glob_pref_time == 0) ||
437		(IN6_IS_ADDR_ULA_ZERO(a) && parm.ula_pref_time == 0) ||
438		(IN6_IS_ADDR_LINK_LOCAL_ZERO(a) && parm.link_pref_time == 0))
439	      len -= IN6ADDRSZ;
440
441	  if (len != 0)
442	    {
443	      put_opt6_char(ICMP6_OPT_RDNSS);
444	      put_opt6_char((len/8) + 1);
445	      put_opt6_short(0);
446	      put_opt6_long(min_pref_time);
447
448	      for (a = (struct in6_addr *)opt_cfg->val, i = 0; i <  opt_cfg->len; i += IN6ADDRSZ, a++)
449		if (IN6_IS_ADDR_UNSPECIFIED(a))
450		  {
451		    if (parm.glob_pref_time != 0)
452		      put_opt6(&parm.link_global, IN6ADDRSZ);
453		  }
454		else if (IN6_IS_ADDR_ULA_ZERO(a))
455		  {
456		    if (parm.ula_pref_time != 0)
457		    put_opt6(&parm.ula, IN6ADDRSZ);
458		  }
459		else if (IN6_IS_ADDR_LINK_LOCAL_ZERO(a))
460		  {
461		    if (parm.link_pref_time != 0)
462		      put_opt6(&parm.link_local, IN6ADDRSZ);
463		  }
464		else
465		  put_opt6(a, IN6ADDRSZ);
466	    }
467	}
468
469      if (opt_cfg->opt == OPTION6_DOMAIN_SEARCH && opt_cfg->len != 0)
470	{
471	  int len = ((opt_cfg->len+7)/8);
472
473	  put_opt6_char(ICMP6_OPT_DNSSL);
474	  put_opt6_char(len + 1);
475	  put_opt6_short(0);
476	  put_opt6_long(min_pref_time);
477	  put_opt6(opt_cfg->val, opt_cfg->len);
478
479	  /* pad */
480	  for (i = opt_cfg->len; i < len * 8; i++)
481	    put_opt6_char(0);
482	}
483    }
484
485  if (daemon->port == NAMESERVER_PORT && !done_dns && parm.link_pref_time != 0)
486    {
487      /* default == us, as long as we are supplying DNS service. */
488      put_opt6_char(ICMP6_OPT_RDNSS);
489      put_opt6_char(3);
490      put_opt6_short(0);
491      put_opt6_long(min_pref_time);
492      put_opt6(&parm.link_local, IN6ADDRSZ);
493    }
494
495  /* set managed bits unless we're providing only RA on this link */
496  if (parm.managed)
497    ra->flags |= 0x80; /* M flag, managed, */
498   if (parm.other)
499    ra->flags |= 0x40; /* O flag, other */
500
501  /* decide where we're sending */
502  memset(&addr, 0, sizeof(addr));
503#ifdef HAVE_SOCKADDR_SA_LEN
504  addr.sin6_len = sizeof(struct sockaddr_in6);
505#endif
506  addr.sin6_family = AF_INET6;
507  addr.sin6_port = htons(IPPROTO_ICMPV6);
508  if (dest)
509    {
510      addr.sin6_addr = *dest;
511      if (IN6_IS_ADDR_LINKLOCAL(dest) ||
512	  IN6_IS_ADDR_MC_LINKLOCAL(dest))
513	addr.sin6_scope_id = iface;
514    }
515  else
516    {
517      inet_pton(AF_INET6, ALL_NODES, &addr.sin6_addr);
518      setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &send_iface, sizeof(send_iface));
519    }
520
521  while (retry_send(sendto(daemon->icmp6fd, daemon->outpacket.iov_base,
522			   save_counter(0), 0, (struct sockaddr *)&addr,
523			   sizeof(addr))));
524
525}
526
527static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest)
528{
529  /* Send an RA on the same interface that the RA content is based
530     on. */
531  send_ra_alias(now, iface, iface_name, dest, iface);
532}
533
534static int add_prefixes(struct in6_addr *local,  int prefix,
535			int scope, int if_index, int flags,
536			unsigned int preferred, unsigned int valid, void *vparam)
537{
538  struct ra_param *param = vparam;
539
540  (void)scope; /* warning */
541
542  if (if_index == param->ind)
543    {
544      if (IN6_IS_ADDR_LINKLOCAL(local))
545	{
546	  /* Can there be more than one LL address?
547	     Select the one with the longest preferred time
548	     if there is. */
549	  if (preferred > param->link_pref_time)
550	    {
551	      param->link_pref_time = preferred;
552	      param->link_local = *local;
553	    }
554	}
555      else if (!IN6_IS_ADDR_LOOPBACK(local) &&
556	       !IN6_IS_ADDR_MULTICAST(local))
557	{
558	  int real_prefix = 0;
559	  int do_slaac = 0;
560	  int deprecate  = 0;
561	  int constructed = 0;
562	  int adv_router = 0;
563	  int off_link = 0;
564	  unsigned int time = 0xffffffff;
565	  struct dhcp_context *context;
566
567	  for (context = daemon->dhcp6; context; context = context->next)
568	    if (!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
569		prefix <= context->prefix &&
570		is_same_net6(local, &context->start6, context->prefix) &&
571		is_same_net6(local, &context->end6, context->prefix))
572	      {
573		context->saved_valid = valid;
574
575		if (context->flags & CONTEXT_RA)
576		  {
577		    do_slaac = 1;
578		    if (context->flags & CONTEXT_DHCP)
579		      {
580			param->other = 1;
581			if (!(context->flags & CONTEXT_RA_STATELESS))
582			  param->managed = 1;
583		      }
584		  }
585		else
586		  {
587		    /* don't do RA for non-ra-only unless --enable-ra is set */
588		    if (!option_bool(OPT_RA))
589		      continue;
590		    param->managed = 1;
591		    param->other = 1;
592		  }
593
594		/* Configured to advertise router address, not prefix. See RFC 3775 7.2
595		 In this case we do all addresses associated with a context,
596		 hence the real_prefix setting here. */
597		if (context->flags & CONTEXT_RA_ROUTER)
598		  {
599		    adv_router = 1;
600		    param->adv_router = 1;
601		    real_prefix = context->prefix;
602		  }
603
604		/* find floor time, don't reduce below 3 * RA interval. */
605		if (time > context->lease_time)
606		  {
607		    time = context->lease_time;
608		    if (time < ((unsigned int)(3 * param->adv_interval)))
609		      time = 3 * param->adv_interval;
610		  }
611
612		if (context->flags & CONTEXT_DEPRECATE)
613		  deprecate = 1;
614
615		if (context->flags & CONTEXT_CONSTRUCTED)
616		  constructed = 1;
617
618
619		/* collect dhcp-range tags */
620		if (context->netid.next == &context->netid && context->netid.net)
621		  {
622		    context->netid.next = param->tags;
623		    param->tags = &context->netid;
624		  }
625
626		/* subsequent prefixes on the same interface
627		   and subsequent instances of this prefix don't need timers.
628		   Be careful not to find the same prefix twice with different
629		   addresses unless we're advertising the actual addresses. */
630		if (!(context->flags & CONTEXT_RA_DONE))
631		  {
632		    if (!param->first)
633		      context->ra_time = 0;
634		    context->flags |= CONTEXT_RA_DONE;
635		    real_prefix = context->prefix;
636                    off_link = (context->flags & CONTEXT_RA_OFF_LINK);
637		  }
638
639		param->first = 0;
640		param->found_context = 1;
641	      }
642
643	  /* configured time is ceiling */
644	  if (!constructed || valid > time)
645	    valid = time;
646
647	  if (flags & IFACE_DEPRECATED)
648	    preferred = 0;
649
650	  if (deprecate)
651	    time = 0;
652
653	  /* configured time is ceiling */
654	  if (!constructed || preferred > time)
655	    preferred = time;
656
657	  if (IN6_IS_ADDR_ULA(local))
658	    {
659	      if (preferred > param->ula_pref_time)
660		{
661		  param->ula_pref_time = preferred;
662		  param->ula = *local;
663		}
664	    }
665	  else
666	    {
667	      if (preferred > param->glob_pref_time)
668		{
669		  param->glob_pref_time = preferred;
670		  param->link_global = *local;
671		}
672	    }
673
674	  if (real_prefix != 0)
675	    {
676	      struct prefix_opt *opt;
677
678	      if ((opt = expand(sizeof(struct prefix_opt))))
679		{
680		  /* zero net part of address */
681		  if (!adv_router)
682		    setaddr6part(local, addr6part(local) & ~((real_prefix == 64) ? (u64)-1LL : (1LLU << (128 - real_prefix)) - 1LLU));
683
684		  opt->type = ICMP6_OPT_PREFIX;
685		  opt->len = 4;
686		  opt->prefix_len = real_prefix;
687		  /* autonomous only if we're not doing dhcp, set
688                     "on-link" unless "off-link" was specified */
689		  opt->flags = (off_link ? 0 : 0x80);
690		  if (do_slaac)
691		    opt->flags |= 0x40;
692		  if (adv_router)
693		    opt->flags |= 0x20;
694		  opt->valid_lifetime = htonl(valid);
695		  opt->preferred_lifetime = htonl(preferred);
696		  opt->reserved = 0;
697		  opt->prefix = *local;
698
699		  inet_ntop(AF_INET6, local, daemon->addrbuff, ADDRSTRLEN);
700		  if (!option_bool(OPT_QUIET_RA))
701		    my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s", param->if_name, daemon->addrbuff);
702		}
703	    }
704	}
705    }
706  return 1;
707}
708
709static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm)
710{
711  (void)type;
712
713  if (index == *((int *)parm))
714    {
715      /* size is in units of 8 octets and includes type and length (2 bytes)
716	 add 7 to round up */
717      int len = (maclen + 9) >> 3;
718      unsigned char *p = expand(len << 3);
719      memset(p, 0, len << 3);
720      *p++ = ICMP6_OPT_SOURCE_MAC;
721      *p++ = len;
722      memcpy(p, mac, maclen);
723
724      return 0;
725    }
726
727  return 1;
728}
729
730time_t periodic_ra(time_t now)
731{
732  struct search_param param;
733  struct dhcp_context *context;
734  time_t next_event;
735  struct alias_param aparam;
736
737  param.now = now;
738  param.iface = 0;
739
740  while (1)
741    {
742      /* find overdue events, and time of first future event */
743      for (next_event = 0, context = daemon->dhcp6; context; context = context->next)
744	if (context->ra_time != 0)
745	  {
746	    if (difftime(context->ra_time, now) <= 0.0)
747	      break; /* overdue */
748
749	    if (next_event == 0 || difftime(next_event, context->ra_time) > 0.0)
750	      next_event = context->ra_time;
751	  }
752
753      /* none overdue */
754      if (!context)
755	break;
756
757      if ((context->flags & CONTEXT_OLD) &&
758	  context->if_index != 0 &&
759	  indextoname(daemon->icmp6fd, context->if_index, param.name))
760	{
761	  /* A context for an old address. We'll not find the interface by
762	     looking for addresses, but we know it anyway, since the context is
763	     constructed */
764	  param.iface = context->if_index;
765	  new_timeout(context, param.name, now);
766	}
767      else if (iface_enumerate(AF_INET6, &param, iface_search))
768	/* There's a context overdue, but we can't find an interface
769	   associated with it, because it's for a subnet we dont
770	   have an interface on. Probably we're doing DHCP on
771	   a remote subnet via a relay. Zero the timer, since we won't
772	   ever be able to send ra's and satistfy it. */
773	context->ra_time = 0;
774
775      if (param.iface != 0 &&
776	  iface_check(AF_LOCAL, NULL, param.name, NULL))
777	{
778	  struct iname *tmp;
779	  for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
780	    if (tmp->name && wildcard_match(tmp->name, param.name))
781	      break;
782	  if (!tmp)
783            {
784              send_ra(now, param.iface, param.name, NULL);
785
786              /* Also send on all interfaces that are aliases of this
787                 one. */
788              for (aparam.bridge = daemon->bridges;
789                   aparam.bridge;
790                   aparam.bridge = aparam.bridge->next)
791                if ((int)if_nametoindex(aparam.bridge->iface) == param.iface)
792                  {
793                    /* Count the number of alias interfaces for this
794                       'bridge', by calling iface_enumerate with
795                       send_ra_to_aliases and NULL alias_ifs. */
796                    aparam.iface = param.iface;
797                    aparam.alias_ifs = NULL;
798                    aparam.num_alias_ifs = 0;
799                    iface_enumerate(AF_LOCAL, &aparam, send_ra_to_aliases);
800                    my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s => %d alias(es)",
801                              param.name, daemon->addrbuff, aparam.num_alias_ifs);
802
803                    /* Allocate memory to store the alias interface
804                       indices. */
805                    aparam.alias_ifs = (int *)whine_malloc(aparam.num_alias_ifs *
806                                                           sizeof(int));
807                    if (aparam.alias_ifs)
808                      {
809                        /* Use iface_enumerate again to get the alias
810                           interface indices, then send on each of
811                           those. */
812                        aparam.max_alias_ifs = aparam.num_alias_ifs;
813                        aparam.num_alias_ifs = 0;
814                        iface_enumerate(AF_LOCAL, &aparam, send_ra_to_aliases);
815                        for (; aparam.num_alias_ifs; aparam.num_alias_ifs--)
816                          {
817                            my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s => i/f %d",
818                                      param.name, daemon->addrbuff,
819                                      aparam.alias_ifs[aparam.num_alias_ifs - 1]);
820                            send_ra_alias(now,
821                                          param.iface,
822                                          param.name,
823                                          NULL,
824                                          aparam.alias_ifs[aparam.num_alias_ifs - 1]);
825                          }
826                        free(aparam.alias_ifs);
827                      }
828
829                    /* The source interface can only appear in at most
830                       one --bridge-interface. */
831                    break;
832                  }
833            }
834	}
835    }
836  return next_event;
837}
838
839static int send_ra_to_aliases(int index, unsigned int type, char *mac, size_t maclen, void *parm)
840{
841  struct alias_param *aparam = (struct alias_param *)parm;
842  char ifrn_name[IFNAMSIZ];
843  struct dhcp_bridge *alias;
844
845  (void)type;
846  (void)mac;
847  (void)maclen;
848
849  if (if_indextoname(index, ifrn_name))
850    for (alias = aparam->bridge->alias; alias; alias = alias->next)
851      if (wildcard_matchn(alias->iface, ifrn_name, IFNAMSIZ))
852        {
853          if (aparam->alias_ifs && (aparam->num_alias_ifs < aparam->max_alias_ifs))
854            aparam->alias_ifs[aparam->num_alias_ifs] = index;
855          aparam->num_alias_ifs++;
856        }
857
858  return 1;
859}
860
861static int iface_search(struct in6_addr *local,  int prefix,
862			int scope, int if_index, int flags,
863			int preferred, int valid, void *vparam)
864{
865  struct search_param *param = vparam;
866  struct dhcp_context *context;
867
868  (void)scope;
869  (void)preferred;
870  (void)valid;
871
872  for (context = daemon->dhcp6; context; context = context->next)
873    if (!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
874	prefix <= context->prefix &&
875	is_same_net6(local, &context->start6, context->prefix) &&
876	is_same_net6(local, &context->end6, context->prefix) &&
877	context->ra_time != 0 &&
878	difftime(context->ra_time, param->now) <= 0.0)
879      {
880	/* found an interface that's overdue for RA determine new
881	   timeout value and arrange for RA to be sent unless interface is
882	   still doing DAD.*/
883
884	if (!(flags & IFACE_TENTATIVE))
885	  param->iface = if_index;
886
887	/* should never fail */
888	if (!indextoname(daemon->icmp6fd, if_index, param->name))
889	  {
890	    param->iface = 0;
891	    return 0;
892	  }
893
894	new_timeout(context, param->name, param->now);
895
896	/* zero timers for other contexts on the same subnet, so they don't timeout
897	   independently */
898	for (context = context->next; context; context = context->next)
899	  if (prefix <= context->prefix &&
900	      is_same_net6(local, &context->start6, context->prefix) &&
901	      is_same_net6(local, &context->end6, context->prefix))
902	    context->ra_time = 0;
903
904	return 0; /* found, abort */
905      }
906
907  return 1; /* keep searching */
908}
909
910static void new_timeout(struct dhcp_context *context, char *iface_name, time_t now)
911{
912  if (difftime(now, context->ra_short_period_start) < 60.0)
913    /* range 5 - 20 */
914    context->ra_time = now + 5 + (rand16()/4400);
915  else
916    {
917      /* range 3/4 - 1 times MaxRtrAdvInterval */
918      unsigned int adv_interval = calc_interval(find_iface_param(iface_name));
919      context->ra_time = now + (3 * adv_interval)/4 + ((adv_interval * (unsigned int)rand16()) >> 18);
920    }
921}
922
923static struct ra_interface *find_iface_param(char *iface)
924{
925  struct ra_interface *ra;
926
927  for (ra = daemon->ra_interfaces; ra; ra = ra->next)
928    if (wildcard_match(ra->name, iface))
929      return ra;
930
931  return NULL;
932}
933
934static unsigned int calc_interval(struct ra_interface *ra)
935{
936  int interval = 600;
937
938  if (ra && ra->interval != 0)
939    {
940      interval = ra->interval;
941      if (interval > 1800)
942	interval = 1800;
943      else if (interval < 4)
944	interval = 4;
945    }
946
947  return (unsigned int)interval;
948}
949
950static unsigned int calc_lifetime(struct ra_interface *ra)
951{
952  int lifetime, interval = (int)calc_interval(ra);
953
954  if (!ra || ra->lifetime == -1) /* not specified */
955    lifetime = 3 * interval;
956  else
957    {
958      lifetime = ra->lifetime;
959      if (lifetime < interval && lifetime != 0)
960	lifetime = interval;
961      else if (lifetime > 9000)
962	lifetime = 9000;
963    }
964
965  return (unsigned int)lifetime;
966}
967
968static unsigned int calc_prio(struct ra_interface *ra)
969{
970  if (ra)
971    return ra->prio;
972
973  return 0;
974}
975
976#endif
977