diff options
author | Jun-ichiro itojun Hagino <itojun@cvs.openbsd.org> | 1999-12-08 07:45:31 +0000 |
---|---|---|
committer | Jun-ichiro itojun Hagino <itojun@cvs.openbsd.org> | 1999-12-08 07:45:31 +0000 |
commit | 10263d773d79045708f7f3f2d633e99293387ff2 (patch) | |
tree | bfe6062ed3afec4d340ff9ebe80ece592f24404d /sbin | |
parent | 57d62e8d0ab872cbb50d2b6c9c9438ea583fa8d0 (diff) |
IPv6-enabled ifconfig from KAME.
it now loops through all the aliases on interfaces.
KAME_SCOPEID will be enabled when get{addr,name}info(3) are replaced with
KAME code.
Diffstat (limited to 'sbin')
-rw-r--r-- | sbin/ifconfig/Makefile | 7 | ||||
-rw-r--r-- | sbin/ifconfig/ifconfig.8 | 27 | ||||
-rw-r--r-- | sbin/ifconfig/ifconfig.c | 436 |
3 files changed, 454 insertions, 16 deletions
diff --git a/sbin/ifconfig/Makefile b/sbin/ifconfig/Makefile index 79f036663bb..9584521cda3 100644 --- a/sbin/ifconfig/Makefile +++ b/sbin/ifconfig/Makefile @@ -1,6 +1,11 @@ -# $OpenBSD: Makefile,v 1.3 1997/09/21 11:36:46 deraadt Exp $ +# $OpenBSD: Makefile,v 1.4 1999/12/08 07:45:30 itojun Exp $ PROG= ifconfig MAN= ifconfig.8 +CPPFLAGS+=-DINET6 + +# kame scopeid hack +#CPPFLAGS+=-DKAME_SCOPEID + .include <bsd.prog.mk> diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8 index 844141524f0..7c17815f682 100644 --- a/sbin/ifconfig/ifconfig.8 +++ b/sbin/ifconfig/ifconfig.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ifconfig.8,v 1.28 1999/09/23 22:42:11 deraadt Exp $ +.\" $OpenBSD: ifconfig.8,v 1.29 1999/12/08 07:45:30 itojun Exp $ .\" $NetBSD: ifconfig.8,v 1.11 1996/01/04 21:27:29 pk Exp $ .\" $FreeBSD: ifconfig.8,v 1.16 1998/02/01 07:03:29 steve Exp $ .\" @@ -157,6 +157,12 @@ Internet addresses and 10Mb/s Ethernet addresses. .It Fl arp Disable the use of the Address Resolution Protocol. +.It Cm anycast +(inet6 only) +Set the IPv6 anycast address bit. +.It Fl anycast +(inet6 only) +Clear the IPv6 anycast address bit. .It Cm broadcast Ar addr (Inet only) Specify the address to use to represent broadcasts to the @@ -238,7 +244,7 @@ Higher metrics have the effect of making a route less favorable; metrics are counted as addition hops to the destination network or host. .It Cm netmask Ar mask -(Inet and ISO) +(Inet, inet6 and ISO) Specify how much of the address to reserve for subdividing networks into sub-networks. The mask includes the network part of the local address @@ -288,6 +294,20 @@ netmasks though OpenBSD implements it internally as a set of netmasks. .It Cm phase The argument following this specifies the version (phase) of the AppleTalk network attached to the interface. Values of 1 or 2 are permitted. +.It Cm pltime Ar n +(inet6 only) +Set preferred lifetime for the address. +.It Cm prefixlen Ar n +(inet6 only) +Effect is similar to +.Cm netmask . +but you can specify by prefix length by digits. +.It Cm tentative +(inet6 only) +Set the IPv6 tentative address bit. +.It Fl tentative +(inet6 only) +Clear the IPv6 tentative address bit. .It Cm trailers Request the use of a .Dq trailer @@ -327,6 +347,9 @@ This may be used to enable an interface after an It happens automatically when setting the first address on an interface. If the interface was reset when previously marked down, the hardware will be re-initialized. +.It Cm vltime Ar n +(inet6 only) +Set valid lifetime for the address. .El .Pp .Pp diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c index 0742e23b3e9..8b71a2ce91f 100644 --- a/sbin/ifconfig/ifconfig.c +++ b/sbin/ifconfig/ifconfig.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ifconfig.c,v 1.22 1999/02/24 21:26:03 deraadt Exp $ */ +/* $OpenBSD: ifconfig.c,v 1.23 1999/12/08 07:45:30 itojun Exp $ */ /* $NetBSD: ifconfig.c,v 1.40 1997/10/01 02:19:43 enami Exp $ */ /* @@ -81,7 +81,7 @@ static char copyright[] = #if 0 static char sccsid[] = "@(#)ifconfig.c 8.2 (Berkeley) 2/16/94"; #else -static char rcsid[] = "$OpenBSD: ifconfig.c,v 1.22 1999/02/24 21:26:03 deraadt Exp $"; +static char rcsid[] = "$OpenBSD: ifconfig.c,v 1.23 1999/12/08 07:45:30 itojun Exp $"; #endif #endif /* not lint */ @@ -93,6 +93,8 @@ static char rcsid[] = "$OpenBSD: ifconfig.c,v 1.22 1999/02/24 21:26:03 deraadt E #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> @@ -122,6 +124,11 @@ static char rcsid[] = "$OpenBSD: ifconfig.c,v 1.22 1999/02/24 21:26:03 deraadt E struct ifreq ifr, ridreq; struct ifaliasreq addreq; +#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; @@ -136,6 +143,10 @@ int nsellength = 1; int af = AF_INET; int dflag, mflag, lflag, uflag; int reset_if_flags; +int explicit_prefix = 0; +#ifdef INET6 +int Lflag = 1; +#endif void notealias __P((char *, int)); void notrailers __P((char *, int)); @@ -146,11 +157,18 @@ void setifbroadaddr __P((char *)); void setifipdst __P((char *)); void setifmetric __P((char *)); void setifnetmask __P((char *)); +void setifprefixlen __P((char *, int)); void setnsellength __P((char *)); void setsnpaoffset __P((char *)); void setipxframetype __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)); @@ -206,6 +224,15 @@ struct cmd { { "metric", NEXTARG, 0, setifmetric }, { "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 }, @@ -240,6 +267,7 @@ void printif __P((struct ifreq *, int)); void printb __P((char *, unsigned short, char *)); void status __P((int)); void usage(); +char *sec2str __P((time_t)); const char *get_media_type_string __P((int)); const char *get_media_subtype_string __P((int)); @@ -257,6 +285,13 @@ void init_current_media __P((void)); */ void in_status __P((int)); void in_getaddr __P((char *, int)); +#ifdef INET6 +void in6_fillscopeid __P((struct sockaddr_in6 *sin6)); +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)); @@ -272,22 +307,27 @@ struct afswtch { short af_af; void (*af_status)(); void (*af_getaddr)(); + void (*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) }, +#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) }, - { "ipx", AF_IPX, ipx_status, ipx_getaddr, + { "ipx", AF_IPX, ipx_status, ipx_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 } @@ -353,6 +393,12 @@ main(argc, argv) exit(0); } +#ifdef INET6 + /* initialization */ + in6_addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; + in6_addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; +#endif + if (getinfo(&ifr) < 0) exit(1); while (argc > 0) { @@ -384,6 +430,16 @@ main(argc, argv) /* Process any media commands that may have been issued. */ process_media_commands(); + 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 switch (af) { @@ -523,16 +579,26 @@ printif(ifrm, ifaliases) } if (!strncmp(ifreq.ifr_name, ifrp->ifr_name, sizeof(ifrp->ifr_name))) { - register struct afswtch *p = afp; + register struct afswtch *p; +#if 0 if (ifaliases == 0 && noinet == 0) continue; +#endif ifr = *ifrp; +#ifdef INET6 + /* quickhack: sizeof(ifr) < sizeof(ifr6) */ + if (ifrp->ifr_addr.sa_family == AF_INET6) + bcopy(ifrp, &ifr6, sizeof(ifr6)); +#endif if ((p = afp) != NULL) { - (*p->af_status)(1); - } else for (p = afs; p->af_name; p++) { - ifr.ifr_addr.sa_family = p->af_af; - (*p->af_status)(0); + if (ifr.ifr_addr.sa_family == p->af_af) + (*p->af_status)(1); + } else { + for (p = afs; p->af_name; p++) { + if (ifr.ifr_addr.sa_family == p->af_af) + (*p->af_status)(0); + } } count++; noinet = 0; @@ -650,6 +716,59 @@ setifflags(vname, value) err(1, "SIOCSIFFLAGS"); } +#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) char *val; @@ -1115,6 +1234,153 @@ 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 +void +in6_fillscopeid(sin6) + struct sockaddr_in6 *sin6; +{ +#if defined(__KAME__) && defined(KAME_SCOPEID) + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { + sin6->sin6_scope_id = + ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]); + sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0; + } +#endif +} + +/* XXX not really an alias */ +void +in6_alias(creq) + struct in6_ifreq *creq; +{ + struct sockaddr_in6 *sin6; + struct in6_ifreq ifr6; /* shadows file static variable */ + u_int32_t scopeid; + char hbuf[NI_MAXHOST]; +#ifdef NI_WITHSCOPEID + const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID; +#else + const int niflag = NI_NUMERICHOST; +#endif + + /* 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; + + in6_fillscopeid(sin6); + scopeid = sin6->sin6_scope_id; + if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len, + hbuf, sizeof(hbuf), NULL, 0, niflag) != 0) + strcpy(hbuf, ""); + printf("\tinet6 %s", hbuf); + + 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; + in6_fillscopeid(sin6); + if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len, + hbuf, sizeof(hbuf), NULL, 0, niflag) != 0) + strcpy(hbuf, ""); + printf(" -> %s", hbuf); + } + + (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 (scopeid) + printf(" scopeid 0x%x", scopeid); + + 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; +{ + in6_alias((struct in6_ifreq *)&ifr6); +} +#endif /*INET6*/ + #ifndef INET_ONLY void @@ -1338,6 +1604,7 @@ in_getaddr(s, which) char *s; int which; { +#ifndef KAME_SCOPEID register struct sockaddr_in *sin = sintab[which]; struct hostent *hp; struct netent *np; @@ -1354,6 +1621,41 @@ in_getaddr(s, which) else errx(1, "%s: bad value", s); } +#else + /* + * XXX + * we can't use gethostbyname() nor getnetbyname() here due to + * library conflicts between libinet6 and libc. + * #if 0 should be modified when we do + * the complete merger of libinet6 into libc. + */ + register struct sockaddr_in *sin = sintab[which]; + struct addrinfo hints, *res; + int error; + struct netent *np; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_RAW; + error = getaddrinfo(s, "NULL", &hints, &res); + if (error) { +#if 0 /* incompatible behavior! */ + if ((np = getnetbyname(s)) != NULL) { + memset(sin, 0, sizeof(*sin)); + sin->sin_family = AF_INET; + sin->sin_len = sizeof(struct sockaddr_in); + sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY); + return; + } +#endif + + errx(1, "%s: %s", s, gai_strerror(error)); + } + if (res->ai_addrlen != sizeof(struct sockaddr_in)) + errx(1, "%s: bad value", s); + memcpy(sin, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); +#endif } /* @@ -1390,9 +1692,80 @@ 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) != 1) + 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; int which; @@ -1574,3 +1947,40 @@ usage() " ifconfig -m interface [af]\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; + char *end = &result[sizeof(result)]; + + if (0) { /*XXX*/ + days = total / 3600 / 24; + hours = (total / 3600) % 24; + mins = (total / 60) % 60; + secs = total % 60; + + if (days) { + first = 0; + p += snprintf(p, end - p, "%dd", days); + } + if (!first || hours) { + first = 0; + p += snprintf(p, end - p, "%dh", hours); + } + if (!first || mins) { + first = 0; + p += snprintf(p, end - p, "%dm", mins); + } + snprintf(p, end - p, "%ds", secs); + } else + snprintf(p, end - p, "%lu", (u_long)total); + + return(result); +} +#endif |