2017-11-20 19:49:47 +00:00
|
|
|
/*-
|
|
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
*
|
2004-12-08 19:18:07 +00:00
|
|
|
* Copyright (c) 1983, 1993
|
|
|
|
* The Regents of the University of California. All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
2017-02-28 23:42:47 +00:00
|
|
|
* 3. Neither the name of the University nor the names of its contributors
|
2004-12-08 19:18:07 +00:00
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <net/if.h>
|
|
|
|
|
|
|
|
#include <err.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
2014-06-30 16:39:37 +00:00
|
|
|
#include <time.h>
|
2004-12-08 19:18:07 +00:00
|
|
|
#include <ifaddrs.h>
|
|
|
|
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/in_var.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include <netdb.h>
|
|
|
|
|
|
|
|
#include <netinet6/nd6.h> /* Define ND6_INFINITE_LIFETIME */
|
|
|
|
|
|
|
|
#include "ifconfig.h"
|
2023-05-10 13:58:21 +00:00
|
|
|
#include "ifconfig_netlink.h"
|
2004-12-08 19:18:07 +00:00
|
|
|
|
2023-05-20 11:53:46 +00:00
|
|
|
#ifndef WITHOUT_NETLINK
|
|
|
|
struct in6_px {
|
|
|
|
struct in6_addr addr;
|
|
|
|
int plen;
|
|
|
|
bool set;
|
|
|
|
};
|
|
|
|
struct in6_pdata {
|
|
|
|
struct in6_px addr;
|
|
|
|
struct in6_px dst_addr;
|
|
|
|
struct in6_addrlifetime lifetime;
|
|
|
|
uint32_t flags;
|
|
|
|
uint32_t vhid;
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct in6_pdata in6_del;
|
|
|
|
static struct in6_pdata in6_add = {
|
|
|
|
.lifetime = { 0, 0, ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME },
|
|
|
|
};
|
|
|
|
#else
|
2004-12-08 19:18:07 +00:00
|
|
|
static struct in6_ifreq in6_ridreq;
|
2015-02-02 14:37:45 +00:00
|
|
|
static struct in6_aliasreq in6_addreq =
|
|
|
|
{ .ifra_flags = 0,
|
2009-06-23 23:49:52 +00:00
|
|
|
.ifra_lifetime = { 0, 0, ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME } };
|
2023-05-20 11:53:46 +00:00
|
|
|
#endif
|
2004-12-08 19:18:07 +00:00
|
|
|
static int ip6lifetime;
|
|
|
|
|
2023-05-23 11:04:09 +00:00
|
|
|
#ifdef WITHOUT_NETLINK
|
2004-12-08 19:18:07 +00:00
|
|
|
static int prefix(void *, int);
|
2023-05-23 11:04:09 +00:00
|
|
|
#endif
|
2004-12-08 19:18:07 +00:00
|
|
|
static char *sec2str(time_t);
|
|
|
|
static int explicit_prefix = 0;
|
2016-06-02 03:16:02 +00:00
|
|
|
extern char *f_inet6, *f_addr;
|
2004-12-08 19:18:07 +00:00
|
|
|
|
2023-05-23 17:02:12 +00:00
|
|
|
extern void setnd6flags(if_ctx *, const char *, int);
|
|
|
|
extern void setnd6defif(if_ctx *,const char *, int);
|
|
|
|
extern void nd6_status(if_ctx *);
|
2009-09-12 22:08:20 +00:00
|
|
|
|
2016-06-02 03:16:02 +00:00
|
|
|
static char addr_buf[NI_MAXHOST]; /*for getnameinfo()*/
|
2004-12-08 19:18:07 +00:00
|
|
|
|
|
|
|
static void
|
2023-06-01 11:54:02 +00:00
|
|
|
setifprefixlen(if_ctx *ctx __netlink_unused, const char *addr, int dummy __unused)
|
2004-12-08 19:18:07 +00:00
|
|
|
{
|
2023-05-20 11:53:46 +00:00
|
|
|
#ifdef WITHOUT_NETLINK
|
2023-05-23 17:02:12 +00:00
|
|
|
const struct afswtch *afp = ctx->afp;
|
|
|
|
|
2004-12-08 19:18:07 +00:00
|
|
|
if (afp->af_getprefix != NULL)
|
|
|
|
afp->af_getprefix(addr, MASK);
|
2023-05-20 11:53:46 +00:00
|
|
|
#else
|
|
|
|
int plen = strtol(addr, NULL, 10);
|
|
|
|
|
|
|
|
if ((plen < 0) || (plen > 128))
|
|
|
|
errx(1, "%s: bad value", addr);
|
|
|
|
in6_add.addr.plen = plen;
|
|
|
|
#endif
|
2004-12-08 19:18:07 +00:00
|
|
|
explicit_prefix = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-05-23 17:02:12 +00:00
|
|
|
setip6flags(if_ctx *ctx, const char *dummyaddr __unused, int flag)
|
2004-12-08 19:18:07 +00:00
|
|
|
{
|
2023-05-23 17:02:12 +00:00
|
|
|
const struct afswtch *afp = ctx->afp;
|
|
|
|
|
2004-12-08 19:18:07 +00:00
|
|
|
if (afp->af_af != AF_INET6)
|
|
|
|
err(1, "address flags can be set only for inet6 addresses");
|
|
|
|
|
2023-05-20 11:53:46 +00:00
|
|
|
#ifdef WITHOUT_NETLINK
|
2004-12-08 19:18:07 +00:00
|
|
|
if (flag < 0)
|
|
|
|
in6_addreq.ifra_flags &= ~(-flag);
|
|
|
|
else
|
|
|
|
in6_addreq.ifra_flags |= flag;
|
2023-05-20 11:53:46 +00:00
|
|
|
#else
|
|
|
|
if (flag < 0)
|
|
|
|
in6_add.flags &= ~(-flag);
|
|
|
|
else
|
|
|
|
in6_add.flags |= flag;
|
|
|
|
#endif
|
2004-12-08 19:18:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-05-23 17:02:12 +00:00
|
|
|
setip6lifetime(if_ctx *ctx, const char *cmd, const char *val)
|
2004-12-08 19:18:07 +00:00
|
|
|
{
|
2023-05-23 17:02:12 +00:00
|
|
|
const struct afswtch *afp = ctx->afp;
|
2014-06-30 16:39:37 +00:00
|
|
|
struct timespec now;
|
|
|
|
time_t newval;
|
2004-12-08 19:18:07 +00:00
|
|
|
char *ep;
|
2023-05-20 11:53:46 +00:00
|
|
|
#ifdef WITHOUT_NETLINK
|
|
|
|
struct in6_addrlifetime *lifetime = &in6_addreq.ifra_lifetime;
|
|
|
|
#else
|
|
|
|
struct in6_addrlifetime *lifetime = &in6_add.lifetime;
|
|
|
|
#endif
|
2004-12-08 19:18:07 +00:00
|
|
|
|
2014-06-30 16:39:37 +00:00
|
|
|
clock_gettime(CLOCK_MONOTONIC_FAST, &now);
|
2004-12-08 19:18:07 +00:00
|
|
|
newval = (time_t)strtoul(val, &ep, 0);
|
|
|
|
if (val == ep)
|
|
|
|
errx(1, "invalid %s", cmd);
|
|
|
|
if (afp->af_af != AF_INET6)
|
|
|
|
errx(1, "%s not allowed for the AF", cmd);
|
|
|
|
if (strcmp(cmd, "vltime") == 0) {
|
2023-05-20 11:53:46 +00:00
|
|
|
lifetime->ia6t_expire = now.tv_sec + newval;
|
|
|
|
lifetime->ia6t_vltime = newval;
|
2004-12-08 19:18:07 +00:00
|
|
|
} else if (strcmp(cmd, "pltime") == 0) {
|
2023-05-20 11:53:46 +00:00
|
|
|
lifetime->ia6t_preferred = now.tv_sec + newval;
|
|
|
|
lifetime->ia6t_pltime = newval;
|
2004-12-08 19:18:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-05-23 17:02:12 +00:00
|
|
|
setip6pltime(if_ctx *ctx, const char *seconds, int dummy __unused)
|
2004-12-08 19:18:07 +00:00
|
|
|
{
|
2023-05-23 17:02:12 +00:00
|
|
|
setip6lifetime(ctx, "pltime", seconds);
|
2004-12-08 19:18:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-05-23 17:02:12 +00:00
|
|
|
setip6vltime(if_ctx *ctx, const char *seconds, int dummy __unused)
|
2004-12-08 19:18:07 +00:00
|
|
|
{
|
2023-05-23 17:02:12 +00:00
|
|
|
setip6lifetime(ctx, "vltime", seconds);
|
2004-12-08 19:18:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-05-23 17:02:12 +00:00
|
|
|
setip6eui64(if_ctx *ctx, const char *cmd, int dummy __unused)
|
2004-12-08 19:18:07 +00:00
|
|
|
{
|
2023-05-23 17:02:12 +00:00
|
|
|
const struct afswtch *afp = ctx->afp;
|
2004-12-08 19:18:07 +00:00
|
|
|
struct ifaddrs *ifap, *ifa;
|
|
|
|
const struct sockaddr_in6 *sin6 = NULL;
|
|
|
|
const struct in6_addr *lladdr = NULL;
|
|
|
|
struct in6_addr *in6;
|
|
|
|
|
|
|
|
if (afp->af_af != AF_INET6)
|
|
|
|
errx(EXIT_FAILURE, "%s not allowed for the AF", cmd);
|
2023-05-20 11:53:46 +00:00
|
|
|
#ifdef WITHOUT_NETLINK
|
2004-12-08 19:18:07 +00:00
|
|
|
in6 = (struct in6_addr *)&in6_addreq.ifra_addr.sin6_addr;
|
2023-05-20 11:53:46 +00:00
|
|
|
#else
|
|
|
|
in6 = &in6_add.addr.addr;
|
|
|
|
#endif
|
2004-12-08 19:18:07 +00:00
|
|
|
if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0)
|
|
|
|
errx(EXIT_FAILURE, "interface index is already filled");
|
|
|
|
if (getifaddrs(&ifap) != 0)
|
|
|
|
err(EXIT_FAILURE, "getifaddrs");
|
|
|
|
for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
|
|
|
|
if (ifa->ifa_addr->sa_family == AF_INET6 &&
|
2023-06-13 06:22:29 +00:00
|
|
|
strcmp(ifa->ifa_name, ctx->ifname) == 0) {
|
2023-05-23 11:04:09 +00:00
|
|
|
sin6 = (const struct sockaddr_in6 *)satosin6(ifa->ifa_addr);
|
2004-12-08 19:18:07 +00:00
|
|
|
if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
|
|
|
|
lladdr = &sin6->sin6_addr;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!lladdr)
|
|
|
|
errx(EXIT_FAILURE, "could not determine link local address");
|
|
|
|
|
|
|
|
memcpy(&in6->s6_addr[8], &lladdr->s6_addr[8], 8);
|
|
|
|
|
|
|
|
freeifaddrs(ifap);
|
|
|
|
}
|
|
|
|
|
2023-05-15 12:17:54 +00:00
|
|
|
static void
|
|
|
|
print_addr(struct sockaddr_in6 *sin)
|
|
|
|
{
|
|
|
|
int error, n_flags;
|
|
|
|
|
|
|
|
if (f_addr != NULL && strcmp(f_addr, "fqdn") == 0)
|
|
|
|
n_flags = 0;
|
|
|
|
else if (f_addr != NULL && strcmp(f_addr, "host") == 0)
|
|
|
|
n_flags = NI_NOFQDN;
|
|
|
|
else
|
|
|
|
n_flags = NI_NUMERICHOST;
|
|
|
|
error = getnameinfo((struct sockaddr *)sin, sin->sin6_len,
|
|
|
|
addr_buf, sizeof(addr_buf), NULL, 0,
|
|
|
|
n_flags);
|
|
|
|
if (error != 0)
|
|
|
|
inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf,
|
|
|
|
sizeof(addr_buf));
|
|
|
|
printf("\tinet6 %s", addr_buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
print_p2p(struct sockaddr_in6 *sin)
|
|
|
|
{
|
|
|
|
int error;
|
|
|
|
|
|
|
|
error = getnameinfo((struct sockaddr *)sin, sin->sin6_len, addr_buf,
|
|
|
|
sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
|
|
|
|
|
|
|
|
if (error != 0)
|
|
|
|
inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf, sizeof(addr_buf));
|
|
|
|
printf(" --> %s", addr_buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
print_mask(int plen)
|
|
|
|
{
|
|
|
|
if (f_inet6 != NULL && strcmp(f_inet6, "cidr") == 0)
|
|
|
|
printf("/%d", plen);
|
|
|
|
else
|
|
|
|
printf(" prefixlen %d", plen);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
print_flags(int flags6)
|
|
|
|
{
|
|
|
|
if ((flags6 & IN6_IFF_ANYCAST) != 0)
|
|
|
|
printf(" anycast");
|
|
|
|
if ((flags6 & IN6_IFF_TENTATIVE) != 0)
|
|
|
|
printf(" tentative");
|
|
|
|
if ((flags6 & IN6_IFF_DUPLICATED) != 0)
|
|
|
|
printf(" duplicated");
|
|
|
|
if ((flags6 & IN6_IFF_DETACHED) != 0)
|
|
|
|
printf(" detached");
|
|
|
|
if ((flags6 & IN6_IFF_DEPRECATED) != 0)
|
|
|
|
printf(" deprecated");
|
|
|
|
if ((flags6 & IN6_IFF_AUTOCONF) != 0)
|
|
|
|
printf(" autoconf");
|
|
|
|
if ((flags6 & IN6_IFF_TEMPORARY) != 0)
|
|
|
|
printf(" temporary");
|
|
|
|
if ((flags6 & IN6_IFF_PREFER_SOURCE) != 0)
|
|
|
|
printf(" prefer_source");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
print_lifetime(const char *prepend, time_t px_time, struct timespec *now)
|
|
|
|
{
|
|
|
|
printf(" %s", prepend);
|
|
|
|
if (px_time == 0)
|
|
|
|
printf(" infty");
|
|
|
|
|
|
|
|
printf(" %s", px_time < now->tv_sec ? "0" : sec2str(px_time - now->tv_sec));
|
|
|
|
}
|
|
|
|
|
2023-05-10 13:58:21 +00:00
|
|
|
#ifdef WITHOUT_NETLINK
|
2004-12-08 19:18:07 +00:00
|
|
|
static void
|
2023-06-14 13:00:49 +00:00
|
|
|
in6_status(if_ctx *ctx, const struct ifaddrs *ifa)
|
2004-12-08 19:18:07 +00:00
|
|
|
{
|
2023-05-15 12:17:54 +00:00
|
|
|
struct sockaddr_in6 *sin, null_sin = {};
|
2004-12-08 19:18:07 +00:00
|
|
|
struct in6_ifreq ifr6;
|
|
|
|
int s6;
|
|
|
|
u_int32_t flags6;
|
|
|
|
struct in6_addrlifetime lifetime;
|
|
|
|
|
2023-06-14 13:21:17 +00:00
|
|
|
sin = satosin6(ifa->ifa_addr);
|
2004-12-08 19:18:07 +00:00
|
|
|
if (sin == NULL)
|
|
|
|
return;
|
|
|
|
|
2023-06-14 13:00:49 +00:00
|
|
|
strlcpy(ifr6.ifr_name, ctx->ifname, sizeof(ifr6.ifr_name));
|
2004-12-08 19:18:07 +00:00
|
|
|
if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
|
|
|
|
warn("socket(AF_INET6,SOCK_DGRAM)");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ifr6.ifr_addr = *sin;
|
|
|
|
if (ioctl(s6, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
|
|
|
|
warn("ioctl(SIOCGIFAFLAG_IN6)");
|
|
|
|
close(s6);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
flags6 = ifr6.ifr_ifru.ifru_flags6;
|
|
|
|
memset(&lifetime, 0, sizeof(lifetime));
|
|
|
|
ifr6.ifr_addr = *sin;
|
|
|
|
if (ioctl(s6, SIOCGIFALIFETIME_IN6, &ifr6) < 0) {
|
|
|
|
warn("ioctl(SIOCGIFALIFETIME_IN6)");
|
|
|
|
close(s6);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
lifetime = ifr6.ifr_ifru.ifru_lifetime;
|
|
|
|
close(s6);
|
|
|
|
|
2023-05-15 12:17:54 +00:00
|
|
|
print_addr(sin);
|
2004-12-08 19:18:07 +00:00
|
|
|
|
2007-02-24 23:55:46 +00:00
|
|
|
if (ifa->ifa_flags & IFF_POINTOPOINT) {
|
2023-06-14 13:21:17 +00:00
|
|
|
sin = satosin6(ifa->ifa_dstaddr);
|
2004-12-08 19:18:07 +00:00
|
|
|
/*
|
|
|
|
* some of the interfaces do not have valid destination
|
|
|
|
* address.
|
|
|
|
*/
|
2023-05-15 12:17:54 +00:00
|
|
|
if (sin != NULL && sin->sin6_family == AF_INET6)
|
|
|
|
print_p2p(sin);
|
2004-12-08 19:18:07 +00:00
|
|
|
}
|
|
|
|
|
2023-06-14 13:21:17 +00:00
|
|
|
sin = satosin6(ifa->ifa_netmask);
|
2007-02-24 23:55:46 +00:00
|
|
|
if (sin == NULL)
|
2004-12-08 19:18:07 +00:00
|
|
|
sin = &null_sin;
|
2023-05-15 12:17:54 +00:00
|
|
|
print_mask(prefix(&sin->sin6_addr, sizeof(struct in6_addr)));
|
2004-12-08 19:18:07 +00:00
|
|
|
|
2023-05-15 12:17:54 +00:00
|
|
|
print_flags(flags6);
|
2004-12-08 19:18:07 +00:00
|
|
|
|
2023-06-14 13:21:17 +00:00
|
|
|
if ((satosin6(ifa->ifa_addr))->sin6_scope_id)
|
2019-02-26 03:34:47 +00:00
|
|
|
printf(" scopeid 0x%x",
|
2023-06-14 13:21:17 +00:00
|
|
|
(satosin6(ifa->ifa_addr))->sin6_scope_id);
|
2004-12-08 19:18:07 +00:00
|
|
|
|
|
|
|
if (ip6lifetime && (lifetime.ia6t_preferred || lifetime.ia6t_expire)) {
|
2023-05-15 12:17:54 +00:00
|
|
|
struct timespec now;
|
|
|
|
|
|
|
|
clock_gettime(CLOCK_MONOTONIC_FAST, &now);
|
|
|
|
print_lifetime("pltime", lifetime.ia6t_preferred, &now);
|
|
|
|
print_lifetime("vltime", lifetime.ia6t_expire, &now);
|
2004-12-08 19:18:07 +00:00
|
|
|
}
|
|
|
|
|
2023-06-14 07:59:01 +00:00
|
|
|
print_vhid(ifa);
|
A major overhaul of the CARP implementation. The ip_carp.c was started
from scratch, copying needed functionality from the old implemenation
on demand, with a thorough review of all code. The main change is that
interface layer has been removed from the CARP. Now redundant addresses
are configured exactly on the interfaces, they run on.
The CARP configuration itself is, as before, configured and read via
SIOCSVH/SIOCGVH ioctls. A new prefix created with SIOCAIFADDR or
SIOCAIFADDR_IN6 may now be configured to a particular virtual host id,
which makes the prefix redundant.
ifconfig(8) semantics has been changed too: now one doesn't need
to clone carpXX interface, he/she should directly configure a vhid
on a Ethernet interface.
To supply vhid data from the kernel to an application the getifaddrs(8)
function had been changed to pass ifam_data with each address. [1]
The new implementation definitely closes all PRs related to carp(4)
being an interface, and may close several others. It also allows
to run a single redundant IP per interface.
Big thanks to Bjoern Zeeb for his help with inet6 part of patch, for
idea on using ifam_data and for several rounds of reviewing!
PR: kern/117000, kern/126945, kern/126714, kern/120130, kern/117448
Reviewed by: bz
Submitted by: bz [1]
2011-12-16 12:16:56 +00:00
|
|
|
|
2004-12-08 19:18:07 +00:00
|
|
|
putchar('\n');
|
|
|
|
}
|
|
|
|
|
2023-05-10 13:58:21 +00:00
|
|
|
#else
|
|
|
|
static void
|
|
|
|
show_lifetime(struct ifa_cacheinfo *ci)
|
|
|
|
{
|
|
|
|
struct timespec now;
|
|
|
|
uint32_t pl, vl;
|
|
|
|
|
|
|
|
if (ci == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
int count = ci->ifa_prefered != ND6_INFINITE_LIFETIME;
|
|
|
|
count += ci->ifa_valid != ND6_INFINITE_LIFETIME;
|
|
|
|
if (count == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
pl = (ci->ifa_prefered == ND6_INFINITE_LIFETIME) ? 0 : ci->ifa_prefered;
|
|
|
|
vl = (ci->ifa_valid == ND6_INFINITE_LIFETIME) ? 0 : ci->ifa_valid;
|
|
|
|
|
|
|
|
clock_gettime(CLOCK_MONOTONIC_FAST, &now);
|
|
|
|
print_lifetime("pltime", pl + now.tv_sec, &now);
|
|
|
|
print_lifetime("vltime", vl + now.tv_sec, &now);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-06-01 11:54:02 +00:00
|
|
|
in6_status_nl(if_ctx *ctx __unused, if_link_t *link __unused, if_addr_t *ifa)
|
2023-05-10 13:58:21 +00:00
|
|
|
{
|
|
|
|
int plen = ifa->ifa_prefixlen;
|
|
|
|
uint32_t scopeid;
|
|
|
|
|
|
|
|
if (ifa->ifa_local == NULL) {
|
|
|
|
/* Non-P2P address */
|
|
|
|
scopeid = satosin6(ifa->ifa_address)->sin6_scope_id;
|
|
|
|
print_addr(satosin6(ifa->ifa_address));
|
|
|
|
} else {
|
|
|
|
scopeid = satosin6(ifa->ifa_local)->sin6_scope_id;
|
|
|
|
print_addr(satosin6(ifa->ifa_local));
|
|
|
|
print_p2p(satosin6(ifa->ifa_address));
|
|
|
|
}
|
|
|
|
|
|
|
|
print_mask(plen);
|
|
|
|
print_flags(ifa->ifaf_flags);
|
|
|
|
|
|
|
|
if (scopeid != 0)
|
|
|
|
printf(" scopeid 0x%x", scopeid);
|
|
|
|
|
|
|
|
show_lifetime(ifa->ifa_cacheinfo);
|
|
|
|
|
|
|
|
if (ifa->ifaf_vhid != 0)
|
|
|
|
printf(" vhid %d", ifa->ifaf_vhid);
|
|
|
|
|
|
|
|
putchar('\n');
|
|
|
|
}
|
2023-05-20 11:53:46 +00:00
|
|
|
|
|
|
|
static struct in6_px *sin6tab_nl[] = {
|
|
|
|
&in6_del.addr, /* RIDADDR */
|
|
|
|
&in6_add.addr, /* ADDR */
|
|
|
|
NULL, /* MASK */
|
|
|
|
&in6_add.dst_addr, /* DSTADDR*/
|
|
|
|
};
|
|
|
|
|
2023-05-25 14:50:57 +00:00
|
|
|
static void
|
2023-06-01 11:54:02 +00:00
|
|
|
in6_copyaddr(if_ctx *ctx __unused, int to, int from)
|
2023-05-25 14:50:57 +00:00
|
|
|
{
|
|
|
|
sin6tab_nl[to]->addr = sin6tab_nl[from]->addr;
|
|
|
|
sin6tab_nl[to]->set = sin6tab_nl[from]->set;
|
|
|
|
}
|
|
|
|
|
2023-05-20 11:53:46 +00:00
|
|
|
static void
|
|
|
|
in6_getaddr(const char *addr_str, int which)
|
|
|
|
{
|
|
|
|
struct in6_px *px = sin6tab_nl[which];
|
|
|
|
|
|
|
|
px->set = true;
|
|
|
|
px->plen = 128;
|
|
|
|
if (which == ADDR) {
|
|
|
|
char *p = NULL;
|
|
|
|
if((p = strrchr(addr_str, '/')) != NULL) {
|
|
|
|
*p = '\0';
|
|
|
|
int plen = strtol(p + 1, NULL, 10);
|
|
|
|
if (plen < 0 || plen > 128)
|
|
|
|
errx(1, "%s: bad value", p + 1);
|
|
|
|
px->plen = plen;
|
|
|
|
explicit_prefix = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct addrinfo hints = { .ai_family = AF_INET6 };
|
|
|
|
struct addrinfo *res;
|
|
|
|
|
|
|
|
int error = getaddrinfo(addr_str, NULL, &hints, &res);
|
|
|
|
if (error != 0) {
|
|
|
|
if (inet_pton(AF_INET6, addr_str, &px->addr) != 1)
|
|
|
|
errx(1, "%s: bad value", addr_str);
|
|
|
|
} else {
|
|
|
|
struct sockaddr_in6 *sin6;
|
|
|
|
|
|
|
|
sin6 = (struct sockaddr_in6 *)(void *)res->ai_addr;
|
|
|
|
px->addr = sin6->sin6_addr;
|
|
|
|
freeaddrinfo(res);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
in6_exec_nl(if_ctx *ctx, unsigned long action, void *data)
|
|
|
|
{
|
|
|
|
struct in6_pdata *pdata = (struct in6_pdata *)data;
|
|
|
|
struct snl_writer nw = {};
|
|
|
|
|
|
|
|
snl_init_writer(ctx->io_ss, &nw);
|
|
|
|
struct nlmsghdr *hdr = snl_create_msg_request(&nw, action);
|
|
|
|
struct ifaddrmsg *ifahdr = snl_reserve_msg_object(&nw, struct ifaddrmsg);
|
|
|
|
|
|
|
|
ifahdr->ifa_family = AF_INET6;
|
|
|
|
ifahdr->ifa_prefixlen = pdata->addr.plen;
|
2023-06-13 06:22:29 +00:00
|
|
|
ifahdr->ifa_index = if_nametoindex_nl(ctx->io_ss, ctx->ifname);
|
2023-05-20 11:53:46 +00:00
|
|
|
|
|
|
|
snl_add_msg_attr_ip6(&nw, IFA_LOCAL, &pdata->addr.addr);
|
|
|
|
if (action == NL_RTM_NEWADDR && pdata->dst_addr.set)
|
|
|
|
snl_add_msg_attr_ip6(&nw, IFA_ADDRESS, &pdata->dst_addr.addr);
|
|
|
|
|
|
|
|
struct ifa_cacheinfo ci = {
|
|
|
|
.ifa_prefered = pdata->lifetime.ia6t_pltime,
|
|
|
|
.ifa_valid = pdata->lifetime.ia6t_vltime,
|
|
|
|
};
|
|
|
|
snl_add_msg_attr(&nw, IFA_CACHEINFO, sizeof(ci), &ci);
|
|
|
|
|
|
|
|
int off = snl_add_msg_attr_nested(&nw, IFA_FREEBSD);
|
|
|
|
snl_add_msg_attr_u32(&nw, IFAF_FLAGS, pdata->flags);
|
|
|
|
if (pdata->vhid != 0)
|
|
|
|
snl_add_msg_attr_u32(&nw, IFAF_VHID, pdata->vhid);
|
|
|
|
snl_end_attr_nested(&nw, off);
|
|
|
|
|
2023-10-16 09:48:57 +00:00
|
|
|
if (! (hdr = snl_finalize_msg(&nw)) || !snl_send_message(ctx->io_ss, hdr))
|
2023-05-20 11:53:46 +00:00
|
|
|
return (0);
|
|
|
|
|
|
|
|
struct snl_errmsg_data e = {};
|
|
|
|
snl_read_reply_code(ctx->io_ss, hdr->nlmsg_seq, &e);
|
|
|
|
|
|
|
|
return (e.error);
|
|
|
|
}
|
2023-05-10 13:58:21 +00:00
|
|
|
#endif
|
|
|
|
|
2023-05-20 11:53:46 +00:00
|
|
|
#ifdef WITHOUT_NETLINK
|
2004-12-08 19:18:07 +00:00
|
|
|
static struct sockaddr_in6 *sin6tab[] = {
|
2023-05-23 11:04:09 +00:00
|
|
|
&in6_ridreq.ifr_addr, &in6_addreq.ifra_addr,
|
|
|
|
&in6_addreq.ifra_prefixmask, &in6_addreq.ifra_dstaddr
|
2004-12-08 19:18:07 +00:00
|
|
|
};
|
|
|
|
|
2023-05-25 14:50:57 +00:00
|
|
|
static void
|
2023-06-14 13:21:17 +00:00
|
|
|
in6_copyaddr(if_ctx *ctx __unused, int to, int from)
|
2023-05-25 14:50:57 +00:00
|
|
|
{
|
|
|
|
memcpy(sin6tab[to], sin6tab[from], sizeof(struct sockaddr_in6));
|
|
|
|
}
|
|
|
|
|
2004-12-08 19:18:07 +00:00
|
|
|
static void
|
|
|
|
in6_getprefix(const char *plen, int which)
|
|
|
|
{
|
|
|
|
struct sockaddr_in6 *sin = sin6tab[which];
|
|
|
|
u_char *cp;
|
|
|
|
int len = atoi(plen);
|
|
|
|
|
|
|
|
if ((len < 0) || (len > 128))
|
|
|
|
errx(1, "%s: bad value", plen);
|
|
|
|
sin->sin6_len = sizeof(*sin);
|
|
|
|
if (which != MASK)
|
|
|
|
sin->sin6_family = AF_INET6;
|
|
|
|
if ((len == 0) || (len == 128)) {
|
|
|
|
memset(&sin->sin6_addr, 0xff, sizeof(struct in6_addr));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
memset((void *)&sin->sin6_addr, 0x00, sizeof(sin->sin6_addr));
|
|
|
|
for (cp = (u_char *)&sin->sin6_addr; len > 7; len -= 8)
|
|
|
|
*cp++ = 0xff;
|
|
|
|
*cp = 0xff << (8 - len);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
in6_getaddr(const char *s, int which)
|
|
|
|
{
|
|
|
|
struct sockaddr_in6 *sin = sin6tab[which];
|
|
|
|
struct addrinfo hints, *res;
|
|
|
|
int error = -1;
|
|
|
|
|
|
|
|
sin->sin6_len = sizeof(*sin);
|
|
|
|
if (which != MASK)
|
|
|
|
sin->sin6_family = AF_INET6;
|
|
|
|
|
|
|
|
if (which == ADDR) {
|
|
|
|
char *p = NULL;
|
|
|
|
if((p = strrchr(s, '/')) != NULL) {
|
|
|
|
*p = '\0';
|
|
|
|
in6_getprefix(p + 1, MASK);
|
|
|
|
explicit_prefix = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sin->sin6_family == AF_INET6) {
|
|
|
|
bzero(&hints, sizeof(struct addrinfo));
|
|
|
|
hints.ai_family = AF_INET6;
|
|
|
|
error = getaddrinfo(s, NULL, &hints, &res);
|
Various Coverity fixes in ifconfig(8)
* Exit early if kldload(2) fails (1011259). This is the only change that
affects ifconfig's behavior.
* Close memory and resource leaks (1305624, 1305205, 1007100)
* Mark usage() as _Noreturn (1305806, 1305750)
* Fix some dereference after null checks (1011474, 270774)
Reported by: Coverity
CID: 1305624, 1305205, 1007100, 1305806, 1305750, 1011474,
CID: 270774, 1011259
Reviewed by: cem
MFC after: 3 weeks
Sponsored by: Spectra Logic Corp
Differential Revision: https://reviews.freebsd.org/D10587
2017-05-03 17:21:01 +00:00
|
|
|
if (error != 0) {
|
|
|
|
if (inet_pton(AF_INET6, s, &sin->sin6_addr) != 1)
|
|
|
|
errx(1, "%s: bad value", s);
|
|
|
|
} else {
|
|
|
|
bcopy(res->ai_addr, sin, res->ai_addrlen);
|
|
|
|
freeaddrinfo(res);
|
|
|
|
}
|
2004-12-08 19:18:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
prefix(void *val, int size)
|
|
|
|
{
|
2015-02-02 14:37:45 +00:00
|
|
|
u_char *name = (u_char *)val;
|
|
|
|
int byte, bit, plen = 0;
|
2004-12-08 19:18:07 +00:00
|
|
|
|
2015-02-02 14:37:45 +00:00
|
|
|
for (byte = 0; byte < size; byte++, plen += 8)
|
|
|
|
if (name[byte] != 0xff)
|
|
|
|
break;
|
2004-12-08 19:18:07 +00:00
|
|
|
if (byte == size)
|
|
|
|
return (plen);
|
|
|
|
for (bit = 7; bit != 0; bit--, plen++)
|
2015-02-02 14:37:45 +00:00
|
|
|
if (!(name[byte] & (1 << bit)))
|
|
|
|
break;
|
|
|
|
for (; bit != 0; bit--)
|
|
|
|
if (name[byte] & (1 << bit))
|
|
|
|
return(0);
|
|
|
|
byte++;
|
|
|
|
for (; byte < size; byte++)
|
|
|
|
if (name[byte])
|
|
|
|
return(0);
|
|
|
|
return (plen);
|
2004-12-08 19:18:07 +00:00
|
|
|
}
|
2023-05-23 11:04:09 +00:00
|
|
|
#endif
|
2004-12-08 19:18:07 +00:00
|
|
|
|
|
|
|
static char *
|
|
|
|
sec2str(time_t total)
|
|
|
|
{
|
|
|
|
static char result[256];
|
|
|
|
int days, hours, mins, secs;
|
|
|
|
int first = 1;
|
|
|
|
char *p = result;
|
|
|
|
|
|
|
|
if (0) {
|
|
|
|
days = total / 3600 / 24;
|
|
|
|
hours = (total / 3600) % 24;
|
|
|
|
mins = (total / 60) % 60;
|
|
|
|
secs = total % 60;
|
|
|
|
|
|
|
|
if (days) {
|
|
|
|
first = 0;
|
|
|
|
p += sprintf(p, "%dd", days);
|
|
|
|
}
|
|
|
|
if (!first || hours) {
|
|
|
|
first = 0;
|
|
|
|
p += sprintf(p, "%dh", hours);
|
|
|
|
}
|
|
|
|
if (!first || mins) {
|
|
|
|
first = 0;
|
|
|
|
p += sprintf(p, "%dm", mins);
|
|
|
|
}
|
|
|
|
sprintf(p, "%ds", secs);
|
|
|
|
} else
|
|
|
|
sprintf(result, "%lu", (unsigned long)total);
|
|
|
|
|
|
|
|
return(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-05-23 17:02:12 +00:00
|
|
|
in6_postproc(if_ctx *ctx, int newaddr __unused,
|
2021-10-28 14:32:31 +00:00
|
|
|
int ifflags __unused)
|
2004-12-08 19:18:07 +00:00
|
|
|
{
|
|
|
|
if (explicit_prefix == 0) {
|
|
|
|
/* Aggregatable address architecture defines all prefixes
|
|
|
|
are 64. So, it is convenient to set prefixlen to 64 if
|
|
|
|
it is not specified. */
|
2023-05-23 17:02:12 +00:00
|
|
|
setifprefixlen(ctx, "64", 0);
|
2004-12-08 19:18:07 +00:00
|
|
|
/* in6_getprefix("64", MASK) if MASK is available here... */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-06-13 06:19:50 +00:00
|
|
|
in6_status_tunnel(if_ctx *ctx)
|
2004-12-08 19:18:07 +00:00
|
|
|
{
|
|
|
|
char src[NI_MAXHOST];
|
|
|
|
char dst[NI_MAXHOST];
|
|
|
|
struct in6_ifreq in6_ifr;
|
|
|
|
const struct sockaddr *sa = (const struct sockaddr *) &in6_ifr.ifr_addr;
|
|
|
|
|
|
|
|
memset(&in6_ifr, 0, sizeof(in6_ifr));
|
2023-06-13 06:22:29 +00:00
|
|
|
strlcpy(in6_ifr.ifr_name, ctx->ifname, sizeof(in6_ifr.ifr_name));
|
2004-12-08 19:18:07 +00:00
|
|
|
|
2023-06-13 06:19:50 +00:00
|
|
|
if (ioctl_ctx(ctx, SIOCGIFPSRCADDR_IN6, (caddr_t)&in6_ifr) < 0)
|
2004-12-08 19:18:07 +00:00
|
|
|
return;
|
2005-06-16 19:37:09 +00:00
|
|
|
if (sa->sa_family != AF_INET6)
|
|
|
|
return;
|
2005-05-13 16:31:11 +00:00
|
|
|
if (getnameinfo(sa, sa->sa_len, src, sizeof(src), 0, 0,
|
|
|
|
NI_NUMERICHOST) != 0)
|
2004-12-08 19:18:07 +00:00
|
|
|
src[0] = '\0';
|
|
|
|
|
2023-06-13 06:19:50 +00:00
|
|
|
if (ioctl_ctx(ctx, SIOCGIFPDSTADDR_IN6, (caddr_t)&in6_ifr) < 0)
|
2004-12-08 19:18:07 +00:00
|
|
|
return;
|
2005-06-16 19:37:09 +00:00
|
|
|
if (sa->sa_family != AF_INET6)
|
|
|
|
return;
|
2005-05-13 16:31:11 +00:00
|
|
|
if (getnameinfo(sa, sa->sa_len, dst, sizeof(dst), 0, 0,
|
|
|
|
NI_NUMERICHOST) != 0)
|
2004-12-08 19:18:07 +00:00
|
|
|
dst[0] = '\0';
|
|
|
|
|
|
|
|
printf("\ttunnel inet6 %s --> %s\n", src, dst);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-06-13 06:19:50 +00:00
|
|
|
in6_set_tunnel(if_ctx *ctx, struct addrinfo *srcres, struct addrinfo *dstres)
|
2004-12-08 19:18:07 +00:00
|
|
|
{
|
2023-06-14 13:21:17 +00:00
|
|
|
struct in6_aliasreq in6_req = {};
|
2004-12-08 19:18:07 +00:00
|
|
|
|
2023-06-14 13:21:17 +00:00
|
|
|
strlcpy(in6_req.ifra_name, ctx->ifname, sizeof(in6_req.ifra_name));
|
|
|
|
memcpy(&in6_req.ifra_addr, srcres->ai_addr, srcres->ai_addr->sa_len);
|
|
|
|
memcpy(&in6_req.ifra_dstaddr, dstres->ai_addr,
|
2004-12-08 19:18:07 +00:00
|
|
|
dstres->ai_addr->sa_len);
|
|
|
|
|
2023-06-14 13:21:17 +00:00
|
|
|
if (ioctl_ctx(ctx, SIOCSIFPHYADDR_IN6, &in6_req) < 0)
|
2004-12-08 19:18:07 +00:00
|
|
|
warn("SIOCSIFPHYADDR_IN6");
|
|
|
|
}
|
|
|
|
|
2023-05-19 10:18:43 +00:00
|
|
|
static void
|
|
|
|
in6_set_vhid(int vhid)
|
|
|
|
{
|
2023-05-20 11:53:46 +00:00
|
|
|
#ifdef WITHOUT_NETLINK
|
2023-05-19 10:18:43 +00:00
|
|
|
in6_addreq.ifra_vhid = vhid;
|
2023-05-20 11:53:46 +00:00
|
|
|
#else
|
|
|
|
in6_add.vhid = (uint32_t)vhid;
|
|
|
|
#endif
|
2023-05-19 10:18:43 +00:00
|
|
|
}
|
|
|
|
|
2004-12-08 19:18:07 +00:00
|
|
|
static struct cmd inet6_cmds[] = {
|
|
|
|
DEF_CMD_ARG("prefixlen", setifprefixlen),
|
|
|
|
DEF_CMD("anycast", IN6_IFF_ANYCAST, setip6flags),
|
|
|
|
DEF_CMD("tentative", IN6_IFF_TENTATIVE, setip6flags),
|
|
|
|
DEF_CMD("-tentative", -IN6_IFF_TENTATIVE, setip6flags),
|
|
|
|
DEF_CMD("deprecated", IN6_IFF_DEPRECATED, setip6flags),
|
|
|
|
DEF_CMD("-deprecated", -IN6_IFF_DEPRECATED, setip6flags),
|
|
|
|
DEF_CMD("autoconf", IN6_IFF_AUTOCONF, setip6flags),
|
|
|
|
DEF_CMD("-autoconf", -IN6_IFF_AUTOCONF, setip6flags),
|
2014-09-09 10:52:50 +00:00
|
|
|
DEF_CMD("prefer_source",IN6_IFF_PREFER_SOURCE, setip6flags),
|
|
|
|
DEF_CMD("-prefer_source",-IN6_IFF_PREFER_SOURCE,setip6flags),
|
2009-09-12 22:08:20 +00:00
|
|
|
DEF_CMD("accept_rtadv", ND6_IFF_ACCEPT_RTADV, setnd6flags),
|
|
|
|
DEF_CMD("-accept_rtadv",-ND6_IFF_ACCEPT_RTADV, setnd6flags),
|
- Accept Router Advertisement messages even when net.inet6.ip6.forwarding=1.
- A new per-interface knob IFF_ND6_NO_RADR and sysctl IPV6CTL_NO_RADR.
This controls if accepting a route in an RA message as the default route.
The default value for each interface can be set by net.inet6.ip6.no_radr.
The system wide default value is 0.
- A new sysctl: net.inet6.ip6.norbit_raif. This controls if setting R-bit in
NA on RA accepting interfaces. The default is 0 (R-bit is set based on
net.inet6.ip6.forwarding).
Background:
IPv6 host/router model suggests a router sends an RA and a host accepts it for
router discovery. Because of that, KAME implementation does not allow
accepting RAs when net.inet6.ip6.forwarding=1. Accepting RAs on a router can
make the routing table confused since it can change the default router
unintentionally.
However, in practice there are cases where we cannot distinguish a host from
a router clearly. For example, a customer edge router often works as a host
against the ISP, and as a router against the LAN at the same time. Another
example is a complex network configurations like an L2TP tunnel for IPv6
connection to Internet over an Ethernet link with another native IPv6 subnet.
In this case, the physical interface for the native IPv6 subnet works as a
host, and the pseudo-interface for L2TP works as the default IP forwarding
route.
Problem:
Disabling processing RA messages when net.inet6.ip6.forwarding=1 and
accepting them when net.inet6.ip6.forward=0 cause the following practical
issues:
- A router cannot perform SLAAC. It becomes a problem if a box has
multiple interfaces and you want to use SLAAC on some of them, for
example. A customer edge router for IPv6 Internet access service
using an IPv6-over-IPv6 tunnel sometimes needs SLAAC on the
physical interface for administration purpose; updating firmware
and so on (link-local addresses can be used there, but GUAs by
SLAAC are often used for scalability).
- When a host has multiple IPv6 interfaces and it receives multiple RAs on
them, controlling the default route is difficult. Router preferences
defined in RFC 4191 works only when the routers on the links are
under your control.
Details of Implementation Changes:
Router Advertisement messages will be accepted even when
net.inet6.ip6.forwarding=1. More precisely, the conditions are as
follow:
(ACCEPT_RTADV && !NO_RADR && !ip6.forwarding)
=> Normal RA processing on that interface. (as IPv6 host)
(ACCEPT_RTADV && (NO_RADR || ip6.forwarding))
=> Accept RA but add the router to the defroute list with
rtlifetime=0 unconditionally. This effectively prevents
from setting the received router address as the box's
default route.
(!ACCEPT_RTADV)
=> No RA processing on that interface.
ACCEPT_RTADV and NO_RADR are per-interface knob. In short, all interface
are classified as "RA-accepting" or not. An RA-accepting interface always
processes RA messages regardless of ip6.forwarding. The difference caused by
NO_RADR or ip6.forwarding is whether the RA source address is considered as
the default router or not.
R-bit in NA on the RA accepting interfaces is set based on
net.inet6.ip6.forwarding. While RFC 6204 W-1 rule (for CPE case) suggests
a router should disable the R-bit completely even when the box has
net.inet6.ip6.forwarding=1, I believe there is no technical reason with
doing so. This behavior can be set by a new sysctl net.inet6.ip6.norbit_raif
(the default is 0).
Usage:
# ifconfig fxp0 inet6 accept_rtadv
=> accept RA on fxp0
# ifconfig fxp0 inet6 accept_rtadv no_radr
=> accept RA on fxp0 but ignore default route information in it.
# sysctl net.inet6.ip6.norbit_no_radr=1
=> R-bit in NAs on RA accepting interfaces will always be set to 0.
2011-06-06 02:14:23 +00:00
|
|
|
DEF_CMD("no_radr", ND6_IFF_NO_RADR, setnd6flags),
|
|
|
|
DEF_CMD("-no_radr", -ND6_IFF_NO_RADR, setnd6flags),
|
2009-09-12 22:08:20 +00:00
|
|
|
DEF_CMD("defaultif", 1, setnd6defif),
|
|
|
|
DEF_CMD("-defaultif", -1, setnd6defif),
|
|
|
|
DEF_CMD("ifdisabled", ND6_IFF_IFDISABLED, setnd6flags),
|
|
|
|
DEF_CMD("-ifdisabled", -ND6_IFF_IFDISABLED, setnd6flags),
|
|
|
|
DEF_CMD("nud", ND6_IFF_PERFORMNUD, setnd6flags),
|
|
|
|
DEF_CMD("-nud", -ND6_IFF_PERFORMNUD, setnd6flags),
|
|
|
|
DEF_CMD("auto_linklocal",ND6_IFF_AUTO_LINKLOCAL,setnd6flags),
|
|
|
|
DEF_CMD("-auto_linklocal",-ND6_IFF_AUTO_LINKLOCAL,setnd6flags),
|
2013-01-09 18:18:08 +00:00
|
|
|
DEF_CMD("no_prefer_iface",ND6_IFF_NO_PREFER_IFACE,setnd6flags),
|
|
|
|
DEF_CMD("-no_prefer_iface",-ND6_IFF_NO_PREFER_IFACE,setnd6flags),
|
2015-03-05 21:27:49 +00:00
|
|
|
DEF_CMD("no_dad", ND6_IFF_NO_DAD, setnd6flags),
|
|
|
|
DEF_CMD("-no_dad", -ND6_IFF_NO_DAD, setnd6flags),
|
2004-12-08 19:18:07 +00:00
|
|
|
DEF_CMD_ARG("pltime", setip6pltime),
|
|
|
|
DEF_CMD_ARG("vltime", setip6vltime),
|
|
|
|
DEF_CMD("eui64", 0, setip6eui64),
|
2019-03-06 23:31:42 +00:00
|
|
|
#ifdef EXPERIMENTAL
|
|
|
|
DEF_CMD("ipv6_only", ND6_IFF_IPV6_ONLY_MANUAL,setnd6flags),
|
|
|
|
DEF_CMD("-ipv6_only", -ND6_IFF_IPV6_ONLY_MANUAL,setnd6flags),
|
|
|
|
#endif
|
2004-12-08 19:18:07 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct afswtch af_inet6 = {
|
|
|
|
.af_name = "inet6",
|
|
|
|
.af_af = AF_INET6,
|
2023-05-10 13:58:21 +00:00
|
|
|
#ifdef WITHOUT_NETLINK
|
2004-12-08 19:18:07 +00:00
|
|
|
.af_status = in6_status,
|
2023-05-10 13:58:21 +00:00
|
|
|
#else
|
2023-05-23 17:02:12 +00:00
|
|
|
.af_status = in6_status_nl,
|
2023-05-10 13:58:21 +00:00
|
|
|
#endif
|
2004-12-08 19:18:07 +00:00
|
|
|
.af_getaddr = in6_getaddr,
|
2023-05-25 14:50:57 +00:00
|
|
|
.af_copyaddr = in6_copyaddr,
|
2023-05-20 11:53:46 +00:00
|
|
|
#ifdef WITHOUT_NETLINK
|
2004-12-08 19:18:07 +00:00
|
|
|
.af_getprefix = in6_getprefix,
|
2023-05-20 11:53:46 +00:00
|
|
|
#endif
|
2011-06-05 11:37:20 +00:00
|
|
|
.af_other_status = nd6_status,
|
2004-12-08 19:18:07 +00:00
|
|
|
.af_postproc = in6_postproc,
|
|
|
|
.af_status_tunnel = in6_status_tunnel,
|
|
|
|
.af_settunnel = in6_set_tunnel,
|
2023-05-19 10:18:43 +00:00
|
|
|
.af_setvhid = in6_set_vhid,
|
2023-05-20 11:53:46 +00:00
|
|
|
#ifdef WITHOUT_NETLINK
|
2004-12-08 19:18:07 +00:00
|
|
|
.af_difaddr = SIOCDIFADDR_IN6,
|
|
|
|
.af_aifaddr = SIOCAIFADDR_IN6,
|
2007-02-03 03:40:33 +00:00
|
|
|
.af_ridreq = &in6_addreq,
|
2004-12-08 19:18:07 +00:00
|
|
|
.af_addreq = &in6_addreq,
|
2023-05-20 11:53:46 +00:00
|
|
|
.af_exec = af_exec_ioctl,
|
|
|
|
#else
|
|
|
|
.af_difaddr = NL_RTM_DELADDR,
|
|
|
|
.af_aifaddr = NL_RTM_NEWADDR,
|
|
|
|
.af_ridreq = &in6_add,
|
|
|
|
.af_addreq = &in6_add,
|
|
|
|
.af_exec = in6_exec_nl,
|
|
|
|
#endif
|
2004-12-08 19:18:07 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
2023-06-01 11:54:02 +00:00
|
|
|
in6_Lopt_cb(const char *arg __unused)
|
2004-12-08 19:18:07 +00:00
|
|
|
{
|
|
|
|
ip6lifetime++; /* print IPv6 address lifetime */
|
|
|
|
}
|
2015-02-02 14:37:45 +00:00
|
|
|
static struct option in6_Lopt = {
|
|
|
|
.opt = "L",
|
|
|
|
.opt_usage = "[-L]",
|
|
|
|
.cb = in6_Lopt_cb
|
|
|
|
};
|
2004-12-08 19:18:07 +00:00
|
|
|
|
|
|
|
static __constructor void
|
|
|
|
inet6_ctor(void)
|
|
|
|
{
|
2009-06-23 23:49:52 +00:00
|
|
|
size_t i;
|
2004-12-08 19:18:07 +00:00
|
|
|
|
2011-07-18 10:29:16 +00:00
|
|
|
#ifndef RESCUE
|
2011-05-31 14:40:21 +00:00
|
|
|
if (!feature_present("inet6"))
|
|
|
|
return;
|
2011-07-18 10:29:16 +00:00
|
|
|
#endif
|
2011-05-31 14:40:21 +00:00
|
|
|
|
2015-09-27 07:51:18 +00:00
|
|
|
for (i = 0; i < nitems(inet6_cmds); i++)
|
2004-12-08 19:18:07 +00:00
|
|
|
cmd_register(&inet6_cmds[i]);
|
|
|
|
af_register(&af_inet6);
|
|
|
|
opt_register(&in6_Lopt);
|
|
|
|
}
|