1 /* $KAME: common.c,v 1.129 2005/09/16 11:30:13 suz Exp $ */
2 /*
3 * Copyright (C) 1998 and 1999 WIDE Project.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the project nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <sys/ioctl.h>
34 #include <sys/queue.h>
35 #include <sys/stat.h>
36 #if TIME_WITH_SYS_TIME
37 # include <sys/time.h>
38 # include <time.h>
39 #else
40 # if HAVE_SYS_TIME_H
41 # include <sys/time.h>
42 # else
43 # include <time.h>
44 # endif
45 #endif
46 #include <net/if.h>
47 #include <netinet/in.h>
48 #ifdef __KAME__
49 #include <net/if_types.h>
50 #ifdef __FreeBSD__
51 #include <net/if_var.h>
52 #endif
53 #include <net/if_dl.h>
54 #endif
55 #ifdef __linux__
56 #include <linux/if_packet.h>
57 #endif
58 #include <net/if_arp.h>
59 #ifdef __sun__
60 #include <sys/sockio.h>
61 #include <sys/dlpi.h>
62 #include <stropts.h>
63 #include <fcntl.h>
64 #include <libdevinfo.h>
65 #endif
66
67 #ifdef __KAME__
68 #include <netinet6/in6_var.h>
69 #endif
70
71 #include <ctype.h>
72 #include <errno.h>
73 #include <limits.h>
74 #include <stdio.h>
75 #include <stdarg.h>
76 #include <syslog.h>
77 #include <stdlib.h>
78 #include <unistd.h>
79 #include <string.h>
80 #include <err.h>
81 #include <netdb.h>
82 #include <ifaddrs.h>
83
84 #include <dhcp6.h>
85 #include <config.h>
86 #include <common.h>
87 #include <timer.h>
88
89 #ifdef __linux__
90 /* from /usr/include/linux/ipv6.h */
91
92 struct in6_ifreq {
93 struct in6_addr ifr6_addr;
94 u_int32_t ifr6_prefixlen;
95 unsigned int ifr6_ifindex;
96 };
97 #endif
98
99 #define MAXDNAME 255
100
101 int foreground;
102 int debug_thresh;
103
104 static int dhcp6_count_list __P((struct dhcp6_list *));
105 static int in6_matchflags __P((struct sockaddr *, char *, int));
106 static ssize_t dnsencode __P((const char *, char *, size_t));
107 static char *dnsdecode __P((u_char **, u_char *, char *, size_t));
108 static int copyout_option __P((char *, char *, struct dhcp6_listval *));
109 static int copyin_option __P((int, struct dhcp6opt *, struct dhcp6opt *,
110 struct dhcp6_list *));
111 static int copy_option __P((u_int16_t, u_int16_t, void *, struct dhcp6opt **,
112 struct dhcp6opt *, int *));
113 static ssize_t gethwid __P((char *, int, const char *, u_int16_t *));
114 static char *sprint_uint64 __P((char *, int, u_int64_t));
115 static char *sprint_auth __P((struct dhcp6_optinfo *));
116
117 int
dhcp6_copy_list(dst,src)118 dhcp6_copy_list(dst, src)
119 struct dhcp6_list *dst, *src;
120 {
121 struct dhcp6_listval *ent;
122
123 for (ent = TAILQ_FIRST(src); ent; ent = TAILQ_NEXT(ent, link)) {
124 if (dhcp6_add_listval(dst, ent->type,
125 &ent->uv, &ent->sublist) == NULL)
126 goto fail;
127 }
128
129 return (0);
130
131 fail:
132 dhcp6_clear_list(dst);
133 return (-1);
134 }
135
136 void
dhcp6_move_list(dst,src)137 dhcp6_move_list(dst, src)
138 struct dhcp6_list *dst, *src;
139 {
140 struct dhcp6_listval *v;
141
142 while ((v = TAILQ_FIRST(src)) != NULL) {
143 TAILQ_REMOVE(src, v, link);
144 TAILQ_INSERT_TAIL(dst, v, link);
145 }
146 }
147
148 void
dhcp6_clear_list(head)149 dhcp6_clear_list(head)
150 struct dhcp6_list *head;
151 {
152 struct dhcp6_listval *v;
153
154 while ((v = TAILQ_FIRST(head)) != NULL) {
155 TAILQ_REMOVE(head, v, link);
156 dhcp6_clear_listval(v);
157 }
158
159 return;
160 }
161
162 static int
dhcp6_count_list(head)163 dhcp6_count_list(head)
164 struct dhcp6_list *head;
165 {
166 struct dhcp6_listval *v;
167 int i;
168
169 for (i = 0, v = TAILQ_FIRST(head); v; v = TAILQ_NEXT(v, link))
170 i++;
171
172 return (i);
173 }
174
175 void
dhcp6_clear_listval(lv)176 dhcp6_clear_listval(lv)
177 struct dhcp6_listval *lv;
178 {
179 dhcp6_clear_list(&lv->sublist);
180 switch (lv->type) {
181 case DHCP6_LISTVAL_VBUF:
182 dhcp6_vbuf_free(&lv->val_vbuf);
183 break;
184 default: /* nothing to do */
185 break;
186 }
187 free(lv);
188 }
189
190 /*
191 * Note: this function only searches for the first entry that matches
192 * VAL. It also does not care about sublists.
193 */
194 struct dhcp6_listval *
dhcp6_find_listval(head,type,val,option)195 dhcp6_find_listval(head, type, val, option)
196 struct dhcp6_list *head;
197 dhcp6_listval_type_t type;
198 void *val;
199 int option;
200 {
201 struct dhcp6_listval *lv;
202
203 for (lv = TAILQ_FIRST(head); lv; lv = TAILQ_NEXT(lv, link)) {
204 if (lv->type != type)
205 continue;
206
207 switch(type) {
208 case DHCP6_LISTVAL_NUM:
209 if (lv->val_num == *(int *)val)
210 return (lv);
211 break;
212 case DHCP6_LISTVAL_STCODE:
213 if (lv->val_num16 == *(u_int16_t *)val)
214 return (lv);
215 break;
216 case DHCP6_LISTVAL_ADDR6:
217 if (IN6_ARE_ADDR_EQUAL(&lv->val_addr6,
218 (struct in6_addr *)val)) {
219 return (lv);
220 }
221 break;
222 case DHCP6_LISTVAL_PREFIX6:
223 if ((option & MATCHLIST_PREFIXLEN) &&
224 lv->val_prefix6.plen ==
225 ((struct dhcp6_prefix *)val)->plen) {
226 return (lv);
227 } else if (IN6_ARE_ADDR_EQUAL(&lv->val_prefix6.addr,
228 &((struct dhcp6_prefix *)val)->addr) &&
229 lv->val_prefix6.plen ==
230 ((struct dhcp6_prefix *)val)->plen) {
231 return (lv);
232 }
233 break;
234 case DHCP6_LISTVAL_STATEFULADDR6:
235 if (IN6_ARE_ADDR_EQUAL(&lv->val_statefuladdr6.addr,
236 &((struct dhcp6_prefix *)val)->addr)) {
237 return (lv);
238 }
239 break;
240 case DHCP6_LISTVAL_IAPD:
241 case DHCP6_LISTVAL_IANA:
242 if (lv->val_ia.iaid ==
243 ((struct dhcp6_ia *)val)->iaid) {
244 return (lv);
245 }
246 break;
247 case DHCP6_LISTVAL_VBUF:
248 if (dhcp6_vbuf_cmp(&lv->val_vbuf,
249 (struct dhcp6_vbuf *)val) == 0) {
250 return (lv);
251 }
252 break;
253 }
254 }
255
256 return (NULL);
257 }
258
259 struct dhcp6_listval *
dhcp6_add_listval(head,type,val,sublist)260 dhcp6_add_listval(head, type, val, sublist)
261 struct dhcp6_list *head, *sublist;
262 dhcp6_listval_type_t type;
263 void *val;
264 {
265 struct dhcp6_listval *lv = NULL;
266
267 if ((lv = malloc(sizeof(*lv))) == NULL) {
268 d_printf(LOG_ERR, FNAME,
269 "failed to allocate memory for list entry");
270 goto fail;
271 }
272 memset(lv, 0, sizeof(*lv));
273 lv->type = type;
274 TAILQ_INIT(&lv->sublist);
275
276 switch(type) {
277 case DHCP6_LISTVAL_NUM:
278 lv->val_num = *(int *)val;
279 break;
280 case DHCP6_LISTVAL_STCODE:
281 lv->val_num16 = *(u_int16_t *)val;
282 break;
283 case DHCP6_LISTVAL_ADDR6:
284 lv->val_addr6 = *(struct in6_addr *)val;
285 break;
286 case DHCP6_LISTVAL_PREFIX6:
287 lv->val_prefix6 = *(struct dhcp6_prefix *)val;
288 break;
289 case DHCP6_LISTVAL_STATEFULADDR6:
290 lv->val_statefuladdr6 = *(struct dhcp6_statefuladdr *)val;
291 break;
292 case DHCP6_LISTVAL_IAPD:
293 case DHCP6_LISTVAL_IANA:
294 lv->val_ia = *(struct dhcp6_ia *)val;
295 break;
296 case DHCP6_LISTVAL_VBUF:
297 if (dhcp6_vbuf_copy(&lv->val_vbuf, (struct dhcp6_vbuf *)val))
298 goto fail;
299 break;
300 default:
301 d_printf(LOG_ERR, FNAME,
302 "unexpected list value type (%d)", type);
303 goto fail;
304 }
305
306 if (sublist && dhcp6_copy_list(&lv->sublist, sublist))
307 goto fail;
308
309 TAILQ_INSERT_TAIL(head, lv, link);
310
311 return (lv);
312
313 fail:
314 if (lv)
315 free(lv);
316
317 return (NULL);
318 }
319
320 int
dhcp6_vbuf_copy(dst,src)321 dhcp6_vbuf_copy(dst, src)
322 struct dhcp6_vbuf *dst, *src;
323 {
324 dst->dv_buf = malloc(src->dv_len);
325 if (dst->dv_buf == NULL)
326 return (-1);
327
328 dst->dv_len = src->dv_len;
329 memcpy(dst->dv_buf, src->dv_buf, dst->dv_len);
330
331 return (0);
332 }
333
334 void
dhcp6_vbuf_free(vbuf)335 dhcp6_vbuf_free(vbuf)
336 struct dhcp6_vbuf *vbuf;
337 {
338 free(vbuf->dv_buf);
339
340 vbuf->dv_len = 0;
341 vbuf->dv_buf = NULL;
342 }
343
344 int
dhcp6_vbuf_cmp(vb1,vb2)345 dhcp6_vbuf_cmp(vb1, vb2)
346 struct dhcp6_vbuf *vb1, *vb2;
347 {
348 if (vb1->dv_len != vb2->dv_len)
349 return (vb1->dv_len - vb2->dv_len);
350
351 return (memcmp(vb1->dv_buf, vb2->dv_buf, vb1->dv_len));
352 }
353
354 static int
dhcp6_get_addr(optlen,cp,type,list)355 dhcp6_get_addr(optlen, cp, type, list)
356 int optlen;
357 void *cp;
358 dhcp6_listval_type_t type;
359 struct dhcp6_list *list;
360 {
361 void *val;
362
363 if (optlen % sizeof(struct in6_addr) || optlen == 0) {
364 d_printf(LOG_INFO, FNAME,
365 "malformed DHCP option: type %d, len %d", type, optlen);
366 return -1;
367 }
368 for (val = cp; val < cp + optlen; val += sizeof(struct in6_addr)) {
369 struct in6_addr valaddr;
370
371 memcpy(&valaddr, val, sizeof(valaddr));
372 if (dhcp6_find_listval(list,
373 DHCP6_LISTVAL_ADDR6, &valaddr, 0)) {
374 d_printf(LOG_INFO, FNAME, "duplicated %s address (%s)",
375 dhcp6optstr(type), in6addr2str(&valaddr, 0));
376 continue;
377 }
378
379 if (dhcp6_add_listval(list, DHCP6_LISTVAL_ADDR6,
380 &valaddr, NULL) == NULL) {
381 d_printf(LOG_ERR, FNAME,
382 "failed to copy %s address", dhcp6optstr(type));
383 return -1;
384 }
385 }
386
387 return 0;
388 }
389
390 static int
dhcp6_set_addr(type,list,p,optep,len)391 dhcp6_set_addr(type, list, p, optep, len)
392 dhcp6_listval_type_t type;
393 struct dhcp6_list *list;
394 struct dhcp6opt **p, *optep;
395 int *len;
396 {
397 struct in6_addr *in6;
398 char *tmpbuf;
399 struct dhcp6_listval *d;
400 int optlen;
401
402 if (TAILQ_EMPTY(list))
403 return 0;
404
405 tmpbuf = NULL;
406 optlen = dhcp6_count_list(list) * sizeof(struct in6_addr);
407 if ((tmpbuf = malloc(optlen)) == NULL) {
408 d_printf(LOG_ERR, FNAME,
409 "memory allocation failed for %s options",
410 dhcp6optstr(type));
411 return -1;
412 }
413 in6 = (struct in6_addr *)tmpbuf;
414 for (d = TAILQ_FIRST(list); d; d = TAILQ_NEXT(d, link), in6++)
415 memcpy(in6, &d->val_addr6, sizeof(*in6));
416 if (copy_option(type, optlen, tmpbuf, p, optep, len) != 0) {
417 free(tmpbuf);
418 return -1;
419 }
420
421 free(tmpbuf);
422 return 0;
423 }
424
425 static int
dhcp6_get_domain(optlen,cp,type,list)426 dhcp6_get_domain(optlen, cp, type, list)
427 int optlen;
428 void *cp;
429 dhcp6_listval_type_t type;
430 struct dhcp6_list *list;
431 {
432 void *val;
433
434 val = cp;
435 while (val < cp + optlen) {
436 struct dhcp6_vbuf vb;
437 char name[MAXDNAME + 1];
438
439 if (dnsdecode((u_char **)(void *)&val,
440 (u_char *)(cp + optlen), name, sizeof(name)) == NULL) {
441 d_printf(LOG_INFO, FNAME, "failed to "
442 "decode a %s domain name",
443 dhcp6optstr(type));
444 d_printf(LOG_INFO, FNAME,
445 "malformed DHCP option: type %d, len %d",
446 type, optlen);
447 return -1;
448 }
449
450 vb.dv_len = strlen(name) + 1;
451 vb.dv_buf = name;
452
453 if (dhcp6_add_listval(list,
454 DHCP6_LISTVAL_VBUF, &vb, NULL) == NULL) {
455 d_printf(LOG_ERR, FNAME, "failed to "
456 "copy a %s domain name", dhcp6optstr(type));
457 return -1;
458 }
459 }
460
461 return 0;
462 }
463
464 static int
dhcp6_set_domain(type,list,p,optep,len)465 dhcp6_set_domain(type, list, p, optep, len)
466 dhcp6_listval_type_t type;
467 struct dhcp6_list *list;
468 struct dhcp6opt **p, *optep;
469 int *len;
470 {
471 int optlen = 0;
472 struct dhcp6_listval *d;
473 char *tmpbuf;
474 char name[MAXDNAME], *cp, *ep;
475
476 if (TAILQ_EMPTY(list))
477 return 0;
478
479 for (d = TAILQ_FIRST(list); d; d = TAILQ_NEXT(d, link))
480 optlen += (d->val_vbuf.dv_len + 1);
481
482 if (optlen == 0) {
483 return 0;
484 }
485
486 tmpbuf = NULL;
487 if ((tmpbuf = malloc(optlen)) == NULL) {
488 d_printf(LOG_ERR, FNAME, "memory allocation failed for "
489 "%s domain options", dhcp6optstr(type));
490 return -1;
491 }
492 cp = tmpbuf;
493 ep = cp + optlen;
494 for (d = TAILQ_FIRST(list); d; d = TAILQ_NEXT(d, link)) {
495 int nlen;
496
497 nlen = dnsencode((const char *)d->val_vbuf.dv_buf,
498 name, sizeof (name));
499 if (nlen < 0) {
500 d_printf(LOG_ERR, FNAME,
501 "failed to encode a %s domain name",
502 dhcp6optstr(type));
503 free(tmpbuf);
504 return -1;
505 }
506 if (ep - cp < nlen) {
507 d_printf(LOG_ERR, FNAME,
508 "buffer length for %s domain name is too short",
509 dhcp6optstr(type));
510 free(tmpbuf);
511 return -1;
512 }
513 memcpy(cp, name, nlen);
514 cp += nlen;
515 }
516 if (copy_option(type, cp - tmpbuf, tmpbuf, p, optep, len) != 0) {
517 free(tmpbuf);
518 return -1;
519 }
520 free(tmpbuf);
521
522 return 0;
523 }
524
525 struct dhcp6_event *
dhcp6_create_event(ifp,state)526 dhcp6_create_event(ifp, state)
527 struct dhcp6_if *ifp;
528 int state;
529 {
530 struct dhcp6_event *ev;
531
532 if ((ev = malloc(sizeof(*ev))) == NULL) {
533 d_printf(LOG_ERR, FNAME,
534 "failed to allocate memory for an event");
535 return (NULL);
536 }
537 memset(ev, 0, sizeof(*ev));
538 ev->ifp = ifp;
539 ev->state = state;
540 TAILQ_INIT(&ev->data_list);
541
542 return (ev);
543 }
544
545 void
dhcp6_remove_event(ev)546 dhcp6_remove_event(ev)
547 struct dhcp6_event *ev;
548 {
549 struct dhcp6_serverinfo *sp, *sp_next;
550
551 d_printf(LOG_DEBUG, FNAME, "removing an event on %s, state=%s",
552 ev->ifp->ifname, dhcp6_event_statestr(ev));
553
554 dhcp6_remove_evdata(ev);
555
556 duidfree(&ev->serverid);
557
558 if (ev->timer)
559 dhcp6_remove_timer(&ev->timer);
560 TAILQ_REMOVE(&ev->ifp->event_list, ev, link);
561
562 for (sp = ev->servers; sp; sp = sp_next) {
563 sp_next = sp->next;
564
565 d_printf(LOG_DEBUG, FNAME, "removing server (ID: %s)",
566 duidstr(&sp->optinfo.serverID));
567 dhcp6_clear_options(&sp->optinfo);
568 if (sp->authparam != NULL)
569 free(sp->authparam);
570 free(sp);
571 }
572
573 if (ev->authparam != NULL)
574 free(ev->authparam);
575
576 free(ev);
577 }
578
579 void
dhcp6_remove_evdata(ev)580 dhcp6_remove_evdata(ev)
581 struct dhcp6_event *ev;
582 {
583 struct dhcp6_eventdata *evd;
584
585 while ((evd = TAILQ_FIRST(&ev->data_list)) != NULL) {
586 TAILQ_REMOVE(&ev->data_list, evd, link);
587 if (evd->destructor)
588 (*evd->destructor)(evd);
589 free(evd);
590 }
591 }
592
593 struct authparam *
new_authparam(proto,alg,rdm)594 new_authparam(proto, alg, rdm)
595 int proto, alg, rdm;
596 {
597 struct authparam *authparam;
598
599 if ((authparam = malloc(sizeof(*authparam))) == NULL)
600 return (NULL);
601
602 memset(authparam, 0, sizeof(*authparam));
603
604 authparam->authproto = proto;
605 authparam->authalgorithm = alg;
606 authparam->authrdm = rdm;
607 authparam->key = NULL;
608 authparam->flags |= AUTHPARAM_FLAGS_NOPREVRD;
609 authparam->prevrd = 0;
610
611 return (authparam);
612 }
613
614 struct authparam *
copy_authparam(authparam)615 copy_authparam(authparam)
616 struct authparam *authparam;
617 {
618 struct authparam *dst;
619
620 if ((dst = malloc(sizeof(*dst))) == NULL)
621 return (NULL);
622
623 memcpy(dst, authparam, sizeof(*dst));
624
625 return (dst);
626 }
627
628 /*
629 * Home-brew function of a 64-bit version of ntohl.
630 * XXX: is there any standard for this?
631 */
632 #if (BYTE_ORDER == LITTLE_ENDIAN)
633 static __inline u_int64_t
ntohq(u_int64_t x)634 ntohq(u_int64_t x)
635 {
636 return (u_int64_t)ntohl((u_int32_t)(x >> 32)) |
637 (int64_t)ntohl((u_int32_t)(x & 0xffffffff)) << 32;
638 }
639 #else /* (BYTE_ORDER == LITTLE_ENDIAN) */
640 #define ntohq(x) (x)
641 #endif
642
643 int
dhcp6_auth_replaycheck(method,prev,current)644 dhcp6_auth_replaycheck(method, prev, current)
645 int method;
646 u_int64_t prev, current;
647 {
648 char bufprev[] = "ffff ffff ffff ffff";
649 char bufcurrent[] = "ffff ffff ffff ffff";
650
651 if (method != DHCP6_AUTHRDM_MONOCOUNTER) {
652 d_printf(LOG_ERR, FNAME, "unsupported replay detection "
653 "method (%d)", method);
654 return (-1);
655 }
656
657 (void)sprint_uint64(bufprev, sizeof(bufprev), prev);
658 (void)sprint_uint64(bufcurrent, sizeof(bufcurrent), current);
659 d_printf(LOG_DEBUG, FNAME, "previous: %s, current: %s",
660 bufprev, bufcurrent);
661
662 prev = ntohq(prev);
663 current = ntohq(current);
664
665 /*
666 * we call the singular point guilty, since we cannot guess
667 * whether the serial number is increasing or not.
668 */
669 if (prev == (current ^ 0x8000000000000000ULL)) {
670 d_printf(LOG_INFO, FNAME, "detected a singular point");
671 return (1);
672 }
673
674 return (((int64_t)(current - prev) > 0) ? 0 : 1);
675 }
676
677 int
getifaddr(addr,ifnam,prefix,plen,strong,ignoreflags)678 getifaddr(addr, ifnam, prefix, plen, strong, ignoreflags)
679 struct in6_addr *addr;
680 char *ifnam;
681 struct in6_addr *prefix;
682 int plen;
683 int strong; /* if strong host model is required or not */
684 int ignoreflags;
685 {
686 struct ifaddrs *ifap, *ifa;
687 struct sockaddr_in6 sin6;
688 int error = -1;
689
690 if (getifaddrs(&ifap) != 0) {
691 d_printf(LOG_WARNING, FNAME,
692 "getifaddrs failed: %s", strerror(errno));
693 return (-1);
694 }
695
696 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
697 int s1, s2;
698
699 if (strong && strcmp(ifnam, ifa->ifa_name) != 0)
700 continue;
701
702 /* in any case, ignore interfaces in different scope zones. */
703 if ((s1 = in6_addrscopebyif(prefix, ifnam)) < 0 ||
704 (s2 = in6_addrscopebyif(prefix, ifa->ifa_name)) < 0 ||
705 s1 != s2)
706 continue;
707
708 if (ifa->ifa_addr->sa_family != AF_INET6)
709 continue;
710 #ifdef HAVE_SA_LEN
711 if (ifa->ifa_addr->sa_len > sizeof(sin6))
712 continue;
713 #endif
714
715 if (in6_matchflags(ifa->ifa_addr, ifa->ifa_name, ignoreflags))
716 continue;
717
718 memcpy(&sin6, ifa->ifa_addr, sysdep_sa_len(ifa->ifa_addr));
719 #ifdef __KAME__
720 if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr)) {
721 sin6.sin6_addr.s6_addr[2] = 0;
722 sin6.sin6_addr.s6_addr[3] = 0;
723 }
724 #endif
725 if (plen % 8 == 0) {
726 if (memcmp(&sin6.sin6_addr, prefix, plen / 8) != 0)
727 continue;
728 } else {
729 struct in6_addr a, m;
730 int i;
731
732 memcpy(&a, &sin6.sin6_addr, sizeof(sin6.sin6_addr));
733 memset(&m, 0, sizeof(m));
734 memset(&m, 0xff, plen / 8);
735 m.s6_addr[plen / 8] = (0xff00 >> (plen % 8)) & 0xff;
736 for (i = 0; i < sizeof(a); i++)
737 a.s6_addr[i] &= m.s6_addr[i];
738
739 if (memcmp(&a, prefix, plen / 8) != 0 ||
740 a.s6_addr[plen / 8] !=
741 (prefix->s6_addr[plen / 8] & m.s6_addr[plen / 8]))
742 continue;
743 }
744 memcpy(addr, &sin6.sin6_addr, sizeof(sin6.sin6_addr));
745 #ifdef __KAME__
746 if (IN6_IS_ADDR_LINKLOCAL(addr))
747 addr->s6_addr[2] = addr->s6_addr[3] = 0;
748 #endif
749 error = 0;
750 break;
751 }
752
753 freeifaddrs(ifap);
754 return (error);
755 }
756
757 int
getifidfromaddr(addr,ifidp)758 getifidfromaddr(addr, ifidp)
759 struct in6_addr *addr;
760 unsigned int *ifidp;
761 {
762 struct ifaddrs *ifap, *ifa;
763 struct sockaddr_in6 *sa6;
764 unsigned int ifid;
765 int retval = -1;
766
767 if (getifaddrs(&ifap) != 0) {
768 d_printf(LOG_WARNING, FNAME,
769 "getifaddrs failed: %s", strerror(errno));
770 return (-1);
771 }
772
773 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
774 if (ifa->ifa_addr->sa_family != AF_INET6)
775 continue;
776
777 sa6 = (struct sockaddr_in6 *)ifa->ifa_addr;
778 if (IN6_ARE_ADDR_EQUAL(addr, &sa6->sin6_addr))
779 break;
780 }
781
782 if (ifa != NULL) {
783 if ((ifid = if_nametoindex(ifa->ifa_name)) == 0) {
784 d_printf(LOG_ERR, FNAME,
785 "if_nametoindex failed for %s", ifa->ifa_name);
786 goto end;
787 }
788 retval = 0;
789 *ifidp = ifid;
790 }
791
792 end:
793 freeifaddrs(ifap);
794 return (retval);
795 }
796
797 int
in6_addrscopebyif(addr,ifnam)798 in6_addrscopebyif(addr, ifnam)
799 struct in6_addr *addr;
800 char *ifnam;
801 {
802 u_int ifindex;
803
804 if ((ifindex = if_nametoindex(ifnam)) == 0)
805 return (-1);
806
807 if (IN6_IS_ADDR_LINKLOCAL(addr) || IN6_IS_ADDR_MC_LINKLOCAL(addr))
808 return (ifindex);
809
810 if (IN6_IS_ADDR_SITELOCAL(addr) || IN6_IS_ADDR_MC_SITELOCAL(addr))
811 return (1); /* XXX */
812
813 if (IN6_IS_ADDR_MC_ORGLOCAL(addr))
814 return (1); /* XXX */
815
816 return (1); /* treat it as global */
817 }
818
819 int
transmit_sa(s,sa,buf,len)820 transmit_sa(s, sa, buf, len)
821 int s;
822 struct sockaddr *sa;
823 char *buf;
824 size_t len;
825 {
826 int error;
827
828 error = sendto(s, buf, len, 0, sa, sysdep_sa_len(sa));
829
830 return (error != len) ? -1 : 0;
831 }
832
833 long
random_between(x,y)834 random_between(x, y)
835 long x;
836 long y;
837 {
838 long ratio;
839
840 ratio = 1 << 16;
841 while ((y - x) * ratio < (y - x))
842 ratio = ratio / 2;
843 return (x + ((y - x) * (ratio - 1) / random() & (ratio - 1)));
844 }
845
846 int
prefix6_mask(in6,plen)847 prefix6_mask(in6, plen)
848 struct in6_addr *in6;
849 int plen;
850 {
851 struct sockaddr_in6 mask6;
852 int i;
853
854 if (sa6_plen2mask(&mask6, plen))
855 return (-1);
856
857 for (i = 0; i < 16; i++)
858 in6->s6_addr[i] &= mask6.sin6_addr.s6_addr[i];
859
860 return (0);
861 }
862
863 int
sa6_plen2mask(sa6,plen)864 sa6_plen2mask(sa6, plen)
865 struct sockaddr_in6 *sa6;
866 int plen;
867 {
868 u_char *cp;
869
870 if (plen < 0 || plen > 128)
871 return (-1);
872
873 memset(sa6, 0, sizeof(*sa6));
874 sa6->sin6_family = AF_INET6;
875 #ifdef HAVE_SA_LEN
876 sa6->sin6_len = sizeof(*sa6);
877 #endif
878
879 for (cp = (u_char *)&sa6->sin6_addr; plen > 7; plen -= 8)
880 *cp++ = 0xff;
881 *cp = 0xff << (8 - plen);
882
883 return (0);
884 }
885
886 char *
addr2str(sa)887 addr2str(sa)
888 struct sockaddr *sa;
889 {
890 static char addrbuf[8][NI_MAXHOST];
891 static int round = 0;
892 char *cp;
893
894 round = (round + 1) & 7;
895 cp = addrbuf[round];
896
897 getnameinfo(sa, sysdep_sa_len(sa), cp, NI_MAXHOST,
898 NULL, 0, NI_NUMERICHOST);
899
900 return (cp);
901 }
902
903 char *
in6addr2str(in6,scopeid)904 in6addr2str(in6, scopeid)
905 struct in6_addr *in6;
906 int scopeid;
907 {
908 struct sockaddr_in6 sa6;
909
910 memset(&sa6, 0, sizeof(sa6));
911 sa6.sin6_family = AF_INET6;
912 #ifdef HAVE_SA_LEN
913 sa6.sin6_len = sizeof(sa6);
914 #endif
915 sa6.sin6_addr = *in6;
916 sa6.sin6_scope_id = scopeid;
917
918 return (addr2str((struct sockaddr *)&sa6));
919 }
920
921 /* return IPv6 address scope type. caller assumes that smaller is narrower. */
922 int
in6_scope(addr)923 in6_scope(addr)
924 struct in6_addr *addr;
925 {
926 int scope;
927
928 if (addr->s6_addr[0] == 0xfe) {
929 scope = addr->s6_addr[1] & 0xc0;
930
931 switch (scope) {
932 case 0x80:
933 return (2); /* link-local */
934 break;
935 case 0xc0:
936 return (5); /* site-local */
937 break;
938 default:
939 return (14); /* global: just in case */
940 break;
941 }
942 }
943
944 /* multicast scope. just return the scope field */
945 if (addr->s6_addr[0] == 0xff)
946 return (addr->s6_addr[1] & 0x0f);
947
948 if (bcmp(&in6addr_loopback, addr, sizeof(addr) - 1) == 0) {
949 if (addr->s6_addr[15] == 1) /* loopback */
950 return (1);
951 if (addr->s6_addr[15] == 0) /* unspecified */
952 return (0); /* XXX: good value? */
953 }
954
955 return (14); /* global */
956 }
957
958 static int
in6_matchflags(addr,ifnam,flags)959 in6_matchflags(addr, ifnam, flags)
960 struct sockaddr *addr;
961 char *ifnam;
962 int flags;
963 {
964 #ifdef __KAME__
965 int s;
966 struct in6_ifreq ifr6;
967
968 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
969 warn("in6_matchflags: socket(DGRAM6)");
970 return (-1);
971 }
972 memset(&ifr6, 0, sizeof(ifr6));
973 strncpy(ifr6.ifr_name, ifnam, sizeof(ifr6.ifr_name));
974 ifr6.ifr_addr = *(struct sockaddr_in6 *)addr;
975
976 if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
977 warn("in6_matchflags: ioctl(SIOCGIFAFLAG_IN6, %s)",
978 addr2str(addr));
979 close(s);
980 return (-1);
981 }
982
983 close(s);
984
985 return (ifr6.ifr_ifru.ifru_flags6 & flags);
986 #else
987 return (0);
988 #endif
989 }
990
991 int
get_duid(idfile,duid)992 get_duid(idfile, duid)
993 char *idfile;
994 struct duid *duid;
995 {
996 FILE *fp = NULL;
997 u_int16_t len = 0, hwtype;
998 struct dhcp6opt_duid_type1 *dp; /* we only support the type1 DUID */
999 char tmpbuf[256]; /* DUID should be no more than 256 bytes */
1000
1001 if ((fp = fopen(idfile, "r")) == NULL && errno != ENOENT)
1002 d_printf(LOG_NOTICE, FNAME, "failed to open DUID file: %s",
1003 idfile);
1004
1005 if (fp) {
1006 /* decode length */
1007 if (fread(&len, sizeof(len), 1, fp) != 1) {
1008 d_printf(LOG_ERR, FNAME, "DUID file corrupted");
1009 goto fail;
1010 }
1011 } else {
1012 int l;
1013
1014 if ((l = gethwid(tmpbuf, sizeof(tmpbuf), NULL, &hwtype)) < 0) {
1015 d_printf(LOG_INFO, FNAME,
1016 "failed to get a hardware address");
1017 goto fail;
1018 }
1019 len = l + sizeof(struct dhcp6opt_duid_type1);
1020 }
1021
1022 memset(duid, 0, sizeof(*duid));
1023 duid->duid_len = len;
1024 if ((duid->duid_id = (char *)malloc(len)) == NULL) {
1025 d_printf(LOG_ERR, FNAME, "failed to allocate memory");
1026 goto fail;
1027 }
1028
1029 /* copy (and fill) the ID */
1030 if (fp) {
1031 if (fread(duid->duid_id, len, 1, fp) != 1) {
1032 d_printf(LOG_ERR, FNAME, "DUID file corrupted");
1033 goto fail;
1034 }
1035
1036 d_printf(LOG_DEBUG, FNAME,
1037 "extracted an existing DUID from %s: %s",
1038 idfile, duidstr(duid));
1039 } else {
1040 u_int64_t t64;
1041
1042 dp = (struct dhcp6opt_duid_type1 *)duid->duid_id;
1043 dp->dh6_duid1_type = htons(1); /* type 1 */
1044 dp->dh6_duid1_hwtype = htons(hwtype);
1045 /* time is Jan 1, 2000 (UTC), modulo 2^32 */
1046 t64 = (u_int64_t)(time(NULL) - 946684800);
1047 dp->dh6_duid1_time = htonl((u_long)(t64 & 0xffffffff));
1048 memcpy((void *)(dp + 1), tmpbuf, (len - sizeof(*dp)));
1049
1050 d_printf(LOG_DEBUG, FNAME, "generated a new DUID: %s",
1051 duidstr(duid));
1052 }
1053
1054 /* save the (new) ID to the file for next time */
1055 if (!fp) {
1056 if ((fp = fopen(idfile, "w+")) == NULL) {
1057 d_printf(LOG_ERR, FNAME,
1058 "failed to open DUID file for save");
1059 goto fail;
1060 }
1061 if ((fwrite(&len, sizeof(len), 1, fp)) != 1) {
1062 d_printf(LOG_ERR, FNAME, "failed to save DUID");
1063 goto fail;
1064 }
1065 if ((fwrite(duid->duid_id, len, 1, fp)) != 1) {
1066 d_printf(LOG_ERR, FNAME, "failed to save DUID");
1067 goto fail;
1068 }
1069
1070 d_printf(LOG_DEBUG, FNAME, "saved generated DUID to %s",
1071 idfile);
1072 }
1073
1074 if (fp)
1075 fclose(fp);
1076 return (0);
1077
1078 fail:
1079 if (fp)
1080 fclose(fp);
1081 if (duid->duid_id) {
1082 free(duid->duid_id);
1083 duid->duid_id = NULL; /* for safety */
1084 }
1085 return (-1);
1086 }
1087
1088 #ifdef __sun__
1089 struct hwparms {
1090 char *buf;
1091 u_int16_t *hwtypep;
1092 ssize_t retval;
1093 };
1094
1095 static ssize_t
getifhwaddr(const char * ifname,char * buf,u_int16_t * hwtypep,int ppa)1096 getifhwaddr(const char *ifname, char *buf, u_int16_t *hwtypep, int ppa)
1097 {
1098 int fd, flags;
1099 char fname[MAXPATHLEN], *cp;
1100 struct strbuf putctl;
1101 struct strbuf getctl;
1102 long getbuf[1024];
1103 dl_info_req_t dlir;
1104 dl_phys_addr_req_t dlpar;
1105 dl_phys_addr_ack_t *dlpaa;
1106
1107 d_printf(LOG_DEBUG, FNAME, "trying %s ppa %d", ifname, ppa);
1108
1109 if (ifname[0] == '\0')
1110 return (-1);
1111 if (ppa >= 0 && !isdigit(ifname[strlen(ifname) - 1]))
1112 (void) snprintf(fname, sizeof (fname), "/dev/%s%d", ifname,
1113 ppa);
1114 else
1115 (void) snprintf(fname, sizeof (fname), "/dev/%s", ifname);
1116 getctl.maxlen = sizeof (getbuf);
1117 getctl.buf = (char *)getbuf;
1118 if ((fd = open(fname, O_RDWR)) == -1) {
1119 dl_attach_req_t dlar;
1120
1121 cp = fname + strlen(fname) - 1;
1122 if (!isdigit(*cp))
1123 return (-1);
1124 while (cp > fname) {
1125 if (!isdigit(*cp))
1126 break;
1127 cp--;
1128 }
1129 if (cp == fname)
1130 return (-1);
1131 cp++;
1132 dlar.dl_ppa = atoi(cp);
1133 *cp = '\0';
1134 if ((fd = open(fname, O_RDWR)) == -1)
1135 return (-1);
1136 dlar.dl_primitive = DL_ATTACH_REQ;
1137 putctl.len = sizeof (dlar);
1138 putctl.buf = (char *)&dlar;
1139 if (putmsg(fd, &putctl, NULL, 0) == -1) {
1140 (void) close(fd);
1141 return (-1);
1142 }
1143 flags = 0;
1144 if (getmsg(fd, &getctl, NULL, &flags) == -1) {
1145 (void) close(fd);
1146 return (-1);
1147 }
1148 if (getbuf[0] != DL_OK_ACK) {
1149 (void) close(fd);
1150 return (-1);
1151 }
1152 }
1153 dlir.dl_primitive = DL_INFO_REQ;
1154 putctl.len = sizeof (dlir);
1155 putctl.buf = (char *)&dlir;
1156 if (putmsg(fd, &putctl, NULL, 0) == -1) {
1157 (void) close(fd);
1158 return (-1);
1159 }
1160 flags = 0;
1161 if (getmsg(fd, &getctl, NULL, &flags) == -1) {
1162 (void) close(fd);
1163 return (-1);
1164 }
1165 if (getbuf[0] != DL_INFO_ACK) {
1166 (void) close(fd);
1167 return (-1);
1168 }
1169 switch (((dl_info_ack_t *)getbuf)->dl_mac_type) {
1170 case DL_CSMACD:
1171 case DL_ETHER:
1172 case DL_100VG:
1173 case DL_ETH_CSMA:
1174 case DL_100BT:
1175 *hwtypep = ARPHRD_ETHER;
1176 break;
1177 default:
1178 (void) close(fd);
1179 return (-1);
1180 }
1181 dlpar.dl_primitive = DL_PHYS_ADDR_REQ;
1182 dlpar.dl_addr_type = DL_CURR_PHYS_ADDR;
1183 putctl.len = sizeof (dlpar);
1184 putctl.buf = (char *)&dlpar;
1185 if (putmsg(fd, &putctl, NULL, 0) == -1) {
1186 (void) close(fd);
1187 return (-1);
1188 }
1189 flags = 0;
1190 if (getmsg(fd, &getctl, NULL, &flags) == -1) {
1191 (void) close(fd);
1192 return (-1);
1193 }
1194 if (getbuf[0] != DL_PHYS_ADDR_ACK) {
1195 (void) close(fd);
1196 return (-1);
1197 }
1198 dlpaa = (dl_phys_addr_ack_t *)getbuf;
1199 if (dlpaa->dl_addr_length != 6) {
1200 (void) close(fd);
1201 return (-1);
1202 }
1203 (void) memcpy(buf, (char *)getbuf + dlpaa->dl_addr_offset,
1204 dlpaa->dl_addr_length);
1205 return (dlpaa->dl_addr_length);
1206 }
1207
1208 static int
devfs_handler(di_node_t node,di_minor_t minor,void * arg)1209 devfs_handler(di_node_t node, di_minor_t minor, void *arg)
1210 {
1211 struct hwparms *parms = arg;
1212
1213 parms->retval = getifhwaddr(di_minor_name(minor), parms->buf,
1214 parms->hwtypep, di_instance(node));
1215 return (parms->retval == -1 ? DI_WALK_CONTINUE : DI_WALK_TERMINATE);
1216 }
1217 #endif
1218
1219 static ssize_t
gethwid(buf,len,ifname,hwtypep)1220 gethwid(buf, len, ifname, hwtypep)
1221 char *buf;
1222 int len;
1223 const char *ifname;
1224 u_int16_t *hwtypep;
1225 {
1226 struct ifaddrs *ifa, *ifap;
1227 #ifdef __KAME__
1228 struct sockaddr_dl *sdl;
1229 #endif
1230 #ifdef __linux__
1231 struct sockaddr_ll *sll;
1232 #endif
1233 ssize_t l;
1234
1235 #ifdef __sun__
1236 if (ifname == NULL) {
1237 di_node_t root;
1238 struct hwparms parms;
1239
1240 if ((root = di_init("/", DINFOSUBTREE | DINFOMINOR |
1241 DINFOPROP)) == DI_NODE_NIL) {
1242 d_printf(LOG_INFO, FNAME, "di_init failed");
1243 return (-1);
1244 }
1245 parms.buf = buf;
1246 parms.hwtypep = hwtypep;
1247 parms.retval = -1;
1248 (void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, &parms,
1249 devfs_handler);
1250 di_fini(root);
1251 return (parms.retval);
1252 } else {
1253 return (getifhwaddr(ifname, buf, hwtypep, -1));
1254 }
1255 #endif
1256
1257 if (getifaddrs(&ifap) < 0)
1258 return (-1);
1259
1260 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1261 if (ifname && strcmp(ifa->ifa_name, ifname) != 0)
1262 continue;
1263 if (ifa->ifa_addr == NULL)
1264 continue;
1265 #ifdef __KAME__
1266 if (ifa->ifa_addr->sa_family != AF_LINK)
1267 continue;
1268
1269 sdl = (struct sockaddr_dl *)ifa->ifa_addr;
1270 if (len < 2 + sdl->sdl_alen)
1271 goto fail;
1272 /*
1273 * translate interface type to hardware type based on
1274 * http://www.iana.org/assignments/arp-parameters
1275 */
1276 switch(sdl->sdl_type) {
1277 case IFT_ETHER:
1278 #ifdef IFT_IEEE80211
1279 case IFT_IEEE80211:
1280 #endif
1281 *hwtypep = ARPHRD_ETHER;
1282 break;
1283 default:
1284 continue; /* XXX */
1285 }
1286 d_printf(LOG_DEBUG, FNAME, "found an interface %s for DUID",
1287 ifa->ifa_name);
1288 memcpy(buf, LLADDR(sdl), sdl->sdl_alen);
1289 l = sdl->sdl_alen; /* sdl will soon be freed */
1290 #endif
1291 #ifdef __linux__
1292 if (ifa->ifa_addr->sa_family != AF_PACKET)
1293 continue;
1294
1295 sll = (struct sockaddr_ll *)ifa->ifa_addr;
1296 if (sll->sll_hatype != ARPHRD_ETHER)
1297 continue;
1298 *hwtypep = ARPHRD_ETHER;
1299 d_printf(LOG_DEBUG, FNAME, "found an interface %s for DUID",
1300 ifa->ifa_name);
1301 memcpy(buf, sll->sll_addr, sll->sll_halen);
1302 l = sll->sll_halen; /* sll will soon be freed */
1303 #endif
1304 freeifaddrs(ifap);
1305 return (l);
1306 }
1307
1308 fail:
1309 freeifaddrs(ifap);
1310 return (-1);
1311 }
1312
1313 void
dhcp6_init_options(optinfo)1314 dhcp6_init_options(optinfo)
1315 struct dhcp6_optinfo *optinfo;
1316 {
1317 memset(optinfo, 0, sizeof(*optinfo));
1318
1319 optinfo->pref = DH6OPT_PREF_UNDEF;
1320 optinfo->elapsed_time = DH6OPT_ELAPSED_TIME_UNDEF;
1321 optinfo->refreshtime = DH6OPT_REFRESHTIME_UNDEF;
1322
1323 TAILQ_INIT(&optinfo->iapd_list);
1324 TAILQ_INIT(&optinfo->iana_list);
1325 TAILQ_INIT(&optinfo->reqopt_list);
1326 TAILQ_INIT(&optinfo->stcode_list);
1327 TAILQ_INIT(&optinfo->sip_list);
1328 TAILQ_INIT(&optinfo->sipname_list);
1329 TAILQ_INIT(&optinfo->dns_list);
1330 TAILQ_INIT(&optinfo->dnsname_list);
1331 TAILQ_INIT(&optinfo->ntp_list);
1332 TAILQ_INIT(&optinfo->prefix_list);
1333 TAILQ_INIT(&optinfo->nis_list);
1334 TAILQ_INIT(&optinfo->nisname_list);
1335 TAILQ_INIT(&optinfo->nisp_list);
1336 TAILQ_INIT(&optinfo->nispname_list);
1337 TAILQ_INIT(&optinfo->bcmcs_list);
1338 TAILQ_INIT(&optinfo->bcmcsname_list);
1339
1340 optinfo->authproto = DHCP6_AUTHPROTO_UNDEF;
1341 optinfo->authalgorithm = DHCP6_AUTHALG_UNDEF;
1342 optinfo->authrdm = DHCP6_AUTHRDM_UNDEF;
1343 }
1344
1345 void
dhcp6_clear_options(optinfo)1346 dhcp6_clear_options(optinfo)
1347 struct dhcp6_optinfo *optinfo;
1348 {
1349 switch (optinfo->authproto) {
1350 case DHCP6_AUTHPROTO_DELAYED:
1351 if (optinfo->delayedauth_realmval != NULL) {
1352 free(optinfo->delayedauth_realmval);
1353 }
1354 break;
1355 }
1356
1357 duidfree(&optinfo->clientID);
1358 duidfree(&optinfo->serverID);
1359
1360 dhcp6_clear_list(&optinfo->iapd_list);
1361 dhcp6_clear_list(&optinfo->iana_list);
1362 dhcp6_clear_list(&optinfo->reqopt_list);
1363 dhcp6_clear_list(&optinfo->stcode_list);
1364 dhcp6_clear_list(&optinfo->sip_list);
1365 dhcp6_clear_list(&optinfo->sipname_list);
1366 dhcp6_clear_list(&optinfo->dns_list);
1367 dhcp6_clear_list(&optinfo->dnsname_list);
1368 dhcp6_clear_list(&optinfo->ntp_list);
1369 dhcp6_clear_list(&optinfo->prefix_list);
1370 dhcp6_clear_list(&optinfo->nis_list);
1371 dhcp6_clear_list(&optinfo->nisname_list);
1372 dhcp6_clear_list(&optinfo->nisp_list);
1373 dhcp6_clear_list(&optinfo->nispname_list);
1374 dhcp6_clear_list(&optinfo->bcmcs_list);
1375 dhcp6_clear_list(&optinfo->bcmcsname_list);
1376
1377 if (optinfo->relaymsg_msg != NULL)
1378 free(optinfo->relaymsg_msg);
1379
1380 if (optinfo->ifidopt_id != NULL)
1381 free(optinfo->ifidopt_id);
1382
1383 dhcp6_init_options(optinfo);
1384 }
1385
1386 int
dhcp6_copy_options(dst,src)1387 dhcp6_copy_options(dst, src)
1388 struct dhcp6_optinfo *dst, *src;
1389 {
1390 if (duidcpy(&dst->clientID, &src->clientID))
1391 goto fail;
1392 if (duidcpy(&dst->serverID, &src->serverID))
1393 goto fail;
1394 dst->rapidcommit = src->rapidcommit;
1395
1396 if (dhcp6_copy_list(&dst->iapd_list, &src->iapd_list))
1397 goto fail;
1398 if (dhcp6_copy_list(&dst->iana_list, &src->iana_list))
1399 goto fail;
1400 if (dhcp6_copy_list(&dst->reqopt_list, &src->reqopt_list))
1401 goto fail;
1402 if (dhcp6_copy_list(&dst->stcode_list, &src->stcode_list))
1403 goto fail;
1404 if (dhcp6_copy_list(&dst->sip_list, &src->sip_list))
1405 goto fail;
1406 if (dhcp6_copy_list(&dst->sipname_list, &src->sipname_list))
1407 goto fail;
1408 if (dhcp6_copy_list(&dst->dns_list, &src->dns_list))
1409 goto fail;
1410 if (dhcp6_copy_list(&dst->dnsname_list, &src->dnsname_list))
1411 goto fail;
1412 if (dhcp6_copy_list(&dst->ntp_list, &src->ntp_list))
1413 goto fail;
1414 if (dhcp6_copy_list(&dst->prefix_list, &src->prefix_list))
1415 goto fail;
1416 if (dhcp6_copy_list(&dst->nis_list, &src->nis_list))
1417 goto fail;
1418 if (dhcp6_copy_list(&dst->nisname_list, &src->nisname_list))
1419 goto fail;
1420 if (dhcp6_copy_list(&dst->nisp_list, &src->nisp_list))
1421 goto fail;
1422 if (dhcp6_copy_list(&dst->nispname_list, &src->nispname_list))
1423 goto fail;
1424 if (dhcp6_copy_list(&dst->bcmcs_list, &src->bcmcs_list))
1425 goto fail;
1426 if (dhcp6_copy_list(&dst->bcmcsname_list, &src->bcmcsname_list))
1427 goto fail;
1428 dst->elapsed_time = src->elapsed_time;
1429 dst->refreshtime = src->refreshtime;
1430 dst->pref = src->pref;
1431
1432 if (src->relaymsg_msg != NULL) {
1433 if ((dst->relaymsg_msg = malloc(src->relaymsg_len)) == NULL)
1434 goto fail;
1435 dst->relaymsg_len = src->relaymsg_len;
1436 memcpy(dst->relaymsg_msg, src->relaymsg_msg,
1437 src->relaymsg_len);
1438 }
1439
1440 if (src->ifidopt_id != NULL) {
1441 if ((dst->ifidopt_id = malloc(src->ifidopt_len)) == NULL)
1442 goto fail;
1443 dst->ifidopt_len = src->ifidopt_len;
1444 memcpy(dst->ifidopt_id, src->ifidopt_id, src->ifidopt_len);
1445 }
1446
1447 dst->authflags = src->authflags;
1448 dst->authproto = src->authproto;
1449 dst->authalgorithm = src->authalgorithm;
1450 dst->authrdm = src->authrdm;
1451 dst->authrd = src->authrd;
1452
1453 switch (src->authproto) {
1454 case DHCP6_AUTHPROTO_DELAYED:
1455 dst->delayedauth_keyid = src->delayedauth_keyid;
1456 dst->delayedauth_offset = src->delayedauth_offset;
1457 dst->delayedauth_realmlen = src->delayedauth_realmlen;
1458 if (src->delayedauth_realmval != NULL) {
1459 if ((dst->delayedauth_realmval =
1460 malloc(src->delayedauth_realmlen)) == NULL) {
1461 goto fail;
1462 }
1463 memcpy(dst->delayedauth_realmval,
1464 src->delayedauth_realmval,
1465 src->delayedauth_realmlen);
1466 }
1467 break;
1468 case DHCP6_AUTHPROTO_RECONFIG:
1469 dst->reconfigauth_type = src->reconfigauth_type;
1470 dst->reconfigauth_offset = src->reconfigauth_offset;
1471 memcpy(dst->reconfigauth_val, src->reconfigauth_val,
1472 sizeof(dst->reconfigauth_val));
1473 break;
1474 }
1475
1476 return (0);
1477
1478 fail:
1479 /* cleanup temporary resources */
1480 dhcp6_clear_options(dst);
1481 return (-1);
1482 }
1483
1484 int
dhcp6_get_options(p,ep,optinfo)1485 dhcp6_get_options(p, ep, optinfo)
1486 struct dhcp6opt *p, *ep;
1487 struct dhcp6_optinfo *optinfo;
1488 {
1489 struct dhcp6opt *np, opth;
1490 int i, opt, optlen, reqopts, num;
1491 u_int16_t num16;
1492 char *bp, *cp, *val;
1493 u_int16_t val16;
1494 u_int32_t val32;
1495 struct dhcp6opt_ia optia;
1496 struct dhcp6_ia ia;
1497 struct dhcp6_list sublist;
1498 int authinfolen;
1499
1500 bp = (char *)p;
1501 for (; p + 1 <= ep; p = np) {
1502 struct duid duid0;
1503
1504 /*
1505 * get the option header. XXX: since there is no guarantee
1506 * about the header alignment, we need to make a local copy.
1507 */
1508 memcpy(&opth, p, sizeof(opth));
1509 optlen = ntohs(opth.dh6opt_len);
1510 opt = ntohs(opth.dh6opt_type);
1511
1512 cp = (char *)(p + 1);
1513 np = (struct dhcp6opt *)(cp + optlen);
1514
1515 d_printf(LOG_DEBUG, FNAME, "get DHCP option %s, len %d",
1516 dhcp6optstr(opt), optlen);
1517
1518 /* option length field overrun */
1519 if (np > ep) {
1520 d_printf(LOG_INFO, FNAME, "malformed DHCP options");
1521 goto fail;
1522 }
1523
1524 switch (opt) {
1525 case DH6OPT_CLIENTID:
1526 if (optlen == 0)
1527 goto malformed;
1528 duid0.duid_len = optlen;
1529 duid0.duid_id = cp;
1530 d_printf(LOG_DEBUG, "",
1531 " DUID: %s", duidstr(&duid0));
1532 if (duidcpy(&optinfo->clientID, &duid0)) {
1533 d_printf(LOG_ERR, FNAME, "failed to copy DUID");
1534 goto fail;
1535 }
1536 break;
1537 case DH6OPT_SERVERID:
1538 if (optlen == 0)
1539 goto malformed;
1540 duid0.duid_len = optlen;
1541 duid0.duid_id = cp;
1542 d_printf(LOG_DEBUG, "", " DUID: %s", duidstr(&duid0));
1543 if (duidcpy(&optinfo->serverID, &duid0)) {
1544 d_printf(LOG_ERR, FNAME, "failed to copy DUID");
1545 goto fail;
1546 }
1547 break;
1548 case DH6OPT_STATUS_CODE:
1549 if (optlen < sizeof(u_int16_t))
1550 goto malformed;
1551 memcpy(&val16, cp, sizeof(val16));
1552 num16 = ntohs(val16);
1553 d_printf(LOG_DEBUG, "", " status code: %s",
1554 dhcp6_stcodestr(num16));
1555
1556 /* need to check duplication? */
1557
1558 if (dhcp6_add_listval(&optinfo->stcode_list,
1559 DHCP6_LISTVAL_STCODE, &num16, NULL) == NULL) {
1560 d_printf(LOG_ERR, FNAME, "failed to copy "
1561 "status code");
1562 goto fail;
1563 }
1564
1565 break;
1566 case DH6OPT_ORO:
1567 if ((optlen % 2) != 0 || optlen == 0)
1568 goto malformed;
1569 reqopts = optlen / 2;
1570 for (i = 0, val = cp; i < reqopts;
1571 i++, val += sizeof(u_int16_t)) {
1572 u_int16_t opttype;
1573
1574 memcpy(&opttype, val, sizeof(u_int16_t));
1575 num = (int)ntohs(opttype);
1576
1577 d_printf(LOG_DEBUG, "",
1578 " requested option: %s",
1579 dhcp6optstr(num));
1580
1581 if (dhcp6_find_listval(&optinfo->reqopt_list,
1582 DHCP6_LISTVAL_NUM, &num, 0)) {
1583 d_printf(LOG_INFO, FNAME, "duplicated "
1584 "option type (%s)",
1585 dhcp6optstr(opttype));
1586 goto nextoption;
1587 }
1588
1589 if (dhcp6_add_listval(&optinfo->reqopt_list,
1590 DHCP6_LISTVAL_NUM, &num, NULL) == NULL) {
1591 d_printf(LOG_ERR, FNAME,
1592 "failed to copy requested option");
1593 goto fail;
1594 }
1595 nextoption:
1596 ;
1597 }
1598 break;
1599 case DH6OPT_PREFERENCE:
1600 if (optlen != 1)
1601 goto malformed;
1602 d_printf(LOG_DEBUG, "", " preference: %d",
1603 (int)*(u_char *)cp);
1604 if (optinfo->pref != DH6OPT_PREF_UNDEF) {
1605 d_printf(LOG_INFO, FNAME,
1606 "duplicated preference option");
1607 } else
1608 optinfo->pref = (int)*(u_char *)cp;
1609 break;
1610 case DH6OPT_ELAPSED_TIME:
1611 if (optlen != 2)
1612 goto malformed;
1613 memcpy(&val16, cp, sizeof(val16));
1614 val16 = ntohs(val16);
1615 d_printf(LOG_DEBUG, "", " elapsed time: %lu",
1616 (u_int32_t)val16);
1617 if (optinfo->elapsed_time !=
1618 DH6OPT_ELAPSED_TIME_UNDEF) {
1619 d_printf(LOG_INFO, FNAME,
1620 "duplicated elapsed time option");
1621 } else
1622 optinfo->elapsed_time = val16;
1623 break;
1624 case DH6OPT_RELAY_MSG:
1625 if ((optinfo->relaymsg_msg = malloc(optlen)) == NULL)
1626 goto fail;
1627 memcpy(optinfo->relaymsg_msg, cp, optlen);
1628 optinfo->relaymsg_len = optlen;
1629 break;
1630 case DH6OPT_AUTH:
1631 if (optlen < sizeof(struct dhcp6opt_auth) - 4)
1632 goto malformed;
1633
1634 /*
1635 * Any DHCP message that includes more than one
1636 * authentication option MUST be discarded.
1637 * [RFC3315 Section 21.4.2]
1638 */
1639 if (optinfo->authproto != DHCP6_AUTHPROTO_UNDEF) {
1640 d_printf(LOG_INFO, FNAME, "found more than one "
1641 "authentication option");
1642 goto fail;
1643 }
1644
1645 optinfo->authproto = *cp++;
1646 optinfo->authalgorithm = *cp++;
1647 optinfo->authrdm = *cp++;
1648 memcpy(&optinfo->authrd, cp, sizeof(optinfo->authrd));
1649 cp += sizeof(optinfo->authrd);
1650
1651 d_printf(LOG_DEBUG, "", " %s", sprint_auth(optinfo));
1652
1653 authinfolen =
1654 optlen - (sizeof(struct dhcp6opt_auth) - 4);
1655 switch (optinfo->authproto) {
1656 case DHCP6_AUTHPROTO_DELAYED:
1657 if (authinfolen == 0) {
1658 optinfo->authflags |=
1659 DHCP6OPT_AUTHFLAG_NOINFO;
1660 break;
1661 }
1662 /* XXX: should we reject an empty realm? */
1663 if (authinfolen <
1664 sizeof(optinfo->delayedauth_keyid) + 16) {
1665 goto malformed;
1666 }
1667
1668 optinfo->delayedauth_realmlen = authinfolen -
1669 (sizeof(optinfo->delayedauth_keyid) + 16);
1670 optinfo->delayedauth_realmval =
1671 malloc(optinfo->delayedauth_realmlen);
1672 if (optinfo->delayedauth_realmval == NULL) {
1673 d_printf(LOG_WARNING, FNAME, "failed "
1674 "allocate memory for auth realm");
1675 goto fail;
1676 }
1677 memcpy(optinfo->delayedauth_realmval, cp,
1678 optinfo->delayedauth_realmlen);
1679 cp += optinfo->delayedauth_realmlen;
1680
1681 memcpy(&optinfo->delayedauth_keyid, cp,
1682 sizeof(optinfo->delayedauth_keyid));
1683 optinfo->delayedauth_keyid =
1684 ntohl(optinfo->delayedauth_keyid);
1685 cp += sizeof(optinfo->delayedauth_keyid);
1686
1687 optinfo->delayedauth_offset = cp - bp;
1688 cp += 16;
1689
1690 d_printf(LOG_DEBUG, "", " auth key ID: %x, "
1691 "offset=%d, realmlen=%d",
1692 optinfo->delayedauth_keyid,
1693 optinfo->delayedauth_offset,
1694 optinfo->delayedauth_realmlen);
1695 break;
1696 #ifdef notyet
1697 case DHCP6_AUTHPROTO_RECONFIG:
1698 break;
1699 #endif
1700 default:
1701 d_printf(LOG_INFO, FNAME,
1702 "unsupported authentication protocol: %d",
1703 *cp);
1704 goto fail;
1705 }
1706 break;
1707 case DH6OPT_RAPID_COMMIT:
1708 if (optlen != 0)
1709 goto malformed;
1710 optinfo->rapidcommit = 1;
1711 break;
1712 case DH6OPT_INTERFACE_ID:
1713 if ((optinfo->ifidopt_id = malloc(optlen)) == NULL)
1714 goto fail;
1715 memcpy(optinfo->ifidopt_id, cp, optlen);
1716 optinfo->ifidopt_len = optlen;
1717 break;
1718 case DH6OPT_SIP_SERVER_D:
1719 if (dhcp6_get_domain(optlen, cp, opt,
1720 &optinfo->sipname_list) == -1)
1721 goto fail;
1722 break;
1723 case DH6OPT_DNSNAME:
1724 if (dhcp6_get_domain(optlen, cp, opt,
1725 &optinfo->dnsname_list) == -1)
1726 goto fail;
1727 break;
1728 case DH6OPT_NIS_DOMAIN_NAME:
1729 if (dhcp6_get_domain(optlen, cp, opt,
1730 &optinfo->nisname_list) == -1)
1731 goto fail;
1732 break;
1733 case DH6OPT_NISP_DOMAIN_NAME:
1734 if (dhcp6_get_domain(optlen, cp, opt,
1735 &optinfo->nispname_list) == -1)
1736 goto fail;
1737 break;
1738 case DH6OPT_BCMCS_SERVER_D:
1739 if (dhcp6_get_domain(optlen, cp, opt,
1740 &optinfo->bcmcsname_list) == -1)
1741 goto fail;
1742 break;
1743 case DH6OPT_SIP_SERVER_A:
1744 if (dhcp6_get_addr(optlen, cp, opt,
1745 &optinfo->sip_list) == -1)
1746 goto fail;
1747 break;
1748 case DH6OPT_DNS:
1749 if (dhcp6_get_addr(optlen, cp, opt,
1750 &optinfo->dns_list) == -1)
1751 goto fail;
1752 break;
1753 case DH6OPT_NIS_SERVERS:
1754 if (dhcp6_get_addr(optlen, cp, opt,
1755 &optinfo->nis_list) == -1)
1756 goto fail;
1757 break;
1758 case DH6OPT_NISP_SERVERS:
1759 if (dhcp6_get_addr(optlen, cp, opt,
1760 &optinfo->nisp_list) == -1)
1761 goto fail;
1762 break;
1763 case DH6OPT_BCMCS_SERVER_A:
1764 if (dhcp6_get_addr(optlen, cp, opt,
1765 &optinfo->bcmcs_list) == -1)
1766 goto fail;
1767 break;
1768 case DH6OPT_NTP:
1769 if (dhcp6_get_addr(optlen, cp, opt,
1770 &optinfo->ntp_list) == -1)
1771 goto fail;
1772 break;
1773 case DH6OPT_IA_PD:
1774 if (optlen + sizeof(struct dhcp6opt) <
1775 sizeof(optia))
1776 goto malformed;
1777 memcpy(&optia, p, sizeof(optia));
1778 ia.iaid = ntohl(optia.dh6_ia_iaid);
1779 ia.t1 = ntohl(optia.dh6_ia_t1);
1780 ia.t2 = ntohl(optia.dh6_ia_t2);
1781
1782 d_printf(LOG_DEBUG, "",
1783 " IA_PD: ID=%lu, T1=%lu, T2=%lu",
1784 ia.iaid, ia.t1, ia.t2);
1785
1786 /* duplication check */
1787 if (dhcp6_find_listval(&optinfo->iapd_list,
1788 DHCP6_LISTVAL_IAPD, &ia, 0)) {
1789 d_printf(LOG_INFO, FNAME,
1790 "duplicated IA_PD %lu", ia.iaid);
1791 break; /* ignore this IA_PD */
1792 }
1793
1794 /* take care of sub-options */
1795 TAILQ_INIT(&sublist);
1796 if (copyin_option(opt,
1797 (struct dhcp6opt *)((char *)p + sizeof(optia)),
1798 (struct dhcp6opt *)(cp + optlen), &sublist)) {
1799 goto fail;
1800 }
1801
1802 /* link this option set */
1803 if (dhcp6_add_listval(&optinfo->iapd_list,
1804 DHCP6_LISTVAL_IAPD, &ia, &sublist) == NULL) {
1805 dhcp6_clear_list(&sublist);
1806 goto fail;
1807 }
1808 dhcp6_clear_list(&sublist);
1809
1810 break;
1811 case DH6OPT_REFRESHTIME:
1812 if (optlen != 4)
1813 goto malformed;
1814 memcpy(&val32, cp, sizeof(val32));
1815 val32 = ntohl(val32);
1816 d_printf(LOG_DEBUG, "",
1817 " information refresh time: %lu", val32);
1818 if (val32 < DHCP6_IRT_MINIMUM) {
1819 /*
1820 * A client MUST use the refresh time
1821 * IRT_MINIMUM if it receives the option with a
1822 * value less than IRT_MINIMUM.
1823 * [draft-ietf-dhc-lifetime-02.txt,
1824 * Section 3.2]
1825 */
1826 d_printf(LOG_INFO, FNAME,
1827 "refresh time is too small (%d), adjusted",
1828 val32);
1829 val32 = DHCP6_IRT_MINIMUM;
1830 }
1831 if (optinfo->refreshtime != DH6OPT_REFRESHTIME_UNDEF) {
1832 d_printf(LOG_INFO, FNAME,
1833 "duplicated refresh time option");
1834 } else
1835 optinfo->refreshtime = (int64_t)val32;
1836 break;
1837 case DH6OPT_IA_NA:
1838 if (optlen + sizeof(struct dhcp6opt) <
1839 sizeof(optia))
1840 goto malformed;
1841 memcpy(&optia, p, sizeof(optia));
1842 ia.iaid = ntohl(optia.dh6_ia_iaid);
1843 ia.t1 = ntohl(optia.dh6_ia_t1);
1844 ia.t2 = ntohl(optia.dh6_ia_t2);
1845
1846 d_printf(LOG_DEBUG, "",
1847 " IA_NA: ID=%lu, T1=%lu, T2=%lu",
1848 ia.iaid, ia.t1, ia.t2);
1849
1850 /* duplication check */
1851 if (dhcp6_find_listval(&optinfo->iana_list,
1852 DHCP6_LISTVAL_IANA, &ia, 0)) {
1853 d_printf(LOG_INFO, FNAME,
1854 "duplicated IA_NA %lu", ia.iaid);
1855 break; /* ignore this IA_NA */
1856 }
1857
1858 /* take care of sub-options */
1859 TAILQ_INIT(&sublist);
1860 if (copyin_option(opt,
1861 (struct dhcp6opt *)((char *)p + sizeof(optia)),
1862 (struct dhcp6opt *)(cp + optlen), &sublist)) {
1863 goto fail;
1864 }
1865
1866 /* link this option set */
1867 if (dhcp6_add_listval(&optinfo->iana_list,
1868 DHCP6_LISTVAL_IANA, &ia, &sublist) == NULL) {
1869 dhcp6_clear_list(&sublist);
1870 goto fail;
1871 }
1872 dhcp6_clear_list(&sublist);
1873
1874 break;
1875 default:
1876 /* no option specific behavior */
1877 d_printf(LOG_INFO, FNAME,
1878 "unknown or unexpected DHCP6 option %s, len %d",
1879 dhcp6optstr(opt), optlen);
1880 break;
1881 }
1882 }
1883
1884 return (0);
1885
1886 malformed:
1887 d_printf(LOG_INFO, FNAME, "malformed DHCP option: type %d, len %d",
1888 opt, optlen);
1889 fail:
1890 dhcp6_clear_options(optinfo);
1891 return (-1);
1892 }
1893
1894 static char *
dnsdecode(sp,ep,buf,bufsiz)1895 dnsdecode(sp, ep, buf, bufsiz)
1896 u_char **sp;
1897 u_char *ep;
1898 char *buf;
1899 size_t bufsiz;
1900 {
1901 int i, l;
1902 u_char *cp;
1903 char tmpbuf[MAXDNAME + 1];
1904
1905 cp = *sp;
1906 *buf = '\0';
1907 i = 0; /* XXX: appease gcc */
1908
1909 if (cp >= ep)
1910 return (NULL);
1911 while (cp < ep) {
1912 i = *cp;
1913 if (i == 0 || cp != *sp) {
1914 if (strlcat((char *)buf, ".", bufsiz) >= bufsiz)
1915 return (NULL); /* result overrun */
1916 }
1917 if (i == 0)
1918 break;
1919 cp++;
1920
1921 if (i > 0x3f)
1922 return (NULL); /* invalid label */
1923
1924 if (i > ep - cp)
1925 return (NULL); /* source overrun */
1926 while (i-- > 0 && cp < ep) {
1927 if (!isprint(*cp)) /* we don't accept non-printables */
1928 return (NULL);
1929 l = snprintf(tmpbuf, sizeof(tmpbuf), "%c" , *cp);
1930 if (l >= sizeof(tmpbuf) || l < 0)
1931 return (NULL);
1932 if (strlcat(buf, tmpbuf, bufsiz) >= bufsiz)
1933 return (NULL); /* result overrun */
1934 cp++;
1935 }
1936 }
1937 if (i != 0)
1938 return (NULL); /* not terminated */
1939 cp++;
1940 *sp = cp;
1941 return (buf);
1942 }
1943
1944 static int
copyin_option(type,p,ep,list)1945 copyin_option(type, p, ep, list)
1946 int type;
1947 struct dhcp6opt *p, *ep;
1948 struct dhcp6_list *list;
1949 {
1950 int opt, optlen;
1951 char *cp;
1952 struct dhcp6opt *np, opth;
1953 struct dhcp6opt_stcode opt_stcode;
1954 struct dhcp6opt_ia_pd_prefix opt_iapd_prefix;
1955 struct dhcp6_prefix iapd_prefix;
1956 struct dhcp6opt_ia_addr opt_ia_addr;
1957 struct dhcp6_prefix ia_addr;
1958 struct dhcp6_list sublist;
1959
1960 TAILQ_INIT(&sublist);
1961
1962 for (; p + 1 <= ep; p = np) {
1963 memcpy(&opth, p, sizeof(opth));
1964 optlen = ntohs(opth.dh6opt_len);
1965 opt = ntohs(opth.dh6opt_type);
1966
1967 cp = (char *)(p + 1);
1968 np = (struct dhcp6opt *)(cp + optlen);
1969
1970 d_printf(LOG_DEBUG, FNAME, "get DHCP option %s, len %d",
1971 dhcp6optstr(opt), optlen);
1972
1973 if (np > ep) {
1974 d_printf(LOG_INFO, FNAME, "malformed DHCP option");
1975 goto fail;
1976 }
1977
1978 switch (opt) {
1979 case DH6OPT_IA_PD_PREFIX:
1980 /* check option context */
1981 if (type != DH6OPT_IA_PD) {
1982 d_printf(LOG_INFO, FNAME,
1983 "%s is an invalid position for %s",
1984 dhcp6optstr(type), dhcp6optstr(opt));
1985 goto fail;
1986 }
1987 /* check option length */
1988 if (optlen + sizeof(opth) < sizeof(opt_iapd_prefix))
1989 goto malformed;
1990
1991 /* copy and convert option values */
1992 memcpy(&opt_iapd_prefix, p, sizeof(opt_iapd_prefix));
1993 if (opt_iapd_prefix.dh6_iapd_prefix_prefix_len > 128) {
1994 d_printf(LOG_INFO, FNAME,
1995 "invalid prefix length (%d)",
1996 opt_iapd_prefix.dh6_iapd_prefix_prefix_len);
1997 goto malformed;
1998 }
1999 iapd_prefix.pltime = ntohl(opt_iapd_prefix.dh6_iapd_prefix_preferred_time);
2000 iapd_prefix.vltime = ntohl(opt_iapd_prefix.dh6_iapd_prefix_valid_time);
2001 iapd_prefix.plen =
2002 opt_iapd_prefix.dh6_iapd_prefix_prefix_len;
2003 memcpy(&iapd_prefix.addr,
2004 &opt_iapd_prefix.dh6_iapd_prefix_prefix_addr,
2005 sizeof(iapd_prefix.addr));
2006 /* clear padding bits in the prefix address */
2007 prefix6_mask(&iapd_prefix.addr, iapd_prefix.plen);
2008
2009 d_printf(LOG_DEBUG, FNAME, " IA_PD prefix: "
2010 "%s/%d pltime=%lu vltime=%lu",
2011 in6addr2str(&iapd_prefix.addr, 0),
2012 iapd_prefix.plen,
2013 iapd_prefix.pltime, iapd_prefix.vltime);
2014
2015 if (dhcp6_find_listval(list, DHCP6_LISTVAL_PREFIX6,
2016 &iapd_prefix, 0)) {
2017 d_printf(LOG_INFO, FNAME,
2018 "duplicated IA_PD prefix "
2019 "%s/%d pltime=%lu vltime=%lu",
2020 in6addr2str(&iapd_prefix.addr, 0),
2021 iapd_prefix.plen,
2022 iapd_prefix.pltime, iapd_prefix.vltime);
2023 goto nextoption;
2024 }
2025
2026 /* take care of sub-options */
2027 TAILQ_INIT(&sublist);
2028 if (copyin_option(opt,
2029 (struct dhcp6opt *)((char *)p +
2030 sizeof(opt_iapd_prefix)), np, &sublist)) {
2031 goto fail;
2032 }
2033
2034 if (dhcp6_add_listval(list, DHCP6_LISTVAL_PREFIX6,
2035 &iapd_prefix, &sublist) == NULL) {
2036 dhcp6_clear_list(&sublist);
2037 goto fail;
2038 }
2039 dhcp6_clear_list(&sublist);
2040 break;
2041 case DH6OPT_IAADDR:
2042 /* check option context */
2043 if (type != DH6OPT_IA_NA) {
2044 d_printf(LOG_INFO, FNAME,
2045 "%s is an invalid position for %s",
2046 dhcp6optstr(type), dhcp6optstr(opt));
2047 goto fail;
2048 }
2049 /* check option length */
2050 if (optlen + sizeof(opth) < sizeof(opt_ia_addr))
2051 goto malformed;
2052
2053 /* copy and convert option values */
2054 memcpy(&opt_ia_addr, p, sizeof(opt_ia_addr));
2055 ia_addr.pltime = ntohl(opt_ia_addr.dh6_ia_addr_preferred_time);
2056 ia_addr.vltime = ntohl(opt_ia_addr.dh6_ia_addr_valid_time);
2057 memcpy(&ia_addr.addr, &opt_ia_addr.dh6_ia_addr_addr,
2058 sizeof(ia_addr.addr));
2059
2060 d_printf(LOG_DEBUG, FNAME, " IA_NA address: "
2061 "%s pltime=%lu vltime=%lu",
2062 in6addr2str(&ia_addr.addr, 0),
2063 ia_addr.pltime, ia_addr.vltime);
2064
2065 if (dhcp6_find_listval(list,
2066 DHCP6_LISTVAL_STATEFULADDR6, &ia_addr, 0)) {
2067 d_printf(LOG_INFO, FNAME,
2068 "duplicated IA_NA address"
2069 "%s pltime=%lu vltime=%lu",
2070 in6addr2str(&ia_addr.addr, 0),
2071 ia_addr.pltime, ia_addr.vltime);
2072 goto nextoption;
2073 }
2074
2075 /* take care of sub-options */
2076 TAILQ_INIT(&sublist);
2077 if (copyin_option(opt,
2078 (struct dhcp6opt *)((char *)p +
2079 sizeof(opt_ia_addr)), np, &sublist)) {
2080 goto fail;
2081 }
2082
2083 if (dhcp6_add_listval(list, DHCP6_LISTVAL_STATEFULADDR6,
2084 &ia_addr, &sublist) == NULL) {
2085 dhcp6_clear_list(&sublist);
2086 goto fail;
2087 }
2088 dhcp6_clear_list(&sublist);
2089 break;
2090 case DH6OPT_STATUS_CODE:
2091 /* check option context */
2092 if (type != DH6OPT_IA_PD &&
2093 type != DH6OPT_IA_PD_PREFIX &&
2094 type != DH6OPT_IA_NA &&
2095 type != DH6OPT_IAADDR) {
2096 d_printf(LOG_INFO, FNAME,
2097 "%s is an invalid position for %s",
2098 dhcp6optstr(type), dhcp6optstr(opt));
2099 goto nextoption; /* or discard the message? */
2100 }
2101 /* check option length */
2102 if (optlen + sizeof(opth) < sizeof(opt_stcode))
2103 goto malformed;
2104
2105 /* copy and convert option values */
2106 memcpy(&opt_stcode, p, sizeof(opt_stcode));
2107 opt_stcode.dh6_stcode_code =
2108 ntohs(opt_stcode.dh6_stcode_code);
2109
2110 d_printf(LOG_DEBUG, "", " status code: %s",
2111 dhcp6_stcodestr(opt_stcode.dh6_stcode_code));
2112
2113 /* duplication check */
2114 if (dhcp6_find_listval(list, DHCP6_LISTVAL_STCODE,
2115 &opt_stcode.dh6_stcode_code, 0)) {
2116 d_printf(LOG_INFO, FNAME,
2117 "duplicated status code (%d)",
2118 opt_stcode.dh6_stcode_code);
2119 goto nextoption;
2120 }
2121
2122 /* copy-in the code value */
2123 if (dhcp6_add_listval(list, DHCP6_LISTVAL_STCODE,
2124 &opt_stcode.dh6_stcode_code, NULL) == NULL)
2125 goto fail;
2126
2127 break;
2128 }
2129 nextoption:
2130 ;
2131 }
2132
2133 return (0);
2134
2135 malformed:
2136 d_printf(LOG_INFO, "", " malformed DHCP option: type %d", opt);
2137
2138 fail:
2139 dhcp6_clear_list(&sublist);
2140 return (-1);
2141 }
2142
2143 static char *
sprint_uint64(buf,buflen,i64)2144 sprint_uint64(buf, buflen, i64)
2145 char *buf;
2146 int buflen;
2147 u_int64_t i64;
2148 {
2149 u_int16_t rd0, rd1, rd2, rd3;
2150 u_int16_t *ptr = (u_int16_t *)(void *)&i64;
2151
2152 rd0 = ntohs(*ptr++);
2153 rd1 = ntohs(*ptr++);
2154 rd2 = ntohs(*ptr++);
2155 rd3 = ntohs(*ptr);
2156
2157 snprintf(buf, buflen, "%04x %04x %04x %04x", rd0, rd1, rd2, rd3);
2158
2159 return (buf);
2160 }
2161
2162 static char *
sprint_auth(optinfo)2163 sprint_auth(optinfo)
2164 struct dhcp6_optinfo *optinfo;
2165 {
2166 static char ret[1024]; /* XXX: thread unsafe */
2167 char *proto, proto0[] = "unknown(255)";
2168 char *alg, alg0[] = "unknown(255)";
2169 char *rdm, rdm0[] = "unknown(255)";
2170 char rd[] = "ffff ffff ffff ffff";
2171
2172 switch (optinfo->authproto) {
2173 case DHCP6_AUTHPROTO_DELAYED:
2174 proto = "delayed";
2175 break;
2176 case DHCP6_AUTHPROTO_RECONFIG:
2177 proto = "reconfig";
2178 break;
2179 default:
2180 snprintf(proto0, sizeof(proto0), "unknown(%d)",
2181 optinfo->authproto & 0xff);
2182 proto = proto0;
2183 break;
2184 }
2185
2186 switch (optinfo->authalgorithm) {
2187 case DHCP6_AUTHALG_HMACMD5:
2188 alg = "HMAC-MD5";
2189 break;
2190 default:
2191 snprintf(alg0, sizeof(alg0), "unknown(%d)",
2192 optinfo->authalgorithm & 0xff);
2193 alg = alg0;
2194 break;
2195 }
2196
2197 switch (optinfo->authrdm) {
2198 case DHCP6_AUTHRDM_MONOCOUNTER:
2199 rdm = "mono counter";
2200 break;
2201 default:
2202 snprintf(rdm0, sizeof(rdm0), "unknown(%d)", optinfo->authrdm);
2203 rdm = rdm0;
2204 }
2205
2206 (void)sprint_uint64(rd, sizeof(rd), optinfo->authrd);
2207
2208 snprintf(ret, sizeof(ret), "proto: %s, alg: %s, RDM: %s, RD: %s",
2209 proto, alg, rdm, rd);
2210
2211 return (ret);
2212 }
2213
2214 static int
copy_option(type,len,val,optp,ep,totallenp)2215 copy_option(type, len, val, optp, ep, totallenp)
2216 u_int16_t type, len;
2217 void *val;
2218 struct dhcp6opt **optp, *ep;
2219 int *totallenp;
2220 {
2221 struct dhcp6opt *opt = *optp, opth;
2222
2223 if ((void *)ep - (void *)optp < len + sizeof(struct dhcp6opt)) {
2224 d_printf(LOG_INFO, FNAME,
2225 "option buffer short for %s", dhcp6optstr(type));
2226 return (-1);
2227 }
2228 opth.dh6opt_type = htons(type);
2229 opth.dh6opt_len = htons(len);
2230 memcpy(opt, &opth, sizeof(opth));
2231 if (len != 0)
2232 memcpy(opt + 1, val, len);
2233
2234 *optp = (struct dhcp6opt *)((char *)(opt + 1) + len);
2235 *totallenp += sizeof(struct dhcp6opt) + len;
2236 d_printf(LOG_DEBUG, FNAME, "set %s (len %d)", dhcp6optstr(type), len);
2237
2238 return (0);
2239 }
2240
2241 int
dhcp6_set_options(type,optbp,optep,optinfo)2242 dhcp6_set_options(type, optbp, optep, optinfo)
2243 int type;
2244 struct dhcp6opt *optbp, *optep;
2245 struct dhcp6_optinfo *optinfo;
2246 {
2247 struct dhcp6opt *p = optbp;
2248 struct dhcp6_listval *stcode, *op;
2249 int len = 0, optlen;
2250 char *tmpbuf = NULL;
2251
2252 if (optinfo->clientID.duid_len) {
2253 if (copy_option(DH6OPT_CLIENTID, optinfo->clientID.duid_len,
2254 optinfo->clientID.duid_id, &p, optep, &len) != 0) {
2255 goto fail;
2256 }
2257 }
2258
2259 if (optinfo->serverID.duid_len) {
2260 if (copy_option(DH6OPT_SERVERID, optinfo->serverID.duid_len,
2261 optinfo->serverID.duid_id, &p, optep, &len) != 0) {
2262 goto fail;
2263 }
2264 }
2265
2266 for (op = TAILQ_FIRST(&optinfo->iana_list); op;
2267 op = TAILQ_NEXT(op, link)) {
2268 int optlen;
2269
2270 tmpbuf = NULL;
2271 if ((optlen = copyout_option(NULL, NULL, op)) < 0) {
2272 d_printf(LOG_INFO, FNAME,
2273 "failed to count option length");
2274 goto fail;
2275 }
2276 if ((void *)optep - (void *)p < optlen) {
2277 d_printf(LOG_INFO, FNAME, "short buffer");
2278 goto fail;
2279 }
2280 if ((tmpbuf = malloc(optlen)) == NULL) {
2281 d_printf(LOG_NOTICE, FNAME,
2282 "memory allocation failed for IA_NA options");
2283 goto fail;
2284 }
2285 if (copyout_option(tmpbuf, tmpbuf + optlen, op) < 0) {
2286 d_printf(LOG_ERR, FNAME,
2287 "failed to construct an IA_NA option");
2288 goto fail;
2289 }
2290 memcpy(p, tmpbuf, optlen);
2291 free(tmpbuf);
2292 tmpbuf = NULL;
2293 p = (struct dhcp6opt *)((char *)p + optlen);
2294 len += optlen;
2295 }
2296
2297 if (optinfo->rapidcommit) {
2298 if (copy_option(DH6OPT_RAPID_COMMIT, 0, NULL, &p,
2299 optep, &len) != 0) {
2300 goto fail;
2301 }
2302 }
2303
2304 if (optinfo->pref != DH6OPT_PREF_UNDEF) {
2305 u_int8_t p8 = (u_int8_t)optinfo->pref;
2306
2307 if (copy_option(DH6OPT_PREFERENCE, sizeof(p8), &p8, &p,
2308 optep, &len) != 0) {
2309 goto fail;
2310 }
2311 }
2312
2313 if (optinfo->elapsed_time != DH6OPT_ELAPSED_TIME_UNDEF) {
2314 u_int16_t p16 = (u_int16_t)optinfo->elapsed_time;
2315
2316 p16 = htons(p16);
2317 if (copy_option(DH6OPT_ELAPSED_TIME, sizeof(p16), &p16, &p,
2318 optep, &len) != 0) {
2319 goto fail;
2320 }
2321 }
2322
2323 for (stcode = TAILQ_FIRST(&optinfo->stcode_list); stcode;
2324 stcode = TAILQ_NEXT(stcode, link)) {
2325 u_int16_t code;
2326
2327 code = htons(stcode->val_num16);
2328 if (copy_option(DH6OPT_STATUS_CODE, sizeof(code), &code, &p,
2329 optep, &len) != 0) {
2330 goto fail;
2331 }
2332 }
2333
2334 if (!TAILQ_EMPTY(&optinfo->reqopt_list)) {
2335 struct dhcp6_listval *opt;
2336 u_int16_t *valp;
2337 int buflen;
2338
2339 tmpbuf = NULL;
2340 buflen = dhcp6_count_list(&optinfo->reqopt_list) *
2341 sizeof(u_int16_t);
2342 if ((tmpbuf = malloc(buflen)) == NULL) {
2343 d_printf(LOG_ERR, FNAME,
2344 "memory allocation failed for options");
2345 goto fail;
2346 }
2347 optlen = 0;
2348 valp = (u_int16_t *)tmpbuf;
2349 for (opt = TAILQ_FIRST(&optinfo->reqopt_list); opt;
2350 opt = TAILQ_NEXT(opt, link)) {
2351 /*
2352 * Information request option can only be specified
2353 * in information-request messages.
2354 * [draft-ietf-dhc-lifetime-02.txt, Section 3.2]
2355 */
2356 if (opt->val_num == DH6OPT_REFRESHTIME &&
2357 type != DH6_INFORM_REQ) {
2358 d_printf(LOG_DEBUG, FNAME,
2359 "refresh time option is not requested "
2360 "for %s", dhcp6msgstr(type));
2361 }
2362
2363 *valp = htons((u_int16_t)opt->val_num);
2364 valp++;
2365 optlen += sizeof(u_int16_t);
2366 }
2367 if (optlen > 0 &&
2368 copy_option(DH6OPT_ORO, optlen, tmpbuf, &p,
2369 optep, &len) != 0) {
2370 goto fail;
2371 }
2372 free(tmpbuf);
2373 tmpbuf = NULL;
2374 }
2375
2376 if (dhcp6_set_domain(DH6OPT_SIP_SERVER_D, &optinfo->sipname_list,
2377 &p, optep, &len) != 0)
2378 goto fail;
2379
2380 if (dhcp6_set_addr(DH6OPT_SIP_SERVER_A, &optinfo->sip_list,
2381 &p, optep, &len) != 0)
2382 goto fail;
2383
2384 if (dhcp6_set_addr(DH6OPT_DNS, &optinfo->dns_list,
2385 &p, optep, &len) != 0)
2386 goto fail;
2387
2388 if (dhcp6_set_domain(DH6OPT_DNSNAME, &optinfo->dnsname_list,
2389 &p, optep, &len) != 0)
2390 goto fail;
2391
2392 if (dhcp6_set_addr(DH6OPT_NIS_SERVERS, &optinfo->nis_list,
2393 &p, optep, &len) != 0)
2394 goto fail;
2395
2396 if (dhcp6_set_addr(DH6OPT_NISP_SERVERS, &optinfo->nisp_list,
2397 &p, optep, &len) != 0)
2398 goto fail;
2399
2400 if (dhcp6_set_domain(DH6OPT_NIS_DOMAIN_NAME, &optinfo->nisname_list,
2401 &p, optep, &len) != 0)
2402 goto fail;
2403
2404 if (dhcp6_set_domain(DH6OPT_NISP_DOMAIN_NAME, &optinfo->nispname_list,
2405 &p, optep, &len) != 0)
2406 goto fail;
2407
2408 if (dhcp6_set_addr(DH6OPT_NTP, &optinfo->ntp_list,
2409 &p, optep, &len) != 0)
2410 goto fail;
2411
2412 if (dhcp6_set_domain(DH6OPT_BCMCS_SERVER_D, &optinfo->bcmcsname_list,
2413 &p, optep, &len) != 0)
2414 goto fail;
2415
2416 if (dhcp6_set_addr(DH6OPT_BCMCS_SERVER_A, &optinfo->bcmcs_list,
2417 &p, optep, &len) != 0)
2418 goto fail;
2419
2420 for (op = TAILQ_FIRST(&optinfo->iapd_list); op;
2421 op = TAILQ_NEXT(op, link)) {
2422 int optlen;
2423
2424 tmpbuf = NULL;
2425 if ((optlen = copyout_option(NULL, NULL, op)) < 0) {
2426 d_printf(LOG_INFO, FNAME,
2427 "failed to count option length");
2428 goto fail;
2429 }
2430 if ((void *)optep - (void *)p < optlen) {
2431 d_printf(LOG_INFO, FNAME, "short buffer");
2432 goto fail;
2433 }
2434 if ((tmpbuf = malloc(optlen)) == NULL) {
2435 d_printf(LOG_NOTICE, FNAME,
2436 "memory allocation failed for IA_PD options");
2437 goto fail;
2438 }
2439 if (copyout_option(tmpbuf, tmpbuf + optlen, op) < 0) {
2440 d_printf(LOG_ERR, FNAME,
2441 "failed to construct an IA_PD option");
2442 goto fail;
2443 }
2444 memcpy(p, tmpbuf, optlen);
2445 free(tmpbuf);
2446 tmpbuf = NULL;
2447 p = (struct dhcp6opt *)((char *)p + optlen);
2448 len += optlen;
2449 }
2450
2451 if (optinfo->relaymsg_len) {
2452 if (copy_option(DH6OPT_RELAY_MSG, optinfo->relaymsg_len,
2453 optinfo->relaymsg_msg, &p, optep, &len) != 0) {
2454 goto fail;
2455 }
2456 }
2457
2458 if (optinfo->ifidopt_id) {
2459 if (copy_option(DH6OPT_INTERFACE_ID, optinfo->ifidopt_len,
2460 optinfo->ifidopt_id, &p, optep, &len) != 0) {
2461 goto fail;
2462 }
2463 }
2464
2465 if (optinfo->refreshtime != DH6OPT_REFRESHTIME_UNDEF) {
2466 u_int32_t p32 = (u_int32_t)optinfo->refreshtime;
2467
2468 p32 = htonl(p32);
2469 if (copy_option(DH6OPT_REFRESHTIME, sizeof(p32), &p32, &p,
2470 optep, &len) != 0) {
2471 goto fail;
2472 }
2473 }
2474
2475 if (optinfo->authproto != DHCP6_AUTHPROTO_UNDEF) {
2476 struct dhcp6opt_auth *auth;
2477 int authlen;
2478 char *authinfo;
2479
2480 authlen = sizeof(*auth);
2481 if (!(optinfo->authflags & DHCP6OPT_AUTHFLAG_NOINFO)) {
2482 switch (optinfo->authproto) {
2483 case DHCP6_AUTHPROTO_DELAYED:
2484 /* Realm + key ID + HMAC-MD5 */
2485 authlen += optinfo->delayedauth_realmlen +
2486 sizeof(optinfo->delayedauth_keyid) + 16;
2487 break;
2488 #ifdef notyet
2489 case DHCP6_AUTHPROTO_RECONFIG:
2490 /* type + key-or-HAMC */
2491 authlen += 17;
2492 break;
2493 #endif
2494 default:
2495 d_printf(LOG_ERR, FNAME,
2496 "unexpected authentication protocol");
2497 goto fail;
2498 }
2499 }
2500 if ((auth = malloc(authlen)) == NULL) {
2501 d_printf(LOG_WARNING, FNAME, "failed to allocate "
2502 "memory for authentication information");
2503 goto fail;
2504 }
2505
2506 memset(auth, 0, authlen);
2507 /* copy_option will take care of type and len later */
2508 auth->dh6_auth_proto = (u_int8_t)optinfo->authproto;
2509 auth->dh6_auth_alg = (u_int8_t)optinfo->authalgorithm;
2510 auth->dh6_auth_rdm = (u_int8_t)optinfo->authrdm;
2511 memcpy(auth->dh6_auth_rdinfo, &optinfo->authrd,
2512 sizeof(auth->dh6_auth_rdinfo));
2513
2514 if (!(optinfo->authflags & DHCP6OPT_AUTHFLAG_NOINFO)) {
2515 u_int32_t p32;
2516
2517 switch (optinfo->authproto) {
2518 case DHCP6_AUTHPROTO_DELAYED:
2519 authinfo = (char *)(auth + 1);
2520
2521 /* copy realm */
2522 memcpy(authinfo, optinfo->delayedauth_realmval,
2523 optinfo->delayedauth_realmlen);
2524 authinfo += optinfo->delayedauth_realmlen;
2525
2526 /* copy key ID (need memcpy for alignment) */
2527 p32 = htonl(optinfo->delayedauth_keyid);
2528 memcpy(authinfo, &p32, sizeof(p32));
2529
2530 /*
2531 * Set the offset so that the caller can
2532 * calculate the HMAC.
2533 */
2534 optinfo->delayedauth_offset =
2535 ((char *)p - (char *)optbp) + authlen - 16;
2536
2537 d_printf(LOG_DEBUG, FNAME,
2538 "key ID %x, offset %d",
2539 optinfo->delayedauth_keyid,
2540 optinfo->delayedauth_offset);
2541 break;
2542 #ifdef notyet
2543 case DHCP6_AUTHPROTO_RECONFIG:
2544 #endif
2545 default:
2546 d_printf(LOG_ERR, FNAME,
2547 "unexpected authentication protocol");
2548 free(auth);
2549 goto fail;
2550 }
2551 }
2552
2553 if (copy_option(DH6OPT_AUTH, authlen - 4,
2554 &auth->dh6_auth_proto, &p, optep, &len) != 0) {
2555 goto fail;
2556 }
2557 free(auth);
2558 }
2559
2560 return (len);
2561
2562 fail:
2563 if (tmpbuf)
2564 free(tmpbuf);
2565 return (-1);
2566 }
2567 #undef COPY_OPTION
2568
2569 static ssize_t
dnsencode(name,buf,buflen)2570 dnsencode(name, buf, buflen)
2571 const char *name;
2572 char *buf;
2573 size_t buflen;
2574 {
2575 char *cp, *ep;
2576 const char *p, *q;
2577 int i;
2578 int namelen = strlen(name);
2579
2580 cp = buf;
2581 ep = cp + buflen;
2582
2583 /* if not certain about my name, return an empty buffer */
2584 if (namelen == 0)
2585 return (0);
2586
2587 p = name;
2588 while (cp < ep && p < name + namelen) {
2589 i = 0;
2590 for (q = p; q < name + namelen && *q && *q != '.'; q++)
2591 i++;
2592 /* result does not fit into buf */
2593 if (cp + i + 1 >= ep)
2594 goto fail;
2595 /*
2596 * DNS label length restriction, RFC1035 page 8.
2597 * "i == 0" case is included here to avoid returning
2598 * 0-length label on "foo..bar".
2599 */
2600 if (i <= 0 || i >= 64)
2601 goto fail;
2602 *cp++ = i;
2603 if (!isalpha(p[0]) || !isalnum(p[i - 1]))
2604 goto fail;
2605 while (i > 0) {
2606 if (!isalnum(*p) && *p != '-')
2607 goto fail;
2608 if (isupper(*p))
2609 *cp++ = tolower(*p++);
2610 else
2611 *cp++ = *p++;
2612 i--;
2613 }
2614 p = q;
2615 if (p < name + namelen && *p == '.')
2616 p++;
2617 }
2618 /* termination */
2619 if (cp + 1 >= ep)
2620 goto fail;
2621 *cp++ = '\0';
2622 return (cp - buf);
2623
2624 fail:
2625 return (-1);
2626 }
2627
2628 /*
2629 * Construct a DHCPv6 option along with sub-options in the wire format.
2630 * If the packet buffer is NULL, just calculate the length of the option
2631 * (and sub-options) so that the caller can allocate a buffer to store the
2632 * option(s).
2633 * This function basically assumes that the caller prepares enough buffer to
2634 * store all the options. However, it also takes the buffer end and checks
2635 * the possibility of overrun for safety.
2636 */
2637 static int
copyout_option(p,ep,optval)2638 copyout_option(p, ep, optval)
2639 char *p, *ep;
2640 struct dhcp6_listval *optval;
2641 {
2642 struct dhcp6opt *opt;
2643 struct dhcp6opt_stcode stcodeopt;
2644 struct dhcp6opt_ia ia;
2645 struct dhcp6opt_ia_pd_prefix pd_prefix;
2646 struct dhcp6opt_ia_addr ia_addr;
2647 char *subp;
2648 struct dhcp6_listval *subov;
2649 int optlen, headlen, sublen, opttype;
2650
2651 /* check invariant for safety */
2652 if (p && ep <= p)
2653 return (-1);
2654
2655 /* first, detect the length of the option head */
2656 switch(optval->type) {
2657 case DHCP6_LISTVAL_IAPD:
2658 memset(&ia, 0, sizeof(ia));
2659 headlen = sizeof(ia);
2660 opttype = DH6OPT_IA_PD;
2661 opt = (struct dhcp6opt *)(void *)&ia;
2662 break;
2663 case DHCP6_LISTVAL_IANA:
2664 memset(&ia, 0, sizeof(ia));
2665 headlen = sizeof(ia);
2666 opttype = DH6OPT_IA_NA;
2667 opt = (struct dhcp6opt *)(void *)&ia;
2668 break;
2669 case DHCP6_LISTVAL_ADDR6:
2670 memset(&pd_prefix, 0, sizeof(pd_prefix));
2671 headlen = sizeof(pd_prefix);
2672 opttype = DH6OPT_IA_PD_PREFIX;
2673 opt = (struct dhcp6opt *)&pd_prefix;
2674 break;
2675 case DHCP6_LISTVAL_PREFIX6:
2676 memset(&pd_prefix, 0, sizeof(pd_prefix));
2677 headlen = sizeof(pd_prefix);
2678 opttype = DH6OPT_IA_PD_PREFIX;
2679 opt = (struct dhcp6opt *)&pd_prefix;
2680 break;
2681 case DHCP6_LISTVAL_STATEFULADDR6:
2682 memset(&ia_addr, 0, sizeof(ia_addr));
2683 headlen = sizeof(ia_addr);
2684 opttype = DH6OPT_IAADDR;
2685 opt = (struct dhcp6opt *)&ia_addr;
2686 break;
2687 case DHCP6_LISTVAL_STCODE:
2688 memset(&stcodeopt, 0, sizeof(stcodeopt));
2689 headlen = sizeof(stcodeopt);
2690 opttype = DH6OPT_STATUS_CODE;
2691 opt = (struct dhcp6opt *)(void *)&stcodeopt;
2692 break;
2693 default:
2694 /*
2695 * we encounter an unknown option. this should be an internal
2696 * error.
2697 */
2698 d_printf(LOG_ERR, FNAME, "unknown option: code %d",
2699 optval->type);
2700 return (-1);
2701 }
2702
2703 /* then, calculate the length of and/or fill in the sub-options */
2704 subp = NULL;
2705 sublen = 0;
2706 if (p)
2707 subp = p + headlen;
2708 for (subov = TAILQ_FIRST(&optval->sublist); subov;
2709 subov = TAILQ_NEXT(subov, link)) {
2710 int s;
2711
2712 if ((s = copyout_option(subp, ep, subov)) < 0)
2713 return (-1);
2714 if (p)
2715 subp += s;
2716 sublen += s;
2717 }
2718
2719 /* finally, deal with the head part again */
2720 optlen = headlen + sublen;
2721 if (!p)
2722 return(optlen);
2723
2724 d_printf(LOG_DEBUG, FNAME, "set %s", dhcp6optstr(opttype));
2725 if (ep - p < headlen) /* check it just in case */
2726 return (-1);
2727
2728 /* fill in the common part */
2729 opt->dh6opt_type = htons(opttype);
2730 opt->dh6opt_len = htons(optlen - sizeof(struct dhcp6opt));
2731
2732 /* fill in type specific fields */
2733 switch(optval->type) {
2734 case DHCP6_LISTVAL_IAPD:
2735 ia.dh6_ia_iaid = htonl(optval->val_ia.iaid);
2736 ia.dh6_ia_t1 = htonl(optval->val_ia.t1);
2737 ia.dh6_ia_t2 = htonl(optval->val_ia.t2);
2738 break;
2739 case DHCP6_LISTVAL_IANA:
2740 ia.dh6_ia_iaid = htonl(optval->val_ia.iaid);
2741 ia.dh6_ia_t1 = htonl(optval->val_ia.t1);
2742 ia.dh6_ia_t2 = htonl(optval->val_ia.t2);
2743 break;
2744 case DHCP6_LISTVAL_PREFIX6:
2745 pd_prefix.dh6_iapd_prefix_preferred_time =
2746 htonl(optval->val_prefix6.pltime);
2747 pd_prefix.dh6_iapd_prefix_valid_time =
2748 htonl(optval->val_prefix6.vltime);
2749 pd_prefix.dh6_iapd_prefix_prefix_len =
2750 optval->val_prefix6.plen;
2751 /* XXX: prefix_addr is badly aligned, so we need memcpy */
2752 memcpy(&pd_prefix.dh6_iapd_prefix_prefix_addr,
2753 &optval->val_prefix6.addr, sizeof(struct in6_addr));
2754 break;
2755 case DHCP6_LISTVAL_STATEFULADDR6:
2756 ia_addr.dh6_ia_addr_preferred_time =
2757 htonl(optval->val_statefuladdr6.pltime);
2758 ia_addr.dh6_ia_addr_valid_time =
2759 htonl(optval->val_statefuladdr6.vltime);
2760 ia_addr.dh6_ia_addr_addr = optval->val_statefuladdr6.addr;
2761 break;
2762 case DHCP6_LISTVAL_STCODE:
2763 stcodeopt.dh6_stcode_code = htons(optval->val_num16);
2764 break;
2765 default:
2766 /*
2767 * XXX: this case should be rejected at the beginning of this
2768 * function.
2769 */
2770 return (-1);
2771 }
2772
2773 /* copyout the data (p must be non NULL at this point) */
2774 memcpy(p, opt, headlen);
2775 return (optlen);
2776 }
2777
2778 void
dhcp6_set_timeoparam(ev)2779 dhcp6_set_timeoparam(ev)
2780 struct dhcp6_event *ev;
2781 {
2782 ev->retrans = 0;
2783 ev->init_retrans = 0;
2784 ev->max_retrans_cnt = 0;
2785 ev->max_retrans_dur = 0;
2786 ev->max_retrans_time = 0;
2787
2788 switch(ev->state) {
2789 case DHCP6S_SOLICIT:
2790 ev->init_retrans = SOL_TIMEOUT;
2791 ev->max_retrans_time = SOL_MAX_RT;
2792 break;
2793 case DHCP6S_INFOREQ:
2794 ev->init_retrans = INF_TIMEOUT;
2795 ev->max_retrans_time = INF_MAX_RT;
2796 break;
2797 case DHCP6S_REQUEST:
2798 ev->init_retrans = REQ_TIMEOUT;
2799 ev->max_retrans_time = REQ_MAX_RT;
2800 ev->max_retrans_cnt = REQ_MAX_RC;
2801 break;
2802 case DHCP6S_RENEW:
2803 ev->init_retrans = REN_TIMEOUT;
2804 ev->max_retrans_time = REN_MAX_RT;
2805 break;
2806 case DHCP6S_REBIND:
2807 ev->init_retrans = REB_TIMEOUT;
2808 ev->max_retrans_time = REB_MAX_RT;
2809 break;
2810 case DHCP6S_RELEASE:
2811 ev->init_retrans = REL_TIMEOUT;
2812 ev->max_retrans_cnt = REL_MAX_RC;
2813 break;
2814 default:
2815 d_printf(LOG_ERR, FNAME, "unexpected event state %d on %s",
2816 ev->state, ev->ifp->ifname);
2817 exit(1);
2818 }
2819 }
2820
2821 void
dhcp6_reset_timer(ev)2822 dhcp6_reset_timer(ev)
2823 struct dhcp6_event *ev;
2824 {
2825 double n, r;
2826 char *statestr;
2827 struct timeval interval;
2828
2829 switch(ev->state) {
2830 case DHCP6S_INIT:
2831 /*
2832 * The first Solicit message from the client on the interface
2833 * MUST be delayed by a random amount of time between
2834 * 0 and SOL_MAX_DELAY.
2835 * [RFC3315 17.1.2]
2836 * XXX: a random delay is also necessary before the first
2837 * information-request message. Fortunately, the parameters
2838 * and the algorithm for these two cases are the same.
2839 * [RFC3315 18.1.5]
2840 */
2841 ev->retrans = (random() % (SOL_MAX_DELAY));
2842 break;
2843 default:
2844 if (ev->state == DHCP6S_SOLICIT && ev->timeouts == 0) {
2845 /*
2846 * The first RT MUST be selected to be strictly
2847 * greater than IRT by choosing RAND to be strictly
2848 * greater than 0.
2849 * [RFC3315 17.1.2]
2850 */
2851 r = (double)((random() % 1000) + 1) / 10000;
2852 n = ev->init_retrans + r * ev->init_retrans;
2853 } else {
2854 r = (double)((random() % 2000) - 1000) / 10000;
2855
2856 if (ev->timeouts == 0) {
2857 n = ev->init_retrans + r * ev->init_retrans;
2858 } else
2859 n = 2 * ev->retrans + r * ev->retrans;
2860 }
2861 if (ev->max_retrans_time && n > ev->max_retrans_time)
2862 n = ev->max_retrans_time + r * ev->max_retrans_time;
2863 ev->retrans = (long)n;
2864 break;
2865 }
2866
2867 interval.tv_sec = (ev->retrans * 1000) / 1000000;
2868 interval.tv_usec = (ev->retrans * 1000) % 1000000;
2869 dhcp6_set_timer(&interval, ev->timer);
2870
2871 statestr = dhcp6_event_statestr(ev);
2872
2873 d_printf(LOG_DEBUG, FNAME, "reset a timer on %s, "
2874 "state=%s, timeo=%d, retrans=%d",
2875 ev->ifp->ifname, statestr, ev->timeouts, ev->retrans);
2876 }
2877
2878 int
duidcpy(dd,ds)2879 duidcpy(dd, ds)
2880 struct duid *dd, *ds;
2881 {
2882 dd->duid_len = ds->duid_len;
2883 if ((dd->duid_id = malloc(dd->duid_len)) == NULL) {
2884 d_printf(LOG_ERR, FNAME, "memory allocation failed");
2885 return (-1);
2886 }
2887 memcpy(dd->duid_id, ds->duid_id, dd->duid_len);
2888
2889 return (0);
2890 }
2891
2892 int
duidcmp(d1,d2)2893 duidcmp(d1, d2)
2894 struct duid *d1, *d2;
2895 {
2896 if (d1->duid_len == d2->duid_len) {
2897 return (memcmp(d1->duid_id, d2->duid_id, d1->duid_len));
2898 } else
2899 return (-1);
2900 }
2901
2902 void
duidfree(duid)2903 duidfree(duid)
2904 struct duid *duid;
2905 {
2906 if (duid->duid_id)
2907 free(duid->duid_id);
2908 duid->duid_id = NULL;
2909 duid->duid_len = 0;
2910 }
2911
2912 /*
2913 * Provide an NTP-format timestamp as a replay detection counter
2914 * as mentioned in RFC3315.
2915 */
2916 #define JAN_1970 2208988800UL /* 1970 - 1900 in seconds */
2917 int
get_rdvalue(rdm,rdvalue,rdsize)2918 get_rdvalue(rdm, rdvalue, rdsize)
2919 int rdm;
2920 void *rdvalue;
2921 size_t rdsize;
2922 {
2923 #if defined(HAVE_CLOCK_GETTIME)
2924 struct timespec tp;
2925 double nsec;
2926 #else
2927 struct timeval tv;
2928 #endif
2929 u_int32_t u32, l32;
2930
2931 if (rdm != DHCP6_AUTHRDM_MONOCOUNTER) {
2932 d_printf(LOG_INFO, FNAME, "unsupported RDM (%d)", rdm);
2933 return (-1);
2934 }
2935 if (rdsize != sizeof(u_int64_t)) {
2936 d_printf(LOG_INFO, FNAME, "unsupported RD size (%d)", rdsize);
2937 return (-1);
2938 }
2939
2940 #if defined(HAVE_CLOCK_GETTIME)
2941 if (clock_gettime(CLOCK_REALTIME, &tp)) {
2942 d_printf(LOG_WARNING, FNAME, "clock_gettime failed: %s",
2943 strerror(errno));
2944 return (-1);
2945 }
2946
2947 u32 = (u_int32_t)tp.tv_sec;
2948 u32 += JAN_1970;
2949
2950 nsec = (double)tp.tv_nsec / 1e9 * 0x100000000ULL;
2951 /* nsec should be smaller than 2^32 */
2952 l32 = (u_int32_t)nsec;
2953 #else
2954 if (gettimeofday(&tv, NULL) != 0) {
2955 d_printf(LOG_WARNING, FNAME, "gettimeofday failed: %s",
2956 strerror(errno));
2957 return (-1);
2958 }
2959 u32 = (u_int32_t)tv.tv_sec;
2960 u32 += JAN_1970;
2961 l32 = (u_int32_t)tv.tv_usec;
2962 #endif /* HAVE_CLOCK_GETTIME */
2963
2964 u32 = htonl(u32);
2965 l32 = htonl(l32);
2966
2967 memcpy(rdvalue, &u32, sizeof(u32));
2968 memcpy((char *)rdvalue + sizeof(u32), &l32, sizeof(l32));
2969
2970 return (0);
2971 }
2972
2973 char *
dhcp6optstr(type)2974 dhcp6optstr(type)
2975 int type;
2976 {
2977 static char genstr[sizeof("opt_65535") + 1]; /* XXX thread unsafe */
2978
2979 if (type > 65535)
2980 return ("INVALID option");
2981
2982 switch(type) {
2983 case DH6OPT_CLIENTID:
2984 return ("client ID");
2985 case DH6OPT_SERVERID:
2986 return ("server ID");
2987 case DH6OPT_IA_NA:
2988 return ("identity association");
2989 case DH6OPT_IA_TA:
2990 return ("IA for temporary");
2991 case DH6OPT_IAADDR:
2992 return ("IA address");
2993 case DH6OPT_ORO:
2994 return ("option request");
2995 case DH6OPT_PREFERENCE:
2996 return ("preference");
2997 case DH6OPT_ELAPSED_TIME:
2998 return ("elapsed time");
2999 case DH6OPT_RELAY_MSG:
3000 return ("relay message");
3001 case DH6OPT_AUTH:
3002 return ("authentication");
3003 case DH6OPT_UNICAST:
3004 return ("server unicast");
3005 case DH6OPT_STATUS_CODE:
3006 return ("status code");
3007 case DH6OPT_RAPID_COMMIT:
3008 return ("rapid commit");
3009 case DH6OPT_USER_CLASS:
3010 return ("user class");
3011 case DH6OPT_VENDOR_CLASS:
3012 return ("vendor class");
3013 case DH6OPT_VENDOR_OPTS:
3014 return ("vendor specific info");
3015 case DH6OPT_INTERFACE_ID:
3016 return ("interface ID");
3017 case DH6OPT_RECONF_MSG:
3018 return ("reconfigure message");
3019 case DH6OPT_SIP_SERVER_D:
3020 return ("SIP domain name");
3021 case DH6OPT_SIP_SERVER_A:
3022 return ("SIP server address");
3023 case DH6OPT_DNS:
3024 return ("DNS");
3025 case DH6OPT_DNSNAME:
3026 return ("domain search list");
3027 case DH6OPT_NTP:
3028 return ("NTP server");
3029 case DH6OPT_IA_PD:
3030 return ("IA_PD");
3031 case DH6OPT_IA_PD_PREFIX:
3032 return ("IA_PD prefix");
3033 case DH6OPT_REFRESHTIME:
3034 return ("information refresh time");
3035 case DH6OPT_NIS_SERVERS:
3036 return ("NIS servers");
3037 case DH6OPT_NISP_SERVERS:
3038 return ("NIS+ servers");
3039 case DH6OPT_NIS_DOMAIN_NAME:
3040 return ("NIS domain name");
3041 case DH6OPT_NISP_DOMAIN_NAME:
3042 return ("NIS+ domain name");
3043 case DH6OPT_BCMCS_SERVER_D:
3044 return ("BCMCS domain name");
3045 case DH6OPT_BCMCS_SERVER_A:
3046 return ("BCMCS server address");
3047 case DH6OPT_GEOCONF_CIVIC:
3048 return ("Geoconf Civic");
3049 case DH6OPT_REMOTE_ID:
3050 return ("remote ID");
3051 case DH6OPT_SUBSCRIBER_ID:
3052 return ("subscriber ID");
3053 case DH6OPT_CLIENT_FQDN:
3054 return ("client FQDN");
3055 default:
3056 snprintf(genstr, sizeof(genstr), "opt_%d", type);
3057 return (genstr);
3058 }
3059 }
3060
3061 char *
dhcp6msgstr(type)3062 dhcp6msgstr(type)
3063 int type;
3064 {
3065 static char genstr[sizeof("msg255") + 1]; /* XXX thread unsafe */
3066
3067 if (type > 255)
3068 return ("INVALID msg");
3069
3070 switch(type) {
3071 case DH6_SOLICIT:
3072 return ("solicit");
3073 case DH6_ADVERTISE:
3074 return ("advertise");
3075 case DH6_REQUEST:
3076 return ("request");
3077 case DH6_CONFIRM:
3078 return ("confirm");
3079 case DH6_RENEW:
3080 return ("renew");
3081 case DH6_REBIND:
3082 return ("rebind");
3083 case DH6_REPLY:
3084 return ("reply");
3085 case DH6_RELEASE:
3086 return ("release");
3087 case DH6_DECLINE:
3088 return ("decline");
3089 case DH6_RECONFIGURE:
3090 return ("reconfigure");
3091 case DH6_INFORM_REQ:
3092 return ("information request");
3093 case DH6_RELAY_FORW:
3094 return ("relay-forward");
3095 case DH6_RELAY_REPLY:
3096 return ("relay-reply");
3097 default:
3098 snprintf(genstr, sizeof(genstr), "msg%d", type);
3099 return (genstr);
3100 }
3101 }
3102
3103 char *
dhcp6_stcodestr(code)3104 dhcp6_stcodestr(code)
3105 u_int16_t code;
3106 {
3107 static char genstr[sizeof("code255") + 1]; /* XXX thread unsafe */
3108
3109 if (code > 255)
3110 return ("INVALID code");
3111
3112 switch(code) {
3113 case DH6OPT_STCODE_SUCCESS:
3114 return ("success");
3115 case DH6OPT_STCODE_UNSPECFAIL:
3116 return ("unspec failure");
3117 case DH6OPT_STCODE_NOADDRSAVAIL:
3118 return ("no addresses");
3119 case DH6OPT_STCODE_NOBINDING:
3120 return ("no binding");
3121 case DH6OPT_STCODE_NOTONLINK:
3122 return ("not on-link");
3123 case DH6OPT_STCODE_USEMULTICAST:
3124 return ("use multicast");
3125 case DH6OPT_STCODE_NOPREFIXAVAIL:
3126 return ("no prefixes");
3127 default:
3128 snprintf(genstr, sizeof(genstr), "code%d", code);
3129 return (genstr);
3130 }
3131 }
3132
3133 char *
duidstr(duid)3134 duidstr(duid)
3135 struct duid *duid;
3136 {
3137 int i, n;
3138 char *cp, *ep;
3139 static char duidstr[sizeof("xx:") * 128 + sizeof("...")];
3140
3141 cp = duidstr;
3142 ep = duidstr + sizeof(duidstr);
3143 for (i = 0; i < duid->duid_len && i <= 128; i++) {
3144 n = snprintf(cp, ep - cp, "%s%02x", i == 0 ? "" : ":",
3145 duid->duid_id[i] & 0xff);
3146 if (n < 0)
3147 return NULL;
3148 cp += n;
3149 }
3150 if (i < duid->duid_len)
3151 snprintf(cp, ep - cp, "%s", "...");
3152
3153 return (duidstr);
3154 }
3155
dhcp6_event_statestr(ev)3156 char *dhcp6_event_statestr(ev)
3157 struct dhcp6_event *ev;
3158 {
3159 switch(ev->state) {
3160 case DHCP6S_INIT:
3161 return ("INIT");
3162 case DHCP6S_SOLICIT:
3163 return ("SOLICIT");
3164 case DHCP6S_INFOREQ:
3165 return ("INFOREQ");
3166 case DHCP6S_REQUEST:
3167 return ("REQUEST");
3168 case DHCP6S_RENEW:
3169 return ("RENEW");
3170 case DHCP6S_REBIND:
3171 return ("REBIND");
3172 case DHCP6S_RELEASE:
3173 return ("RELEASE");
3174 case DHCP6S_IDLE:
3175 return ("IDLE");
3176 case DHCP6S_EXIT:
3177 return ("EXIT");
3178 default:
3179 return ("???"); /* XXX */
3180 }
3181 }
3182
3183 void
setloglevel(debuglevel)3184 setloglevel(debuglevel)
3185 int debuglevel;
3186 {
3187 if (foreground) {
3188 switch(debuglevel) {
3189 case 0:
3190 debug_thresh = LOG_ERR;
3191 break;
3192 case 1:
3193 debug_thresh = LOG_INFO;
3194 break;
3195 default:
3196 debug_thresh = LOG_DEBUG;
3197 break;
3198 }
3199 } else {
3200 switch(debuglevel) {
3201 case 0:
3202 setlogmask(LOG_UPTO(LOG_ERR));
3203 break;
3204 case 1:
3205 setlogmask(LOG_UPTO(LOG_INFO));
3206 break;
3207 case 2:
3208 setlogmask(LOG_UPTO(LOG_DEBUG));
3209 break;
3210 }
3211 }
3212 }
3213
3214 void
d_printf(int level,const char * fname,const char * fmt,...)3215 d_printf(int level, const char *fname, const char *fmt, ...)
3216 {
3217 va_list ap;
3218 char logbuf[LINE_MAX];
3219 int printfname = 1;
3220
3221 va_start(ap, fmt);
3222 vsnprintf(logbuf, sizeof(logbuf), fmt, ap);
3223
3224 if (*fname == '\0')
3225 printfname = 0;
3226
3227 if (foreground && debug_thresh >= level) {
3228 time_t now;
3229 struct tm *tm_now;
3230 const char *month[] = {
3231 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
3232 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
3233 };
3234
3235 if ((now = time(NULL)) < 0)
3236 exit(1); /* XXX */
3237 tm_now = localtime(&now);
3238 fprintf(stderr, "%3s/%02d/%04d %02d:%02d:%02d: %s%s%s\n",
3239 month[tm_now->tm_mon], tm_now->tm_mday,
3240 tm_now->tm_year + 1900,
3241 tm_now->tm_hour, tm_now->tm_min, tm_now->tm_sec,
3242 fname, printfname ? ": " : "",
3243 logbuf);
3244 } else
3245 syslog(level, "%s%s%s", fname, printfname ? ": " : "", logbuf);
3246 }
3247
3248 int
ifaddrconf(cmd,ifname,addr,plen,pltime,vltime)3249 ifaddrconf(cmd, ifname, addr, plen, pltime, vltime)
3250 ifaddrconf_cmd_t cmd;
3251 char *ifname;
3252 struct sockaddr_in6 *addr;
3253 int plen;
3254 int pltime;
3255 int vltime;
3256 {
3257 #ifdef __KAME__
3258 struct in6_aliasreq req;
3259 #endif
3260 #ifdef __linux__
3261 struct in6_ifreq req;
3262 struct ifreq ifr;
3263 #endif
3264 #ifdef __sun__
3265 struct lifreq req;
3266 #endif
3267 unsigned long ioctl_cmd;
3268 char *cmdstr;
3269 int s; /* XXX overhead */
3270
3271 switch(cmd) {
3272 case IFADDRCONF_ADD:
3273 cmdstr = "add";
3274 #ifdef __KAME__
3275 ioctl_cmd = SIOCAIFADDR_IN6;
3276 #endif
3277 #ifdef __linux__
3278 ioctl_cmd = SIOCSIFADDR;
3279 #endif
3280 #ifdef __sun__
3281 ioctl_cmd = SIOCLIFADDIF;
3282 #endif
3283 break;
3284 case IFADDRCONF_REMOVE:
3285 cmdstr = "remove";
3286 #ifdef __KAME__
3287 ioctl_cmd = SIOCDIFADDR_IN6;
3288 #endif
3289 #ifdef __linux__
3290 ioctl_cmd = SIOCDIFADDR;
3291 #endif
3292 #ifdef __sun__
3293 ioctl_cmd = SIOCLIFREMOVEIF;
3294 #endif
3295 break;
3296 default:
3297 return (-1);
3298 }
3299
3300 if ((s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
3301 d_printf(LOG_ERR, FNAME, "can't open a temporary socket: %s",
3302 strerror(errno));
3303 return (-1);
3304 }
3305
3306 memset(&req, 0, sizeof(req));
3307 #ifdef __KAME__
3308 req.ifra_addr = *addr;
3309 memcpy(req.ifra_name, ifname, sizeof(req.ifra_name));
3310 (void)sa6_plen2mask(&req.ifra_prefixmask, plen);
3311 /* XXX: should lifetimes be calculated based on the lease duration? */
3312 req.ifra_lifetime.ia6t_vltime = vltime;
3313 req.ifra_lifetime.ia6t_pltime = pltime;
3314 #endif
3315 #ifdef __linux__
3316 memset(&ifr, 0, sizeof(ifr));
3317 strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);
3318 if (ioctl(s, SIOGIFINDEX, &ifr) < 0) {
3319 d_printf(LOG_NOTICE, FNAME, "failed to get the index of %s: %s",
3320 ifname, strerror(errno));
3321 close(s);
3322 return (-1);
3323 }
3324 memcpy(&req.ifr6_addr, &addr->sin6_addr, sizeof(struct in6_addr));
3325 req.ifr6_prefixlen = plen;
3326 req.ifr6_ifindex = ifr.ifr_ifindex;
3327 #endif
3328 #ifdef __sun__
3329 strncpy(req.lifr_name, ifname, sizeof (req.lifr_name));
3330 #endif
3331
3332 if (ioctl(s, ioctl_cmd, &req)) {
3333 d_printf(LOG_NOTICE, FNAME, "failed to %s an address on %s: %s",
3334 cmdstr, ifname, strerror(errno));
3335 close(s);
3336 return (-1);
3337 }
3338
3339 #ifdef __sun__
3340 memcpy(&req.lifr_addr, addr, sizeof (*addr));
3341 if (ioctl(s, SIOCSLIFADDR, &req) == -1) {
3342 d_printf(LOG_NOTICE, FNAME, "failed to %s new address on %s: %s",
3343 cmdstr, ifname, strerror(errno));
3344 close(s);
3345 return (-1);
3346 }
3347 #endif
3348
3349 d_printf(LOG_INFO, FNAME, "%s an address %s/%d on %s", cmdstr,
3350 addr2str((struct sockaddr *)addr), plen, ifname);
3351
3352 close(s);
3353 return (0);
3354 }
3355
3356 int
safefile(path)3357 safefile(path)
3358 const char *path;
3359 {
3360 struct stat s;
3361 uid_t myuid;
3362
3363 /* no setuid */
3364 if (getuid() != geteuid()) {
3365 d_printf(LOG_NOTICE, FNAME,
3366 "setuid'ed execution not allowed");
3367 return (-1);
3368 }
3369
3370 if (lstat(path, &s) != 0) {
3371 d_printf(LOG_NOTICE, FNAME, "lstat failed: %s",
3372 strerror(errno));
3373 return (-1);
3374 }
3375
3376 /* the file must be owned by the running uid */
3377 myuid = getuid();
3378 if (s.st_uid != myuid) {
3379 d_printf(LOG_NOTICE, FNAME, "%s has invalid owner uid", path);
3380 return (-1);
3381 }
3382
3383 switch (s.st_mode & S_IFMT) {
3384 case S_IFREG:
3385 break;
3386 default:
3387 d_printf(LOG_NOTICE, FNAME, "%s is an invalid file type 0x%o",
3388 path, (s.st_mode & S_IFMT));
3389 return (-1);
3390 }
3391
3392 return (0);
3393 }
3394