Dnsmasq: update to 2.66TEST16
[tomato.git] / release / src / router / dnsmasq / src / dhcp6.c
blob76aaf87f69ccb1f33f9e9af52ecd1104bd5ead98
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/>.
17 #include "dnsmasq.h"
19 #ifdef HAVE_DHCP6
21 struct iface_param {
22 struct dhcp_context *current;
23 struct in6_addr fallback;
24 int ind, addr_match;
27 static int complete_context6(struct in6_addr *local, int prefix,
28 int scope, int if_index, int flags,
29 unsigned int preferred, unsigned int valid, void *vparam);
31 static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm);
33 void dhcp6_init(void)
35 int fd;
36 struct sockaddr_in6 saddr;
37 #if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
38 int class = IPTOS_CLASS_CS6;
39 #endif
40 int oneopt = 1;
42 if ((fd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == -1 ||
43 #if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
44 setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &class, sizeof(class)) == -1 ||
45 #endif
46 setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &oneopt, sizeof(oneopt)) == -1 ||
47 !fix_fd(fd) ||
48 !set_ipv6pktinfo(fd))
49 die (_("cannot create DHCPv6 socket: %s"), NULL, EC_BADNET);
51 /* When bind-interfaces is set, there might be more than one dnmsasq
52 instance binding port 547. That's OK if they serve different networks.
53 Need to set REUSEADDR to make this posible, or REUSEPORT on *BSD. */
54 if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
56 #ifdef SO_REUSEPORT
57 int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt));
58 #else
59 int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
60 #endif
61 if (rc == -1)
62 die(_("failed to set SO_REUSE{ADDR|PORT} on DHCPv6 socket: %s"), NULL, EC_BADNET);
65 memset(&saddr, 0, sizeof(saddr));
66 #ifdef HAVE_SOCKADDR_SA_LEN
67 saddr.sin6_len = sizeof(struct sockaddr_in6);
68 #endif
69 saddr.sin6_family = AF_INET6;
70 saddr.sin6_addr = in6addr_any;
71 saddr.sin6_port = htons(DHCPV6_SERVER_PORT);
73 if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in6)))
74 die(_("failed to bind DHCPv6 server socket: %s"), NULL, EC_BADNET);
76 daemon->dhcp6fd = fd;
79 void dhcp6_packet(time_t now)
81 struct dhcp_context *context;
82 struct iface_param parm;
83 struct cmsghdr *cmptr;
84 struct msghdr msg;
85 int if_index = 0;
86 union {
87 struct cmsghdr align; /* this ensures alignment */
88 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
89 } control_u;
90 struct sockaddr_in6 from;
91 ssize_t sz;
92 struct ifreq ifr;
93 struct iname *tmp;
94 unsigned short port;
96 msg.msg_control = control_u.control6;
97 msg.msg_controllen = sizeof(control_u);
98 msg.msg_flags = 0;
99 msg.msg_name = &from;
100 msg.msg_namelen = sizeof(from);
101 msg.msg_iov = &daemon->dhcp_packet;
102 msg.msg_iovlen = 1;
104 if ((sz = recv_dhcp_packet(daemon->dhcp6fd, &msg)) == -1)
105 return;
107 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
108 if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
110 union {
111 unsigned char *c;
112 struct in6_pktinfo *p;
113 } p;
114 p.c = CMSG_DATA(cmptr);
116 if_index = p.p->ipi6_ifindex;
119 if (!indextoname(daemon->dhcp6fd, if_index, ifr.ifr_name))
120 return;
122 for (tmp = daemon->if_except; tmp; tmp = tmp->next)
123 if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
124 return;
126 for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
127 if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
128 return;
130 parm.current = NULL;
131 parm.ind = if_index;
132 parm.addr_match = 0;
133 memset(&parm.fallback, 0, IN6ADDRSZ);
135 for (context = daemon->dhcp6; context; context = context->next)
136 if (IN6_IS_ADDR_UNSPECIFIED(&context->start6) && context->prefix == 0)
138 /* wildcard context for DHCP-stateless only */
139 parm.current = context;
140 context->current = NULL;
142 else
144 /* unlinked contexts are marked by context->current == context */
145 context->current = context;
146 memset(&context->local6, 0, IN6ADDRSZ);
149 if (!iface_enumerate(AF_INET6, &parm, complete_context6))
150 return;
152 if (daemon->if_names || daemon->if_addrs)
155 for (tmp = daemon->if_names; tmp; tmp = tmp->next)
156 if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
157 break;
159 if (!tmp && !parm.addr_match)
160 return;
163 lease_prune(NULL, now); /* lose any expired leases */
165 port = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback,
166 sz, IN6_IS_ADDR_MULTICAST(&from.sin6_addr), now);
168 lease_update_file(now);
169 lease_update_dns(0);
171 /* The port in the source address of the original request should
172 be correct, but at least once client sends from the server port,
173 so we explicitly send to the client port to a client, and the
174 server port to a relay. */
175 if (port != 0)
177 from.sin6_port = htons(port);
178 while (sendto(daemon->dhcp6fd, daemon->outpacket.iov_base, save_counter(0),
179 0, (struct sockaddr *)&from, sizeof(from)) == -1 &&
180 retry_send());
184 static int complete_context6(struct in6_addr *local, int prefix,
185 int scope, int if_index, int flags, unsigned int preferred,
186 unsigned int valid, void *vparam)
188 struct dhcp_context *context;
189 struct iface_param *param = vparam;
190 struct iname *tmp;
192 (void)scope; /* warning */
194 if (if_index == param->ind &&
195 !IN6_IS_ADDR_LOOPBACK(local) &&
196 !IN6_IS_ADDR_LINKLOCAL(local) &&
197 !IN6_IS_ADDR_MULTICAST(local))
199 /* if we have --listen-address config, see if the
200 arrival interface has a matching address. */
201 for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
202 if (tmp->addr.sa.sa_family == AF_INET6 &&
203 IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, local))
204 param->addr_match = 1;
206 /* Determine a globally address on the arrival interface, even
207 if we have no matching dhcp-context, because we're only
208 allocating on remote subnets via relays. This
209 is used as a default for the DNS server option. */
210 param->fallback = *local;
212 for (context = daemon->dhcp6; context; context = context->next)
214 if ((context->flags & CONTEXT_DHCP) &&
215 !(context->flags & CONTEXT_TEMPLATE) &&
216 prefix == context->prefix &&
217 is_same_net6(local, &context->start6, prefix) &&
218 is_same_net6(local, &context->end6, prefix))
222 /* link it onto the current chain if we've not seen it before */
223 if (context->current == context)
225 struct dhcp_context *tmp, **up;
227 /* use interface values only for contructed contexts */
228 if (!(context->flags & CONTEXT_CONSTRUCTED))
229 preferred = valid = 0xffffffff;
230 else if (flags & IFACE_DEPRECATED)
231 preferred = 0;
233 if (context->flags & CONTEXT_DEPRECATE)
234 preferred = 0;
236 /* order chain, longest preferred time first */
237 for (up = &param->current, tmp = param->current; tmp; tmp = tmp->current)
238 if (tmp->preferred <= preferred)
239 break;
240 else
241 up = &tmp->current;
243 context->current = *up;
244 *up = context;
245 context->local6 = *local;
246 context->preferred = preferred;
247 context->valid = valid;
252 return 1;
255 struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net, int prefix, u64 addr)
257 struct dhcp_config *config;
259 for (config = configs; config; config = config->next)
260 if ((config->flags & CONFIG_ADDR6) &&
261 is_same_net6(&config->addr6, net, prefix) &&
262 (prefix == 128 || addr6part(&config->addr6) == addr))
263 return config;
265 return NULL;
268 int address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len,
269 int serial, struct dhcp_netid *netids, struct in6_addr *ans)
271 /* Find a free address: exclude anything in use and anything allocated to
272 a particular hwaddr/clientid/hostname in our configuration.
273 Try to return from contexts which match netids first.
275 Note that we assume the address prefix lengths are 64 or greater, so we can
276 get by with 64 bit arithmetic.
279 u64 start, addr;
280 struct dhcp_context *c, *d;
281 int i, pass;
282 u64 j;
284 /* hash hwaddr: use the SDBM hashing algorithm. This works
285 for MAC addresses, let's see how it manages with client-ids! */
286 for (j = 0, i = 0; i < clid_len; i++)
287 j += clid[i] + (j << 6) + (j << 16) - j;
289 for (pass = 0; pass <= 1; pass++)
290 for (c = context; c; c = c->current)
291 if (c->flags & (CONTEXT_DEPRECATE | CONTEXT_STATIC | CONTEXT_RA_STATELESS))
292 continue;
293 else if (!match_netid(c->filter, netids, pass))
294 continue;
295 else
297 if (option_bool(OPT_CONSEC_ADDR))
298 /* seed is largest extant lease addr in this context */
299 start = lease_find_max_addr6(c) + serial;
300 else
301 start = addr6part(&c->start6) + ((j + c->addr_epoch + serial) % (1 + addr6part(&c->end6) - addr6part(&c->start6)));
303 /* iterate until we find a free address. */
304 addr = start;
306 do {
307 /* eliminate addresses in use by the server. */
308 for (d = context; d; d = d->current)
309 if (addr == addr6part(&d->local6))
310 break;
312 if (!d &&
313 !lease6_find_by_addr(&c->start6, c->prefix, addr) &&
314 !config_find_by_address6(daemon->dhcp_conf, &c->start6, c->prefix, addr))
316 *ans = c->start6;
317 setaddr6part (ans, addr);
318 return 1;
321 addr++;
323 if (addr == addr6part(&c->end6) + 1)
324 addr = addr6part(&c->start6);
326 } while (addr != start);
329 return 0;
332 /* can dynamically allocate addr */
333 struct dhcp_context *address6_available(struct dhcp_context *context,
334 struct in6_addr *taddr,
335 struct dhcp_netid *netids)
337 u64 start, end, addr = addr6part(taddr);
338 struct dhcp_context *tmp;
340 for (tmp = context; tmp; tmp = tmp->current)
342 start = addr6part(&tmp->start6);
343 end = addr6part(&tmp->end6);
345 if (!(tmp->flags & (CONTEXT_STATIC | CONTEXT_RA_STATELESS)) &&
346 is_same_net6(&tmp->start6, taddr, tmp->prefix) &&
347 is_same_net6(&tmp->end6, taddr, tmp->prefix) &&
348 addr >= start &&
349 addr <= end &&
350 match_netid(tmp->filter, netids, 1))
351 return tmp;
354 return NULL;
357 /* address OK if configured */
358 struct dhcp_context *address6_valid(struct dhcp_context *context,
359 struct in6_addr *taddr,
360 struct dhcp_netid *netids)
362 struct dhcp_context *tmp;
364 for (tmp = context; tmp; tmp = tmp->current)
365 if (is_same_net6(&tmp->start6, taddr, tmp->prefix) &&
366 match_netid(tmp->filter, netids, 1))
367 return tmp;
369 return NULL;
372 struct dhcp_context *narrow_context6(struct dhcp_context *context,
373 struct in6_addr *taddr,
374 struct dhcp_netid *netids)
376 /* We start of with a set of possible contexts, all on the current physical interface.
377 These are chained on ->current.
378 Here we have an address, and return the actual context correponding to that
379 address. Note that none may fit, if the address came a dhcp-host and is outside
380 any dhcp-range. In that case we return a static range if possible, or failing that,
381 any context on the correct subnet. (If there's more than one, this is a dodgy
382 configuration: maybe there should be a warning.) */
384 struct dhcp_context *tmp;
386 if (!(tmp = address6_available(context, taddr, netids)) &&
387 !(tmp = address6_valid(context, taddr, netids)))
388 for (tmp = context; tmp; tmp = tmp->current)
389 if (match_netid(tmp->filter, netids, 1) &&
390 is_same_net6(taddr, &tmp->start6, tmp->prefix))
391 break;
393 /* Only one context allowed now */
394 if (tmp)
395 tmp->current = NULL;
397 return tmp;
400 static int is_config_in_context6(struct dhcp_context *context, struct dhcp_config *config)
402 /* expand wildcard on contructed contexts */
403 if ((config->flags & CONFIG_WILDCARD) &&
404 (context->flags & CONTEXT_CONSTRUCTED))
406 u64 addrpart = addr6part(&config->addr6);
407 config->addr6 = context->start6;
408 setaddr6part(&config->addr6, addrpart);
409 return 1;
412 if (!(config->flags & CONFIG_ADDR6) || is_addr_in_context6(context, &config->addr6))
413 return 1;
415 return 0;
419 int is_addr_in_context6(struct dhcp_context *context, struct in6_addr *addr)
421 for (; context; context = context->current)
422 if (is_same_net6(addr, &context->start6, context->prefix))
423 return 1;
425 return 0;
429 struct dhcp_config *find_config6(struct dhcp_config *configs,
430 struct dhcp_context *context,
431 unsigned char *duid, int duid_len,
432 char *hostname)
434 struct dhcp_config *config;
436 if (duid)
437 for (config = configs; config; config = config->next)
438 if (config->flags & CONFIG_CLID)
440 if (config->clid_len == duid_len &&
441 memcmp(config->clid, duid, duid_len) == 0 &&
442 is_config_in_context6(context, config))
443 return config;
446 if (hostname && context)
447 for (config = configs; config; config = config->next)
448 if ((config->flags & CONFIG_NAME) &&
449 hostname_isequal(config->hostname, hostname) &&
450 is_config_in_context6(context, config))
451 return config;
453 return NULL;
456 void make_duid(time_t now)
458 if (daemon->duid_config)
460 unsigned char *p;
462 daemon->duid = p = safe_malloc(daemon->duid_config_len + 6);
463 daemon->duid_len = daemon->duid_config_len + 6;
464 PUTSHORT(2, p); /* DUID_EN */
465 PUTLONG(daemon->duid_enterprise, p);
466 memcpy(p, daemon->duid_config, daemon->duid_config_len);
468 else
470 /* rebase epoch to 1/1/2000 */
471 time_t newnow = now - 946684800;
473 iface_enumerate(AF_LOCAL, &newnow, make_duid1);
475 if(!daemon->duid)
476 die("Cannot create DHCPv6 server DUID: %s", NULL, EC_MISC);
480 static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm)
482 /* create DUID as specified in RFC3315. We use the MAC of the
483 first interface we find that isn't loopback or P-to-P and
484 has address-type < 256. Address types above 256 are things like
485 tunnels which don't have usable MAC addresses. */
487 unsigned char *p;
488 (void)index;
490 if (type >= 256)
491 return 1;
493 #ifdef HAVE_BROKEN_RTC
494 daemon->duid = p = safe_malloc(maclen + 4);
495 daemon->duid_len = maclen + 4;
496 PUTSHORT(3, p); /* DUID_LL */
497 PUTSHORT(type, p); /* address type */
498 #else
499 daemon->duid = p = safe_malloc(maclen + 8);
500 daemon->duid_len = maclen + 8;
501 PUTSHORT(1, p); /* DUID_LLT */
502 PUTSHORT(type, p); /* address type */
503 PUTLONG(*((time_t *)parm), p); /* time */
504 #endif
506 memcpy(p, mac, maclen);
508 return 0;
511 struct cparam {
512 time_t now;
513 int newone, newname;
516 static int construct_worker(struct in6_addr *local, int prefix,
517 int scope, int if_index, int flags,
518 int preferred, int valid, void *vparam)
520 char ifrn_name[IFNAMSIZ];
521 struct in6_addr start6, end6;
522 struct dhcp_context *template, *context;
524 (void)scope;
525 (void)flags;
526 (void)valid;
527 (void)preferred;
529 struct cparam *param = vparam;
531 if (IN6_IS_ADDR_LOOPBACK(local) ||
532 IN6_IS_ADDR_LINKLOCAL(local) ||
533 IN6_IS_ADDR_MULTICAST(local))
534 return 1;
536 if (!indextoname(daemon->doing_dhcp6 ? daemon->dhcp6fd : daemon->icmp6fd, if_index, ifrn_name))
537 return 0;
539 for (template = daemon->dhcp6; template; template = template->next)
540 if (!(template->flags & CONTEXT_TEMPLATE))
542 /* non-template entries, just fill in interface and local addresses */
543 if (prefix == template->prefix &&
544 is_same_net6(local, &template->start6, prefix) &&
545 is_same_net6(local, &template->end6, prefix))
547 template->if_index = if_index;
548 template->local6 = *local;
552 else if (addr6part(local) == addr6part(&template->start6) &&
553 strncmp(template->template_interface, ifrn_name, strlen(template->template_interface)) == 0 &&
554 (strlen(template->template_interface) == strlen(ifrn_name) || (template->flags & CONTEXT_WILDCARD)))
556 start6 = *local;
557 setaddr6part(&start6, addr6part(&template->start6));
558 end6 = *local;
559 setaddr6part(&end6, addr6part(&template->end6));
561 for (context = daemon->dhcp6; context; context = context->next)
562 if ((context->flags & CONTEXT_CONSTRUCTED) &&
563 IN6_ARE_ADDR_EQUAL(&start6, &context->start6) &&
564 IN6_ARE_ADDR_EQUAL(&end6, &context->end6))
566 context->flags &= ~CONTEXT_GC;
567 break;
570 if (!context && (context = whine_malloc(sizeof (struct dhcp_context))))
572 *context = *template;
573 context->start6 = start6;
574 context->end6 = end6;
575 context->flags &= ~CONTEXT_TEMPLATE;
576 context->flags |= CONTEXT_CONSTRUCTED;
577 context->if_index = if_index;
578 context->local6 = *local;
580 context->next = daemon->dhcp6;
581 daemon->dhcp6 = context;
583 ra_start_unsolicted(param->now, context);
584 /* we created a new one, need to call
585 lease_update_file to get periodic functions called */
586 param->newone = 1;
588 /* Will need to add new putative SLAAC addresses to existing leases */
589 if (context->flags & CONTEXT_RA_NAME)
590 param->newname = 1;
592 log_context(AF_INET6, context);
596 return 1;
599 void dhcp_construct_contexts(time_t now)
601 struct dhcp_context *tmp, *context, **up;
602 struct cparam param;
603 param.newone = 0;
604 param.newname = 0;
605 param.now = now;
607 for (context = daemon->dhcp6; context; context = context->next)
609 context->if_index = 0;
610 if (context->flags & CONTEXT_CONSTRUCTED)
611 context->flags |= CONTEXT_GC;
614 iface_enumerate(AF_INET6, &param, construct_worker);
616 for (up = &daemon->dhcp6, context = daemon->dhcp6; context; context = tmp)
618 tmp = context->next;
620 if (context->flags & CONTEXT_GC)
622 *up = context->next;
623 param.newone = 1; /* include deletion */
624 if (context->flags & CONTEXT_RA_NAME)
625 param.newname = 1;
626 free(context);
628 else
629 up = &context->next;
632 if (param.newone)
634 if (daemon->dhcp || daemon->doing_dhcp6)
636 if (param.newname)
637 lease_update_slaac(now);
638 lease_update_file(now);
640 else
641 /* Not doing DHCP, so no lease system, manage alarms for ra only */
642 send_alarm(periodic_ra(now), now);
646 #endif