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/ifconfig/ifconfig.c | |
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/ifconfig/ifconfig.c')
-rw-r--r-- | sbin/ifconfig/ifconfig.c | 436 |
1 files changed, 423 insertions, 13 deletions
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 |