dnsmasq: v2.67test16 patch Sept.25th/2013.
[tomato.git] / release / src / router / dnsmasq / src / radv.c
blob3b499e45cda6a36f763ec3cb228792c93d8c0952
1 /* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
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.
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.
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/>.
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 */
23 #include "dnsmasq.h"
25 #ifdef HAVE_DHCP6
27 #include <netinet/icmp6.h>
29 struct ra_param {
30 time_t now;
31 int ind, managed, other, found_context, first;
32 char *if_name;
33 struct dhcp_netid *tags;
34 struct in6_addr link_local, link_global;
35 unsigned int pref_time;
38 struct search_param {
39 time_t now; int iface;
42 static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest);
43 static int add_prefixes(struct in6_addr *local, int prefix,
44 int scope, int if_index, int flags,
45 unsigned int preferred, unsigned int valid, void *vparam);
46 static int iface_search(struct in6_addr *local, int prefix,
47 int scope, int if_index, int flags,
48 int prefered, int valid, void *vparam);
49 static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm);
50 static void new_timeout(struct dhcp_context *context, time_t now);
52 static int hop_limit;
54 void ra_init(time_t now)
56 struct icmp6_filter filter;
57 int fd;
58 #if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
59 int class = IPTOS_CLASS_CS6;
60 #endif
61 int val = 255; /* radvd uses this value */
62 socklen_t len = sizeof(int);
63 struct dhcp_context *context;
65 /* ensure this is around even if we're not doing DHCPv6 */
66 expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet));
68 /* See if we're guessing SLAAC addresses, if so we need to recieve ping replies */
69 for (context = daemon->dhcp6; context; context = context->next)
70 if ((context->flags & CONTEXT_RA_NAME))
71 break;
73 /* Need ICMP6 socket for transmission for DHCPv6 even when not doing RA. */
75 ICMP6_FILTER_SETBLOCKALL(&filter);
76 if (daemon->doing_ra)
78 ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
79 if (context)
80 ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filter);
83 if ((fd = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1 ||
84 getsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hop_limit, &len) ||
85 #if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
86 setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &class, sizeof(class)) == -1 ||
87 #endif
88 !fix_fd(fd) ||
89 !set_ipv6pktinfo(fd) ||
90 setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val)) ||
91 setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val)) ||
92 setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter)) == -1)
93 die (_("cannot create ICMPv6 socket: %s"), NULL, EC_BADNET);
95 daemon->icmp6fd = fd;
97 if (daemon->doing_ra)
98 ra_start_unsolicted(now, NULL);
101 void ra_start_unsolicted(time_t now, struct dhcp_context *context)
103 /* init timers so that we do ra's for some/all soon. some ra_times will end up zeroed
104 if it's not appropriate to advertise those contexts.
105 This gets re-called on a netlink route-change to re-do the advertisement
106 and pick up new interfaces */
108 if (context)
109 context->ra_short_period_start = context->ra_time = now;
110 else
111 for (context = daemon->dhcp6; context; context = context->next)
112 if (!(context->flags & CONTEXT_TEMPLATE))
114 context->ra_time = now + (rand16()/13000); /* range 0 - 5 */
115 /* re-do frequently for a minute or so, in case the first gets lost. */
116 context->ra_short_period_start = now;
120 void icmp6_packet(time_t now)
122 char interface[IF_NAMESIZE+1];
123 ssize_t sz;
124 int if_index = 0;
125 struct cmsghdr *cmptr;
126 struct msghdr msg;
127 union {
128 struct cmsghdr align; /* this ensures alignment */
129 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
130 } control_u;
131 struct sockaddr_in6 from;
132 unsigned char *packet;
133 struct iname *tmp;
135 /* Note: use outpacket for input buffer */
136 msg.msg_control = control_u.control6;
137 msg.msg_controllen = sizeof(control_u);
138 msg.msg_flags = 0;
139 msg.msg_name = &from;
140 msg.msg_namelen = sizeof(from);
141 msg.msg_iov = &daemon->outpacket;
142 msg.msg_iovlen = 1;
144 if ((sz = recv_dhcp_packet(daemon->icmp6fd, &msg)) == -1 || sz < 8)
145 return;
147 packet = (unsigned char *)daemon->outpacket.iov_base;
149 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
150 if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
152 union {
153 unsigned char *c;
154 struct in6_pktinfo *p;
155 } p;
156 p.c = CMSG_DATA(cmptr);
158 if_index = p.p->ipi6_ifindex;
161 if (!indextoname(daemon->icmp6fd, if_index, interface))
162 return;
164 if (!iface_check(AF_LOCAL, NULL, interface, NULL))
165 return;
167 for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
168 if (tmp->name && wildcard_match(tmp->name, interface))
169 return;
171 if (packet[1] != 0)
172 return;
174 if (packet[0] == ICMP6_ECHO_REPLY)
175 lease_ping_reply(&from.sin6_addr, packet, interface);
176 else if (packet[0] == ND_ROUTER_SOLICIT)
178 char *mac = "";
180 /* look for link-layer address option for logging */
181 if (sz >= 16 && packet[8] == ICMP6_OPT_SOURCE_MAC && (packet[9] * 8) + 8 <= sz)
183 print_mac(daemon->namebuff, &packet[10], (packet[9] * 8) - 2);
184 mac = daemon->namebuff;
187 #ifdef HAVE_QUIET_DHCP
188 if (!option_bool(OPT_QUIET_RA))
189 #endif
190 my_syslog(MS_DHCP | LOG_INFO, "RTR-SOLICIT(%s) %s", interface, mac);
191 /* source address may not be valid in solicit request. */
192 send_ra(now, if_index, interface, !IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr) ? &from.sin6_addr : NULL);
196 static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest)
198 struct ra_packet *ra;
199 struct ra_param parm;
200 struct sockaddr_in6 addr;
201 struct dhcp_context *context, *tmp, **up;
202 struct dhcp_netid iface_id;
203 struct dhcp_opt *opt_cfg;
204 int done_dns = 0;
205 #ifdef HAVE_LINUX_NETWORK
206 FILE *f;
207 #endif
209 save_counter(0);
210 ra = expand(sizeof(struct ra_packet));
212 ra->type = ND_ROUTER_ADVERT;
213 ra->code = 0;
214 ra->hop_limit = hop_limit;
215 ra->flags = 0x00;
216 ra->lifetime = htons(RA_INTERVAL * 3); /* AdvDefaultLifetime * 3 */
217 ra->reachable_time = 0;
218 ra->retrans_time = 0;
220 parm.ind = iface;
221 parm.managed = 0;
222 parm.other = 0;
223 parm.found_context = 0;
224 parm.if_name = iface_name;
225 parm.first = 1;
226 parm.now = now;
227 parm.pref_time = 0;
229 /* set tag with name == interface */
230 iface_id.net = iface_name;
231 iface_id.next = NULL;
232 parm.tags = &iface_id;
234 for (context = daemon->dhcp6; context; context = context->next)
236 context->flags &= ~CONTEXT_RA_DONE;
237 context->netid.next = &context->netid;
240 if (!iface_enumerate(AF_INET6, &parm, add_prefixes))
241 return;
243 /* Look for constructed contexts associated with addresses which have gone,
244 and advertise them with preferred_time == 0 RFC 6204 4.3 L-13 */
245 for (up = &daemon->dhcp6, context = daemon->dhcp6; context; context = tmp)
247 tmp = context->next;
249 if (context->if_index == iface && (context->flags & CONTEXT_OLD))
251 unsigned int old = difftime(now, context->address_lost_time);
253 if (old > context->saved_valid)
255 /* We've advertised this enough, time to go */
256 *up = context->next;
257 free(context);
259 else
261 struct prefix_opt *opt;
262 struct in6_addr local = context->start6;
263 int do_slaac = 0;
265 parm.found_context = 1;
267 /* zero net part of address */
268 setaddr6part(&local, addr6part(&local) & ~((context->prefix == 64) ? (u64)-1LL : (1LLU << (128 - context->prefix)) - 1LLU));
270 if ((context->flags &
271 (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
272 do_slaac = 1;
274 if ((opt = expand(sizeof(struct prefix_opt))))
276 opt->type = ICMP6_OPT_PREFIX;
277 opt->len = 4;
278 opt->prefix_len = context->prefix;
279 /* autonomous only if we're not doing dhcp, always set "on-link" */
280 opt->flags = do_slaac ? 0xC0 : 0x80;
281 opt->valid_lifetime = htonl(context->saved_valid - old);
282 opt->preferred_lifetime = htonl(0);
283 opt->reserved = 0;
284 opt->prefix = local;
286 inet_ntop(AF_INET6, &local, daemon->addrbuff, ADDRSTRLEN);
287 my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s old prefix", iface_name, daemon->addrbuff);
290 up = &context->next;
293 else
294 up = &context->next;
297 if (!parm.found_context)
298 return;
300 #ifdef HAVE_LINUX_NETWORK
301 /* Note that IPv6 MTU is not necessarilly the same as the IPv4 MTU
302 available from SIOCGIFMTU */
303 sprintf(daemon->namebuff, "/proc/sys/net/ipv6/conf/%s/mtu", iface_name);
304 if ((f = fopen(daemon->namebuff, "r")))
306 if (fgets(daemon->namebuff, MAXDNAME, f))
308 put_opt6_char(ICMP6_OPT_MTU);
309 put_opt6_char(1);
310 put_opt6_short(0);
311 put_opt6_long(atoi(daemon->namebuff));
313 fclose(f);
315 #endif
317 iface_enumerate(AF_LOCAL, &iface, add_lla);
319 /* RDNSS, RFC 6106, use relevant DHCP6 options */
320 (void)option_filter(parm.tags, NULL, daemon->dhcp_opts6);
322 for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
324 int i;
326 /* netids match and not encapsulated? */
327 if (!(opt_cfg->flags & DHOPT_TAGOK))
328 continue;
330 if (opt_cfg->opt == OPTION6_DNS_SERVER)
332 struct in6_addr *a = (struct in6_addr *)opt_cfg->val;
334 done_dns = 1;
335 if (opt_cfg->len == 0)
336 continue;
338 put_opt6_char(ICMP6_OPT_RDNSS);
339 put_opt6_char((opt_cfg->len/8) + 1);
340 put_opt6_short(0);
341 put_opt6_long(RA_INTERVAL * 2); /* lifetime - twice RA retransmit */
342 /* zero means "self" */
343 for (i = 0; i < opt_cfg->len; i += IN6ADDRSZ, a++)
344 if (IN6_IS_ADDR_UNSPECIFIED(a))
345 put_opt6(&parm.link_global, IN6ADDRSZ);
346 else
347 put_opt6(a, IN6ADDRSZ);
350 if (opt_cfg->opt == OPTION6_DOMAIN_SEARCH && opt_cfg->len != 0)
352 int len = ((opt_cfg->len+7)/8);
354 put_opt6_char(ICMP6_OPT_DNSSL);
355 put_opt6_char(len + 1);
356 put_opt6_short(0);
357 put_opt6_long(RA_INTERVAL * 2); /* lifetime - twice RA retransmit */
358 put_opt6(opt_cfg->val, opt_cfg->len);
360 /* pad */
361 for (i = opt_cfg->len; i < len * 8; i++)
362 put_opt6_char(0);
366 if (daemon->port == NAMESERVER_PORT && !done_dns)
368 /* default == us, as long as we are supplying DNS service. */
369 put_opt6_char(ICMP6_OPT_RDNSS);
370 put_opt6_char(3);
371 put_opt6_short(0);
372 put_opt6_long(RA_INTERVAL * 2); /* lifetime - twice RA retransmit */
373 put_opt6(&parm.link_global, IN6ADDRSZ);
376 /* set managed bits unless we're providing only RA on this link */
377 if (parm.managed)
378 ra->flags |= 0x80; /* M flag, managed, */
379 if (parm.other)
380 ra->flags |= 0x40; /* O flag, other */
382 /* decide where we're sending */
383 memset(&addr, 0, sizeof(addr));
384 #ifdef HAVE_SOCKADDR_SA_LEN
385 addr.sin6_len = sizeof(struct sockaddr_in6);
386 #endif
387 addr.sin6_family = AF_INET6;
388 addr.sin6_port = htons(IPPROTO_ICMPV6);
389 if (dest)
391 addr.sin6_addr = *dest;
392 if (IN6_IS_ADDR_LINKLOCAL(dest) ||
393 IN6_IS_ADDR_MC_LINKLOCAL(dest))
394 addr.sin6_scope_id = iface;
396 else
397 inet_pton(AF_INET6, ALL_NODES, &addr.sin6_addr);
399 send_from(daemon->icmp6fd, 0, daemon->outpacket.iov_base, save_counter(0),
400 (union mysockaddr *)&addr, (struct all_addr *)&parm.link_local, iface);
404 static int add_prefixes(struct in6_addr *local, int prefix,
405 int scope, int if_index, int flags,
406 unsigned int preferred, unsigned int valid, void *vparam)
408 struct ra_param *param = vparam;
410 (void)scope; /* warning */
412 if (if_index == param->ind)
414 if (IN6_IS_ADDR_LINKLOCAL(local))
415 param->link_local = *local;
416 else if (!IN6_IS_ADDR_LOOPBACK(local) &&
417 !IN6_IS_ADDR_MULTICAST(local))
419 int do_prefix = 0;
420 int do_slaac = 0;
421 int deprecate = 0;
422 int constructed = 0;
423 unsigned int time = 0xffffffff;
424 struct dhcp_context *context;
426 for (context = daemon->dhcp6; context; context = context->next)
427 if (!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
428 prefix == context->prefix &&
429 is_same_net6(local, &context->start6, prefix) &&
430 is_same_net6(local, &context->end6, prefix))
432 context->saved_valid = valid;
434 if ((context->flags &
435 (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
437 do_slaac = 1;
438 if (context->flags & CONTEXT_DHCP)
440 param->other = 1;
441 if (!(context->flags & CONTEXT_RA_STATELESS))
442 param->managed = 1;
445 else
447 /* don't do RA for non-ra-only unless --enable-ra is set */
448 if (!option_bool(OPT_RA))
449 continue;
450 param->managed = 1;
451 param->other = 1;
454 /* find floor time, don't reduce below 3 * RA interval. */
455 if (time > context->lease_time)
457 time = context->lease_time;
458 if (time < ((unsigned int)(3 * RA_INTERVAL)))
459 time = 3 * RA_INTERVAL;
462 if (context->flags & CONTEXT_DEPRECATE)
463 deprecate = 1;
465 if (context->flags & CONTEXT_CONSTRUCTED)
466 constructed = 1;
469 /* collect dhcp-range tags */
470 if (context->netid.next == &context->netid && context->netid.net)
472 context->netid.next = param->tags;
473 param->tags = &context->netid;
476 /* subsequent prefixes on the same interface
477 and subsequent instances of this prefix don't need timers.
478 Be careful not to find the same prefix twice with different
479 addresses. */
480 if (!(context->flags & CONTEXT_RA_DONE))
482 if (!param->first)
483 context->ra_time = 0;
484 context->flags |= CONTEXT_RA_DONE;
485 do_prefix = 1;
488 param->first = 0;
489 param->found_context = 1;
492 /* configured time is ceiling */
493 if (!constructed || valid > time)
494 valid = time;
496 if (flags & IFACE_DEPRECATED)
497 preferred = 0;
499 if (deprecate)
500 time = 0;
502 /* configured time is ceiling */
503 if (!constructed || preferred > time)
504 preferred = time;
506 if (preferred > param->pref_time)
508 param->pref_time = preferred;
509 param->link_global = *local;
512 if (do_prefix)
514 struct prefix_opt *opt;
516 if ((opt = expand(sizeof(struct prefix_opt))))
518 /* zero net part of address */
519 setaddr6part(local, addr6part(local) & ~((prefix == 64) ? (u64)-1LL : (1LLU << (128 - prefix)) - 1LLU));
521 opt->type = ICMP6_OPT_PREFIX;
522 opt->len = 4;
523 opt->prefix_len = prefix;
524 /* autonomous only if we're not doing dhcp, always set "on-link" */
525 opt->flags = do_slaac ? 0xC0 : 0x80;
526 opt->valid_lifetime = htonl(valid);
527 opt->preferred_lifetime = htonl(preferred);
528 opt->reserved = 0;
529 opt->prefix = *local;
531 inet_ntop(AF_INET6, local, daemon->addrbuff, ADDRSTRLEN);
532 #ifdef HAVE_QUIET_DHCP
533 if (!option_bool(OPT_QUIET_RA))
534 #endif
535 my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s", param->if_name, daemon->addrbuff);
541 return 1;
544 static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm)
546 (void)type;
548 if (index == *((int *)parm))
550 /* size is in units of 8 octets and includes type and length (2 bytes)
551 add 7 to round up */
552 int len = (maclen + 9) >> 3;
553 unsigned char *p = expand(len << 3);
554 memset(p, 0, len << 3);
555 *p++ = ICMP6_OPT_SOURCE_MAC;
556 *p++ = len;
557 memcpy(p, mac, maclen);
559 return 0;
562 return 1;
565 time_t periodic_ra(time_t now)
567 struct search_param param;
568 struct dhcp_context *context;
569 time_t next_event;
570 char interface[IF_NAMESIZE+1];
572 param.now = now;
573 param.iface = 0;
575 while (1)
577 /* find overdue events, and time of first future event */
578 for (next_event = 0, context = daemon->dhcp6; context; context = context->next)
579 if (context->ra_time != 0)
581 if (difftime(context->ra_time, now) <= 0.0)
582 break; /* overdue */
584 if (next_event == 0 || difftime(next_event, context->ra_time) > 0.0)
585 next_event = context->ra_time;
588 /* none overdue */
589 if (!context)
590 break;
592 if ((context->flags & CONTEXT_OLD) && context->if_index != 0)
594 /* A context for an old address. We'll not find the interface by
595 looking for addresses, but we know it anyway, as long as we
596 sent at least one RA whilst the address was current. */
597 param.iface = context->if_index;
598 new_timeout(context, now);
600 else if (iface_enumerate(AF_INET6, &param, iface_search))
601 /* There's a context overdue, but we can't find an interface
602 associated with it, because it's for a subnet we dont
603 have an interface on. Probably we're doing DHCP on
604 a remote subnet via a relay. Zero the timer, since we won't
605 ever be able to send ra's and satistfy it. */
606 context->ra_time = 0;
608 if (param.iface != 0 &&
609 indextoname(daemon->icmp6fd, param.iface, interface) &&
610 iface_check(AF_LOCAL, NULL, interface, NULL))
612 struct iname *tmp;
613 for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
614 if (tmp->name && wildcard_match(tmp->name, interface))
615 break;
616 if (!tmp)
617 send_ra(now, param.iface, interface, NULL);
620 return next_event;
623 static int iface_search(struct in6_addr *local, int prefix,
624 int scope, int if_index, int flags,
625 int preferred, int valid, void *vparam)
627 struct search_param *param = vparam;
628 struct dhcp_context *context;
630 (void)scope;
631 (void)preferred;
632 (void)valid;
634 for (context = daemon->dhcp6; context; context = context->next)
635 if (!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
636 prefix == context->prefix &&
637 is_same_net6(local, &context->start6, prefix) &&
638 is_same_net6(local, &context->end6, prefix) &&
639 context->ra_time != 0 &&
640 difftime(context->ra_time, param->now) <= 0.0)
642 /* found an interface that's overdue for RA determine new
643 timeout value and arrange for RA to be sent unless interface is
644 still doing DAD.*/
646 if (!(flags & IFACE_TENTATIVE))
647 param->iface = if_index;
649 new_timeout(context, param->now);
651 /* zero timers for other contexts on the same subnet, so they don't timeout
652 independently */
653 for (context = context->next; context; context = context->next)
654 if (prefix == context->prefix &&
655 is_same_net6(local, &context->start6, prefix) &&
656 is_same_net6(local, &context->end6, prefix))
657 context->ra_time = 0;
659 return 0; /* found, abort */
662 return 1; /* keep searching */
665 static void new_timeout(struct dhcp_context *context, time_t now)
667 if (difftime(now, context->ra_short_period_start) < 60.0 || option_bool(OPT_FAST_RA))
668 /* range 5 - 20 */
669 context->ra_time = now + 5 + (rand16()/4400);
670 else
671 /* range 3/4 - 1 times RA_INTERVAL */
672 context->ra_time = now + (3 * RA_INTERVAL)/4 + ((RA_INTERVAL * (unsigned int)rand16()) >> 18);
675 #endif