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