summaryrefslogtreecommitdiff
path: root/sbin/ifconfig/ifconfig.c
diff options
context:
space:
mode:
authorJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>1999-12-08 07:45:31 +0000
committerJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>1999-12-08 07:45:31 +0000
commit10263d773d79045708f7f3f2d633e99293387ff2 (patch)
treebfe6062ed3afec4d340ff9ebe80ece592f24404d /sbin/ifconfig/ifconfig.c
parent57d62e8d0ab872cbb50d2b6c9c9438ea583fa8d0 (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.c436
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