1 /* $KAME: common.c,v 1.129 2005/09/16 11:30:13 suz Exp $ */
3 * Copyright (C) 1998 and 1999 WIDE Project.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <sys/ioctl.h>
34 #include <sys/queue.h>
36 #if TIME_WITH_SYS_TIME
37 # include <sys/time.h>
41 # include <sys/time.h>
47 #include <netinet/in.h>
49 #include <net/if_types.h>
51 #include <net/if_var.h>
53 #include <net/if_dl.h>
56 #include <linux/if_packet.h>
58 #include <net/if_arp.h>
60 #include <sys/sockio.h>
64 #include <libdevinfo.h>
68 #include <netinet6/in6_var.h>
90 /* from /usr/include/linux/ipv6.h */
93 struct in6_addr ifr6_addr
;
94 u_int32_t ifr6_prefixlen
;
95 unsigned int ifr6_ifindex
;
105 static int dhcp6_count_list
__P((struct dhcp6_list
*));
106 static int in6_matchflags
__P((struct sockaddr
*, char *, int));
107 static ssize_t dnsencode
__P((const char *, char *, size_t));
108 static char *dnsdecode
__P((u_char
**, u_char
*, char *, size_t));
109 static int copyout_option
__P((char *, char *, struct dhcp6_listval
*));
110 static int copyin_option
__P((int, struct dhcp6opt
*, struct dhcp6opt
*,
111 struct dhcp6_list
*));
112 static int copy_option
__P((u_int16_t
, u_int16_t
, void *, struct dhcp6opt
**,
113 struct dhcp6opt
*, int *));
114 static ssize_t gethwid
__P((char *, int, const char *, u_int16_t
*));
115 static char *sprint_uint64
__P((char *, int, u_int64_t
));
116 static char *sprint_auth
__P((struct dhcp6_optinfo
*));
119 dhcp6_copy_list(dst
, src
)
120 struct dhcp6_list
*dst
, *src
;
122 struct dhcp6_listval
*ent
;
124 for (ent
= TAILQ_FIRST(src
); ent
; ent
= TAILQ_NEXT(ent
, link
)) {
125 if (dhcp6_add_listval(dst
, ent
->type
,
126 &ent
->uv
, &ent
->sublist
) == NULL
)
133 dhcp6_clear_list(dst
);
138 dhcp6_move_list(dst
, src
)
139 struct dhcp6_list
*dst
, *src
;
141 struct dhcp6_listval
*v
;
143 while ((v
= TAILQ_FIRST(src
)) != NULL
) {
144 TAILQ_REMOVE(src
, v
, link
);
145 TAILQ_INSERT_TAIL(dst
, v
, link
);
150 dhcp6_clear_list(head
)
151 struct dhcp6_list
*head
;
153 struct dhcp6_listval
*v
;
155 while ((v
= TAILQ_FIRST(head
)) != NULL
) {
156 TAILQ_REMOVE(head
, v
, link
);
157 dhcp6_clear_listval(v
);
164 dhcp6_count_list(head
)
165 struct dhcp6_list
*head
;
167 struct dhcp6_listval
*v
;
170 for (i
= 0, v
= TAILQ_FIRST(head
); v
; v
= TAILQ_NEXT(v
, link
))
177 dhcp6_clear_listval(lv
)
178 struct dhcp6_listval
*lv
;
180 dhcp6_clear_list(&lv
->sublist
);
182 case DHCP6_LISTVAL_VBUF
:
183 dhcp6_vbuf_free(&lv
->val_vbuf
);
185 default: /* nothing to do */
192 * Note: this function only searches for the first entry that matches
193 * VAL. It also does not care about sublists.
195 struct dhcp6_listval
*
196 dhcp6_find_listval(head
, type
, val
, option
)
197 struct dhcp6_list
*head
;
198 dhcp6_listval_type_t type
;
202 struct dhcp6_listval
*lv
;
204 for (lv
= TAILQ_FIRST(head
); lv
; lv
= TAILQ_NEXT(lv
, link
)) {
205 if (lv
->type
!= type
)
209 case DHCP6_LISTVAL_NUM
:
210 if (lv
->val_num
== *(int *)val
)
213 case DHCP6_LISTVAL_STCODE
:
214 if (lv
->val_num16
== *(u_int16_t
*)val
)
217 case DHCP6_LISTVAL_ADDR6
:
218 if (IN6_ARE_ADDR_EQUAL(&lv
->val_addr6
,
219 (struct in6_addr
*)val
)) {
223 case DHCP6_LISTVAL_PREFIX6
:
224 if ((option
& MATCHLIST_PREFIXLEN
) &&
225 lv
->val_prefix6
.plen
==
226 ((struct dhcp6_prefix
*)val
)->plen
) {
228 } else if (IN6_ARE_ADDR_EQUAL(&lv
->val_prefix6
.addr
,
229 &((struct dhcp6_prefix
*)val
)->addr
) &&
230 lv
->val_prefix6
.plen
==
231 ((struct dhcp6_prefix
*)val
)->plen
) {
235 case DHCP6_LISTVAL_STATEFULADDR6
:
236 if (IN6_ARE_ADDR_EQUAL(&lv
->val_statefuladdr6
.addr
,
237 &((struct dhcp6_prefix
*)val
)->addr
)) {
241 case DHCP6_LISTVAL_IAPD
:
242 case DHCP6_LISTVAL_IANA
:
243 if (lv
->val_ia
.iaid
==
244 ((struct dhcp6_ia
*)val
)->iaid
) {
248 case DHCP6_LISTVAL_VBUF
:
249 if (dhcp6_vbuf_cmp(&lv
->val_vbuf
,
250 (struct dhcp6_vbuf
*)val
) == 0) {
260 struct dhcp6_listval
*
261 dhcp6_add_listval(head
, type
, val
, sublist
)
262 struct dhcp6_list
*head
, *sublist
;
263 dhcp6_listval_type_t type
;
266 struct dhcp6_listval
*lv
= NULL
;
268 if ((lv
= malloc(sizeof(*lv
))) == NULL
) {
269 dprintf(LOG_ERR
, FNAME
,
270 "failed to allocate memory for list entry");
273 memset(lv
, 0, sizeof(*lv
));
275 TAILQ_INIT(&lv
->sublist
);
278 case DHCP6_LISTVAL_NUM
:
279 lv
->val_num
= *(int *)val
;
281 case DHCP6_LISTVAL_STCODE
:
282 lv
->val_num16
= *(u_int16_t
*)val
;
284 case DHCP6_LISTVAL_ADDR6
:
285 lv
->val_addr6
= *(struct in6_addr
*)val
;
287 case DHCP6_LISTVAL_PREFIX6
:
288 lv
->val_prefix6
= *(struct dhcp6_prefix
*)val
;
290 case DHCP6_LISTVAL_STATEFULADDR6
:
291 lv
->val_statefuladdr6
= *(struct dhcp6_statefuladdr
*)val
;
293 case DHCP6_LISTVAL_IAPD
:
294 case DHCP6_LISTVAL_IANA
:
295 lv
->val_ia
= *(struct dhcp6_ia
*)val
;
297 case DHCP6_LISTVAL_VBUF
:
298 if (dhcp6_vbuf_copy(&lv
->val_vbuf
, (struct dhcp6_vbuf
*)val
))
302 dprintf(LOG_ERR
, FNAME
,
303 "unexpected list value type (%d)", type
);
307 if (sublist
&& dhcp6_copy_list(&lv
->sublist
, sublist
))
310 TAILQ_INSERT_TAIL(head
, lv
, link
);
322 dhcp6_vbuf_copy(dst
, src
)
323 struct dhcp6_vbuf
*dst
, *src
;
325 dst
->dv_buf
= malloc(src
->dv_len
);
326 if (dst
->dv_buf
== NULL
)
329 dst
->dv_len
= src
->dv_len
;
330 memcpy(dst
->dv_buf
, src
->dv_buf
, dst
->dv_len
);
336 dhcp6_vbuf_free(vbuf
)
337 struct dhcp6_vbuf
*vbuf
;
346 dhcp6_vbuf_cmp(vb1
, vb2
)
347 struct dhcp6_vbuf
*vb1
, *vb2
;
349 if (vb1
->dv_len
!= vb2
->dv_len
)
350 return (vb1
->dv_len
- vb2
->dv_len
);
352 return (memcmp(vb1
->dv_buf
, vb2
->dv_buf
, vb1
->dv_len
));
356 dhcp6_get_addr(optlen
, cp
, type
, list
)
359 dhcp6_listval_type_t type
;
360 struct dhcp6_list
*list
;
364 if (optlen
% sizeof(struct in6_addr
) || optlen
== 0) {
365 dprintf(LOG_INFO
, FNAME
,
366 "malformed DHCP option: type %d, len %d", type
, optlen
);
369 for (val
= cp
; val
< cp
+ optlen
; val
+= sizeof(struct in6_addr
)) {
370 struct in6_addr valaddr
;
372 memcpy(&valaddr
, val
, sizeof(valaddr
));
373 if (dhcp6_find_listval(list
,
374 DHCP6_LISTVAL_ADDR6
, &valaddr
, 0)) {
375 dprintf(LOG_INFO
, FNAME
, "duplicated %s address (%s)",
376 dhcp6optstr(type
), in6addr2str(&valaddr
, 0));
380 if (dhcp6_add_listval(list
, DHCP6_LISTVAL_ADDR6
,
381 &valaddr
, NULL
) == NULL
) {
382 dprintf(LOG_ERR
, FNAME
,
383 "failed to copy %s address", dhcp6optstr(type
));
392 dhcp6_set_addr(type
, list
, p
, optep
, len
)
393 dhcp6_listval_type_t type
;
394 struct dhcp6_list
*list
;
395 struct dhcp6opt
**p
, *optep
;
398 struct in6_addr
*in6
;
400 struct dhcp6_listval
*d
;
403 if (TAILQ_EMPTY(list
))
407 optlen
= dhcp6_count_list(list
) * sizeof(struct in6_addr
);
408 if ((tmpbuf
= malloc(optlen
)) == NULL
) {
409 dprintf(LOG_ERR
, FNAME
,
410 "memory allocation failed for %s options",
414 in6
= (struct in6_addr
*)tmpbuf
;
415 for (d
= TAILQ_FIRST(list
); d
; d
= TAILQ_NEXT(d
, link
), in6
++)
416 memcpy(in6
, &d
->val_addr6
, sizeof(*in6
));
417 if (copy_option(type
, optlen
, tmpbuf
, p
, optep
, len
) != 0) {
427 dhcp6_get_domain(optlen
, cp
, type
, list
)
430 dhcp6_listval_type_t type
;
431 struct dhcp6_list
*list
;
436 while (val
< cp
+ optlen
) {
437 struct dhcp6_vbuf vb
;
438 char name
[MAXDNAME
+ 1];
440 if (dnsdecode((u_char
**)(void *)&val
,
441 (u_char
*)(cp
+ optlen
), name
, sizeof(name
)) == NULL
) {
442 dprintf(LOG_INFO
, FNAME
, "failed to "
443 "decode a %s domain name",
445 dprintf(LOG_INFO
, FNAME
,
446 "malformed DHCP option: type %d, len %d",
451 vb
.dv_len
= strlen(name
) + 1;
454 if (dhcp6_add_listval(list
,
455 DHCP6_LISTVAL_VBUF
, &vb
, NULL
) == NULL
) {
456 dprintf(LOG_ERR
, FNAME
, "failed to "
457 "copy a %s domain name", dhcp6optstr(type
));
466 dhcp6_set_domain(type
, list
, p
, optep
, len
)
467 dhcp6_listval_type_t type
;
468 struct dhcp6_list
*list
;
469 struct dhcp6opt
**p
, *optep
;
473 struct dhcp6_listval
*d
;
475 char name
[MAXDNAME
], *cp
, *ep
;
477 if (TAILQ_EMPTY(list
))
480 for (d
= TAILQ_FIRST(list
); d
; d
= TAILQ_NEXT(d
, link
))
481 optlen
+= (d
->val_vbuf
.dv_len
+ 1);
488 if ((tmpbuf
= malloc(optlen
)) == NULL
) {
489 dprintf(LOG_ERR
, FNAME
, "memory allocation failed for "
490 "%s domain options", dhcp6optstr(type
));
495 for (d
= TAILQ_FIRST(list
); d
; d
= TAILQ_NEXT(d
, link
)) {
498 nlen
= dnsencode((const char *)d
->val_vbuf
.dv_buf
,
499 name
, sizeof (name
));
501 dprintf(LOG_ERR
, FNAME
,
502 "failed to encode a %s domain name",
507 if (ep
- cp
< nlen
) {
508 dprintf(LOG_ERR
, FNAME
,
509 "buffer length for %s domain name is too short",
514 memcpy(cp
, name
, nlen
);
517 if (copy_option(type
, cp
- tmpbuf
, tmpbuf
, p
, optep
, len
) != 0) {
527 dhcp6_create_event(ifp
, state
)
528 struct dhcp6_if
*ifp
;
531 struct dhcp6_event
*ev
;
533 if ((ev
= malloc(sizeof(*ev
))) == NULL
) {
534 dprintf(LOG_ERR
, FNAME
,
535 "failed to allocate memory for an event");
538 memset(ev
, 0, sizeof(*ev
));
541 TAILQ_INIT(&ev
->data_list
);
547 dhcp6_remove_event(ev
)
548 struct dhcp6_event
*ev
;
550 struct dhcp6_serverinfo
*sp
, *sp_next
;
552 dprintf(LOG_DEBUG
, FNAME
, "removing an event on %s, state=%s",
553 ev
->ifp
->ifname
, dhcp6_event_statestr(ev
));
555 dhcp6_remove_evdata(ev
);
557 duidfree(&ev
->serverid
);
560 dhcp6_remove_timer(&ev
->timer
);
561 TAILQ_REMOVE(&ev
->ifp
->event_list
, ev
, link
);
563 for (sp
= ev
->servers
; sp
; sp
= sp_next
) {
566 dprintf(LOG_DEBUG
, FNAME
, "removing server (ID: %s)",
567 duidstr(&sp
->optinfo
.serverID
));
568 dhcp6_clear_options(&sp
->optinfo
);
569 if (sp
->authparam
!= NULL
)
574 if (ev
->authparam
!= NULL
)
581 dhcp6_remove_evdata(ev
)
582 struct dhcp6_event
*ev
;
584 struct dhcp6_eventdata
*evd
;
586 while ((evd
= TAILQ_FIRST(&ev
->data_list
)) != NULL
) {
587 TAILQ_REMOVE(&ev
->data_list
, evd
, link
);
589 (*evd
->destructor
)(evd
);
595 new_authparam(proto
, alg
, rdm
)
598 struct authparam
*authparam
;
600 if ((authparam
= malloc(sizeof(*authparam
))) == NULL
)
603 memset(authparam
, 0, sizeof(*authparam
));
605 authparam
->authproto
= proto
;
606 authparam
->authalgorithm
= alg
;
607 authparam
->authrdm
= rdm
;
608 authparam
->key
= NULL
;
609 authparam
->flags
|= AUTHPARAM_FLAGS_NOPREVRD
;
610 authparam
->prevrd
= 0;
616 copy_authparam(authparam
)
617 struct authparam
*authparam
;
619 struct authparam
*dst
;
621 if ((dst
= malloc(sizeof(*dst
))) == NULL
)
624 memcpy(dst
, authparam
, sizeof(*dst
));
630 * Home-brew function of a 64-bit version of ntohl.
631 * XXX: is there any standard for this?
633 #if (BYTE_ORDER == LITTLE_ENDIAN)
634 static __inline u_int64_t
637 return (u_int64_t
)ntohl((u_int32_t
)(x
>> 32)) |
638 (int64_t)ntohl((u_int32_t
)(x
& 0xffffffff)) << 32;
640 #else /* (BYTE_ORDER == LITTLE_ENDIAN) */
645 dhcp6_auth_replaycheck(method
, prev
, current
)
647 u_int64_t prev
, current
;
649 char bufprev
[] = "ffff ffff ffff ffff";
650 char bufcurrent
[] = "ffff ffff ffff ffff";
652 if (method
!= DHCP6_AUTHRDM_MONOCOUNTER
) {
653 dprintf(LOG_ERR
, FNAME
, "unsupported replay detection "
654 "method (%d)", method
);
658 (void)sprint_uint64(bufprev
, sizeof(bufprev
), prev
);
659 (void)sprint_uint64(bufcurrent
, sizeof(bufcurrent
), current
);
660 dprintf(LOG_DEBUG
, FNAME
, "previous: %s, current: %s",
661 bufprev
, bufcurrent
);
664 current
= ntohq(current
);
667 * we call the singular point guilty, since we cannot guess
668 * whether the serial number is increasing or not.
670 if (prev
== (current
^ 0x8000000000000000ULL
)) {
671 dprintf(LOG_INFO
, FNAME
, "detected a singular point");
675 return (((int64_t)(current
- prev
) > 0) ? 0 : 1);
679 getifaddr(addr
, ifnam
, prefix
, plen
, strong
, ignoreflags
)
680 struct in6_addr
*addr
;
682 struct in6_addr
*prefix
;
684 int strong
; /* if strong host model is required or not */
687 struct ifaddrs
*ifap
, *ifa
;
688 struct sockaddr_in6 sin6
;
691 if (getifaddrs(&ifap
) != 0) {
692 dprintf(LOG_WARNING
, FNAME
,
693 "getifaddrs failed: %s", strerror(errno
));
697 for (ifa
= ifap
; ifa
; ifa
= ifa
->ifa_next
) {
700 if (strong
&& strcmp(ifnam
, ifa
->ifa_name
) != 0)
703 /* in any case, ignore interfaces in different scope zones. */
704 if ((s1
= in6_addrscopebyif(prefix
, ifnam
)) < 0 ||
705 (s2
= in6_addrscopebyif(prefix
, ifa
->ifa_name
)) < 0 ||
709 if (ifa
->ifa_addr
->sa_family
!= AF_INET6
)
712 if (ifa
->ifa_addr
->sa_len
> sizeof(sin6
))
716 if (in6_matchflags(ifa
->ifa_addr
, ifa
->ifa_name
, ignoreflags
))
719 memcpy(&sin6
, ifa
->ifa_addr
, sysdep_sa_len(ifa
->ifa_addr
));
721 if (IN6_IS_ADDR_LINKLOCAL(&sin6
.sin6_addr
)) {
722 sin6
.sin6_addr
.s6_addr
[2] = 0;
723 sin6
.sin6_addr
.s6_addr
[3] = 0;
727 if (memcmp(&sin6
.sin6_addr
, prefix
, plen
/ 8) != 0)
730 struct in6_addr a
, m
;
733 memcpy(&a
, &sin6
.sin6_addr
, sizeof(sin6
.sin6_addr
));
734 memset(&m
, 0, sizeof(m
));
735 memset(&m
, 0xff, plen
/ 8);
736 m
.s6_addr
[plen
/ 8] = (0xff00 >> (plen
% 8)) & 0xff;
737 for (i
= 0; i
< sizeof(a
); i
++)
738 a
.s6_addr
[i
] &= m
.s6_addr
[i
];
740 if (memcmp(&a
, prefix
, plen
/ 8) != 0 ||
741 a
.s6_addr
[plen
/ 8] !=
742 (prefix
->s6_addr
[plen
/ 8] & m
.s6_addr
[plen
/ 8]))
745 memcpy(addr
, &sin6
.sin6_addr
, sizeof(sin6
.sin6_addr
));
747 if (IN6_IS_ADDR_LINKLOCAL(addr
))
748 addr
->s6_addr
[2] = addr
->s6_addr
[3] = 0;
759 getifidfromaddr(addr
, ifidp
)
760 struct in6_addr
*addr
;
763 struct ifaddrs
*ifap
, *ifa
;
764 struct sockaddr_in6
*sa6
;
768 if (getifaddrs(&ifap
) != 0) {
769 dprintf(LOG_WARNING
, FNAME
,
770 "getifaddrs failed: %s", strerror(errno
));
774 for (ifa
= ifap
; ifa
; ifa
= ifa
->ifa_next
) {
775 if (ifa
->ifa_addr
->sa_family
!= AF_INET6
)
778 sa6
= (struct sockaddr_in6
*)ifa
->ifa_addr
;
779 if (IN6_ARE_ADDR_EQUAL(addr
, &sa6
->sin6_addr
))
784 if ((ifid
= if_nametoindex(ifa
->ifa_name
)) == 0) {
785 dprintf(LOG_ERR
, FNAME
,
786 "if_nametoindex failed for %s", ifa
->ifa_name
);
799 in6_addrscopebyif(addr
, ifnam
)
800 struct in6_addr
*addr
;
805 if ((ifindex
= if_nametoindex(ifnam
)) == 0)
808 if (IN6_IS_ADDR_LINKLOCAL(addr
) || IN6_IS_ADDR_MC_LINKLOCAL(addr
))
811 if (IN6_IS_ADDR_SITELOCAL(addr
) || IN6_IS_ADDR_MC_SITELOCAL(addr
))
812 return (1); /* XXX */
814 if (IN6_IS_ADDR_MC_ORGLOCAL(addr
))
815 return (1); /* XXX */
817 return (1); /* treat it as global */
821 transmit_sa(s
, sa
, buf
, len
)
829 error
= sendto(s
, buf
, len
, 0, sa
, sysdep_sa_len(sa
));
831 return (error
!= len
) ? -1 : 0;
842 while ((y
- x
) * ratio
< (y
- x
))
844 return (x
+ ((y
- x
) * (ratio
- 1) / random() & (ratio
- 1)));
848 prefix6_mask(in6
, plen
)
849 struct in6_addr
*in6
;
852 struct sockaddr_in6 mask6
;
855 if (sa6_plen2mask(&mask6
, plen
))
858 for (i
= 0; i
< 16; i
++)
859 in6
->s6_addr
[i
] &= mask6
.sin6_addr
.s6_addr
[i
];
865 sa6_plen2mask(sa6
, plen
)
866 struct sockaddr_in6
*sa6
;
871 if (plen
< 0 || plen
> 128)
874 memset(sa6
, 0, sizeof(*sa6
));
875 sa6
->sin6_family
= AF_INET6
;
877 sa6
->sin6_len
= sizeof(*sa6
);
880 for (cp
= (u_char
*)&sa6
->sin6_addr
; plen
> 7; plen
-= 8)
882 *cp
= 0xff << (8 - plen
);
891 static char addrbuf
[8][NI_MAXHOST
];
892 static int round
= 0;
895 round
= (round
+ 1) & 7;
898 getnameinfo(sa
, sysdep_sa_len(sa
), cp
, NI_MAXHOST
,
899 NULL
, 0, NI_NUMERICHOST
);
905 in6addr2str(in6
, scopeid
)
906 struct in6_addr
*in6
;
909 struct sockaddr_in6 sa6
;
911 memset(&sa6
, 0, sizeof(sa6
));
912 sa6
.sin6_family
= AF_INET6
;
914 sa6
.sin6_len
= sizeof(sa6
);
916 sa6
.sin6_addr
= *in6
;
917 sa6
.sin6_scope_id
= scopeid
;
919 return (addr2str((struct sockaddr
*)&sa6
));
922 /* return IPv6 address scope type. caller assumes that smaller is narrower. */
925 struct in6_addr
*addr
;
929 if (addr
->s6_addr
[0] == 0xfe) {
930 scope
= addr
->s6_addr
[1] & 0xc0;
934 return (2); /* link-local */
937 return (5); /* site-local */
940 return (14); /* global: just in case */
945 /* multicast scope. just return the scope field */
946 if (addr
->s6_addr
[0] == 0xff)
947 return (addr
->s6_addr
[1] & 0x0f);
949 if (bcmp(&in6addr_loopback
, addr
, sizeof(addr
) - 1) == 0) {
950 if (addr
->s6_addr
[15] == 1) /* loopback */
952 if (addr
->s6_addr
[15] == 0) /* unspecified */
953 return (0); /* XXX: good value? */
956 return (14); /* global */
960 in6_matchflags(addr
, ifnam
, flags
)
961 struct sockaddr
*addr
;
967 struct in6_ifreq ifr6
;
969 if ((s
= socket(AF_INET6
, SOCK_DGRAM
, 0)) < 0) {
970 warn("in6_matchflags: socket(DGRAM6)");
973 memset(&ifr6
, 0, sizeof(ifr6
));
974 strncpy(ifr6
.ifr_name
, ifnam
, sizeof(ifr6
.ifr_name
));
975 ifr6
.ifr_addr
= *(struct sockaddr_in6
*)addr
;
977 if (ioctl(s
, SIOCGIFAFLAG_IN6
, &ifr6
) < 0) {
978 warn("in6_matchflags: ioctl(SIOCGIFAFLAG_IN6, %s)",
986 return (ifr6
.ifr_ifru
.ifru_flags6
& flags
);
993 get_duid(idfile
, duid
)
998 u_int16_t len
= 0, hwtype
;
1000 char tmpbuf
[256]; /* HWID should be no more than 256 bytes */
1002 if ((fp
= fopen(idfile
, "r")) == NULL
&& errno
!= ENOENT
)
1003 dprintf(LOG_NOTICE
, FNAME
, "failed to open DUID file: %s",
1006 memset(duid
, 0, sizeof(*duid
));
1009 if (fread(&len
, sizeof(len
), 1, fp
) != 1) {
1010 dprintf(LOG_ERR
, FNAME
, "DUID file corrupted");
1013 duid
->duid_len
= len
;
1015 if ((hwlen
= gethwid(tmpbuf
, sizeof(tmpbuf
), NULL
, &hwtype
)) < 0) {
1016 dprintf(LOG_INFO
, FNAME
,
1017 "failed to get a hardware address");
1020 len
= hwlen
+ sizeof(union dhcp6opt_duid_type
);
1023 if ((duid
->duid_id
= (char *)malloc(len
)) == NULL
) {
1024 dprintf(LOG_ERR
, FNAME
, "failed to allocate memory");
1028 /* copy (and fill) the ID */
1030 if (fread(duid
->duid_id
, len
, 1, fp
) != 1) {
1031 dprintf(LOG_ERR
, FNAME
, "DUID file corrupted");
1035 dprintf(LOG_DEBUG
, FNAME
,
1036 "extracted an existing DUID from %s: %s",
1037 idfile
, duidstr(duid
));
1039 /* we only support the types 1,3 DUID */
1040 switch (duid_type
) {
1043 struct dhcp6opt_duid_type1
*dp
;
1045 duid
->duid_len
= hwlen
+ sizeof(struct dhcp6opt_duid_type1
);
1046 dp
= (struct dhcp6opt_duid_type1
*)duid
->duid_id
;
1047 dp
->dh6_duid1_type
= htons(1); /* type 1 */
1048 dp
->dh6_duid1_hwtype
= htons(hwtype
);
1049 /* time is Jan 1, 2000 (UTC), modulo 2^32 */
1050 t64
= (u_int64_t
)(time(NULL
) - 946684800);
1051 dp
->dh6_duid1_time
= htonl((u_long
)(t64
& 0xffffffff));
1052 memcpy((void *)(dp
+ 1), tmpbuf
, hwlen
);
1056 struct dhcp6opt_duid_type3
*dp
;
1058 duid
->duid_len
= hwlen
+ sizeof(struct dhcp6opt_duid_type3
);
1059 dp
= (struct dhcp6opt_duid_type3
*)duid
->duid_id
;
1060 dp
->dh6_duid3_type
= htons(3); /* type 3 */
1061 dp
->dh6_duid3_hwtype
= htons(hwtype
);
1062 memcpy((void *)(dp
+ 1), tmpbuf
, hwlen
);
1067 dprintf(LOG_DEBUG
, FNAME
, "generated a new DUID: %s",
1071 /* save the (new) ID to the file for next time */
1073 if ((fp
= fopen(idfile
, "w+")) == NULL
) {
1074 dprintf(LOG_ERR
, FNAME
,
1075 "failed to open DUID file for save");
1078 len
= duid
->duid_len
;
1079 if ((fwrite(&len
, sizeof(len
), 1, fp
)) != 1) {
1080 dprintf(LOG_ERR
, FNAME
, "failed to save DUID");
1083 if ((fwrite(duid
->duid_id
, len
, 1, fp
)) != 1) {
1084 dprintf(LOG_ERR
, FNAME
, "failed to save DUID");
1088 dprintf(LOG_DEBUG
, FNAME
, "saved generated DUID to %s",
1111 getifhwaddr(const char *ifname
, char *buf
, u_int16_t
*hwtypep
, int ppa
)
1114 char fname
[MAXPATHLEN
], *cp
;
1115 struct strbuf putctl
;
1116 struct strbuf getctl
;
1119 dl_phys_addr_req_t dlpar
;
1120 dl_phys_addr_ack_t
*dlpaa
;
1122 dprintf(LOG_DEBUG
, FNAME
, "trying %s ppa %d", ifname
, ppa
);
1124 if (ifname
[0] == '\0')
1126 if (ppa
>= 0 && !isdigit(ifname
[strlen(ifname
) - 1]))
1127 (void) snprintf(fname
, sizeof (fname
), "/dev/%s%d", ifname
,
1130 (void) snprintf(fname
, sizeof (fname
), "/dev/%s", ifname
);
1131 getctl
.maxlen
= sizeof (getbuf
);
1132 getctl
.buf
= (char *)getbuf
;
1133 if ((fd
= open(fname
, O_RDWR
)) == -1) {
1134 dl_attach_req_t dlar
;
1136 cp
= fname
+ strlen(fname
) - 1;
1139 while (cp
> fname
) {
1147 dlar
.dl_ppa
= atoi(cp
);
1149 if ((fd
= open(fname
, O_RDWR
)) == -1)
1151 dlar
.dl_primitive
= DL_ATTACH_REQ
;
1152 putctl
.len
= sizeof (dlar
);
1153 putctl
.buf
= (char *)&dlar
;
1154 if (putmsg(fd
, &putctl
, NULL
, 0) == -1) {
1159 if (getmsg(fd
, &getctl
, NULL
, &flags
) == -1) {
1163 if (getbuf
[0] != DL_OK_ACK
) {
1168 dlir
.dl_primitive
= DL_INFO_REQ
;
1169 putctl
.len
= sizeof (dlir
);
1170 putctl
.buf
= (char *)&dlir
;
1171 if (putmsg(fd
, &putctl
, NULL
, 0) == -1) {
1176 if (getmsg(fd
, &getctl
, NULL
, &flags
) == -1) {
1180 if (getbuf
[0] != DL_INFO_ACK
) {
1184 switch (((dl_info_ack_t
*)getbuf
)->dl_mac_type
) {
1190 *hwtypep
= ARPHRD_ETHER
;
1196 dlpar
.dl_primitive
= DL_PHYS_ADDR_REQ
;
1197 dlpar
.dl_addr_type
= DL_CURR_PHYS_ADDR
;
1198 putctl
.len
= sizeof (dlpar
);
1199 putctl
.buf
= (char *)&dlpar
;
1200 if (putmsg(fd
, &putctl
, NULL
, 0) == -1) {
1205 if (getmsg(fd
, &getctl
, NULL
, &flags
) == -1) {
1209 if (getbuf
[0] != DL_PHYS_ADDR_ACK
) {
1213 dlpaa
= (dl_phys_addr_ack_t
*)getbuf
;
1214 if (dlpaa
->dl_addr_length
!= 6) {
1218 (void) memcpy(buf
, (char *)getbuf
+ dlpaa
->dl_addr_offset
,
1219 dlpaa
->dl_addr_length
);
1220 return (dlpaa
->dl_addr_length
);
1224 devfs_handler(di_node_t node
, di_minor_t minor
, void *arg
)
1226 struct hwparms
*parms
= arg
;
1228 parms
->retval
= getifhwaddr(di_minor_name(minor
), parms
->buf
,
1229 parms
->hwtypep
, di_instance(node
));
1230 return (parms
->retval
== -1 ? DI_WALK_CONTINUE
: DI_WALK_TERMINATE
);
1235 gethwid(buf
, len
, ifname
, hwtypep
)
1241 struct ifaddrs
*ifa
, *ifap
;
1243 struct sockaddr_dl
*sdl
;
1246 struct sockaddr_ll
*sll
;
1251 if (ifname
== NULL
) {
1253 struct hwparms parms
;
1255 if ((root
= di_init("/", DINFOSUBTREE
| DINFOMINOR
|
1256 DINFOPROP
)) == DI_NODE_NIL
) {
1257 dprintf(LOG_INFO
, FNAME
, "di_init failed");
1261 parms
.hwtypep
= hwtypep
;
1263 (void) di_walk_minor(root
, DDI_NT_NET
, DI_CHECK_ALIAS
, &parms
,
1266 return (parms
.retval
);
1268 return (getifhwaddr(ifname
, buf
, hwtypep
, -1));
1272 if (getifaddrs(&ifap
) < 0)
1275 for (ifa
= ifap
; ifa
; ifa
= ifa
->ifa_next
) {
1276 if (ifname
&& strcmp(ifa
->ifa_name
, ifname
) != 0)
1278 if (ifa
->ifa_addr
== NULL
)
1281 if (ifa
->ifa_addr
->sa_family
!= AF_LINK
)
1284 sdl
= (struct sockaddr_dl
*)ifa
->ifa_addr
;
1285 if (len
< 2 + sdl
->sdl_alen
)
1288 * translate interface type to hardware type based on
1289 * http://www.iana.org/assignments/arp-parameters
1291 switch(sdl
->sdl_type
) {
1293 #ifdef IFT_IEEE80211
1296 *hwtypep
= ARPHRD_ETHER
;
1301 dprintf(LOG_DEBUG
, FNAME
, "found an interface %s for DUID",
1303 memcpy(buf
, LLADDR(sdl
), sdl
->sdl_alen
);
1304 l
= sdl
->sdl_alen
; /* sdl will soon be freed */
1307 if (ifa
->ifa_addr
->sa_family
!= AF_PACKET
)
1310 sll
= (struct sockaddr_ll
*)ifa
->ifa_addr
;
1311 if (sll
->sll_hatype
!= ARPHRD_ETHER
)
1313 *hwtypep
= ARPHRD_ETHER
;
1314 dprintf(LOG_DEBUG
, FNAME
, "found an interface %s for DUID",
1316 memcpy(buf
, sll
->sll_addr
, sll
->sll_halen
);
1317 l
= sll
->sll_halen
; /* sll will soon be freed */
1331 dhcp6_init_options(optinfo
)
1332 struct dhcp6_optinfo
*optinfo
;
1334 memset(optinfo
, 0, sizeof(*optinfo
));
1336 optinfo
->pref
= DH6OPT_PREF_UNDEF
;
1337 optinfo
->elapsed_time
= DH6OPT_ELAPSED_TIME_UNDEF
;
1338 optinfo
->refreshtime
= DH6OPT_REFRESHTIME_UNDEF
;
1340 TAILQ_INIT(&optinfo
->iapd_list
);
1341 TAILQ_INIT(&optinfo
->iana_list
);
1342 TAILQ_INIT(&optinfo
->reqopt_list
);
1343 TAILQ_INIT(&optinfo
->stcode_list
);
1344 TAILQ_INIT(&optinfo
->sip_list
);
1345 TAILQ_INIT(&optinfo
->sipname_list
);
1346 TAILQ_INIT(&optinfo
->dns_list
);
1347 TAILQ_INIT(&optinfo
->dnsname_list
);
1348 TAILQ_INIT(&optinfo
->ntp_list
);
1349 TAILQ_INIT(&optinfo
->prefix_list
);
1350 TAILQ_INIT(&optinfo
->nis_list
);
1351 TAILQ_INIT(&optinfo
->nisname_list
);
1352 TAILQ_INIT(&optinfo
->nisp_list
);
1353 TAILQ_INIT(&optinfo
->nispname_list
);
1354 TAILQ_INIT(&optinfo
->bcmcs_list
);
1355 TAILQ_INIT(&optinfo
->bcmcsname_list
);
1357 optinfo
->authproto
= DHCP6_AUTHPROTO_UNDEF
;
1358 optinfo
->authalgorithm
= DHCP6_AUTHALG_UNDEF
;
1359 optinfo
->authrdm
= DHCP6_AUTHRDM_UNDEF
;
1363 dhcp6_clear_options(optinfo
)
1364 struct dhcp6_optinfo
*optinfo
;
1366 switch (optinfo
->authproto
) {
1367 case DHCP6_AUTHPROTO_DELAYED
:
1368 if (optinfo
->delayedauth_realmval
!= NULL
) {
1369 free(optinfo
->delayedauth_realmval
);
1374 duidfree(&optinfo
->clientID
);
1375 duidfree(&optinfo
->serverID
);
1377 dhcp6_clear_list(&optinfo
->iapd_list
);
1378 dhcp6_clear_list(&optinfo
->iana_list
);
1379 dhcp6_clear_list(&optinfo
->reqopt_list
);
1380 dhcp6_clear_list(&optinfo
->stcode_list
);
1381 dhcp6_clear_list(&optinfo
->sip_list
);
1382 dhcp6_clear_list(&optinfo
->sipname_list
);
1383 dhcp6_clear_list(&optinfo
->dns_list
);
1384 dhcp6_clear_list(&optinfo
->dnsname_list
);
1385 dhcp6_clear_list(&optinfo
->ntp_list
);
1386 dhcp6_clear_list(&optinfo
->prefix_list
);
1387 dhcp6_clear_list(&optinfo
->nis_list
);
1388 dhcp6_clear_list(&optinfo
->nisname_list
);
1389 dhcp6_clear_list(&optinfo
->nisp_list
);
1390 dhcp6_clear_list(&optinfo
->nispname_list
);
1391 dhcp6_clear_list(&optinfo
->bcmcs_list
);
1392 dhcp6_clear_list(&optinfo
->bcmcsname_list
);
1394 if (optinfo
->relaymsg_msg
!= NULL
)
1395 free(optinfo
->relaymsg_msg
);
1397 if (optinfo
->ifidopt_id
!= NULL
)
1398 free(optinfo
->ifidopt_id
);
1400 dhcp6_init_options(optinfo
);
1404 dhcp6_copy_options(dst
, src
)
1405 struct dhcp6_optinfo
*dst
, *src
;
1407 if (duidcpy(&dst
->clientID
, &src
->clientID
))
1409 if (duidcpy(&dst
->serverID
, &src
->serverID
))
1411 dst
->rapidcommit
= src
->rapidcommit
;
1413 if (dhcp6_copy_list(&dst
->iapd_list
, &src
->iapd_list
))
1415 if (dhcp6_copy_list(&dst
->iana_list
, &src
->iana_list
))
1417 if (dhcp6_copy_list(&dst
->reqopt_list
, &src
->reqopt_list
))
1419 if (dhcp6_copy_list(&dst
->stcode_list
, &src
->stcode_list
))
1421 if (dhcp6_copy_list(&dst
->sip_list
, &src
->sip_list
))
1423 if (dhcp6_copy_list(&dst
->sipname_list
, &src
->sipname_list
))
1425 if (dhcp6_copy_list(&dst
->dns_list
, &src
->dns_list
))
1427 if (dhcp6_copy_list(&dst
->dnsname_list
, &src
->dnsname_list
))
1429 if (dhcp6_copy_list(&dst
->ntp_list
, &src
->ntp_list
))
1431 if (dhcp6_copy_list(&dst
->prefix_list
, &src
->prefix_list
))
1433 if (dhcp6_copy_list(&dst
->nis_list
, &src
->nis_list
))
1435 if (dhcp6_copy_list(&dst
->nisname_list
, &src
->nisname_list
))
1437 if (dhcp6_copy_list(&dst
->nisp_list
, &src
->nisp_list
))
1439 if (dhcp6_copy_list(&dst
->nispname_list
, &src
->nispname_list
))
1441 if (dhcp6_copy_list(&dst
->bcmcs_list
, &src
->bcmcs_list
))
1443 if (dhcp6_copy_list(&dst
->bcmcsname_list
, &src
->bcmcsname_list
))
1445 dst
->elapsed_time
= src
->elapsed_time
;
1446 dst
->refreshtime
= src
->refreshtime
;
1447 dst
->pref
= src
->pref
;
1449 if (src
->relaymsg_msg
!= NULL
) {
1450 if ((dst
->relaymsg_msg
= malloc(src
->relaymsg_len
)) == NULL
)
1452 dst
->relaymsg_len
= src
->relaymsg_len
;
1453 memcpy(dst
->relaymsg_msg
, src
->relaymsg_msg
,
1457 if (src
->ifidopt_id
!= NULL
) {
1458 if ((dst
->ifidopt_id
= malloc(src
->ifidopt_len
)) == NULL
)
1460 dst
->ifidopt_len
= src
->ifidopt_len
;
1461 memcpy(dst
->ifidopt_id
, src
->ifidopt_id
, src
->ifidopt_len
);
1464 dst
->authflags
= src
->authflags
;
1465 dst
->authproto
= src
->authproto
;
1466 dst
->authalgorithm
= src
->authalgorithm
;
1467 dst
->authrdm
= src
->authrdm
;
1468 dst
->authrd
= src
->authrd
;
1470 switch (src
->authproto
) {
1471 case DHCP6_AUTHPROTO_DELAYED
:
1472 dst
->delayedauth_keyid
= src
->delayedauth_keyid
;
1473 dst
->delayedauth_offset
= src
->delayedauth_offset
;
1474 dst
->delayedauth_realmlen
= src
->delayedauth_realmlen
;
1475 if (src
->delayedauth_realmval
!= NULL
) {
1476 if ((dst
->delayedauth_realmval
=
1477 malloc(src
->delayedauth_realmlen
)) == NULL
) {
1480 memcpy(dst
->delayedauth_realmval
,
1481 src
->delayedauth_realmval
,
1482 src
->delayedauth_realmlen
);
1485 case DHCP6_AUTHPROTO_RECONFIG
:
1486 dst
->reconfigauth_type
= src
->reconfigauth_type
;
1487 dst
->reconfigauth_offset
= src
->reconfigauth_offset
;
1488 memcpy(dst
->reconfigauth_val
, src
->reconfigauth_val
,
1489 sizeof(dst
->reconfigauth_val
));
1496 /* cleanup temporary resources */
1497 dhcp6_clear_options(dst
);
1502 dhcp6_get_options(p
, ep
, optinfo
)
1503 struct dhcp6opt
*p
, *ep
;
1504 struct dhcp6_optinfo
*optinfo
;
1506 struct dhcp6opt
*np
, opth
;
1507 int i
, opt
, optlen
, reqopts
, num
;
1509 char *bp
, *cp
, *val
;
1512 struct dhcp6opt_ia optia
;
1514 struct dhcp6_list sublist
;
1518 for (; p
+ 1 <= ep
; p
= np
) {
1522 * get the option header. XXX: since there is no guarantee
1523 * about the header alignment, we need to make a local copy.
1525 memcpy(&opth
, p
, sizeof(opth
));
1526 optlen
= ntohs(opth
.dh6opt_len
);
1527 opt
= ntohs(opth
.dh6opt_type
);
1529 cp
= (char *)(p
+ 1);
1530 np
= (struct dhcp6opt
*)(cp
+ optlen
);
1532 dprintf(LOG_DEBUG
, FNAME
, "get DHCP option %s, len %d",
1533 dhcp6optstr(opt
), optlen
);
1535 /* option length field overrun */
1537 dprintf(LOG_INFO
, FNAME
, "malformed DHCP options");
1542 case DH6OPT_CLIENTID
:
1545 duid0
.duid_len
= optlen
;
1547 dprintf(LOG_DEBUG
, "",
1548 " DUID: %s", duidstr(&duid0
));
1549 if (duidcpy(&optinfo
->clientID
, &duid0
)) {
1550 dprintf(LOG_ERR
, FNAME
, "failed to copy DUID");
1554 case DH6OPT_SERVERID
:
1557 duid0
.duid_len
= optlen
;
1559 dprintf(LOG_DEBUG
, "", " DUID: %s", duidstr(&duid0
));
1560 if (duidcpy(&optinfo
->serverID
, &duid0
)) {
1561 dprintf(LOG_ERR
, FNAME
, "failed to copy DUID");
1565 case DH6OPT_STATUS_CODE
:
1566 if (optlen
< sizeof(u_int16_t
))
1568 memcpy(&val16
, cp
, sizeof(val16
));
1569 num16
= ntohs(val16
);
1570 dprintf(LOG_DEBUG
, "", " status code: %s",
1571 dhcp6_stcodestr(num16
));
1573 /* need to check duplication? */
1575 if (dhcp6_add_listval(&optinfo
->stcode_list
,
1576 DHCP6_LISTVAL_STCODE
, &num16
, NULL
) == NULL
) {
1577 dprintf(LOG_ERR
, FNAME
, "failed to copy "
1584 if ((optlen
% 2) != 0 || optlen
== 0)
1586 reqopts
= optlen
/ 2;
1587 for (i
= 0, val
= cp
; i
< reqopts
;
1588 i
++, val
+= sizeof(u_int16_t
)) {
1591 memcpy(&opttype
, val
, sizeof(u_int16_t
));
1592 num
= (int)ntohs(opttype
);
1594 dprintf(LOG_DEBUG
, "",
1595 " requested option: %s",
1598 if (dhcp6_find_listval(&optinfo
->reqopt_list
,
1599 DHCP6_LISTVAL_NUM
, &num
, 0)) {
1600 dprintf(LOG_INFO
, FNAME
, "duplicated "
1602 dhcp6optstr(opttype
));
1606 if (dhcp6_add_listval(&optinfo
->reqopt_list
,
1607 DHCP6_LISTVAL_NUM
, &num
, NULL
) == NULL
) {
1608 dprintf(LOG_ERR
, FNAME
,
1609 "failed to copy requested option");
1616 case DH6OPT_PREFERENCE
:
1619 dprintf(LOG_DEBUG
, "", " preference: %d",
1620 (int)*(u_char
*)cp
);
1621 if (optinfo
->pref
!= DH6OPT_PREF_UNDEF
) {
1622 dprintf(LOG_INFO
, FNAME
,
1623 "duplicated preference option");
1625 optinfo
->pref
= (int)*(u_char
*)cp
;
1627 case DH6OPT_ELAPSED_TIME
:
1630 memcpy(&val16
, cp
, sizeof(val16
));
1631 val16
= ntohs(val16
);
1632 dprintf(LOG_DEBUG
, "", " elapsed time: %lu",
1634 if (optinfo
->elapsed_time
!=
1635 DH6OPT_ELAPSED_TIME_UNDEF
) {
1636 dprintf(LOG_INFO
, FNAME
,
1637 "duplicated elapsed time option");
1639 optinfo
->elapsed_time
= val16
;
1641 case DH6OPT_RELAY_MSG
:
1642 if ((optinfo
->relaymsg_msg
= malloc(optlen
)) == NULL
)
1644 memcpy(optinfo
->relaymsg_msg
, cp
, optlen
);
1645 optinfo
->relaymsg_len
= optlen
;
1648 if (optlen
< sizeof(struct dhcp6opt_auth
) - 4)
1652 * Any DHCP message that includes more than one
1653 * authentication option MUST be discarded.
1654 * [RFC3315 Section 21.4.2]
1656 if (optinfo
->authproto
!= DHCP6_AUTHPROTO_UNDEF
) {
1657 dprintf(LOG_INFO
, FNAME
, "found more than one "
1658 "authentication option");
1662 optinfo
->authproto
= *cp
++;
1663 optinfo
->authalgorithm
= *cp
++;
1664 optinfo
->authrdm
= *cp
++;
1665 memcpy(&optinfo
->authrd
, cp
, sizeof(optinfo
->authrd
));
1666 cp
+= sizeof(optinfo
->authrd
);
1668 dprintf(LOG_DEBUG
, "", " %s", sprint_auth(optinfo
));
1671 optlen
- (sizeof(struct dhcp6opt_auth
) - 4);
1672 switch (optinfo
->authproto
) {
1673 case DHCP6_AUTHPROTO_DELAYED
:
1674 if (authinfolen
== 0) {
1675 optinfo
->authflags
|=
1676 DHCP6OPT_AUTHFLAG_NOINFO
;
1679 /* XXX: should we reject an empty realm? */
1681 sizeof(optinfo
->delayedauth_keyid
) + 16) {
1685 optinfo
->delayedauth_realmlen
= authinfolen
-
1686 (sizeof(optinfo
->delayedauth_keyid
) + 16);
1687 optinfo
->delayedauth_realmval
=
1688 malloc(optinfo
->delayedauth_realmlen
);
1689 if (optinfo
->delayedauth_realmval
== NULL
) {
1690 dprintf(LOG_WARNING
, FNAME
, "failed "
1691 "allocate memory for auth realm");
1694 memcpy(optinfo
->delayedauth_realmval
, cp
,
1695 optinfo
->delayedauth_realmlen
);
1696 cp
+= optinfo
->delayedauth_realmlen
;
1698 memcpy(&optinfo
->delayedauth_keyid
, cp
,
1699 sizeof(optinfo
->delayedauth_keyid
));
1700 optinfo
->delayedauth_keyid
=
1701 ntohl(optinfo
->delayedauth_keyid
);
1702 cp
+= sizeof(optinfo
->delayedauth_keyid
);
1704 optinfo
->delayedauth_offset
= cp
- bp
;
1707 dprintf(LOG_DEBUG
, "", " auth key ID: %x, "
1708 "offset=%d, realmlen=%d",
1709 optinfo
->delayedauth_keyid
,
1710 optinfo
->delayedauth_offset
,
1711 optinfo
->delayedauth_realmlen
);
1714 case DHCP6_AUTHPROTO_RECONFIG
:
1718 dprintf(LOG_INFO
, FNAME
,
1719 "unsupported authentication protocol: %d",
1724 case DH6OPT_RAPID_COMMIT
:
1727 optinfo
->rapidcommit
= 1;
1729 case DH6OPT_INTERFACE_ID
:
1730 if ((optinfo
->ifidopt_id
= malloc(optlen
)) == NULL
)
1732 memcpy(optinfo
->ifidopt_id
, cp
, optlen
);
1733 optinfo
->ifidopt_len
= optlen
;
1735 case DH6OPT_SIP_SERVER_D
:
1736 if (dhcp6_get_domain(optlen
, cp
, opt
,
1737 &optinfo
->sipname_list
) == -1)
1740 case DH6OPT_DNSNAME
:
1741 if (dhcp6_get_domain(optlen
, cp
, opt
,
1742 &optinfo
->dnsname_list
) == -1)
1745 case DH6OPT_NIS_DOMAIN_NAME
:
1746 if (dhcp6_get_domain(optlen
, cp
, opt
,
1747 &optinfo
->nisname_list
) == -1)
1750 case DH6OPT_NISP_DOMAIN_NAME
:
1751 if (dhcp6_get_domain(optlen
, cp
, opt
,
1752 &optinfo
->nispname_list
) == -1)
1755 case DH6OPT_BCMCS_SERVER_D
:
1756 if (dhcp6_get_domain(optlen
, cp
, opt
,
1757 &optinfo
->bcmcsname_list
) == -1)
1760 case DH6OPT_SIP_SERVER_A
:
1761 if (dhcp6_get_addr(optlen
, cp
, opt
,
1762 &optinfo
->sip_list
) == -1)
1766 if (dhcp6_get_addr(optlen
, cp
, opt
,
1767 &optinfo
->dns_list
) == -1)
1770 case DH6OPT_NIS_SERVERS
:
1771 if (dhcp6_get_addr(optlen
, cp
, opt
,
1772 &optinfo
->nis_list
) == -1)
1775 case DH6OPT_NISP_SERVERS
:
1776 if (dhcp6_get_addr(optlen
, cp
, opt
,
1777 &optinfo
->nisp_list
) == -1)
1780 case DH6OPT_BCMCS_SERVER_A
:
1781 if (dhcp6_get_addr(optlen
, cp
, opt
,
1782 &optinfo
->bcmcs_list
) == -1)
1786 if (dhcp6_get_addr(optlen
, cp
, opt
,
1787 &optinfo
->ntp_list
) == -1)
1791 if (optlen
+ sizeof(struct dhcp6opt
) <
1794 memcpy(&optia
, p
, sizeof(optia
));
1795 ia
.iaid
= ntohl(optia
.dh6_ia_iaid
);
1796 ia
.t1
= ntohl(optia
.dh6_ia_t1
);
1797 ia
.t2
= ntohl(optia
.dh6_ia_t2
);
1799 dprintf(LOG_DEBUG
, "",
1800 " IA_PD: ID=%lu, T1=%lu, T2=%lu",
1801 ia
.iaid
, ia
.t1
, ia
.t2
);
1803 /* duplication check */
1804 if (dhcp6_find_listval(&optinfo
->iapd_list
,
1805 DHCP6_LISTVAL_IAPD
, &ia
, 0)) {
1806 dprintf(LOG_INFO
, FNAME
,
1807 "duplicated IA_PD %lu", ia
.iaid
);
1808 break; /* ignore this IA_PD */
1811 /* take care of sub-options */
1812 TAILQ_INIT(&sublist
);
1813 if (copyin_option(opt
,
1814 (struct dhcp6opt
*)((char *)p
+ sizeof(optia
)),
1815 (struct dhcp6opt
*)(cp
+ optlen
), &sublist
)) {
1819 /* link this option set */
1820 if (dhcp6_add_listval(&optinfo
->iapd_list
,
1821 DHCP6_LISTVAL_IAPD
, &ia
, &sublist
) == NULL
) {
1822 dhcp6_clear_list(&sublist
);
1825 dhcp6_clear_list(&sublist
);
1828 case DH6OPT_REFRESHTIME
:
1831 memcpy(&val32
, cp
, sizeof(val32
));
1832 val32
= ntohl(val32
);
1833 dprintf(LOG_DEBUG
, "",
1834 " information refresh time: %lu", val32
);
1835 if (val32
< DHCP6_IRT_MINIMUM
) {
1837 * A client MUST use the refresh time
1838 * IRT_MINIMUM if it receives the option with a
1839 * value less than IRT_MINIMUM.
1840 * [draft-ietf-dhc-lifetime-02.txt,
1843 dprintf(LOG_INFO
, FNAME
,
1844 "refresh time is too small (%d), adjusted",
1846 val32
= DHCP6_IRT_MINIMUM
;
1848 if (optinfo
->refreshtime
!= DH6OPT_REFRESHTIME_UNDEF
) {
1849 dprintf(LOG_INFO
, FNAME
,
1850 "duplicated refresh time option");
1852 optinfo
->refreshtime
= (int64_t)val32
;
1855 if (optlen
+ sizeof(struct dhcp6opt
) <
1858 memcpy(&optia
, p
, sizeof(optia
));
1859 ia
.iaid
= ntohl(optia
.dh6_ia_iaid
);
1860 ia
.t1
= ntohl(optia
.dh6_ia_t1
);
1861 ia
.t2
= ntohl(optia
.dh6_ia_t2
);
1863 dprintf(LOG_DEBUG
, "",
1864 " IA_NA: ID=%lu, T1=%lu, T2=%lu",
1865 ia
.iaid
, ia
.t1
, ia
.t2
);
1867 /* duplication check */
1868 if (dhcp6_find_listval(&optinfo
->iana_list
,
1869 DHCP6_LISTVAL_IANA
, &ia
, 0)) {
1870 dprintf(LOG_INFO
, FNAME
,
1871 "duplicated IA_NA %lu", ia
.iaid
);
1872 break; /* ignore this IA_NA */
1875 /* take care of sub-options */
1876 TAILQ_INIT(&sublist
);
1877 if (copyin_option(opt
,
1878 (struct dhcp6opt
*)((char *)p
+ sizeof(optia
)),
1879 (struct dhcp6opt
*)(cp
+ optlen
), &sublist
)) {
1883 /* link this option set */
1884 if (dhcp6_add_listval(&optinfo
->iana_list
,
1885 DHCP6_LISTVAL_IANA
, &ia
, &sublist
) == NULL
) {
1886 dhcp6_clear_list(&sublist
);
1889 dhcp6_clear_list(&sublist
);
1893 /* no option specific behavior */
1894 dprintf(LOG_INFO
, FNAME
,
1895 "unknown or unexpected DHCP6 option %s, len %d",
1896 dhcp6optstr(opt
), optlen
);
1904 dprintf(LOG_INFO
, FNAME
, "malformed DHCP option: type %d, len %d",
1907 dhcp6_clear_options(optinfo
);
1912 dnsdecode(sp
, ep
, buf
, bufsiz
)
1920 char tmpbuf
[MAXDNAME
+ 1];
1924 i
= 0; /* XXX: appease gcc */
1930 if (i
== 0 || cp
!= *sp
) {
1931 if (strlcat((char *)buf
, ".", bufsiz
) >= bufsiz
)
1932 return (NULL
); /* result overrun */
1939 return (NULL
); /* invalid label */
1942 return (NULL
); /* source overrun */
1943 while (i
-- > 0 && cp
< ep
) {
1944 if (!isprint(*cp
)) /* we don't accept non-printables */
1946 l
= snprintf(tmpbuf
, sizeof(tmpbuf
), "%c" , *cp
);
1947 if (l
>= sizeof(tmpbuf
) || l
< 0)
1949 if (strlcat(buf
, tmpbuf
, bufsiz
) >= bufsiz
)
1950 return (NULL
); /* result overrun */
1955 return (NULL
); /* not terminated */
1962 copyin_option(type
, p
, ep
, list
)
1964 struct dhcp6opt
*p
, *ep
;
1965 struct dhcp6_list
*list
;
1969 struct dhcp6opt
*np
, opth
;
1970 struct dhcp6opt_stcode opt_stcode
;
1971 struct dhcp6opt_ia_pd_prefix opt_iapd_prefix
;
1972 struct dhcp6_prefix iapd_prefix
;
1973 struct dhcp6opt_ia_addr opt_ia_addr
;
1974 struct dhcp6_prefix ia_addr
;
1975 struct dhcp6_list sublist
;
1977 TAILQ_INIT(&sublist
);
1979 for (; p
+ 1 <= ep
; p
= np
) {
1980 memcpy(&opth
, p
, sizeof(opth
));
1981 optlen
= ntohs(opth
.dh6opt_len
);
1982 opt
= ntohs(opth
.dh6opt_type
);
1984 cp
= (char *)(p
+ 1);
1985 np
= (struct dhcp6opt
*)(cp
+ optlen
);
1987 dprintf(LOG_DEBUG
, FNAME
, "get DHCP option %s, len %d",
1988 dhcp6optstr(opt
), optlen
);
1991 dprintf(LOG_INFO
, FNAME
, "malformed DHCP option");
1996 case DH6OPT_IA_PD_PREFIX
:
1997 /* check option context */
1998 if (type
!= DH6OPT_IA_PD
) {
1999 dprintf(LOG_INFO
, FNAME
,
2000 "%s is an invalid position for %s",
2001 dhcp6optstr(type
), dhcp6optstr(opt
));
2004 /* check option length */
2005 if (optlen
+ sizeof(opth
) < sizeof(opt_iapd_prefix
))
2008 /* copy and convert option values */
2009 memcpy(&opt_iapd_prefix
, p
, sizeof(opt_iapd_prefix
));
2010 if (opt_iapd_prefix
.dh6_iapd_prefix_prefix_len
> 128) {
2011 dprintf(LOG_INFO
, FNAME
,
2012 "invalid prefix length (%d)",
2013 opt_iapd_prefix
.dh6_iapd_prefix_prefix_len
);
2016 iapd_prefix
.pltime
= ntohl(opt_iapd_prefix
.dh6_iapd_prefix_preferred_time
);
2017 iapd_prefix
.vltime
= ntohl(opt_iapd_prefix
.dh6_iapd_prefix_valid_time
);
2019 opt_iapd_prefix
.dh6_iapd_prefix_prefix_len
;
2020 memcpy(&iapd_prefix
.addr
,
2021 &opt_iapd_prefix
.dh6_iapd_prefix_prefix_addr
,
2022 sizeof(iapd_prefix
.addr
));
2023 /* clear padding bits in the prefix address */
2024 prefix6_mask(&iapd_prefix
.addr
, iapd_prefix
.plen
);
2026 dprintf(LOG_DEBUG
, FNAME
, " IA_PD prefix: "
2027 "%s/%d pltime=%lu vltime=%lu",
2028 in6addr2str(&iapd_prefix
.addr
, 0),
2030 iapd_prefix
.pltime
, iapd_prefix
.vltime
);
2032 if (dhcp6_find_listval(list
, DHCP6_LISTVAL_PREFIX6
,
2034 dprintf(LOG_INFO
, FNAME
,
2035 "duplicated IA_PD prefix "
2036 "%s/%d pltime=%lu vltime=%lu",
2037 in6addr2str(&iapd_prefix
.addr
, 0),
2039 iapd_prefix
.pltime
, iapd_prefix
.vltime
);
2043 /* take care of sub-options */
2044 TAILQ_INIT(&sublist
);
2045 if (copyin_option(opt
,
2046 (struct dhcp6opt
*)((char *)p
+
2047 sizeof(opt_iapd_prefix
)), np
, &sublist
)) {
2051 if (dhcp6_add_listval(list
, DHCP6_LISTVAL_PREFIX6
,
2052 &iapd_prefix
, &sublist
) == NULL
) {
2053 dhcp6_clear_list(&sublist
);
2056 dhcp6_clear_list(&sublist
);
2059 /* check option context */
2060 if (type
!= DH6OPT_IA_NA
) {
2061 dprintf(LOG_INFO
, FNAME
,
2062 "%s is an invalid position for %s",
2063 dhcp6optstr(type
), dhcp6optstr(opt
));
2066 /* check option length */
2067 if (optlen
+ sizeof(opth
) < sizeof(opt_ia_addr
))
2070 /* copy and convert option values */
2071 memcpy(&opt_ia_addr
, p
, sizeof(opt_ia_addr
));
2072 ia_addr
.pltime
= ntohl(opt_ia_addr
.dh6_ia_addr_preferred_time
);
2073 ia_addr
.vltime
= ntohl(opt_ia_addr
.dh6_ia_addr_valid_time
);
2074 memcpy(&ia_addr
.addr
, &opt_ia_addr
.dh6_ia_addr_addr
,
2075 sizeof(ia_addr
.addr
));
2077 dprintf(LOG_DEBUG
, FNAME
, " IA_NA address: "
2078 "%s pltime=%lu vltime=%lu",
2079 in6addr2str(&ia_addr
.addr
, 0),
2080 ia_addr
.pltime
, ia_addr
.vltime
);
2082 if (dhcp6_find_listval(list
,
2083 DHCP6_LISTVAL_STATEFULADDR6
, &ia_addr
, 0)) {
2084 dprintf(LOG_INFO
, FNAME
,
2085 "duplicated IA_NA address"
2086 "%s pltime=%lu vltime=%lu",
2087 in6addr2str(&ia_addr
.addr
, 0),
2088 ia_addr
.pltime
, ia_addr
.vltime
);
2092 /* take care of sub-options */
2093 TAILQ_INIT(&sublist
);
2094 if (copyin_option(opt
,
2095 (struct dhcp6opt
*)((char *)p
+
2096 sizeof(opt_ia_addr
)), np
, &sublist
)) {
2100 if (dhcp6_add_listval(list
, DHCP6_LISTVAL_STATEFULADDR6
,
2101 &ia_addr
, &sublist
) == NULL
) {
2102 dhcp6_clear_list(&sublist
);
2105 dhcp6_clear_list(&sublist
);
2107 case DH6OPT_STATUS_CODE
:
2108 /* check option context */
2109 if (type
!= DH6OPT_IA_PD
&&
2110 type
!= DH6OPT_IA_PD_PREFIX
&&
2111 type
!= DH6OPT_IA_NA
&&
2112 type
!= DH6OPT_IAADDR
) {
2113 dprintf(LOG_INFO
, FNAME
,
2114 "%s is an invalid position for %s",
2115 dhcp6optstr(type
), dhcp6optstr(opt
));
2116 goto nextoption
; /* or discard the message? */
2118 /* check option length */
2119 if (optlen
+ sizeof(opth
) < sizeof(opt_stcode
))
2122 /* copy and convert option values */
2123 memcpy(&opt_stcode
, p
, sizeof(opt_stcode
));
2124 opt_stcode
.dh6_stcode_code
=
2125 ntohs(opt_stcode
.dh6_stcode_code
);
2127 dprintf(LOG_DEBUG
, "", " status code: %s",
2128 dhcp6_stcodestr(opt_stcode
.dh6_stcode_code
));
2130 /* duplication check */
2131 if (dhcp6_find_listval(list
, DHCP6_LISTVAL_STCODE
,
2132 &opt_stcode
.dh6_stcode_code
, 0)) {
2133 dprintf(LOG_INFO
, FNAME
,
2134 "duplicated status code (%d)",
2135 opt_stcode
.dh6_stcode_code
);
2139 /* copy-in the code value */
2140 if (dhcp6_add_listval(list
, DHCP6_LISTVAL_STCODE
,
2141 &opt_stcode
.dh6_stcode_code
, NULL
) == NULL
)
2153 dprintf(LOG_INFO
, "", " malformed DHCP option: type %d", opt
);
2156 dhcp6_clear_list(&sublist
);
2161 sprint_uint64(buf
, buflen
, i64
)
2166 u_int16_t rd0
, rd1
, rd2
, rd3
;
2167 u_int16_t
*ptr
= (u_int16_t
*)(void *)&i64
;
2169 rd0
= ntohs(*ptr
++);
2170 rd1
= ntohs(*ptr
++);
2171 rd2
= ntohs(*ptr
++);
2174 snprintf(buf
, buflen
, "%04x %04x %04x %04x", rd0
, rd1
, rd2
, rd3
);
2180 sprint_auth(optinfo
)
2181 struct dhcp6_optinfo
*optinfo
;
2183 static char ret
[1024]; /* XXX: thread unsafe */
2184 char *proto
, proto0
[] = "unknown(255)";
2185 char *alg
, alg0
[] = "unknown(255)";
2186 char *rdm
, rdm0
[] = "unknown(255)";
2187 char rd
[] = "ffff ffff ffff ffff";
2189 switch (optinfo
->authproto
) {
2190 case DHCP6_AUTHPROTO_DELAYED
:
2193 case DHCP6_AUTHPROTO_RECONFIG
:
2197 snprintf(proto0
, sizeof(proto0
), "unknown(%d)",
2198 optinfo
->authproto
& 0xff);
2203 switch (optinfo
->authalgorithm
) {
2204 case DHCP6_AUTHALG_HMACMD5
:
2208 snprintf(alg0
, sizeof(alg0
), "unknown(%d)",
2209 optinfo
->authalgorithm
& 0xff);
2214 switch (optinfo
->authrdm
) {
2215 case DHCP6_AUTHRDM_MONOCOUNTER
:
2216 rdm
= "mono counter";
2219 snprintf(rdm0
, sizeof(rdm0
), "unknown(%d)", optinfo
->authrdm
);
2223 (void)sprint_uint64(rd
, sizeof(rd
), optinfo
->authrd
);
2225 snprintf(ret
, sizeof(ret
), "proto: %s, alg: %s, RDM: %s, RD: %s",
2226 proto
, alg
, rdm
, rd
);
2232 copy_option(type
, len
, val
, optp
, ep
, totallenp
)
2233 u_int16_t type
, len
;
2235 struct dhcp6opt
**optp
, *ep
;
2238 struct dhcp6opt
*opt
= *optp
, opth
;
2240 if ((void *)ep
- (void *)optp
< len
+ sizeof(struct dhcp6opt
)) {
2241 dprintf(LOG_INFO
, FNAME
,
2242 "option buffer short for %s", dhcp6optstr(type
));
2245 opth
.dh6opt_type
= htons(type
);
2246 opth
.dh6opt_len
= htons(len
);
2247 memcpy(opt
, &opth
, sizeof(opth
));
2249 memcpy(opt
+ 1, val
, len
);
2251 *optp
= (struct dhcp6opt
*)((char *)(opt
+ 1) + len
);
2252 *totallenp
+= sizeof(struct dhcp6opt
) + len
;
2253 dprintf(LOG_DEBUG
, FNAME
, "set %s (len %d)", dhcp6optstr(type
), len
);
2259 dhcp6_set_options(type
, optbp
, optep
, optinfo
)
2261 struct dhcp6opt
*optbp
, *optep
;
2262 struct dhcp6_optinfo
*optinfo
;
2264 struct dhcp6opt
*p
= optbp
;
2265 struct dhcp6_listval
*stcode
, *op
;
2266 int len
= 0, optlen
;
2267 char *tmpbuf
= NULL
;
2269 if (optinfo
->clientID
.duid_len
) {
2270 if (copy_option(DH6OPT_CLIENTID
, optinfo
->clientID
.duid_len
,
2271 optinfo
->clientID
.duid_id
, &p
, optep
, &len
) != 0) {
2276 if (optinfo
->serverID
.duid_len
) {
2277 if (copy_option(DH6OPT_SERVERID
, optinfo
->serverID
.duid_len
,
2278 optinfo
->serverID
.duid_id
, &p
, optep
, &len
) != 0) {
2283 for (op
= TAILQ_FIRST(&optinfo
->iana_list
); op
;
2284 op
= TAILQ_NEXT(op
, link
)) {
2288 if ((optlen
= copyout_option(NULL
, NULL
, op
)) < 0) {
2289 dprintf(LOG_INFO
, FNAME
,
2290 "failed to count option length");
2293 if ((void *)optep
- (void *)p
< optlen
) {
2294 dprintf(LOG_INFO
, FNAME
, "short buffer");
2297 if ((tmpbuf
= malloc(optlen
)) == NULL
) {
2298 dprintf(LOG_NOTICE
, FNAME
,
2299 "memory allocation failed for IA_NA options");
2302 if (copyout_option(tmpbuf
, tmpbuf
+ optlen
, op
) < 0) {
2303 dprintf(LOG_ERR
, FNAME
,
2304 "failed to construct an IA_NA option");
2307 memcpy(p
, tmpbuf
, optlen
);
2310 p
= (struct dhcp6opt
*)((char *)p
+ optlen
);
2314 if (optinfo
->rapidcommit
) {
2315 if (copy_option(DH6OPT_RAPID_COMMIT
, 0, NULL
, &p
,
2316 optep
, &len
) != 0) {
2321 if (optinfo
->pref
!= DH6OPT_PREF_UNDEF
) {
2322 u_int8_t p8
= (u_int8_t
)optinfo
->pref
;
2324 if (copy_option(DH6OPT_PREFERENCE
, sizeof(p8
), &p8
, &p
,
2325 optep
, &len
) != 0) {
2330 if (optinfo
->elapsed_time
!= DH6OPT_ELAPSED_TIME_UNDEF
) {
2331 u_int16_t p16
= (u_int16_t
)optinfo
->elapsed_time
;
2334 if (copy_option(DH6OPT_ELAPSED_TIME
, sizeof(p16
), &p16
, &p
,
2335 optep
, &len
) != 0) {
2340 for (stcode
= TAILQ_FIRST(&optinfo
->stcode_list
); stcode
;
2341 stcode
= TAILQ_NEXT(stcode
, link
)) {
2344 code
= htons(stcode
->val_num16
);
2345 if (copy_option(DH6OPT_STATUS_CODE
, sizeof(code
), &code
, &p
,
2346 optep
, &len
) != 0) {
2351 if (!TAILQ_EMPTY(&optinfo
->reqopt_list
)) {
2352 struct dhcp6_listval
*opt
;
2357 buflen
= dhcp6_count_list(&optinfo
->reqopt_list
) *
2359 if ((tmpbuf
= malloc(buflen
)) == NULL
) {
2360 dprintf(LOG_ERR
, FNAME
,
2361 "memory allocation failed for options");
2365 valp
= (u_int16_t
*)tmpbuf
;
2366 for (opt
= TAILQ_FIRST(&optinfo
->reqopt_list
); opt
;
2367 opt
= TAILQ_NEXT(opt
, link
)) {
2369 * Information request option can only be specified
2370 * in information-request messages.
2371 * [draft-ietf-dhc-lifetime-02.txt, Section 3.2]
2373 if (opt
->val_num
== DH6OPT_REFRESHTIME
&&
2374 type
!= DH6_INFORM_REQ
) {
2375 dprintf(LOG_DEBUG
, FNAME
,
2376 "refresh time option is not requested "
2377 "for %s", dhcp6msgstr(type
));
2380 *valp
= htons((u_int16_t
)opt
->val_num
);
2382 optlen
+= sizeof(u_int16_t
);
2385 copy_option(DH6OPT_ORO
, optlen
, tmpbuf
, &p
,
2386 optep
, &len
) != 0) {
2393 if (dhcp6_set_domain(DH6OPT_SIP_SERVER_D
, &optinfo
->sipname_list
,
2394 &p
, optep
, &len
) != 0)
2397 if (dhcp6_set_addr(DH6OPT_SIP_SERVER_A
, &optinfo
->sip_list
,
2398 &p
, optep
, &len
) != 0)
2401 if (dhcp6_set_addr(DH6OPT_DNS
, &optinfo
->dns_list
,
2402 &p
, optep
, &len
) != 0)
2405 if (dhcp6_set_domain(DH6OPT_DNSNAME
, &optinfo
->dnsname_list
,
2406 &p
, optep
, &len
) != 0)
2409 if (dhcp6_set_addr(DH6OPT_NIS_SERVERS
, &optinfo
->nis_list
,
2410 &p
, optep
, &len
) != 0)
2413 if (dhcp6_set_addr(DH6OPT_NISP_SERVERS
, &optinfo
->nisp_list
,
2414 &p
, optep
, &len
) != 0)
2417 if (dhcp6_set_domain(DH6OPT_NIS_DOMAIN_NAME
, &optinfo
->nisname_list
,
2418 &p
, optep
, &len
) != 0)
2421 if (dhcp6_set_domain(DH6OPT_NISP_DOMAIN_NAME
, &optinfo
->nispname_list
,
2422 &p
, optep
, &len
) != 0)
2425 if (dhcp6_set_addr(DH6OPT_NTP
, &optinfo
->ntp_list
,
2426 &p
, optep
, &len
) != 0)
2429 if (dhcp6_set_domain(DH6OPT_BCMCS_SERVER_D
, &optinfo
->bcmcsname_list
,
2430 &p
, optep
, &len
) != 0)
2433 if (dhcp6_set_addr(DH6OPT_BCMCS_SERVER_A
, &optinfo
->bcmcs_list
,
2434 &p
, optep
, &len
) != 0)
2437 for (op
= TAILQ_FIRST(&optinfo
->iapd_list
); op
;
2438 op
= TAILQ_NEXT(op
, link
)) {
2442 if ((optlen
= copyout_option(NULL
, NULL
, op
)) < 0) {
2443 dprintf(LOG_INFO
, FNAME
,
2444 "failed to count option length");
2447 if ((void *)optep
- (void *)p
< optlen
) {
2448 dprintf(LOG_INFO
, FNAME
, "short buffer");
2451 if ((tmpbuf
= malloc(optlen
)) == NULL
) {
2452 dprintf(LOG_NOTICE
, FNAME
,
2453 "memory allocation failed for IA_PD options");
2456 if (copyout_option(tmpbuf
, tmpbuf
+ optlen
, op
) < 0) {
2457 dprintf(LOG_ERR
, FNAME
,
2458 "failed to construct an IA_PD option");
2461 memcpy(p
, tmpbuf
, optlen
);
2464 p
= (struct dhcp6opt
*)((char *)p
+ optlen
);
2468 if (optinfo
->relaymsg_len
) {
2469 if (copy_option(DH6OPT_RELAY_MSG
, optinfo
->relaymsg_len
,
2470 optinfo
->relaymsg_msg
, &p
, optep
, &len
) != 0) {
2475 if (optinfo
->ifidopt_id
) {
2476 if (copy_option(DH6OPT_INTERFACE_ID
, optinfo
->ifidopt_len
,
2477 optinfo
->ifidopt_id
, &p
, optep
, &len
) != 0) {
2482 if (optinfo
->refreshtime
!= DH6OPT_REFRESHTIME_UNDEF
) {
2483 u_int32_t p32
= (u_int32_t
)optinfo
->refreshtime
;
2486 if (copy_option(DH6OPT_REFRESHTIME
, sizeof(p32
), &p32
, &p
,
2487 optep
, &len
) != 0) {
2492 if (optinfo
->authproto
!= DHCP6_AUTHPROTO_UNDEF
) {
2493 struct dhcp6opt_auth
*auth
;
2497 authlen
= sizeof(*auth
);
2498 if (!(optinfo
->authflags
& DHCP6OPT_AUTHFLAG_NOINFO
)) {
2499 switch (optinfo
->authproto
) {
2500 case DHCP6_AUTHPROTO_DELAYED
:
2501 /* Realm + key ID + HMAC-MD5 */
2502 authlen
+= optinfo
->delayedauth_realmlen
+
2503 sizeof(optinfo
->delayedauth_keyid
) + 16;
2506 case DHCP6_AUTHPROTO_RECONFIG
:
2507 /* type + key-or-HAMC */
2512 dprintf(LOG_ERR
, FNAME
,
2513 "unexpected authentication protocol");
2517 if ((auth
= malloc(authlen
)) == NULL
) {
2518 dprintf(LOG_WARNING
, FNAME
, "failed to allocate "
2519 "memory for authentication information");
2523 memset(auth
, 0, authlen
);
2524 /* copy_option will take care of type and len later */
2525 auth
->dh6_auth_proto
= (u_int8_t
)optinfo
->authproto
;
2526 auth
->dh6_auth_alg
= (u_int8_t
)optinfo
->authalgorithm
;
2527 auth
->dh6_auth_rdm
= (u_int8_t
)optinfo
->authrdm
;
2528 memcpy(auth
->dh6_auth_rdinfo
, &optinfo
->authrd
,
2529 sizeof(auth
->dh6_auth_rdinfo
));
2531 if (!(optinfo
->authflags
& DHCP6OPT_AUTHFLAG_NOINFO
)) {
2534 switch (optinfo
->authproto
) {
2535 case DHCP6_AUTHPROTO_DELAYED
:
2536 authinfo
= (char *)(auth
+ 1);
2539 memcpy(authinfo
, optinfo
->delayedauth_realmval
,
2540 optinfo
->delayedauth_realmlen
);
2541 authinfo
+= optinfo
->delayedauth_realmlen
;
2543 /* copy key ID (need memcpy for alignment) */
2544 p32
= htonl(optinfo
->delayedauth_keyid
);
2545 memcpy(authinfo
, &p32
, sizeof(p32
));
2548 * Set the offset so that the caller can
2549 * calculate the HMAC.
2551 optinfo
->delayedauth_offset
=
2552 ((char *)p
- (char *)optbp
) + authlen
- 16;
2554 dprintf(LOG_DEBUG
, FNAME
,
2555 "key ID %x, offset %d",
2556 optinfo
->delayedauth_keyid
,
2557 optinfo
->delayedauth_offset
);
2560 case DHCP6_AUTHPROTO_RECONFIG
:
2563 dprintf(LOG_ERR
, FNAME
,
2564 "unexpected authentication protocol");
2570 if (copy_option(DH6OPT_AUTH
, authlen
- 4,
2571 &auth
->dh6_auth_proto
, &p
, optep
, &len
) != 0) {
2587 dnsencode(name
, buf
, buflen
)
2595 int namelen
= strlen(name
);
2600 /* if not certain about my name, return an empty buffer */
2605 while (cp
< ep
&& p
< name
+ namelen
) {
2607 for (q
= p
; q
< name
+ namelen
&& *q
&& *q
!= '.'; q
++)
2609 /* result does not fit into buf */
2610 if (cp
+ i
+ 1 >= ep
)
2613 * DNS label length restriction, RFC1035 page 8.
2614 * "i == 0" case is included here to avoid returning
2615 * 0-length label on "foo..bar".
2617 if (i
<= 0 || i
>= 64)
2620 if (!isalpha(p
[0]) || !isalnum(p
[i
- 1]))
2623 if (!isalnum(*p
) && *p
!= '-')
2626 *cp
++ = tolower(*p
++);
2632 if (p
< name
+ namelen
&& *p
== '.')
2646 * Construct a DHCPv6 option along with sub-options in the wire format.
2647 * If the packet buffer is NULL, just calculate the length of the option
2648 * (and sub-options) so that the caller can allocate a buffer to store the
2650 * This function basically assumes that the caller prepares enough buffer to
2651 * store all the options. However, it also takes the buffer end and checks
2652 * the possibility of overrun for safety.
2655 copyout_option(p
, ep
, optval
)
2657 struct dhcp6_listval
*optval
;
2659 struct dhcp6opt
*opt
;
2660 struct dhcp6opt_stcode stcodeopt
;
2661 struct dhcp6opt_ia ia
;
2662 struct dhcp6opt_ia_pd_prefix pd_prefix
;
2663 struct dhcp6opt_ia_addr ia_addr
;
2665 struct dhcp6_listval
*subov
;
2666 int optlen
, headlen
, sublen
, opttype
;
2668 /* check invariant for safety */
2672 /* first, detect the length of the option head */
2673 switch(optval
->type
) {
2674 case DHCP6_LISTVAL_IAPD
:
2675 memset(&ia
, 0, sizeof(ia
));
2676 headlen
= sizeof(ia
);
2677 opttype
= DH6OPT_IA_PD
;
2678 opt
= (struct dhcp6opt
*)(void *)&ia
;
2680 case DHCP6_LISTVAL_IANA
:
2681 memset(&ia
, 0, sizeof(ia
));
2682 headlen
= sizeof(ia
);
2683 opttype
= DH6OPT_IA_NA
;
2684 opt
= (struct dhcp6opt
*)(void *)&ia
;
2686 case DHCP6_LISTVAL_ADDR6
:
2687 memset(&pd_prefix
, 0, sizeof(pd_prefix
));
2688 headlen
= sizeof(pd_prefix
);
2689 opttype
= DH6OPT_IA_PD_PREFIX
;
2690 opt
= (struct dhcp6opt
*)&pd_prefix
;
2692 case DHCP6_LISTVAL_PREFIX6
:
2693 memset(&pd_prefix
, 0, sizeof(pd_prefix
));
2694 headlen
= sizeof(pd_prefix
);
2695 opttype
= DH6OPT_IA_PD_PREFIX
;
2696 opt
= (struct dhcp6opt
*)&pd_prefix
;
2698 case DHCP6_LISTVAL_STATEFULADDR6
:
2699 memset(&ia_addr
, 0, sizeof(ia_addr
));
2700 headlen
= sizeof(ia_addr
);
2701 opttype
= DH6OPT_IAADDR
;
2702 opt
= (struct dhcp6opt
*)&ia_addr
;
2704 case DHCP6_LISTVAL_STCODE
:
2705 memset(&stcodeopt
, 0, sizeof(stcodeopt
));
2706 headlen
= sizeof(stcodeopt
);
2707 opttype
= DH6OPT_STATUS_CODE
;
2708 opt
= (struct dhcp6opt
*)(void *)&stcodeopt
;
2712 * we encounter an unknown option. this should be an internal
2715 dprintf(LOG_ERR
, FNAME
, "unknown option: code %d",
2720 /* then, calculate the length of and/or fill in the sub-options */
2725 for (subov
= TAILQ_FIRST(&optval
->sublist
); subov
;
2726 subov
= TAILQ_NEXT(subov
, link
)) {
2729 if ((s
= copyout_option(subp
, ep
, subov
)) < 0)
2736 /* finally, deal with the head part again */
2737 optlen
= headlen
+ sublen
;
2741 dprintf(LOG_DEBUG
, FNAME
, "set %s", dhcp6optstr(opttype
));
2742 if (ep
- p
< headlen
) /* check it just in case */
2745 /* fill in the common part */
2746 opt
->dh6opt_type
= htons(opttype
);
2747 opt
->dh6opt_len
= htons(optlen
- sizeof(struct dhcp6opt
));
2749 /* fill in type specific fields */
2750 switch(optval
->type
) {
2751 case DHCP6_LISTVAL_IAPD
:
2752 ia
.dh6_ia_iaid
= htonl(optval
->val_ia
.iaid
);
2753 ia
.dh6_ia_t1
= htonl(optval
->val_ia
.t1
);
2754 ia
.dh6_ia_t2
= htonl(optval
->val_ia
.t2
);
2756 case DHCP6_LISTVAL_IANA
:
2757 ia
.dh6_ia_iaid
= htonl(optval
->val_ia
.iaid
);
2758 ia
.dh6_ia_t1
= htonl(optval
->val_ia
.t1
);
2759 ia
.dh6_ia_t2
= htonl(optval
->val_ia
.t2
);
2761 case DHCP6_LISTVAL_PREFIX6
:
2762 pd_prefix
.dh6_iapd_prefix_preferred_time
=
2763 htonl(optval
->val_prefix6
.pltime
);
2764 pd_prefix
.dh6_iapd_prefix_valid_time
=
2765 htonl(optval
->val_prefix6
.vltime
);
2766 pd_prefix
.dh6_iapd_prefix_prefix_len
=
2767 optval
->val_prefix6
.plen
;
2768 /* XXX: prefix_addr is badly aligned, so we need memcpy */
2769 memcpy(&pd_prefix
.dh6_iapd_prefix_prefix_addr
,
2770 &optval
->val_prefix6
.addr
, sizeof(struct in6_addr
));
2772 case DHCP6_LISTVAL_STATEFULADDR6
:
2773 ia_addr
.dh6_ia_addr_preferred_time
=
2774 htonl(optval
->val_statefuladdr6
.pltime
);
2775 ia_addr
.dh6_ia_addr_valid_time
=
2776 htonl(optval
->val_statefuladdr6
.vltime
);
2777 ia_addr
.dh6_ia_addr_addr
= optval
->val_statefuladdr6
.addr
;
2779 case DHCP6_LISTVAL_STCODE
:
2780 stcodeopt
.dh6_stcode_code
= htons(optval
->val_num16
);
2784 * XXX: this case should be rejected at the beginning of this
2790 /* copyout the data (p must be non NULL at this point) */
2791 memcpy(p
, opt
, headlen
);
2796 dhcp6_set_timeoparam(ev
)
2797 struct dhcp6_event
*ev
;
2800 ev
->init_retrans
= 0;
2801 ev
->max_retrans_cnt
= 0;
2802 ev
->max_retrans_dur
= 0;
2803 ev
->max_retrans_time
= 0;
2806 case DHCP6S_SOLICIT
:
2807 ev
->init_retrans
= SOL_TIMEOUT
;
2808 ev
->max_retrans_time
= SOL_MAX_RT
;
2810 case DHCP6S_INFOREQ
:
2811 ev
->init_retrans
= INF_TIMEOUT
;
2812 ev
->max_retrans_time
= INF_MAX_RT
;
2814 case DHCP6S_REQUEST
:
2815 ev
->init_retrans
= REQ_TIMEOUT
;
2816 ev
->max_retrans_time
= REQ_MAX_RT
;
2817 ev
->max_retrans_cnt
= REQ_MAX_RC
;
2820 ev
->init_retrans
= REN_TIMEOUT
;
2821 ev
->max_retrans_time
= REN_MAX_RT
;
2824 ev
->init_retrans
= REB_TIMEOUT
;
2825 ev
->max_retrans_time
= REB_MAX_RT
;
2827 case DHCP6S_RELEASE
:
2828 ev
->init_retrans
= REL_TIMEOUT
;
2829 ev
->max_retrans_cnt
= REL_MAX_RC
;
2832 dprintf(LOG_ERR
, FNAME
, "unexpected event state %d on %s",
2833 ev
->state
, ev
->ifp
->ifname
);
2839 dhcp6_reset_timer(ev
)
2840 struct dhcp6_event
*ev
;
2844 struct timeval interval
;
2849 * The first Solicit message from the client on the interface
2850 * MUST be delayed by a random amount of time between
2851 * 0 and SOL_MAX_DELAY.
2853 * XXX: a random delay is also necessary before the first
2854 * information-request message. Fortunately, the parameters
2855 * and the algorithm for these two cases are the same.
2858 ev
->retrans
= (random() % (SOL_MAX_DELAY
));
2861 if (ev
->state
== DHCP6S_SOLICIT
&& ev
->timeouts
== 0) {
2863 * The first RT MUST be selected to be strictly
2864 * greater than IRT by choosing RAND to be strictly
2868 r
= (double)((random() % 1000) + 1) / 10000;
2869 n
= ev
->init_retrans
+ r
* ev
->init_retrans
;
2871 r
= (double)((random() % 2000) - 1000) / 10000;
2873 if (ev
->timeouts
== 0) {
2874 n
= ev
->init_retrans
+ r
* ev
->init_retrans
;
2876 n
= 2 * ev
->retrans
+ r
* ev
->retrans
;
2878 if (ev
->max_retrans_time
&& n
> ev
->max_retrans_time
)
2879 n
= ev
->max_retrans_time
+ r
* ev
->max_retrans_time
;
2880 ev
->retrans
= (long)n
;
2884 interval
.tv_sec
= (ev
->retrans
* 1000) / 1000000;
2885 interval
.tv_usec
= (ev
->retrans
* 1000) % 1000000;
2886 dhcp6_set_timer(&interval
, ev
->timer
);
2888 statestr
= dhcp6_event_statestr(ev
);
2890 dprintf(LOG_DEBUG
, FNAME
, "reset a timer on %s, "
2891 "state=%s, timeo=%d, retrans=%d",
2892 ev
->ifp
->ifname
, statestr
, ev
->timeouts
, ev
->retrans
);
2897 struct duid
*dd
, *ds
;
2899 dd
->duid_len
= ds
->duid_len
;
2900 if ((dd
->duid_id
= malloc(dd
->duid_len
)) == NULL
) {
2901 dprintf(LOG_ERR
, FNAME
, "memory allocation failed");
2904 memcpy(dd
->duid_id
, ds
->duid_id
, dd
->duid_len
);
2911 struct duid
*d1
, *d2
;
2913 if (d1
->duid_len
== d2
->duid_len
) {
2914 return (memcmp(d1
->duid_id
, d2
->duid_id
, d1
->duid_len
));
2924 free(duid
->duid_id
);
2925 duid
->duid_id
= NULL
;
2930 * Provide an NTP-format timestamp as a replay detection counter
2931 * as mentioned in RFC3315.
2933 #define JAN_1970 2208988800UL /* 1970 - 1900 in seconds */
2935 get_rdvalue(rdm
, rdvalue
, rdsize
)
2940 #if defined(HAVE_CLOCK_GETTIME)
2948 if (rdm
!= DHCP6_AUTHRDM_MONOCOUNTER
) {
2949 dprintf(LOG_INFO
, FNAME
, "unsupported RDM (%d)", rdm
);
2952 if (rdsize
!= sizeof(u_int64_t
)) {
2953 dprintf(LOG_INFO
, FNAME
, "unsupported RD size (%d)", rdsize
);
2957 #if defined(HAVE_CLOCK_GETTIME)
2958 if (clock_gettime(CLOCK_REALTIME
, &tp
)) {
2959 dprintf(LOG_WARNING
, FNAME
, "clock_gettime failed: %s",
2964 u32
= (u_int32_t
)tp
.tv_sec
;
2967 nsec
= (double)tp
.tv_nsec
/ 1e9
* 0x100000000ULL
;
2968 /* nsec should be smaller than 2^32 */
2969 l32
= (u_int32_t
)nsec
;
2971 if (gettimeofday(&tv
, NULL
) != 0) {
2972 dprintf(LOG_WARNING
, FNAME
, "gettimeofday failed: %s",
2976 u32
= (u_int32_t
)tv
.tv_sec
;
2978 l32
= (u_int32_t
)tv
.tv_usec
;
2979 #endif /* HAVE_CLOCK_GETTIME */
2984 memcpy(rdvalue
, &u32
, sizeof(u32
));
2985 memcpy((char *)rdvalue
+ sizeof(u32
), &l32
, sizeof(l32
));
2994 static char genstr
[sizeof("opt_65535") + 1]; /* XXX thread unsafe */
2997 return ("INVALID option");
3000 case DH6OPT_CLIENTID
:
3001 return ("client ID");
3002 case DH6OPT_SERVERID
:
3003 return ("server ID");
3005 return ("identity association");
3007 return ("IA for temporary");
3009 return ("IA address");
3011 return ("option request");
3012 case DH6OPT_PREFERENCE
:
3013 return ("preference");
3014 case DH6OPT_ELAPSED_TIME
:
3015 return ("elapsed time");
3016 case DH6OPT_RELAY_MSG
:
3017 return ("relay message");
3019 return ("authentication");
3020 case DH6OPT_UNICAST
:
3021 return ("server unicast");
3022 case DH6OPT_STATUS_CODE
:
3023 return ("status code");
3024 case DH6OPT_RAPID_COMMIT
:
3025 return ("rapid commit");
3026 case DH6OPT_USER_CLASS
:
3027 return ("user class");
3028 case DH6OPT_VENDOR_CLASS
:
3029 return ("vendor class");
3030 case DH6OPT_VENDOR_OPTS
:
3031 return ("vendor specific info");
3032 case DH6OPT_INTERFACE_ID
:
3033 return ("interface ID");
3034 case DH6OPT_RECONF_MSG
:
3035 return ("reconfigure message");
3036 case DH6OPT_SIP_SERVER_D
:
3037 return ("SIP domain name");
3038 case DH6OPT_SIP_SERVER_A
:
3039 return ("SIP server address");
3042 case DH6OPT_DNSNAME
:
3043 return ("domain search list");
3045 return ("NTP server");
3048 case DH6OPT_IA_PD_PREFIX
:
3049 return ("IA_PD prefix");
3050 case DH6OPT_REFRESHTIME
:
3051 return ("information refresh time");
3052 case DH6OPT_NIS_SERVERS
:
3053 return ("NIS servers");
3054 case DH6OPT_NISP_SERVERS
:
3055 return ("NIS+ servers");
3056 case DH6OPT_NIS_DOMAIN_NAME
:
3057 return ("NIS domain name");
3058 case DH6OPT_NISP_DOMAIN_NAME
:
3059 return ("NIS+ domain name");
3060 case DH6OPT_BCMCS_SERVER_D
:
3061 return ("BCMCS domain name");
3062 case DH6OPT_BCMCS_SERVER_A
:
3063 return ("BCMCS server address");
3064 case DH6OPT_GEOCONF_CIVIC
:
3065 return ("Geoconf Civic");
3066 case DH6OPT_REMOTE_ID
:
3067 return ("remote ID");
3068 case DH6OPT_SUBSCRIBER_ID
:
3069 return ("subscriber ID");
3070 case DH6OPT_CLIENT_FQDN
:
3071 return ("client FQDN");
3073 snprintf(genstr
, sizeof(genstr
), "opt_%d", type
);
3082 static char genstr
[sizeof("msg255") + 1]; /* XXX thread unsafe */
3085 return ("INVALID msg");
3091 return ("advertise");
3106 case DH6_RECONFIGURE
:
3107 return ("reconfigure");
3108 case DH6_INFORM_REQ
:
3109 return ("information request");
3110 case DH6_RELAY_FORW
:
3111 return ("relay-forward");
3112 case DH6_RELAY_REPLY
:
3113 return ("relay-reply");
3115 snprintf(genstr
, sizeof(genstr
), "msg%d", type
);
3121 dhcp6_stcodestr(code
)
3124 static char genstr
[sizeof("code255") + 1]; /* XXX thread unsafe */
3127 return ("INVALID code");
3130 case DH6OPT_STCODE_SUCCESS
:
3132 case DH6OPT_STCODE_UNSPECFAIL
:
3133 return ("unspec failure");
3134 case DH6OPT_STCODE_NOADDRSAVAIL
:
3135 return ("no addresses");
3136 case DH6OPT_STCODE_NOBINDING
:
3137 return ("no binding");
3138 case DH6OPT_STCODE_NOTONLINK
:
3139 return ("not on-link");
3140 case DH6OPT_STCODE_USEMULTICAST
:
3141 return ("use multicast");
3142 case DH6OPT_STCODE_NOPREFIXAVAIL
:
3143 return ("no prefixes");
3145 snprintf(genstr
, sizeof(genstr
), "code%d", code
);
3156 static char duidstr
[sizeof("xx:") * 128 + sizeof("...")];
3159 ep
= duidstr
+ sizeof(duidstr
);
3160 for (i
= 0; i
< duid
->duid_len
&& i
<= 128; i
++) {
3161 n
= snprintf(cp
, ep
- cp
, "%s%02x", i
== 0 ? "" : ":",
3162 duid
->duid_id
[i
] & 0xff);
3167 if (i
< duid
->duid_len
)
3168 snprintf(cp
, ep
- cp
, "%s", "...");
3173 char *dhcp6_event_statestr(ev
)
3174 struct dhcp6_event
*ev
;
3179 case DHCP6S_SOLICIT
:
3181 case DHCP6S_INFOREQ
:
3183 case DHCP6S_REQUEST
:
3189 case DHCP6S_RELEASE
:
3194 return ("???"); /* XXX */
3199 setloglevel(debuglevel
)
3203 switch(debuglevel
) {
3205 debug_thresh
= LOG_ERR
;
3208 debug_thresh
= LOG_INFO
;
3211 debug_thresh
= LOG_DEBUG
;
3215 switch(debuglevel
) {
3217 setlogmask(LOG_UPTO(LOG_ERR
));
3220 setlogmask(LOG_UPTO(LOG_INFO
));
3227 my_dprintf(int level
, const char *fname
, const char *fmt
, ...)
3230 char logbuf
[LINE_MAX
];
3234 vsnprintf(logbuf
, sizeof(logbuf
), fmt
, ap
);
3239 if (foreground
&& debug_thresh
>= level
) {
3242 const char *month
[] = {
3243 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
3244 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
3247 if ((now
= time(NULL
)) < 0)
3249 tm_now
= localtime(&now
);
3250 fprintf(stderr
, "%3s/%02d/%04d %02d:%02d:%02d: %s%s%s\n",
3251 month
[tm_now
->tm_mon
], tm_now
->tm_mday
,
3252 tm_now
->tm_year
+ 1900,
3253 tm_now
->tm_hour
, tm_now
->tm_min
, tm_now
->tm_sec
,
3254 fname
, printfname
? ": " : "",
3257 syslog(level
, "%s%s%s", fname
, printfname
? ": " : "", logbuf
);
3261 ifaddrconf(cmd
, ifname
, addr
, plen
, pltime
, vltime
)
3262 ifaddrconf_cmd_t cmd
;
3264 struct sockaddr_in6
*addr
;
3270 struct in6_aliasreq req
;
3273 struct in6_ifreq req
;
3279 unsigned long ioctl_cmd
;
3281 int s
; /* XXX overhead */
3284 case IFADDRCONF_ADD
:
3287 ioctl_cmd
= SIOCAIFADDR_IN6
;
3290 ioctl_cmd
= SIOCSIFADDR
;
3293 ioctl_cmd
= SIOCLIFADDIF
;
3296 case IFADDRCONF_REMOVE
:
3299 ioctl_cmd
= SIOCDIFADDR_IN6
;
3302 ioctl_cmd
= SIOCDIFADDR
;
3305 ioctl_cmd
= SIOCLIFREMOVEIF
;
3312 if ((s
= socket(PF_INET6
, SOCK_DGRAM
, IPPROTO_UDP
)) < 0) {
3313 dprintf(LOG_ERR
, FNAME
, "can't open a temporary socket: %s",
3318 memset(&req
, 0, sizeof(req
));
3320 req
.ifra_addr
= *addr
;
3321 memcpy(req
.ifra_name
, ifname
, sizeof(req
.ifra_name
));
3322 (void)sa6_plen2mask(&req
.ifra_prefixmask
, plen
);
3323 /* XXX: should lifetimes be calculated based on the lease duration? */
3324 req
.ifra_lifetime
.ia6t_vltime
= vltime
;
3325 req
.ifra_lifetime
.ia6t_pltime
= pltime
;
3328 memset(&ifr
, 0, sizeof(ifr
));
3329 strncpy(ifr
.ifr_name
, ifname
, IFNAMSIZ
- 1);
3330 if (ioctl(s
, SIOGIFINDEX
, &ifr
) < 0) {
3331 dprintf(LOG_NOTICE
, FNAME
, "failed to get the index of %s: %s",
3332 ifname
, strerror(errno
));
3336 memcpy(&req
.ifr6_addr
, &addr
->sin6_addr
, sizeof(struct in6_addr
));
3337 req
.ifr6_prefixlen
= plen
;
3338 req
.ifr6_ifindex
= ifr
.ifr_ifindex
;
3341 strncpy(req
.lifr_name
, ifname
, sizeof (req
.lifr_name
));
3344 if (ioctl(s
, ioctl_cmd
, &req
)) {
3345 dprintf(LOG_NOTICE
, FNAME
, "failed to %s an address on %s: %s",
3346 cmdstr
, ifname
, strerror(errno
));
3352 memcpy(&req
.lifr_addr
, addr
, sizeof (*addr
));
3353 if (ioctl(s
, SIOCSLIFADDR
, &req
) == -1) {
3354 dprintf(LOG_NOTICE
, FNAME
, "failed to %s new address on %s: %s",
3355 cmdstr
, ifname
, strerror(errno
));
3361 dprintf(LOG_DEBUG
, FNAME
, "%s an address %s/%d on %s", cmdstr
,
3362 addr2str((struct sockaddr
*)addr
), plen
, ifname
);
3376 if (getuid() != geteuid()) {
3377 dprintf(LOG_NOTICE
, FNAME
,
3378 "setuid'ed execution not allowed");
3382 if (lstat(path
, &s
) != 0) {
3383 dprintf(LOG_NOTICE
, FNAME
, "lstat failed: %s",
3388 /* the file must be owned by the running uid */
3390 if (s
.st_uid
!= myuid
) {
3391 dprintf(LOG_NOTICE
, FNAME
, "%s has invalid owner uid", path
);
3395 switch (s
.st_mode
& S_IFMT
) {
3400 dprintf(LOG_NOTICE
, FNAME
, "%s is an invalid file type 0x%o",
3401 path
, (s
.st_mode
& S_IFMT
));