]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/ifconfig/af_inet6.c
bhnd(9): Fix a few mandoc related issues
[FreeBSD/FreeBSD.git] / sbin / ifconfig / af_inet6.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1983, 1993
5  *      The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #ifndef lint
33 static const char rcsid[] =
34   "$FreeBSD$";
35 #endif /* not lint */
36
37 #include <sys/param.h>
38 #include <sys/ioctl.h>
39 #include <sys/socket.h>
40 #include <net/if.h>
41
42 #include <err.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47 #include <time.h>
48 #include <ifaddrs.h>
49
50 #include <arpa/inet.h>
51
52 #include <netinet/in.h>
53 #include <netinet/in_var.h>
54 #include <arpa/inet.h>
55 #include <netdb.h>
56
57 #include <netinet6/nd6.h>       /* Define ND6_INFINITE_LIFETIME */
58
59 #include "ifconfig.h"
60
61 static  struct in6_ifreq in6_ridreq;
62 static  struct in6_aliasreq in6_addreq =
63   { .ifra_flags = 0,
64     .ifra_lifetime = { 0, 0, ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME } };
65 static  int ip6lifetime;
66
67 static  int prefix(void *, int);
68 static  char *sec2str(time_t);
69 static  int explicit_prefix = 0;
70 extern  char *f_inet6, *f_addr;
71
72 extern void setnd6flags(const char *, int, int, const struct afswtch *);
73 extern void setnd6defif(const char *, int, int, const struct afswtch *);
74 extern void nd6_status(int);
75
76 static  char addr_buf[NI_MAXHOST];      /*for getnameinfo()*/
77
78 static void
79 setifprefixlen(const char *addr, int dummy __unused, int s,
80     const struct afswtch *afp)
81 {
82         if (afp->af_getprefix != NULL)
83                 afp->af_getprefix(addr, MASK);
84         explicit_prefix = 1;
85 }
86
87 static void
88 setip6flags(const char *dummyaddr __unused, int flag, int dummysoc __unused,
89     const struct afswtch *afp)
90 {
91         if (afp->af_af != AF_INET6)
92                 err(1, "address flags can be set only for inet6 addresses");
93
94         if (flag < 0)
95                 in6_addreq.ifra_flags &= ~(-flag);
96         else
97                 in6_addreq.ifra_flags |= flag;
98 }
99
100 static void
101 setip6lifetime(const char *cmd, const char *val, int s, 
102     const struct afswtch *afp)
103 {
104         struct timespec now;
105         time_t newval;
106         char *ep;
107
108         clock_gettime(CLOCK_MONOTONIC_FAST, &now);
109         newval = (time_t)strtoul(val, &ep, 0);
110         if (val == ep)
111                 errx(1, "invalid %s", cmd);
112         if (afp->af_af != AF_INET6)
113                 errx(1, "%s not allowed for the AF", cmd);
114         if (strcmp(cmd, "vltime") == 0) {
115                 in6_addreq.ifra_lifetime.ia6t_expire = now.tv_sec + newval;
116                 in6_addreq.ifra_lifetime.ia6t_vltime = newval;
117         } else if (strcmp(cmd, "pltime") == 0) {
118                 in6_addreq.ifra_lifetime.ia6t_preferred = now.tv_sec + newval;
119                 in6_addreq.ifra_lifetime.ia6t_pltime = newval;
120         }
121 }
122
123 static void
124 setip6pltime(const char *seconds, int dummy __unused, int s, 
125     const struct afswtch *afp)
126 {
127         setip6lifetime("pltime", seconds, s, afp);
128 }
129
130 static void
131 setip6vltime(const char *seconds, int dummy __unused, int s, 
132     const struct afswtch *afp)
133 {
134         setip6lifetime("vltime", seconds, s, afp);
135 }
136
137 static void
138 setip6eui64(const char *cmd, int dummy __unused, int s,
139     const struct afswtch *afp)
140 {
141         struct ifaddrs *ifap, *ifa;
142         const struct sockaddr_in6 *sin6 = NULL;
143         const struct in6_addr *lladdr = NULL;
144         struct in6_addr *in6;
145
146         if (afp->af_af != AF_INET6)
147                 errx(EXIT_FAILURE, "%s not allowed for the AF", cmd);
148         in6 = (struct in6_addr *)&in6_addreq.ifra_addr.sin6_addr;
149         if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0)
150                 errx(EXIT_FAILURE, "interface index is already filled");
151         if (getifaddrs(&ifap) != 0)
152                 err(EXIT_FAILURE, "getifaddrs");
153         for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
154                 if (ifa->ifa_addr->sa_family == AF_INET6 &&
155                     strcmp(ifa->ifa_name, name) == 0) {
156                         sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr;
157                         if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
158                                 lladdr = &sin6->sin6_addr;
159                                 break;
160                         }
161                 }
162         }
163         if (!lladdr)
164                 errx(EXIT_FAILURE, "could not determine link local address"); 
165
166         memcpy(&in6->s6_addr[8], &lladdr->s6_addr[8], 8);
167
168         freeifaddrs(ifap);
169 }
170
171 static void
172 in6_status(int s __unused, const struct ifaddrs *ifa)
173 {
174         struct sockaddr_in6 *sin, null_sin;
175         struct in6_ifreq ifr6;
176         int s6;
177         u_int32_t flags6;
178         struct in6_addrlifetime lifetime;
179         struct timespec now;
180         int error, n_flags;
181
182         clock_gettime(CLOCK_MONOTONIC_FAST, &now);
183
184         memset(&null_sin, 0, sizeof(null_sin));
185
186         sin = (struct sockaddr_in6 *)ifa->ifa_addr;
187         if (sin == NULL)
188                 return;
189
190         strlcpy(ifr6.ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name));
191         if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
192                 warn("socket(AF_INET6,SOCK_DGRAM)");
193                 return;
194         }
195         ifr6.ifr_addr = *sin;
196         if (ioctl(s6, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
197                 warn("ioctl(SIOCGIFAFLAG_IN6)");
198                 close(s6);
199                 return;
200         }
201         flags6 = ifr6.ifr_ifru.ifru_flags6;
202         memset(&lifetime, 0, sizeof(lifetime));
203         ifr6.ifr_addr = *sin;
204         if (ioctl(s6, SIOCGIFALIFETIME_IN6, &ifr6) < 0) {
205                 warn("ioctl(SIOCGIFALIFETIME_IN6)");
206                 close(s6);
207                 return;
208         }
209         lifetime = ifr6.ifr_ifru.ifru_lifetime;
210         close(s6);
211
212         if (f_addr != NULL && strcmp(f_addr, "fqdn") == 0)
213                 n_flags = 0;
214         else if (f_addr != NULL && strcmp(f_addr, "host") == 0)
215                 n_flags = NI_NOFQDN;
216         else
217                 n_flags = NI_NUMERICHOST;
218         error = getnameinfo((struct sockaddr *)sin, sin->sin6_len,
219                             addr_buf, sizeof(addr_buf), NULL, 0,
220                             n_flags);
221         if (error != 0)
222                 inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf,
223                           sizeof(addr_buf));
224         printf("\tinet6 %s", addr_buf);
225
226         if (ifa->ifa_flags & IFF_POINTOPOINT) {
227                 sin = (struct sockaddr_in6 *)ifa->ifa_dstaddr;
228                 /*
229                  * some of the interfaces do not have valid destination
230                  * address.
231                  */
232                 if (sin != NULL && sin->sin6_family == AF_INET6) {
233                         int error;
234
235                         error = getnameinfo((struct sockaddr *)sin,
236                                             sin->sin6_len, addr_buf,
237                                             sizeof(addr_buf), NULL, 0,
238                                             NI_NUMERICHOST);
239                         if (error != 0)
240                                 inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf,
241                                           sizeof(addr_buf));
242                         printf(" --> %s", addr_buf);
243                 }
244         }
245
246         sin = (struct sockaddr_in6 *)ifa->ifa_netmask;
247         if (sin == NULL)
248                 sin = &null_sin;
249         if (f_inet6 != NULL && strcmp(f_inet6, "cidr") == 0)
250                 printf("/%d", prefix(&sin->sin6_addr,
251                         sizeof(struct in6_addr)));
252         else
253                 printf(" prefixlen %d", prefix(&sin->sin6_addr,
254                         sizeof(struct in6_addr)));
255
256         if ((flags6 & IN6_IFF_ANYCAST) != 0)
257                 printf(" anycast");
258         if ((flags6 & IN6_IFF_TENTATIVE) != 0)
259                 printf(" tentative");
260         if ((flags6 & IN6_IFF_DUPLICATED) != 0)
261                 printf(" duplicated");
262         if ((flags6 & IN6_IFF_DETACHED) != 0)
263                 printf(" detached");
264         if ((flags6 & IN6_IFF_DEPRECATED) != 0)
265                 printf(" deprecated");
266         if ((flags6 & IN6_IFF_AUTOCONF) != 0)
267                 printf(" autoconf");
268         if ((flags6 & IN6_IFF_TEMPORARY) != 0)
269                 printf(" temporary");
270         if ((flags6 & IN6_IFF_PREFER_SOURCE) != 0)
271                 printf(" prefer_source");
272
273         if (((struct sockaddr_in6 *)(ifa->ifa_addr))->sin6_scope_id)
274                 printf(" scopeid 0x%x",
275                     ((struct sockaddr_in6 *)(ifa->ifa_addr))->sin6_scope_id);
276
277         if (ip6lifetime && (lifetime.ia6t_preferred || lifetime.ia6t_expire)) {
278                 printf(" pltime");
279                 if (lifetime.ia6t_preferred) {
280                         printf(" %s", lifetime.ia6t_preferred < now.tv_sec
281                             ? "0" :
282                             sec2str(lifetime.ia6t_preferred - now.tv_sec));
283                 } else
284                         printf(" infty");
285
286                 printf(" vltime");
287                 if (lifetime.ia6t_expire) {
288                         printf(" %s", lifetime.ia6t_expire < now.tv_sec
289                             ? "0" :
290                             sec2str(lifetime.ia6t_expire - now.tv_sec));
291                 } else
292                         printf(" infty");
293         }
294
295         print_vhid(ifa, " ");
296
297         putchar('\n');
298 }
299
300 #define SIN6(x) ((struct sockaddr_in6 *) &(x))
301 static struct   sockaddr_in6 *sin6tab[] = {
302         SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr),
303         SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)
304 };
305
306 static void
307 in6_getprefix(const char *plen, int which)
308 {
309         struct sockaddr_in6 *sin = sin6tab[which];
310         u_char *cp;
311         int len = atoi(plen);
312
313         if ((len < 0) || (len > 128))
314                 errx(1, "%s: bad value", plen);
315         sin->sin6_len = sizeof(*sin);
316         if (which != MASK)
317                 sin->sin6_family = AF_INET6;
318         if ((len == 0) || (len == 128)) {
319                 memset(&sin->sin6_addr, 0xff, sizeof(struct in6_addr));
320                 return;
321         }
322         memset((void *)&sin->sin6_addr, 0x00, sizeof(sin->sin6_addr));
323         for (cp = (u_char *)&sin->sin6_addr; len > 7; len -= 8)
324                 *cp++ = 0xff;
325         *cp = 0xff << (8 - len);
326 }
327
328 static void
329 in6_getaddr(const char *s, int which)
330 {
331         struct sockaddr_in6 *sin = sin6tab[which];
332         struct addrinfo hints, *res;
333         int error = -1;
334
335         newaddr &= 1;
336
337         sin->sin6_len = sizeof(*sin);
338         if (which != MASK)
339                 sin->sin6_family = AF_INET6;
340
341         if (which == ADDR) {
342                 char *p = NULL;
343                 if((p = strrchr(s, '/')) != NULL) {
344                         *p = '\0';
345                         in6_getprefix(p + 1, MASK);
346                         explicit_prefix = 1;
347                 }
348         }
349
350         if (sin->sin6_family == AF_INET6) {
351                 bzero(&hints, sizeof(struct addrinfo));
352                 hints.ai_family = AF_INET6;
353                 error = getaddrinfo(s, NULL, &hints, &res);
354                 if (error != 0) {
355                         if (inet_pton(AF_INET6, s, &sin->sin6_addr) != 1)
356                                 errx(1, "%s: bad value", s);
357                 } else {
358                         bcopy(res->ai_addr, sin, res->ai_addrlen);
359                         freeaddrinfo(res);
360                 }
361         }
362 }
363
364 static int
365 prefix(void *val, int size)
366 {
367         u_char *name = (u_char *)val;
368         int byte, bit, plen = 0;
369
370         for (byte = 0; byte < size; byte++, plen += 8)
371                 if (name[byte] != 0xff)
372                         break;
373         if (byte == size)
374                 return (plen);
375         for (bit = 7; bit != 0; bit--, plen++)
376                 if (!(name[byte] & (1 << bit)))
377                         break;
378         for (; bit != 0; bit--)
379                 if (name[byte] & (1 << bit))
380                         return(0);
381         byte++;
382         for (; byte < size; byte++)
383                 if (name[byte])
384                         return(0);
385         return (plen);
386 }
387
388 static char *
389 sec2str(time_t total)
390 {
391         static char result[256];
392         int days, hours, mins, secs;
393         int first = 1;
394         char *p = result;
395
396         if (0) {
397                 days = total / 3600 / 24;
398                 hours = (total / 3600) % 24;
399                 mins = (total / 60) % 60;
400                 secs = total % 60;
401
402                 if (days) {
403                         first = 0;
404                         p += sprintf(p, "%dd", days);
405                 }
406                 if (!first || hours) {
407                         first = 0;
408                         p += sprintf(p, "%dh", hours);
409                 }
410                 if (!first || mins) {
411                         first = 0;
412                         p += sprintf(p, "%dm", mins);
413                 }
414                 sprintf(p, "%ds", secs);
415         } else
416                 sprintf(result, "%lu", (unsigned long)total);
417
418         return(result);
419 }
420
421 static void
422 in6_postproc(int s, const struct afswtch *afp)
423 {
424         if (explicit_prefix == 0) {
425                 /* Aggregatable address architecture defines all prefixes
426                    are 64. So, it is convenient to set prefixlen to 64 if
427                    it is not specified. */
428                 setifprefixlen("64", 0, s, afp);
429                 /* in6_getprefix("64", MASK) if MASK is available here... */
430         }
431 }
432
433 static void
434 in6_status_tunnel(int s)
435 {
436         char src[NI_MAXHOST];
437         char dst[NI_MAXHOST];
438         struct in6_ifreq in6_ifr;
439         const struct sockaddr *sa = (const struct sockaddr *) &in6_ifr.ifr_addr;
440
441         memset(&in6_ifr, 0, sizeof(in6_ifr));
442         strlcpy(in6_ifr.ifr_name, name, sizeof(in6_ifr.ifr_name));
443
444         if (ioctl(s, SIOCGIFPSRCADDR_IN6, (caddr_t)&in6_ifr) < 0)
445                 return;
446         if (sa->sa_family != AF_INET6)
447                 return;
448         if (getnameinfo(sa, sa->sa_len, src, sizeof(src), 0, 0,
449             NI_NUMERICHOST) != 0)
450                 src[0] = '\0';
451
452         if (ioctl(s, SIOCGIFPDSTADDR_IN6, (caddr_t)&in6_ifr) < 0)
453                 return;
454         if (sa->sa_family != AF_INET6)
455                 return;
456         if (getnameinfo(sa, sa->sa_len, dst, sizeof(dst), 0, 0,
457             NI_NUMERICHOST) != 0)
458                 dst[0] = '\0';
459
460         printf("\ttunnel inet6 %s --> %s\n", src, dst);
461 }
462
463 static void
464 in6_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres)
465 {
466         struct in6_aliasreq in6_addreq; 
467
468         memset(&in6_addreq, 0, sizeof(in6_addreq));
469         strlcpy(in6_addreq.ifra_name, name, sizeof(in6_addreq.ifra_name));
470         memcpy(&in6_addreq.ifra_addr, srcres->ai_addr, srcres->ai_addr->sa_len);
471         memcpy(&in6_addreq.ifra_dstaddr, dstres->ai_addr,
472             dstres->ai_addr->sa_len);
473
474         if (ioctl(s, SIOCSIFPHYADDR_IN6, &in6_addreq) < 0)
475                 warn("SIOCSIFPHYADDR_IN6");
476 }
477
478 static struct cmd inet6_cmds[] = {
479         DEF_CMD_ARG("prefixlen",                        setifprefixlen),
480         DEF_CMD("anycast",      IN6_IFF_ANYCAST,        setip6flags),
481         DEF_CMD("tentative",    IN6_IFF_TENTATIVE,      setip6flags),
482         DEF_CMD("-tentative",   -IN6_IFF_TENTATIVE,     setip6flags),
483         DEF_CMD("deprecated",   IN6_IFF_DEPRECATED,     setip6flags),
484         DEF_CMD("-deprecated", -IN6_IFF_DEPRECATED,     setip6flags),
485         DEF_CMD("autoconf",     IN6_IFF_AUTOCONF,       setip6flags),
486         DEF_CMD("-autoconf",    -IN6_IFF_AUTOCONF,      setip6flags),
487         DEF_CMD("prefer_source",IN6_IFF_PREFER_SOURCE,  setip6flags),
488         DEF_CMD("-prefer_source",-IN6_IFF_PREFER_SOURCE,setip6flags),
489         DEF_CMD("accept_rtadv", ND6_IFF_ACCEPT_RTADV,   setnd6flags),
490         DEF_CMD("-accept_rtadv",-ND6_IFF_ACCEPT_RTADV,  setnd6flags),
491         DEF_CMD("no_radr",      ND6_IFF_NO_RADR,        setnd6flags),
492         DEF_CMD("-no_radr",     -ND6_IFF_NO_RADR,       setnd6flags),
493         DEF_CMD("defaultif",    1,                      setnd6defif),
494         DEF_CMD("-defaultif",   -1,                     setnd6defif),
495         DEF_CMD("ifdisabled",   ND6_IFF_IFDISABLED,     setnd6flags),
496         DEF_CMD("-ifdisabled",  -ND6_IFF_IFDISABLED,    setnd6flags),
497         DEF_CMD("nud",          ND6_IFF_PERFORMNUD,     setnd6flags),
498         DEF_CMD("-nud",         -ND6_IFF_PERFORMNUD,    setnd6flags),
499         DEF_CMD("auto_linklocal",ND6_IFF_AUTO_LINKLOCAL,setnd6flags),
500         DEF_CMD("-auto_linklocal",-ND6_IFF_AUTO_LINKLOCAL,setnd6flags),
501         DEF_CMD("no_prefer_iface",ND6_IFF_NO_PREFER_IFACE,setnd6flags),
502         DEF_CMD("-no_prefer_iface",-ND6_IFF_NO_PREFER_IFACE,setnd6flags),
503         DEF_CMD("no_dad",       ND6_IFF_NO_DAD,         setnd6flags),
504         DEF_CMD("-no_dad",      -ND6_IFF_NO_DAD,        setnd6flags),
505         DEF_CMD_ARG("pltime",                           setip6pltime),
506         DEF_CMD_ARG("vltime",                           setip6vltime),
507         DEF_CMD("eui64",        0,                      setip6eui64),
508 #ifdef EXPERIMENTAL
509         DEF_CMD("ipv6_only",    ND6_IFF_IPV6_ONLY_MANUAL,setnd6flags),
510         DEF_CMD("-ipv6_only",   -ND6_IFF_IPV6_ONLY_MANUAL,setnd6flags),
511 #endif
512 };
513
514 static struct afswtch af_inet6 = {
515         .af_name        = "inet6",
516         .af_af          = AF_INET6,
517         .af_status      = in6_status,
518         .af_getaddr     = in6_getaddr,
519         .af_getprefix   = in6_getprefix,
520         .af_other_status = nd6_status,
521         .af_postproc    = in6_postproc,
522         .af_status_tunnel = in6_status_tunnel,
523         .af_settunnel   = in6_set_tunnel,
524         .af_difaddr     = SIOCDIFADDR_IN6,
525         .af_aifaddr     = SIOCAIFADDR_IN6,
526         .af_ridreq      = &in6_addreq,
527         .af_addreq      = &in6_addreq,
528 };
529
530 static void
531 in6_Lopt_cb(const char *optarg __unused)
532 {
533         ip6lifetime++;  /* print IPv6 address lifetime */
534 }
535 static struct option in6_Lopt = {
536         .opt = "L",
537         .opt_usage = "[-L]",
538         .cb = in6_Lopt_cb
539 };
540
541 static __constructor void
542 inet6_ctor(void)
543 {
544         size_t i;
545
546 #ifndef RESCUE
547         if (!feature_present("inet6"))
548                 return;
549 #endif
550
551         for (i = 0; i < nitems(inet6_cmds);  i++)
552                 cmd_register(&inet6_cmds[i]);
553         af_register(&af_inet6);
554         opt_register(&in6_Lopt);
555 }