/* $FreeBSD: src/usr.sbin/gifconfig/gifconfig.c,v 1.2.2.4 2002/08/30 14:23:39 sobomax Exp $ */ /* $KAME: gifconfig.c,v 1.14 2001/01/01 04:04:56 jinmei Exp $ */ /* * 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. 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 #include #include #include #include #if defined(__DragonFly__) #include #endif /* __DragonFly__ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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 newaddr = 0; int s; kvm_t *kvmd; #ifdef INET6 char ntop_buf[INET6_ADDRSTRLEN]; /*inet_ntop()*/ #endif void setifpsrc(char *, int); void setifpdst(char *, int); void setifflags(char *, int); #ifdef SIOCDIFPHYADDR void delifaddrs(char *, int); #endif #define NEXTARG 0xffffff static struct cmd { char *c_name; int c_parameter; /* NEXTARG means next argv */ void (*c_func)(char *, int); } cmds[] = { { "up", IFF_UP, setifflags } , { "down", -IFF_UP, setifflags }, #ifdef SIOCDIFPHYADDR { "delete", 0, delifaddrs }, #endif { 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. */ void status(void); void phys_status(int); void in_status(int); #ifdef INET6 void in6_status(int); #endif void ether_status(int); void Perror(char *); void in_getaddr(char *, int); #ifdef INET6 void in6_getaddr(char *, int); void in6_getprefix(char *, int); #endif void printb(char *, unsigned int, char *); int prefix(void *, int); char ntop_buf[INET6_ADDRSTRLEN]; /* Known address families */ struct afswtch { char *af_name; short af_af; void (*af_status)(int); void (*af_getaddr)(char *, int); void (*af_getprefix)(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(caddr_t, caddr_t, struct rt_addrinfo *); int ifconfig(int argc, char *argv[], int af, struct afswtch *rafp); void rt_xaddrs(caddr_t cp, caddr_t 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; RT_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(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 [af] [physsrc physdst]\n"); #ifdef SIOCDIFPHYADDR fprintf(stderr, " gifconfig interface delete\n"); #endif fprintf(stderr, " gifconfig -a\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(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) { struct cmd *p; for (p = cmds; p->c_name; p++) if (strcmp(*argv, p->c_name) == 0) break; if (p->c_name == NULL && 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 (newaddr) { strncpy(rafp->af_addreq, name, sizeof ifr.ifr_name); if (ioctl(s, rafp->af_pifaddr, rafp->af_addreq) < 0) Perror("ioctl (SIOCSIFPHYADDR)"); } else if (setpsrc) { errx(1, "destination is not specified"); } return(0); } #define PSRC 0 #define PDST 1 /*ARGSUSED*/ void setifpsrc(char *addr, int param) { param = 0; /*fool gcc*/ (*afp->af_getaddr)(addr, PSRC); setpsrc = 1; } /*ARGSUSED*/ void setifpdst(char *addr, int param) { param = 0; /*fool gcc*/ (*afp->af_getaddr)(addr, PDST); newaddr = 1; } void setifflags(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 & 0xffff) | (ifr.ifr_flagshigh << 16); if (value < 0) { value = -value; flags &= ~value; } else flags |= value; ifr.ifr_flags = flags & 0xffff; ifr.ifr_flagshigh = flags >> 16; if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) Perror(vname); } #ifdef SIOCDIFPHYADDR /* ARGSUSED */ void delifaddrs(char *vname, int param) { param = 0; /* fool gcc */ vname = NULL; /* ditto */ if (ioctl(s, SIOCDIFPHYADDR, (caddr_t)&ifr) < 0) err(1, "ioctl(SIOCDIFPHYADDR)"); } #endif #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(void) { 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(int force) { char psrcaddr[256]; char pdstaddr[256]; int flags = NI_NUMERICHOST; char *af; #ifndef SIOCGLIFPHYADDR u_long srccmd, dstcmd; struct ifreq *ifrp; #ifdef INET6 int s6; #endif force = 0; /*fool gcc*/ psrcaddr[0] = pdstaddr[0] = '\0'; #ifdef INET6 s6 = socket(AF_INET6, SOCK_DGRAM, 0); if (s6 < 0) { ifrp = 𝔦 srccmd = SIOCGIFPSRCADDR; dstcmd = SIOCGIFPDSTADDR; } else { close(s6); srccmd = SIOCGIFPSRCADDR_IN6; dstcmd = SIOCGIFPDSTADDR_IN6; ifrp = (struct ifreq *)&in6_ifr; } #else /* INET6 */ ifrp = 𝔦 srccmd = SIOCGIFPSRCADDR; dstcmd = SIOCGIFPDSTADDR; #endif /* INET6 */ if (0 <= ioctl(s, srccmd, (caddr_t)ifrp)) { #ifdef INET6 if (ifrp->ifr_addr.sa_family == AF_INET6) af = "inet6"; else af = "inet"; #else af = "inet"; #endif /* INET6 */ if (getnameinfo(&ifrp->ifr_addr, ifrp->ifr_addr.sa_len, psrcaddr, sizeof(psrcaddr), 0, 0, flags) != 0) psrcaddr[0] = '\0'; } if (0 <= ioctl(s, dstcmd, (caddr_t)ifrp)) { if (getnameinfo(&ifrp->ifr_addr, ifrp->ifr_addr.sa_len, pdstaddr, sizeof(pdstaddr), 0, 0, flags) != 0) pdstaddr[0] = '\0'; } printf("\tphysical address %s %s --> %s\n", af, psrcaddr, pdstaddr); #else struct if_laddrreq iflr; force = 0; /*fool gcc*/ psrcaddr[0] = pdstaddr[0] = '\0'; memset(&iflr, 0, sizeof(iflr)); memcpy(iflr.iflr_name, ifr.ifr_name, sizeof(iflr.iflr_name)); if (0 <= ioctl(s, SIOCGLIFPHYADDR, (caddr_t)&iflr)) { switch (iflr.addr.ss_family) { case AF_INET: af = "inet"; break; #ifdef INET6 case AF_INET6: af = "inet6"; break; #endif /* INET6 */ } if (getnameinfo((struct sockaddr *)&iflr.addr, iflr.addr.ss_len, psrcaddr, sizeof(psrcaddr), 0, 0, flags) != 0) psrcaddr[0] = '\0'; if (getnameinfo((struct sockaddr *)&iflr.dstaddr, iflr.dstaddr.ss_len, pdstaddr, sizeof(pdstaddr), 0, 0, flags) != 0) pdstaddr[0] = '\0'; } printf("\tphysical address %s %s --> %s\n", af, psrcaddr, pdstaddr); #endif } void in_status(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(int force) { struct sockaddr_in6 *sin, null_sin; char hostname[NI_MAXHOST]; int niflags = NI_NUMERICHOST; memset(&null_sin, 0, sizeof(null_sin)); #ifdef NI_WITHSCOPEID niflags |= NI_WITHSCOPEID; #endif 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; } #ifdef __KAME__ if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) { sin->sin6_scope_id = ntohs(*(u_int16_t *)&sin->sin6_addr.s6_addr[2]); sin->sin6_addr.s6_addr[2] = 0; sin->sin6_addr.s6_addr[3] = 0; } #endif getnameinfo((struct sockaddr *)sin, sin->sin6_len, hostname, sizeof(hostname), 0, 0, niflags); printf("\tinet6 %s ", hostname); 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) { #ifdef __KAME__ if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) { sin->sin6_scope_id = ntohs(*(u_int16_t *)&sin->sin6_addr.s6_addr[2]); sin->sin6_addr.s6_addr[2] = 0; sin->sin6_addr.s6_addr[3] = 0; } #endif getnameinfo((struct sockaddr *)sin, sin->sin6_len, hostname, sizeof(hostname), 0, 0, niflags); printf("--> %s ", hostname); } } 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(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(char *cmd) { 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(char *s, int which) { 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(char *s, int which) { 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(char *plen, int which) { struct sockaddr_in6 *sin = sin6tab[which]; 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(char *s, unsigned int v, char *bits) { int i, any = 0; 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(void *val, int size) { u_char *name = (u_char *)val; 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*/