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