]> git.saurik.com Git - apple/network_cmds.git/blame - ifconfig.tproj/af_inet6.c
network_cmds-606.100.3.tar.gz
[apple/network_cmds.git] / ifconfig.tproj / af_inet6.c
CommitLineData
fdfd5971 1/*
a3cc5c72 2 * Copyright (c) 2009-2017, 2020 Apple Inc. All rights reserved.
fdfd5971
A
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
8d01c344
A
29/*
30 * Copyright (c) 1983, 1993
31 * The Regents of the University of California. All rights reserved.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
35 * are met:
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 * 4. Neither the name of the University nor the names of its contributors
42 * may be used to endorse or promote products derived from this software
43 * without specific prior written permission.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * SUCH DAMAGE.
56 */
57
8d01c344
A
58
59#include <sys/param.h>
60#include <sys/ioctl.h>
61#include <sys/socket.h>
62#include <net/if.h>
63
64#include <err.h>
9dc66a05 65#include <errno.h>
8d01c344
A
66#include <stdio.h>
67#include <stdlib.h>
68#include <string.h>
69#include <unistd.h>
70#include <ifaddrs.h>
71
72#include <arpa/inet.h>
73
74#include <netinet/in.h>
75#include <net/if_var.h> /* for struct ifaddr */
76#include <netinet/in_var.h>
77#include <arpa/inet.h>
78#include <netdb.h>
79
80#include <netinet6/nd6.h> /* Define ND6_INFINITE_LIFETIME */
81
82#include "ifconfig.h"
83
9dc66a05
A
84#define ND6BITS "\020\001PERFORMNUD\002ACCEPT_RTADV\003PREFER_SOURCE" \
85 "\004IFDISABLED\005DONT_SET_IFROUTE\006PROXY_PREFIXES" \
26c66ce9 86 "\007IGNORE_NA\010INSECURE\011REPLICATED\012DAD"
9dc66a05 87
8d01c344
A
88static struct in6_ifreq in6_ridreq;
89static struct in6_aliasreq in6_addreq =
90 { { 0 },
91 { 0 },
92 { 0 },
93 { 0 },
94 0,
95 { 0, 0, ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME } };
96static int ip6lifetime;
97
98static void in6_fillscopeid(struct sockaddr_in6 *sin6);
99static int prefix(void *, int);
100static char *sec2str(time_t);
101static int explicit_prefix = 0;
102
103static char addr_buf[MAXHOSTNAMELEN *2 + 1]; /*for getnameinfo()*/
104
105static void
106setifprefixlen(const char *addr, int dummy __unused, int s,
107 const struct afswtch *afp)
108{
109 if (afp->af_getprefix != NULL)
110 afp->af_getprefix(addr, MASK);
111 explicit_prefix = 1;
112}
113
9dc66a05
A
114static void
115setnd6flags(const char *dummyaddr __unused, int d, int s,
116 const struct afswtch *afp)
117{
118 struct in6_ndireq nd;
119 int error;
120
121 memset(&nd, 0, sizeof(nd));
e0b07f2d 122 strlcpy(nd.ifname, ifr.ifr_name, sizeof(nd.ifname));
9dc66a05
A
123 error = ioctl(s, SIOCGIFINFO_IN6, &nd);
124 if (error) {
125 warn("ioctl(SIOCGIFINFO_IN6)");
126 return;
127 }
128 if (d < 0)
129 nd.ndi.flags &= ~(-d);
130 else
131 nd.ndi.flags |= d;
132 error = ioctl(s, SIOCSIFINFO_FLAGS, (caddr_t)&nd);
133 if (error)
134 warn("ioctl(SIOCSIFINFO_FLAGS)");
135}
136
8d01c344
A
137static void
138setip6flags(const char *dummyaddr __unused, int flag, int dummysoc __unused,
139 const struct afswtch *afp)
140{
141 if (afp->af_af != AF_INET6)
142 err(1, "address flags can be set only for inet6 addresses");
143
144 if (flag < 0)
145 in6_addreq.ifra_flags &= ~(-flag);
146 else
147 in6_addreq.ifra_flags |= flag;
148}
149
150static void
151setip6lifetime(const char *cmd, const char *val, int s,
152 const struct afswtch *afp)
153{
154 time_t newval, t;
155 char *ep;
156
157 t = time(NULL);
158 newval = (time_t)strtoul(val, &ep, 0);
159 if (val == ep)
160 errx(1, "invalid %s", cmd);
161 if (afp->af_af != AF_INET6)
162 errx(1, "%s not allowed for the AF", cmd);
163 if (strcmp(cmd, "vltime") == 0) {
164 in6_addreq.ifra_lifetime.ia6t_expire = t + newval;
165 in6_addreq.ifra_lifetime.ia6t_vltime = newval;
166 } else if (strcmp(cmd, "pltime") == 0) {
167 in6_addreq.ifra_lifetime.ia6t_preferred = t + newval;
168 in6_addreq.ifra_lifetime.ia6t_pltime = newval;
169 }
170}
171
172static void
173setip6pltime(const char *seconds, int dummy __unused, int s,
174 const struct afswtch *afp)
175{
176 setip6lifetime("pltime", seconds, s, afp);
177}
178
179static void
180setip6vltime(const char *seconds, int dummy __unused, int s,
181 const struct afswtch *afp)
182{
183 setip6lifetime("vltime", seconds, s, afp);
184}
185
186static void
187setip6eui64(const char *cmd, int dummy __unused, int s,
188 const struct afswtch *afp)
189{
190 struct ifaddrs *ifap, *ifa;
191 const struct sockaddr_in6 *sin6 = NULL;
192 const struct in6_addr *lladdr = NULL;
193 struct in6_addr *in6;
194
195 if (afp->af_af != AF_INET6)
196 errx(EXIT_FAILURE, "%s not allowed for the AF", cmd);
197 in6 = (struct in6_addr *)&in6_addreq.ifra_addr.sin6_addr;
198 if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0)
199 errx(EXIT_FAILURE, "interface index is already filled");
200 if (getifaddrs(&ifap) != 0)
201 err(EXIT_FAILURE, "getifaddrs");
202 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
203 if (ifa->ifa_addr->sa_family == AF_INET6 &&
204 strcmp(ifa->ifa_name, name) == 0) {
205 sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr;
206 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
207 lladdr = &sin6->sin6_addr;
208 break;
209 }
210 }
211 }
212 if (!lladdr)
213 errx(EXIT_FAILURE, "could not determine link local address");
214
215 memcpy(&in6->s6_addr[8], &lladdr->s6_addr[8], 8);
216
217 freeifaddrs(ifap);
218}
219
220static void
221in6_fillscopeid(struct sockaddr_in6 *sin6)
222{
223#if defined(__KAME__) && defined(KAME_SCOPEID)
224 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
225 sin6->sin6_scope_id =
226 ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
227 sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
228 }
229#endif
230}
231
232static void
233in6_status(int s __unused, const struct ifaddrs *ifa)
234{
235 struct sockaddr_in6 *sin, null_sin;
236 struct in6_ifreq ifr6;
237 int s6;
238 u_int32_t flags6;
239 struct in6_addrlifetime lifetime;
240 time_t t = time(NULL);
241 int error;
242 u_int32_t scopeid;
243
244 memset(&null_sin, 0, sizeof(null_sin));
245
246 sin = (struct sockaddr_in6 *)ifa->ifa_addr;
247 if (sin == NULL)
248 return;
249
e0b07f2d 250 strlcpy(ifr6.ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name));
8d01c344
A
251 if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
252 warn("socket(AF_INET6,SOCK_DGRAM)");
253 return;
254 }
255 ifr6.ifr_addr = *sin;
256 if (ioctl(s6, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
257 warn("ioctl(SIOCGIFAFLAG_IN6)");
258 close(s6);
259 return;
260 }
261 flags6 = ifr6.ifr_ifru.ifru_flags6;
262 memset(&lifetime, 0, sizeof(lifetime));
263 ifr6.ifr_addr = *sin;
264 if (ioctl(s6, SIOCGIFALIFETIME_IN6, &ifr6) < 0) {
265 warn("ioctl(SIOCGIFALIFETIME_IN6)");
266 close(s6);
267 return;
268 }
269 lifetime = ifr6.ifr_ifru.ifru_lifetime;
270 close(s6);
271
272 /* XXX: embedded link local addr check */
273 if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) &&
274 *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) {
275 u_short index;
276
277 index = *(u_short *)&sin->sin6_addr.s6_addr[2];
278 *(u_short *)&sin->sin6_addr.s6_addr[2] = 0;
279 if (sin->sin6_scope_id == 0)
280 sin->sin6_scope_id = ntohs(index);
281 }
282 scopeid = sin->sin6_scope_id;
283
284 error = getnameinfo((struct sockaddr *)sin, sin->sin6_len, addr_buf,
285 sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
286 if (error != 0)
287 inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf,
288 sizeof(addr_buf));
289 printf("\tinet6 %s ", addr_buf);
290
291 if (ifa->ifa_flags & IFF_POINTOPOINT) {
292 sin = (struct sockaddr_in6 *)ifa->ifa_dstaddr;
293 /*
294 * some of the interfaces do not have valid destination
295 * address.
296 */
297 if (sin != NULL && sin->sin6_family == AF_INET6) {
298 int error;
299
300 /* XXX: embedded link local addr check */
301 if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) &&
302 *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) {
303 u_short index;
304
305 index = *(u_short *)&sin->sin6_addr.s6_addr[2];
306 *(u_short *)&sin->sin6_addr.s6_addr[2] = 0;
307 if (sin->sin6_scope_id == 0)
308 sin->sin6_scope_id = ntohs(index);
309 }
310
311 error = getnameinfo((struct sockaddr *)sin,
312 sin->sin6_len, addr_buf,
313 sizeof(addr_buf), NULL, 0,
314 NI_NUMERICHOST);
315 if (error != 0)
316 inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf,
317 sizeof(addr_buf));
318 printf("--> %s ", addr_buf);
319 }
320 }
321
322 sin = (struct sockaddr_in6 *)ifa->ifa_netmask;
323 if (sin == NULL)
324 sin = &null_sin;
325 printf("prefixlen %d ", prefix(&sin->sin6_addr,
326 sizeof(struct in6_addr)));
327
328 if ((flags6 & IN6_IFF_ANYCAST) != 0)
329 printf("anycast ");
330 if ((flags6 & IN6_IFF_TENTATIVE) != 0)
331 printf("tentative ");
7af5ce03
A
332 if ((flags6 & IN6_IFF_OPTIMISTIC) != 0)
333 printf("optimistic ");
8d01c344
A
334 if ((flags6 & IN6_IFF_DUPLICATED) != 0)
335 printf("duplicated ");
336 if ((flags6 & IN6_IFF_DETACHED) != 0)
337 printf("detached ");
338 if ((flags6 & IN6_IFF_DEPRECATED) != 0)
339 printf("deprecated ");
340 if ((flags6 & IN6_IFF_AUTOCONF) != 0)
341 printf("autoconf ");
342 if ((flags6 & IN6_IFF_TEMPORARY) != 0)
343 printf("temporary ");
342c141e
A
344 if ((flags6 & IN6_IFF_DYNAMIC) != 0)
345 printf("dynamic ");
9dc66a05
A
346 if ((flags6 & IN6_IFF_SECURED) != 0)
347 printf("secured ");
213b8c4f
A
348 if ((flags6 & IN6_IFF_CLAT46) != 0)
349 printf("clat46 ");
8d01c344
A
350
351 if (scopeid)
352 printf("scopeid 0x%x ", scopeid);
353
354 if (ip6lifetime && (lifetime.ia6t_preferred || lifetime.ia6t_expire)) {
355 printf("pltime ");
356 if (lifetime.ia6t_preferred) {
357 printf("%s ", lifetime.ia6t_preferred < t
358 ? "0" : sec2str(lifetime.ia6t_preferred - t));
359 } else
360 printf("infty ");
361
362 printf("vltime ");
363 if (lifetime.ia6t_expire) {
364 printf("%s ", lifetime.ia6t_expire < t
365 ? "0" : sec2str(lifetime.ia6t_expire - t));
366 } else
367 printf("infty ");
368 }
369
370 putchar('\n');
371}
372
373#define SIN6(x) ((struct sockaddr_in6 *) &(x))
374static struct sockaddr_in6 *sin6tab[] = {
375 SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr),
376 SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)
377};
378
379static void
380in6_getprefix(const char *plen, int which)
381{
382 struct sockaddr_in6 *sin = sin6tab[which];
383 u_char *cp;
384 int len = atoi(plen);
385
386 if ((len < 0) || (len > 128))
387 errx(1, "%s: bad value", plen);
388 sin->sin6_len = sizeof(*sin);
389 if (which != MASK)
390 sin->sin6_family = AF_INET6;
391 if ((len == 0) || (len == 128)) {
392 memset(&sin->sin6_addr, 0xff, sizeof(struct in6_addr));
393 return;
394 }
395 memset((void *)&sin->sin6_addr, 0x00, sizeof(sin->sin6_addr));
396 for (cp = (u_char *)&sin->sin6_addr; len > 7; len -= 8)
397 *cp++ = 0xff;
398 *cp = 0xff << (8 - len);
399}
400
401static void
402in6_getaddr(const char *s, int which)
403{
404 struct sockaddr_in6 *sin = sin6tab[which];
405 struct addrinfo hints, *res;
406 int error = -1;
407
408 newaddr &= 1;
409
410 sin->sin6_len = sizeof(*sin);
411 if (which != MASK)
412 sin->sin6_family = AF_INET6;
413
414 if (which == ADDR) {
415 char *p = NULL;
416 if((p = strrchr(s, '/')) != NULL) {
417 *p = '\0';
418 in6_getprefix(p + 1, MASK);
419 explicit_prefix = 1;
420 }
421 }
422
423 if (sin->sin6_family == AF_INET6) {
424 bzero(&hints, sizeof(struct addrinfo));
425 hints.ai_family = AF_INET6;
426 error = getaddrinfo(s, NULL, &hints, &res);
427 }
428 if (error != 0) {
429 if (inet_pton(AF_INET6, s, &sin->sin6_addr) != 1)
430 errx(1, "%s: bad value", s);
431 } else
432 bcopy(res->ai_addr, sin, res->ai_addrlen);
433}
434
435static int
436prefix(void *val, int size)
437{
438 u_char *name = (u_char *)val;
439 int byte, bit, plen = 0;
440
441 for (byte = 0; byte < size; byte++, plen += 8)
442 if (name[byte] != 0xff)
443 break;
444 if (byte == size)
445 return (plen);
446 for (bit = 7; bit != 0; bit--, plen++)
447 if (!(name[byte] & (1 << bit)))
448 break;
449 for (; bit != 0; bit--)
450 if (name[byte] & (1 << bit))
451 return(0);
452 byte++;
453 for (; byte < size; byte++)
454 if (name[byte])
455 return(0);
456 return (plen);
457}
458
459static char *
460sec2str(time_t total)
461{
462 static char result[256];
463 int days, hours, mins, secs;
464 int first = 1;
465 char *p = result;
466
467 if (0) {
468 days = total / 3600 / 24;
469 hours = (total / 3600) % 24;
470 mins = (total / 60) % 60;
471 secs = total % 60;
472
473 if (days) {
474 first = 0;
fdfd5971 475 p += snprintf(p, sizeof(result) - (p - result), "%dd", days);
8d01c344
A
476 }
477 if (!first || hours) {
478 first = 0;
fdfd5971 479 p += snprintf(p, sizeof(result) - (p - result), "%dh", hours);
8d01c344
A
480 }
481 if (!first || mins) {
482 first = 0;
fdfd5971 483 p += snprintf(p, sizeof(result) - (p - result), "%dm", mins);
8d01c344 484 }
fdfd5971 485 snprintf(p, sizeof(result) - (p - result), "%ds", secs);
8d01c344 486 } else
fdfd5971 487 snprintf(result, sizeof(result), "%lu", (unsigned long)total);
8d01c344
A
488
489 return(result);
490}
491
492static void
493in6_postproc(int s, const struct afswtch *afp)
494{
495 if (explicit_prefix == 0) {
496 /* Aggregatable address architecture defines all prefixes
497 are 64. So, it is convenient to set prefixlen to 64 if
498 it is not specified. */
499 setifprefixlen("64", 0, s, afp);
500 /* in6_getprefix("64", MASK) if MASK is available here... */
501 }
502}
503
504static void
505in6_status_tunnel(int s)
506{
507 char src[NI_MAXHOST];
508 char dst[NI_MAXHOST];
509 struct in6_ifreq in6_ifr;
510 const struct sockaddr *sa = (const struct sockaddr *) &in6_ifr.ifr_addr;
511
512 memset(&in6_ifr, 0, sizeof(in6_ifr));
e0b07f2d 513 strlcpy(in6_ifr.ifr_name, name, sizeof(in6_ifr.ifr_name));
8d01c344
A
514
515 if (ioctl(s, SIOCGIFPSRCADDR_IN6, (caddr_t)&in6_ifr) < 0)
516 return;
517 if (sa->sa_family != AF_INET6)
518 return;
519 in6_fillscopeid(&in6_ifr.ifr_addr);
520 if (getnameinfo(sa, sa->sa_len, src, sizeof(src), 0, 0,
521 NI_NUMERICHOST) != 0)
522 src[0] = '\0';
523
524 if (ioctl(s, SIOCGIFPDSTADDR_IN6, (caddr_t)&in6_ifr) < 0)
525 return;
526 if (sa->sa_family != AF_INET6)
527 return;
528 in6_fillscopeid(&in6_ifr.ifr_addr);
529 if (getnameinfo(sa, sa->sa_len, dst, sizeof(dst), 0, 0,
530 NI_NUMERICHOST) != 0)
531 dst[0] = '\0';
532
533 printf("\ttunnel inet6 %s --> %s\n", src, dst);
534}
535
9dc66a05
A
536static void
537nd6_status(int s)
538{
539 struct in6_ndireq nd;
540 int s6;
541 int error;
542
543 memset(&nd, 0, sizeof(nd));
e0b07f2d 544 strlcpy(nd.ifname, ifr.ifr_name, sizeof(nd.ifname));
9dc66a05
A
545 if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
546 if (errno != EPROTONOSUPPORT)
547 warn("socket(AF_INET6, SOCK_DGRAM)");
548 return;
549 }
550 error = ioctl(s6, SIOCGIFINFO_IN6, &nd);
551 if (error) {
552 if (errno != EPFNOSUPPORT && errno != EINVAL)
553 warn("ioctl(SIOCGIFINFO_IN6)");
554 close(s6);
555 return;
556 }
557 close(s6);
558 if (nd.ndi.flags == 0)
559 return;
560 printb("\tnd6 options", (unsigned int)nd.ndi.flags, ND6BITS);
561 putchar('\n');
562}
563
8d01c344
A
564static void
565in6_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres)
566{
567 struct in6_aliasreq in6_addreq;
568
569 memset(&in6_addreq, 0, sizeof(in6_addreq));
e0b07f2d 570 strlcpy(in6_addreq.ifra_name, name, sizeof(in6_addreq.ifra_name));
8d01c344
A
571 memcpy(&in6_addreq.ifra_addr, srcres->ai_addr, srcres->ai_addr->sa_len);
572 memcpy(&in6_addreq.ifra_dstaddr, dstres->ai_addr,
573 dstres->ai_addr->sa_len);
574
575 if (ioctl(s, SIOCSIFPHYADDR_IN6, &in6_addreq) < 0)
576 warn("SIOCSIFPHYADDR_IN6");
577}
578
a3cc5c72
A
579#ifndef IPV6_ROUTER_MODE_EXCLUSIVE
580#define IPV6_ROUTER_MODE_DISABLED 0
581#define IPV6_ROUTER_MODE_EXCLUSIVE 1
582#define IPV6_ROUTER_MODE_HYBRID 2
583#endif /* IPV6_ROUTER_MODE_EXCLUSIVE */
584
7af5ce03
A
585static void
586in6_set_router(int s, int enable)
587{
588 struct ifreq ifr;
589
590 bzero(&ifr, sizeof (ifr));
e0b07f2d 591 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
a3cc5c72
A
592 ifr.ifr_intval = (enable == 0)
593 ? IPV6_ROUTER_MODE_DISABLED
594 : IPV6_ROUTER_MODE_EXCLUSIVE;
7af5ce03
A
595
596 if (ioctl(s, SIOCSETROUTERMODE_IN6, &ifr) < 0)
597 warn("SIOCSETROUTERMODE_IN6");
598}
599
a3cc5c72
A
600static int
601routermode_from_string(char * str, int *mode_p)
602{
603 int success = 1;
604
605 if (strcasecmp(str, "exclusive") == 0 ||
606 strcasecmp(str, "enabled") == 0) {
607 *mode_p = IPV6_ROUTER_MODE_EXCLUSIVE;
608 } else if (strcasecmp(str, "hybrid") == 0) {
609 *mode_p = IPV6_ROUTER_MODE_HYBRID;
610 } else if (strcasecmp(str, "disabled") == 0) {
611 *mode_p = IPV6_ROUTER_MODE_DISABLED;
612 } else {
613 success = 0;
614 }
615 return (success);
616}
617
618static const char *
619routermode_string(int mode)
620{
621 const char * str;
622
623 switch (mode) {
624 case IPV6_ROUTER_MODE_EXCLUSIVE:
625 str = "enabled";
626 break;
627 case IPV6_ROUTER_MODE_HYBRID:
628 str = "hybrid";
629 break;
630 case IPV6_ROUTER_MODE_DISABLED:
631 str = "disabled";
632 break;
633 default:
634 str = "<unknown>";
635 break;
636 }
637 return str;
638}
639
640static int
641in6_routermode(int s, int argc, char *const*argv)
642{
643 struct in6_ifreq ifr;
644 int ret;
645
646 bzero(&ifr, sizeof (ifr));
647 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
648 if (argc == 0) {
649 ret = 0;
650#ifndef SIOCGETROUTERMODE_IN6
651#define SIOCGETROUTERMODE_IN6 _IOWR('i', 137, struct in6_ifreq)
652#endif /* SIOCGETROUTERMODE_IN6 */
653 if (ioctl(s, SIOCGETROUTERMODE_IN6, &ifr) < 0) {
654 if (argv != NULL) {
655 warn("SIOCGETROUTERMODE_IN6");
656 }
657 } else {
658 /* argv is NULL if we're called from status() */
659 printf("%s%s\n",
660 (argv == NULL) ? "\troutermode6: " : "",
661 routermode_string(ifr.ifr_intval));
662 }
663 ret = 0;
664 } else {
665 int mode;
666
667 if (routermode_from_string(argv[0], &mode) == 0) {
668 errx(EXIT_FAILURE,
669 "mode '%s' invalid, must be one of "
670 "disabled, exclusive, or hybrid",
671 argv[0]);
672 }
673 ifr.ifr_intval = mode;
674 if (ioctl(s, SIOCSETROUTERMODE_IN6, &ifr) < 0) {
675 warn("SIOCSETROUTERMODE_IN6");
676 }
677 ret = 1;
678 }
679 return ret;
680}
681
8d01c344
A
682static struct cmd inet6_cmds[] = {
683 DEF_CMD_ARG("prefixlen", setifprefixlen),
684 DEF_CMD("anycast", IN6_IFF_ANYCAST, setip6flags),
685 DEF_CMD("tentative", IN6_IFF_TENTATIVE, setip6flags),
686 DEF_CMD("-tentative", -IN6_IFF_TENTATIVE, setip6flags),
7af5ce03
A
687 /* RFC 4429, section 3.1, says:
688 * "Optimistic DAD SHOULD NOT be used for manually entered
689 * addresses."
89c4ed63 690 * it's not a MUST...
7af5ce03 691 */
89c4ed63
A
692 DEF_CMD("optimistic", IN6_IFF_OPTIMISTIC, setip6flags),
693 DEF_CMD("-optimistic", -IN6_IFF_OPTIMISTIC, setip6flags),
8d01c344
A
694 DEF_CMD("deprecated", IN6_IFF_DEPRECATED, setip6flags),
695 DEF_CMD("-deprecated", -IN6_IFF_DEPRECATED, setip6flags),
696 DEF_CMD("autoconf", IN6_IFF_AUTOCONF, setip6flags),
697 DEF_CMD("-autoconf", -IN6_IFF_AUTOCONF, setip6flags),
9dc66a05
A
698 DEF_CMD("nud", ND6_IFF_PERFORMNUD, setnd6flags),
699 DEF_CMD("-nud", -ND6_IFF_PERFORMNUD, setnd6flags),
700 DEF_CMD("ifdisabled", ND6_IFF_IFDISABLED, setnd6flags),
701 DEF_CMD("-ifdisabled", -ND6_IFF_IFDISABLED, setnd6flags),
26c66ce9
A
702 DEF_CMD("replicated", ND6_IFF_REPLICATED, setnd6flags),
703 DEF_CMD("-replicated", -ND6_IFF_REPLICATED, setnd6flags),
9dc66a05
A
704 DEF_CMD("proxy_prefixes", ND6_IFF_PROXY_PREFIXES, setnd6flags),
705 DEF_CMD("-proxy_prefixes", -ND6_IFF_PROXY_PREFIXES, setnd6flags),
706 DEF_CMD("insecure", ND6_IFF_INSECURE, setnd6flags),
707 DEF_CMD("-insecure", -ND6_IFF_INSECURE, setnd6flags),
8d01c344
A
708 DEF_CMD_ARG("pltime", setip6pltime),
709 DEF_CMD_ARG("vltime", setip6vltime),
710 DEF_CMD("eui64", 0, setip6eui64),
9dc66a05
A
711 DEF_CMD("secured", IN6_IFF_SECURED, setip6flags),
712 DEF_CMD("-secured", -IN6_IFF_SECURED, setip6flags),
26c66ce9
A
713 DEF_CMD("dad", ND6_IFF_DAD, setnd6flags),
714 DEF_CMD("-dad", -ND6_IFF_DAD, setnd6flags),
8d01c344
A
715};
716
717static struct afswtch af_inet6 = {
718 .af_name = "inet6",
719 .af_af = AF_INET6,
720 .af_status = in6_status,
721 .af_getaddr = in6_getaddr,
722 .af_getprefix = in6_getprefix,
9dc66a05 723 .af_other_status = nd6_status,
8d01c344
A
724 .af_postproc = in6_postproc,
725 .af_status_tunnel = in6_status_tunnel,
726 .af_settunnel = in6_set_tunnel,
7af5ce03 727 .af_setrouter = in6_set_router,
a3cc5c72 728 .af_routermode = in6_routermode,
8d01c344
A
729 .af_difaddr = SIOCDIFADDR_IN6,
730 .af_aifaddr = SIOCAIFADDR_IN6,
7af5ce03 731 .af_ridreq = &in6_ridreq,
8d01c344
A
732 .af_addreq = &in6_addreq,
733};
734
735static void
736in6_Lopt_cb(const char *optarg __unused)
737{
738 ip6lifetime++; /* print IPv6 address lifetime */
739}
740static struct option in6_Lopt = { "L", "[-L]", in6_Lopt_cb };
741
742static __constructor void
743inet6_ctor(void)
744{
745#define N(a) (sizeof(a) / sizeof(a[0]))
746 int i;
747
748 for (i = 0; i < N(inet6_cmds); i++)
749 cmd_register(&inet6_cmds[i]);
750 af_register(&af_inet6);
751 opt_register(&in6_Lopt);
752#undef N
753}