diff options
author | Jun-ichiro itojun Hagino <itojun@cvs.openbsd.org> | 1999-12-21 08:45:41 +0000 |
---|---|---|
committer | Jun-ichiro itojun Hagino <itojun@cvs.openbsd.org> | 1999-12-21 08:45:41 +0000 |
commit | 4ff44393c449d1e4cd59bb7d858a210475688f1e (patch) | |
tree | 1ca585ed7ef8709e96205504bd0909cc34e0ffde | |
parent | 4f206260ca6b0dea002deeff501bc5170d94e9cd (diff) |
gifconfig from KAME
-rw-r--r-- | usr.sbin/gifconfig/gifconfig.8 | 139 | ||||
-rw-r--r-- | usr.sbin/gifconfig/gifconfig.c | 832 |
2 files changed, 971 insertions, 0 deletions
diff --git a/usr.sbin/gifconfig/gifconfig.8 b/usr.sbin/gifconfig/gifconfig.8 new file mode 100644 index 00000000000..0b3858deade --- /dev/null +++ b/usr.sbin/gifconfig/gifconfig.8 @@ -0,0 +1,139 @@ +.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the project nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id: gifconfig.8,v 1.1 1999/12/21 08:45:40 itojun Exp $ +.\" +.Dd May 17, 1998 +.Dt GIFCONFIG 8 +.Os KAME +.\" +.Sh NAME +.Nm gifconfig +.Nd configure generic IP tunnel +.\" +.Sh SYNOPSIS +.Nm +.Ar interface +.Op Ar af +.Op Ar physsrc physdest +.Nm gifconfig +.Fl a +.\" +.Sh DESCRIPTION +.Nm +configures the physical address for the generic IP tunnel +inteface, such as "gif0". +Argument +.Ar physsrc +and +.Ar physdest +are interpreted as the outer source/destination address for +encapsulating IPv4/v6 header. +Argument +.Ar af +specifies the address family for +.Ar physsrc +and +.Ar physdest . +.Ar Af +can be +.Li inet +or +.Li inet6 , +and will be treated as +.Li inet +if ommitted. +.Pp +.Nm +takes the following optional argument: +.Bl -tag -width Ds +.It Fl a +Display information associated all generic IP tunnel interfaces. +.El +.Pp +Please note that it is very easy to create infinite routing loop, +when you configure tunnel over same address family +.Po +e.g. IPv4-over-IPv4 +.Pc . +.\" +.Sh EXAMPLES +If you would like to configure IPv6 over IPv4 +.Pq aka IPv6 in IPv4 +tunnel between +.Li 10.1.1.1 +and +.Li 10.2.3.4 , +you should perform the following command: +.Bd -literal -offset +# gifconfig gif0 inet 10.1.1.1 10.2.3.4 +.Ed +.Pp +.\" To use the +.\" .Li 0.0.0.0 +.\" feature to establish a tunnel from host1 to host3 +.\" which will encapsulate and carry packets from host2, on host1 do: +.\" .Bd -literal -offset +.\" # ifconfig gif0 inet host1 127.0.0.2 # assign an address to gif0 +.\" # gifconfig gif0 inet host1 0.0.0.0 # assign encapsulation addresses +.\" # route add host2 host3 -ifp gif0: # encap host2 packets, send to host3 +.\" .Ed +.\" .Pp +.\" Note: the +.\" .Fl ifp +.\" option to route does not work as documented in +.\" most versions of FreeBSD. +.\" .Pp +.\" On host3 do: +.\" .Bd -literal -offset +.\" # ifconfig gif0 inet host3 127.0.0.2 # assign an address to gif0 +.\" # gifconfig gif0 inet host3 0.0.0.0 # assign encapsulation addresses +.\" .Ed +.\" .Pp +.\" Now if you ping host2 from host1, the packets should be encapsulated +.\" with outer source address = host1 and outer destination address = host3, +.\" and delivered to host3. +.\" host3 will decapsulate the packet and deliver it normally to host2. +.\" .Pp +This is also possible to use IPv6 as outer proto, by replacing +.Li inet +to +.Li inet6 , +and IPv4 addresses to some appropriate IPv6 addresses in above example. +.\" +.Sh RETURN VALUES +The command exits with exit status of 1 on errors, 0 on success. +.\" +.Sh SEE ALSO +.Xr gif 4 , +.Xr ifconfig 8 +.Sh HISTORY +The +.Nm +command first appeared in WIDE Hydrangea IPv6 protocol stack kit. +.\" .Sh BUGS +.\" (to be written) diff --git a/usr.sbin/gifconfig/gifconfig.c b/usr.sbin/gifconfig/gifconfig.c new file mode 100644 index 00000000000..f5bdbb40d65 --- /dev/null +++ b/usr.sbin/gifconfig/gifconfig.c @@ -0,0 +1,832 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * gifconfig, derived from ifconfig + * + * @(#) Copyright (c) 1983, 1993\n\ + * The Regents of the University of California. All rights reserved.\n + * + * @(#)ifconfig.c 8.2 (Berkeley) 2/16/94 + */ + +/* + * 951109 - Andrew@pubnix.net - Changed to iterative buffer growing mechanism + * for ifconfig -a so all interfaces are queried. + * + * 960101 - peter@freebsd.org - Blow away the SIOCGIFCONF code and use + * sysctl() to get the structured interface conf + * and parse the messages in there. REALLY UGLY! + */ + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <sys/sysctl.h> + +#include <net/if.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <net/if_var.h> +#endif /* __FreeBSD__ >= 3 */ +#include <net/if_dl.h> +#include <net/if_types.h> +#include <net/route.h> +#include <netinet/in.h> +#include <netinet/in_var.h> +#include <arpa/inet.h> +#include <netdb.h> + +#include <sys/protosw.h> + +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <nlist.h> +#include <kvm.h> +#include <fcntl.h> + +struct ifreq ifr; +struct ifaliasreq addreq; +#ifdef INET6 +struct in6_ifreq in6_ifr; +struct in6_aliasreq in6_addreq; +#endif + +char name[32]; +int flags; +int metric; +int mtu; +int setpsrc = 0; +int s; +kvm_t *kvmd; +extern int errno; + +#ifdef INET6 +char ntop_buf[INET6_ADDRSTRLEN]; /*inet_ntop()*/ +#endif + +void setifpsrc __P((char *, int)); +void setifpdst __P((char *, int)); +void setifflags __P((char *, int)); + + +#define NEXTARG 0xffffff + +struct cmd { + char *c_name; + int c_parameter; /* NEXTARG means next argv */ + void (*c_func) __P((char *, int)); +} cmds[] = { + { "up", IFF_UP, setifflags } , + { "down", -IFF_UP, setifflags }, + { 0, 0, setifpsrc }, + { 0, 0, setifpdst }, +}; + +/* + * XNS support liberally adapted from code written at the University of + * Maryland principally by James O'Toole and Chris Torek. + */ +int main __P((int, char *[])); +void status __P((void)); +void phys_status __P((int)); +void in_status __P((int)); +#ifdef INET6 +void in6_status __P((int)); +#endif +void ether_status __P((int)); +void Perror __P((char *)); +void in_getaddr __P((char *, int)); +#ifdef INET6 +void in6_getaddr __P((char *, int)); +void in6_getprefix __P((char *, int)); +#endif +void printb __P((char *, unsigned int, char *)); +int prefix __P((void *, int)); + +char ntop_buf[INET6_ADDRSTRLEN]; + +/* Known address families */ +struct afswtch { + char *af_name; + short af_af; + void (*af_status) __P((int)); + void (*af_getaddr) __P((char *, int)); + void (*af_getprefix) __P((char *, int)); + u_long af_pifaddr; + caddr_t af_addreq; + caddr_t af_req; +} afs[] = { +#define C(x) ((caddr_t) &x) + { "inet", AF_INET, in_status, in_getaddr, 0, + SIOCSIFPHYADDR, C(addreq), C(ifr) }, +#ifdef INET6 + { "inet6", AF_INET6, in6_status, in6_getaddr, in6_getprefix, + SIOCSIFPHYADDR_IN6, C(in6_addreq), C(in6_ifr) }, +#endif + { "ether", AF_INET, ether_status, NULL, NULL }, /* XXX not real!! */ + { 0, 0, 0, 0, 0 } +}; + +struct afswtch *afp = NULL; /*the address family being set or asked about*/ + +void rt_xaddrs __P((caddr_t, caddr_t, struct rt_addrinfo *)); +int ifconfig __P((int argc, char *argv[], int af, struct afswtch *rafp)); + + + +/* + * Expand the compacted form of addresses as returned via the + * configuration read via sysctl(). + */ + +#define ROUNDUP(a) \ + ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) +#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) + +void +rt_xaddrs(cp, cplim, rtinfo) + caddr_t cp, cplim; + struct rt_addrinfo *rtinfo; +{ + struct sockaddr *sa; + int i; + + memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info)); + for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { + if ((rtinfo->rti_addrs & (1 << i)) == 0) + continue; + rtinfo->rti_info[i] = sa = (struct sockaddr *)cp; + ADVANCE(cp, sa); + } +} + + +/* + * Grunge for new-style sysctl() decoding.. :-( + * Apologies to the world for committing gross things like this in 1996.. + */ +struct if_msghdr *ifm; +struct ifa_msghdr *ifam; +struct sockaddr_dl *sdl; +struct rt_addrinfo info; +char *buf, *lim, *next; + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int af = AF_INET; + struct afswtch *rafp = NULL; + size_t needed; + int mib[6]; + int all; + + if (argc < 2) { + fprintf(stderr, "usage: gifconfig interface %s", + "[ af ] physsrc physdst\n"); + exit(1); + } + argc--, argv++; + strncpy(name, *argv, sizeof(name)); + strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + argc--, argv++; + if (argc > 0) { + for (afp = rafp = afs; rafp->af_name; rafp++) + if (strcmp(rafp->af_name, *argv) == 0) { + afp = rafp; argc--; argv++; + break; + } + rafp = afp; + af = ifr.ifr_addr.sa_family = rafp->af_af; + } + + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; + mib[3] = 0; /* address family */ + mib[4] = NET_RT_IFLIST; + mib[5] = 0; + + /* if particular family specified, only ask about it */ + if (afp) { + mib[3] = afp->af_af; + } + + if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) + errx(1, "iflist-sysctl-estimate"); + if ((buf = malloc(needed)) == NULL) + errx(1, "malloc"); + if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) + errx(1, "actual retrieval of interface table"); + lim = buf + needed; + + all = 0; + if (strcmp(name, "-a") == 0) + all = 1; /* All interfaces */ + else if (strcmp(name, "-au") == 0) + all = 2; /* All IFF_UPinterfaces */ + else if (strcmp(name, "-ad") == 0) + all = 3; /* All !IFF_UP interfaces */ + + for (next = buf; next < lim; next += ifm->ifm_msglen) { + + ifm = (struct if_msghdr *)next; + + /* XXX: Swallow up leftover NEWADDR messages */ + if (ifm->ifm_type == RTM_NEWADDR) + continue; + + if (ifm->ifm_type == RTM_IFINFO) { + sdl = (struct sockaddr_dl *)(ifm + 1); + flags = ifm->ifm_flags; + } else { + errx(1, "out of sync parsing NET_RT_IFLIST"); + } + + switch(all) { + case -1: + case 0: + if (strlen(name) != sdl->sdl_nlen) + continue; /* not same len */ + if (strncmp(name, sdl->sdl_data, sdl->sdl_nlen) != 0) + continue; /* not same name */ + break; + case 1: + break; /* always do it */ + case 2: + if ((flags & IFF_UP) == 0) + continue; /* not up */ + break; + case 3: + if (flags & IFF_UP) + continue; /* not down */ + break; + } + + /* + * Let's just do it for gif only + */ + if (sdl->sdl_type != IFT_GIF) { + if (all != 0) + continue; + + fprintf(stderr, "gifconfig: %s is not gif.\n", + ifr.ifr_name); + exit(1); + } + + if (all > 0) { + strncpy(name, sdl->sdl_data, sdl->sdl_nlen); + name[sdl->sdl_nlen] = '\0'; + } + + if ((s = socket(af, SOCK_DGRAM, 0)) < 0) { + perror("gifconfig: socket"); + exit(1); + } + + ifconfig(argc,argv,af,rafp); + + close(s); + + if (all == 0) { + all = -1; /* flag it as 'done' */ + break; + } + } + free(buf); + + if (all == 0) + errx(1, "interface %s does not exist", name); + + + exit (0); +} + + +int +ifconfig(argc, argv, af, rafp) + int argc; + char *argv[]; + int af; + struct afswtch *rafp; +{ + + af = 0; /*fool gcc*/ + + strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); +#ifdef INET6 + strncpy(in6_ifr.ifr_name, name, sizeof in6_ifr.ifr_name); +#endif /* INET6 */ + + if (ioctl(s, SIOCGIFMETRIC, (caddr_t)&ifr) < 0) + perror("ioctl (SIOCGIFMETRIC)"); + else + metric = ifr.ifr_metric; + +#if defined(SIOCGIFMTU) && !defined(__OpenBSD__) + if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) < 0) + perror("ioctl (SIOCGIFMTU)"); + else + mtu = ifr.ifr_mtu; +#else + mtu = 0; +#endif + + if (argc == 0) { + status(); + return(0); + } + + while (argc > 0) { + register struct cmd *p; + + for (p = cmds; p->c_name; p++) + if (strcmp(*argv, p->c_name) == 0) + break; + if (p->c_name == 0 && setpsrc) + p++; /* got src, do dst */ + if (p->c_func) { + if (p->c_parameter == NEXTARG) { + if (argv[1] == NULL) + errx(1, "'%s' requires argument", + p->c_name); + (*p->c_func)(argv[1], 0); + argc--, argv++; + } else + (*p->c_func)(*argv, p->c_parameter); + } + argc--, argv++; + } + if (1 /*newaddr*/) { + strncpy(rafp->af_addreq, name, sizeof ifr.ifr_name); + if (ioctl(s, rafp->af_pifaddr, rafp->af_addreq) < 0) + Perror("ioctl (SIOCSIFPHYADDR)"); + } + return(0); +} +#define PSRC 0 +#define PDST 1 + +/*ARGSUSED*/ +void +setifpsrc(addr, param) + char *addr; + int param; +{ + param = 0; /*fool gcc*/ + (*afp->af_getaddr)(addr, PSRC); + setpsrc = 1; +} + +/*ARGSUSED*/ +void +setifpdst(addr, param) + char *addr; + int param; +{ + param = 0; /*fool gcc*/ + (*afp->af_getaddr)(addr, PDST); +} + +void +setifflags(vname, value) + char *vname; + int value; +{ + if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) { + Perror("ioctl (SIOCGIFFLAGS)"); + exit(1); + } + strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); + flags = ifr.ifr_flags; + + if (value < 0) { + value = -value; + flags &= ~value; + } else + flags |= value; + ifr.ifr_flags = flags; + if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) + Perror(vname); +} + +#define IFFBITS \ +"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6NOTRAILERS\7RUNNING\10NOARP\ +\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2\20MULTICAST" + +/* + * Print the status of the interface. If an address family was + * specified, show it and it only; otherwise, show them all. + */ +void +status() +{ + struct afswtch *p = NULL; + char *mynext; + struct if_msghdr *myifm; + + printf("%s: ", name); + printb("flags", flags, IFFBITS); + if (metric) + printf(" metric %d", metric); + if (mtu) + printf(" mtu %d", mtu); + putchar('\n'); + + /* + * XXX: Sigh. This is bad, I know. At this point, we may have + * *zero* RTM_NEWADDR's, so we have to "feel the water" before + * incrementing the loop. One day, I might feel inspired enough + * to get the top level loop to pass a count down here so we + * dont have to mess with this. -Peter + */ + myifm = ifm; + + while (1) { + + mynext = next + ifm->ifm_msglen; + + if (mynext >= lim) + break; + + myifm = (struct if_msghdr *)mynext; + + if (myifm->ifm_type != RTM_NEWADDR) + break; + + next = mynext; + + ifm = (struct if_msghdr *)next; + + ifam = (struct ifa_msghdr *)myifm; + info.rti_addrs = ifam->ifam_addrs; + + /* Expand the compacted addresses */ + rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam, + &info); + + if (afp) { + if (afp->af_af == info.rti_info[RTAX_IFA]->sa_family && + afp->af_status != ether_status) { + p = afp; + if (p->af_status != ether_status) + (*p->af_status)(1); + } + } else for (p = afs; p->af_name; p++) { + if (p->af_af == info.rti_info[RTAX_IFA]->sa_family && + p->af_status != ether_status) + (*p->af_status)(0); + } + } + if (afp == NULL || afp->af_status == ether_status) + ether_status(0); + else if (afp && !p) { + warnx("%s has no %s IFA address!", name, afp->af_name); + } + + phys_status(0); +} + +void +phys_status(force) + int force; +{ + char psrcaddr[256]; + char pdstaddr[256]; + char hostname[NI_MAXHOST]; + u_long srccmd, dstcmd; + int flags = NI_NUMERICHOST; + struct ifreq *ifrp; + char *ver = ""; + + force = 0; /*fool gcc*/ + + psrcaddr[0] = pdstaddr[0] = '\0'; + +#ifdef INET6 + srccmd = SIOCGIFPSRCADDR_IN6; + dstcmd = SIOCGIFPDSTADDR_IN6; + ifrp = (struct ifreq *)&in6_ifr; +#else /* INET6 */ + ifrp = ifr; + srccmd = SIOCGIFPSRCADDR; + dstcmd = SIOCGIFPDSTADDR; +#endif /* INET6 */ + + if (0 <= ioctl(s, srccmd, (caddr_t)ifrp)) { + getnameinfo(&ifrp->ifr_addr, ifrp->ifr_addr.sa_len, + hostname, NI_MAXHOST, 0, 0, flags); +#ifdef INET6 + if (ifrp->ifr_addr.sa_family == AF_INET6) + ver = "6"; +#endif /* INET6 */ + sprintf(psrcaddr, "inet%s %s", ver, hostname); + } + if (0 <= ioctl(s, dstcmd, (caddr_t)ifrp)) { + getnameinfo(&ifrp->ifr_addr, ifrp->ifr_addr.sa_len, + hostname, NI_MAXHOST, 0, 0, flags); + sprintf(pdstaddr, "%s", hostname); + } + printf("\tphysical address %s --> %s\n", psrcaddr, pdstaddr); +} + +void +in_status(force) + int force; +{ + struct sockaddr_in *sin, null_sin; +#if 0 + char *inet_ntoa(); +#endif + + memset(&null_sin, 0, sizeof(null_sin)); + + sin = (struct sockaddr_in *)info.rti_info[RTAX_IFA]; + if (!sin || sin->sin_family != AF_INET) { + if (!force) + return; + /* warnx("%s has no AF_INET IFA address!", name); */ + sin = &null_sin; + } + printf("\tinet %s ", inet_ntoa(sin->sin_addr)); + + if (flags & IFF_POINTOPOINT) { + /* note RTAX_BRD overlap with IFF_BROADCAST */ + sin = (struct sockaddr_in *)info.rti_info[RTAX_BRD]; + if (!sin) + sin = &null_sin; + printf("--> %s ", inet_ntoa(sin->sin_addr)); + } + + sin = (struct sockaddr_in *)info.rti_info[RTAX_NETMASK]; + if (!sin) + sin = &null_sin; + printf("netmask 0x%x ", (u_int32_t)ntohl(sin->sin_addr.s_addr)); + + if (flags & IFF_BROADCAST) { + /* note RTAX_BRD overlap with IFF_POINTOPOINT */ + sin = (struct sockaddr_in *)info.rti_info[RTAX_BRD]; + if (sin && sin->sin_addr.s_addr != 0) + printf("broadcast %s", inet_ntoa(sin->sin_addr)); + } + putchar('\n'); +} + +#ifdef INET6 +void +in6_status(force) + int force; +{ + struct sockaddr_in6 *sin, null_sin; +#if 0 + char *inet_ntop(); +#endif + + + memset(&null_sin, 0, sizeof(null_sin)); + + sin = (struct sockaddr_in6 *)info.rti_info[RTAX_IFA]; + if (!sin || sin->sin6_family != AF_INET6) { + if (!force) + return; + /* warnx("%s has no AF_INET6 IFA address!", name); */ + sin = &null_sin; + } + 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 ther interfaces do not have valid destination + * address. + */ + if (sin->sin6_family == AF_INET6) { + if (!sin) + sin = &null_sin; + 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))); + + putchar('\n'); +} +#endif /*INET6*/ + +/*ARGSUSED*/ +void +ether_status(dummy) + int dummy; +{ + char *cp; + int n; + + dummy = 0; /*fool gcc*/ + + cp = (char *)LLADDR(sdl); + if ((n = sdl->sdl_alen) > 0) { + if (sdl->sdl_type == IFT_ETHER) + printf ("\tether "); + else + printf ("\tlladdr "); + while (--n >= 0) + printf("%02x%c",*cp++ & 0xff, n>0? ':' : ' '); + putchar('\n'); + } +} + +void +Perror(cmd) + char *cmd; +{ + extern int errno; + + switch (errno) { + + case ENXIO: + errx(1, "%s: no such interface", cmd); + break; + + case EPERM: + errx(1, "%s: permission denied", cmd); + break; + + default: + err(1, "%s", cmd); + } +} + +#define SIN(x) ((struct sockaddr_in *) &(x)) +struct sockaddr_in *sintab[] = { +SIN(addreq.ifra_addr), SIN(addreq.ifra_dstaddr)}; + +void +in_getaddr(s, which) + char *s; + int which; +{ + register struct sockaddr_in *sin = sintab[which]; + struct hostent *hp; + struct netent *np; + + sin->sin_len = sizeof(*sin); + sin->sin_family = AF_INET; + + if (inet_aton(s, &sin->sin_addr)) + ; + else if ((hp = gethostbyname(s)) != NULL) + bcopy(hp->h_addr, (char *)&sin->sin_addr, hp->h_length); + else if ((np = getnetbyname(s)) != NULL) + sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY); + else + errx(1, "%s: bad value", s); +} + +#ifdef INET6 +#define SIN6(x) ((struct sockaddr_in6 *) &(x)) +struct sockaddr_in6 *sin6tab[] = { +SIN6(in6_addreq.ifra_addr), SIN6(in6_addreq.ifra_dstaddr)}; + +void +in6_getaddr(s, which) + char *s; + int which; +{ + register struct sockaddr_in6 *sin = sin6tab[which]; + + sin->sin6_len = sizeof(*sin); + 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 = atoi(plen); + + if ((len < 0) || (len > 128)) + errx(1, "%s: bad value", plen); + sin->sin6_len = sizeof(*sin); + sin->sin6_family = AF_INET6; + if ((len == 0) || (len == 128)) { + memset(&sin->sin6_addr, -1, sizeof(struct in6_addr)); + return; + } + for (cp = (u_char *)&sin->sin6_addr; len > 7; len -= 8) + *cp++ = -1; + *cp = (-1) << (8 - len); +} +#endif + +/* + * Print a value a la the %b format of the kernel's printf + */ +void +printb(s, v, bits) + char *s; + register unsigned int v; + register char *bits; +{ + register int i, any = 0; + register char c; + + if (bits && *bits == 8) + printf("%s=%o", s, v & 0xffff); + else + printf("%s=%x", s, v & 0xffff); + bits++; + if (bits) { + putchar('<'); + while ((i = *bits++) != 0) { + if ((v & (1 << (i-1))) != 0) { + if (any) + putchar(','); + any = 1; + for (; (c = *bits) > 32; bits++) + putchar(c); + } else + for (; *bits > 32; bits++) + ; + } + putchar('>'); + } +} + +#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); +} +#endif /*INET6*/ |