]> git.ipfire.org Git - people/ms/dnsmasq.git/blame - src/radv.c
Allow router advertisements to have the "off-link" bit set.
[people/ms/dnsmasq.git] / src / radv.c
CommitLineData
aff33962 1/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
c5ad4e79
SK
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
843c96b4 18/* NB. This code may be called during a DHCPv4 or transaction which is in ping-wait
c5ad4e79 19 It therefore cannot use any DHCP buffer resources except outpacket, which is
843c96b4
SK
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 */
c5ad4e79
SK
22
23#include "dnsmasq.h"
c5ad4e79
SK
24
25#ifdef HAVE_DHCP6
26
22d904db
SK
27#include <netinet/icmp6.h>
28
c5ad4e79 29struct ra_param {
1f776932 30 time_t now;
7ea3d3fd 31 int ind, managed, other, found_context, first, adv_router;
c5ad4e79 32 char *if_name;
18f0fb05 33 struct dhcp_netid *tags;
c3a04081 34 struct in6_addr link_local, link_global, ula;
5bf50af2 35 unsigned int glob_pref_time, link_pref_time, ula_pref_time, adv_interval, prio;
c5ad4e79
SK
36};
37
38struct search_param {
39 time_t now; int iface;
c4cd95df 40 char name[IF_NAMESIZE+1];
c5ad4e79
SK
41};
42
1f776932 43static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest);
c5ad4e79 44static int add_prefixes(struct in6_addr *local, int prefix,
bad7b875 45 int scope, int if_index, int flags,
55b42f6d 46 unsigned int preferred, unsigned int valid, void *vparam);
c5ad4e79 47static int iface_search(struct in6_addr *local, int prefix,
bad7b875 48 int scope, int if_index, int flags,
1f776932 49 int prefered, int valid, void *vparam);
c5ad4e79 50static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm);
c4cd95df
SK
51static void new_timeout(struct dhcp_context *context, char *iface_name, time_t now);
52static unsigned int calc_lifetime(struct ra_interface *ra);
53static unsigned int calc_interval(struct ra_interface *ra);
54static unsigned int calc_prio(struct ra_interface *ra);
55static struct ra_interface *find_iface_param(char *iface);
c5ad4e79 56
c5379c1a 57static int hop_limit;
c5ad4e79
SK
58
59void ra_init(time_t now)
60{
c5ad4e79
SK
61 struct icmp6_filter filter;
62 int fd;
0e88d53f 63#if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
c5ad4e79
SK
64 int class = IPTOS_CLASS_CS6;
65#endif
66 int val = 255; /* radvd uses this value */
7b6dd880 67 socklen_t len = sizeof(int);
353ae4d2
SK
68 struct dhcp_context *context;
69
843c96b4
SK
70 /* ensure this is around even if we're not doing DHCPv6 */
71 expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet));
353ae4d2
SK
72
73 /* See if we're guessing SLAAC addresses, if so we need to recieve ping replies */
1f776932 74 for (context = daemon->dhcp6; context; context = context->next)
353ae4d2
SK
75 if ((context->flags & CONTEXT_RA_NAME))
76 break;
77
89500e31
SK
78 /* Need ICMP6 socket for transmission for DHCPv6 even when not doing RA. */
79
c5ad4e79 80 ICMP6_FILTER_SETBLOCKALL(&filter);
89500e31
SK
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 }
c5ad4e79
SK
87
88 if ((fd = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1 ||
c5379c1a 89 getsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hop_limit, &len) ||
0e88d53f 90#if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
c5ad4e79
SK
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
89500e31
SK
102 if (daemon->doing_ra)
103 ra_start_unsolicted(now, NULL);
c5ad4e79
SK
104}
105
353ae4d2 106void ra_start_unsolicted(time_t now, struct dhcp_context *context)
c5ad4e79 107{
353ae4d2 108 /* init timers so that we do ra's for some/all soon. some ra_times will end up zeroed
c5ad4e79
SK
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 */
6e3dba3f 112
353ae4d2 113 if (context)
1b75c1e6 114 context->ra_short_period_start = context->ra_time = now;
353ae4d2 115 else
1f776932 116 for (context = daemon->dhcp6; context; context = context->next)
6e3dba3f 117 if (!(context->flags & CONTEXT_TEMPLATE))
1b75c1e6
SK
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 }
c5ad4e79
SK
123}
124
1f776932 125void icmp6_packet(time_t now)
c5ad4e79
SK
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;
5ef33279 137 unsigned char *packet;
c5ad4e79 138 struct iname *tmp;
c5ad4e79
SK
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;
5ef33279
SK
151
152 packet = (unsigned char *)daemon->outpacket.iov_base;
c5ad4e79
SK
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
4f7b304f 169 if (!iface_check(AF_LOCAL, NULL, interface, NULL))
c5ad4e79
SK
170 return;
171
172 for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
49333cbd 173 if (tmp->name && wildcard_match(tmp->name, interface))
c5ad4e79
SK
174 return;
175
8bc4cece 176 if (packet[1] != 0)
353ae4d2 177 return;
8bc4cece 178
5ef33279
SK
179 if (packet[0] == ICMP6_ECHO_REPLY)
180 lease_ping_reply(&from.sin6_addr, packet, interface);
181 else if (packet[0] == ND_ROUTER_SOLICIT)
c5ad4e79 182 {
5ef33279
SK
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
8c0b73d3
KDB
192 if (!option_bool(OPT_QUIET_RA))
193 my_syslog(MS_DHCP | LOG_INFO, "RTR-SOLICIT(%s) %s", interface, mac);
f632e567 194 /* source address may not be valid in solicit request. */
1f776932 195 send_ra(now, if_index, interface, !IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr) ? &from.sin6_addr : NULL);
c5ad4e79 196 }
c5ad4e79
SK
197}
198
1f776932 199static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest)
c5ad4e79
SK
200{
201 struct ra_packet *ra;
202 struct ra_param parm;
c5ad4e79 203 struct sockaddr_in6 addr;
ef1a94ab 204 struct dhcp_context *context, *tmp, **up;
18f0fb05
SK
205 struct dhcp_netid iface_id;
206 struct dhcp_opt *opt_cfg;
c4cd95df 207 struct ra_interface *ra_param = find_iface_param(iface_name);
44522920 208 int done_dns = 0, old_prefix = 0;
c3a04081 209 unsigned int min_pref_time;
3b43646a
SK
210#ifdef HAVE_LINUX_NETWORK
211 FILE *f;
212#endif
c5ad4e79 213
c5ad4e79
SK
214 parm.ind = iface;
215 parm.managed = 0;
30cd9666 216 parm.other = 0;
c5ad4e79 217 parm.found_context = 0;
7ea3d3fd 218 parm.adv_router = 0;
c5ad4e79
SK
219 parm.if_name = iface_name;
220 parm.first = 1;
1f776932 221 parm.now = now;
c3a04081 222 parm.glob_pref_time = parm.link_pref_time = parm.ula_pref_time = 0;
c4cd95df 223 parm.adv_interval = calc_interval(ra_param);
5bf50af2
IP
224 parm.prio = calc_prio(ra_param);
225
226 save_counter(0);
227 ra = expand(sizeof(struct ra_packet));
1f776932 228
5bf50af2
IP
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
18f0fb05
SK
237 /* set tag with name == interface */
238 iface_id.net = iface_name;
239 iface_id.next = NULL;
240 parm.tags = &iface_id;
c5ad4e79 241
1f776932 242 for (context = daemon->dhcp6; context; context = context->next)
18f0fb05
SK
243 {
244 context->flags &= ~CONTEXT_RA_DONE;
245 context->netid.next = &context->netid;
246 }
247
ef1a94ab 248 if (!iface_enumerate(AF_INET6, &parm, add_prefixes))
c5ad4e79
SK
249 return;
250
c3a04081
SK
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
ef1a94ab
SK
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;
3b43646a 268
ef1a94ab
SK
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
44522920 285 old_prefix = 1;
ef1a94ab
SK
286
287 /* zero net part of address */
288 setaddr6part(&local, addr6part(&local) & ~((context->prefix == 64) ? (u64)-1LL : (1LLU << (128 - context->prefix)) - 1LLU));
289
6ea1f23b 290
7ea3d3fd 291 if (context->flags & CONTEXT_RA)
6ea1f23b
SK
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
ef1a94ab
SK
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;
2fd5bc95
NJ
316 /* autonomous only if we're not doing dhcp, set
317 "on-link" unless "off-link" was specified */
318 opt->flags = (do_slaac ? 0x40 : 0) |
319 ((context->flags & CONTEXT_RA_OFF_LINK) ? 0 : 0x80);
ef1a94ab
SK
320 opt->valid_lifetime = htonl(context->saved_valid - old);
321 opt->preferred_lifetime = htonl(0);
322 opt->reserved = 0;
323 opt->prefix = local;
324
325 inet_ntop(AF_INET6, &local, daemon->addrbuff, ADDRSTRLEN);
8c0b73d3
KDB
326 if (!option_bool(OPT_QUIET_RA))
327 my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s old prefix", iface_name, daemon->addrbuff);
ef1a94ab
SK
328 }
329
330 up = &context->next;
331 }
332 }
333 else
334 up = &context->next;
335 }
336
44522920
SK
337 /* If we're advertising only old prefixes, set router lifetime to zero. */
338 if (old_prefix && !parm.found_context)
339 ra->lifetime = htons(0);
340
341 /* No prefixes to advertise. */
342 if (!old_prefix && !parm.found_context)
343 return;
344
7ea3d3fd
SK
345 /* If we're sending router address instead of prefix in at least on prefix,
346 include the advertisement interval option. */
347 if (parm.adv_router)
348 {
349 put_opt6_char(ICMP6_OPT_ADV_INTERVAL);
350 put_opt6_char(1);
351 put_opt6_short(0);
352 /* interval value is in milliseconds */
353 put_opt6_long(1000 * calc_interval(find_iface_param(iface_name)));
354 }
355
3b43646a
SK
356#ifdef HAVE_LINUX_NETWORK
357 /* Note that IPv6 MTU is not necessarilly the same as the IPv4 MTU
358 available from SIOCGIFMTU */
359 sprintf(daemon->namebuff, "/proc/sys/net/ipv6/conf/%s/mtu", iface_name);
360 if ((f = fopen(daemon->namebuff, "r")))
c5ad4e79 361 {
3b43646a
SK
362 if (fgets(daemon->namebuff, MAXDNAME, f))
363 {
364 put_opt6_char(ICMP6_OPT_MTU);
365 put_opt6_char(1);
366 put_opt6_short(0);
367 put_opt6_long(atoi(daemon->namebuff));
368 }
369 fclose(f);
c5ad4e79 370 }
3b43646a 371#endif
c5ad4e79
SK
372
373 iface_enumerate(AF_LOCAL, &iface, add_lla);
18f0fb05
SK
374
375 /* RDNSS, RFC 6106, use relevant DHCP6 options */
376 (void)option_filter(parm.tags, NULL, daemon->dhcp_opts6);
c5ad4e79 377
18f0fb05
SK
378 for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
379 {
380 int i;
381
382 /* netids match and not encapsulated? */
383 if (!(opt_cfg->flags & DHOPT_TAGOK))
384 continue;
385
386 if (opt_cfg->opt == OPTION6_DNS_SERVER)
387 {
c3a04081
SK
388 struct in6_addr *a;
389 int len;
390
18f0fb05 391 done_dns = 1;
c3a04081
SK
392
393 if (opt_cfg->len == 0)
806cf787 394 continue;
18f0fb05 395
c3a04081
SK
396 /* reduce len for any addresses we can't substitute */
397 for (a = (struct in6_addr *)opt_cfg->val, len = opt_cfg->len, i = 0;
398 i < opt_cfg->len; i += IN6ADDRSZ, a++)
399 if ((IN6_IS_ADDR_UNSPECIFIED(a) && parm.glob_pref_time == 0) ||
400 (IN6_IS_ADDR_ULA_ZERO(a) && parm.ula_pref_time == 0) ||
401 (IN6_IS_ADDR_LINK_LOCAL_ZERO(a) && parm.link_pref_time == 0))
402 len -= IN6ADDRSZ;
403
404 if (len != 0)
405 {
406 put_opt6_char(ICMP6_OPT_RDNSS);
407 put_opt6_char((len/8) + 1);
408 put_opt6_short(0);
409 put_opt6_long(min_pref_time);
410
411 for (a = (struct in6_addr *)opt_cfg->val, i = 0; i < opt_cfg->len; i += IN6ADDRSZ, a++)
412 if (IN6_IS_ADDR_UNSPECIFIED(a))
413 {
414 if (parm.glob_pref_time != 0)
415 put_opt6(&parm.link_global, IN6ADDRSZ);
416 }
417 else if (IN6_IS_ADDR_ULA_ZERO(a))
418 {
419 if (parm.ula_pref_time != 0)
420 put_opt6(&parm.ula, IN6ADDRSZ);
421 }
422 else if (IN6_IS_ADDR_LINK_LOCAL_ZERO(a))
423 {
424 if (parm.link_pref_time != 0)
425 put_opt6(&parm.link_local, IN6ADDRSZ);
426 }
427 else
428 put_opt6(a, IN6ADDRSZ);
429 }
18f0fb05
SK
430 }
431
432 if (opt_cfg->opt == OPTION6_DOMAIN_SEARCH && opt_cfg->len != 0)
433 {
434 int len = ((opt_cfg->len+7)/8);
435
436 put_opt6_char(ICMP6_OPT_DNSSL);
437 put_opt6_char(len + 1);
438 put_opt6_short(0);
c3a04081 439 put_opt6_long(min_pref_time);
18f0fb05
SK
440 put_opt6(opt_cfg->val, opt_cfg->len);
441
442 /* pad */
443 for (i = opt_cfg->len; i < len * 8; i++)
444 put_opt6_char(0);
445 }
446 }
447
c3a04081 448 if (daemon->port == NAMESERVER_PORT && !done_dns && parm.link_pref_time != 0)
18f0fb05 449 {
ab915f83 450 /* default == us, as long as we are supplying DNS service. */
18f0fb05
SK
451 put_opt6_char(ICMP6_OPT_RDNSS);
452 put_opt6_char(3);
453 put_opt6_short(0);
c3a04081 454 put_opt6_long(min_pref_time);
806cf787 455 put_opt6(&parm.link_local, IN6ADDRSZ);
18f0fb05 456 }
c5ad4e79
SK
457
458 /* set managed bits unless we're providing only RA on this link */
459 if (parm.managed)
30cd9666
SK
460 ra->flags |= 0x80; /* M flag, managed, */
461 if (parm.other)
462 ra->flags |= 0x40; /* O flag, other */
463
c5ad4e79
SK
464 /* decide where we're sending */
465 memset(&addr, 0, sizeof(addr));
22d904db
SK
466#ifdef HAVE_SOCKADDR_SA_LEN
467 addr.sin6_len = sizeof(struct sockaddr_in6);
468#endif
c5ad4e79
SK
469 addr.sin6_family = AF_INET6;
470 addr.sin6_port = htons(IPPROTO_ICMPV6);
471 if (dest)
472 {
353ae4d2 473 addr.sin6_addr = *dest;
c5ad4e79
SK
474 if (IN6_IS_ADDR_LINKLOCAL(dest) ||
475 IN6_IS_ADDR_MC_LINKLOCAL(dest))
476 addr.sin6_scope_id = iface;
477 }
478 else
8f3194f7
SK
479 {
480 inet_pton(AF_INET6, ALL_NODES, &addr.sin6_addr);
481 setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &iface, sizeof(iface));
482 }
22d904db 483
ff841ebf
SK
484 while (retry_send(sendto(daemon->icmp6fd, daemon->outpacket.iov_base,
485 save_counter(0), 0, (struct sockaddr *)&addr,
486 sizeof(addr))));
c5ad4e79
SK
487
488}
489
490static int add_prefixes(struct in6_addr *local, int prefix,
bad7b875 491 int scope, int if_index, int flags,
55b42f6d 492 unsigned int preferred, unsigned int valid, void *vparam)
c5ad4e79 493{
c5ad4e79 494 struct ra_param *param = vparam;
c5ad4e79
SK
495
496 (void)scope; /* warning */
ed8b68ad 497
c5ad4e79
SK
498 if (if_index == param->ind)
499 {
500 if (IN6_IS_ADDR_LINKLOCAL(local))
c3a04081
SK
501 {
502 /* Can there be more than one LL address?
503 Select the one with the longest preferred time
504 if there is. */
505 if (preferred > param->link_pref_time)
506 {
507 param->link_pref_time = preferred;
508 param->link_local = *local;
509 }
510 }
c5ad4e79 511 else if (!IN6_IS_ADDR_LOOPBACK(local) &&
c5ad4e79
SK
512 !IN6_IS_ADDR_MULTICAST(local))
513 {
4c82efc5 514 int real_prefix = 0;
c8257540
SK
515 int do_slaac = 0;
516 int deprecate = 0;
3bc0d932 517 int constructed = 0;
7ea3d3fd 518 int adv_router = 0;
2fd5bc95 519 int off_link = 0;
c8257540 520 unsigned int time = 0xffffffff;
1e02a859
SK
521 struct dhcp_context *context;
522
1f776932 523 for (context = daemon->dhcp6; context; context = context->next)
ef1a94ab 524 if (!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
4c82efc5
VG
525 prefix <= context->prefix &&
526 is_same_net6(local, &context->start6, context->prefix) &&
527 is_same_net6(local, &context->end6, context->prefix))
c5ad4e79 528 {
ef1a94ab
SK
529 context->saved_valid = valid;
530
7ea3d3fd 531 if (context->flags & CONTEXT_RA)
30cd9666
SK
532 {
533 do_slaac = 1;
4723d49d 534 if (context->flags & CONTEXT_DHCP)
05e92e5a
SK
535 {
536 param->other = 1;
537 if (!(context->flags & CONTEXT_RA_STATELESS))
538 param->managed = 1;
539 }
30cd9666 540 }
884a6dfe 541 else
0010b474
SK
542 {
543 /* don't do RA for non-ra-only unless --enable-ra is set */
544 if (!option_bool(OPT_RA))
545 continue;
546 param->managed = 1;
30cd9666 547 param->other = 1;
0010b474 548 }
7ea3d3fd
SK
549
550 /* Configured to advertise router address, not prefix. See RFC 3775 7.2
551 In this case we do all addresses associated with a context,
552 hence the real_prefix setting here. */
553 if (context->flags & CONTEXT_RA_ROUTER)
554 {
555 adv_router = 1;
556 param->adv_router = 1;
557 real_prefix = context->prefix;
558 }
559
1ecbaaa3 560 /* find floor time, don't reduce below 3 * RA interval. */
c8257540 561 if (time > context->lease_time)
7f035f58
SK
562 {
563 time = context->lease_time;
c4cd95df
SK
564 if (time < ((unsigned int)(3 * param->adv_interval)))
565 time = 3 * param->adv_interval;
7f035f58
SK
566 }
567
c8257540
SK
568 if (context->flags & CONTEXT_DEPRECATE)
569 deprecate = 1;
3bc0d932
SK
570
571 if (context->flags & CONTEXT_CONSTRUCTED)
572 constructed = 1;
573
c8257540 574
18f0fb05
SK
575 /* collect dhcp-range tags */
576 if (context->netid.next == &context->netid && context->netid.net)
577 {
578 context->netid.next = param->tags;
579 param->tags = &context->netid;
580 }
581
5ae34bf3
SK
582 /* subsequent prefixes on the same interface
583 and subsequent instances of this prefix don't need timers.
584 Be careful not to find the same prefix twice with different
7ea3d3fd 585 addresses unless we're advertising the actual addresses. */
1e02a859
SK
586 if (!(context->flags & CONTEXT_RA_DONE))
587 {
5ae34bf3
SK
588 if (!param->first)
589 context->ra_time = 0;
1e02a859 590 context->flags |= CONTEXT_RA_DONE;
4c82efc5 591 real_prefix = context->prefix;
2fd5bc95 592 off_link = (context->flags & CONTEXT_RA_OFF_LINK);
1e02a859 593 }
5ae34bf3
SK
594
595 param->first = 0;
596 param->found_context = 1;
c5ad4e79 597 }
1f776932 598
ed8b68ad 599 /* configured time is ceiling */
3bc0d932 600 if (!constructed || valid > time)
ed8b68ad
SK
601 valid = time;
602
3bc0d932 603 if (flags & IFACE_DEPRECATED)
ed8b68ad 604 preferred = 0;
1e02a859 605
3bc0d932
SK
606 if (deprecate)
607 time = 0;
608
609 /* configured time is ceiling */
610 if (!constructed || preferred > time)
611 preferred = time;
c3a04081
SK
612
613 if (IN6_IS_ADDR_ULA(local))
55b42f6d 614 {
c3a04081
SK
615 if (preferred > param->ula_pref_time)
616 {
617 param->ula_pref_time = preferred;
618 param->ula = *local;
619 }
620 }
621 else
622 {
623 if (preferred > param->glob_pref_time)
624 {
625 param->glob_pref_time = preferred;
626 param->link_global = *local;
627 }
55b42f6d
SK
628 }
629
4c82efc5 630 if (real_prefix != 0)
c8257540 631 {
1e02a859
SK
632 struct prefix_opt *opt;
633
634 if ((opt = expand(sizeof(struct prefix_opt))))
635 {
5ef33279 636 /* zero net part of address */
7ea3d3fd
SK
637 if (!adv_router)
638 setaddr6part(local, addr6part(local) & ~((real_prefix == 64) ? (u64)-1LL : (1LLU << (128 - real_prefix)) - 1LLU));
5ef33279 639
1e02a859
SK
640 opt->type = ICMP6_OPT_PREFIX;
641 opt->len = 4;
4c82efc5 642 opt->prefix_len = real_prefix;
2fd5bc95
NJ
643 /* autonomous only if we're not doing dhcp, set
644 "on-link" unless "off-link" was specified */
645 opt->flags = (off_link ? 0 : 0x80);
7ea3d3fd
SK
646 if (do_slaac)
647 opt->flags |= 0x40;
648 if (adv_router)
649 opt->flags |= 0x20;
ed8b68ad
SK
650 opt->valid_lifetime = htonl(valid);
651 opt->preferred_lifetime = htonl(preferred);
5ef33279 652 opt->reserved = 0;
1e02a859 653 opt->prefix = *local;
1e02a859 654
5ef33279 655 inet_ntop(AF_INET6, local, daemon->addrbuff, ADDRSTRLEN);
8c0b73d3
KDB
656 if (!option_bool(OPT_QUIET_RA))
657 my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s", param->if_name, daemon->addrbuff);
1e02a859 658 }
c8257540 659 }
c5ad4e79
SK
660 }
661 }
662 return 1;
663}
664
665static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm)
666{
667 (void)type;
668
669 if (index == *((int *)parm))
670 {
671 /* size is in units of 8 octets and includes type and length (2 bytes)
672 add 7 to round up */
673 int len = (maclen + 9) >> 3;
674 unsigned char *p = expand(len << 3);
675 memset(p, 0, len << 3);
676 *p++ = ICMP6_OPT_SOURCE_MAC;
677 *p++ = len;
678 memcpy(p, mac, maclen);
679
680 return 0;
681 }
682
683 return 1;
684}
685
686time_t periodic_ra(time_t now)
687{
688 struct search_param param;
689 struct dhcp_context *context;
690 time_t next_event;
c4cd95df 691
c5ad4e79 692 param.now = now;
29d28dda 693 param.iface = 0;
c5ad4e79
SK
694
695 while (1)
696 {
697 /* find overdue events, and time of first future event */
1f776932 698 for (next_event = 0, context = daemon->dhcp6; context; context = context->next)
c5ad4e79
SK
699 if (context->ra_time != 0)
700 {
7dbe9814 701 if (difftime(context->ra_time, now) <= 0.0)
c5ad4e79
SK
702 break; /* overdue */
703
7dbe9814
SK
704 if (next_event == 0 || difftime(next_event, context->ra_time) > 0.0)
705 next_event = context->ra_time;
c5ad4e79
SK
706 }
707
708 /* none overdue */
709 if (!context)
710 break;
711
c4cd95df
SK
712 if ((context->flags & CONTEXT_OLD) &&
713 context->if_index != 0 &&
dd9d9ce5 714 indextoname(daemon->icmp6fd, context->if_index, param.name))
ef1a94ab
SK
715 {
716 /* A context for an old address. We'll not find the interface by
c4cd95df
SK
717 looking for addresses, but we know it anyway, since the context is
718 constructed */
ef1a94ab 719 param.iface = context->if_index;
c4cd95df 720 new_timeout(context, param.name, now);
ef1a94ab
SK
721 }
722 else if (iface_enumerate(AF_INET6, &param, iface_search))
723 /* There's a context overdue, but we can't find an interface
724 associated with it, because it's for a subnet we dont
725 have an interface on. Probably we're doing DHCP on
726 a remote subnet via a relay. Zero the timer, since we won't
727 ever be able to send ra's and satistfy it. */
c5ad4e79 728 context->ra_time = 0;
ef1a94ab
SK
729
730 if (param.iface != 0 &&
c4cd95df 731 iface_check(AF_LOCAL, NULL, param.name, NULL))
421594f8
SK
732 {
733 struct iname *tmp;
734 for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
c4cd95df 735 if (tmp->name && wildcard_match(tmp->name, param.name))
421594f8
SK
736 break;
737 if (!tmp)
c4cd95df 738 send_ra(now, param.iface, param.name, NULL);
421594f8
SK
739 }
740 }
c5ad4e79
SK
741 return next_event;
742}
421594f8 743
c5ad4e79 744static int iface_search(struct in6_addr *local, int prefix,
bad7b875 745 int scope, int if_index, int flags,
1f776932 746 int preferred, int valid, void *vparam)
c5ad4e79
SK
747{
748 struct search_param *param = vparam;
741c2952 749 struct dhcp_context *context;
c5ad4e79
SK
750
751 (void)scope;
1f776932
SK
752 (void)preferred;
753 (void)valid;
c5ad4e79 754
1f776932 755 for (context = daemon->dhcp6; context; context = context->next)
ef1a94ab 756 if (!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
4c82efc5
VG
757 prefix <= context->prefix &&
758 is_same_net6(local, &context->start6, context->prefix) &&
759 is_same_net6(local, &context->end6, context->prefix) &&
6e3dba3f
SK
760 context->ra_time != 0 &&
761 difftime(context->ra_time, param->now) <= 0.0)
762 {
763 /* found an interface that's overdue for RA determine new
764 timeout value and arrange for RA to be sent unless interface is
765 still doing DAD.*/
766
bad7b875 767 if (!(flags & IFACE_TENTATIVE))
6e3dba3f
SK
768 param->iface = if_index;
769
c4cd95df
SK
770 /* should never fail */
771 if (!indextoname(daemon->icmp6fd, if_index, param->name))
772 {
773 param->iface = 0;
774 return 0;
775 }
776
777 new_timeout(context, param->name, param->now);
6e3dba3f
SK
778
779 /* zero timers for other contexts on the same subnet, so they don't timeout
780 independently */
781 for (context = context->next; context; context = context->next)
4c82efc5
VG
782 if (prefix <= context->prefix &&
783 is_same_net6(local, &context->start6, context->prefix) &&
784 is_same_net6(local, &context->end6, context->prefix))
6e3dba3f
SK
785 context->ra_time = 0;
786
787 return 0; /* found, abort */
788 }
c5ad4e79
SK
789
790 return 1; /* keep searching */
791}
ef1a94ab 792
c4cd95df 793static void new_timeout(struct dhcp_context *context, char *iface_name, time_t now)
ef1a94ab 794{
c4cd95df 795 if (difftime(now, context->ra_short_period_start) < 60.0)
ef1a94ab
SK
796 /* range 5 - 20 */
797 context->ra_time = now + 5 + (rand16()/4400);
798 else
c4cd95df
SK
799 {
800 /* range 3/4 - 1 times MaxRtrAdvInterval */
801 unsigned int adv_interval = calc_interval(find_iface_param(iface_name));
802 context->ra_time = now + (3 * adv_interval)/4 + ((adv_interval * (unsigned int)rand16()) >> 18);
803 }
804}
805
806static struct ra_interface *find_iface_param(char *iface)
807{
808 struct ra_interface *ra;
809
810 for (ra = daemon->ra_interfaces; ra; ra = ra->next)
811 if (wildcard_match(ra->name, iface))
812 return ra;
813
814 return NULL;
815}
816
817static unsigned int calc_interval(struct ra_interface *ra)
818{
819 int interval = 600;
820
821 if (ra && ra->interval != 0)
822 {
823 interval = ra->interval;
824 if (interval > 1800)
825 interval = 1800;
826 else if (interval < 4)
827 interval = 4;
828 }
829
830 return (unsigned int)interval;
831}
832
833static unsigned int calc_lifetime(struct ra_interface *ra)
834{
835 int lifetime, interval = (int)calc_interval(ra);
836
837 if (!ra || ra->lifetime == -1) /* not specified */
838 lifetime = 3 * interval;
839 else
840 {
841 lifetime = ra->lifetime;
842 if (lifetime < interval && lifetime != 0)
843 lifetime = interval;
844 else if (lifetime > 9000)
845 lifetime = 9000;
846 }
847
848 return (unsigned int)lifetime;
849}
850
851static unsigned int calc_prio(struct ra_interface *ra)
852{
853 if (ra)
854 return ra->prio;
855
856 return 0;
ef1a94ab 857}
801ca9a7 858
c5ad4e79 859#endif