]> git.ipfire.org Git - people/ms/dnsmasq.git/blob - src/radv.c
Fix new poll() code for helper pipe. Removed CPU-spin.
[people/ms/dnsmasq.git] / src / radv.c
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
29 struct 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
38 struct search_param {
39 time_t now; int iface;
40 char name[IF_NAMESIZE+1];
41 };
42
43 struct 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
51 static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest);
52 static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_addr *dest,
53 int send_iface);
54 static int send_ra_to_aliases(int index, unsigned int type, char *mac, size_t maclen, void *parm);
55 static 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);
58 static int iface_search(struct in6_addr *local, int prefix,
59 int scope, int if_index, int flags,
60 int prefered, int valid, void *vparam);
61 static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm);
62 static void new_timeout(struct dhcp_context *context, char *iface_name, time_t now);
63 static unsigned int calc_lifetime(struct ra_interface *ra);
64 static unsigned int calc_interval(struct ra_interface *ra);
65 static unsigned int calc_prio(struct ra_interface *ra);
66 static struct ra_interface *find_iface_param(char *iface);
67
68 static int hop_limit;
69
70 void 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
117 void 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
136 void 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
236 static 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
527 static 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
534 static 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
709 static 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
730 time_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
839 static 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
861 static 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
910 static 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
923 static 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
934 static 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
950 static 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
968 static unsigned int calc_prio(struct ra_interface *ra)
969 {
970 if (ra)
971 return ra->prio;
972
973 return 0;
974 }
975
976 #endif