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