xref: /dflybsd-src/sbin/ifconfig/af_inet6.c (revision 68a422abf119a92fb3d3b080f017adc079531488)
1ca74a0a2SSepherosa Ziehau /*
2ca74a0a2SSepherosa Ziehau  * Copyright (c) 1983, 1993
3ca74a0a2SSepherosa Ziehau  *	The Regents of the University of California.  All rights reserved.
4ca74a0a2SSepherosa Ziehau  *
5ca74a0a2SSepherosa Ziehau  * Redistribution and use in source and binary forms, with or without
6ca74a0a2SSepherosa Ziehau  * modification, are permitted provided that the following conditions
7ca74a0a2SSepherosa Ziehau  * are met:
8ca74a0a2SSepherosa Ziehau  * 1. Redistributions of source code must retain the above copyright
9ca74a0a2SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer.
10ca74a0a2SSepherosa Ziehau  * 2. Redistributions in binary form must reproduce the above copyright
11ca74a0a2SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer in the
12ca74a0a2SSepherosa Ziehau  *    documentation and/or other materials provided with the distribution.
13dc71b7abSJustin C. Sherrill  * 3. Neither the name of the University nor the names of its contributors
14ca74a0a2SSepherosa Ziehau  *    may be used to endorse or promote products derived from this software
15ca74a0a2SSepherosa Ziehau  *    without specific prior written permission.
16ca74a0a2SSepherosa Ziehau  *
17ca74a0a2SSepherosa Ziehau  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18ca74a0a2SSepherosa Ziehau  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19ca74a0a2SSepherosa Ziehau  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20ca74a0a2SSepherosa Ziehau  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21ca74a0a2SSepherosa Ziehau  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22ca74a0a2SSepherosa Ziehau  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23ca74a0a2SSepherosa Ziehau  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24ca74a0a2SSepherosa Ziehau  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25ca74a0a2SSepherosa Ziehau  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26ca74a0a2SSepherosa Ziehau  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27ca74a0a2SSepherosa Ziehau  * SUCH DAMAGE.
28ca74a0a2SSepherosa Ziehau  *
29ca74a0a2SSepherosa Ziehau  * $FreeBSD: src/sbin/ifconfig/af_inet6.c,v 1.3 2005/06/16 19:37:09 ume Exp $
30ca74a0a2SSepherosa Ziehau  */
31ca74a0a2SSepherosa Ziehau 
32ca74a0a2SSepherosa Ziehau #include <sys/param.h>
33ca74a0a2SSepherosa Ziehau #include <sys/ioctl.h>
34ca74a0a2SSepherosa Ziehau #include <sys/socket.h>
35ca74a0a2SSepherosa Ziehau #include <net/if.h>
3646158ff5SAaron LI #include <net/if_var.h>		/* for struct ifaddr */
3746158ff5SAaron LI #include <netinet/in.h>
3846158ff5SAaron LI #include <netinet/in_var.h>
3946158ff5SAaron LI #include <netinet6/nd6.h>	/* Define ND6_INFINITE_LIFETIME */
4046158ff5SAaron LI #include <arpa/inet.h>
4146158ff5SAaron LI #include <netdb.h>
42ca74a0a2SSepherosa Ziehau 
43ca74a0a2SSepherosa Ziehau #include <err.h>
445ecbd701SAaron LI #include <ifaddrs.h>
456dc504c3SAaron LI #include <stdbool.h>
46ca74a0a2SSepherosa Ziehau #include <stdio.h>
47ca74a0a2SSepherosa Ziehau #include <stdlib.h>
48ca74a0a2SSepherosa Ziehau #include <string.h>
4965c2d39eSSascha Wildner #include <time.h>
505ecbd701SAaron LI #include <unistd.h>
51ca74a0a2SSepherosa Ziehau 
52ca74a0a2SSepherosa Ziehau #include "ifconfig.h"
53ca74a0a2SSepherosa Ziehau 
54ca74a0a2SSepherosa Ziehau static	struct in6_ifreq in6_ridreq;
55ca74a0a2SSepherosa Ziehau static	struct in6_aliasreq in6_addreq =
56ca74a0a2SSepherosa Ziehau   { { 0 },
57ca74a0a2SSepherosa Ziehau     { 0 },
58ca74a0a2SSepherosa Ziehau     { 0 },
59ca74a0a2SSepherosa Ziehau     { 0 },
60ca74a0a2SSepherosa Ziehau     0,
61ca74a0a2SSepherosa Ziehau     { 0, 0, ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME } };
62ca74a0a2SSepherosa Ziehau static	int ip6lifetime;
63ca74a0a2SSepherosa Ziehau 
64ca74a0a2SSepherosa Ziehau static	void in6_fillscopeid(struct sockaddr_in6 *sin6);
65ca74a0a2SSepherosa Ziehau static	int prefix(void *, int);
66ca74a0a2SSepherosa Ziehau static	char *sec2str(time_t);
67ca74a0a2SSepherosa Ziehau static	int explicit_prefix = 0;
68ca74a0a2SSepherosa Ziehau 
6951a3d09eSAaron LI static 	char addr_buf[NI_MAXHOST];  /* for getnameinfo() */
70ca74a0a2SSepherosa Ziehau 
71ca74a0a2SSepherosa Ziehau static void
setifprefixlen(const char * addr,int dummy __unused,int s __unused,const struct afswtch * afp)7263f85492SAaron LI setifprefixlen(const char *addr, int dummy __unused, int s __unused,
73ca74a0a2SSepherosa Ziehau     const struct afswtch *afp)
74ca74a0a2SSepherosa Ziehau {
75ca74a0a2SSepherosa Ziehau         if (afp->af_getprefix != NULL)
76ca74a0a2SSepherosa Ziehau                 afp->af_getprefix(addr, MASK);
77ca74a0a2SSepherosa Ziehau 	explicit_prefix = 1;
78ca74a0a2SSepherosa Ziehau }
79ca74a0a2SSepherosa Ziehau 
80ca74a0a2SSepherosa Ziehau static void
setip6flags(const char * addr __unused,int flag,int s __unused,const struct afswtch * afp)8163f85492SAaron LI setip6flags(const char *addr __unused, int flag, int s __unused,
82ca74a0a2SSepherosa Ziehau     const struct afswtch *afp)
83ca74a0a2SSepherosa Ziehau {
84ca74a0a2SSepherosa Ziehau 	if (afp->af_af != AF_INET6)
85ca74a0a2SSepherosa Ziehau 		err(1, "address flags can be set only for inet6 addresses");
86ca74a0a2SSepherosa Ziehau 
87ca74a0a2SSepherosa Ziehau 	if (flag < 0)
88ca74a0a2SSepherosa Ziehau 		in6_addreq.ifra_flags &= ~(-flag);
89ca74a0a2SSepherosa Ziehau 	else
90ca74a0a2SSepherosa Ziehau 		in6_addreq.ifra_flags |= flag;
91ca74a0a2SSepherosa Ziehau }
92ca74a0a2SSepherosa Ziehau 
93ca74a0a2SSepherosa Ziehau static void
setip6lifetime(const char * cmd,const char * val,int s __unused,const struct afswtch * afp)9463f85492SAaron LI setip6lifetime(const char *cmd, const char *val, int s __unused,
95ca74a0a2SSepherosa Ziehau     const struct afswtch *afp)
96ca74a0a2SSepherosa Ziehau {
9765c2d39eSSascha Wildner 	struct timespec now;
9865c2d39eSSascha Wildner 	time_t newval;
99ca74a0a2SSepherosa Ziehau 	char *ep;
100ca74a0a2SSepherosa Ziehau 
10165c2d39eSSascha Wildner 	clock_gettime(CLOCK_MONOTONIC_FAST, &now);
102ca74a0a2SSepherosa Ziehau 	newval = (time_t)strtoul(val, &ep, 0);
103ca74a0a2SSepherosa Ziehau 	if (val == ep)
104ca74a0a2SSepherosa Ziehau 		errx(1, "invalid %s", cmd);
105ca74a0a2SSepherosa Ziehau 	if (afp->af_af != AF_INET6)
106ca74a0a2SSepherosa Ziehau 		errx(1, "%s not allowed for the AF", cmd);
107ca74a0a2SSepherosa Ziehau 	if (strcmp(cmd, "vltime") == 0) {
10865c2d39eSSascha Wildner 		in6_addreq.ifra_lifetime.ia6t_expire = now.tv_sec + newval;
109ca74a0a2SSepherosa Ziehau 		in6_addreq.ifra_lifetime.ia6t_vltime = newval;
110ca74a0a2SSepherosa Ziehau 	} else if (strcmp(cmd, "pltime") == 0) {
11165c2d39eSSascha Wildner 		in6_addreq.ifra_lifetime.ia6t_preferred = now.tv_sec + newval;
112ca74a0a2SSepherosa Ziehau 		in6_addreq.ifra_lifetime.ia6t_pltime = newval;
113ca74a0a2SSepherosa Ziehau 	}
114ca74a0a2SSepherosa Ziehau }
115ca74a0a2SSepherosa Ziehau 
116ca74a0a2SSepherosa Ziehau static void
setip6pltime(const char * seconds,int dummy __unused,int s,const struct afswtch * afp)117ca74a0a2SSepherosa Ziehau setip6pltime(const char *seconds, int dummy __unused, int s,
118ca74a0a2SSepherosa Ziehau     const struct afswtch *afp)
119ca74a0a2SSepherosa Ziehau {
120ca74a0a2SSepherosa Ziehau 	setip6lifetime("pltime", seconds, s, afp);
121ca74a0a2SSepherosa Ziehau }
122ca74a0a2SSepherosa Ziehau 
123ca74a0a2SSepherosa Ziehau static void
setip6vltime(const char * seconds,int dummy __unused,int s,const struct afswtch * afp)124ca74a0a2SSepherosa Ziehau setip6vltime(const char *seconds, int dummy __unused, int s,
125ca74a0a2SSepherosa Ziehau     const struct afswtch *afp)
126ca74a0a2SSepherosa Ziehau {
127ca74a0a2SSepherosa Ziehau 	setip6lifetime("vltime", seconds, s, afp);
128ca74a0a2SSepherosa Ziehau }
129ca74a0a2SSepherosa Ziehau 
130ca74a0a2SSepherosa Ziehau static void
setip6eui64(const char * cmd,int dummy __unused,int s __unused,const struct afswtch * afp)13163f85492SAaron LI setip6eui64(const char *cmd, int dummy __unused, int s __unused,
132ca74a0a2SSepherosa Ziehau     const struct afswtch *afp)
133ca74a0a2SSepherosa Ziehau {
134ca74a0a2SSepherosa Ziehau 	struct ifaddrs *ifap, *ifa;
135ca74a0a2SSepherosa Ziehau 	const struct sockaddr_in6 *sin6 = NULL;
136ca74a0a2SSepherosa Ziehau 	const struct in6_addr *lladdr = NULL;
137ca74a0a2SSepherosa Ziehau 	struct in6_addr *in6;
138ca74a0a2SSepherosa Ziehau 
139ca74a0a2SSepherosa Ziehau 	if (afp->af_af != AF_INET6)
140ca74a0a2SSepherosa Ziehau 		errx(EXIT_FAILURE, "%s not allowed for the AF", cmd);
141ca74a0a2SSepherosa Ziehau 	in6 = (struct in6_addr *)&in6_addreq.ifra_addr.sin6_addr;
142ca74a0a2SSepherosa Ziehau 	if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0)
143ca74a0a2SSepherosa Ziehau 		errx(EXIT_FAILURE, "interface index is already filled");
144ca74a0a2SSepherosa Ziehau 	if (getifaddrs(&ifap) != 0)
145ca74a0a2SSepherosa Ziehau 		err(EXIT_FAILURE, "getifaddrs");
146ca74a0a2SSepherosa Ziehau 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
147ca74a0a2SSepherosa Ziehau 		if (ifa->ifa_addr->sa_family == AF_INET6 &&
1487203d4e3SAaron LI 		    strcmp(ifa->ifa_name, IfName) == 0) {
149ca74a0a2SSepherosa Ziehau 			sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr;
150ca74a0a2SSepherosa Ziehau 			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
151ca74a0a2SSepherosa Ziehau 				lladdr = &sin6->sin6_addr;
152ca74a0a2SSepherosa Ziehau 				break;
153ca74a0a2SSepherosa Ziehau 			}
154ca74a0a2SSepherosa Ziehau 		}
155ca74a0a2SSepherosa Ziehau 	}
156ca74a0a2SSepherosa Ziehau 	if (!lladdr)
157ca74a0a2SSepherosa Ziehau 		errx(EXIT_FAILURE, "could not determine link local address");
158ca74a0a2SSepherosa Ziehau 
159ca74a0a2SSepherosa Ziehau 	memcpy(&in6->s6_addr[8], &lladdr->s6_addr[8], 8);
160ca74a0a2SSepherosa Ziehau 
161ca74a0a2SSepherosa Ziehau 	freeifaddrs(ifap);
162ca74a0a2SSepherosa Ziehau }
163ca74a0a2SSepherosa Ziehau 
164ca74a0a2SSepherosa Ziehau static void
in6_fillscopeid(struct sockaddr_in6 * sin6)165ca74a0a2SSepherosa Ziehau in6_fillscopeid(struct sockaddr_in6 *sin6)
166ca74a0a2SSepherosa Ziehau {
167ca74a0a2SSepherosa Ziehau #if defined(__KAME__) && defined(KAME_SCOPEID)
168ca74a0a2SSepherosa Ziehau 	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
169ca74a0a2SSepherosa Ziehau 		sin6->sin6_scope_id =
170ca74a0a2SSepherosa Ziehau 			ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
171ca74a0a2SSepherosa Ziehau 		sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
172ca74a0a2SSepherosa Ziehau 	}
17363f85492SAaron LI #else
17463f85492SAaron LI 	(void)sin6;
175ca74a0a2SSepherosa Ziehau #endif
176ca74a0a2SSepherosa Ziehau }
177ca74a0a2SSepherosa Ziehau 
178ca74a0a2SSepherosa Ziehau static void
in6_status(int s __unused,const struct ifaddrs * ifa)1795ecbd701SAaron LI in6_status(int s __unused, const struct ifaddrs *ifa)
180ca74a0a2SSepherosa Ziehau {
181ca74a0a2SSepherosa Ziehau 	struct sockaddr_in6 *sin, null_sin;
182ca74a0a2SSepherosa Ziehau 	struct in6_ifreq ifr6;
183ca74a0a2SSepherosa Ziehau 	int s6;
184ca74a0a2SSepherosa Ziehau 	u_int32_t flags6;
185ca74a0a2SSepherosa Ziehau 	struct in6_addrlifetime lifetime;
18665c2d39eSSascha Wildner 	struct timespec now;
18751a3d09eSAaron LI 	int n_flags, prefixlen;
188ca74a0a2SSepherosa Ziehau 	int error;
189ca74a0a2SSepherosa Ziehau 	u_int32_t scopeid;
190ca74a0a2SSepherosa Ziehau 
19165c2d39eSSascha Wildner 	clock_gettime(CLOCK_MONOTONIC_FAST, &now);
19265c2d39eSSascha Wildner 
193ca74a0a2SSepherosa Ziehau 	memset(&null_sin, 0, sizeof(null_sin));
194ca74a0a2SSepherosa Ziehau 
1955ecbd701SAaron LI 	sin = (struct sockaddr_in6 *)ifa->ifa_addr;
196ca74a0a2SSepherosa Ziehau 	if (sin == NULL)
197ca74a0a2SSepherosa Ziehau 		return;
198ca74a0a2SSepherosa Ziehau 
1997203d4e3SAaron LI 	strlcpy(ifr6.ifr_name, IfName, sizeof(ifr6.ifr_name));
200ca74a0a2SSepherosa Ziehau 	if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
201ca74a0a2SSepherosa Ziehau 		warn("socket(AF_INET6,SOCK_DGRAM)");
202ca74a0a2SSepherosa Ziehau 		return;
203ca74a0a2SSepherosa Ziehau 	}
204ca74a0a2SSepherosa Ziehau 	ifr6.ifr_addr = *sin;
205ca74a0a2SSepherosa Ziehau 	if (ioctl(s6, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
206ca74a0a2SSepherosa Ziehau 		warn("ioctl(SIOCGIFAFLAG_IN6)");
207ca74a0a2SSepherosa Ziehau 		close(s6);
208ca74a0a2SSepherosa Ziehau 		return;
209ca74a0a2SSepherosa Ziehau 	}
210ca74a0a2SSepherosa Ziehau 	flags6 = ifr6.ifr_ifru.ifru_flags6;
211ca74a0a2SSepherosa Ziehau 	memset(&lifetime, 0, sizeof(lifetime));
212ca74a0a2SSepherosa Ziehau 	ifr6.ifr_addr = *sin;
213ca74a0a2SSepherosa Ziehau 	if (ioctl(s6, SIOCGIFALIFETIME_IN6, &ifr6) < 0) {
214ca74a0a2SSepherosa Ziehau 		warn("ioctl(SIOCGIFALIFETIME_IN6)");
215ca74a0a2SSepherosa Ziehau 		close(s6);
216ca74a0a2SSepherosa Ziehau 		return;
217ca74a0a2SSepherosa Ziehau 	}
218ca74a0a2SSepherosa Ziehau 	lifetime = ifr6.ifr_ifru.ifru_lifetime;
219ca74a0a2SSepherosa Ziehau 	close(s6);
220ca74a0a2SSepherosa Ziehau 
221ca74a0a2SSepherosa Ziehau 	/* XXX: embedded link local addr check */
222ca74a0a2SSepherosa Ziehau 	if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) &&
223ca74a0a2SSepherosa Ziehau 	    *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) {
224ca74a0a2SSepherosa Ziehau 		u_short index;
225ca74a0a2SSepherosa Ziehau 
226ca74a0a2SSepherosa Ziehau 		index = *(u_short *)&sin->sin6_addr.s6_addr[2];
227ca74a0a2SSepherosa Ziehau 		*(u_short *)&sin->sin6_addr.s6_addr[2] = 0;
228ca74a0a2SSepherosa Ziehau 		if (sin->sin6_scope_id == 0)
229ca74a0a2SSepherosa Ziehau 			sin->sin6_scope_id = ntohs(index);
230ca74a0a2SSepherosa Ziehau 	}
231ca74a0a2SSepherosa Ziehau 	scopeid = sin->sin6_scope_id;
232ca74a0a2SSepherosa Ziehau 
23351a3d09eSAaron LI 	if (f_addr != NULL && strcmp(f_addr, "fqdn") == 0)
23451a3d09eSAaron LI 		n_flags = 0;
23551a3d09eSAaron LI 	else if (f_addr != NULL && strcmp(f_addr, "host") == 0)
23651a3d09eSAaron LI 		n_flags = NI_NOFQDN;
23751a3d09eSAaron LI 	else
23851a3d09eSAaron LI 		n_flags = NI_NUMERICHOST;
23951a3d09eSAaron LI 
240ca74a0a2SSepherosa Ziehau 	error = getnameinfo((struct sockaddr *)sin, sin->sin6_len, addr_buf,
24151a3d09eSAaron LI 			    sizeof(addr_buf), NULL, 0, n_flags);
242ca74a0a2SSepherosa Ziehau 	if (error != 0)
243ca74a0a2SSepherosa Ziehau 		inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf,
244ca74a0a2SSepherosa Ziehau 			  sizeof(addr_buf));
245ca74a0a2SSepherosa Ziehau 	printf("\tinet6 %s", addr_buf);
246ca74a0a2SSepherosa Ziehau 
2475ecbd701SAaron LI 	if (ifa->ifa_flags & IFF_POINTOPOINT) {
2485ecbd701SAaron LI 		sin = (struct sockaddr_in6 *)ifa->ifa_dstaddr;
249ca74a0a2SSepherosa Ziehau 		/*
250ca74a0a2SSepherosa Ziehau 		 * some of the interfaces do not have valid destination
251ca74a0a2SSepherosa Ziehau 		 * address.
252ca74a0a2SSepherosa Ziehau 		 */
2535ecbd701SAaron LI 		if (sin != NULL && sin->sin6_family == AF_INET6) {
254ca74a0a2SSepherosa Ziehau 			/* XXX: embedded link local addr check */
255ca74a0a2SSepherosa Ziehau 			if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) &&
256ca74a0a2SSepherosa Ziehau 			    *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) {
257ca74a0a2SSepherosa Ziehau 				u_short index;
258ca74a0a2SSepherosa Ziehau 
259ca74a0a2SSepherosa Ziehau 				index = *(u_short *)&sin->sin6_addr.s6_addr[2];
260ca74a0a2SSepherosa Ziehau 				*(u_short *)&sin->sin6_addr.s6_addr[2] = 0;
261ca74a0a2SSepherosa Ziehau 				if (sin->sin6_scope_id == 0)
262ca74a0a2SSepherosa Ziehau 					sin->sin6_scope_id = ntohs(index);
263ca74a0a2SSepherosa Ziehau 			}
264ca74a0a2SSepherosa Ziehau 
265ca74a0a2SSepherosa Ziehau 			error = getnameinfo((struct sockaddr *)sin,
266ca74a0a2SSepherosa Ziehau 					    sin->sin6_len, addr_buf,
267ca74a0a2SSepherosa Ziehau 					    sizeof(addr_buf), NULL, 0,
268ca74a0a2SSepherosa Ziehau 					    NI_NUMERICHOST);
269ca74a0a2SSepherosa Ziehau 			if (error != 0)
270ca74a0a2SSepherosa Ziehau 				inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf,
271ca74a0a2SSepherosa Ziehau 					  sizeof(addr_buf));
272ca74a0a2SSepherosa Ziehau 			printf(" --> %s", addr_buf);
273ca74a0a2SSepherosa Ziehau 		}
274ca74a0a2SSepherosa Ziehau 	}
275ca74a0a2SSepherosa Ziehau 
2765ecbd701SAaron LI 	sin = (struct sockaddr_in6 *)ifa->ifa_netmask;
2775ecbd701SAaron LI 	if (sin == NULL)
278ca74a0a2SSepherosa Ziehau 		sin = &null_sin;
27951a3d09eSAaron LI 	prefixlen = prefix(&sin->sin6_addr, sizeof(struct in6_addr));
28051a3d09eSAaron LI 	if (f_inet6 != NULL && strcmp(f_inet6, "cidr") == 0)
28151a3d09eSAaron LI 		printf("/%d", prefixlen);
28251a3d09eSAaron LI 	else
28351a3d09eSAaron LI 		printf(" prefixlen %d", prefixlen);
284ca74a0a2SSepherosa Ziehau 
285ca74a0a2SSepherosa Ziehau 	if ((flags6 & IN6_IFF_ANYCAST) != 0)
286ca74a0a2SSepherosa Ziehau 		printf(" anycast");
287ca74a0a2SSepherosa Ziehau 	if ((flags6 & IN6_IFF_TENTATIVE) != 0)
288ca74a0a2SSepherosa Ziehau 		printf(" tentative");
289ca74a0a2SSepherosa Ziehau 	if ((flags6 & IN6_IFF_DUPLICATED) != 0)
290ca74a0a2SSepherosa Ziehau 		printf(" duplicated");
291ca74a0a2SSepherosa Ziehau 	if ((flags6 & IN6_IFF_DETACHED) != 0)
292ca74a0a2SSepherosa Ziehau 		printf(" detached");
293ca74a0a2SSepherosa Ziehau 	if ((flags6 & IN6_IFF_DEPRECATED) != 0)
294ca74a0a2SSepherosa Ziehau 		printf(" deprecated");
295ca74a0a2SSepherosa Ziehau 	if ((flags6 & IN6_IFF_AUTOCONF) != 0)
296ca74a0a2SSepherosa Ziehau 		printf(" autoconf");
297ca74a0a2SSepherosa Ziehau 	if ((flags6 & IN6_IFF_TEMPORARY) != 0)
298ca74a0a2SSepherosa Ziehau 		printf(" temporary");
299ca74a0a2SSepherosa Ziehau 
300ca74a0a2SSepherosa Ziehau         if (scopeid)
301ca74a0a2SSepherosa Ziehau 		printf(" scopeid 0x%x", scopeid);
302ca74a0a2SSepherosa Ziehau 
303ca74a0a2SSepherosa Ziehau 	if (ip6lifetime && (lifetime.ia6t_preferred || lifetime.ia6t_expire)) {
304ca74a0a2SSepherosa Ziehau 		printf(" pltime");
305ca74a0a2SSepherosa Ziehau 		if (lifetime.ia6t_preferred) {
30665c2d39eSSascha Wildner 			printf(" %s", lifetime.ia6t_preferred < now.tv_sec
30765c2d39eSSascha Wildner 				? "0" : sec2str(lifetime.ia6t_preferred - now.tv_sec));
308a143db09SAaron LI 		} else {
309ca74a0a2SSepherosa Ziehau 			printf(" infty");
310a143db09SAaron LI 		}
311ca74a0a2SSepherosa Ziehau 
312ca74a0a2SSepherosa Ziehau 		printf(" vltime");
313ca74a0a2SSepherosa Ziehau 		if (lifetime.ia6t_expire) {
31465c2d39eSSascha Wildner 			printf(" %s", lifetime.ia6t_expire < now.tv_sec
31565c2d39eSSascha Wildner 				? "0" : sec2str(lifetime.ia6t_expire - now.tv_sec));
316a143db09SAaron LI 		} else {
317ca74a0a2SSepherosa Ziehau 			printf(" infty");
318ca74a0a2SSepherosa Ziehau 		}
319a143db09SAaron LI 	}
320ca74a0a2SSepherosa Ziehau 
321ca74a0a2SSepherosa Ziehau 	putchar('\n');
322ca74a0a2SSepherosa Ziehau }
323ca74a0a2SSepherosa Ziehau 
324ca74a0a2SSepherosa Ziehau #define	SIN6(x) ((struct sockaddr_in6 *) &(x))
325ca74a0a2SSepherosa Ziehau static struct	sockaddr_in6 *sin6tab[] = {
326ca74a0a2SSepherosa Ziehau 	SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr),
327ca74a0a2SSepherosa Ziehau 	SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)
328ca74a0a2SSepherosa Ziehau };
329ca74a0a2SSepherosa Ziehau 
330ca74a0a2SSepherosa Ziehau static void
in6_getprefix(const char * plen,int which)331ca74a0a2SSepherosa Ziehau in6_getprefix(const char *plen, int which)
332ca74a0a2SSepherosa Ziehau {
333ca74a0a2SSepherosa Ziehau 	struct sockaddr_in6 *sin = sin6tab[which];
334ca74a0a2SSepherosa Ziehau 	u_char *cp;
335ca74a0a2SSepherosa Ziehau 	int len = atoi(plen);
336ca74a0a2SSepherosa Ziehau 
337ca74a0a2SSepherosa Ziehau 	if ((len < 0) || (len > 128))
338ca74a0a2SSepherosa Ziehau 		errx(1, "%s: bad value", plen);
339ca74a0a2SSepherosa Ziehau 	sin->sin6_len = sizeof(*sin);
340ca74a0a2SSepherosa Ziehau 	if (which != MASK)
341ca74a0a2SSepherosa Ziehau 		sin->sin6_family = AF_INET6;
342ca74a0a2SSepherosa Ziehau 	if ((len == 0) || (len == 128)) {
343ca74a0a2SSepherosa Ziehau 		memset(&sin->sin6_addr, 0xff, sizeof(struct in6_addr));
344ca74a0a2SSepherosa Ziehau 		return;
345ca74a0a2SSepherosa Ziehau 	}
346*68a422abSAaron LI 	memset(&sin->sin6_addr, 0x00, sizeof(sin->sin6_addr));
347ca74a0a2SSepherosa Ziehau 	for (cp = (u_char *)&sin->sin6_addr; len > 7; len -= 8)
348ca74a0a2SSepherosa Ziehau 		*cp++ = 0xff;
349ca74a0a2SSepherosa Ziehau 	*cp = 0xff << (8 - len);
350ca74a0a2SSepherosa Ziehau }
351ca74a0a2SSepherosa Ziehau 
352ca74a0a2SSepherosa Ziehau static void
in6_getaddr(const char * s,int which)353ca74a0a2SSepherosa Ziehau in6_getaddr(const char *s, int which)
354ca74a0a2SSepherosa Ziehau {
355ca74a0a2SSepherosa Ziehau 	struct sockaddr_in6 *sin = sin6tab[which];
356ca74a0a2SSepherosa Ziehau 	struct addrinfo hints, *res;
357ca74a0a2SSepherosa Ziehau 	int error = -1;
358ca74a0a2SSepherosa Ziehau 
3596dc504c3SAaron LI 	newaddr = true;
360ca74a0a2SSepherosa Ziehau 
361ca74a0a2SSepherosa Ziehau 	sin->sin6_len = sizeof(*sin);
362ca74a0a2SSepherosa Ziehau 	if (which != MASK)
363ca74a0a2SSepherosa Ziehau 		sin->sin6_family = AF_INET6;
364ca74a0a2SSepherosa Ziehau 
365ca74a0a2SSepherosa Ziehau 	if (which == ADDR) {
366ca74a0a2SSepherosa Ziehau 		char *p = NULL;
367ca74a0a2SSepherosa Ziehau 		if((p = strrchr(s, '/')) != NULL) {
368ca74a0a2SSepherosa Ziehau 			*p = '\0';
369ca74a0a2SSepherosa Ziehau 			in6_getprefix(p + 1, MASK);
370ca74a0a2SSepherosa Ziehau 			explicit_prefix = 1;
371ca74a0a2SSepherosa Ziehau 		}
372ca74a0a2SSepherosa Ziehau 	}
373ca74a0a2SSepherosa Ziehau 
374ca74a0a2SSepherosa Ziehau 	if (sin->sin6_family == AF_INET6) {
3750989c651SAaron LI 		memset(&hints, 0, sizeof(struct addrinfo));
376ca74a0a2SSepherosa Ziehau 		hints.ai_family = AF_INET6;
377ca74a0a2SSepherosa Ziehau 		error = getaddrinfo(s, NULL, &hints, &res);
378ca74a0a2SSepherosa Ziehau 	}
379ca74a0a2SSepherosa Ziehau 	if (error != 0) {
380ca74a0a2SSepherosa Ziehau 		if (inet_pton(AF_INET6, s, &sin->sin6_addr) != 1)
381ca74a0a2SSepherosa Ziehau 			errx(1, "%s: bad value", s);
382ca74a0a2SSepherosa Ziehau 	} else
3830989c651SAaron LI 		memcpy(sin, res->ai_addr, res->ai_addrlen);
384ca74a0a2SSepherosa Ziehau }
385ca74a0a2SSepherosa Ziehau 
386ca74a0a2SSepherosa Ziehau static int
prefix(void * val,int size)387ca74a0a2SSepherosa Ziehau prefix(void *val, int size)
388ca74a0a2SSepherosa Ziehau {
389ca74a0a2SSepherosa Ziehau         u_char *name = (u_char *)val;
390ca74a0a2SSepherosa Ziehau         int byte, bit, plen = 0;
391ca74a0a2SSepherosa Ziehau 
392ca74a0a2SSepherosa Ziehau         for (byte = 0; byte < size; byte++, plen += 8)
393ca74a0a2SSepherosa Ziehau                 if (name[byte] != 0xff)
394ca74a0a2SSepherosa Ziehau                         break;
395ca74a0a2SSepherosa Ziehau 	if (byte == size)
396ca74a0a2SSepherosa Ziehau 		return (plen);
397ca74a0a2SSepherosa Ziehau 	for (bit = 7; bit != 0; bit--, plen++)
398ca74a0a2SSepherosa Ziehau                 if (!(name[byte] & (1 << bit)))
399ca74a0a2SSepherosa Ziehau                         break;
400ca74a0a2SSepherosa Ziehau         for (; bit != 0; bit--)
401ca74a0a2SSepherosa Ziehau                 if (name[byte] & (1 << bit))
402ca74a0a2SSepherosa Ziehau                         return(0);
403ca74a0a2SSepherosa Ziehau         byte++;
404ca74a0a2SSepherosa Ziehau         for (; byte < size; byte++)
405ca74a0a2SSepherosa Ziehau                 if (name[byte])
406ca74a0a2SSepherosa Ziehau                         return(0);
407ca74a0a2SSepherosa Ziehau         return (plen);
408ca74a0a2SSepherosa Ziehau }
409ca74a0a2SSepherosa Ziehau 
410ca74a0a2SSepherosa Ziehau static char *
sec2str(time_t total)411ca74a0a2SSepherosa Ziehau sec2str(time_t total)
412ca74a0a2SSepherosa Ziehau {
413ca74a0a2SSepherosa Ziehau 	static char result[256];
414ca74a0a2SSepherosa Ziehau 	int days, hours, mins, secs;
415ca74a0a2SSepherosa Ziehau 	int first = 1;
416ca74a0a2SSepherosa Ziehau 	char *p = result;
417ca74a0a2SSepherosa Ziehau 
418ca74a0a2SSepherosa Ziehau 	if (0) {
419ca74a0a2SSepherosa Ziehau 		days = total / 3600 / 24;
420ca74a0a2SSepherosa Ziehau 		hours = (total / 3600) % 24;
421ca74a0a2SSepherosa Ziehau 		mins = (total / 60) % 60;
422ca74a0a2SSepherosa Ziehau 		secs = total % 60;
423ca74a0a2SSepherosa Ziehau 
424ca74a0a2SSepherosa Ziehau 		if (days) {
425ca74a0a2SSepherosa Ziehau 			first = 0;
426ca74a0a2SSepherosa Ziehau 			p += sprintf(p, "%dd", days);
427ca74a0a2SSepherosa Ziehau 		}
428ca74a0a2SSepherosa Ziehau 		if (!first || hours) {
429ca74a0a2SSepherosa Ziehau 			first = 0;
430ca74a0a2SSepherosa Ziehau 			p += sprintf(p, "%dh", hours);
431ca74a0a2SSepherosa Ziehau 		}
432ca74a0a2SSepherosa Ziehau 		if (!first || mins) {
433ca74a0a2SSepherosa Ziehau 			first = 0;
434ca74a0a2SSepherosa Ziehau 			p += sprintf(p, "%dm", mins);
435ca74a0a2SSepherosa Ziehau 		}
436ca74a0a2SSepherosa Ziehau 		sprintf(p, "%ds", secs);
437ca74a0a2SSepherosa Ziehau 	} else
438ca74a0a2SSepherosa Ziehau 		sprintf(result, "%lu", (unsigned long)total);
439ca74a0a2SSepherosa Ziehau 
440ca74a0a2SSepherosa Ziehau 	return(result);
441ca74a0a2SSepherosa Ziehau }
442ca74a0a2SSepherosa Ziehau 
443ca74a0a2SSepherosa Ziehau static void
in6_postproc(int s,const struct afswtch * afp)444ca74a0a2SSepherosa Ziehau in6_postproc(int s, const struct afswtch *afp)
445ca74a0a2SSepherosa Ziehau {
446ca74a0a2SSepherosa Ziehau 	if (explicit_prefix == 0) {
447ca74a0a2SSepherosa Ziehau 		/* Aggregatable address architecture defines all prefixes
448ca74a0a2SSepherosa Ziehau 		   are 64. So, it is convenient to set prefixlen to 64 if
449ca74a0a2SSepherosa Ziehau 		   it is not specified. */
450ca74a0a2SSepherosa Ziehau 		setifprefixlen("64", 0, s, afp);
451ca74a0a2SSepherosa Ziehau 		/* in6_getprefix("64", MASK) if MASK is available here... */
452ca74a0a2SSepherosa Ziehau 	}
453ca74a0a2SSepherosa Ziehau }
454ca74a0a2SSepherosa Ziehau 
455ca74a0a2SSepherosa Ziehau static void
in6_status_tunnel(int s)456ca74a0a2SSepherosa Ziehau in6_status_tunnel(int s)
457ca74a0a2SSepherosa Ziehau {
458ca74a0a2SSepherosa Ziehau 	char src[NI_MAXHOST];
459ca74a0a2SSepherosa Ziehau 	char dst[NI_MAXHOST];
460ca74a0a2SSepherosa Ziehau 	struct in6_ifreq in6_ifr;
461ca74a0a2SSepherosa Ziehau 	const struct sockaddr *sa = (const struct sockaddr *) &in6_ifr.ifr_addr;
462ca74a0a2SSepherosa Ziehau 
463ca74a0a2SSepherosa Ziehau 	memset(&in6_ifr, 0, sizeof(in6_ifr));
4647203d4e3SAaron LI 	strlcpy(in6_ifr.ifr_name, IfName, sizeof(in6_ifr.ifr_name));
465ca74a0a2SSepherosa Ziehau 
4660b22c3cfSAaron LI 	if (ioctl(s, SIOCGIFPSRCADDR_IN6, &in6_ifr) < 0)
467ca74a0a2SSepherosa Ziehau 		return;
468ca74a0a2SSepherosa Ziehau 	if (sa->sa_family != AF_INET6)
469ca74a0a2SSepherosa Ziehau 		return;
470ca74a0a2SSepherosa Ziehau 	in6_fillscopeid(&in6_ifr.ifr_addr);
471ca74a0a2SSepherosa Ziehau 	if (getnameinfo(sa, sa->sa_len, src, sizeof(src), 0, 0,
472ca74a0a2SSepherosa Ziehau 	    NI_NUMERICHOST) != 0)
473ca74a0a2SSepherosa Ziehau 		src[0] = '\0';
474ca74a0a2SSepherosa Ziehau 
4750b22c3cfSAaron LI 	if (ioctl(s, SIOCGIFPDSTADDR_IN6, &in6_ifr) < 0)
476ca74a0a2SSepherosa Ziehau 		return;
477ca74a0a2SSepherosa Ziehau 	if (sa->sa_family != AF_INET6)
478ca74a0a2SSepherosa Ziehau 		return;
479ca74a0a2SSepherosa Ziehau 	in6_fillscopeid(&in6_ifr.ifr_addr);
480ca74a0a2SSepherosa Ziehau 	if (getnameinfo(sa, sa->sa_len, dst, sizeof(dst), 0, 0,
481ca74a0a2SSepherosa Ziehau 	    NI_NUMERICHOST) != 0)
482ca74a0a2SSepherosa Ziehau 		dst[0] = '\0';
483ca74a0a2SSepherosa Ziehau 
484ca74a0a2SSepherosa Ziehau 	printf("\ttunnel inet6 %s --> %s\n", src, dst);
485ca74a0a2SSepherosa Ziehau }
486ca74a0a2SSepherosa Ziehau 
487ca74a0a2SSepherosa Ziehau static void
in6_set_tunnel(int s,struct addrinfo * srcres,struct addrinfo * dstres)488ca74a0a2SSepherosa Ziehau in6_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres)
489ca74a0a2SSepherosa Ziehau {
49018983bb4SAaron LI 	struct in6_aliasreq addreq;
491ca74a0a2SSepherosa Ziehau 
49218983bb4SAaron LI 	memset(&addreq, 0, sizeof(addreq));
4937203d4e3SAaron LI 	strlcpy(addreq.ifra_name, IfName, sizeof(addreq.ifra_name));
49418983bb4SAaron LI 	memcpy(&addreq.ifra_addr, srcres->ai_addr, srcres->ai_addr->sa_len);
49518983bb4SAaron LI 	memcpy(&addreq.ifra_dstaddr, dstres->ai_addr, dstres->ai_addr->sa_len);
496ca74a0a2SSepherosa Ziehau 
49718983bb4SAaron LI 	if (ioctl(s, SIOCSIFPHYADDR_IN6, &addreq) < 0)
498ca74a0a2SSepherosa Ziehau 		warn("SIOCSIFPHYADDR_IN6");
499ca74a0a2SSepherosa Ziehau }
500ca74a0a2SSepherosa Ziehau 
501ca74a0a2SSepherosa Ziehau static struct cmd inet6_cmds[] = {
502ca74a0a2SSepherosa Ziehau 	DEF_CMD_ARG("prefixlen",			setifprefixlen),
503ca74a0a2SSepherosa Ziehau 	DEF_CMD("anycast",	IN6_IFF_ANYCAST,	setip6flags),
504ca74a0a2SSepherosa Ziehau 	DEF_CMD("tentative",	IN6_IFF_TENTATIVE,	setip6flags),
505ca74a0a2SSepherosa Ziehau 	DEF_CMD("-tentative",	-IN6_IFF_TENTATIVE,	setip6flags),
506ca74a0a2SSepherosa Ziehau 	DEF_CMD("deprecated",	IN6_IFF_DEPRECATED,	setip6flags),
507ca74a0a2SSepherosa Ziehau 	DEF_CMD("-deprecated", -IN6_IFF_DEPRECATED,	setip6flags),
508ca74a0a2SSepherosa Ziehau 	DEF_CMD("autoconf",	IN6_IFF_AUTOCONF,	setip6flags),
509ca74a0a2SSepherosa Ziehau 	DEF_CMD("-autoconf",	-IN6_IFF_AUTOCONF,	setip6flags),
510ca74a0a2SSepherosa Ziehau 	DEF_CMD_ARG("pltime",				setip6pltime),
511ca74a0a2SSepherosa Ziehau 	DEF_CMD_ARG("vltime",				setip6vltime),
512ca74a0a2SSepherosa Ziehau 	DEF_CMD("eui64",	0,			setip6eui64),
513ca74a0a2SSepherosa Ziehau };
514ca74a0a2SSepherosa Ziehau 
515ca74a0a2SSepherosa Ziehau static struct afswtch af_inet6 = {
516ca74a0a2SSepherosa Ziehau 	.af_name	= "inet6",
517ca74a0a2SSepherosa Ziehau 	.af_af		= AF_INET6,
518ca74a0a2SSepherosa Ziehau 	.af_status	= in6_status,
519ca74a0a2SSepherosa Ziehau 	.af_getaddr	= in6_getaddr,
520ca74a0a2SSepherosa Ziehau 	.af_getprefix	= in6_getprefix,
521ca74a0a2SSepherosa Ziehau 	.af_postproc	= in6_postproc,
522ca74a0a2SSepherosa Ziehau 	.af_status_tunnel = in6_status_tunnel,
523ca74a0a2SSepherosa Ziehau 	.af_settunnel	= in6_set_tunnel,
524ca74a0a2SSepherosa Ziehau 	.af_difaddr	= SIOCDIFADDR_IN6,
525ca74a0a2SSepherosa Ziehau 	.af_aifaddr	= SIOCAIFADDR_IN6,
526dd1649aaSSepherosa Ziehau 	.af_ridreq	= &in6_ridreq,
527ca74a0a2SSepherosa Ziehau 	.af_addreq	= &in6_addreq,
528ca74a0a2SSepherosa Ziehau };
529ca74a0a2SSepherosa Ziehau 
530ca74a0a2SSepherosa Ziehau static void
in6_Lopt_cb(const char * arg __unused)53118983bb4SAaron LI in6_Lopt_cb(const char *arg __unused)
532ca74a0a2SSepherosa Ziehau {
533ca74a0a2SSepherosa Ziehau 	ip6lifetime++;	/* print IPv6 address lifetime */
534ca74a0a2SSepherosa Ziehau }
53546158ff5SAaron LI static struct option in6_Lopt = { "L", "[-L]", in6_Lopt_cb, NULL };
536ca74a0a2SSepherosa Ziehau 
537ec7e0eebSAaron LI __constructor(113)
538ec7e0eebSAaron LI static void
inet6_ctor(void)539ca74a0a2SSepherosa Ziehau inet6_ctor(void)
540ca74a0a2SSepherosa Ziehau {
54146158ff5SAaron LI 	size_t i;
542ca74a0a2SSepherosa Ziehau 
543b6b91ec7SAaron LI 	for (i = 0; i < nitems(inet6_cmds);  i++)
544ca74a0a2SSepherosa Ziehau 		cmd_register(&inet6_cmds[i]);
54593b0f758SAaron LI 
546ca74a0a2SSepherosa Ziehau 	af_register(&af_inet6);
547ca74a0a2SSepherosa Ziehau 	opt_register(&in6_Lopt);
548ca74a0a2SSepherosa Ziehau }
549