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