]>
git.ipfire.org Git - people/ms/dnsmasq.git/blob - src/dhcp6.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/>.
21 #include <netinet/icmp6.h>
24 struct dhcp_context
*current
;
25 struct dhcp_relay
*relay
;
26 struct in6_addr fallback
, relay_local
;
31 struct in6_addr
*target
;
32 unsigned char mac
[DHCP_CHADDR_MAX
];
37 static int complete_context6(struct in6_addr
*local
, int prefix
,
38 int scope
, int if_index
, int flags
,
39 unsigned int preferred
, unsigned int valid
, void *vparam
);
40 static int find_mac(int family
, char *addrp
, char *mac
, size_t maclen
, void *parmv
);
41 static int make_duid1(int index
, unsigned int type
, char *mac
, size_t maclen
, void *parm
);
46 struct sockaddr_in6 saddr
;
47 #if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
48 int class = IPTOS_CLASS_CS6
;
52 if ((fd
= socket(PF_INET6
, SOCK_DGRAM
, IPPROTO_UDP
)) == -1 ||
53 #if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
54 setsockopt(fd
, IPPROTO_IPV6
, IPV6_TCLASS
, &class, sizeof(class)) == -1 ||
56 setsockopt(fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &oneopt
, sizeof(oneopt
)) == -1 ||
59 die (_("cannot create DHCPv6 socket: %s"), NULL
, EC_BADNET
);
61 /* When bind-interfaces is set, there might be more than one dnmsasq
62 instance binding port 547. That's OK if they serve different networks.
63 Need to set REUSEADDR|REUSEPORT to make this posible.
64 Handle the case that REUSEPORT is defined, but the kernel doesn't
65 support it. This handles the introduction of REUSEPORT on Linux. */
66 if (option_bool(OPT_NOWILD
) || option_bool(OPT_CLEVERBIND
))
71 if ((rc
= setsockopt(fd
, SOL_SOCKET
, SO_REUSEPORT
, &oneopt
, sizeof(oneopt
))) == -1 &&
77 rc
= setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &oneopt
, sizeof(oneopt
));
80 die(_("failed to set SO_REUSE{ADDR|PORT} on DHCPv6 socket: %s"), NULL
, EC_BADNET
);
83 memset(&saddr
, 0, sizeof(saddr
));
84 #ifdef HAVE_SOCKADDR_SA_LEN
85 saddr
.sin6_len
= sizeof(struct sockaddr_in6
);
87 saddr
.sin6_family
= AF_INET6
;
88 saddr
.sin6_addr
= in6addr_any
;
89 saddr
.sin6_port
= htons(DHCPV6_SERVER_PORT
);
91 if (bind(fd
, (struct sockaddr
*)&saddr
, sizeof(struct sockaddr_in6
)))
92 die(_("failed to bind DHCPv6 server socket: %s"), NULL
, EC_BADNET
);
97 void dhcp6_packet(time_t now
)
99 struct dhcp_context
*context
;
100 struct dhcp_relay
*relay
;
101 struct iface_param parm
;
102 struct mac_param mac_param
;
103 struct cmsghdr
*cmptr
;
107 struct cmsghdr align
; /* this ensures alignment */
108 char control6
[CMSG_SPACE(sizeof(struct in6_pktinfo
))];
110 struct sockaddr_in6 from
;
115 struct in6_addr dst_addr
;
117 msg
.msg_control
= control_u
.control6
;
118 msg
.msg_controllen
= sizeof(control_u
);
120 msg
.msg_name
= &from
;
121 msg
.msg_namelen
= sizeof(from
);
122 msg
.msg_iov
= &daemon
->dhcp_packet
;
125 if ((sz
= recv_dhcp_packet(daemon
->dhcp6fd
, &msg
)) == -1)
128 for (cmptr
= CMSG_FIRSTHDR(&msg
); cmptr
; cmptr
= CMSG_NXTHDR(&msg
, cmptr
))
129 if (cmptr
->cmsg_level
== IPPROTO_IPV6
&& cmptr
->cmsg_type
== daemon
->v6pktinfo
)
133 struct in6_pktinfo
*p
;
135 p
.c
= CMSG_DATA(cmptr
);
137 if_index
= p
.p
->ipi6_ifindex
;
138 dst_addr
= p
.p
->ipi6_addr
;
141 if (!indextoname(daemon
->dhcp6fd
, if_index
, ifr
.ifr_name
))
144 if ((port
= relay_reply6(&from
, sz
, ifr
.ifr_name
)) == 0)
148 for (tmp
= daemon
->if_except
; tmp
; tmp
= tmp
->next
)
149 if (tmp
->name
&& wildcard_match(tmp
->name
, ifr
.ifr_name
))
152 for (tmp
= daemon
->dhcp_except
; tmp
; tmp
= tmp
->next
)
153 if (tmp
->name
&& wildcard_match(tmp
->name
, ifr
.ifr_name
))
158 memset(&parm
.relay_local
, 0, IN6ADDRSZ
);
161 memset(&parm
.fallback
, 0, IN6ADDRSZ
);
163 for (context
= daemon
->dhcp6
; context
; context
= context
->next
)
164 if (IN6_IS_ADDR_UNSPECIFIED(&context
->start6
) && context
->prefix
== 0)
166 /* wildcard context for DHCP-stateless only */
167 parm
.current
= context
;
168 context
->current
= NULL
;
172 /* unlinked contexts are marked by context->current == context */
173 context
->current
= context
;
174 memset(&context
->local6
, 0, IN6ADDRSZ
);
177 for (relay
= daemon
->relay6
; relay
; relay
= relay
->next
)
178 relay
->current
= relay
;
180 if (!iface_enumerate(AF_INET6
, &parm
, complete_context6
))
183 /* Recieving a packet from a host does not populate the neighbour
184 cache, so we send a ping to prompt neighbour discovery if we can't
185 find the sender. Repeat a few times in case of packet loss. */
187 for (i
= 0; i
< 5; i
++)
190 struct ping_packet
*ping
;
191 struct sockaddr_in6 addr
;
193 mac_param
.target
= &from
.sin6_addr
;
194 mac_param
.maclen
= 0;
196 iface_enumerate(AF_UNSPEC
, &mac_param
, find_mac
);
198 if (mac_param
.maclen
!= 0)
202 ping
= expand(sizeof(struct ping_packet
));
203 ping
->type
= ICMP6_ECHO_REQUEST
;
205 ping
->identifier
= 1;
206 ping
->sequence_no
= 1;
208 memset(&addr
, 0, sizeof(addr
));
209 #ifdef HAVE_SOCKADDR_SA_LEN
210 addr
.sin6_len
= sizeof(struct sockaddr_in6
);
212 addr
.sin6_family
= AF_INET6
;
213 addr
.sin6_port
= htons(IPPROTO_ICMPV6
);
214 addr
.sin6_addr
= from
.sin6_addr
;
216 sendto(daemon
->icmp6fd
, daemon
->outpacket
.iov_base
, save_counter(0), 0,
217 (struct sockaddr
*)&addr
, sizeof(addr
));
220 ts
.tv_nsec
= 100000000; /* 100ms */
221 nanosleep(&ts
, NULL
);
224 if (daemon
->if_names
|| daemon
->if_addrs
)
227 for (tmp
= daemon
->if_names
; tmp
; tmp
= tmp
->next
)
228 if (tmp
->name
&& wildcard_match(tmp
->name
, ifr
.ifr_name
))
231 if (!tmp
&& !parm
.addr_match
)
237 /* Ignore requests sent to the ALL_SERVERS multicast address for relay when
238 we're listening there for DHCPv6 server reasons. */
239 struct in6_addr all_servers
;
241 inet_pton(AF_INET6
, ALL_SERVERS
, &all_servers
);
243 if (!IN6_ARE_ADDR_EQUAL(&dst_addr
, &all_servers
))
244 relay_upstream6(parm
.relay
, sz
, &from
.sin6_addr
, from
.sin6_scope_id
,
245 mac_param
.maclen
== 0 ? NULL
: &mac_param
.mac
[0], mac_param
.maclen
, ARPHRD_ETHER
);
249 /* May have configured relay, but not DHCP server */
250 if (!daemon
->doing_dhcp6
)
253 lease_prune(NULL
, now
); /* lose any expired leases */
255 port
= dhcp6_reply(parm
.current
, if_index
, ifr
.ifr_name
, &parm
.fallback
,
256 sz
, IN6_IS_ADDR_MULTICAST(&from
.sin6_addr
), now
,
257 mac_param
.maclen
== 0 ? NULL
: &mac_param
.mac
[0], mac_param
.maclen
, ARPHRD_ETHER
);
259 lease_update_file(now
);
263 /* The port in the source address of the original request should
264 be correct, but at least once client sends from the server port,
265 so we explicitly send to the client port to a client, and the
266 server port to a relay. */
269 from
.sin6_port
= htons(port
);
270 while (sendto(daemon
->dhcp6fd
, daemon
->outpacket
.iov_base
, save_counter(0),
271 0, (struct sockaddr
*)&from
, sizeof(from
)) == -1 &&
276 static int find_mac(int family
, char *addrp
, char *mac
, size_t maclen
, void *parmv
)
278 struct mac_param
*parm
= parmv
;
280 if (family
== AF_INET6
&& IN6_ARE_ADDR_EQUAL(parm
->target
, addrp
))
282 if (maclen
<= DHCP_CHADDR_MAX
)
284 parm
->maclen
= maclen
;
285 memcpy(parm
->mac
, mac
, maclen
);
288 return 0; /* found, abort */
294 static int complete_context6(struct in6_addr
*local
, int prefix
,
295 int scope
, int if_index
, int flags
, unsigned int preferred
,
296 unsigned int valid
, void *vparam
)
298 struct dhcp_context
*context
;
299 struct dhcp_relay
*relay
;
300 struct iface_param
*param
= vparam
;
303 (void)scope
; /* warning */
305 if (if_index
== param
->ind
)
307 if (!IN6_IS_ADDR_LOOPBACK(local
) &&
308 !IN6_IS_ADDR_LINKLOCAL(local
) &&
309 !IN6_IS_ADDR_MULTICAST(local
))
311 /* if we have --listen-address config, see if the
312 arrival interface has a matching address. */
313 for (tmp
= daemon
->if_addrs
; tmp
; tmp
= tmp
->next
)
314 if (tmp
->addr
.sa
.sa_family
== AF_INET6
&&
315 IN6_ARE_ADDR_EQUAL(&tmp
->addr
.in6
.sin6_addr
, local
))
316 param
->addr_match
= 1;
318 /* Determine a globally address on the arrival interface, even
319 if we have no matching dhcp-context, because we're only
320 allocating on remote subnets via relays. This
321 is used as a default for the DNS server option. */
322 param
->fallback
= *local
;
324 for (context
= daemon
->dhcp6
; context
; context
= context
->next
)
326 if ((context
->flags
& CONTEXT_DHCP
) &&
327 !(context
->flags
& (CONTEXT_TEMPLATE
| CONTEXT_OLD
)) &&
328 prefix
== context
->prefix
&&
329 is_same_net6(local
, &context
->start6
, prefix
) &&
330 is_same_net6(local
, &context
->end6
, prefix
))
334 /* link it onto the current chain if we've not seen it before */
335 if (context
->current
== context
)
337 struct dhcp_context
*tmp
, **up
;
339 /* use interface values only for contructed contexts */
340 if (!(context
->flags
& CONTEXT_CONSTRUCTED
))
341 preferred
= valid
= 0xffffffff;
342 else if (flags
& IFACE_DEPRECATED
)
345 if (context
->flags
& CONTEXT_DEPRECATE
)
348 /* order chain, longest preferred time first */
349 for (up
= ¶m
->current
, tmp
= param
->current
; tmp
; tmp
= tmp
->current
)
350 if (tmp
->preferred
<= preferred
)
355 context
->current
= *up
;
357 context
->local6
= *local
;
358 context
->preferred
= preferred
;
359 context
->valid
= valid
;
365 for (relay
= daemon
->relay6
; relay
; relay
= relay
->next
)
366 if (IN6_ARE_ADDR_EQUAL(local
, &relay
->local
.addr
.addr6
) && relay
->current
== relay
&&
367 (IN6_IS_ADDR_UNSPECIFIED(¶m
->relay_local
) || IN6_ARE_ADDR_EQUAL(local
, ¶m
->relay_local
)))
369 relay
->current
= param
->relay
;
370 param
->relay
= relay
;
371 param
->relay_local
= *local
;
379 struct dhcp_config
*config_find_by_address6(struct dhcp_config
*configs
, struct in6_addr
*net
, int prefix
, u64 addr
)
381 struct dhcp_config
*config
;
383 for (config
= configs
; config
; config
= config
->next
)
384 if ((config
->flags
& CONFIG_ADDR6
) &&
385 is_same_net6(&config
->addr6
, net
, prefix
) &&
386 (prefix
== 128 || addr6part(&config
->addr6
) == addr
))
392 struct dhcp_context
*address6_allocate(struct dhcp_context
*context
, unsigned char *clid
, int clid_len
,
393 int iaid
, int serial
, struct dhcp_netid
*netids
, int plain_range
, struct in6_addr
*ans
)
395 /* Find a free address: exclude anything in use and anything allocated to
396 a particular hwaddr/clientid/hostname in our configuration.
397 Try to return from contexts which match netids first.
399 Note that we assume the address prefix lengths are 64 or greater, so we can
400 get by with 64 bit arithmetic.
404 struct dhcp_context
*c
, *d
;
408 /* hash hwaddr: use the SDBM hashing algorithm. This works
409 for MAC addresses, let's see how it manages with client-ids! */
410 for (j
= iaid
, i
= 0; i
< clid_len
; i
++)
411 j
+= clid
[i
] + (j
<< 6) + (j
<< 16) - j
;
413 for (pass
= 0; pass
<= plain_range
? 1 : 0; pass
++)
414 for (c
= context
; c
; c
= c
->current
)
415 if (c
->flags
& (CONTEXT_DEPRECATE
| CONTEXT_STATIC
| CONTEXT_RA_STATELESS
| CONTEXT_USED
))
417 else if (!match_netid(c
->filter
, netids
, pass
))
421 if (option_bool(OPT_CONSEC_ADDR
))
422 /* seed is largest extant lease addr in this context */
423 start
= lease_find_max_addr6(c
) + serial
;
425 start
= addr6part(&c
->start6
) + ((j
+ c
->addr_epoch
) % (1 + addr6part(&c
->end6
) - addr6part(&c
->start6
)));
427 /* iterate until we find a free address. */
431 /* eliminate addresses in use by the server. */
432 for (d
= context
; d
; d
= d
->current
)
433 if (addr
== addr6part(&d
->local6
))
437 !lease6_find_by_addr(&c
->start6
, c
->prefix
, addr
) &&
438 !config_find_by_address6(daemon
->dhcp_conf
, &c
->start6
, c
->prefix
, addr
))
441 setaddr6part (ans
, addr
);
447 if (addr
== addr6part(&c
->end6
) + 1)
448 addr
= addr6part(&c
->start6
);
450 } while (addr
!= start
);
456 /* can dynamically allocate addr */
457 struct dhcp_context
*address6_available(struct dhcp_context
*context
,
458 struct in6_addr
*taddr
,
459 struct dhcp_netid
*netids
,
462 u64 start
, end
, addr
= addr6part(taddr
);
463 struct dhcp_context
*tmp
;
465 for (tmp
= context
; tmp
; tmp
= tmp
->current
)
467 start
= addr6part(&tmp
->start6
);
468 end
= addr6part(&tmp
->end6
);
470 if (!(tmp
->flags
& (CONTEXT_STATIC
| CONTEXT_RA_STATELESS
)) &&
471 is_same_net6(&tmp
->start6
, taddr
, tmp
->prefix
) &&
472 is_same_net6(&tmp
->end6
, taddr
, tmp
->prefix
) &&
475 match_netid(tmp
->filter
, netids
, plain_range
))
482 /* address OK if configured */
483 struct dhcp_context
*address6_valid(struct dhcp_context
*context
,
484 struct in6_addr
*taddr
,
485 struct dhcp_netid
*netids
,
488 struct dhcp_context
*tmp
;
490 for (tmp
= context
; tmp
; tmp
= tmp
->current
)
491 if (is_same_net6(&tmp
->start6
, taddr
, tmp
->prefix
) &&
492 match_netid(tmp
->filter
, netids
, plain_range
))
498 int config_valid(struct dhcp_config
*config
, struct dhcp_context
*context
, struct in6_addr
*addr
)
500 if (!config
|| !(config
->flags
& CONFIG_ADDR6
))
503 if ((config
->flags
& CONFIG_WILDCARD
) && context
->prefix
== 64)
505 *addr
= context
->start6
;
506 setaddr6part(addr
, addr6part(&config
->addr6
));
510 if (is_same_net6(&context
->start6
, &config
->addr6
, context
->prefix
))
512 *addr
= config
->addr6
;
519 void make_duid(time_t now
)
521 if (daemon
->duid_config
)
525 daemon
->duid
= p
= safe_malloc(daemon
->duid_config_len
+ 6);
526 daemon
->duid_len
= daemon
->duid_config_len
+ 6;
527 PUTSHORT(2, p
); /* DUID_EN */
528 PUTLONG(daemon
->duid_enterprise
, p
);
529 memcpy(p
, daemon
->duid_config
, daemon
->duid_config_len
);
533 /* rebase epoch to 1/1/2000 */
534 time_t newnow
= now
- 946684800;
536 iface_enumerate(AF_LOCAL
, &newnow
, make_duid1
);
539 die("Cannot create DHCPv6 server DUID: %s", NULL
, EC_MISC
);
543 static int make_duid1(int index
, unsigned int type
, char *mac
, size_t maclen
, void *parm
)
545 /* create DUID as specified in RFC3315. We use the MAC of the
546 first interface we find that isn't loopback or P-to-P and
547 has address-type < 256. Address types above 256 are things like
548 tunnels which don't have usable MAC addresses. */
556 #ifdef HAVE_BROKEN_RTC
557 daemon
->duid
= p
= safe_malloc(maclen
+ 4);
558 daemon
->duid_len
= maclen
+ 4;
559 PUTSHORT(3, p
); /* DUID_LL */
560 PUTSHORT(type
, p
); /* address type */
562 daemon
->duid
= p
= safe_malloc(maclen
+ 8);
563 daemon
->duid_len
= maclen
+ 8;
564 PUTSHORT(1, p
); /* DUID_LLT */
565 PUTSHORT(type
, p
); /* address type */
566 PUTLONG(*((time_t *)parm
), p
); /* time */
569 memcpy(p
, mac
, maclen
);
579 static int construct_worker(struct in6_addr
*local
, int prefix
,
580 int scope
, int if_index
, int flags
,
581 int preferred
, int valid
, void *vparam
)
583 char ifrn_name
[IFNAMSIZ
];
584 struct in6_addr start6
, end6
;
585 struct dhcp_context
*template, *context
;
592 struct cparam
*param
= vparam
;
594 if (IN6_IS_ADDR_LOOPBACK(local
) ||
595 IN6_IS_ADDR_LINKLOCAL(local
) ||
596 IN6_IS_ADDR_MULTICAST(local
))
599 if (!indextoname(daemon
->doing_dhcp6
? daemon
->dhcp6fd
: daemon
->icmp6fd
, if_index
, ifrn_name
))
602 for (template = daemon
->dhcp6
; template; template = template->next
)
603 if (!(template->flags
& CONTEXT_TEMPLATE
))
605 /* non-template entries, just fill in interface and local addresses */
606 if (prefix
== template->prefix
&&
607 is_same_net6(local
, &template->start6
, prefix
) &&
608 is_same_net6(local
, &template->end6
, prefix
))
610 template->if_index
= if_index
;
611 template->local6
= *local
;
615 else if ((addr6part(local
) == addr6part(&template->start6
) ||
616 addr6part(local
) == addr6part(&template->end6
) ||
617 (IN6_IS_ADDR_UNSPECIFIED(&template->start6
) &&
618 IFACE_PERMANENT
== (flags
& (IFACE_PERMANENT
| IFACE_DEPRECATED
)))) &&
619 wildcard_match(template->template_interface
, ifrn_name
))
622 setaddr6part(&start6
, addr6part(&template->start6
));
624 setaddr6part(&end6
, addr6part(&template->end6
));
626 for (context
= daemon
->dhcp6
; context
; context
= context
->next
)
627 if ((context
->flags
& CONTEXT_CONSTRUCTED
) &&
628 IN6_ARE_ADDR_EQUAL(&start6
, &context
->start6
) &&
629 IN6_ARE_ADDR_EQUAL(&end6
, &context
->end6
))
631 int flags
= context
->flags
;
632 context
->flags
&= ~(CONTEXT_GC
| CONTEXT_OLD
);
633 if (flags
& CONTEXT_OLD
)
635 /* address went, now it's back */
636 log_context(AF_INET6
, context
);
637 /* fast RAs for a while */
638 ra_start_unsolicted(param
->now
, context
);
639 /* Add address to name again */
640 if (context
->flags
& CONTEXT_RA_NAME
)
646 if (!context
&& (context
= whine_malloc(sizeof (struct dhcp_context
))))
648 *context
= *template;
649 context
->start6
= start6
;
650 context
->end6
= end6
;
651 context
->flags
&= ~CONTEXT_TEMPLATE
;
652 context
->flags
|= CONTEXT_CONSTRUCTED
;
653 context
->if_index
= if_index
;
654 context
->local6
= *local
;
655 context
->saved_valid
= 0;
657 context
->next
= daemon
->dhcp6
;
658 daemon
->dhcp6
= context
;
660 ra_start_unsolicted(param
->now
, context
);
661 /* we created a new one, need to call
662 lease_update_file to get periodic functions called */
665 /* Will need to add new putative SLAAC addresses to existing leases */
666 if (context
->flags
& CONTEXT_RA_NAME
)
669 log_context(AF_INET6
, context
);
676 void dhcp_construct_contexts(time_t now
)
678 struct dhcp_context
*context
, *tmp
, **up
;
684 for (context
= daemon
->dhcp6
; context
; context
= context
->next
)
685 if (context
->flags
& CONTEXT_CONSTRUCTED
)
686 context
->flags
|= CONTEXT_GC
;
688 iface_enumerate(AF_INET6
, ¶m
, construct_worker
);
690 for (up
= &daemon
->dhcp6
, context
= daemon
->dhcp6
; context
; context
= tmp
)
695 if (context
->flags
& CONTEXT_GC
&& !(context
->flags
& CONTEXT_OLD
))
698 if ((context
->flags
& (CONTEXT_RA_ONLY
| CONTEXT_RA_NAME
| CONTEXT_RA_STATELESS
)) ||
701 /* previously constructed context has gone. advertise it's demise */
702 context
->flags
|= CONTEXT_OLD
;
703 context
->address_lost_time
= now
;
704 /* Apply same ceiling of configured lease time as in radv.c */
705 if (context
->saved_valid
> context
->lease_time
)
706 context
->saved_valid
= context
->lease_time
;
707 /* maximum time is 2 hours, from RFC */
708 if (context
->saved_valid
> 7200) /* 2 hours */
709 context
->saved_valid
= 7200;
710 ra_start_unsolicted(now
, context
);
711 param
.newone
= 1; /* include deletion */
713 if (context
->flags
& CONTEXT_RA_NAME
)
716 log_context(AF_INET6
, context
);
722 /* we were never doing RA for this, so free now */
733 if (daemon
->dhcp
|| daemon
->doing_dhcp6
)
736 lease_update_slaac(now
);
737 lease_update_file(now
);
740 /* Not doing DHCP, so no lease system, manage alarms for ra only */
741 send_alarm(periodic_ra(now
), now
);