minidlna support now Samsung TV C550/C650 (thx amir909)
[tomato.git] / release / src / router / dhcpv6 / config.c
blob3a1eeeafaa76cbc4da91f7c7bd3f66ed12503600
1 /* $KAME: config.c,v 1.53 2005/09/16 11:30:14 suz Exp $ */
3 /*
4 * Copyright (C) 2002 WIDE Project.
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <sys/queue.h>
34 #include <sys/ioctl.h>
36 #include <net/if.h>
37 #include <netinet/in.h>
38 #ifdef __KAME__
39 #include <net/if_dl.h>
40 #endif
41 #ifdef __linux__
42 #include <linux/if_packet.h>
43 #endif
45 #include <syslog.h>
46 #include <stdlib.h>
47 #include <stdio.h>
48 #include <string.h>
49 #include <ifaddrs.h>
50 #include <errno.h>
51 #ifdef __linux__
52 #define __USE_XOPEN
53 #include <time.h>
54 #endif
56 #include <dhcp6.h>
57 #include <config.h>
58 #include <common.h>
59 #include <auth.h>
60 #include <base64.h>
61 #ifdef USE_DHCP6SRV
62 #include <lease.h>
63 #endif
65 extern int errno;
67 struct prefix_ifconf *prefix_ifconflist;
68 struct dhcp6_list siplist, sipnamelist, dnslist, dnsnamelist, ntplist;
69 struct dhcp6_list nislist, nisnamelist;
70 struct dhcp6_list nisplist, nispnamelist;
71 struct dhcp6_list bcmcslist, bcmcsnamelist;
72 long long optrefreshtime;
74 static struct dhcp6_ifconf *dhcp6_ifconflist;
75 struct ia_conflist ia_conflist0;
76 static struct host_conf *host_conflist0, *host_conflist;
77 static struct keyinfo *key_list, *key_list0;
78 static struct authinfo *auth_list, *auth_list0;
79 static struct dhcp6_list siplist0, sipnamelist0, dnslist0, dnsnamelist0, ntplist0;
80 static struct dhcp6_list nislist0, nisnamelist0;
81 static struct dhcp6_list nisplist0, nispnamelist0;
82 static struct dhcp6_list bcmcslist0, bcmcsnamelist0;
83 static long long optrefreshtime0 = -1;
84 #ifndef DHCP6_DYNAMIC_HOSTCONF_MAX
85 #define DHCP6_DYNAMIC_HOSTCONF_MAX 1024
86 #endif
87 struct dynamic_hostconf {
88 TAILQ_ENTRY(dynamic_hostconf) link;
89 struct host_conf *host;
91 static TAILQ_HEAD(dynamic_hostconf_listhead, dynamic_hostconf)
92 dynamic_hostconf_head;
93 static unsigned int dynamic_hostconf_count;
94 static struct pool_conf *pool_conflist, *pool_conflist0;
96 enum { DHCPOPTCODE_SEND, DHCPOPTCODE_REQUEST, DHCPOPTCODE_ALLOW };
98 /* temporary configuration structure for DHCP interface */
99 struct dhcp6_ifconf {
100 struct dhcp6_ifconf *next;
102 char *ifname;
104 /* configuration flags */
105 u_long send_flags;
106 u_long allow_flags;
108 int server_pref; /* server preference (server only) */
110 char *scriptpath; /* path to config script (client only) */
112 struct dhcp6_list reqopt_list;
113 struct ia_conflist iaconf_list;
115 struct authinfo *authinfo; /* authentication information
116 * (no need to clear) */
117 struct dhcp6_poolspec pool;
120 extern struct cf_list *cf_dns_list, *cf_dns_name_list, *cf_ntp_list;
121 extern struct cf_list *cf_sip_list, *cf_sip_name_list;
122 extern struct cf_list *cf_nis_list, *cf_nis_name_list;
123 extern struct cf_list *cf_nisp_list, *cf_nisp_name_list;
124 extern struct cf_list *cf_bcmcs_list, *cf_bcmcs_name_list;
125 extern long long cf_refreshtime;
126 extern char *configfilename;
128 static struct keyinfo *find_keybyname __P((struct keyinfo *, char *));
129 static int add_pd_pif __P((struct iapd_conf *, struct cf_list *));
130 static int add_options __P((int, struct dhcp6_ifconf *, struct cf_list *));
131 static int add_prefix __P((struct dhcp6_list *, char *, int,
132 struct dhcp6_prefix *));
133 static void clear_pd_pif __P((struct iapd_conf *));
134 static void clear_ifconf __P((struct dhcp6_ifconf *));
135 static void clear_iaconf __P((struct ia_conflist *));
136 static void clear_hostconf __P((struct host_conf *));
137 static void clear_keys __P((struct keyinfo *));
138 static void clear_authinfo __P((struct authinfo *));
139 static int configure_duid __P((char *, struct duid *));
140 static int configure_addr __P((struct cf_list *, struct dhcp6_list *, char *));
141 static int configure_domain __P((struct cf_list *, struct dhcp6_list *, char *));
142 static int get_default_ifid __P((struct prefix_ifconf *));
143 static void clear_poolconf __P((struct pool_conf *));
144 static struct pool_conf *create_pool __P((char *, struct dhcp6_range *));
145 struct host_conf *find_dynamic_hostconf __P((struct duid *));
146 static int in6_addr_cmp __P((struct in6_addr *, struct in6_addr *));
147 #ifdef USE_DHCP6SRV
148 static void in6_addr_inc __P((struct in6_addr *));
149 #endif
152 configure_interface(iflist)
153 struct cf_namelist *iflist;
155 struct cf_namelist *ifp;
156 struct dhcp6_ifconf *ifc;
157 char *cp;
159 for (ifp = iflist; ifp; ifp = ifp->next) {
160 struct cf_list *cfl;
162 if (if_nametoindex(ifp->name) == 0) {
163 dprintf(LOG_ERR, FNAME, "invalid interface(%s): %s",
164 ifp->name, strerror(errno));
165 goto bad;
168 if ((ifc = malloc(sizeof(*ifc))) == NULL) {
169 dprintf(LOG_ERR, FNAME,
170 "memory allocation for %s failed", ifp->name);
171 goto bad;
173 memset(ifc, 0, sizeof(*ifc));
174 ifc->next = dhcp6_ifconflist;
175 dhcp6_ifconflist = ifc;
177 if ((ifc->ifname = strdup(ifp->name)) == NULL) {
178 dprintf(LOG_ERR, FNAME, "failed to copy ifname");
179 goto bad;
182 ifc->server_pref = DH6OPT_PREF_UNDEF;
183 TAILQ_INIT(&ifc->reqopt_list);
184 TAILQ_INIT(&ifc->iaconf_list);
186 for (cfl = ifp->params; cfl; cfl = cfl->next) {
187 switch(cfl->type) {
188 case DECL_REQUEST:
189 if (dhcp6_mode != DHCP6_MODE_CLIENT) {
190 dprintf(LOG_INFO, FNAME, "%s:%d "
191 "client-only configuration",
192 configfilename,
193 cfl->line);
194 goto bad;
196 if (add_options(DHCPOPTCODE_REQUEST,
197 ifc, cfl->list)) {
198 goto bad;
200 break;
201 case DECL_SEND:
202 if (add_options(DHCPOPTCODE_SEND,
203 ifc, cfl->list)) {
204 goto bad;
206 break;
207 case DECL_ALLOW:
208 if (add_options(DHCPOPTCODE_ALLOW,
209 ifc, cfl->list)) {
210 goto bad;
212 break;
213 case DECL_INFO_ONLY:
214 if (dhcp6_mode != DHCP6_MODE_CLIENT) {
215 dprintf(LOG_INFO, FNAME, "%s:%d "
216 "client-only configuration",
217 configfilename, cfl->line);
218 goto bad;
220 ifc->send_flags |= DHCIFF_INFO_ONLY;
221 break;
222 case DECL_PREFERENCE:
223 if (dhcp6_mode != DHCP6_MODE_SERVER) {
224 dprintf(LOG_INFO, FNAME, "%s:%d "
225 "server-only configuration",
226 configfilename, cfl->line);
227 goto bad;
229 ifc->server_pref = (int)cfl->num;
230 if (ifc->server_pref < 0 ||
231 ifc->server_pref > 255) {
232 dprintf(LOG_INFO, FNAME, "%s:%d "
233 "bad value: %d",
234 configfilename, cfl->line,
235 ifc->server_pref);
236 goto bad;
238 break;
239 case DECL_SCRIPT:
240 if (dhcp6_mode != DHCP6_MODE_CLIENT) {
241 dprintf(LOG_INFO, FNAME, "%s:%d "
242 "client-only configuration",
243 configfilename, cfl->line);
244 goto bad;
246 if (ifc->scriptpath) {
247 dprintf(LOG_INFO, FNAME,
248 "%s:%d duplicated configuration",
249 configfilename, cfl->line);
250 goto bad;
252 cp = cfl->ptr;
253 ifc->scriptpath = strdup(cp + 1);
254 if (ifc->scriptpath == NULL) {
255 dprintf(LOG_NOTICE, FNAME,
256 "failed to copy script path");
257 goto bad;
259 cp = ifc->scriptpath;
260 if (*cp != '/') {
261 dprintf(LOG_INFO, FNAME,
262 "script must be an absolute path");
263 goto bad;
265 cp += strlen(ifc->scriptpath) - 1;
266 *cp = '\0'; /* clear the terminating quote */
267 break;
268 case DECL_ADDRESSPOOL:
270 struct dhcp6_poolspec* spec;
271 struct pool_conf* pool;
273 spec = (struct dhcp6_poolspec *)cfl->ptr;
275 for (pool = pool_conflist0; pool; pool = pool->next)
276 if (strcmp(spec->name, pool->name) == 0)
277 break;
278 if (pool == NULL) {
279 dprintf(LOG_ERR, FNAME, "%s:%d "
280 "pool '%s' not found",
281 configfilename, cfl->line,
282 spec->name);
283 goto bad;
285 if (spec->vltime != DHCP6_DURATION_INFINITE &&
286 (spec->pltime == DHCP6_DURATION_INFINITE ||
287 spec->pltime > spec->vltime)) {
288 dprintf(LOG_ERR, FNAME, "%s:%d ",
289 configfilename, cfl->line,
290 "specified a larger preferred lifetime "
291 "than valid lifetime");
292 goto bad;
294 ifc->pool = *spec;
295 if ((ifc->pool.name = strdup(spec->name)) == NULL) {
296 dprintf(LOG_ERR, FNAME,
297 "memory allocation failed");
298 goto bad;
300 dprintf(LOG_DEBUG, FNAME,
301 "pool '%s' is specified to the interface '%s'",
302 ifc->pool.name, ifc->ifname);
304 break;
305 default:
306 dprintf(LOG_ERR, FNAME, "%s:%d "
307 "invalid interface configuration",
308 configfilename, cfl->line);
309 goto bad;
314 return (0);
316 bad:
317 clear_ifconf(dhcp6_ifconflist);
318 dhcp6_ifconflist = NULL;
319 return (-1);
323 configure_ia(ialist, iatype)
324 struct cf_namelist *ialist;
325 iatype_t iatype;
327 struct cf_namelist *iap;
328 struct ia_conf *iac = NULL;
329 size_t confsize;
330 static int init = 1;
332 if (init) {
333 TAILQ_INIT(&ia_conflist0);
334 init = 0;
337 switch(iatype) {
338 case IATYPE_PD:
339 confsize = sizeof(struct iapd_conf);
340 break;
341 case IATYPE_NA:
342 confsize = sizeof(struct iana_conf);
343 break;
344 default:
345 dprintf(LOG_ERR, FNAME, "internal error");
346 goto bad;
349 for (iap = ialist; iap; iap = iap->next) {
350 struct cf_list *cfl;
352 if ((iac = malloc(confsize)) == NULL) {
353 dprintf(LOG_ERR, FNAME,
354 "memory allocation for IA %s failed",
355 iap->name);
356 goto bad;
358 memset(iac, 0, confsize);
360 /* common initialization */
361 iac->type = iatype;
362 iac->iaid = (u_int32_t)atoi(iap->name);
363 TAILQ_INIT(&iac->iadata);
364 TAILQ_INSERT_TAIL(&ia_conflist0, iac, link);
366 /* IA-type specific initialization */
367 switch(iatype) {
368 case IATYPE_PD:
369 TAILQ_INIT(&((struct iapd_conf *)iac)->iapd_prefix_list);
370 TAILQ_INIT(&((struct iapd_conf *)iac)->iapd_pif_list);
371 break;
372 case IATYPE_NA:
373 TAILQ_INIT(&((struct iana_conf *)iac)->iana_address_list);
374 break;
377 /* set up parameters for the IA */
378 for (cfl = iap->params; cfl; cfl = cfl->next) {
379 struct iapd_conf *pdp = (struct iapd_conf *) iac;
380 struct iana_conf *nap = (struct iana_conf *) iac;
382 switch (iatype) {
383 case IATYPE_PD:
384 switch(cfl->type) {
385 case IACONF_PIF:
386 if (add_pd_pif(pdp, cfl))
387 goto bad;
388 break;
389 case IACONF_PREFIX:
390 if (add_prefix(&pdp->iapd_prefix_list,
391 "IAPD", DHCP6_LISTVAL_PREFIX6,
392 cfl->ptr)) {
393 dprintf(LOG_NOTICE, FNAME, "failed "
394 "to configure prefix");
395 goto bad;
397 break;
398 default:
399 dprintf(LOG_ERR, FNAME, "%s:%d "
400 "invalid configuration",
401 configfilename, cfl->line);
402 goto bad;
404 break;
405 case IATYPE_NA:
406 switch(cfl->type) {
407 case IACONF_ADDR:
408 if (add_prefix(&nap->iana_address_list,
409 "IANA", DHCP6_LISTVAL_STATEFULADDR6,
410 cfl->ptr)) {
411 dprintf(LOG_NOTICE, FNAME, "failed "
412 "to configure address");
413 goto bad;
415 break;
416 default:
417 dprintf(LOG_ERR, FNAME, "%s:%d "
418 "invalid configuration",
419 configfilename, cfl->line);
420 goto bad;
422 break;
423 default:
424 dprintf(LOG_ERR, FNAME, "%s:%d "
425 "invalid iatype %d",
426 configfilename, cfl->line, iatype);
427 goto bad;
432 return (0);
434 bad:
435 return (-1);
438 static int
439 add_pd_pif(iapdc, cfl0)
440 struct iapd_conf *iapdc;
441 struct cf_list *cfl0;
443 struct cf_list *cfl;
444 struct prefix_ifconf *pif;
446 /* duplication check */
447 for (pif = TAILQ_FIRST(&iapdc->iapd_pif_list); pif;
448 pif = TAILQ_NEXT(pif, link)) {
449 if (strcmp(pif->ifname, cfl0->ptr) == 0) {
450 dprintf(LOG_NOTICE, FNAME, "%s:%d "
451 "duplicated prefix interface: %s",
452 configfilename, cfl0->line, cfl0->ptr);
453 return (0); /* ignore it */
457 if ((pif = malloc(sizeof(*pif))) == NULL) {
458 dprintf(LOG_ERR, FNAME,
459 "memory allocation for %s failed", cfl0->ptr);
460 goto bad;
462 memset(pif, 0, sizeof(*pif));
464 /* validate and copy ifname */
465 if (if_nametoindex(cfl0->ptr) == 0) {
466 dprintf(LOG_ERR, FNAME, "%s:%d invalid interface (%s): %s",
467 configfilename, cfl0->line,
468 cfl0->ptr, strerror(errno));
469 goto bad;
471 if ((pif->ifname = strdup(cfl0->ptr)) == NULL) {
472 dprintf(LOG_ERR, FNAME, "failed to copy ifname");
473 goto bad;
476 pif->ifid_len = IFID_LEN_DEFAULT;
477 pif->sla_len = SLA_LEN_DEFAULT;
478 if (get_default_ifid(pif)) {
479 dprintf(LOG_NOTICE, FNAME,
480 "failed to get default IF ID for %s", pif->ifname);
481 goto bad;
484 for (cfl = cfl0->list; cfl; cfl = cfl->next) {
485 switch(cfl->type) {
486 case IFPARAM_SLA_ID:
487 pif->sla_id = (u_int32_t)cfl->num;
488 break;
489 case IFPARAM_SLA_LEN:
490 pif->sla_len = (int)cfl->num;
491 if (pif->sla_len < 0 || pif->sla_len > 128) {
492 dprintf(LOG_ERR, FNAME, "%s:%d "
493 "invalid SLA length: %d",
494 configfilename, cfl->line, pif->sla_len);
495 goto bad;
497 break;
498 default:
499 dprintf(LOG_ERR, FNAME, "%s:%d internal error: "
500 "invalid configuration",
501 configfilename, cfl->line);
502 goto bad;
506 TAILQ_INSERT_TAIL(&iapdc->iapd_pif_list, pif, link);
507 return (0);
509 bad:
510 if (pif->ifname)
511 free(pif->ifname);
512 free(pif);
513 return (-1);
517 configure_host(hostlist)
518 struct cf_namelist *hostlist;
520 struct cf_namelist *host;
521 struct host_conf *hconf;
523 for (host = hostlist; host; host = host->next) {
524 struct cf_list *cfl;
526 if ((hconf = malloc(sizeof(*hconf))) == NULL) {
527 dprintf(LOG_ERR, FNAME, "memory allocation failed "
528 "for host %s", host->name);
529 goto bad;
531 memset(hconf, 0, sizeof(*hconf));
532 TAILQ_INIT(&hconf->prefix_list);
533 TAILQ_INIT(&hconf->addr_list);
534 hconf->next = host_conflist0;
535 host_conflist0 = hconf;
537 if ((hconf->name = strdup(host->name)) == NULL) {
538 dprintf(LOG_ERR, FNAME, "failed to copy host name: %s",
539 host->name);
540 goto bad;
543 for (cfl = host->params; cfl; cfl = cfl->next) {
544 switch(cfl->type) {
545 case DECL_DUID:
546 if (hconf->duid.duid_id) {
547 dprintf(LOG_ERR, FNAME, "%s:%d "
548 "duplicated DUID for %s",
549 configfilename,
550 cfl->line, host->name);
551 goto bad;
553 if ((configure_duid((char *)cfl->ptr,
554 &hconf->duid)) != 0) {
555 dprintf(LOG_ERR, FNAME, "%s:%d "
556 "failed to configure "
557 "DUID for %s",
558 configfilename, cfl->line,
559 host->name);
560 goto bad;
562 dprintf(LOG_DEBUG, FNAME,
563 "configure DUID for %s: %s",
564 host->name, duidstr(&hconf->duid));
565 break;
566 case DECL_PREFIX:
567 if (add_prefix(&hconf->prefix_list,
568 hconf->name, DHCP6_LISTVAL_PREFIX6,
569 cfl->ptr)) {
570 dprintf(LOG_ERR, FNAME, "failed "
571 "to configure prefix for %s",
572 host->name);
573 goto bad;
575 break;
576 case DECL_ADDRESS:
577 if (add_prefix(&hconf->addr_list,
578 hconf->name, DHCP6_LISTVAL_STATEFULADDR6,
579 cfl->ptr)) {
580 dprintf(LOG_ERR, FNAME, "failed "
581 "to configure address for %s",
582 host->name);
583 goto bad;
585 break;
586 case DECL_DELAYEDKEY:
587 if (hconf->delayedkey != NULL) {
588 dprintf(LOG_WARNING, FNAME,
589 "%s:%d: duplicate key %s for %s"
590 " (ignored)", configfilename,
591 cfl->line, cfl->ptr, host->name);
592 continue;
594 if ((hconf->delayedkey =
595 find_keybyname(key_list0, cfl->ptr))
596 == NULL) {
597 dprintf(LOG_ERR, FNAME, "failed to "
598 "find key information for %s",
599 cfl->ptr);
600 goto bad;
602 dprintf(LOG_DEBUG, FNAME, "configure key for "
603 "delayed auth with %s (keyid=%08x)",
604 host->name, hconf->delayedkey->keyid);
605 break;
606 case DECL_ADDRESSPOOL:
608 struct dhcp6_poolspec* spec;
609 struct pool_conf *pool;
611 spec = (struct dhcp6_poolspec *)cfl->ptr;
613 for (pool = pool_conflist0; pool; pool = pool->next)
614 if (strcmp(spec->name, pool->name) == 0)
615 break;
616 if (pool == NULL) {
617 dprintf(LOG_ERR, FNAME, "%s:%d "
618 "pool '%s' not found",
619 configfilename, cfl->line,
620 spec->name);
621 goto bad;
623 if (spec->vltime != DHCP6_DURATION_INFINITE &&
624 (spec->pltime == DHCP6_DURATION_INFINITE ||
625 spec->pltime > spec->vltime)) {
626 dprintf(LOG_ERR, FNAME, "%s:%d ",
627 configfilename, cfl->line,
628 "specified a larger preferred lifetime "
629 "than valid lifetime");
630 goto bad;
632 hconf->pool = *spec;
633 if ((hconf->pool.name = strdup(spec->name)) == NULL) {
634 dprintf(LOG_ERR, FNAME,
635 "memory allocation failed");
636 goto bad;
638 dprintf(LOG_DEBUG, FNAME,
639 "pool '%s' is specified to the host '%s'",
640 hconf->pool.name, hconf->name);
642 break;
643 default:
644 dprintf(LOG_ERR, FNAME, "%s:%d "
645 "invalid host configuration for %s",
646 configfilename, cfl->line,
647 host->name);
648 goto bad;
653 return (0);
655 bad:
656 /* there is currently nothing special to recover the error */
657 return (-1);
661 configure_keys(keylist)
662 struct cf_namelist *keylist;
664 struct cf_namelist *key;
665 char *secretstr;
666 char secret[1024];
667 int secretlen;
668 struct keyinfo *kinfo;
669 long long keyid;
670 char *expire = NULL;
672 for (key = keylist; key; key = key->next) {
673 struct cf_list *cfl;
675 if ((kinfo = malloc(sizeof(*kinfo))) == NULL) {
676 dprintf(LOG_ERR, FNAME, "memory allocation failed "
677 "for key %s", key->name);
678 goto bad;
680 memset(kinfo, 0, sizeof(*kinfo));
681 kinfo->next = key_list0;
682 key_list0 = kinfo;
684 if ((kinfo->name = strdup(key->name)) == NULL) {
685 dprintf(LOG_ERR, FNAME, "failed to copy key name: %s",
686 key->name);
687 goto bad;
690 keyid = -1;
691 expire = NULL;
692 for (cfl = key->params; cfl; cfl = cfl->next) {
693 switch (cfl->type) {
694 case KEYPARAM_REALM:
695 if (kinfo->realm != NULL) {
696 dprintf(LOG_WARNING, FNAME,
697 "%s:%d duplicate realm for key %s "
698 "(ignored)", configfilename,
699 cfl->line, key->name);
700 continue;
702 kinfo->realm = qstrdup(cfl->ptr);
703 if (kinfo->realm == NULL) {
704 dprintf(LOG_WARNING, FNAME,
705 "failed to allocate memory for "
706 "realm");
707 goto bad;
709 kinfo->realmlen = strlen(kinfo->realm);
710 break;
711 case KEYPARAM_KEYID:
712 if (keyid != -1) {
713 dprintf(LOG_WARNING, FNAME,
714 "%s:%d duplicate realm for key %s "
715 "(ignored)",
716 configfilename, cfl->line);
717 continue;
719 keyid = cfl->num;
720 if (keyid < 0 || keyid > 0xffffffff) {
721 dprintf(LOG_WARNING, FNAME,
722 "%s:%d key ID overflow",
723 configfilename, cfl->line);
724 goto bad;
726 break;
727 case KEYPARAM_SECRET:
728 /* duplicate check */
729 if (kinfo->secret != NULL) {
730 dprintf(LOG_WARNING, FNAME,
731 "%s:%d duplicate secret "
732 "for key %s (ignored)",
733 configfilename, cfl->line,
734 key->name);
735 continue; /* ignored */
738 /* convert base64 string to binary secret */
739 if ((secretstr = qstrdup(cfl->ptr)) == NULL) {
740 dprintf(LOG_WARNING, FNAME,
741 "failed to make a copy of secret");
742 goto bad;
744 memset(secret, 0, sizeof(secret));
745 secretlen = base64_decodestring(secretstr,
746 secret, sizeof(secret));
747 if (secretlen < 0) {
748 dprintf(LOG_ERR, FNAME,
749 "%s:%d failed to parse base64 key",
750 configfilename, cfl->line);
751 free(secretstr);
752 goto bad;
754 free(secretstr);
756 /* set the binary secret */
757 kinfo->secret = malloc(secretlen);
758 if (kinfo->secret == NULL) {
759 dprintf(LOG_WARNING, FNAME,
760 "failed to allocate memory "
761 "for secret");
762 goto bad;
764 memcpy(kinfo->secret, secret, secretlen);
765 kinfo->secretlen = secretlen;
766 break;
767 case KEYPARAM_EXPIRE:
768 if (expire != NULL) {
769 dprintf(LOG_WARNING, FNAME,
770 "%s:%d duplicate expire for key "
771 "%s (ignored)", configfilename,
772 cfl->line, key->name);
773 continue;
775 expire = qstrdup(cfl->ptr);
776 break;
777 default:
778 dprintf(LOG_ERR, FNAME,
779 "%s:%d invalid key parameter for %s",
780 configfilename, cfl->line, key->name);
781 goto bad;
785 /* check for mandatory parameters or use default */
786 if (kinfo->realm == NULL) {
787 dprintf(LOG_ERR, FNAME,
788 "realm not specified for key %s", key->name);
789 goto bad;
791 if (keyid == -1) {
792 dprintf(LOG_ERR, FNAME,
793 "key ID not specified for key %s", key->name);
794 goto bad;
796 kinfo->keyid = keyid;
797 if (kinfo->secret == NULL) {
798 dprintf(LOG_ERR, FNAME,
799 "secret not specified for key %s", key->name);
800 goto bad;
802 kinfo->expire = 0;
803 if (expire != NULL) {
804 if (strcmp(expire, "forever") != 0) {
805 time_t now, expire_time;
806 struct tm *lt;
808 if (time(&now) == -1) {
809 dprintf(LOG_ERR, FNAME, "cannot get "
810 "current time: %s",
811 strerror(errno));
812 goto bad;
814 lt = localtime(&now);
815 lt->tm_sec = 0;
817 if (strptime(expire, "%Y-%m-%d %H:%M", lt)
818 == NULL &&
819 strptime(expire, "%m-%d %H:%M", lt)
820 == NULL &&
821 strptime(expire, "%H:%M", lt) == NULL) {
822 dprintf(LOG_ERR, FNAME, "invalid "
823 "expiration time: %s");
824 goto bad;
827 expire_time = mktime(lt);
828 if (expire_time < now) {
829 dprintf(LOG_ERR, FNAME, "past "
830 "expiration time specified: %s",
831 expire);
832 goto bad;
835 kinfo->expire = expire_time;
840 return (0);
842 bad:
843 if (expire != NULL)
844 free(expire);
845 return (-1);
848 static struct keyinfo *
849 find_keybyname(head, kname)
850 struct keyinfo *head;
851 char *kname;
853 struct keyinfo *kinfo;
855 for (kinfo = head; kinfo != NULL; kinfo = kinfo->next) {
856 if (strcmp(kname, kinfo->name) == 0)
857 return (kinfo);
860 return (NULL);
864 configure_authinfo(authlist)
865 struct cf_namelist *authlist;
867 struct cf_namelist *auth;
868 struct authinfo *ainfo;
870 for (auth = authlist; auth; auth = auth->next) {
871 struct cf_list *cfl;
873 if ((ainfo = malloc(sizeof(*ainfo))) == NULL) {
874 dprintf(LOG_ERR, FNAME, "memory allocation failed "
875 "for auth info %s", auth->name);
876 goto bad;
878 memset(ainfo, 0, sizeof(*ainfo));
879 ainfo->next = auth_list0;
880 auth_list0 = ainfo;
881 ainfo->protocol = DHCP6_AUTHPROTO_UNDEF;
882 ainfo->algorithm = DHCP6_AUTHALG_UNDEF;
883 ainfo->rdm = DHCP6_AUTHRDM_UNDEF;
885 if ((ainfo->name = strdup(auth->name)) == NULL) {
886 dprintf(LOG_ERR, FNAME,
887 "failed to copy auth info name: %s", auth->name);
888 goto bad;
891 for (cfl = auth->params; cfl; cfl = cfl->next) {
892 switch (cfl->type) {
893 case AUTHPARAM_PROTO:
894 if (ainfo->protocol != DHCP6_AUTHPROTO_UNDEF) {
895 dprintf(LOG_WARNING, FNAME,
896 "%s:%d duplicate protocol "
897 "for auth info %s "
898 "(ignored)",
899 configfilename, cfl->line,
900 auth->name);
901 continue; /* ignored */
903 ainfo->protocol = (int)cfl->num;
904 break;
905 case AUTHPARAM_ALG:
906 if (ainfo->algorithm != DHCP6_AUTHALG_UNDEF) {
907 dprintf(LOG_WARNING, FNAME,
908 "%s:%d duplicate algorithm "
909 "for auth info %s "
910 "(ignored)",
911 configfilename, cfl->line,
912 auth->name);
913 continue; /* ignored */
915 ainfo->algorithm = (int)cfl->num;
916 break;
917 case AUTHPARAM_RDM:
918 if (ainfo->rdm != DHCP6_AUTHRDM_UNDEF) {
919 dprintf(LOG_WARNING, FNAME,
920 "%s:%d duplicate RDM "
921 "for auth info %s "
922 "(ignored)",
923 configfilename, cfl->line,
924 auth->name);
925 continue; /* ignored */
927 ainfo->rdm = (int)cfl->num;
928 break;
929 case AUTHPARAM_KEY:
930 dprintf(LOG_WARNING, FNAME,
931 "%s:%d auth info specific keys "
932 "are not supported",
933 configfilename, cfl->line);
934 break;
935 default:
936 dprintf(LOG_ERR, FNAME,
937 "%s:%d invalid auth info parameter for %s",
938 configfilename, cfl->line, auth->name);
939 goto bad;
943 /* check for mandatory parameters and consistency */
944 switch (ainfo->protocol) {
945 case DHCP6_AUTHPROTO_UNDEF:
946 dprintf(LOG_ERR, FNAME,
947 "auth protocol is not specified for %s",
948 auth->name);
949 goto bad;
950 case DHCP6_AUTHPROTO_DELAYED:
951 if (dhcp6_mode != DHCP6_MODE_CLIENT) {
952 dprintf(LOG_ERR, FNAME,
953 "client-only auth protocol is specified");
954 goto bad;
956 break;
957 case DHCP6_AUTHPROTO_RECONFIG:
958 if (dhcp6_mode != DHCP6_MODE_SERVER) {
959 dprintf(LOG_ERR, FNAME,
960 "server-only auth protocol is specified");
961 goto bad;
963 break;
965 if (ainfo->algorithm == DHCP6_AUTHALG_UNDEF)
966 ainfo->algorithm = DHCP6_AUTHALG_HMACMD5;
967 if (ainfo->rdm == DHCP6_AUTHRDM_UNDEF)
968 ainfo->rdm = DHCP6_AUTHRDM_MONOCOUNTER;
971 return (0);
973 bad:
974 /* there is currently nothing special to recover the error */
975 return (-1);
979 configure_global_option()
981 /* SIP Server address */
982 if (configure_addr(cf_sip_list, &siplist0, "SIP") < 0)
983 goto bad;
985 /* SIP domain name */
986 if (configure_domain(cf_sip_name_list, &sipnamelist0, "SIP") < 0)
987 goto bad;
989 /* DNS servers */
990 if (configure_addr(cf_dns_list, &dnslist0, "DNS") < 0)
991 goto bad;
993 /* DNS name */
994 if (configure_domain(cf_dns_name_list, &dnsnamelist0, "DNS") < 0)
995 goto bad;
997 /* NTP servers */
998 if (configure_addr(cf_ntp_list, &ntplist0, "NTP") < 0)
999 goto bad;
1001 /* NIS Server address */
1002 if (configure_addr(cf_nis_list, &nislist0, "NIS") < 0)
1003 goto bad;
1005 /* NIS domain name */
1006 if (configure_domain(cf_nis_name_list, &nisnamelist0, "NIS") < 0)
1007 goto bad;
1009 /* NIS+ Server address */
1010 if (configure_addr(cf_nisp_list, &nisplist0, "NISP") < 0)
1011 goto bad;
1013 /* NIS+ domain name */
1014 if (configure_domain(cf_nisp_name_list, &nispnamelist0, "NISP") < 0)
1015 goto bad;
1017 /* BCMCS Server address */
1018 if (configure_addr(cf_bcmcs_list, &bcmcslist0, "BCMCS") < 0)
1019 goto bad;
1021 /* BCMCS domain name */
1022 if (configure_domain(cf_bcmcs_name_list, &bcmcsnamelist0, "BCMCS") < 0)
1023 goto bad;
1025 /* Lifetime for stateless options */
1026 if (cf_refreshtime >= 0) {
1027 optrefreshtime0 = cf_refreshtime;
1030 return (0);
1032 bad:
1033 return (-1); /* no need to free intermediate list */
1036 static int
1037 configure_addr(cf_addr_list, list0, optname)
1038 struct cf_list *cf_addr_list;
1039 struct dhcp6_list *list0;
1040 char *optname;
1042 struct cf_list *cl;
1044 /* check against configuration restriction */
1045 if (cf_addr_list != NULL && dhcp6_mode != DHCP6_MODE_SERVER) {
1046 dprintf(LOG_INFO, FNAME, "%s:%d server-only configuration",
1047 configfilename, cf_addr_list->line);
1048 return -1;
1051 TAILQ_INIT(list0);
1052 for (cl = cf_addr_list; cl; cl = cl->next) {
1053 /* duplication check */
1054 if (dhcp6_find_listval(list0, DHCP6_LISTVAL_ADDR6,
1055 cl->ptr, 0)) {
1056 dprintf(LOG_INFO, FNAME,
1057 "%s:%d duplicated %s server: %s",
1058 configfilename, cl->line,
1059 optname,
1060 in6addr2str((struct in6_addr *)cl->ptr, 0));
1061 return -1;
1063 if (dhcp6_add_listval(list0, DHCP6_LISTVAL_ADDR6,
1064 cl->ptr, NULL) == NULL) {
1065 dprintf(LOG_ERR, FNAME, "failed to add a %s server",
1066 optname);
1067 return -1;
1071 return 0;
1074 static int
1075 configure_domain(cf_name_list, list0, optname)
1076 struct cf_list *cf_name_list;
1077 struct dhcp6_list *list0;
1078 char *optname;
1080 struct cf_list *cl;
1082 /* check against configuration restriction */
1083 if (cf_name_list != NULL && dhcp6_mode != DHCP6_MODE_SERVER) {
1084 dprintf(LOG_INFO, FNAME, "%s:%d server-only configuration",
1085 configfilename, cf_name_list->line);
1086 return -1;
1089 TAILQ_INIT(list0);
1090 for (cl = cf_name_list; cl; cl = cl->next) {
1091 char *name, *cp;
1092 struct dhcp6_vbuf name_vbuf;
1094 name = strdup(cl->ptr + 1);
1095 if (name == NULL) {
1096 dprintf(LOG_ERR, FNAME,
1097 "failed to copy a %s domain name",
1098 optname);
1099 return -1;
1101 cp = name + strlen(name) - 1;
1102 *cp = '\0'; /* clear the terminating quote */
1104 name_vbuf.dv_buf = name;
1105 name_vbuf.dv_len = strlen(name) + 1;
1107 /* duplication check */
1108 if (dhcp6_find_listval(list0, DHCP6_LISTVAL_VBUF,
1109 &name_vbuf, 0)) {
1110 dprintf(LOG_INFO, FNAME,
1111 "%s:%d duplicated %s name: %s",
1112 configfilename, cl->line, optname,
1113 name_vbuf.dv_buf);
1114 dhcp6_vbuf_free(&name_vbuf);
1115 return -1;
1118 /* add the name */
1119 if (dhcp6_add_listval(list0, DHCP6_LISTVAL_VBUF,
1120 &name_vbuf, NULL) == NULL) {
1121 dprintf(LOG_ERR, FNAME, "failed to add a %s name",
1122 optname);
1123 dhcp6_vbuf_free(&name_vbuf);
1124 return -1;
1126 dhcp6_vbuf_free(&name_vbuf);
1129 return 0;
1132 static int
1133 configure_duid(str, duid)
1134 char *str; /* this is a valid DUID string */
1135 struct duid *duid;
1137 char *cp, *bp;
1138 char *idbuf = NULL;
1139 int duidlen, slen;
1140 unsigned int x;
1142 /* calculate DUID len */
1143 slen = strlen(str);
1144 if (slen < 2)
1145 goto bad;
1146 duidlen = 1;
1147 slen -= 2;
1148 if ((slen % 3) != 0)
1149 goto bad;
1150 duidlen += (slen / 3);
1151 if (duidlen > 128) {
1152 dprintf(LOG_ERR, FNAME, "too long DUID (%d)", duidlen);
1153 return (-1);
1156 if ((idbuf = malloc(duidlen)) == NULL) {
1157 dprintf(LOG_ERR, FNAME, "memory allocation failed");
1158 return (-1);
1161 for (cp = str, bp = idbuf; *cp;) {
1162 if (*cp == ':') {
1163 cp++;
1164 continue;
1167 if (sscanf(cp, "%02x", &x) != 1)
1168 goto bad;
1169 *bp = x;
1170 cp += 2;
1171 bp++;
1174 duid->duid_len = duidlen;
1175 duid->duid_id = idbuf;
1177 return (0);
1179 bad:
1180 if (idbuf)
1181 free(idbuf);
1182 dprintf(LOG_ERR, FNAME, "assumption failure (bad string)");
1183 return (-1);
1186 /* we currently only construct EUI-64 based interface ID */
1187 static int
1188 get_default_ifid(pif)
1189 struct prefix_ifconf *pif;
1191 struct ifaddrs *ifa, *ifap;
1192 #ifdef __KAME__
1193 struct sockaddr_dl *sdl;
1194 #endif
1195 #ifdef __linux__
1196 struct sockaddr_ll *sll;
1197 #endif
1199 if (pif->ifid_len < 64) {
1200 dprintf(LOG_NOTICE, FNAME, "ID length too short");
1201 return (-1);
1204 if (getifaddrs(&ifap) < 0) {
1205 dprintf(LOG_ERR, FNAME, "getifaddrs failed: %s",
1206 strerror(errno));
1207 return (-1);
1210 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1211 char *cp;
1213 if (strcmp(ifa->ifa_name, pif->ifname) != 0)
1214 continue;
1216 if (ifa->ifa_addr == NULL)
1217 continue;
1219 #ifdef __KAME__
1220 if (ifa->ifa_addr->sa_family != AF_LINK)
1221 continue;
1223 sdl = (struct sockaddr_dl *)ifa->ifa_addr;
1224 if (sdl->sdl_alen < 6) {
1225 dprintf(LOG_NOTICE, FNAME,
1226 "link layer address is too short (%s)",
1227 pif->ifname);
1228 goto fail;
1231 memset(pif->ifid, 0, sizeof(pif->ifid));
1232 cp = (char *)(sdl->sdl_data + sdl->sdl_nlen);
1233 #endif
1234 #ifdef __linux__
1235 if (ifa->ifa_addr->sa_family != AF_PACKET)
1236 continue;
1238 sll = (struct sockaddr_ll *)ifa->ifa_addr;
1239 if (sll->sll_halen < 6) {
1240 dprintf(LOG_NOTICE, FNAME,
1241 "link layer address is too short (%s)",
1242 pif->ifname);
1243 goto fail;
1246 memset(pif->ifid, 0, sizeof(pif->ifid));
1247 cp = (char *)(sll->sll_addr);
1248 #endif
1249 pif->ifid[8] = cp[0];
1250 pif->ifid[8] ^= 0x02; /* reverse the u/l bit*/
1251 pif->ifid[9] = cp[1];
1252 pif->ifid[10] = cp[2];
1253 pif->ifid[11] = 0xff;
1254 pif->ifid[12] = 0xfe;
1255 pif->ifid[13] = cp[3];
1256 pif->ifid[14] = cp[4];
1257 pif->ifid[15] = cp[5];
1259 break;
1262 if (ifa == NULL) {
1263 dprintf(LOG_INFO, FNAME,
1264 "cannot find interface information for %s", pif->ifname);
1265 goto fail;
1268 freeifaddrs(ifap);
1269 return (0);
1271 fail:
1272 freeifaddrs(ifap);
1273 return (-1);
1276 void
1277 configure_cleanup()
1279 clear_iaconf(&ia_conflist0);
1280 clear_ifconf(dhcp6_ifconflist);
1281 dhcp6_ifconflist = NULL;
1282 clear_hostconf(host_conflist0);
1283 host_conflist0 = NULL;
1284 clear_keys(key_list0);
1285 key_list0 = NULL;
1286 clear_authinfo(auth_list0);
1287 auth_list0 = NULL;
1289 dhcp6_clear_list(&siplist0);
1290 TAILQ_INIT(&siplist0);
1291 dhcp6_clear_list(&sipnamelist0);
1292 TAILQ_INIT(&sipnamelist0);
1293 dhcp6_clear_list(&dnslist0);
1294 TAILQ_INIT(&dnslist0);
1295 dhcp6_clear_list(&dnsnamelist0);
1296 TAILQ_INIT(&dnsnamelist0);
1297 dhcp6_clear_list(&ntplist0);
1298 TAILQ_INIT(&ntplist0);
1299 optrefreshtime0 = -1;
1300 clear_poolconf(pool_conflist0);
1303 void
1304 configure_commit()
1306 struct dhcp6_ifconf *ifc;
1307 struct dhcp6_if *ifp;
1308 struct ia_conf *iac;
1310 /* commit interface configuration */
1311 for (ifp = dhcp6_if; ifp; ifp = ifp->next) {
1312 /* re-initialization */
1313 ifp->send_flags = 0;
1314 ifp->allow_flags = 0;
1315 dhcp6_clear_list(&ifp->reqopt_list);
1316 clear_iaconf(&ifp->iaconf_list);
1317 ifp->server_pref = DH6OPT_PREF_UNDEF;
1318 if (ifp->scriptpath != NULL)
1319 free(ifp->scriptpath);
1320 ifp->scriptpath = NULL;
1321 ifp->authproto = DHCP6_AUTHPROTO_UNDEF;
1322 ifp->authalgorithm = DHCP6_AUTHALG_UNDEF;
1323 ifp->authrdm = DHCP6_AUTHRDM_UNDEF;
1325 for (ifc = dhcp6_ifconflist; ifc; ifc = ifc->next) {
1326 if (strcmp(ifp->ifname, ifc->ifname) == 0)
1327 break;
1329 if (ifc == NULL)
1330 continue;
1332 /* copy new configuration */
1333 ifp->send_flags = ifc->send_flags;
1334 ifp->allow_flags = ifc->allow_flags;
1335 dhcp6_copy_list(&ifp->reqopt_list, &ifc->reqopt_list);
1336 while ((iac = TAILQ_FIRST(&ifc->iaconf_list)) != NULL) {
1337 TAILQ_REMOVE(&ifc->iaconf_list, iac, link);
1338 TAILQ_INSERT_TAIL(&ifp->iaconf_list,
1339 iac, link);
1341 ifp->server_pref = ifc->server_pref;
1342 ifp->scriptpath = ifc->scriptpath;
1343 ifc->scriptpath = NULL;
1345 if (ifc->authinfo != NULL) {
1346 ifp->authproto = ifc->authinfo->protocol;
1347 ifp->authalgorithm = ifc->authinfo->algorithm;
1348 ifp->authrdm = ifc->authinfo->rdm;
1350 ifp->pool = ifc->pool;
1351 ifc->pool.name = NULL;
1354 clear_ifconf(dhcp6_ifconflist);
1355 dhcp6_ifconflist = NULL;
1357 /* clear unused IA configuration */
1358 if (!TAILQ_EMPTY(&ia_conflist0)) {
1359 dprintf(LOG_INFO, FNAME,
1360 "some IA configuration defined but not used");
1362 clear_iaconf(&ia_conflist0);
1364 /* commit per-host configuration */
1365 clear_hostconf(host_conflist);
1366 host_conflist = host_conflist0;
1367 host_conflist0 = NULL;
1369 /* commit secret key information */
1370 clear_keys(key_list);
1371 key_list = key_list0;
1372 key_list0 = NULL;
1374 /* commit authentication information */
1375 clear_authinfo(auth_list);
1376 auth_list = auth_list0;
1377 auth_list0 = NULL;
1379 /* commit SIP server addresses */
1380 dhcp6_clear_list(&siplist);
1381 dhcp6_move_list(&siplist, &siplist0);
1383 /* commit SIP domain names */
1384 dhcp6_clear_list(&sipnamelist);
1385 dhcp6_move_list(&sipnamelist, &sipnamelist0);
1387 /* commit DNS addresses */
1388 dhcp6_clear_list(&dnslist);
1389 dhcp6_move_list(&dnslist, &dnslist0);
1391 /* commit DNS names */
1392 dhcp6_clear_list(&dnsnamelist);
1393 dhcp6_move_list(&dnsnamelist, &dnsnamelist0);
1395 /* commit NTP addresses */
1396 dhcp6_clear_list(&ntplist);
1397 dhcp6_move_list(&ntplist, &ntplist0);
1399 /* commit NIS server addresses */
1400 dhcp6_clear_list(&nislist);
1401 dhcp6_move_list(&nislist, &nislist0);
1403 /* commit NIS domain names */
1404 dhcp6_clear_list(&nisnamelist);
1405 dhcp6_move_list(&nisnamelist, &nisnamelist0);
1407 /* commit NIS+ server addresses */
1408 dhcp6_clear_list(&nisplist);
1409 dhcp6_move_list(&nisplist, &nisplist0);
1411 /* commit NIS+ domain names */
1412 dhcp6_clear_list(&nispnamelist);
1413 dhcp6_move_list(&nispnamelist, &nispnamelist0);
1415 /* commit BCMCS server addresses */
1416 dhcp6_clear_list(&bcmcslist);
1417 dhcp6_move_list(&bcmcslist, &bcmcslist0);
1419 /* commit BCMCS domain names */
1420 dhcp6_clear_list(&bcmcsnamelist);
1421 dhcp6_move_list(&bcmcsnamelist, &bcmcsnamelist0);
1423 /* commit information refresh time */
1424 optrefreshtime = optrefreshtime0;
1425 /* commit pool configuration */
1426 clear_poolconf(pool_conflist);
1427 pool_conflist = pool_conflist0;
1428 pool_conflist0 = NULL;
1431 static void
1432 clear_ifconf(iflist)
1433 struct dhcp6_ifconf *iflist;
1435 struct dhcp6_ifconf *ifc, *ifc_next;
1437 for (ifc = iflist; ifc; ifc = ifc_next) {
1438 ifc_next = ifc->next;
1440 free(ifc->ifname);
1441 dhcp6_clear_list(&ifc->reqopt_list);
1443 clear_iaconf(&ifc->iaconf_list);
1445 if (ifc->scriptpath)
1446 free(ifc->scriptpath);
1448 if (ifc->pool.name)
1449 free(ifc->pool.name);
1450 free(ifc);
1454 static void
1455 clear_pd_pif(iapdc)
1456 struct iapd_conf *iapdc;
1458 struct prefix_ifconf *pif, *pif_next;
1460 for (pif = TAILQ_FIRST(&iapdc->iapd_pif_list); pif; pif = pif_next) {
1461 pif_next = TAILQ_NEXT(pif, link);
1463 free(pif->ifname);
1464 free(pif);
1467 dhcp6_clear_list(&iapdc->iapd_prefix_list);
1470 static void
1471 clear_iaconf(ialist)
1472 struct ia_conflist *ialist;
1474 struct ia_conf *iac;
1476 while ((iac = TAILQ_FIRST(ialist)) != NULL) {
1477 TAILQ_REMOVE(ialist, iac, link);
1479 switch(iac->type) {
1480 case IATYPE_PD:
1481 if (!TAILQ_EMPTY(&iac->iadata)) {
1482 dprintf(LOG_ERR, FNAME, "assumption failure");
1483 exit(1);
1485 clear_pd_pif((struct iapd_conf *)iac);
1486 break;
1487 case IATYPE_NA:
1488 break;
1490 free(iac);
1494 static void
1495 clear_hostconf(hlist)
1496 struct host_conf *hlist;
1498 struct host_conf *host, *host_next;
1500 for (host = hlist; host; host = host_next) {
1501 host_next = host->next;
1503 free(host->name);
1504 dhcp6_clear_list(&host->prefix_list);
1505 dhcp6_clear_list(&host->addr_list);
1506 if (host->duid.duid_id)
1507 free(host->duid.duid_id);
1508 if (host->pool.name)
1509 free(host->pool.name);
1510 free(host);
1514 static void
1515 clear_keys(klist)
1516 struct keyinfo *klist;
1518 struct keyinfo *key, *key_next;
1520 for (key = klist; key; key = key_next) {
1521 key_next = key->next;
1523 free(key->name);
1524 free(key->realm);
1525 free(key->secret);
1526 free(key);
1530 static void
1531 clear_authinfo(alist)
1532 struct authinfo *alist;
1534 struct authinfo *auth, *auth_next;
1536 for (auth = alist; auth; auth = auth_next) {
1537 auth_next = auth->next;
1538 free(auth);
1542 static int
1543 add_options(opcode, ifc, cfl0)
1544 int opcode;
1545 struct dhcp6_ifconf *ifc;
1546 struct cf_list *cfl0;
1548 struct cf_list *cfl;
1549 int opttype;
1550 struct authinfo *ainfo;
1551 struct ia_conf *iac;
1553 for (cfl = cfl0; cfl; cfl = cfl->next) {
1554 switch(cfl->type) {
1555 case DHCPOPT_RAPID_COMMIT:
1556 switch (opcode) {
1557 case DHCPOPTCODE_SEND:
1558 ifc->send_flags |= DHCIFF_RAPID_COMMIT;
1559 break;
1560 case DHCPOPTCODE_ALLOW:
1561 ifc->allow_flags |= DHCIFF_RAPID_COMMIT;
1562 break;
1563 default:
1564 dprintf(LOG_ERR, FNAME,
1565 "invalid operation (%d) "
1566 "for option type (%d)",
1567 opcode, cfl->type);
1568 return (-1);
1570 break;
1571 case DHCPOPT_AUTHINFO:
1572 if (opcode != DHCPOPTCODE_SEND) {
1573 dprintf(LOG_ERR, FNAME,
1574 "invalid operation (%d) "
1575 "for option type (%d)",
1576 opcode, cfl->type);
1577 return (-1);
1579 ainfo = find_authinfo(auth_list0, cfl->ptr);
1580 if (ainfo == NULL) {
1581 dprintf(LOG_ERR, FNAME, "%s:%d "
1582 "auth info (%s) is not defined",
1583 configfilename, cfl->line,
1584 (char *)cfl->ptr);
1585 return (-1);
1587 if (ifc->authinfo != NULL) {
1588 dprintf(LOG_ERR, FNAME,
1589 "%s:%d authinfo is doubly specified on %s",
1590 configfilename, cfl->line, ifc->ifname);
1591 return (-1);
1593 ifc->authinfo = ainfo;
1594 break;
1595 case DHCPOPT_IA_PD:
1596 switch (opcode) {
1597 case DHCPOPTCODE_SEND:
1598 iac = find_iaconf(&ia_conflist0, IATYPE_PD,
1599 (u_int32_t)cfl->num);
1600 if (iac == NULL) {
1601 dprintf(LOG_ERR, FNAME, "%s:%d "
1602 "IA_PD (%lu) is not defined",
1603 configfilename, cfl->line,
1604 (u_long)cfl->num);
1605 return (-1);
1608 TAILQ_REMOVE(&ia_conflist0, iac, link);
1609 TAILQ_INSERT_TAIL(&ifc->iaconf_list,
1610 iac, link);
1612 break;
1613 default:
1614 dprintf(LOG_ERR, FNAME,
1615 "invalid operation (%d) "
1616 "for option type (%d)", opcode, cfl->type);
1617 break;
1619 break;
1620 case DHCPOPT_IA_NA:
1621 switch (opcode) {
1622 case DHCPOPTCODE_SEND:
1623 iac = find_iaconf(&ia_conflist0, IATYPE_NA,
1624 (u_int32_t)cfl->num);
1625 if (iac == NULL) {
1626 dprintf(LOG_ERR, FNAME, "%s:%d "
1627 "IA_NA (%lu) is not defined",
1628 configfilename, cfl->line,
1629 (u_long)cfl->num);
1630 return (-1);
1633 TAILQ_REMOVE(&ia_conflist0, iac, link);
1634 TAILQ_INSERT_TAIL(&ifc->iaconf_list,
1635 iac, link);
1637 break;
1638 default:
1639 dprintf(LOG_ERR, FNAME,
1640 "invalid operation (%d) "
1641 "for option type (%d)", opcode, cfl->type);
1642 break;
1644 break;
1645 case DHCPOPT_SIP:
1646 case DHCPOPT_SIPNAME:
1647 case DHCPOPT_DNS:
1648 case DHCPOPT_DNSNAME:
1649 case DHCPOPT_NTP:
1650 case DHCPOPT_NIS:
1651 case DHCPOPT_NISNAME:
1652 case DHCPOPT_NISP:
1653 case DHCPOPT_NISPNAME:
1654 case DHCPOPT_BCMCS:
1655 case DHCPOPT_BCMCSNAME:
1656 case DHCPOPT_REFRESHTIME:
1657 switch (cfl->type) {
1658 case DHCPOPT_SIP:
1659 opttype = DH6OPT_SIP_SERVER_A;
1660 break;
1661 case DHCPOPT_SIPNAME:
1662 opttype = DH6OPT_SIP_SERVER_D;
1663 break;
1664 case DHCPOPT_DNS:
1665 opttype = DH6OPT_DNS;
1666 break;
1667 case DHCPOPT_DNSNAME:
1668 opttype = DH6OPT_DNSNAME;
1669 break;
1670 case DHCPOPT_NTP:
1671 opttype = DH6OPT_NTP;
1672 break;
1673 case DHCPOPT_NIS:
1674 opttype = DH6OPT_NIS_SERVERS;
1675 break;
1676 case DHCPOPT_NISNAME:
1677 opttype = DH6OPT_NIS_DOMAIN_NAME;
1678 break;
1679 case DHCPOPT_NISP:
1680 opttype = DH6OPT_NISP_SERVERS;
1681 break;
1682 case DHCPOPT_NISPNAME:
1683 opttype = DH6OPT_NISP_DOMAIN_NAME;
1684 break;
1685 case DHCPOPT_BCMCS:
1686 opttype = DH6OPT_BCMCS_SERVER_A;
1687 break;
1688 case DHCPOPT_BCMCSNAME:
1689 opttype = DH6OPT_BCMCS_SERVER_D;
1690 break;
1691 case DHCPOPT_REFRESHTIME:
1692 opttype = DH6OPT_REFRESHTIME;
1693 break;
1695 switch(opcode) {
1696 case DHCPOPTCODE_REQUEST:
1697 if (dhcp6_find_listval(&ifc->reqopt_list,
1698 DHCP6_LISTVAL_NUM, &opttype, 0)
1699 != NULL) {
1700 dprintf(LOG_INFO, FNAME,
1701 "duplicated requested option: %s",
1702 dhcp6optstr(opttype));
1703 goto next; /* ignore it */
1705 if (dhcp6_add_listval(&ifc->reqopt_list,
1706 DHCP6_LISTVAL_NUM, &opttype, NULL)
1707 == NULL) {
1708 dprintf(LOG_ERR, FNAME, "failed to "
1709 "configure an option");
1710 return (-1);
1712 break;
1713 default:
1714 dprintf(LOG_ERR, FNAME,
1715 "invalid operation (%d) "
1716 "for option type (%d)", opcode, cfl->type);
1717 break;
1719 break;
1720 default:
1721 dprintf(LOG_ERR, FNAME,
1722 "%s:%d unsupported option type: %d",
1723 configfilename, cfl->line, cfl->type);
1724 return (-1);
1727 next:
1731 return (0);
1734 static int
1735 add_prefix(head, name, type, prefix0)
1736 struct dhcp6_list *head;
1737 char *name;
1738 int type;
1739 struct dhcp6_prefix *prefix0;
1741 struct dhcp6_prefix oprefix;
1743 oprefix = *prefix0;
1745 /* additional validation of parameters */
1746 if (oprefix.plen < 4 || oprefix.plen > 128) {
1747 dprintf(LOG_ERR, FNAME, "invalid prefix: %d", oprefix.plen);
1748 return (-1);
1750 /* clear trailing bits */
1751 prefix6_mask(&oprefix.addr, oprefix.plen);
1752 if (!IN6_ARE_ADDR_EQUAL(&prefix0->addr, &oprefix.addr)) {
1753 dprintf(LOG_WARNING, FNAME, "prefix %s/%d for %s "
1754 "has a trailing garbage. It should be %s/%d",
1755 in6addr2str(&prefix0->addr, 0), prefix0->plen,
1756 name, in6addr2str(&oprefix.addr, 0), oprefix.plen);
1757 /* ignore the error */
1760 /* avoid invalid prefix addresses */
1761 if (IN6_IS_ADDR_MULTICAST(&oprefix.addr) ||
1762 IN6_IS_ADDR_LINKLOCAL(&oprefix.addr) ||
1763 IN6_IS_ADDR_SITELOCAL(&oprefix.addr)) {
1764 dprintf(LOG_ERR, FNAME, "invalid prefix address: %s",
1765 in6addr2str(&oprefix.addr, 0));
1766 return (-1);
1769 /* prefix duplication check */
1770 if (dhcp6_find_listval(head, type, &oprefix, 0)) {
1771 if (type == DHCP6_LISTVAL_PREFIX6) {
1772 dprintf(LOG_NOTICE, FNAME,
1773 "duplicated prefix: %s/%d for %s",
1774 in6addr2str(&oprefix.addr, 0), oprefix.plen, name);
1775 } else {
1776 dprintf(LOG_NOTICE, FNAME,
1777 "duplicated address: %s for %s",
1778 in6addr2str(&oprefix.addr, 0), name);
1780 return (-1);
1783 /* validation about relationship of pltime and vltime */
1784 if (oprefix.vltime != DHCP6_DURATION_INFINITE &&
1785 (oprefix.pltime == DHCP6_DURATION_INFINITE ||
1786 oprefix.pltime > oprefix.vltime)) {
1787 if (type == DHCP6_LISTVAL_PREFIX6) {
1788 dprintf(LOG_NOTICE, FNAME,
1789 "%s/%d has larger preferred lifetime "
1790 "than valid lifetime",
1791 in6addr2str(&oprefix.addr, 0), oprefix.plen);
1792 } else {
1793 dprintf(LOG_NOTICE, FNAME,
1794 "%s has larger preferred lifetime "
1795 "than valid lifetime",
1796 in6addr2str(&oprefix.addr, 0));
1798 return (-1);
1801 /* insert the new prefix to the chain */
1802 if (dhcp6_add_listval(head, type, &oprefix, NULL) == NULL) {
1803 return (-1);
1806 return (0);
1809 struct ia_conf *
1810 find_iaconf(head, type, iaid)
1811 struct ia_conflist *head;
1812 int type;
1813 u_int32_t iaid;
1815 struct ia_conf *iac;
1817 for (iac = TAILQ_FIRST(head); iac; iac = TAILQ_NEXT(iac, link)) {
1818 if (iac->type == type && iac->iaid == iaid)
1819 return (iac);
1822 return (NULL);
1825 struct host_conf *
1826 find_hostconf(duid)
1827 struct duid *duid;
1829 struct host_conf *host;
1831 if ((host = find_dynamic_hostconf(duid)) != NULL) {
1832 return (host);
1835 for (host = host_conflist; host; host = host->next) {
1836 if (host->duid.duid_len == duid->duid_len &&
1837 memcmp(host->duid.duid_id, duid->duid_id,
1838 host->duid.duid_len) == 0) {
1839 return (host);
1843 return (NULL);
1846 struct authinfo *
1847 find_authinfo(head, name)
1848 struct authinfo *head;
1849 char *name;
1851 struct authinfo *ainfo;
1853 for (ainfo = head; ainfo; ainfo = ainfo->next) {
1854 if (strcmp(ainfo->name, name) == 0)
1855 return (ainfo);
1858 return (NULL);
1861 struct dhcp6_prefix *
1862 find_prefix6(list, prefix)
1863 struct dhcp6_list *list;
1864 struct dhcp6_prefix *prefix;
1866 struct dhcp6_listval *v;
1868 for (v = TAILQ_FIRST(list); v; v = TAILQ_NEXT(v, link)) {
1869 if (v->val_prefix6.plen == prefix->plen &&
1870 IN6_ARE_ADDR_EQUAL(&v->val_prefix6.addr, &prefix->addr)) {
1871 return (&v->val_prefix6);
1874 return (NULL);
1877 struct keyinfo *
1878 find_key(realm, realmlen, id)
1879 char *realm;
1880 size_t realmlen;
1881 u_int32_t id;
1883 struct keyinfo *key;
1885 for (key = key_list; key; key = key->next) {
1886 if (key->realmlen == realmlen &&
1887 memcmp(key->realm, realm, realmlen) == 0 &&
1888 key->keyid == id) {
1889 return (key);
1893 return (NULL);
1896 char *
1897 qstrdup(qstr)
1898 char *qstr;
1900 size_t len;
1901 char *dup;
1903 len = strlen(qstr);
1904 if (qstr[0] != '"' || len < 2 || qstr[len - 1] != '"')
1905 return (NULL);
1907 if ((dup = malloc(len)) == NULL)
1908 return (NULL);
1910 memcpy(dup, qstr + 1, len - 1);
1911 dup[len - 2] = '\0';
1913 return (dup);
1917 configure_pool(poollist)
1918 struct cf_namelist *poollist;
1920 struct cf_namelist *plp;
1922 dprintf(LOG_DEBUG, FNAME, "called");
1924 if (poollist && dhcp6_mode != DHCP6_MODE_SERVER) {
1925 dprintf(LOG_ERR, FNAME, "%s:%d "
1926 "pool statement is server-only",
1927 configfilename, poollist->line);
1928 goto bad;
1931 for (plp = poollist; plp; plp = plp->next) {
1932 struct pool_conf *pool = NULL;
1933 struct dhcp6_range *range = NULL;
1934 struct cf_list *cfl;
1936 for (cfl = plp->params; cfl; cfl = cfl->next) {
1937 switch(cfl->type) {
1938 case DECL_RANGE:
1939 range = cfl->ptr;
1940 break;
1941 default:
1942 dprintf(LOG_ERR, FNAME, "%s:%d "
1943 "invalid pool configuration",
1944 configfilename, cfl->line);
1945 goto bad;
1949 if (!range) {
1950 dprintf(LOG_ERR, FNAME, "%s:%d "
1951 "pool '%s' has no range declaration",
1952 configfilename, plp->line,
1953 plp->name);
1954 goto bad;
1956 if ((pool = create_pool(plp->name, range)) == NULL) {
1957 dprintf(LOG_ERR, FNAME,
1958 "faled to craete pool '%s'", plp->name);
1959 goto bad;
1961 pool->next = pool_conflist0;
1962 pool_conflist0 = pool;
1965 return (0);
1967 bad:
1968 /* there is currently nothing special to recover the error */
1969 return (-1);
1972 static void
1973 clear_poolconf(plist)
1974 struct pool_conf *plist;
1976 struct pool_conf *pool, *pool_next;
1978 dprintf(LOG_DEBUG, FNAME, "called");
1980 for (pool = plist; pool; pool = pool_next) {
1981 pool_next = pool->next;
1982 free(pool->name);
1983 free(pool);
1987 struct host_conf *
1988 create_dynamic_hostconf(duid, pool)
1989 struct duid *duid;
1990 struct dhcp6_poolspec *pool;
1992 struct dynamic_hostconf *dynconf = NULL;
1993 struct host_conf *host;
1994 char* strid = NULL;
1995 static int init = 1;
1997 if (init) {
1998 TAILQ_INIT(&dynamic_hostconf_head);
1999 dynamic_hostconf_count = 0;
2000 init = 0;
2003 if (dynamic_hostconf_count >= DHCP6_DYNAMIC_HOSTCONF_MAX) {
2004 struct dynamic_hostconf_listhead *head = &dynamic_hostconf_head;
2006 dprintf(LOG_DEBUG, FNAME, "reached to the max count (count=%lu)",
2007 dynamic_hostconf_count);
2009 /* Find the last entry that doesn't need authentication */
2010 TAILQ_FOREACH_REVERSE(dynconf, head, dynamic_hostconf_listhead, link)
2011 if (dynconf->host->delayedkey == NULL)
2012 break;
2013 if (dynconf == NULL)
2014 dynconf = TAILQ_LAST(head, dynamic_hostconf_listhead);
2015 TAILQ_REMOVE(head, dynconf, link);
2016 dynamic_hostconf_count--;
2017 clear_hostconf(dynconf->host);
2018 } else {
2019 if ((dynconf = malloc(sizeof(*dynconf))) == NULL) {
2020 dprintf(LOG_ERR, FNAME, "memory allocation failed");
2021 return (NULL);
2024 memset(dynconf, 0, sizeof(*dynconf));
2026 if ((host = malloc(sizeof(*host))) == NULL) {
2027 dprintf(LOG_ERR, FNAME, "memory allocation failed");
2028 goto bad;
2030 memset(host, 0, sizeof(*host));
2031 TAILQ_INIT(&host->prefix_list);
2032 TAILQ_INIT(&host->addr_list);
2034 if ((strid = duidstr(duid)) == NULL)
2035 strid = "???";
2036 if ((host->name = strdup(strid)) == NULL) {
2037 dprintf(LOG_ERR, FNAME, "memory allocation failed");
2038 goto bad;
2040 if (duidcpy(&host->duid, duid) != 0) {
2041 goto bad;
2043 if (pool->name) {
2044 if ((host->pool.name = strdup(pool->name)) == NULL) {
2045 dprintf(LOG_ERR, FNAME, "memory allocation failed");
2046 goto bad;
2049 host->pool.pltime = pool->pltime;
2050 host->pool.vltime = pool->vltime;
2052 dynconf->host = host;
2053 TAILQ_INSERT_HEAD(&dynamic_hostconf_head, dynconf, link);
2054 dynamic_hostconf_count++;
2056 dprintf(LOG_DEBUG, FNAME, "created host_conf (name=%s)", host->name);
2058 return (host);
2060 bad:
2061 if (host)
2062 clear_hostconf(host); /* host->next must be NULL */
2063 if (dynconf)
2064 free(dynconf);
2066 return (NULL);
2069 struct host_conf *
2070 find_dynamic_hostconf(duid)
2071 struct duid *duid;
2073 struct dynamic_hostconf *dynconf = NULL;
2075 TAILQ_FOREACH(dynconf, &dynamic_hostconf_head, link) {
2076 if (dynconf->host->duid.duid_len == duid->duid_len &&
2077 memcmp(dynconf->host->duid.duid_id, duid->duid_id,
2078 duid->duid_len) == 0)
2079 break;
2082 if (dynconf) {
2083 /* relocation */
2084 TAILQ_REMOVE(&dynamic_hostconf_head, dynconf, link);
2085 TAILQ_INSERT_HEAD(&dynamic_hostconf_head, dynconf, link);
2087 return (dynconf->host);
2090 return (NULL);
2093 struct pool_conf *
2094 create_pool(name, range)
2095 char *name;
2096 struct dhcp6_range *range;
2098 struct pool_conf *pool = NULL;
2100 if (!name || !range) {
2101 return (NULL);
2104 dprintf(LOG_DEBUG, FNAME, "name=%s, range=%s->%s", name,
2105 in6addr2str(&range->min, 0), in6addr2str(&range->max, 0));
2107 if (in6_addr_cmp(&range->min, &range->max) > 0) {
2108 dprintf(LOG_ERR, FNAME, "invalid address range %s->%s",
2109 in6addr2str(&range->min, 0),
2110 in6addr2str(&range->max, 0));
2111 return (NULL);
2114 if ((pool = malloc(sizeof(struct pool_conf))) == NULL) {
2115 dprintf(LOG_ERR, FNAME, "memory allocation failed");
2116 return (NULL);
2118 if ((pool->name = strdup(name)) == NULL) {
2119 dprintf(LOG_ERR, FNAME, "memory allocation failed");
2120 free(pool);
2121 return (NULL);
2123 pool->min = range->min;
2124 pool->max = range->max;
2126 return (pool);
2129 struct pool_conf *
2130 find_pool(name)
2131 const char *name;
2133 struct pool_conf *pool = NULL;
2135 if (!name)
2136 return (NULL);
2138 dprintf(LOG_DEBUG, FNAME, "name=%s", name);
2140 for (pool = pool_conflist; pool; pool = pool->next) {
2141 if (strcmp(name, pool->name) == 0) {
2142 dprintf(LOG_DEBUG, FNAME, "found (name=%s)", name);
2143 return (pool);
2147 dprintf(LOG_DEBUG, FNAME, "not found (name=%s)", name);
2149 return (NULL);
2152 #ifdef USE_DHCP6SRV
2154 get_free_address_from_pool(pool, addr)
2155 struct pool_conf *pool;
2156 struct in6_addr *addr;
2158 struct in6_addr cur;
2159 if (!pool || !addr)
2160 return (0);
2162 dprintf(LOG_DEBUG, FNAME, "called (pool=%s)", pool->name);
2164 for (cur = pool->min; in6_addr_cmp(&cur, &pool->max) <= 0;
2165 in6_addr_inc(&cur)) {
2166 if (!is_leased(&cur) &&
2167 !IN6_IS_ADDR_MULTICAST(&cur) &&
2168 !IN6_IS_ADDR_LINKLOCAL(&cur) &&
2169 !IN6_IS_ADDR_SITELOCAL(&cur)) {
2170 dprintf(LOG_DEBUG, FNAME, "found %s",
2171 in6addr2str(&cur, 0));
2172 *addr= cur;
2173 return 1;
2176 dprintf(LOG_DEBUG, FNAME, "next address %s",
2177 in6addr2str(&cur, 0));
2180 dprintf(LOG_NOTICE, FNAME, "no available address");
2181 return 0;
2185 is_available_in_pool(pool, addr)
2186 struct pool_conf *pool;
2187 struct in6_addr *addr;
2189 if (!pool || !addr)
2190 return (0);
2192 dprintf(LOG_DEBUG, FNAME, "pool=%s, addr=%s",
2193 pool->name, in6addr2str(addr, 0));
2195 if (in6_addr_cmp(addr, &pool->min) >= 0 &&
2196 in6_addr_cmp(addr, &pool->max) <= 0 &&
2197 !is_leased(addr) &&
2198 !IN6_IS_ADDR_MULTICAST(addr) &&
2199 !IN6_IS_ADDR_LINKLOCAL(addr) &&
2200 !IN6_IS_ADDR_SITELOCAL(addr)) {
2201 return (1);
2204 dprintf(LOG_DEBUG, FNAME, "unavailable address (pool=%s, addr=%s)",
2205 pool->name, in6addr2str(addr, 0));
2207 return (0);
2209 #endif
2211 static int
2212 in6_addr_cmp(addr1, addr2)
2213 struct in6_addr *addr1, *addr2;
2215 int i;
2217 for (i = 0; i < 16; i++) {
2218 if (addr1->s6_addr[i] != addr2->s6_addr[i]) {
2219 if (addr1->s6_addr[i] > addr2->s6_addr[i])
2220 return (1);
2221 else
2222 return (-1);
2226 return (0);
2229 #ifdef USE_DHCP6SRV
2230 static void
2231 in6_addr_inc(addr)
2232 struct in6_addr *addr;
2234 int i;
2236 for (i = 15; i >= 0; i--) {
2237 if (++(addr->s6_addr[i]) != 0x00)
2238 break;
2241 #endif