make ifconfig IPv6-ready.

TODO: update manpage for new options.
This commit is contained in:
itojun 1999-07-01 13:19:20 +00:00
parent f3a6841709
commit 25eb444e29
3 changed files with 406 additions and 21 deletions

View File

@ -1,7 +1,9 @@
# $NetBSD: Makefile,v 1.7 1995/03/18 14:56:21 cgd Exp $
# $NetBSD: Makefile,v 1.8 1999/07/01 13:19:20 itojun Exp $
# @(#)Makefile 8.1 (Berkeley) 6/5/93
PROG= ifconfig
MAN= ifconfig.8
CFLAGS+= -DINET6
.include <bsd.prog.mk>

View File

@ -1,4 +1,4 @@
.\" $NetBSD: ifconfig.8,v 1.24 1998/09/06 17:51:32 christos Exp $
.\" $NetBSD: ifconfig.8,v 1.25 1999/07/01 13:19:20 itojun Exp $
.\"
.\" Copyright (c) 1983, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
@ -49,13 +49,13 @@
.Op Ar parameters
.Nm ""
.Op Fl A
.Op Fl m
.Op Fl mL
.Ar interface
.Op Ar protocol_family
.Nm ""
.Fl a
.Op Fl A
.Op Fl m
.Op Fl mL
.Op Fl d
.Op Fl u
.Op Ar protocol_family
@ -318,6 +318,10 @@ If the
flag is passed before an interface name,
.Nm
will display all of the supported media for the specified interface.
If the
.Fl L
flag is supplied, address lifetime is dislayed for IPv6 addresses,
as time offset string.
.Pp
Optionally, the
.Fl a

View File

@ -1,4 +1,4 @@
/* $NetBSD: ifconfig.c,v 1.52 1999/05/18 18:01:08 thorpej Exp $ */
/* $NetBSD: ifconfig.c,v 1.53 1999/07/01 13:19:20 itojun Exp $ */
/*-
* Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
@ -80,7 +80,7 @@ __COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\
#if 0
static char sccsid[] = "@(#)ifconfig.c 8.2 (Berkeley) 2/16/94";
#else
__RCSID("$NetBSD: ifconfig.c,v 1.52 1999/05/18 18:01:08 thorpej Exp $");
__RCSID("$NetBSD: ifconfig.c,v 1.53 1999/07/01 13:19:20 itojun Exp $");
#endif
#endif /* not lint */
@ -92,6 +92,8 @@ __RCSID("$NetBSD: ifconfig.c,v 1.52 1999/05/18 18:01:08 thorpej Exp $");
#include <net/if_dl.h>
#include <net/if_media.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <netinet6/nd6.h>
#include <arpa/inet.h>
#include <netatalk/at.h>
@ -117,6 +119,11 @@ __RCSID("$NetBSD: ifconfig.c,v 1.52 1999/05/18 18:01:08 thorpej Exp $");
struct ifreq ifr, ridreq;
struct ifaliasreq addreq __attribute__((aligned(4)));
#ifdef INET6
struct in6_ifreq ifr6;
struct in6_ifreq in6_ridreq;
struct in6_aliasreq in6_addreq __attribute__((aligned(4)));
#endif
struct iso_ifreq iso_ridreq;
struct iso_aliasreq iso_addreq;
struct sockaddr_in netmask;
@ -129,7 +136,14 @@ int newaddr = -1;
int nsellength = 1;
int af;
int Aflag, aflag, dflag, mflag, lflag, uflag;
#ifdef INET6
int Lflag;
#endif
int reset_if_flags;
int explicit_prefix = 0;
#ifndef INET_ONLY
char ntop_buf[INET6_ADDRSTRLEN]; /*inet_ntop()*/
#endif /* INET_ONLY */
void notealias __P((char *, int));
void notrailers __P((char *, int));
@ -141,10 +155,17 @@ void setifipdst __P((char *, int));
void setifmetric __P((char *, int));
void setifmtu __P((char *, int));
void setifnetmask __P((char *, int));
void setifprefixlen __P((char *, int));
void setnsellength __P((char *, int));
void setsnpaoffset __P((char *, int));
void setatrange __P((char *, int));
void setatphase __P((char *, int));
#ifdef INET6
void setia6flags __P((char *, int));
void setia6pltime __P((char *, int));
void setia6vltime __P((char *, int));
void setia6lifetime __P((char *, char *));
#endif
void checkatrange __P ((struct sockaddr_at *));
void setmedia __P((char *, int));
void setmediaopt __P((char *, int));
@ -201,6 +222,15 @@ struct cmd {
{ "mtu", NEXTARG, 0, setifmtu },
{ "broadcast", NEXTARG, 0, setifbroadaddr },
{ "ipdst", NEXTARG, 0, setifipdst },
{ "prefixlen", NEXTARG, 0, setifprefixlen},
#ifdef INET6
{ "anycast", IN6_IFF_ANYCAST, 0, setia6flags },
{ "-anycast", -IN6_IFF_ANYCAST, 0, setia6flags },
{ "tentative", IN6_IFF_TENTATIVE, 0, setia6flags },
{ "-tentative", -IN6_IFF_TENTATIVE, 0, setia6flags },
{ "pltime", NEXTARG, 0, setia6pltime },
{ "vltime", NEXTARG, 0, setia6vltime },
#endif /*INET6*/
#ifndef INET_ONLY
{ "range", NEXTARG, 0, setatrange },
{ "phase", NEXTARG, 0, setatphase },
@ -226,10 +256,12 @@ void adjust_nsellength __P((void));
int getinfo __P((struct ifreq *));
void getsock __P((int));
void printall __P((void));
void printalias __P((const char *));
void printalias __P((const char *, int));
void printb __P((char *, unsigned short, char *));
int prefix __P((void *, int));
void status __P((const u_int8_t *, int));
void usage __P((void));
char *sec2str __P((time_t));
const char *get_media_type_string __P((int));
const char *get_media_subtype_string __P((int));
@ -248,6 +280,12 @@ void init_current_media __P((void));
void in_alias __P((struct ifreq *));
void in_status __P((int));
void in_getaddr __P((char *, int));
#ifdef INET6
void in6_alias __P((struct in6_ifreq *));
void in6_status __P((int));
void in6_getaddr __P((char *, int));
void in6_getprefix __P((char *, int));
#endif
void at_status __P((int));
void at_getaddr __P((char *, int));
void xns_status __P((int));
@ -261,20 +299,25 @@ struct afswtch {
short af_af;
void (*af_status) __P((int));
void (*af_getaddr) __P((char *, int));
void (*af_getprefix) __P((char *, int));
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) },
#ifdef INET6
{ "inet6", AF_INET6, in6_status, in6_getaddr, in6_getprefix,
SIOCDIFADDR_IN6, SIOCAIFADDR_IN6, C(in6_ridreq), C(in6_addreq) },
#endif
#ifndef INET_ONLY /* small version, for boot media */
{ "atalk", AF_APPLETALK, at_status, at_getaddr,
{ "atalk", AF_APPLETALK, at_status, at_getaddr, NULL,
SIOCDIFADDR, SIOCAIFADDR, C(addreq), C(addreq) },
{ "ns", AF_NS, xns_status, xns_getaddr,
{ "ns", AF_NS, xns_status, xns_getaddr, NULL,
SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
{ "iso", AF_ISO, iso_status, iso_getaddr,
{ "iso", AF_ISO, iso_status, iso_getaddr, NULL,
SIOCDIFADDR_ISO, SIOCAIFADDR_ISO, C(iso_ridreq), C(iso_addreq) },
#endif /* INET_ONLY */
{ 0, 0, 0, 0 }
@ -293,7 +336,11 @@ main(argc, argv)
/* Parse command-line options */
aflag = mflag = 0;
while ((ch = getopt(argc, argv, "Aadlmu")) != -1) {
while ((ch = getopt(argc, argv, "Aadlmu"
#ifdef INET6
"L"
#endif
)) != -1) {
switch (ch) {
case 'A':
Aflag = 1;
@ -307,6 +354,12 @@ main(argc, argv)
dflag = 1;
break;
#ifdef INET6
case 'L':
Lflag = 1;
break;
#endif
case 'l':
lflag = 1;
break;
@ -384,11 +437,17 @@ main(argc, argv)
exit(0);
}
/* The following operations assume inet family as the default. */
/* following operations assume inet familiy as default */
if (afp == NULL)
afp = afs;
af = ifr.ifr_addr.sa_family = afp->af_af;
#ifdef INET6
/* initialization */
in6_addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
in6_addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
#endif
/* Process commands. */
while (argc > 0) {
struct cmd *p;
@ -415,8 +474,17 @@ main(argc, argv)
/* Process any media commands that may have been issued. */
process_media_commands();
#ifndef INET_ONLY
if (af == 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);
/* in6_getprefix("64", MASK) if MASK is available here... */
}
#ifndef INET_ONLY
if (af == AF_ISO)
adjust_nsellength();
@ -511,8 +579,9 @@ getinfo(ifr)
}
void
printalias(iname)
printalias(iname, af)
const char *iname;
int af;
{
char inbuf[8192];
struct ifconf ifc;
@ -534,8 +603,14 @@ printalias(iname)
? ifr->ifr_addr.sa_len
: sizeof(struct sockaddr));
if (!strncmp(iname, ifr->ifr_name, sizeof(ifr->ifr_name))) {
if (ifr->ifr_addr.sa_family == AF_INET)
in_alias(ifr);
if (ifr->ifr_addr.sa_family == af)
switch (af) {
case AF_INET:
in_alias(ifr);
break;
default:
/*none*/
}
continue;
}
}
@ -714,6 +789,59 @@ setifflags(vname, value)
reset_if_flags = 1;
}
#ifdef INET6
void
setia6flags(vname, value)
char *vname;
int value;
{
if (value < 0) {
value = -value;
in6_addreq.ifra_flags &= ~value;
} else
in6_addreq.ifra_flags |= value;
}
void
setia6pltime(val, d)
char *val;
int d;
{
setia6lifetime("pltime", val);
}
void
setia6vltime(val, d)
char *val;
int d;
{
setia6lifetime("vltime", val);
}
void
setia6lifetime(cmd, val)
char *cmd;
char *val;
{
time_t newval, t;
char *ep;
t = time(NULL);
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) {
in6_addreq.ifra_lifetime.ia6t_expire = t + newval;
in6_addreq.ifra_lifetime.ia6t_vltime = newval;
} else if (strcmp(cmd, "pltime") == 0) {
in6_addreq.ifra_lifetime.ia6t_preferred = t + newval;
in6_addreq.ifra_lifetime.ia6t_pltime = newval;
}
}
#endif
void
setifmetric(val, d)
char *val;
@ -1138,12 +1266,12 @@ status(ap, alen)
if ((p = afp) != NULL) {
(*p->af_status)(1);
if (Aflag & !aflag)
printalias(name);
printalias(name, p->af_af);
} else for (p = afs; p->af_name; p++) {
ifr.ifr_addr.sa_family = p->af_af;
(*p->af_status)(0);
if (Aflag & !aflag && p->af_af == AF_INET)
printalias(name);
printalias(name, p->af_af);
}
}
@ -1265,6 +1393,145 @@ in_status(force)
putchar('\n');
}
void
setifprefixlen(addr, d)
char *addr;
int d;
{
if (*afp->af_getprefix)
(*afp->af_getprefix)(addr, MASK);
explicit_prefix = 1;
}
#ifdef INET6
/* XXX not really an alias */
void
in6_alias(creq)
struct in6_ifreq *creq;
{
struct sockaddr_in6 *sin6;
/* Get the non-alias address for this interface. */
getsock(AF_INET6);
if (s < 0) {
if (errno == EPROTONOSUPPORT)
return;
err(1, "socket");
}
sin6 = (struct sockaddr_in6 *)&creq->ifr_addr;
printf("\tinet6 %s", inet_ntop(AF_INET6, &sin6->sin6_addr,
ntop_buf, sizeof(ntop_buf)));
if (flags & IFF_POINTOPOINT) {
(void) memset(&ifr6, 0, sizeof(ifr6));
(void) strncpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
ifr6.ifr_addr = creq->ifr_addr;
if (ioctl(s, SIOCGIFDSTADDR_IN6, (caddr_t)&ifr6) < 0) {
if (errno != EADDRNOTAVAIL)
warn("SIOCGIFDSTADDR_IN6");
(void) memset(&ifr6.ifr_addr, 0, sizeof(ifr6.ifr_addr));
ifr6.ifr_addr.sin6_family = AF_INET6;
ifr6.ifr_addr.sin6_len = sizeof(struct sockaddr_in6);
}
sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr;
printf(" -> %s", inet_ntop(AF_INET6, &sin6->sin6_addr,
ntop_buf, sizeof(ntop_buf)));
}
(void) memset(&ifr6, 0, sizeof(ifr6));
(void) strncpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
ifr6.ifr_addr = creq->ifr_addr;
if (ioctl(s, SIOCGIFNETMASK_IN6, (caddr_t)&ifr6) < 0) {
if (errno != EADDRNOTAVAIL)
warn("SIOCGIFNETMASK_IN6");
} else {
sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr;
printf(" prefixlen %d", prefix(&sin6->sin6_addr,
sizeof(struct in6_addr)));
}
(void) memset(&ifr6, 0, sizeof(ifr6));
(void) strncpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
ifr6.ifr_addr = creq->ifr_addr;
if (ioctl(s, SIOCGIFAFLAG_IN6, (caddr_t)&ifr6) < 0) {
if (errno != EADDRNOTAVAIL)
warn("SIOCGIFAFLAG_IN6");
} else {
if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_ANYCAST)
printf(" anycast");
if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
printf(" tentative");
if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED)
printf(" duplicated");
if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DETACHED)
printf(" detached");
}
if (Lflag) {
struct in6_addrlifetime *lifetime;
(void) memset(&ifr6, 0, sizeof(ifr6));
(void) strncpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
ifr6.ifr_addr = creq->ifr_addr;
lifetime = &ifr6.ifr_ifru.ifru_lifetime;
if (ioctl(s, SIOCGIFALIFETIME_IN6, (caddr_t)&ifr6) < 0) {
if (errno != EADDRNOTAVAIL)
warn("SIOCGIFALIFETIME_IN6");
} else if (lifetime->ia6t_preferred || lifetime->ia6t_expire) {
time_t t = time(NULL);
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");
}
}
printf("\n");
}
void
in6_status(force)
int force;
{
char inbuf[8192];
struct ifconf ifc;
struct ifreq *ifr;
int i;
ifc.ifc_len = sizeof(inbuf);
ifc.ifc_buf = inbuf;
getsock(af);
if (s < 0)
err(1, "socket");
if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
err(1, "SIOCGIFCONF");
ifr = ifc.ifc_req;
for (i = 0; i < ifc.ifc_len; ) {
ifr = (struct ifreq *)((caddr_t)ifc.ifc_req + i);
i += sizeof(ifr->ifr_name) +
(ifr->ifr_addr.sa_len > sizeof(struct sockaddr)
? ifr->ifr_addr.sa_len
: sizeof(struct sockaddr));
if (!strncmp(name, ifr->ifr_name, sizeof(ifr->ifr_name))) {
if (ifr->ifr_addr.sa_family == AF_INET6)
in6_alias((struct in6_ifreq *)ifr);
}
}
}
#endif /*INET6*/
#ifndef INET_ONLY
void
@ -1478,8 +1745,79 @@ printb(s, v, bits)
}
}
#ifndef INET_ONLY
#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)
char *s;
int which;
{
struct sockaddr_in6 *sin = sin6tab[which];
sin->sin6_len = sizeof(*sin);
if (which != MASK)
sin->sin6_family = AF_INET6;
if (inet_pton(AF_INET6, s, &sin->sin6_addr) <= 0)
errx(1, "%s: bad value", s);
}
void
in6_getprefix(plen, which)
char *plen;
int which;
{
register struct sockaddr_in6 *sin = sin6tab[which];
register u_char *cp;
int len = strtol(plen, (char **)NULL, 10);
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);
}
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);
}
#endif /*INET6*/
#ifndef INET_ONLY
void
at_getaddr(addr, which)
char *addr;
@ -1631,7 +1969,12 @@ void
usage()
{
fprintf(stderr,
"usage: ifconfig [ -m ] [ -A ] interface\n%s%s%s%s%s%s%s%s%s%s%s%s",
"usage: ifconfig [ -m ] [ -A ] %s interface\n%s%s%s%s%s%s%s%s%s%s%s%s",
#ifdef INET6
"[ -L ]",
#else
"",
#endif
"\t[ af [ address [ dest_addr ] ] [ up ] [ down ] ",
"[ netmask mask ] ]\n",
"\t[ metric n ]\n",
@ -1646,3 +1989,39 @@ usage()
" ifconfig -l [ -d ] [ -u ]\n");
exit(1);
}
#ifdef INET6
char *
sec2str(total)
time_t total;
{
static char result[256];
int days, hours, mins, secs;
int first = 1;
char *p = result;
if (0) { /*XXX*/
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(p, "%lu", (u_long)total);
return(result);
}
#endif