xref: /freebsd/sbin/ifconfig/af_inet6.c (revision e7fa8d0ada7547ca92a905aa9f683ea66c750c88)
15faf8dcbSSam Leffler /*
25faf8dcbSSam Leffler  * Copyright (c) 1983, 1993
35faf8dcbSSam Leffler  *	The Regents of the University of California.  All rights reserved.
45faf8dcbSSam Leffler  *
55faf8dcbSSam Leffler  * Redistribution and use in source and binary forms, with or without
65faf8dcbSSam Leffler  * modification, are permitted provided that the following conditions
75faf8dcbSSam Leffler  * are met:
85faf8dcbSSam Leffler  * 1. Redistributions of source code must retain the above copyright
95faf8dcbSSam Leffler  *    notice, this list of conditions and the following disclaimer.
105faf8dcbSSam Leffler  * 2. Redistributions in binary form must reproduce the above copyright
115faf8dcbSSam Leffler  *    notice, this list of conditions and the following disclaimer in the
125faf8dcbSSam Leffler  *    documentation and/or other materials provided with the distribution.
135faf8dcbSSam Leffler  * 4. Neither the name of the University nor the names of its contributors
145faf8dcbSSam Leffler  *    may be used to endorse or promote products derived from this software
155faf8dcbSSam Leffler  *    without specific prior written permission.
165faf8dcbSSam Leffler  *
175faf8dcbSSam Leffler  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
185faf8dcbSSam Leffler  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
195faf8dcbSSam Leffler  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
205faf8dcbSSam Leffler  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
215faf8dcbSSam Leffler  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
225faf8dcbSSam Leffler  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
235faf8dcbSSam Leffler  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
245faf8dcbSSam Leffler  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
255faf8dcbSSam Leffler  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
265faf8dcbSSam Leffler  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
275faf8dcbSSam Leffler  * SUCH DAMAGE.
285faf8dcbSSam Leffler  */
295faf8dcbSSam Leffler 
305faf8dcbSSam Leffler #ifndef lint
315faf8dcbSSam Leffler static const char rcsid[] =
325faf8dcbSSam Leffler   "$FreeBSD$";
335faf8dcbSSam Leffler #endif /* not lint */
345faf8dcbSSam Leffler 
355faf8dcbSSam Leffler #include <sys/param.h>
365faf8dcbSSam Leffler #include <sys/ioctl.h>
375faf8dcbSSam Leffler #include <sys/socket.h>
385faf8dcbSSam Leffler #include <net/if.h>
395faf8dcbSSam Leffler 
405faf8dcbSSam Leffler #include <err.h>
415faf8dcbSSam Leffler #include <stdio.h>
425faf8dcbSSam Leffler #include <stdlib.h>
435faf8dcbSSam Leffler #include <string.h>
445faf8dcbSSam Leffler #include <unistd.h>
455faf8dcbSSam Leffler #include <ifaddrs.h>
465faf8dcbSSam Leffler 
475faf8dcbSSam Leffler #include <arpa/inet.h>
485faf8dcbSSam Leffler 
495faf8dcbSSam Leffler #include <netinet/in.h>
505faf8dcbSSam Leffler #include <net/if_var.h>		/* for struct ifaddr */
515faf8dcbSSam Leffler #include <netinet/in_var.h>
525faf8dcbSSam Leffler #include <arpa/inet.h>
535faf8dcbSSam Leffler #include <netdb.h>
545faf8dcbSSam Leffler 
555faf8dcbSSam Leffler #include <netinet6/nd6.h>	/* Define ND6_INFINITE_LIFETIME */
565faf8dcbSSam Leffler 
575faf8dcbSSam Leffler #include "ifconfig.h"
585faf8dcbSSam Leffler 
595faf8dcbSSam Leffler static	struct in6_ifreq in6_ridreq;
605faf8dcbSSam Leffler static	struct in6_aliasreq in6_addreq =
61b59dcaeeSXin LI   { .ifra_flags = 0,
62b59dcaeeSXin LI     .ifra_lifetime = { 0, 0, ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME } };
635faf8dcbSSam Leffler static	int ip6lifetime;
645faf8dcbSSam Leffler 
655faf8dcbSSam Leffler static	void in6_fillscopeid(struct sockaddr_in6 *sin6);
665faf8dcbSSam Leffler static	int prefix(void *, int);
675faf8dcbSSam Leffler static	char *sec2str(time_t);
685faf8dcbSSam Leffler static	int explicit_prefix = 0;
695faf8dcbSSam Leffler 
70a283298cSHiroki Sato extern void setnd6flags(const char *, int, int, const struct afswtch *);
71a283298cSHiroki Sato extern void setnd6defif(const char *, int, int, const struct afswtch *);
72c3cc3217SHiroki Sato extern void nd6_status(int);
73a283298cSHiroki Sato 
745faf8dcbSSam Leffler static	char addr_buf[MAXHOSTNAMELEN *2 + 1];	/*for getnameinfo()*/
755faf8dcbSSam Leffler 
765faf8dcbSSam Leffler static void
775faf8dcbSSam Leffler setifprefixlen(const char *addr, int dummy __unused, int s,
785faf8dcbSSam Leffler     const struct afswtch *afp)
795faf8dcbSSam Leffler {
805faf8dcbSSam Leffler         if (afp->af_getprefix != NULL)
815faf8dcbSSam Leffler                 afp->af_getprefix(addr, MASK);
825faf8dcbSSam Leffler 	explicit_prefix = 1;
835faf8dcbSSam Leffler }
845faf8dcbSSam Leffler 
855faf8dcbSSam Leffler static void
865faf8dcbSSam Leffler setip6flags(const char *dummyaddr __unused, int flag, int dummysoc __unused,
875faf8dcbSSam Leffler     const struct afswtch *afp)
885faf8dcbSSam Leffler {
895faf8dcbSSam Leffler 	if (afp->af_af != AF_INET6)
905faf8dcbSSam Leffler 		err(1, "address flags can be set only for inet6 addresses");
915faf8dcbSSam Leffler 
925faf8dcbSSam Leffler 	if (flag < 0)
935faf8dcbSSam Leffler 		in6_addreq.ifra_flags &= ~(-flag);
945faf8dcbSSam Leffler 	else
955faf8dcbSSam Leffler 		in6_addreq.ifra_flags |= flag;
965faf8dcbSSam Leffler }
975faf8dcbSSam Leffler 
985faf8dcbSSam Leffler static void
995faf8dcbSSam Leffler setip6lifetime(const char *cmd, const char *val, int s,
1005faf8dcbSSam Leffler     const struct afswtch *afp)
1015faf8dcbSSam Leffler {
1025faf8dcbSSam Leffler 	time_t newval, t;
1035faf8dcbSSam Leffler 	char *ep;
1045faf8dcbSSam Leffler 
1055faf8dcbSSam Leffler 	t = time(NULL);
1065faf8dcbSSam Leffler 	newval = (time_t)strtoul(val, &ep, 0);
1075faf8dcbSSam Leffler 	if (val == ep)
1085faf8dcbSSam Leffler 		errx(1, "invalid %s", cmd);
1095faf8dcbSSam Leffler 	if (afp->af_af != AF_INET6)
1105faf8dcbSSam Leffler 		errx(1, "%s not allowed for the AF", cmd);
1115faf8dcbSSam Leffler 	if (strcmp(cmd, "vltime") == 0) {
1125faf8dcbSSam Leffler 		in6_addreq.ifra_lifetime.ia6t_expire = t + newval;
1135faf8dcbSSam Leffler 		in6_addreq.ifra_lifetime.ia6t_vltime = newval;
1145faf8dcbSSam Leffler 	} else if (strcmp(cmd, "pltime") == 0) {
1155faf8dcbSSam Leffler 		in6_addreq.ifra_lifetime.ia6t_preferred = t + newval;
1165faf8dcbSSam Leffler 		in6_addreq.ifra_lifetime.ia6t_pltime = newval;
1175faf8dcbSSam Leffler 	}
1185faf8dcbSSam Leffler }
1195faf8dcbSSam Leffler 
1205faf8dcbSSam Leffler static void
1215faf8dcbSSam Leffler setip6pltime(const char *seconds, int dummy __unused, int s,
1225faf8dcbSSam Leffler     const struct afswtch *afp)
1235faf8dcbSSam Leffler {
1245faf8dcbSSam Leffler 	setip6lifetime("pltime", seconds, s, afp);
1255faf8dcbSSam Leffler }
1265faf8dcbSSam Leffler 
1275faf8dcbSSam Leffler static void
1285faf8dcbSSam Leffler setip6vltime(const char *seconds, int dummy __unused, int s,
1295faf8dcbSSam Leffler     const struct afswtch *afp)
1305faf8dcbSSam Leffler {
1315faf8dcbSSam Leffler 	setip6lifetime("vltime", seconds, s, afp);
1325faf8dcbSSam Leffler }
1335faf8dcbSSam Leffler 
1345faf8dcbSSam Leffler static void
1355faf8dcbSSam Leffler setip6eui64(const char *cmd, int dummy __unused, int s,
1365faf8dcbSSam Leffler     const struct afswtch *afp)
1375faf8dcbSSam Leffler {
1385faf8dcbSSam Leffler 	struct ifaddrs *ifap, *ifa;
1395faf8dcbSSam Leffler 	const struct sockaddr_in6 *sin6 = NULL;
1405faf8dcbSSam Leffler 	const struct in6_addr *lladdr = NULL;
1415faf8dcbSSam Leffler 	struct in6_addr *in6;
1425faf8dcbSSam Leffler 
1435faf8dcbSSam Leffler 	if (afp->af_af != AF_INET6)
1445faf8dcbSSam Leffler 		errx(EXIT_FAILURE, "%s not allowed for the AF", cmd);
1455faf8dcbSSam Leffler  	in6 = (struct in6_addr *)&in6_addreq.ifra_addr.sin6_addr;
1465faf8dcbSSam Leffler 	if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0)
1475faf8dcbSSam Leffler 		errx(EXIT_FAILURE, "interface index is already filled");
1485faf8dcbSSam Leffler 	if (getifaddrs(&ifap) != 0)
1495faf8dcbSSam Leffler 		err(EXIT_FAILURE, "getifaddrs");
1505faf8dcbSSam Leffler 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1515faf8dcbSSam Leffler 		if (ifa->ifa_addr->sa_family == AF_INET6 &&
1525faf8dcbSSam Leffler 		    strcmp(ifa->ifa_name, name) == 0) {
1535faf8dcbSSam Leffler 			sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr;
1545faf8dcbSSam Leffler 			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
1555faf8dcbSSam Leffler 				lladdr = &sin6->sin6_addr;
1565faf8dcbSSam Leffler 				break;
1575faf8dcbSSam Leffler 			}
1585faf8dcbSSam Leffler 		}
1595faf8dcbSSam Leffler 	}
1605faf8dcbSSam Leffler 	if (!lladdr)
1615faf8dcbSSam Leffler 		errx(EXIT_FAILURE, "could not determine link local address");
1625faf8dcbSSam Leffler 
1635faf8dcbSSam Leffler  	memcpy(&in6->s6_addr[8], &lladdr->s6_addr[8], 8);
1645faf8dcbSSam Leffler 
1655faf8dcbSSam Leffler 	freeifaddrs(ifap);
1665faf8dcbSSam Leffler }
1675faf8dcbSSam Leffler 
1685faf8dcbSSam Leffler static void
1695faf8dcbSSam Leffler in6_fillscopeid(struct sockaddr_in6 *sin6)
1705faf8dcbSSam Leffler {
1715faf8dcbSSam Leffler #if defined(__KAME__) && defined(KAME_SCOPEID)
1725faf8dcbSSam Leffler 	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
1735faf8dcbSSam Leffler 		sin6->sin6_scope_id =
1745faf8dcbSSam Leffler 			ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
1755faf8dcbSSam Leffler 		sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
1765faf8dcbSSam Leffler 	}
1775faf8dcbSSam Leffler #endif
1785faf8dcbSSam Leffler }
1795faf8dcbSSam Leffler 
1805faf8dcbSSam Leffler static void
181cb8c905aSSam Leffler in6_status(int s __unused, const struct ifaddrs *ifa)
1825faf8dcbSSam Leffler {
1835faf8dcbSSam Leffler 	struct sockaddr_in6 *sin, null_sin;
1845faf8dcbSSam Leffler 	struct in6_ifreq ifr6;
1855faf8dcbSSam Leffler 	int s6;
1865faf8dcbSSam Leffler 	u_int32_t flags6;
1875faf8dcbSSam Leffler 	struct in6_addrlifetime lifetime;
1885faf8dcbSSam Leffler 	time_t t = time(NULL);
1895faf8dcbSSam Leffler 	int error;
1905faf8dcbSSam Leffler 	u_int32_t scopeid;
1915faf8dcbSSam Leffler 
1925faf8dcbSSam Leffler 	memset(&null_sin, 0, sizeof(null_sin));
1935faf8dcbSSam Leffler 
194cb8c905aSSam Leffler 	sin = (struct sockaddr_in6 *)ifa->ifa_addr;
1955faf8dcbSSam Leffler 	if (sin == NULL)
1965faf8dcbSSam Leffler 		return;
1975faf8dcbSSam Leffler 
1985faf8dcbSSam Leffler 	strncpy(ifr6.ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name));
1995faf8dcbSSam Leffler 	if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
2005faf8dcbSSam Leffler 		warn("socket(AF_INET6,SOCK_DGRAM)");
2015faf8dcbSSam Leffler 		return;
2025faf8dcbSSam Leffler 	}
2035faf8dcbSSam Leffler 	ifr6.ifr_addr = *sin;
2045faf8dcbSSam Leffler 	if (ioctl(s6, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
2055faf8dcbSSam Leffler 		warn("ioctl(SIOCGIFAFLAG_IN6)");
2065faf8dcbSSam Leffler 		close(s6);
2075faf8dcbSSam Leffler 		return;
2085faf8dcbSSam Leffler 	}
2095faf8dcbSSam Leffler 	flags6 = ifr6.ifr_ifru.ifru_flags6;
2105faf8dcbSSam Leffler 	memset(&lifetime, 0, sizeof(lifetime));
2115faf8dcbSSam Leffler 	ifr6.ifr_addr = *sin;
2125faf8dcbSSam Leffler 	if (ioctl(s6, SIOCGIFALIFETIME_IN6, &ifr6) < 0) {
2135faf8dcbSSam Leffler 		warn("ioctl(SIOCGIFALIFETIME_IN6)");
2145faf8dcbSSam Leffler 		close(s6);
2155faf8dcbSSam Leffler 		return;
2165faf8dcbSSam Leffler 	}
2175faf8dcbSSam Leffler 	lifetime = ifr6.ifr_ifru.ifru_lifetime;
2185faf8dcbSSam Leffler 	close(s6);
2195faf8dcbSSam Leffler 
2205faf8dcbSSam Leffler 	/* XXX: embedded link local addr check */
2215faf8dcbSSam Leffler 	if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) &&
2225faf8dcbSSam Leffler 	    *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) {
2235faf8dcbSSam Leffler 		u_short index;
2245faf8dcbSSam Leffler 
2255faf8dcbSSam Leffler 		index = *(u_short *)&sin->sin6_addr.s6_addr[2];
2265faf8dcbSSam Leffler 		*(u_short *)&sin->sin6_addr.s6_addr[2] = 0;
2275faf8dcbSSam Leffler 		if (sin->sin6_scope_id == 0)
2285faf8dcbSSam Leffler 			sin->sin6_scope_id = ntohs(index);
2295faf8dcbSSam Leffler 	}
2305faf8dcbSSam Leffler 	scopeid = sin->sin6_scope_id;
2315faf8dcbSSam Leffler 
2325faf8dcbSSam Leffler 	error = getnameinfo((struct sockaddr *)sin, sin->sin6_len, addr_buf,
2334f101318SHajimu UMEMOTO 			    sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
2345faf8dcbSSam Leffler 	if (error != 0)
2355faf8dcbSSam Leffler 		inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf,
2365faf8dcbSSam Leffler 			  sizeof(addr_buf));
2375faf8dcbSSam Leffler 	printf("\tinet6 %s ", addr_buf);
2385faf8dcbSSam Leffler 
239cb8c905aSSam Leffler 	if (ifa->ifa_flags & IFF_POINTOPOINT) {
240cb8c905aSSam Leffler 		sin = (struct sockaddr_in6 *)ifa->ifa_dstaddr;
2415faf8dcbSSam Leffler 		/*
2425faf8dcbSSam Leffler 		 * some of the interfaces do not have valid destination
2435faf8dcbSSam Leffler 		 * address.
2445faf8dcbSSam Leffler 		 */
245cb8c905aSSam Leffler 		if (sin != NULL && sin->sin6_family == AF_INET6) {
2465faf8dcbSSam Leffler 			int error;
2475faf8dcbSSam Leffler 
2485faf8dcbSSam Leffler 			/* XXX: embedded link local addr check */
2495faf8dcbSSam Leffler 			if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) &&
2505faf8dcbSSam Leffler 			    *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) {
2515faf8dcbSSam Leffler 				u_short index;
2525faf8dcbSSam Leffler 
2535faf8dcbSSam Leffler 				index = *(u_short *)&sin->sin6_addr.s6_addr[2];
2545faf8dcbSSam Leffler 				*(u_short *)&sin->sin6_addr.s6_addr[2] = 0;
2555faf8dcbSSam Leffler 				if (sin->sin6_scope_id == 0)
2565faf8dcbSSam Leffler 					sin->sin6_scope_id = ntohs(index);
2575faf8dcbSSam Leffler 			}
2585faf8dcbSSam Leffler 
2595faf8dcbSSam Leffler 			error = getnameinfo((struct sockaddr *)sin,
2605faf8dcbSSam Leffler 					    sin->sin6_len, addr_buf,
2615faf8dcbSSam Leffler 					    sizeof(addr_buf), NULL, 0,
2624f101318SHajimu UMEMOTO 					    NI_NUMERICHOST);
2635faf8dcbSSam Leffler 			if (error != 0)
2645faf8dcbSSam Leffler 				inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf,
2655faf8dcbSSam Leffler 					  sizeof(addr_buf));
2665faf8dcbSSam Leffler 			printf("--> %s ", addr_buf);
2675faf8dcbSSam Leffler 		}
2685faf8dcbSSam Leffler 	}
2695faf8dcbSSam Leffler 
270cb8c905aSSam Leffler 	sin = (struct sockaddr_in6 *)ifa->ifa_netmask;
271cb8c905aSSam Leffler 	if (sin == NULL)
2725faf8dcbSSam Leffler 		sin = &null_sin;
2735faf8dcbSSam Leffler 	printf("prefixlen %d ", prefix(&sin->sin6_addr,
2745faf8dcbSSam Leffler 		sizeof(struct in6_addr)));
2755faf8dcbSSam Leffler 
2765faf8dcbSSam Leffler 	if ((flags6 & IN6_IFF_ANYCAST) != 0)
2775faf8dcbSSam Leffler 		printf("anycast ");
2785faf8dcbSSam Leffler 	if ((flags6 & IN6_IFF_TENTATIVE) != 0)
2795faf8dcbSSam Leffler 		printf("tentative ");
2805faf8dcbSSam Leffler 	if ((flags6 & IN6_IFF_DUPLICATED) != 0)
2815faf8dcbSSam Leffler 		printf("duplicated ");
2825faf8dcbSSam Leffler 	if ((flags6 & IN6_IFF_DETACHED) != 0)
2835faf8dcbSSam Leffler 		printf("detached ");
2845faf8dcbSSam Leffler 	if ((flags6 & IN6_IFF_DEPRECATED) != 0)
2855faf8dcbSSam Leffler 		printf("deprecated ");
2865faf8dcbSSam Leffler 	if ((flags6 & IN6_IFF_AUTOCONF) != 0)
2875faf8dcbSSam Leffler 		printf("autoconf ");
2885faf8dcbSSam Leffler 	if ((flags6 & IN6_IFF_TEMPORARY) != 0)
2895faf8dcbSSam Leffler 		printf("temporary ");
2905faf8dcbSSam Leffler 
2915faf8dcbSSam Leffler         if (scopeid)
2925faf8dcbSSam Leffler 		printf("scopeid 0x%x ", scopeid);
2935faf8dcbSSam Leffler 
2945faf8dcbSSam Leffler 	if (ip6lifetime && (lifetime.ia6t_preferred || lifetime.ia6t_expire)) {
2955faf8dcbSSam Leffler 		printf("pltime ");
2965faf8dcbSSam Leffler 		if (lifetime.ia6t_preferred) {
2975faf8dcbSSam Leffler 			printf("%s ", lifetime.ia6t_preferred < t
2985faf8dcbSSam Leffler 				? "0" : sec2str(lifetime.ia6t_preferred - t));
2995faf8dcbSSam Leffler 		} else
3005faf8dcbSSam Leffler 			printf("infty ");
3015faf8dcbSSam Leffler 
3025faf8dcbSSam Leffler 		printf("vltime ");
3035faf8dcbSSam Leffler 		if (lifetime.ia6t_expire) {
3045faf8dcbSSam Leffler 			printf("%s ", lifetime.ia6t_expire < t
3055faf8dcbSSam Leffler 				? "0" : sec2str(lifetime.ia6t_expire - t));
3065faf8dcbSSam Leffler 		} else
3075faf8dcbSSam Leffler 			printf("infty ");
3085faf8dcbSSam Leffler 	}
3095faf8dcbSSam Leffler 
3105faf8dcbSSam Leffler 	putchar('\n');
3115faf8dcbSSam Leffler }
3125faf8dcbSSam Leffler 
3135faf8dcbSSam Leffler #define	SIN6(x) ((struct sockaddr_in6 *) &(x))
3145faf8dcbSSam Leffler static struct	sockaddr_in6 *sin6tab[] = {
3155faf8dcbSSam Leffler 	SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr),
3165faf8dcbSSam Leffler 	SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)
3175faf8dcbSSam Leffler };
3185faf8dcbSSam Leffler 
3195faf8dcbSSam Leffler static void
3205faf8dcbSSam Leffler in6_getprefix(const char *plen, int which)
3215faf8dcbSSam Leffler {
3225faf8dcbSSam Leffler 	struct sockaddr_in6 *sin = sin6tab[which];
3235faf8dcbSSam Leffler 	u_char *cp;
3245faf8dcbSSam Leffler 	int len = atoi(plen);
3255faf8dcbSSam Leffler 
3265faf8dcbSSam Leffler 	if ((len < 0) || (len > 128))
3275faf8dcbSSam Leffler 		errx(1, "%s: bad value", plen);
3285faf8dcbSSam Leffler 	sin->sin6_len = sizeof(*sin);
3295faf8dcbSSam Leffler 	if (which != MASK)
3305faf8dcbSSam Leffler 		sin->sin6_family = AF_INET6;
3315faf8dcbSSam Leffler 	if ((len == 0) || (len == 128)) {
3325faf8dcbSSam Leffler 		memset(&sin->sin6_addr, 0xff, sizeof(struct in6_addr));
3335faf8dcbSSam Leffler 		return;
3345faf8dcbSSam Leffler 	}
3355faf8dcbSSam Leffler 	memset((void *)&sin->sin6_addr, 0x00, sizeof(sin->sin6_addr));
3365faf8dcbSSam Leffler 	for (cp = (u_char *)&sin->sin6_addr; len > 7; len -= 8)
3375faf8dcbSSam Leffler 		*cp++ = 0xff;
3385faf8dcbSSam Leffler 	*cp = 0xff << (8 - len);
3395faf8dcbSSam Leffler }
3405faf8dcbSSam Leffler 
3415faf8dcbSSam Leffler static void
3425faf8dcbSSam Leffler in6_getaddr(const char *s, int which)
3435faf8dcbSSam Leffler {
3445faf8dcbSSam Leffler 	struct sockaddr_in6 *sin = sin6tab[which];
3455faf8dcbSSam Leffler 	struct addrinfo hints, *res;
3465faf8dcbSSam Leffler 	int error = -1;
3475faf8dcbSSam Leffler 
3485faf8dcbSSam Leffler 	newaddr &= 1;
3495faf8dcbSSam Leffler 
3505faf8dcbSSam Leffler 	sin->sin6_len = sizeof(*sin);
3515faf8dcbSSam Leffler 	if (which != MASK)
3525faf8dcbSSam Leffler 		sin->sin6_family = AF_INET6;
3535faf8dcbSSam Leffler 
3545faf8dcbSSam Leffler 	if (which == ADDR) {
3555faf8dcbSSam Leffler 		char *p = NULL;
3565faf8dcbSSam Leffler 		if((p = strrchr(s, '/')) != NULL) {
3575faf8dcbSSam Leffler 			*p = '\0';
3585faf8dcbSSam Leffler 			in6_getprefix(p + 1, MASK);
3595faf8dcbSSam Leffler 			explicit_prefix = 1;
3605faf8dcbSSam Leffler 		}
3615faf8dcbSSam Leffler 	}
3625faf8dcbSSam Leffler 
3635faf8dcbSSam Leffler 	if (sin->sin6_family == AF_INET6) {
3645faf8dcbSSam Leffler 		bzero(&hints, sizeof(struct addrinfo));
3655faf8dcbSSam Leffler 		hints.ai_family = AF_INET6;
3665faf8dcbSSam Leffler 		error = getaddrinfo(s, NULL, &hints, &res);
3675faf8dcbSSam Leffler 	}
3685faf8dcbSSam Leffler 	if (error != 0) {
3695faf8dcbSSam Leffler 		if (inet_pton(AF_INET6, s, &sin->sin6_addr) != 1)
3705faf8dcbSSam Leffler 			errx(1, "%s: bad value", s);
3715faf8dcbSSam Leffler 	} else
3725faf8dcbSSam Leffler 		bcopy(res->ai_addr, sin, res->ai_addrlen);
3735faf8dcbSSam Leffler }
3745faf8dcbSSam Leffler 
3755faf8dcbSSam Leffler static int
3765faf8dcbSSam Leffler prefix(void *val, int size)
3775faf8dcbSSam Leffler {
3785faf8dcbSSam Leffler         u_char *name = (u_char *)val;
3795faf8dcbSSam Leffler         int byte, bit, plen = 0;
3805faf8dcbSSam Leffler 
3815faf8dcbSSam Leffler         for (byte = 0; byte < size; byte++, plen += 8)
3825faf8dcbSSam Leffler                 if (name[byte] != 0xff)
3835faf8dcbSSam Leffler                         break;
3845faf8dcbSSam Leffler 	if (byte == size)
3855faf8dcbSSam Leffler 		return (plen);
3865faf8dcbSSam Leffler 	for (bit = 7; bit != 0; bit--, plen++)
3875faf8dcbSSam Leffler                 if (!(name[byte] & (1 << bit)))
3885faf8dcbSSam Leffler                         break;
3895faf8dcbSSam Leffler         for (; bit != 0; bit--)
3905faf8dcbSSam Leffler                 if (name[byte] & (1 << bit))
3915faf8dcbSSam Leffler                         return(0);
3925faf8dcbSSam Leffler         byte++;
3935faf8dcbSSam Leffler         for (; byte < size; byte++)
3945faf8dcbSSam Leffler                 if (name[byte])
3955faf8dcbSSam Leffler                         return(0);
3965faf8dcbSSam Leffler         return (plen);
3975faf8dcbSSam Leffler }
3985faf8dcbSSam Leffler 
3995faf8dcbSSam Leffler static char *
4005faf8dcbSSam Leffler sec2str(time_t total)
4015faf8dcbSSam Leffler {
4025faf8dcbSSam Leffler 	static char result[256];
4035faf8dcbSSam Leffler 	int days, hours, mins, secs;
4045faf8dcbSSam Leffler 	int first = 1;
4055faf8dcbSSam Leffler 	char *p = result;
4065faf8dcbSSam Leffler 
4075faf8dcbSSam Leffler 	if (0) {
4085faf8dcbSSam Leffler 		days = total / 3600 / 24;
4095faf8dcbSSam Leffler 		hours = (total / 3600) % 24;
4105faf8dcbSSam Leffler 		mins = (total / 60) % 60;
4115faf8dcbSSam Leffler 		secs = total % 60;
4125faf8dcbSSam Leffler 
4135faf8dcbSSam Leffler 		if (days) {
4145faf8dcbSSam Leffler 			first = 0;
4155faf8dcbSSam Leffler 			p += sprintf(p, "%dd", days);
4165faf8dcbSSam Leffler 		}
4175faf8dcbSSam Leffler 		if (!first || hours) {
4185faf8dcbSSam Leffler 			first = 0;
4195faf8dcbSSam Leffler 			p += sprintf(p, "%dh", hours);
4205faf8dcbSSam Leffler 		}
4215faf8dcbSSam Leffler 		if (!first || mins) {
4225faf8dcbSSam Leffler 			first = 0;
4235faf8dcbSSam Leffler 			p += sprintf(p, "%dm", mins);
4245faf8dcbSSam Leffler 		}
4255faf8dcbSSam Leffler 		sprintf(p, "%ds", secs);
4265faf8dcbSSam Leffler 	} else
4275faf8dcbSSam Leffler 		sprintf(result, "%lu", (unsigned long)total);
4285faf8dcbSSam Leffler 
4295faf8dcbSSam Leffler 	return(result);
4305faf8dcbSSam Leffler }
4315faf8dcbSSam Leffler 
4325faf8dcbSSam Leffler static void
4335faf8dcbSSam Leffler in6_postproc(int s, const struct afswtch *afp)
4345faf8dcbSSam Leffler {
4355faf8dcbSSam Leffler 	if (explicit_prefix == 0) {
4365faf8dcbSSam Leffler 		/* Aggregatable address architecture defines all prefixes
4375faf8dcbSSam Leffler 		   are 64. So, it is convenient to set prefixlen to 64 if
4385faf8dcbSSam Leffler 		   it is not specified. */
4395faf8dcbSSam Leffler 		setifprefixlen("64", 0, s, afp);
4405faf8dcbSSam Leffler 		/* in6_getprefix("64", MASK) if MASK is available here... */
4415faf8dcbSSam Leffler 	}
4425faf8dcbSSam Leffler }
4435faf8dcbSSam Leffler 
4445faf8dcbSSam Leffler static void
4455faf8dcbSSam Leffler in6_status_tunnel(int s)
4465faf8dcbSSam Leffler {
4475faf8dcbSSam Leffler 	char src[NI_MAXHOST];
4485faf8dcbSSam Leffler 	char dst[NI_MAXHOST];
4495faf8dcbSSam Leffler 	struct in6_ifreq in6_ifr;
4505faf8dcbSSam Leffler 	const struct sockaddr *sa = (const struct sockaddr *) &in6_ifr.ifr_addr;
4515faf8dcbSSam Leffler 
4525faf8dcbSSam Leffler 	memset(&in6_ifr, 0, sizeof(in6_ifr));
4535faf8dcbSSam Leffler 	strncpy(in6_ifr.ifr_name, name, IFNAMSIZ);
4545faf8dcbSSam Leffler 
4555faf8dcbSSam Leffler 	if (ioctl(s, SIOCGIFPSRCADDR_IN6, (caddr_t)&in6_ifr) < 0)
4565faf8dcbSSam Leffler 		return;
45773bbc449SHajimu UMEMOTO 	if (sa->sa_family != AF_INET6)
45873bbc449SHajimu UMEMOTO 		return;
4595faf8dcbSSam Leffler 	in6_fillscopeid(&in6_ifr.ifr_addr);
4604f101318SHajimu UMEMOTO 	if (getnameinfo(sa, sa->sa_len, src, sizeof(src), 0, 0,
4614f101318SHajimu UMEMOTO 	    NI_NUMERICHOST) != 0)
4625faf8dcbSSam Leffler 		src[0] = '\0';
4635faf8dcbSSam Leffler 
4645faf8dcbSSam Leffler 	if (ioctl(s, SIOCGIFPDSTADDR_IN6, (caddr_t)&in6_ifr) < 0)
4655faf8dcbSSam Leffler 		return;
46673bbc449SHajimu UMEMOTO 	if (sa->sa_family != AF_INET6)
46773bbc449SHajimu UMEMOTO 		return;
4685faf8dcbSSam Leffler 	in6_fillscopeid(&in6_ifr.ifr_addr);
4694f101318SHajimu UMEMOTO 	if (getnameinfo(sa, sa->sa_len, dst, sizeof(dst), 0, 0,
4704f101318SHajimu UMEMOTO 	    NI_NUMERICHOST) != 0)
4715faf8dcbSSam Leffler 		dst[0] = '\0';
4725faf8dcbSSam Leffler 
4735faf8dcbSSam Leffler 	printf("\ttunnel inet6 %s --> %s\n", src, dst);
4745faf8dcbSSam Leffler }
4755faf8dcbSSam Leffler 
4765faf8dcbSSam Leffler static void
4775faf8dcbSSam Leffler in6_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres)
4785faf8dcbSSam Leffler {
4795faf8dcbSSam Leffler 	struct in6_aliasreq in6_addreq;
4805faf8dcbSSam Leffler 
4815faf8dcbSSam Leffler 	memset(&in6_addreq, 0, sizeof(in6_addreq));
4825faf8dcbSSam Leffler 	strncpy(in6_addreq.ifra_name, name, IFNAMSIZ);
4835faf8dcbSSam Leffler 	memcpy(&in6_addreq.ifra_addr, srcres->ai_addr, srcres->ai_addr->sa_len);
4845faf8dcbSSam Leffler 	memcpy(&in6_addreq.ifra_dstaddr, dstres->ai_addr,
4855faf8dcbSSam Leffler 	    dstres->ai_addr->sa_len);
4865faf8dcbSSam Leffler 
4875faf8dcbSSam Leffler 	if (ioctl(s, SIOCSIFPHYADDR_IN6, &in6_addreq) < 0)
4885faf8dcbSSam Leffler 		warn("SIOCSIFPHYADDR_IN6");
4895faf8dcbSSam Leffler }
4905faf8dcbSSam Leffler 
4915faf8dcbSSam Leffler static struct cmd inet6_cmds[] = {
4925faf8dcbSSam Leffler 	DEF_CMD_ARG("prefixlen",			setifprefixlen),
4935faf8dcbSSam Leffler 	DEF_CMD("anycast",	IN6_IFF_ANYCAST,	setip6flags),
4945faf8dcbSSam Leffler 	DEF_CMD("tentative",	IN6_IFF_TENTATIVE,	setip6flags),
4955faf8dcbSSam Leffler 	DEF_CMD("-tentative",	-IN6_IFF_TENTATIVE,	setip6flags),
4965faf8dcbSSam Leffler 	DEF_CMD("deprecated",	IN6_IFF_DEPRECATED,	setip6flags),
4975faf8dcbSSam Leffler 	DEF_CMD("-deprecated", -IN6_IFF_DEPRECATED,	setip6flags),
4985faf8dcbSSam Leffler 	DEF_CMD("autoconf",	IN6_IFF_AUTOCONF,	setip6flags),
4995faf8dcbSSam Leffler 	DEF_CMD("-autoconf",	-IN6_IFF_AUTOCONF,	setip6flags),
500a283298cSHiroki Sato 	DEF_CMD("accept_rtadv",	ND6_IFF_ACCEPT_RTADV,	setnd6flags),
501a283298cSHiroki Sato 	DEF_CMD("-accept_rtadv",-ND6_IFF_ACCEPT_RTADV,	setnd6flags),
502*e7fa8d0aSHiroki Sato 	DEF_CMD("no_radr",	ND6_IFF_NO_RADR,	setnd6flags),
503*e7fa8d0aSHiroki Sato 	DEF_CMD("-no_radr",	-ND6_IFF_NO_RADR,	setnd6flags),
504a283298cSHiroki Sato 	DEF_CMD("defaultif",	1,			setnd6defif),
505a283298cSHiroki Sato 	DEF_CMD("-defaultif",	-1,			setnd6defif),
506a283298cSHiroki Sato 	DEF_CMD("ifdisabled",	ND6_IFF_IFDISABLED,	setnd6flags),
507a283298cSHiroki Sato 	DEF_CMD("-ifdisabled",	-ND6_IFF_IFDISABLED,	setnd6flags),
508a283298cSHiroki Sato 	DEF_CMD("nud",		ND6_IFF_PERFORMNUD,	setnd6flags),
509a283298cSHiroki Sato 	DEF_CMD("-nud",		-ND6_IFF_PERFORMNUD,	setnd6flags),
510a283298cSHiroki Sato 	DEF_CMD("prefer_source",ND6_IFF_PREFER_SOURCE,	setnd6flags),
511a283298cSHiroki Sato 	DEF_CMD("-prefer_source",-ND6_IFF_PREFER_SOURCE,setnd6flags),
512a283298cSHiroki Sato 	DEF_CMD("auto_linklocal",ND6_IFF_AUTO_LINKLOCAL,setnd6flags),
513a283298cSHiroki Sato 	DEF_CMD("-auto_linklocal",-ND6_IFF_AUTO_LINKLOCAL,setnd6flags),
5145faf8dcbSSam Leffler 	DEF_CMD_ARG("pltime",        			setip6pltime),
5155faf8dcbSSam Leffler 	DEF_CMD_ARG("vltime",        			setip6vltime),
5165faf8dcbSSam Leffler 	DEF_CMD("eui64",	0,			setip6eui64),
5175faf8dcbSSam Leffler };
5185faf8dcbSSam Leffler 
5195faf8dcbSSam Leffler static struct afswtch af_inet6 = {
5205faf8dcbSSam Leffler 	.af_name	= "inet6",
5215faf8dcbSSam Leffler 	.af_af		= AF_INET6,
5225faf8dcbSSam Leffler 	.af_status	= in6_status,
5235faf8dcbSSam Leffler 	.af_getaddr	= in6_getaddr,
5245faf8dcbSSam Leffler 	.af_getprefix	= in6_getprefix,
525c3cc3217SHiroki Sato 	.af_other_status = nd6_status,
5265faf8dcbSSam Leffler 	.af_postproc	= in6_postproc,
5275faf8dcbSSam Leffler 	.af_status_tunnel = in6_status_tunnel,
5285faf8dcbSSam Leffler 	.af_settunnel	= in6_set_tunnel,
5295faf8dcbSSam Leffler 	.af_difaddr	= SIOCDIFADDR_IN6,
5305faf8dcbSSam Leffler 	.af_aifaddr	= SIOCAIFADDR_IN6,
5311b153c92SBruce M Simpson 	.af_ridreq	= &in6_addreq,
5325faf8dcbSSam Leffler 	.af_addreq	= &in6_addreq,
5335faf8dcbSSam Leffler };
5345faf8dcbSSam Leffler 
5355faf8dcbSSam Leffler static void
5365faf8dcbSSam Leffler in6_Lopt_cb(const char *optarg __unused)
5375faf8dcbSSam Leffler {
5385faf8dcbSSam Leffler 	ip6lifetime++;	/* print IPv6 address lifetime */
5395faf8dcbSSam Leffler }
540b59dcaeeSXin LI static struct option in6_Lopt = { .opt = "L", .opt_usage = "[-L]", .cb = in6_Lopt_cb };
5415faf8dcbSSam Leffler 
5425faf8dcbSSam Leffler static __constructor void
5435faf8dcbSSam Leffler inet6_ctor(void)
5445faf8dcbSSam Leffler {
5455faf8dcbSSam Leffler #define	N(a)	(sizeof(a) / sizeof(a[0]))
546b59dcaeeSXin LI 	size_t i;
5475faf8dcbSSam Leffler 
5485af3fa9aSBjoern A. Zeeb 	if (!feature_present("inet6"))
5495af3fa9aSBjoern A. Zeeb 		return;
5505af3fa9aSBjoern A. Zeeb 
5515faf8dcbSSam Leffler 	for (i = 0; i < N(inet6_cmds);  i++)
5525faf8dcbSSam Leffler 		cmd_register(&inet6_cmds[i]);
5535faf8dcbSSam Leffler 	af_register(&af_inet6);
5545faf8dcbSSam Leffler 	opt_register(&in6_Lopt);
5555faf8dcbSSam Leffler #undef N
5565faf8dcbSSam Leffler }
557