summaryrefslogtreecommitdiffstats
path: root/sbin/ifconfig
diff options
context:
space:
mode:
authorshin <shin@FreeBSD.org>1999-12-07 17:39:16 +0000
committershin <shin@FreeBSD.org>1999-12-07 17:39:16 +0000
commit70f0bdf6818a73c858bc47a23afc1e9d7c56d716 (patch)
tree446280db4239de7d7d9030c47d2c30515a265a54 /sbin/ifconfig
parent7bdf4b7db0db632bec3b1040d83cdfbdb35e59cd (diff)
downloadFreeBSD-src-70f0bdf6818a73c858bc47a23afc1e9d7c56d716.zip
FreeBSD-src-70f0bdf6818a73c858bc47a23afc1e9d7c56d716.tar.gz
udp IPv6 support, IPv6/IPv4 tunneling support in kernel,
packet divert at kernel for IPv6/IPv4 translater daemon This includes queue related patch submitted by jburkhol@home.com. Submitted by: queue related patch from jburkhol@home.com Reviewed by: freebsd-arch, cvs-committers Obtained from: KAME project
Diffstat (limited to 'sbin/ifconfig')
-rw-r--r--sbin/ifconfig/Makefile1
-rw-r--r--sbin/ifconfig/ifconfig.829
-rw-r--r--sbin/ifconfig/ifconfig.c314
3 files changed, 336 insertions, 8 deletions
diff --git a/sbin/ifconfig/Makefile b/sbin/ifconfig/Makefile
index b1fe95b..385946d 100644
--- a/sbin/ifconfig/Makefile
+++ b/sbin/ifconfig/Makefile
@@ -7,6 +7,7 @@ SRCS= ifconfig.c
#comment out to exclude SIOC[GS]IFMEDIA support
SRCS+= ifmedia.c
CFLAGS+=-DUSE_IF_MEDIA
+#CFLAGS+=-DINET6
#comment out to exclude SIOC[GS]ETVLAN support
SRCS+= ifvlan.c
diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8
index a2b399a..6defcd4 100644
--- a/sbin/ifconfig/ifconfig.8
+++ b/sbin/ifconfig/ifconfig.8
@@ -109,6 +109,7 @@ with different naming schemes, specifying the address family is recommended.
The address or protocol families currently
supported are
.Dq inet ,
+.Dq inet6 ,
.Dq atalk ,
.\" .Dq iso ,
and
@@ -135,6 +136,13 @@ This is sometimes useful when changing network numbers, and
one wishes to accept packets addressed to the old interface.
If the alias is on the same subnet as the first network adress
for this interface, a netmask of 0xffffffff has to be specified.
+.It Cm anycast
+(Inet6 only)
+Specify that the address configured is an anycast address.
+Based on the current specification,
+only routers may configure anycast addresses.
+Anycast address will not be used as source address of any of outgoing
+IPv6 packets.
.It Cm arp
Enable the use of the Address Resolution Protocol in mapping
between network level addresses and link level addresses (default).
@@ -279,6 +287,16 @@ and 0's for the host part.
The mask should contain at least the standard network portion,
and the subnet field should be contiguous with the network
portion.
+.It Cm prefixlen Ar len
+(Inet6 only)
+Specify that
+.Ar len
+bits are reserved for subdividing networks into sub-networks.
+The
+.Ar len
+must be integer, and for syntactical reason it must be between 0 to 128.
+It is almost always 64 under the current IPv6 assignment rule.
+If the parameter is ommitted, 64 is used.
.\" see
.\" Xr eon 5 .
.\" .It Cm nsellength Ar n
@@ -345,6 +363,11 @@ will report only the details specific to that protocol family.
If the driver does supports the media selection system, the supported
media list will be included in the output.
.Pp
+If
+.Fl L
+flag is supplied, address lifetime is dislayed for IPv6 addresses,
+as time offset string.
+.Pp
Optionally, the
.Fl a
flag may be used instead of an interface name. This flag instructs
@@ -375,6 +398,12 @@ it (or have need for it).
Messages indicating the specified interface does not exist, the
requested address is unknown, or the user is not privileged and
tried to alter an interface's configuration.
+.Sh BUGS
+IPv6 link-local addresses are required for several basic communication
+between IPv6 node. If they are deleted by
+.Nm ifconfig
+manually, the kernel might show very strange behavior.
+So, such manuall deletions are strongly discouraged.
.Sh SEE ALSO
.Xr netstat 1 ,
.Xr netintro 4 ,
diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c
index 00fb30f..32c7ee8 100644
--- a/sbin/ifconfig/ifconfig.c
+++ b/sbin/ifconfig/ifconfig.c
@@ -96,6 +96,10 @@ static const char rcsid[] =
struct ifreq ifr, ridreq;
struct ifaliasreq addreq;
+#ifdef INET6
+struct in6_ifreq in6_ridreq;
+struct in6_aliasreq in6_addreq;
+#endif
struct sockaddr_in netmask;
struct netrange at_nr; /* AppleTalk net range */
@@ -108,9 +112,16 @@ int setipdst;
int doalias;
int clearaddr;
int newaddr = 1;
+#ifdef INET6
+static int ip6lifetime;
+#endif
struct afswtch;
+#ifdef INET6
+char ntop_buf[INET6_ADDRSTRLEN]; /*inet_ntop()*/
+#endif
+
void Perror __P((const char *cmd));
void checkatrange __P((struct sockaddr_at *));
int ifconfig __P((int argc, char *const *argv, const struct afswtch *afp));
@@ -123,9 +134,19 @@ void status __P((const struct afswtch *afp, int addrcount,
void usage __P((void));
void ifmaybeload __P((char *name));
+#ifdef INET6
+int prefix __P((void *, int));
+static char *sec2str __P((time_t));
+int explicit_prefix = 0;
+#endif
+
typedef void c_func __P((const char *cmd, int arg, int s, const struct afswtch *afp));
c_func setatphase, setatrange;
c_func setifaddr, setifbroadaddr, setifdstaddr, setifnetmask;
+#ifdef INET6
+c_func setifprefixlen;
+c_func setip6flags;
+#endif
c_func setifipdst;
c_func setifflags, setifmetric, setifmtu;
@@ -153,6 +174,12 @@ struct cmd {
{ "-swabips", -EN_SWABIPS, setifflags },
#endif
{ "netmask", NEXTARG, setifnetmask },
+#ifdef INET6
+ { "prefixlen", NEXTARG, setifprefixlen },
+ { "anycast", IN6_IFF_ANYCAST, setip6flags },
+ { "tentative", IN6_IFF_TENTATIVE, setip6flags },
+ { "-tentative", -IN6_IFF_TENTATIVE, setip6flags },
+#endif
{ "range", NEXTARG, setatrange },
{ "phase", NEXTARG, setatphase },
{ "metric", NEXTARG, setifmetric },
@@ -188,10 +215,16 @@ struct cmd {
*/
typedef void af_status __P((int, struct rt_addrinfo *));
typedef void af_getaddr __P((const char *, int));
+typedef void af_getprefix __P((const char *, int));
af_status in_status, ipx_status, at_status, ether_status;
af_getaddr in_getaddr, ipx_getaddr, at_getaddr;
+#ifdef INET6
+af_status in6_status;
+af_getaddr in6_getaddr;
+af_getprefix in6_getprefix;
+#endif /*INET6*/
#ifdef NS
af_status xns_status;
af_getaddr xns_getaddr;
@@ -204,29 +237,35 @@ struct afswtch {
short af_af;
af_status *af_status;
af_getaddr *af_getaddr;
+ af_getprefix *af_getprefix;
u_long af_difaddr;
u_long af_aifaddr;
caddr_t af_ridreq;
caddr_t af_addreq;
} afs[] = {
#define C(x) ((caddr_t) &x)
- { "inet", AF_INET, in_status, in_getaddr,
+ { "inet", AF_INET, in_status, in_getaddr, NULL,
SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
- { "ipx", AF_IPX, ipx_status, ipx_getaddr,
+#ifdef INET6
+ { "inet6", AF_INET6, in6_status, in6_getaddr, in6_getprefix,
+ SIOCDIFADDR_IN6, SIOCAIFADDR_IN6,
+ C(in6_ridreq), C(in6_addreq) },
+#endif /*INET6*/
+ { "ipx", AF_IPX, ipx_status, ipx_getaddr, NULL,
SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
- { "atalk", AF_APPLETALK, at_status, at_getaddr,
+ { "atalk", AF_APPLETALK, at_status, at_getaddr, NULL,
SIOCDIFADDR, SIOCAIFADDR, C(addreq), C(addreq) },
#ifdef NS
- { "ns", AF_NS, xns_status, xns_getaddr,
+ { "ns", AF_NS, xns_status, xns_getaddr, NULL,
SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
#endif
- { "ether", AF_INET, ether_status, NULL }, /* XXX not real!! */
+ { "ether", AF_INET, ether_status, NULL, NULL }, /* XXX not real!! */
#if 0 /* XXX conflicts with the media command */
#ifdef USE_IF_MEDIA
- { "media", AF_INET, media_status, NULL }, /* XXX not real!! */
+ { "media", AF_INET, media_status, NULL, NULL, }, /* XXX not real!! */
#endif
#ifdef USE_VLANS
- { "vlan", AF_INET, media_status, NULL }, /* XXX not real!! */
+ { "vlan", AF_INET, media_status, NULL, NULL, }, /* XXX not real!! */
#endif
#endif
{ 0, 0, 0, 0 }
@@ -262,11 +301,19 @@ rt_xaddrs(cp, cplim, rtinfo)
void
usage()
{
+#ifndef INET6
fprintf(stderr, "%s\n%s\n%s\n%s\n",
"usage: ifconfig interface address_family [address [dest_address]]",
" [parameters]",
" ifconfig -a [-d] [-u] [address_family]",
" ifconfig -l [-d] [-u] [address_family]");
+#else
+ fprintf(stderr, "%s\n%s\n%s\n%s\n",
+ "usage: ifconfig [-L] interface address_family [address [dest_address]]",
+ " [parameters]",
+ " ifconfig -a [-L] [-d] [-u] [address_family]",
+ " ifconfig -l [-d] [-u] [address_family]");
+#endif
exit(1);
}
@@ -291,11 +338,20 @@ main(argc, argv)
/* Parse leading line options */
all = downonly = uponly = namesonly = 0;
- while ((c = getopt(argc, argv, "adlmu")) != -1) {
+ while ((c = getopt(argc, argv, "adlmu"
+#ifdef INET6
+ "L"
+#endif
+ )) != -1) {
switch (c) {
case 'a': /* scan all interfaces */
all++;
break;
+#ifdef INET6
+ case 'L':
+ ip6lifetime++; /* print IPv6 adress lifetime */
+ break;
+#endif
case 'l': /* scan interface names only */
namesonly++;
break;
@@ -502,6 +558,15 @@ ifconfig(argc, argv, afp)
}
argc--, argv++;
}
+#ifdef INET6
+ if (ifr.ifr_addr.sa_family == AF_INET6 && 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. */
+ setifprefixlen("64", 0, s, afp);
+ /* in6_getprefix("64", MASK) if MASK is available here... */
+ }
+#endif
if (setipdst && ifr.ifr_addr.sa_family == AF_IPX) {
struct ipxip_req rq;
int size = sizeof(rq);
@@ -592,6 +657,36 @@ setifnetmask(addr, dummy, s, afp)
(*afp->af_getaddr)(addr, MASK);
}
+#ifdef INET6
+void
+setifprefixlen(addr, dummy, s, afp)
+ const char *addr;
+ int dummy __unused;
+ int s;
+ const struct afswtch *afp;
+{
+ if (*afp->af_getprefix)
+ (*afp->af_getprefix)(addr, MASK);
+ explicit_prefix = 1;
+}
+
+void
+setip6flags(dummyaddr, flag, dummysoc, afp)
+ const char *dummyaddr __unused;
+ int flag;
+ int dummysoc __unused;
+ const struct afswtch *afp;
+{
+ if (afp->af_af != AF_INET6)
+ err(1, "address flags can be set only for inet6 addresses");
+
+ if (flag < 0)
+ in6_addreq.ifra_flags &= ~(-flag);
+ else
+ in6_addreq.ifra_flags |= flag;
+}
+#endif
+
void
setifbroadaddr(addr, dummy, s, afp)
const char *addr;
@@ -854,6 +949,99 @@ in_status(s, info)
putchar('\n');
}
+#ifdef INET6
+void
+in6_status(s, info)
+ int s __unused;
+ struct rt_addrinfo * info;
+{
+ struct sockaddr_in6 *sin, null_sin;
+ struct in6_ifreq ifr6;
+ int s6;
+ u_int32_t flags6;
+ struct in6_addrlifetime lifetime;
+ time_t t = time(NULL);
+
+ memset(&null_sin, 0, sizeof(null_sin));
+
+ sin = (struct sockaddr_in6 *)info->rti_info[RTAX_IFA];
+ strncpy(ifr6.ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name));
+ if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ perror("ifconfig: socket");
+ return;
+ }
+ ifr6.ifr_addr = *sin;
+ if (ioctl(s6, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
+ perror("ifconfig: 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) {
+ perror("ifconfig: ioctl(SIOCGIFALIFETIME_IN6)");
+ close(s6);
+ return;
+ }
+ lifetime = ifr6.ifr_ifru.ifru_lifetime;
+ close(s6);
+
+ printf("\tinet6 %s ", inet_ntop(AF_INET6, &sin->sin6_addr,
+ ntop_buf, sizeof(ntop_buf)));
+
+
+ if (flags & IFF_POINTOPOINT) {
+ /* note RTAX_BRD overlap with IFF_BROADCAST */
+ sin = (struct sockaddr_in6 *)info->rti_info[RTAX_BRD];
+ /*
+ * some of the interfaces do not have valid destination
+ * address.
+ */
+ if (sin && sin->sin6_family == AF_INET6) {
+ printf("--> %s ", inet_ntop(AF_INET6, &sin->sin6_addr,
+ ntop_buf, sizeof(ntop_buf)));
+ }
+ }
+
+ sin = (struct sockaddr_in6 *)info->rti_info[RTAX_NETMASK];
+ if (!sin)
+ sin = &null_sin;
+ printf("prefixlen %d ", prefix(&sin->sin6_addr,
+ sizeof(struct in6_addr)));
+
+ if (flags6 & IN6_IFF_ANYCAST)
+ printf("anycast ");
+ if (flags6 & IN6_IFF_TENTATIVE)
+ printf("tentative ");
+ if (flags6 & IN6_IFF_DUPLICATED)
+ printf("duplicated ");
+ if (flags6 & IN6_IFF_DETACHED)
+ printf("detached ");
+ if (flags6 & IN6_IFF_DEPRECATED)
+ printf("deprecated ");
+
+
+ if (ip6lifetime && (lifetime.ia6t_preferred || lifetime.ia6t_expire)) {
+ printf("pltime ");
+ if (lifetime.ia6t_preferred) {
+ printf("%s ", lifetime.ia6t_preferred < t
+ ? "0" : sec2str(lifetime.ia6t_preferred - t));
+ } else
+ printf("infty ");
+
+ printf("vltime ");
+ if (lifetime.ia6t_expire) {
+ printf("%s ", lifetime.ia6t_expire < t
+ ? "0" : sec2str(lifetime.ia6t_expire - t));
+ } else
+ printf("infty ");
+ }
+
+ putchar('\n');
+}
+#endif /*INET6*/
+
void
ipx_status(s, info)
int s __unused;
@@ -1005,6 +1193,54 @@ in_getaddr(s, which)
errx(1, "%s: bad value", s);
}
+#ifdef INET6
+#define SIN6(x) ((struct sockaddr_in6 *) &(x))
+struct sockaddr_in6 *sin6tab[] = {
+SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr),
+SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)};
+
+void
+in6_getaddr(s, which)
+ const char *s;
+ int which;
+{
+ register struct sockaddr_in6 *sin = sin6tab[which];
+
+ newaddr &= 1;
+
+ sin->sin6_len = sizeof(*sin);
+ if (which != MASK)
+ sin->sin6_family = AF_INET6;
+
+ if (inet_pton(AF_INET6, s, &sin->sin6_addr) != 1)
+ errx(1, "%s: bad value", s);
+}
+
+void
+in6_getprefix(plen, which)
+ const char *plen;
+ int which;
+{
+ register struct sockaddr_in6 *sin = sin6tab[which];
+ register 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);
+}
+#endif
+
/*
* Print a value a la the %b format of the kernel's printf
*/
@@ -1150,6 +1386,68 @@ xns_getaddr(addr, which)
}
#endif
+#ifdef INET6
+int
+prefix(val, size)
+ void *val;
+ int size;
+{
+ register u_char *name = (u_char *)val;
+ register int byte, bit, plen = 0;
+
+ for (byte = 0; byte < size; byte++, plen += 8)
+ if (name[byte] != 0xff)
+ break;
+ if (byte == size)
+ return (plen);
+ for (bit = 7; bit != 0; bit--, plen++)
+ 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);
+}
+
+static char *
+sec2str(total)
+ 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);
+}
+#endif /*INET6*/
+
void
ifmaybeload(name)
char *name;
OpenPOWER on IntegriCloud