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