]>
git.ipfire.org Git - people/ms/dnsmasq.git/blob - src/radv.c
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 */
27 #include <netinet/icmp6.h>
31 int ind
, managed
, other
, found_context
, first
;
33 struct dhcp_netid
*tags
;
34 struct in6_addr link_local
, link_global
;
35 unsigned int pref_time
, adv_interval
;
39 time_t now
; int iface
;
40 char name
[IF_NAMESIZE
+1];
43 static void send_ra(time_t now
, int iface
, char *iface_name
, struct in6_addr
*dest
);
44 static int add_prefixes(struct in6_addr
*local
, int prefix
,
45 int scope
, int if_index
, int flags
,
46 unsigned int preferred
, unsigned int valid
, void *vparam
);
47 static int iface_search(struct in6_addr
*local
, int prefix
,
48 int scope
, int if_index
, int flags
,
49 int prefered
, int valid
, void *vparam
);
50 static int add_lla(int index
, unsigned int type
, char *mac
, size_t maclen
, void *parm
);
51 static void new_timeout(struct dhcp_context
*context
, char *iface_name
, time_t now
);
52 static unsigned int calc_lifetime(struct ra_interface
*ra
);
53 static unsigned int calc_interval(struct ra_interface
*ra
);
54 static unsigned int calc_prio(struct ra_interface
*ra
);
55 static struct ra_interface
*find_iface_param(char *iface
);
59 void ra_init(time_t now
)
61 struct icmp6_filter filter
;
63 #if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
64 int class = IPTOS_CLASS_CS6
;
66 int val
= 255; /* radvd uses this value */
67 socklen_t len
= sizeof(int);
68 struct dhcp_context
*context
;
70 /* ensure this is around even if we're not doing DHCPv6 */
71 expand_buf(&daemon
->outpacket
, sizeof(struct dhcp_packet
));
73 /* See if we're guessing SLAAC addresses, if so we need to recieve ping replies */
74 for (context
= daemon
->dhcp6
; context
; context
= context
->next
)
75 if ((context
->flags
& CONTEXT_RA_NAME
))
78 /* Need ICMP6 socket for transmission for DHCPv6 even when not doing RA. */
80 ICMP6_FILTER_SETBLOCKALL(&filter
);
83 ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT
, &filter
);
85 ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY
, &filter
);
88 if ((fd
= socket(PF_INET6
, SOCK_RAW
, IPPROTO_ICMPV6
)) == -1 ||
89 getsockopt(fd
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &hop_limit
, &len
) ||
90 #if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
91 setsockopt(fd
, IPPROTO_IPV6
, IPV6_TCLASS
, &class, sizeof(class)) == -1 ||
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
);
100 daemon
->icmp6fd
= fd
;
102 if (daemon
->doing_ra
)
103 ra_start_unsolicted(now
, NULL
);
106 void ra_start_unsolicted(time_t now
, struct dhcp_context
*context
)
108 /* init timers so that we do ra's for some/all soon. some ra_times will end up zeroed
109 if it's not appropriate to advertise those contexts.
110 This gets re-called on a netlink route-change to re-do the advertisement
111 and pick up new interfaces */
114 context
->ra_short_period_start
= context
->ra_time
= now
;
116 for (context
= daemon
->dhcp6
; context
; context
= context
->next
)
117 if (!(context
->flags
& CONTEXT_TEMPLATE
))
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
;
125 void icmp6_packet(time_t now
)
127 char interface
[IF_NAMESIZE
+1];
130 struct cmsghdr
*cmptr
;
133 struct cmsghdr align
; /* this ensures alignment */
134 char control6
[CMSG_SPACE(sizeof(struct in6_pktinfo
))];
136 struct sockaddr_in6 from
;
137 unsigned char *packet
;
140 /* Note: use outpacket for input buffer */
141 msg
.msg_control
= control_u
.control6
;
142 msg
.msg_controllen
= sizeof(control_u
);
144 msg
.msg_name
= &from
;
145 msg
.msg_namelen
= sizeof(from
);
146 msg
.msg_iov
= &daemon
->outpacket
;
149 if ((sz
= recv_dhcp_packet(daemon
->icmp6fd
, &msg
)) == -1 || sz
< 8)
152 packet
= (unsigned char *)daemon
->outpacket
.iov_base
;
154 for (cmptr
= CMSG_FIRSTHDR(&msg
); cmptr
; cmptr
= CMSG_NXTHDR(&msg
, cmptr
))
155 if (cmptr
->cmsg_level
== IPPROTO_IPV6
&& cmptr
->cmsg_type
== daemon
->v6pktinfo
)
159 struct in6_pktinfo
*p
;
161 p
.c
= CMSG_DATA(cmptr
);
163 if_index
= p
.p
->ipi6_ifindex
;
166 if (!indextoname(daemon
->icmp6fd
, if_index
, interface
))
169 if (!iface_check(AF_LOCAL
, NULL
, interface
, NULL
))
172 for (tmp
= daemon
->dhcp_except
; tmp
; tmp
= tmp
->next
)
173 if (tmp
->name
&& wildcard_match(tmp
->name
, interface
))
179 if (packet
[0] == ICMP6_ECHO_REPLY
)
180 lease_ping_reply(&from
.sin6_addr
, packet
, interface
);
181 else if (packet
[0] == ND_ROUTER_SOLICIT
)
185 /* look for link-layer address option for logging */
186 if (sz
>= 16 && packet
[8] == ICMP6_OPT_SOURCE_MAC
&& (packet
[9] * 8) + 8 <= sz
)
188 print_mac(daemon
->namebuff
, &packet
[10], (packet
[9] * 8) - 2);
189 mac
= daemon
->namebuff
;
192 if (!option_bool(OPT_QUIET_RA
))
193 my_syslog(MS_DHCP
| LOG_INFO
, "RTR-SOLICIT(%s) %s", interface
, mac
);
194 /* source address may not be valid in solicit request. */
195 send_ra(now
, if_index
, interface
, !IN6_IS_ADDR_UNSPECIFIED(&from
.sin6_addr
) ? &from
.sin6_addr
: NULL
);
199 static void send_ra(time_t now
, int iface
, char *iface_name
, struct in6_addr
*dest
)
201 struct ra_packet
*ra
;
202 struct ra_param parm
;
203 struct sockaddr_in6 addr
;
204 struct dhcp_context
*context
, *tmp
, **up
;
205 struct dhcp_netid iface_id
;
206 struct dhcp_opt
*opt_cfg
;
207 struct ra_interface
*ra_param
= find_iface_param(iface_name
);
209 #ifdef HAVE_LINUX_NETWORK
214 ra
= expand(sizeof(struct ra_packet
));
216 ra
->type
= ND_ROUTER_ADVERT
;
218 ra
->hop_limit
= hop_limit
;
219 ra
->flags
= calc_prio(ra_param
);
220 ra
->lifetime
= htons(calc_lifetime(ra_param
));
221 ra
->reachable_time
= 0;
222 ra
->retrans_time
= 0;
227 parm
.found_context
= 0;
228 parm
.if_name
= iface_name
;
232 parm
.adv_interval
= calc_interval(ra_param
);
234 /* set tag with name == interface */
235 iface_id
.net
= iface_name
;
236 iface_id
.next
= NULL
;
237 parm
.tags
= &iface_id
;
239 for (context
= daemon
->dhcp6
; context
; context
= context
->next
)
241 context
->flags
&= ~CONTEXT_RA_DONE
;
242 context
->netid
.next
= &context
->netid
;
245 if (!iface_enumerate(AF_INET6
, &parm
, add_prefixes
))
248 /* Look for constructed contexts associated with addresses which have gone,
249 and advertise them with preferred_time == 0 RFC 6204 4.3 L-13 */
250 for (up
= &daemon
->dhcp6
, context
= daemon
->dhcp6
; context
; context
= tmp
)
254 if (context
->if_index
== iface
&& (context
->flags
& CONTEXT_OLD
))
256 unsigned int old
= difftime(now
, context
->address_lost_time
);
258 if (old
> context
->saved_valid
)
260 /* We've advertised this enough, time to go */
266 struct prefix_opt
*opt
;
267 struct in6_addr local
= context
->start6
;
270 parm
.found_context
= 1;
272 /* zero net part of address */
273 setaddr6part(&local
, addr6part(&local
) & ~((context
->prefix
== 64) ? (u64
)-1LL : (1LLU << (128 - context
->prefix
)) - 1LLU));
275 if ((context
->flags
&
276 (CONTEXT_RA_ONLY
| CONTEXT_RA_NAME
| CONTEXT_RA_STATELESS
)))
279 if ((opt
= expand(sizeof(struct prefix_opt
))))
281 opt
->type
= ICMP6_OPT_PREFIX
;
283 opt
->prefix_len
= context
->prefix
;
284 /* autonomous only if we're not doing dhcp, always set "on-link" */
285 opt
->flags
= do_slaac
? 0xC0 : 0x80;
286 opt
->valid_lifetime
= htonl(context
->saved_valid
- old
);
287 opt
->preferred_lifetime
= htonl(0);
291 inet_ntop(AF_INET6
, &local
, daemon
->addrbuff
, ADDRSTRLEN
);
292 if (!option_bool(OPT_QUIET_RA
))
293 my_syslog(MS_DHCP
| LOG_INFO
, "RTR-ADVERT(%s) %s old prefix", iface_name
, daemon
->addrbuff
);
303 if (!parm
.found_context
)
306 #ifdef HAVE_LINUX_NETWORK
307 /* Note that IPv6 MTU is not necessarilly the same as the IPv4 MTU
308 available from SIOCGIFMTU */
309 sprintf(daemon
->namebuff
, "/proc/sys/net/ipv6/conf/%s/mtu", iface_name
);
310 if ((f
= fopen(daemon
->namebuff
, "r")))
312 if (fgets(daemon
->namebuff
, MAXDNAME
, f
))
314 put_opt6_char(ICMP6_OPT_MTU
);
317 put_opt6_long(atoi(daemon
->namebuff
));
323 iface_enumerate(AF_LOCAL
, &iface
, add_lla
);
325 /* RDNSS, RFC 6106, use relevant DHCP6 options */
326 (void)option_filter(parm
.tags
, NULL
, daemon
->dhcp_opts6
);
328 for (opt_cfg
= daemon
->dhcp_opts6
; opt_cfg
; opt_cfg
= opt_cfg
->next
)
332 /* netids match and not encapsulated? */
333 if (!(opt_cfg
->flags
& DHOPT_TAGOK
))
336 if (opt_cfg
->opt
== OPTION6_DNS_SERVER
)
338 struct in6_addr
*a
= (struct in6_addr
*)opt_cfg
->val
;
341 if (opt_cfg
->len
== 0 || (IN6_IS_ADDR_UNSPECIFIED(a
) && parm
.pref_time
!= 0))
344 put_opt6_char(ICMP6_OPT_RDNSS
);
345 put_opt6_char((opt_cfg
->len
/8) + 1);
347 put_opt6_long(parm
.pref_time
);
348 /* zero means "self" */
349 for (i
= 0; i
< opt_cfg
->len
; i
+= IN6ADDRSZ
, a
++)
350 if (IN6_IS_ADDR_UNSPECIFIED(a
))
351 put_opt6(&parm
.link_global
, IN6ADDRSZ
);
353 put_opt6(a
, IN6ADDRSZ
);
356 if (opt_cfg
->opt
== OPTION6_DOMAIN_SEARCH
&& opt_cfg
->len
!= 0)
358 int len
= ((opt_cfg
->len
+7)/8);
360 put_opt6_char(ICMP6_OPT_DNSSL
);
361 put_opt6_char(len
+ 1);
363 put_opt6_long(parm
.pref_time
);
364 put_opt6(opt_cfg
->val
, opt_cfg
->len
);
367 for (i
= opt_cfg
->len
; i
< len
* 8; i
++)
372 if (daemon
->port
== NAMESERVER_PORT
&& !done_dns
&& parm
.pref_time
!= 0)
374 /* default == us, as long as we are supplying DNS service. */
375 put_opt6_char(ICMP6_OPT_RDNSS
);
378 put_opt6_long(parm
.pref_time
);
379 put_opt6(&parm
.link_local
, IN6ADDRSZ
);
382 /* set managed bits unless we're providing only RA on this link */
384 ra
->flags
|= 0x80; /* M flag, managed, */
386 ra
->flags
|= 0x40; /* O flag, other */
388 /* decide where we're sending */
389 memset(&addr
, 0, sizeof(addr
));
390 #ifdef HAVE_SOCKADDR_SA_LEN
391 addr
.sin6_len
= sizeof(struct sockaddr_in6
);
393 addr
.sin6_family
= AF_INET6
;
394 addr
.sin6_port
= htons(IPPROTO_ICMPV6
);
397 addr
.sin6_addr
= *dest
;
398 if (IN6_IS_ADDR_LINKLOCAL(dest
) ||
399 IN6_IS_ADDR_MC_LINKLOCAL(dest
))
400 addr
.sin6_scope_id
= iface
;
404 inet_pton(AF_INET6
, ALL_NODES
, &addr
.sin6_addr
);
405 setsockopt(daemon
->icmp6fd
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, &iface
, sizeof(iface
));
408 while (sendto(daemon
->icmp6fd
, daemon
->outpacket
.iov_base
, save_counter(0), 0,
409 (struct sockaddr
*)&addr
, sizeof(addr
)) == -1 && retry_send());
413 static int add_prefixes(struct in6_addr
*local
, int prefix
,
414 int scope
, int if_index
, int flags
,
415 unsigned int preferred
, unsigned int valid
, void *vparam
)
417 struct ra_param
*param
= vparam
;
419 (void)scope
; /* warning */
421 if (if_index
== param
->ind
)
423 if (IN6_IS_ADDR_LINKLOCAL(local
))
424 param
->link_local
= *local
;
425 else if (!IN6_IS_ADDR_LOOPBACK(local
) &&
426 !IN6_IS_ADDR_MULTICAST(local
))
432 unsigned int time
= 0xffffffff;
433 struct dhcp_context
*context
;
435 for (context
= daemon
->dhcp6
; context
; context
= context
->next
)
436 if (!(context
->flags
& (CONTEXT_TEMPLATE
| CONTEXT_OLD
)) &&
437 prefix
== context
->prefix
&&
438 is_same_net6(local
, &context
->start6
, prefix
) &&
439 is_same_net6(local
, &context
->end6
, prefix
))
441 context
->saved_valid
= valid
;
443 if ((context
->flags
&
444 (CONTEXT_RA_ONLY
| CONTEXT_RA_NAME
| CONTEXT_RA_STATELESS
)))
447 if (context
->flags
& CONTEXT_DHCP
)
450 if (!(context
->flags
& CONTEXT_RA_STATELESS
))
456 /* don't do RA for non-ra-only unless --enable-ra is set */
457 if (!option_bool(OPT_RA
))
463 /* find floor time, don't reduce below 3 * RA interval. */
464 if (time
> context
->lease_time
)
466 time
= context
->lease_time
;
467 if (time
< ((unsigned int)(3 * param
->adv_interval
)))
468 time
= 3 * param
->adv_interval
;
471 if (context
->flags
& CONTEXT_DEPRECATE
)
474 if (context
->flags
& CONTEXT_CONSTRUCTED
)
478 /* collect dhcp-range tags */
479 if (context
->netid
.next
== &context
->netid
&& context
->netid
.net
)
481 context
->netid
.next
= param
->tags
;
482 param
->tags
= &context
->netid
;
485 /* subsequent prefixes on the same interface
486 and subsequent instances of this prefix don't need timers.
487 Be careful not to find the same prefix twice with different
489 if (!(context
->flags
& CONTEXT_RA_DONE
))
492 context
->ra_time
= 0;
493 context
->flags
|= CONTEXT_RA_DONE
;
498 param
->found_context
= 1;
501 /* configured time is ceiling */
502 if (!constructed
|| valid
> time
)
505 if (flags
& IFACE_DEPRECATED
)
511 /* configured time is ceiling */
512 if (!constructed
|| preferred
> time
)
515 if (preferred
> param
->pref_time
)
517 param
->pref_time
= preferred
;
518 param
->link_global
= *local
;
523 struct prefix_opt
*opt
;
525 if ((opt
= expand(sizeof(struct prefix_opt
))))
527 /* zero net part of address */
528 setaddr6part(local
, addr6part(local
) & ~((prefix
== 64) ? (u64
)-1LL : (1LLU << (128 - prefix
)) - 1LLU));
530 opt
->type
= ICMP6_OPT_PREFIX
;
532 opt
->prefix_len
= prefix
;
533 /* autonomous only if we're not doing dhcp, always set "on-link" */
534 opt
->flags
= do_slaac
? 0xC0 : 0x80;
535 opt
->valid_lifetime
= htonl(valid
);
536 opt
->preferred_lifetime
= htonl(preferred
);
538 opt
->prefix
= *local
;
540 inet_ntop(AF_INET6
, local
, daemon
->addrbuff
, ADDRSTRLEN
);
541 if (!option_bool(OPT_QUIET_RA
))
542 my_syslog(MS_DHCP
| LOG_INFO
, "RTR-ADVERT(%s) %s", param
->if_name
, daemon
->addrbuff
);
551 static int add_lla(int index
, unsigned int type
, char *mac
, size_t maclen
, void *parm
)
555 if (index
== *((int *)parm
))
557 /* size is in units of 8 octets and includes type and length (2 bytes)
559 int len
= (maclen
+ 9) >> 3;
560 unsigned char *p
= expand(len
<< 3);
561 memset(p
, 0, len
<< 3);
562 *p
++ = ICMP6_OPT_SOURCE_MAC
;
564 memcpy(p
, mac
, maclen
);
572 time_t periodic_ra(time_t now
)
574 struct search_param param
;
575 struct dhcp_context
*context
;
583 /* find overdue events, and time of first future event */
584 for (next_event
= 0, context
= daemon
->dhcp6
; context
; context
= context
->next
)
585 if (context
->ra_time
!= 0)
587 if (difftime(context
->ra_time
, now
) <= 0.0)
590 if (next_event
== 0 || difftime(next_event
, context
->ra_time
) > 0.0)
591 next_event
= context
->ra_time
;
598 if ((context
->flags
& CONTEXT_OLD
) &&
599 context
->if_index
!= 0 &&
600 indextoname(daemon
->icmp6fd
, param
.iface
, param
.name
))
602 /* A context for an old address. We'll not find the interface by
603 looking for addresses, but we know it anyway, since the context is
605 param
.iface
= context
->if_index
;
606 new_timeout(context
, param
.name
, now
);
608 else if (iface_enumerate(AF_INET6
, ¶m
, iface_search
))
609 /* There's a context overdue, but we can't find an interface
610 associated with it, because it's for a subnet we dont
611 have an interface on. Probably we're doing DHCP on
612 a remote subnet via a relay. Zero the timer, since we won't
613 ever be able to send ra's and satistfy it. */
614 context
->ra_time
= 0;
616 if (param
.iface
!= 0 &&
617 iface_check(AF_LOCAL
, NULL
, param
.name
, NULL
))
620 for (tmp
= daemon
->dhcp_except
; tmp
; tmp
= tmp
->next
)
621 if (tmp
->name
&& wildcard_match(tmp
->name
, param
.name
))
624 send_ra(now
, param
.iface
, param
.name
, NULL
);
630 static int iface_search(struct in6_addr
*local
, int prefix
,
631 int scope
, int if_index
, int flags
,
632 int preferred
, int valid
, void *vparam
)
634 struct search_param
*param
= vparam
;
635 struct dhcp_context
*context
;
641 for (context
= daemon
->dhcp6
; context
; context
= context
->next
)
642 if (!(context
->flags
& (CONTEXT_TEMPLATE
| CONTEXT_OLD
)) &&
643 prefix
== context
->prefix
&&
644 is_same_net6(local
, &context
->start6
, prefix
) &&
645 is_same_net6(local
, &context
->end6
, prefix
) &&
646 context
->ra_time
!= 0 &&
647 difftime(context
->ra_time
, param
->now
) <= 0.0)
649 /* found an interface that's overdue for RA determine new
650 timeout value and arrange for RA to be sent unless interface is
653 if (!(flags
& IFACE_TENTATIVE
))
654 param
->iface
= if_index
;
656 /* should never fail */
657 if (!indextoname(daemon
->icmp6fd
, if_index
, param
->name
))
663 new_timeout(context
, param
->name
, param
->now
);
665 /* zero timers for other contexts on the same subnet, so they don't timeout
667 for (context
= context
->next
; context
; context
= context
->next
)
668 if (prefix
== context
->prefix
&&
669 is_same_net6(local
, &context
->start6
, prefix
) &&
670 is_same_net6(local
, &context
->end6
, prefix
))
671 context
->ra_time
= 0;
673 return 0; /* found, abort */
676 return 1; /* keep searching */
679 static void new_timeout(struct dhcp_context
*context
, char *iface_name
, time_t now
)
681 if (difftime(now
, context
->ra_short_period_start
) < 60.0)
683 context
->ra_time
= now
+ 5 + (rand16()/4400);
686 /* range 3/4 - 1 times MaxRtrAdvInterval */
687 unsigned int adv_interval
= calc_interval(find_iface_param(iface_name
));
688 context
->ra_time
= now
+ (3 * adv_interval
)/4 + ((adv_interval
* (unsigned int)rand16()) >> 18);
692 static struct ra_interface
*find_iface_param(char *iface
)
694 struct ra_interface
*ra
;
696 for (ra
= daemon
->ra_interfaces
; ra
; ra
= ra
->next
)
697 if (wildcard_match(ra
->name
, iface
))
703 static unsigned int calc_interval(struct ra_interface
*ra
)
707 if (ra
&& ra
->interval
!= 0)
709 interval
= ra
->interval
;
712 else if (interval
< 4)
716 return (unsigned int)interval
;
719 static unsigned int calc_lifetime(struct ra_interface
*ra
)
721 int lifetime
, interval
= (int)calc_interval(ra
);
723 if (!ra
|| ra
->lifetime
== -1) /* not specified */
724 lifetime
= 3 * interval
;
727 lifetime
= ra
->lifetime
;
728 if (lifetime
< interval
&& lifetime
!= 0)
730 else if (lifetime
> 9000)
734 return (unsigned int)lifetime
;
737 static unsigned int calc_prio(struct ra_interface
*ra
)