]> git.ipfire.org Git - people/ms/dnsmasq.git/blame - src/radv.c
Add --dnssec-timestamp option and facility.
[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;
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);
8c0b73d3
KDB
324 if (!option_bool(OPT_QUIET_RA))
325 my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s old prefix", iface_name, daemon->addrbuff);
ef1a94ab
SK
326 }
327
328 up = &context->next;
329 }
330 }
331 else
332 up = &context->next;
333 }
334
44522920
SK
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
7ea3d3fd
SK
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
3b43646a
SK
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")))
c5ad4e79 359 {
3b43646a
SK
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);
c5ad4e79 368 }
3b43646a 369#endif
c5ad4e79
SK
370
371 iface_enumerate(AF_LOCAL, &iface, add_lla);
18f0fb05
SK
372
373 /* RDNSS, RFC 6106, use relevant DHCP6 options */
374 (void)option_filter(parm.tags, NULL, daemon->dhcp_opts6);
c5ad4e79 375
18f0fb05
SK
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 {
c3a04081
SK
386 struct in6_addr *a;
387 int len;
388
18f0fb05 389 done_dns = 1;
c3a04081
SK
390
391 if (opt_cfg->len == 0)
806cf787 392 continue;
18f0fb05 393
c3a04081
SK
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 }
18f0fb05
SK
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);
c3a04081 437 put_opt6_long(min_pref_time);
18f0fb05
SK
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
c3a04081 446 if (daemon->port == NAMESERVER_PORT && !done_dns && parm.link_pref_time != 0)
18f0fb05 447 {
ab915f83 448 /* default == us, as long as we are supplying DNS service. */
18f0fb05
SK
449 put_opt6_char(ICMP6_OPT_RDNSS);
450 put_opt6_char(3);
451 put_opt6_short(0);
c3a04081 452 put_opt6_long(min_pref_time);
806cf787 453 put_opt6(&parm.link_local, IN6ADDRSZ);
18f0fb05 454 }
c5ad4e79
SK
455
456 /* set managed bits unless we're providing only RA on this link */
457 if (parm.managed)
30cd9666
SK
458 ra->flags |= 0x80; /* M flag, managed, */
459 if (parm.other)
460 ra->flags |= 0x40; /* O flag, other */
461
c5ad4e79
SK
462 /* decide where we're sending */
463 memset(&addr, 0, sizeof(addr));
22d904db
SK
464#ifdef HAVE_SOCKADDR_SA_LEN
465 addr.sin6_len = sizeof(struct sockaddr_in6);
466#endif
c5ad4e79
SK
467 addr.sin6_family = AF_INET6;
468 addr.sin6_port = htons(IPPROTO_ICMPV6);
469 if (dest)
470 {
353ae4d2 471 addr.sin6_addr = *dest;
c5ad4e79
SK
472 if (IN6_IS_ADDR_LINKLOCAL(dest) ||
473 IN6_IS_ADDR_MC_LINKLOCAL(dest))
474 addr.sin6_scope_id = iface;
475 }
476 else
8f3194f7
SK
477 {
478 inet_pton(AF_INET6, ALL_NODES, &addr.sin6_addr);
479 setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &iface, sizeof(iface));
480 }
22d904db 481
8f3194f7
SK
482 while (sendto(daemon->icmp6fd, daemon->outpacket.iov_base, save_counter(0), 0,
483 (struct sockaddr *)&addr, sizeof(addr)) == -1 && retry_send());
c5ad4e79
SK
484
485}
486
487static int add_prefixes(struct in6_addr *local, int prefix,
bad7b875 488 int scope, int if_index, int flags,
55b42f6d 489 unsigned int preferred, unsigned int valid, void *vparam)
c5ad4e79 490{
c5ad4e79 491 struct ra_param *param = vparam;
c5ad4e79
SK
492
493 (void)scope; /* warning */
ed8b68ad 494
c5ad4e79
SK
495 if (if_index == param->ind)
496 {
497 if (IN6_IS_ADDR_LINKLOCAL(local))
c3a04081
SK
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 }
c5ad4e79 508 else if (!IN6_IS_ADDR_LOOPBACK(local) &&
c5ad4e79
SK
509 !IN6_IS_ADDR_MULTICAST(local))
510 {
4c82efc5 511 int real_prefix = 0;
c8257540
SK
512 int do_slaac = 0;
513 int deprecate = 0;
3bc0d932 514 int constructed = 0;
7ea3d3fd 515 int adv_router = 0;
c8257540 516 unsigned int time = 0xffffffff;
1e02a859
SK
517 struct dhcp_context *context;
518
1f776932 519 for (context = daemon->dhcp6; context; context = context->next)
ef1a94ab 520 if (!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
4c82efc5
VG
521 prefix <= context->prefix &&
522 is_same_net6(local, &context->start6, context->prefix) &&
523 is_same_net6(local, &context->end6, context->prefix))
c5ad4e79 524 {
ef1a94ab
SK
525 context->saved_valid = valid;
526
7ea3d3fd 527 if (context->flags & CONTEXT_RA)
30cd9666
SK
528 {
529 do_slaac = 1;
4723d49d 530 if (context->flags & CONTEXT_DHCP)
05e92e5a
SK
531 {
532 param->other = 1;
533 if (!(context->flags & CONTEXT_RA_STATELESS))
534 param->managed = 1;
535 }
30cd9666 536 }
884a6dfe 537 else
0010b474
SK
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;
30cd9666 543 param->other = 1;
0010b474 544 }
7ea3d3fd
SK
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
1ecbaaa3 556 /* find floor time, don't reduce below 3 * RA interval. */
c8257540 557 if (time > context->lease_time)
7f035f58
SK
558 {
559 time = context->lease_time;
c4cd95df
SK
560 if (time < ((unsigned int)(3 * param->adv_interval)))
561 time = 3 * param->adv_interval;
7f035f58
SK
562 }
563
c8257540
SK
564 if (context->flags & CONTEXT_DEPRECATE)
565 deprecate = 1;
3bc0d932
SK
566
567 if (context->flags & CONTEXT_CONSTRUCTED)
568 constructed = 1;
569
c8257540 570
18f0fb05
SK
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
5ae34bf3
SK
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
7ea3d3fd 581 addresses unless we're advertising the actual addresses. */
1e02a859
SK
582 if (!(context->flags & CONTEXT_RA_DONE))
583 {
5ae34bf3
SK
584 if (!param->first)
585 context->ra_time = 0;
1e02a859 586 context->flags |= CONTEXT_RA_DONE;
4c82efc5 587 real_prefix = context->prefix;
1e02a859 588 }
5ae34bf3
SK
589
590 param->first = 0;
591 param->found_context = 1;
c5ad4e79 592 }
1f776932 593
ed8b68ad 594 /* configured time is ceiling */
3bc0d932 595 if (!constructed || valid > time)
ed8b68ad
SK
596 valid = time;
597
3bc0d932 598 if (flags & IFACE_DEPRECATED)
ed8b68ad 599 preferred = 0;
1e02a859 600
3bc0d932
SK
601 if (deprecate)
602 time = 0;
603
604 /* configured time is ceiling */
605 if (!constructed || preferred > time)
606 preferred = time;
c3a04081
SK
607
608 if (IN6_IS_ADDR_ULA(local))
55b42f6d 609 {
c3a04081
SK
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 }
55b42f6d
SK
623 }
624
4c82efc5 625 if (real_prefix != 0)
c8257540 626 {
1e02a859
SK
627 struct prefix_opt *opt;
628
629 if ((opt = expand(sizeof(struct prefix_opt))))
630 {
5ef33279 631 /* zero net part of address */
7ea3d3fd
SK
632 if (!adv_router)
633 setaddr6part(local, addr6part(local) & ~((real_prefix == 64) ? (u64)-1LL : (1LLU << (128 - real_prefix)) - 1LLU));
5ef33279 634
1e02a859
SK
635 opt->type = ICMP6_OPT_PREFIX;
636 opt->len = 4;
4c82efc5 637 opt->prefix_len = real_prefix;
fd05f127 638 /* autonomous only if we're not doing dhcp, always set "on-link" */
7ea3d3fd
SK
639 opt->flags = 0x80;
640 if (do_slaac)
641 opt->flags |= 0x40;
642 if (adv_router)
643 opt->flags |= 0x20;
ed8b68ad
SK
644 opt->valid_lifetime = htonl(valid);
645 opt->preferred_lifetime = htonl(preferred);
5ef33279 646 opt->reserved = 0;
1e02a859 647 opt->prefix = *local;
1e02a859 648
5ef33279 649 inet_ntop(AF_INET6, local, daemon->addrbuff, ADDRSTRLEN);
8c0b73d3
KDB
650 if (!option_bool(OPT_QUIET_RA))
651 my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s", param->if_name, daemon->addrbuff);
1e02a859 652 }
c8257540 653 }
c5ad4e79
SK
654 }
655 }
656 return 1;
657}
658
659static 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
680time_t periodic_ra(time_t now)
681{
682 struct search_param param;
683 struct dhcp_context *context;
684 time_t next_event;
c4cd95df 685
c5ad4e79 686 param.now = now;
29d28dda 687 param.iface = 0;
c5ad4e79
SK
688
689 while (1)
690 {
691 /* find overdue events, and time of first future event */
1f776932 692 for (next_event = 0, context = daemon->dhcp6; context; context = context->next)
c5ad4e79
SK
693 if (context->ra_time != 0)
694 {
7dbe9814 695 if (difftime(context->ra_time, now) <= 0.0)
c5ad4e79
SK
696 break; /* overdue */
697
7dbe9814
SK
698 if (next_event == 0 || difftime(next_event, context->ra_time) > 0.0)
699 next_event = context->ra_time;
c5ad4e79
SK
700 }
701
702 /* none overdue */
703 if (!context)
704 break;
705
c4cd95df
SK
706 if ((context->flags & CONTEXT_OLD) &&
707 context->if_index != 0 &&
dd9d9ce5 708 indextoname(daemon->icmp6fd, context->if_index, param.name))
ef1a94ab
SK
709 {
710 /* A context for an old address. We'll not find the interface by
c4cd95df
SK
711 looking for addresses, but we know it anyway, since the context is
712 constructed */
ef1a94ab 713 param.iface = context->if_index;
c4cd95df 714 new_timeout(context, param.name, now);
ef1a94ab
SK
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. */
c5ad4e79 722 context->ra_time = 0;
ef1a94ab
SK
723
724 if (param.iface != 0 &&
c4cd95df 725 iface_check(AF_LOCAL, NULL, param.name, NULL))
421594f8
SK
726 {
727 struct iname *tmp;
728 for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
c4cd95df 729 if (tmp->name && wildcard_match(tmp->name, param.name))
421594f8
SK
730 break;
731 if (!tmp)
c4cd95df 732 send_ra(now, param.iface, param.name, NULL);
421594f8
SK
733 }
734 }
c5ad4e79
SK
735 return next_event;
736}
421594f8 737
c5ad4e79 738static int iface_search(struct in6_addr *local, int prefix,
bad7b875 739 int scope, int if_index, int flags,
1f776932 740 int preferred, int valid, void *vparam)
c5ad4e79
SK
741{
742 struct search_param *param = vparam;
741c2952 743 struct dhcp_context *context;
c5ad4e79
SK
744
745 (void)scope;
1f776932
SK
746 (void)preferred;
747 (void)valid;
c5ad4e79 748
1f776932 749 for (context = daemon->dhcp6; context; context = context->next)
ef1a94ab 750 if (!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
4c82efc5
VG
751 prefix <= context->prefix &&
752 is_same_net6(local, &context->start6, context->prefix) &&
753 is_same_net6(local, &context->end6, context->prefix) &&
6e3dba3f
SK
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
bad7b875 761 if (!(flags & IFACE_TENTATIVE))
6e3dba3f
SK
762 param->iface = if_index;
763
c4cd95df
SK
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);
6e3dba3f
SK
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)
4c82efc5
VG
776 if (prefix <= context->prefix &&
777 is_same_net6(local, &context->start6, context->prefix) &&
778 is_same_net6(local, &context->end6, context->prefix))
6e3dba3f
SK
779 context->ra_time = 0;
780
781 return 0; /* found, abort */
782 }
c5ad4e79
SK
783
784 return 1; /* keep searching */
785}
ef1a94ab 786
c4cd95df 787static void new_timeout(struct dhcp_context *context, char *iface_name, time_t now)
ef1a94ab 788{
c4cd95df 789 if (difftime(now, context->ra_short_period_start) < 60.0)
ef1a94ab
SK
790 /* range 5 - 20 */
791 context->ra_time = now + 5 + (rand16()/4400);
792 else
c4cd95df
SK
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
800static 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
811static 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
827static 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
845static unsigned int calc_prio(struct ra_interface *ra)
846{
847 if (ra)
848 return ra->prio;
849
850 return 0;
ef1a94ab 851}
801ca9a7 852
c5ad4e79 853#endif