route.c revision 78064
11558Srgrimes/* 21558Srgrimes * Copyright (c) 1983, 1989, 1991, 1993 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * 51558Srgrimes * Redistribution and use in source and binary forms, with or without 61558Srgrimes * modification, are permitted provided that the following conditions 71558Srgrimes * are met: 81558Srgrimes * 1. Redistributions of source code must retain the above copyright 91558Srgrimes * notice, this list of conditions and the following disclaimer. 101558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111558Srgrimes * notice, this list of conditions and the following disclaimer in the 121558Srgrimes * documentation and/or other materials provided with the distribution. 131558Srgrimes * 3. All advertising materials mentioning features or use of this software 141558Srgrimes * must display the following acknowledgement: 151558Srgrimes * This product includes software developed by the University of 161558Srgrimes * California, Berkeley and its contributors. 171558Srgrimes * 4. Neither the name of the University nor the names of its contributors 181558Srgrimes * may be used to endorse or promote products derived from this software 191558Srgrimes * without specific prior written permission. 201558Srgrimes * 211558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311558Srgrimes * SUCH DAMAGE. 321558Srgrimes */ 331558Srgrimes 341558Srgrimes#ifndef lint 3513171Swollmanstatic const char copyright[] = 361558Srgrimes"@(#) Copyright (c) 1983, 1989, 1991, 1993\n\ 371558Srgrimes The Regents of the University of California. All rights reserved.\n"; 381558Srgrimes#endif /* not lint */ 391558Srgrimes 401558Srgrimes#ifndef lint 4137907Scharnier#if 0 421558Srgrimesstatic char sccsid[] = "@(#)route.c 8.3 (Berkeley) 3/19/94"; 4337907Scharnier#endif 4413171Swollmanstatic const char rcsid[] = 4550476Speter "$FreeBSD: head/sbin/route/route.c 78064 2001-06-11 12:39:29Z ume $"; 461558Srgrimes#endif /* not lint */ 471558Srgrimes 481558Srgrimes#include <sys/param.h> 491558Srgrimes#include <sys/file.h> 501558Srgrimes#include <sys/socket.h> 511558Srgrimes#include <sys/ioctl.h> 521558Srgrimes#include <sys/sysctl.h> 5351639Sbillf#include <sys/types.h> 541558Srgrimes 551558Srgrimes#include <net/if.h> 561558Srgrimes#include <net/route.h> 571558Srgrimes#include <net/if_dl.h> 581558Srgrimes#include <netinet/in.h> 5917046Sjulian#include <netatalk/at.h> 6014092Swollman#ifdef NS 611558Srgrimes#include <netns/ns.h> 6214092Swollman#endif 631558Srgrimes#include <arpa/inet.h> 641558Srgrimes#include <netdb.h> 651558Srgrimes 6620287Swollman#include <ctype.h> 6720287Swollman#include <err.h> 681558Srgrimes#include <errno.h> 6969793Sobrien#include <paths.h> 701558Srgrimes#include <stdio.h> 711558Srgrimes#include <stdlib.h> 721558Srgrimes#include <string.h> 7313171Swollman#include <sysexits.h> 7420287Swollman#include <unistd.h> 7578064Sume#include <ifaddrs.h> 761558Srgrimes 771558Srgrimesstruct keytab { 781558Srgrimes char *kt_cp; 791558Srgrimes int kt_i; 801558Srgrimes} keywords[] = { 811558Srgrimes#include "keywords.h" 821558Srgrimes {0, 0} 831558Srgrimes}; 841558Srgrimes 851558Srgrimesstruct ortentry route; 861558Srgrimesunion sockunion { 871558Srgrimes struct sockaddr sa; 881558Srgrimes struct sockaddr_in sin; 8954263Sshin#ifdef INET6 9054263Sshin struct sockaddr_in6 sin6; 9154263Sshin#endif 9217046Sjulian struct sockaddr_at sat; 9314092Swollman#ifdef NS 941558Srgrimes struct sockaddr_ns sns; 9514092Swollman#endif 961558Srgrimes struct sockaddr_dl sdl; 9778064Sume struct sockaddr_storage ss; /* added to avoid memory overrun */ 981558Srgrimes} so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp; 991558Srgrimes 1001558Srgrimestypedef union sockunion *sup; 1011558Srgrimesint pid, rtm_addrs, uid; 1021558Srgrimesint s; 1031558Srgrimesint forcehost, forcenet, doflush, nflag, af, qflag, tflag, keyword(); 1041558Srgrimesint iflag, verbose, aflen = sizeof (struct sockaddr_in); 1051558Srgrimesint locking, lockrest, debugonly; 1061558Srgrimesstruct rt_metrics rt_metrics; 1071558Srgrimesu_long rtm_inits; 10817046Sjulianint atalk_aton __P((const char *, struct at_addr *)); 10917046Sjulianchar *atalk_ntoa __P((struct at_addr)); 11078064Sumeconst char *routename(), *netname(); 1111558Srgrimesvoid flushroutes(), newroute(), monitor(), sockaddr(), sodump(), bprintf(); 1121558Srgrimesvoid print_getmsg(), print_rtmsg(), pmsg_common(), pmsg_addrs(), mask_addr(); 1131558Srgrimesint getaddr(), rtmsg(), x25_makemask(); 11454263Sshinint prefixlen(); 11551639Sbillfextern char *iso_ntoa(); 1161558Srgrimes 11718286Sbdevoid usage __P((const char *)) __dead2; 11813171Swollman 11918286Sbdevoid 1201558Srgrimesusage(cp) 12113171Swollman const char *cp; 1221558Srgrimes{ 1231558Srgrimes if (cp) 12413171Swollman warnx("bad keyword: %s", cp); 1251558Srgrimes (void) fprintf(stderr, 12637907Scharnier "usage: route [-dnqtv] command [[modifiers] args]\n"); 12713171Swollman exit(EX_USAGE); 1281558Srgrimes /* NOTREACHED */ 1291558Srgrimes} 1301558Srgrimes 1311558Srgrimes#define ROUNDUP(a) \ 1321558Srgrimes ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 1331558Srgrimes#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 1341558Srgrimes 1351558Srgrimesint 1361558Srgrimesmain(argc, argv) 1371558Srgrimes int argc; 1381558Srgrimes char **argv; 1391558Srgrimes{ 1401558Srgrimes int ch; 1411558Srgrimes 1421558Srgrimes if (argc < 2) 1431558Srgrimes usage((char *)NULL); 1441558Srgrimes 14537907Scharnier while ((ch = getopt(argc, argv, "nqdtv")) != -1) 1461558Srgrimes switch(ch) { 1471558Srgrimes case 'n': 1481558Srgrimes nflag = 1; 1491558Srgrimes break; 1501558Srgrimes case 'q': 1511558Srgrimes qflag = 1; 1521558Srgrimes break; 1531558Srgrimes case 'v': 1541558Srgrimes verbose = 1; 1551558Srgrimes break; 1561558Srgrimes case 't': 1571558Srgrimes tflag = 1; 1581558Srgrimes break; 1591558Srgrimes case 'd': 1601558Srgrimes debugonly = 1; 1611558Srgrimes break; 1621558Srgrimes case '?': 1631558Srgrimes default: 1641558Srgrimes usage((char *)NULL); 1651558Srgrimes } 1661558Srgrimes argc -= optind; 1671558Srgrimes argv += optind; 1681558Srgrimes 1691558Srgrimes pid = getpid(); 1701558Srgrimes uid = getuid(); 1711558Srgrimes if (tflag) 17269793Sobrien s = open(_PATH_DEVNULL, O_WRONLY, 0); 1731558Srgrimes else 1741558Srgrimes s = socket(PF_ROUTE, SOCK_RAW, 0); 1751558Srgrimes if (s < 0) 17613171Swollman err(EX_OSERR, "socket"); 17719209Sfenner setuid(uid); 1781558Srgrimes if (*argv) 1791558Srgrimes switch (keyword(*argv)) { 1801558Srgrimes case K_GET: 1811558Srgrimes uid = 0; 1821558Srgrimes /* FALLTHROUGH */ 1831558Srgrimes 1841558Srgrimes case K_CHANGE: 1851558Srgrimes case K_ADD: 1861558Srgrimes case K_DELETE: 1871558Srgrimes newroute(argc, argv); 1881558Srgrimes /* NOTREACHED */ 1891558Srgrimes 1901558Srgrimes case K_MONITOR: 1911558Srgrimes monitor(); 1921558Srgrimes /* NOTREACHED */ 1931558Srgrimes 1941558Srgrimes case K_FLUSH: 1951558Srgrimes flushroutes(argc, argv); 1961558Srgrimes exit(0); 1971558Srgrimes /* NOTREACHED */ 1981558Srgrimes } 1991558Srgrimes usage(*argv); 2001558Srgrimes /* NOTREACHED */ 2011558Srgrimes} 2021558Srgrimes 2031558Srgrimes/* 2041558Srgrimes * Purge all entries in the routing tables not 2051558Srgrimes * associated with network interfaces. 2061558Srgrimes */ 2071558Srgrimesvoid 2081558Srgrimesflushroutes(argc, argv) 2091558Srgrimes int argc; 2101558Srgrimes char *argv[]; 2111558Srgrimes{ 2121558Srgrimes size_t needed; 2131558Srgrimes int mib[6], rlen, seqno; 2141558Srgrimes char *buf, *next, *lim; 2151558Srgrimes register struct rt_msghdr *rtm; 2161558Srgrimes 2171558Srgrimes if (uid) { 21813171Swollman errx(EX_NOPERM, "must be root to alter routing table"); 2191558Srgrimes } 2201558Srgrimes shutdown(s, 0); /* Don't want to read back our messages */ 2211558Srgrimes if (argc > 1) { 2221558Srgrimes argv++; 2231558Srgrimes if (argc == 2 && **argv == '-') 2241558Srgrimes switch (keyword(*argv + 1)) { 2251558Srgrimes case K_INET: 2261558Srgrimes af = AF_INET; 2271558Srgrimes break; 22854263Sshin#ifdef INET6 22954263Sshin case K_INET6: 23054263Sshin af = AF_INET6; 23154263Sshin break; 23254263Sshin#endif 23317046Sjulian case K_ATALK: 23417046Sjulian af = AF_APPLETALK; 23517046Sjulian break; 23614092Swollman#ifdef NS 2371558Srgrimes case K_XNS: 2381558Srgrimes af = AF_NS; 2391558Srgrimes break; 24014092Swollman#endif 2411558Srgrimes case K_LINK: 2421558Srgrimes af = AF_LINK; 2431558Srgrimes break; 2441558Srgrimes default: 2451558Srgrimes goto bad; 2461558Srgrimes } else 2471558Srgrimesbad: usage(*argv); 2481558Srgrimes } 2491558Srgrimes mib[0] = CTL_NET; 2501558Srgrimes mib[1] = PF_ROUTE; 2511558Srgrimes mib[2] = 0; /* protocol */ 2521558Srgrimes mib[3] = 0; /* wildcard address family */ 2531558Srgrimes mib[4] = NET_RT_DUMP; 2541558Srgrimes mib[5] = 0; /* no flags */ 2551558Srgrimes if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 25613171Swollman err(EX_OSERR, "route-sysctl-estimate"); 2571558Srgrimes if ((buf = malloc(needed)) == NULL) 25837907Scharnier errx(EX_OSERR, "malloc failed"); 2591558Srgrimes if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) 26013171Swollman err(EX_OSERR, "route-sysctl-get"); 2611558Srgrimes lim = buf + needed; 2621558Srgrimes if (verbose) 2631558Srgrimes (void) printf("Examining routing table from sysctl\n"); 2641558Srgrimes seqno = 0; /* ??? */ 2651558Srgrimes for (next = buf; next < lim; next += rtm->rtm_msglen) { 2661558Srgrimes rtm = (struct rt_msghdr *)next; 2671558Srgrimes if (verbose) 2681558Srgrimes print_rtmsg(rtm, rtm->rtm_msglen); 2691558Srgrimes if ((rtm->rtm_flags & RTF_GATEWAY) == 0) 2701558Srgrimes continue; 2711558Srgrimes if (af) { 2721558Srgrimes struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 2731558Srgrimes 2741558Srgrimes if (sa->sa_family != af) 2751558Srgrimes continue; 2761558Srgrimes } 2771558Srgrimes if (debugonly) 2781558Srgrimes continue; 2791558Srgrimes rtm->rtm_type = RTM_DELETE; 2801558Srgrimes rtm->rtm_seq = seqno; 2811558Srgrimes rlen = write(s, next, rtm->rtm_msglen); 2821558Srgrimes if (rlen < (int)rtm->rtm_msglen) { 28313171Swollman warn("write to routing socket"); 2841558Srgrimes (void) printf("got only %d for rlen\n", rlen); 2851558Srgrimes break; 2861558Srgrimes } 2871558Srgrimes seqno++; 2881558Srgrimes if (qflag) 2891558Srgrimes continue; 2901558Srgrimes if (verbose) 2911558Srgrimes print_rtmsg(rtm, rlen); 2921558Srgrimes else { 2931558Srgrimes struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 2941558Srgrimes (void) printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ? 2951558Srgrimes routename(sa) : netname(sa)); 29678064Sume sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa); 2971558Srgrimes (void) printf("%-20.20s ", routename(sa)); 2981558Srgrimes (void) printf("done\n"); 2991558Srgrimes } 3001558Srgrimes } 3011558Srgrimes} 3021558Srgrimes 30378064Sumeconst char * 3041558Srgrimesroutename(sa) 3051558Srgrimes struct sockaddr *sa; 3061558Srgrimes{ 3071558Srgrimes register char *cp; 30819209Sfenner static char line[MAXHOSTNAMELEN + 1]; 3091558Srgrimes struct hostent *hp; 3101558Srgrimes static char domain[MAXHOSTNAMELEN + 1]; 3111558Srgrimes static int first = 1; 31214092Swollman#ifdef NS 3131558Srgrimes char *ns_print(); 31414092Swollman#endif 3151558Srgrimes 3161558Srgrimes if (first) { 3171558Srgrimes first = 0; 3181558Srgrimes if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 31919209Sfenner (cp = index(domain, '.'))) { 32019209Sfenner domain[MAXHOSTNAMELEN] = '\0'; 3211558Srgrimes (void) strcpy(domain, cp + 1); 32219209Sfenner } else 3231558Srgrimes domain[0] = 0; 3241558Srgrimes } 3251558Srgrimes 3261558Srgrimes if (sa->sa_len == 0) 3271558Srgrimes strcpy(line, "default"); 3281558Srgrimes else switch (sa->sa_family) { 3291558Srgrimes 3301558Srgrimes case AF_INET: 3311558Srgrimes { struct in_addr in; 3321558Srgrimes in = ((struct sockaddr_in *)sa)->sin_addr; 3331558Srgrimes 3341558Srgrimes cp = 0; 3351558Srgrimes if (in.s_addr == INADDR_ANY || sa->sa_len < 4) 3361558Srgrimes cp = "default"; 3371558Srgrimes if (cp == 0 && !nflag) { 3381558Srgrimes hp = gethostbyaddr((char *)&in, sizeof (struct in_addr), 3391558Srgrimes AF_INET); 3401558Srgrimes if (hp) { 3411558Srgrimes if ((cp = index(hp->h_name, '.')) && 3421558Srgrimes !strcmp(cp + 1, domain)) 3431558Srgrimes *cp = 0; 3441558Srgrimes cp = hp->h_name; 3451558Srgrimes } 3461558Srgrimes } 34731958Simp if (cp) { 34831958Simp strncpy(line, cp, sizeof(line) - 1); 34931958Simp line[sizeof(line) - 1] = '\0'; 35077873Sru } else 35177873Sru (void) sprintf(line, "%s", inet_ntoa(in)); 3521558Srgrimes break; 3531558Srgrimes } 3541558Srgrimes 35554263Sshin#ifdef INET6 35654263Sshin case AF_INET6: 35778064Sume { 35878064Sume struct sockaddr_in6 sin6; /* use static var for safety */ 35978064Sume int niflags = 0; 36078064Sume#ifdef NI_WITHSCOPEID 36178064Sume niflags = NI_WITHSCOPEID; 36254263Sshin#endif 36354263Sshin 36478064Sume memset(&sin6, 0, sizeof(sin6)); 36578064Sume memcpy(&sin6, sa, sa->sa_len); 36678064Sume sin6.sin6_len = sizeof(struct sockaddr_in6); 36778064Sume sin6.sin6_family = AF_INET6; 36878064Sume#ifdef __KAME__ 36978064Sume if (sa->sa_len == sizeof(struct sockaddr_in6) && 37078064Sume (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) || 37178064Sume IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) && 37278064Sume sin6.sin6_scope_id == 0) { 37378064Sume sin6.sin6_scope_id = 37478064Sume ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]); 37578064Sume sin6.sin6_addr.s6_addr[2] = 0; 37678064Sume sin6.sin6_addr.s6_addr[3] = 0; 37778064Sume } 37878064Sume#endif 37978064Sume if (nflag) 38078064Sume niflags |= NI_NUMERICHOST; 38178064Sume if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, 38278064Sume line, sizeof(line), NULL, 0, niflags) != 0) 38378064Sume strncpy(line, "invalid", sizeof(line)); 38478064Sume 38578064Sume return(line); 38678064Sume } 38778064Sume#endif 38878064Sume 38917046Sjulian case AF_APPLETALK: 39017046Sjulian (void) snprintf(line, sizeof(line), "atalk %s", 39117046Sjulian atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr)); 39217046Sjulian break; 39317046Sjulian 39414092Swollman#ifdef NS 3951558Srgrimes case AF_NS: 3961558Srgrimes return (ns_print((struct sockaddr_ns *)sa)); 39714092Swollman#endif 3981558Srgrimes 3991558Srgrimes case AF_LINK: 4001558Srgrimes return (link_ntoa((struct sockaddr_dl *)sa)); 4011558Srgrimes 4021558Srgrimes default: 4031558Srgrimes { u_short *s = (u_short *)sa; 4041558Srgrimes u_short *slim = s + ((sa->sa_len + 1) >> 1); 4051558Srgrimes char *cp = line + sprintf(line, "(%d)", sa->sa_family); 40619209Sfenner char *cpe = line + sizeof(line); 4071558Srgrimes 40819209Sfenner while (++s < slim && cp < cpe) /* start with sa->sa_data */ 40919209Sfenner cp += snprintf(cp, cpe - cp, " %x", *s); 4101558Srgrimes break; 4111558Srgrimes } 4121558Srgrimes } 4131558Srgrimes return (line); 4141558Srgrimes} 4151558Srgrimes 4161558Srgrimes/* 4171558Srgrimes * Return the name of the network whose address is given. 4181558Srgrimes * The address is assumed to be that of a net or subnet, not a host. 4191558Srgrimes */ 42078064Sumeconst char * 4211558Srgrimesnetname(sa) 4221558Srgrimes struct sockaddr *sa; 4231558Srgrimes{ 4241558Srgrimes char *cp = 0; 42519209Sfenner static char line[MAXHOSTNAMELEN + 1]; 4261558Srgrimes struct netent *np = 0; 4271558Srgrimes u_long net, mask; 4281558Srgrimes register u_long i; 4291558Srgrimes int subnetshift; 43014092Swollman#ifdef NS 4311558Srgrimes char *ns_print(); 43214092Swollman#endif 4331558Srgrimes 4341558Srgrimes switch (sa->sa_family) { 4351558Srgrimes 4361558Srgrimes case AF_INET: 4371558Srgrimes { struct in_addr in; 4381558Srgrimes in = ((struct sockaddr_in *)sa)->sin_addr; 4391558Srgrimes 4401558Srgrimes i = in.s_addr = ntohl(in.s_addr); 4411558Srgrimes if (in.s_addr == 0) 4421558Srgrimes cp = "default"; 4431558Srgrimes else if (!nflag) { 4441558Srgrimes if (IN_CLASSA(i)) { 4451558Srgrimes mask = IN_CLASSA_NET; 4461558Srgrimes subnetshift = 8; 4471558Srgrimes } else if (IN_CLASSB(i)) { 4481558Srgrimes mask = IN_CLASSB_NET; 4491558Srgrimes subnetshift = 8; 4501558Srgrimes } else { 4511558Srgrimes mask = IN_CLASSC_NET; 4521558Srgrimes subnetshift = 4; 4531558Srgrimes } 4541558Srgrimes /* 4551558Srgrimes * If there are more bits than the standard mask 4561558Srgrimes * would suggest, subnets must be in use. 4571558Srgrimes * Guess at the subnet mask, assuming reasonable 4581558Srgrimes * width subnet fields. 4591558Srgrimes */ 4601558Srgrimes while (in.s_addr &~ mask) 4611558Srgrimes mask = (long)mask >> subnetshift; 4621558Srgrimes net = in.s_addr & mask; 4631558Srgrimes while ((mask & 1) == 0) 4641558Srgrimes mask >>= 1, net >>= 1; 4651558Srgrimes np = getnetbyaddr(net, AF_INET); 4661558Srgrimes if (np) 4671558Srgrimes cp = np->n_name; 4681558Srgrimes } 46977873Sru#define C(x) (unsigned)((x) & 0xff) 4701558Srgrimes if (cp) 47119209Sfenner strncpy(line, cp, sizeof(line)); 4721558Srgrimes else if ((in.s_addr & 0xffffff) == 0) 4731558Srgrimes (void) sprintf(line, "%u", C(in.s_addr >> 24)); 4741558Srgrimes else if ((in.s_addr & 0xffff) == 0) 4751558Srgrimes (void) sprintf(line, "%u.%u", C(in.s_addr >> 24), 4761558Srgrimes C(in.s_addr >> 16)); 4771558Srgrimes else if ((in.s_addr & 0xff) == 0) 4781558Srgrimes (void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24), 4791558Srgrimes C(in.s_addr >> 16), C(in.s_addr >> 8)); 4801558Srgrimes else 4811558Srgrimes (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), 4821558Srgrimes C(in.s_addr >> 16), C(in.s_addr >> 8), 4831558Srgrimes C(in.s_addr)); 48477873Sru#undef C 4851558Srgrimes break; 4861558Srgrimes } 4871558Srgrimes 48854263Sshin#ifdef INET6 48954263Sshin case AF_INET6: 49078064Sume { 49178064Sume struct sockaddr_in6 sin6; /* use static var for safety */ 49278064Sume int niflags = 0; 49378064Sume#ifdef NI_WITHSCOPEID 49478064Sume niflags = NI_WITHSCOPEID; 49554263Sshin#endif 49654263Sshin 49778064Sume memset(&sin6, 0, sizeof(sin6)); 49878064Sume memcpy(&sin6, sa, sa->sa_len); 49978064Sume sin6.sin6_len = sizeof(struct sockaddr_in6); 50078064Sume sin6.sin6_family = AF_INET6; 50178064Sume#ifdef __KAME__ 50278064Sume if (sa->sa_len == sizeof(struct sockaddr_in6) && 50378064Sume (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) || 50478064Sume IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) && 50578064Sume sin6.sin6_scope_id == 0) { 50678064Sume sin6.sin6_scope_id = 50778064Sume ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]); 50878064Sume sin6.sin6_addr.s6_addr[2] = 0; 50978064Sume sin6.sin6_addr.s6_addr[3] = 0; 51078064Sume } 51178064Sume#endif 51278064Sume if (nflag) 51378064Sume niflags |= NI_NUMERICHOST; 51478064Sume if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, 51578064Sume line, sizeof(line), NULL, 0, niflags) != 0) 51678064Sume strncpy(line, "invalid", sizeof(line)); 51778064Sume 51878064Sume return(line); 51978064Sume } 52078064Sume#endif 52178064Sume 52217046Sjulian case AF_APPLETALK: 52317046Sjulian (void) snprintf(line, sizeof(line), "atalk %s", 52417046Sjulian atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr)); 52517046Sjulian break; 52617046Sjulian 52714092Swollman#ifdef NS 5281558Srgrimes case AF_NS: 5291558Srgrimes return (ns_print((struct sockaddr_ns *)sa)); 5301558Srgrimes break; 53114092Swollman#endif 5321558Srgrimes 5331558Srgrimes case AF_LINK: 5341558Srgrimes return (link_ntoa((struct sockaddr_dl *)sa)); 5351558Srgrimes 5361558Srgrimes 5371558Srgrimes default: 5381558Srgrimes { u_short *s = (u_short *)sa->sa_data; 5391558Srgrimes u_short *slim = s + ((sa->sa_len + 1)>>1); 5401558Srgrimes char *cp = line + sprintf(line, "af %d:", sa->sa_family); 54119209Sfenner char *cpe = line + sizeof(line); 5421558Srgrimes 54319209Sfenner while (s < slim && cp < cpe) 54419209Sfenner cp += snprintf(cp, cpe - cp, " %x", *s++); 5451558Srgrimes break; 5461558Srgrimes } 5471558Srgrimes } 5481558Srgrimes return (line); 5491558Srgrimes} 5501558Srgrimes 5511558Srgrimesvoid 5521558Srgrimesset_metric(value, key) 5531558Srgrimes char *value; 5541558Srgrimes int key; 5551558Srgrimes{ 5561558Srgrimes int flag = 0; 5571558Srgrimes u_long noval, *valp = &noval; 5581558Srgrimes 5591558Srgrimes switch (key) { 5601558Srgrimes#define caseof(x, y, z) case x: valp = &rt_metrics.z; flag = y; break 5611558Srgrimes caseof(K_MTU, RTV_MTU, rmx_mtu); 5621558Srgrimes caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount); 5631558Srgrimes caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire); 5641558Srgrimes caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe); 5651558Srgrimes caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe); 5661558Srgrimes caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh); 5671558Srgrimes caseof(K_RTT, RTV_RTT, rmx_rtt); 5681558Srgrimes caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar); 5691558Srgrimes } 5701558Srgrimes rtm_inits |= flag; 5711558Srgrimes if (lockrest || locking) 5721558Srgrimes rt_metrics.rmx_locks |= flag; 5731558Srgrimes if (locking) 5741558Srgrimes locking = 0; 5751558Srgrimes *valp = atoi(value); 5761558Srgrimes} 5771558Srgrimes 5781558Srgrimesvoid 5791558Srgrimesnewroute(argc, argv) 5801558Srgrimes int argc; 5811558Srgrimes register char **argv; 5821558Srgrimes{ 5831558Srgrimes char *cmd, *dest = "", *gateway = "", *err; 5841558Srgrimes int ishost = 0, ret, attempts, oerrno, flags = RTF_STATIC; 5851558Srgrimes int key; 5861558Srgrimes struct hostent *hp = 0; 5871558Srgrimes 5881558Srgrimes if (uid) { 58913171Swollman errx(EX_NOPERM, "must be root to alter routing table"); 5901558Srgrimes } 5911558Srgrimes cmd = argv[0]; 5921558Srgrimes if (*cmd != 'g') 5931558Srgrimes shutdown(s, 0); /* Don't want to read back our messages */ 5941558Srgrimes while (--argc > 0) { 5951558Srgrimes if (**(++argv)== '-') { 5961558Srgrimes switch (key = keyword(1 + *argv)) { 5971558Srgrimes case K_LINK: 5981558Srgrimes af = AF_LINK; 5991558Srgrimes aflen = sizeof(struct sockaddr_dl); 6001558Srgrimes break; 6011558Srgrimes case K_INET: 6021558Srgrimes af = AF_INET; 6031558Srgrimes aflen = sizeof(struct sockaddr_in); 6041558Srgrimes break; 60554263Sshin#ifdef INET6 60654263Sshin case K_INET6: 60754263Sshin af = AF_INET6; 60854263Sshin aflen = sizeof(struct sockaddr_in6); 60954263Sshin break; 61054263Sshin#endif 61117046Sjulian case K_ATALK: 61217046Sjulian af = AF_APPLETALK; 61317046Sjulian aflen = sizeof(struct sockaddr_at); 61417046Sjulian break; 6151558Srgrimes case K_SA: 6161558Srgrimes af = PF_ROUTE; 6171558Srgrimes aflen = sizeof(union sockunion); 6181558Srgrimes break; 61914092Swollman#ifdef NS 6201558Srgrimes case K_XNS: 6211558Srgrimes af = AF_NS; 6221558Srgrimes aflen = sizeof(struct sockaddr_ns); 6231558Srgrimes break; 62414092Swollman#endif 6251558Srgrimes case K_IFACE: 6261558Srgrimes case K_INTERFACE: 6271558Srgrimes iflag++; 6282787Spst break; 6291558Srgrimes case K_NOSTATIC: 6301558Srgrimes flags &= ~RTF_STATIC; 6311558Srgrimes break; 63217591Sjulian case K_LLINFO: 63317591Sjulian flags |= RTF_LLINFO; 63417591Sjulian break; 6351558Srgrimes case K_LOCK: 6361558Srgrimes locking = 1; 6371558Srgrimes break; 6381558Srgrimes case K_LOCKREST: 6391558Srgrimes lockrest = 1; 6401558Srgrimes break; 6411558Srgrimes case K_HOST: 6421558Srgrimes forcehost++; 6431558Srgrimes break; 6441558Srgrimes case K_REJECT: 6451558Srgrimes flags |= RTF_REJECT; 6461558Srgrimes break; 6471558Srgrimes case K_BLACKHOLE: 6481558Srgrimes flags |= RTF_BLACKHOLE; 6491558Srgrimes break; 6501558Srgrimes case K_PROTO1: 6511558Srgrimes flags |= RTF_PROTO1; 6521558Srgrimes break; 6531558Srgrimes case K_PROTO2: 6541558Srgrimes flags |= RTF_PROTO2; 6551558Srgrimes break; 6561558Srgrimes case K_CLONING: 6571558Srgrimes flags |= RTF_CLONING; 6581558Srgrimes break; 6591558Srgrimes case K_XRESOLVE: 6601558Srgrimes flags |= RTF_XRESOLVE; 6611558Srgrimes break; 6621558Srgrimes case K_STATIC: 6631558Srgrimes flags |= RTF_STATIC; 6641558Srgrimes break; 6651558Srgrimes case K_IFA: 66647668Sru if (!--argc) 66747668Sru usage((char *)NULL); 6681558Srgrimes (void) getaddr(RTA_IFA, *++argv, 0); 6691558Srgrimes break; 6701558Srgrimes case K_IFP: 67147668Sru if (!--argc) 67247668Sru usage((char *)NULL); 6731558Srgrimes (void) getaddr(RTA_IFP, *++argv, 0); 6741558Srgrimes break; 6751558Srgrimes case K_GENMASK: 67647668Sru if (!--argc) 67747668Sru usage((char *)NULL); 6781558Srgrimes (void) getaddr(RTA_GENMASK, *++argv, 0); 6791558Srgrimes break; 6801558Srgrimes case K_GATEWAY: 68147668Sru if (!--argc) 68247668Sru usage((char *)NULL); 6831558Srgrimes (void) getaddr(RTA_GATEWAY, *++argv, 0); 6841558Srgrimes break; 6851558Srgrimes case K_DST: 68647668Sru if (!--argc) 68747668Sru usage((char *)NULL); 6881558Srgrimes ishost = getaddr(RTA_DST, *++argv, &hp); 6891558Srgrimes dest = *argv; 6901558Srgrimes break; 6911558Srgrimes case K_NETMASK: 69247668Sru if (!--argc) 69347668Sru usage((char *)NULL); 6941558Srgrimes (void) getaddr(RTA_NETMASK, *++argv, 0); 6951558Srgrimes /* FALLTHROUGH */ 6961558Srgrimes case K_NET: 6971558Srgrimes forcenet++; 6981558Srgrimes break; 69954263Sshin case K_PREFIXLEN: 70054263Sshin if (!--argc) 70154263Sshin usage((char *)NULL); 70254263Sshin if (prefixlen(*++argv) == -1) { 70354263Sshin forcenet = 0; 70454263Sshin ishost = 1; 70554263Sshin } else { 70654263Sshin forcenet = 1; 70754263Sshin ishost = 0; 70854263Sshin } 70954263Sshin break; 7101558Srgrimes case K_MTU: 7111558Srgrimes case K_HOPCOUNT: 7121558Srgrimes case K_EXPIRE: 7131558Srgrimes case K_RECVPIPE: 7141558Srgrimes case K_SENDPIPE: 7151558Srgrimes case K_SSTHRESH: 7161558Srgrimes case K_RTT: 7171558Srgrimes case K_RTTVAR: 71847668Sru if (!--argc) 71947668Sru usage((char *)NULL); 7201558Srgrimes set_metric(*++argv, key); 7211558Srgrimes break; 7221558Srgrimes default: 7231558Srgrimes usage(1+*argv); 7241558Srgrimes } 7251558Srgrimes } else { 7261558Srgrimes if ((rtm_addrs & RTA_DST) == 0) { 7271558Srgrimes dest = *argv; 7281558Srgrimes ishost = getaddr(RTA_DST, *argv, &hp); 7291558Srgrimes } else if ((rtm_addrs & RTA_GATEWAY) == 0) { 7301558Srgrimes gateway = *argv; 7311558Srgrimes (void) getaddr(RTA_GATEWAY, *argv, &hp); 7321558Srgrimes } else { 7331558Srgrimes (void) getaddr(RTA_NETMASK, *argv, 0); 7341558Srgrimes } 7351558Srgrimes } 7361558Srgrimes } 73754263Sshin if (forcehost) { 7381558Srgrimes ishost = 1; 73954263Sshin#ifdef INET6 74054263Sshin if (af == AF_INET6) { 74154263Sshin rtm_addrs &= ~RTA_NETMASK; 74254263Sshin memset((void *)&so_mask, 0, sizeof(so_mask)); 74354263Sshin } 74454263Sshin#endif 74554263Sshin } 7461558Srgrimes if (forcenet) 7471558Srgrimes ishost = 0; 7481558Srgrimes flags |= RTF_UP; 7491558Srgrimes if (ishost) 7501558Srgrimes flags |= RTF_HOST; 7511558Srgrimes if (iflag == 0) 7521558Srgrimes flags |= RTF_GATEWAY; 7531558Srgrimes for (attempts = 1; ; attempts++) { 7541558Srgrimes errno = 0; 7551558Srgrimes if ((ret = rtmsg(*cmd, flags)) == 0) 7561558Srgrimes break; 7571558Srgrimes if (errno != ENETUNREACH && errno != ESRCH) 7581558Srgrimes break; 7591558Srgrimes if (af == AF_INET && *gateway && hp && hp->h_addr_list[1]) { 7601558Srgrimes hp->h_addr_list++; 7611558Srgrimes bcopy(hp->h_addr_list[0], &so_gate.sin.sin_addr, 76231958Simp MIN(hp->h_length, sizeof(so_gate.sin.sin_addr))); 7631558Srgrimes } else 7641558Srgrimes break; 7651558Srgrimes } 7661558Srgrimes if (*cmd == 'g') 7671558Srgrimes exit(0); 7681558Srgrimes oerrno = errno; 7691558Srgrimes (void) printf("%s %s %s", cmd, ishost? "host" : "net", dest); 7701558Srgrimes if (*gateway) { 7711558Srgrimes (void) printf(": gateway %s", gateway); 7721558Srgrimes if (attempts > 1 && ret == 0 && af == AF_INET) 7731558Srgrimes (void) printf(" (%s)", 7741558Srgrimes inet_ntoa(((struct sockaddr_in *)&route.rt_gateway)->sin_addr)); 7751558Srgrimes } 77677873Sru if (ret == 0) { 7771558Srgrimes (void) printf("\n"); 77877873Sru exit(0); 77977873Sru } else { 7801558Srgrimes switch (oerrno) { 7811558Srgrimes case ESRCH: 7821558Srgrimes err = "not in table"; 7831558Srgrimes break; 7841558Srgrimes case EBUSY: 7851558Srgrimes err = "entry in use"; 7861558Srgrimes break; 7871558Srgrimes case ENOBUFS: 7881558Srgrimes err = "routing table overflow"; 7891558Srgrimes break; 79077908Sru case EDQUOT: /* handle recursion avoidance in rt_setgate() */ 79177908Sru err = "gateway uses the same route"; 79277908Sru break; 7931558Srgrimes default: 7941558Srgrimes err = strerror(oerrno); 7951558Srgrimes break; 7961558Srgrimes } 7971558Srgrimes (void) printf(": %s\n", err); 79877873Sru exit(1); 7991558Srgrimes } 8001558Srgrimes} 8011558Srgrimes 8021558Srgrimesvoid 80324558Sphkinet_makenetandmask(net, sin, bits) 80424558Sphk u_long net, bits; 8051558Srgrimes register struct sockaddr_in *sin; 8061558Srgrimes{ 8071558Srgrimes u_long addr, mask = 0; 8081558Srgrimes register char *cp; 8091558Srgrimes 8101558Srgrimes rtm_addrs |= RTA_NETMASK; 81177904Sru if (net == 0) 81266448Sru mask = addr = 0; 81366448Sru else if (net < 128) { 8141558Srgrimes addr = net << IN_CLASSA_NSHIFT; 8151558Srgrimes mask = IN_CLASSA_NET; 8161558Srgrimes } else if (net < 65536) { 8171558Srgrimes addr = net << IN_CLASSB_NSHIFT; 8181558Srgrimes mask = IN_CLASSB_NET; 8191558Srgrimes } else if (net < 16777216L) { 8201558Srgrimes addr = net << IN_CLASSC_NSHIFT; 8211558Srgrimes mask = IN_CLASSC_NET; 8221558Srgrimes } else { 8231558Srgrimes addr = net; 8241558Srgrimes if ((addr & IN_CLASSA_HOST) == 0) 8251558Srgrimes mask = IN_CLASSA_NET; 8261558Srgrimes else if ((addr & IN_CLASSB_HOST) == 0) 8271558Srgrimes mask = IN_CLASSB_NET; 8281558Srgrimes else if ((addr & IN_CLASSC_HOST) == 0) 8291558Srgrimes mask = IN_CLASSC_NET; 8301558Srgrimes else 8311558Srgrimes mask = -1; 8321558Srgrimes } 83377904Sru if (bits) 83477904Sru mask = 0xffffffff << (32 - bits); 8351558Srgrimes sin->sin_addr.s_addr = htonl(addr); 8361558Srgrimes sin = &so_mask.sin; 8371558Srgrimes sin->sin_addr.s_addr = htonl(mask); 8381558Srgrimes sin->sin_len = 0; 8391558Srgrimes sin->sin_family = 0; 8401558Srgrimes cp = (char *)(&sin->sin_addr + 1); 8411558Srgrimes while (*--cp == 0 && cp > (char *)sin) 8421558Srgrimes ; 8431558Srgrimes sin->sin_len = 1 + cp - (char *)sin; 8441558Srgrimes} 8451558Srgrimes 8461558Srgrimes/* 8471558Srgrimes * Interpret an argument as a network address of some kind, 8481558Srgrimes * returning 1 if a host address, 0 if a network address. 8491558Srgrimes */ 8501558Srgrimesint 8511558Srgrimesgetaddr(which, s, hpp) 8521558Srgrimes int which; 8531558Srgrimes char *s; 8541558Srgrimes struct hostent **hpp; 8551558Srgrimes{ 8561558Srgrimes register sup su; 8571558Srgrimes struct hostent *hp; 8581558Srgrimes struct netent *np; 8591558Srgrimes u_long val; 86066449Sru char *q; 86154263Sshin int afamily; /* local copy of af so we can change it */ 8621558Srgrimes 8631558Srgrimes if (af == 0) { 8641558Srgrimes af = AF_INET; 8651558Srgrimes aflen = sizeof(struct sockaddr_in); 8661558Srgrimes } 86754263Sshin afamily = af; 8681558Srgrimes rtm_addrs |= which; 8691558Srgrimes switch (which) { 8701558Srgrimes case RTA_DST: 8711558Srgrimes su = &so_dst; 8721558Srgrimes break; 8731558Srgrimes case RTA_GATEWAY: 8741558Srgrimes su = &so_gate; 87517486Sjulian if (iflag) { 87678064Sume struct ifaddrs *ifap, *ifa; 87778064Sume struct sockaddr_dl *sdl = NULL; 87817486Sjulian 87978064Sume if (getifaddrs(&ifap)) 88078064Sume err(1, "getifaddrs"); 88117486Sjulian 88278064Sume for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 88378064Sume if (ifa->ifa_addr->sa_family != AF_LINK) 88478064Sume continue; 88517486Sjulian 88678064Sume if (strcmp(s, ifa->ifa_name) || 88778064Sume (ifa->ifa_flags & IFF_POINTOPOINT) == 0) 88878064Sume continue; 88978064Sume 89078064Sume sdl = (struct sockaddr_dl *)ifa->ifa_addr; 89117486Sjulian } 89217486Sjulian /* If we found it, then use it */ 89317486Sjulian if (sdl) { 89478064Sume /* 89578064Sume * Copy is safe since we have a 89678064Sume * sockaddr_storage member in sockunion{}. 89778064Sume * Note that we need to copy before calling 89878064Sume * freeifaddrs(). 89978064Sume */ 90078064Sume memcpy(&su->sdl, sdl, sdl->sdl_len); 90178064Sume } 90278064Sume freeifaddrs(ifap); 90378064Sume if (sdl) 90417486Sjulian return(1); 90517486Sjulian } 9061558Srgrimes break; 9071558Srgrimes case RTA_NETMASK: 9081558Srgrimes su = &so_mask; 9091558Srgrimes break; 9101558Srgrimes case RTA_GENMASK: 9111558Srgrimes su = &so_genmask; 9121558Srgrimes break; 9131558Srgrimes case RTA_IFP: 9141558Srgrimes su = &so_ifp; 91554263Sshin afamily = AF_LINK; 9161558Srgrimes break; 9171558Srgrimes case RTA_IFA: 9181558Srgrimes su = &so_ifa; 9191558Srgrimes break; 9201558Srgrimes default: 92137907Scharnier usage("internal error"); 9221558Srgrimes /*NOTREACHED*/ 9231558Srgrimes } 9241558Srgrimes su->sa.sa_len = aflen; 92554263Sshin su->sa.sa_family = afamily; /* cases that don't want it have left already */ 9261558Srgrimes if (strcmp(s, "default") == 0) { 92727500Sjulian /* 92827500Sjulian * Default is net 0.0.0.0/0 92927500Sjulian */ 9301558Srgrimes switch (which) { 9311558Srgrimes case RTA_DST: 9321558Srgrimes forcenet++; 93327500Sjulian /* bzero(su, sizeof(*su)); *//* for readability */ 9341558Srgrimes (void) getaddr(RTA_NETMASK, s, 0); 9351558Srgrimes break; 9361558Srgrimes case RTA_NETMASK: 9371558Srgrimes case RTA_GENMASK: 93827500Sjulian /* bzero(su, sizeof(*su)); *//* for readability */ 9391558Srgrimes } 9401558Srgrimes return (0); 9411558Srgrimes } 94254263Sshin switch (afamily) { 94354263Sshin#ifdef INET6 94454263Sshin case AF_INET6: 94578064Sume { 94657108Sshin struct addrinfo hints, *res; 94757108Sshin 94878064Sume memset(&hints, 0, sizeof(hints)); 94978064Sume hints.ai_family = afamily; /*AF_INET6*/ 95078064Sume hints.ai_flags = AI_NUMERICHOST; 95178064Sume hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 95278064Sume if (getaddrinfo(s, "0", &hints, &res) != 0 || 95378064Sume res->ai_family != AF_INET6 || 95478064Sume res->ai_addrlen != sizeof(su->sin6)) { 95578064Sume (void) fprintf(stderr, "%s: bad value\n", s); 95654263Sshin exit(1); 95754263Sshin } 95878064Sume memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6)); 95978064Sume#ifdef __KAME__ 96078064Sume if ((IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr) || 96178064Sume IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr)) && 96278064Sume su->sin6.sin6_scope_id) { 96378064Sume *(u_int16_t *)&su->sin6.sin6_addr.s6_addr[2] = 96478064Sume htons(su->sin6.sin6_scope_id); 96578064Sume su->sin6.sin6_scope_id = 0; 96678064Sume } 96754263Sshin#endif 96878064Sume freeaddrinfo(res); 96978064Sume return (0); 97078064Sume } 97178064Sume#endif /* INET6 */ 97254263Sshin 97314092Swollman#ifdef NS 9741558Srgrimes case AF_NS: 9751558Srgrimes if (which == RTA_DST) { 9761558Srgrimes extern short ns_bh[3]; 9771558Srgrimes struct sockaddr_ns *sms = &(so_mask.sns); 9781558Srgrimes bzero((char *)sms, sizeof(*sms)); 9791558Srgrimes sms->sns_family = 0; 9801558Srgrimes sms->sns_len = 6; 9811558Srgrimes sms->sns_addr.x_net = *(union ns_net *)ns_bh; 9821558Srgrimes rtm_addrs |= RTA_NETMASK; 9831558Srgrimes } 9841558Srgrimes su->sns.sns_addr = ns_addr(s); 9851558Srgrimes return (!ns_nullhost(su->sns.sns_addr)); 98614092Swollman#endif 9871558Srgrimes 9881558Srgrimes 98917046Sjulian case AF_APPLETALK: 99017046Sjulian if (!atalk_aton(s, &su->sat.sat_addr)) 99117046Sjulian errx(EX_NOHOST, "bad address: %s", s); 99217265Sjulian rtm_addrs |= RTA_NETMASK; 99317265Sjulian return(forcehost || su->sat.sat_addr.s_node != 0); 99417046Sjulian 9951558Srgrimes case AF_LINK: 9961558Srgrimes link_addr(s, &su->sdl); 9971558Srgrimes return (1); 9981558Srgrimes 9991558Srgrimes 10001558Srgrimes case PF_ROUTE: 10011558Srgrimes su->sa.sa_len = sizeof(*su); 10021558Srgrimes sockaddr(s, &su->sa); 10031558Srgrimes return (1); 10041558Srgrimes 10051558Srgrimes case AF_INET: 10061558Srgrimes default: 10071558Srgrimes break; 10081558Srgrimes } 10091558Srgrimes 10101558Srgrimes if (hpp == NULL) 10111558Srgrimes hpp = &hp; 10121558Srgrimes *hpp = NULL; 101324558Sphk 101424558Sphk q = strchr(s,'/'); 101524558Sphk if (q && which == RTA_DST) { 101624558Sphk *q = '\0'; 101777904Sru if ((val = inet_network(s)) != INADDR_NONE) { 101824558Sphk inet_makenetandmask( 101977904Sru val, &su->sin, strtoul(q+1, 0, 0)); 102024558Sphk return (0); 102124558Sphk } 102266449Sru *q = '/'; 102324558Sphk } 102466449Sru if ((which != RTA_DST || forcenet == 0) && 102566449Sru (val = inet_addr(s)) != INADDR_NONE) { 10261558Srgrimes su->sin.sin_addr.s_addr = val; 102766449Sru if (which != RTA_DST || 102866449Sru inet_lnaof(su->sin.sin_addr) != INADDR_ANY) 10291558Srgrimes return (1); 10301558Srgrimes else { 10311558Srgrimes val = ntohl(val); 10321558Srgrimes goto netdone; 10331558Srgrimes } 10341558Srgrimes } 103566449Sru if (which == RTA_DST && forcehost == 0 && 103666449Sru ((val = inet_network(s)) != INADDR_NONE || 103766449Sru ((np = getnetbyname(s)) != NULL && (val = np->n_net) != 0))) { 10381558Srgrimesnetdone: 103966449Sru inet_makenetandmask(val, &su->sin, 0); 10401558Srgrimes return (0); 10411558Srgrimes } 10421558Srgrimes hp = gethostbyname(s); 10431558Srgrimes if (hp) { 10441558Srgrimes *hpp = hp; 10451558Srgrimes su->sin.sin_family = hp->h_addrtype; 104631958Simp bcopy(hp->h_addr, (char *)&su->sin.sin_addr, 104732008Simp MIN(hp->h_length, sizeof(su->sin.sin_addr))); 10481558Srgrimes return (1); 10491558Srgrimes } 105013515Smpp errx(EX_NOHOST, "bad address: %s", s); 10511558Srgrimes} 10521558Srgrimes 105354263Sshinint 105454263Sshinprefixlen(s) 105554263Sshin char *s; 105654263Sshin{ 105754263Sshin int len = atoi(s), q, r; 105854263Sshin int max; 105954263Sshin char *p; 10601558Srgrimes 106154263Sshin rtm_addrs |= RTA_NETMASK; 106254263Sshin switch (af) { 106354263Sshin#ifdef INET6 106454263Sshin case AF_INET6: 106554263Sshin max = 128; 106654263Sshin p = (char *)&so_mask.sin6.sin6_addr; 106754263Sshin break; 106854263Sshin#endif 106954263Sshin case AF_INET: 107054263Sshin max = 32; 107154263Sshin p = (char *)&so_mask.sin.sin_addr; 107254263Sshin break; 107354263Sshin default: 107454263Sshin (void) fprintf(stderr, "prefixlen not supported in this af\n"); 107554263Sshin exit(1); 107654263Sshin /*NOTREACHED*/ 107754263Sshin } 107854263Sshin 107954263Sshin if (len < 0 || max < len) { 108054263Sshin (void) fprintf(stderr, "%s: bad value\n", s); 108154263Sshin exit(1); 108254263Sshin } 108354263Sshin 108454263Sshin q = len >> 3; 108554263Sshin r = len & 7; 108654263Sshin so_mask.sa.sa_family = af; 108754263Sshin so_mask.sa.sa_len = aflen; 108854263Sshin memset((void *)p, 0, max / 8); 108954263Sshin if (q > 0) 109054263Sshin memset((void *)p, 0xff, q); 109154263Sshin if (r > 0) 109254263Sshin *((u_char *)p + q) = (0xff00 >> r) & 0xff; 109354263Sshin if (len == max) 109454263Sshin return -1; 109554263Sshin else 109654263Sshin return len; 109754263Sshin} 109854263Sshin 109914092Swollman#ifdef NS 11001558Srgrimesshort ns_nullh[] = {0,0,0}; 11011558Srgrimesshort ns_bh[] = {-1,-1,-1}; 11021558Srgrimes 11031558Srgrimeschar * 11041558Srgrimesns_print(sns) 11051558Srgrimes struct sockaddr_ns *sns; 11061558Srgrimes{ 11071558Srgrimes struct ns_addr work; 11081558Srgrimes union { union ns_net net_e; u_long long_e; } net; 11091558Srgrimes u_short port; 111022953Sroberto static char mybuf[50+MAXHOSTNAMELEN], cport[10], chost[25]; 11111558Srgrimes char *host = ""; 11121558Srgrimes register char *p; 11131558Srgrimes register u_char *q; 11141558Srgrimes 11151558Srgrimes work = sns->sns_addr; 11161558Srgrimes port = ntohs(work.x_port); 11171558Srgrimes work.x_port = 0; 11181558Srgrimes net.net_e = work.x_net; 11191558Srgrimes if (ns_nullhost(work) && net.long_e == 0) { 11201558Srgrimes if (!port) 11211558Srgrimes return ("*.*"); 11221558Srgrimes (void) sprintf(mybuf, "*.%XH", port); 11231558Srgrimes return (mybuf); 11241558Srgrimes } 11251558Srgrimes 11261558Srgrimes if (bcmp((char *)ns_bh, (char *)work.x_host.c_host, 6) == 0) 11271558Srgrimes host = "any"; 11281558Srgrimes else if (bcmp((char *)ns_nullh, (char *)work.x_host.c_host, 6) == 0) 11291558Srgrimes host = "*"; 11301558Srgrimes else { 11311558Srgrimes q = work.x_host.c_host; 11321558Srgrimes (void) sprintf(chost, "%02X%02X%02X%02X%02X%02XH", 11331558Srgrimes q[0], q[1], q[2], q[3], q[4], q[5]); 11341558Srgrimes for (p = chost; *p == '0' && p < chost + 12; p++) 11351558Srgrimes /* void */; 11361558Srgrimes host = p; 11371558Srgrimes } 11381558Srgrimes if (port) 11391558Srgrimes (void) sprintf(cport, ".%XH", htons(port)); 11401558Srgrimes else 11411558Srgrimes *cport = 0; 11421558Srgrimes 114354263Sshin (void) snprintf(mybuf, sizeof(mybuf), "%lxH.%s%s", 114454263Sshin (unsigned long)ntohl(net.long_e), 114554263Sshin host, cport); 11461558Srgrimes return (mybuf); 11471558Srgrimes} 114814092Swollman#endif 11491558Srgrimes 11501558Srgrimesvoid 11511558Srgrimesinterfaces() 11521558Srgrimes{ 11531558Srgrimes size_t needed; 11541558Srgrimes int mib[6]; 11551558Srgrimes char *buf, *lim, *next; 11561558Srgrimes register struct rt_msghdr *rtm; 11571558Srgrimes 11581558Srgrimes mib[0] = CTL_NET; 11591558Srgrimes mib[1] = PF_ROUTE; 11601558Srgrimes mib[2] = 0; /* protocol */ 11611558Srgrimes mib[3] = 0; /* wildcard address family */ 11621558Srgrimes mib[4] = NET_RT_IFLIST; 11631558Srgrimes mib[5] = 0; /* no flags */ 11641558Srgrimes if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 116513171Swollman err(EX_OSERR, "route-sysctl-estimate"); 11661558Srgrimes if ((buf = malloc(needed)) == NULL) 116737907Scharnier errx(EX_OSERR, "malloc failed"); 11681558Srgrimes if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) 116913171Swollman err(EX_OSERR, "actual retrieval of interface table"); 11701558Srgrimes lim = buf + needed; 11711558Srgrimes for (next = buf; next < lim; next += rtm->rtm_msglen) { 11721558Srgrimes rtm = (struct rt_msghdr *)next; 11731558Srgrimes print_rtmsg(rtm, rtm->rtm_msglen); 11741558Srgrimes } 11751558Srgrimes} 11761558Srgrimes 11771558Srgrimesvoid 11781558Srgrimesmonitor() 11791558Srgrimes{ 11801558Srgrimes int n; 11811558Srgrimes char msg[2048]; 11821558Srgrimes 11831558Srgrimes verbose = 1; 11841558Srgrimes if (debugonly) { 11851558Srgrimes interfaces(); 11861558Srgrimes exit(0); 11871558Srgrimes } 11881558Srgrimes for(;;) { 118954263Sshin time_t now; 11901558Srgrimes n = read(s, msg, 2048); 119154263Sshin now = time(NULL); 119271061Sphk (void) printf("\ngot message of size %d on %s", n, ctime(&now)); 11931558Srgrimes print_rtmsg((struct rt_msghdr *)msg, n); 11941558Srgrimes } 11951558Srgrimes} 11961558Srgrimes 11971558Srgrimesstruct { 11981558Srgrimes struct rt_msghdr m_rtm; 11991558Srgrimes char m_space[512]; 12001558Srgrimes} m_rtmsg; 12011558Srgrimes 12021558Srgrimesint 12031558Srgrimesrtmsg(cmd, flags) 12041558Srgrimes int cmd, flags; 12051558Srgrimes{ 12061558Srgrimes static int seq; 12071558Srgrimes int rlen; 12081558Srgrimes register char *cp = m_rtmsg.m_space; 12091558Srgrimes register int l; 12101558Srgrimes 12111558Srgrimes#define NEXTADDR(w, u) \ 12121558Srgrimes if (rtm_addrs & (w)) {\ 12131558Srgrimes l = ROUNDUP(u.sa.sa_len); bcopy((char *)&(u), cp, l); cp += l;\ 12141558Srgrimes if (verbose) sodump(&(u),"u");\ 12151558Srgrimes } 12161558Srgrimes 12171558Srgrimes errno = 0; 12181558Srgrimes bzero((char *)&m_rtmsg, sizeof(m_rtmsg)); 12191558Srgrimes if (cmd == 'a') 12201558Srgrimes cmd = RTM_ADD; 12211558Srgrimes else if (cmd == 'c') 12221558Srgrimes cmd = RTM_CHANGE; 12231558Srgrimes else if (cmd == 'g') { 12241558Srgrimes cmd = RTM_GET; 12251558Srgrimes if (so_ifp.sa.sa_family == 0) { 122613171Swollman so_ifp.sa.sa_family = AF_LINK; 122713171Swollman so_ifp.sa.sa_len = sizeof(struct sockaddr_dl); 12281558Srgrimes rtm_addrs |= RTA_IFP; 12291558Srgrimes } 12301558Srgrimes } else 12311558Srgrimes cmd = RTM_DELETE; 12321558Srgrimes#define rtm m_rtmsg.m_rtm 12331558Srgrimes rtm.rtm_type = cmd; 12341558Srgrimes rtm.rtm_flags = flags; 12351558Srgrimes rtm.rtm_version = RTM_VERSION; 12361558Srgrimes rtm.rtm_seq = ++seq; 12371558Srgrimes rtm.rtm_addrs = rtm_addrs; 12381558Srgrimes rtm.rtm_rmx = rt_metrics; 12391558Srgrimes rtm.rtm_inits = rtm_inits; 12401558Srgrimes 12411558Srgrimes if (rtm_addrs & RTA_NETMASK) 12421558Srgrimes mask_addr(); 12431558Srgrimes NEXTADDR(RTA_DST, so_dst); 12441558Srgrimes NEXTADDR(RTA_GATEWAY, so_gate); 12451558Srgrimes NEXTADDR(RTA_NETMASK, so_mask); 12461558Srgrimes NEXTADDR(RTA_GENMASK, so_genmask); 12471558Srgrimes NEXTADDR(RTA_IFP, so_ifp); 12481558Srgrimes NEXTADDR(RTA_IFA, so_ifa); 12491558Srgrimes rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; 12501558Srgrimes if (verbose) 12511558Srgrimes print_rtmsg(&rtm, l); 12521558Srgrimes if (debugonly) 12531558Srgrimes return (0); 12541558Srgrimes if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { 125537907Scharnier warn("writing to routing socket"); 12561558Srgrimes return (-1); 12571558Srgrimes } 12581558Srgrimes if (cmd == RTM_GET) { 12591558Srgrimes do { 12601558Srgrimes l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); 12611558Srgrimes } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid)); 12621558Srgrimes if (l < 0) 126313171Swollman warn("read from routing socket"); 12641558Srgrimes else 12651558Srgrimes print_getmsg(&rtm, l); 12661558Srgrimes } 12671558Srgrimes#undef rtm 12681558Srgrimes return (0); 12691558Srgrimes} 12701558Srgrimes 12711558Srgrimesvoid 12721558Srgrimesmask_addr() 12731558Srgrimes{ 12741558Srgrimes int olen = so_mask.sa.sa_len; 12751558Srgrimes register char *cp1 = olen + (char *)&so_mask, *cp2; 12761558Srgrimes 12771558Srgrimes for (so_mask.sa.sa_len = 0; cp1 > (char *)&so_mask; ) 12781558Srgrimes if (*--cp1 != 0) { 12791558Srgrimes so_mask.sa.sa_len = 1 + cp1 - (char *)&so_mask; 12801558Srgrimes break; 12811558Srgrimes } 12821558Srgrimes if ((rtm_addrs & RTA_DST) == 0) 12831558Srgrimes return; 12841558Srgrimes switch (so_dst.sa.sa_family) { 128514092Swollman#ifdef NS 12861558Srgrimes case AF_NS: 128714092Swollman#endif 12881558Srgrimes case AF_INET: 128954263Sshin#ifdef INET6 129054263Sshin case AF_INET6: 129154263Sshin#endif 129217046Sjulian case AF_APPLETALK: 12931558Srgrimes case 0: 12941558Srgrimes return; 12951558Srgrimes } 12961558Srgrimes cp1 = so_mask.sa.sa_len + 1 + (char *)&so_dst; 12971558Srgrimes cp2 = so_dst.sa.sa_len + 1 + (char *)&so_dst; 12981558Srgrimes while (cp2 > cp1) 12991558Srgrimes *--cp2 = 0; 13001558Srgrimes cp2 = so_mask.sa.sa_len + 1 + (char *)&so_mask; 13011558Srgrimes while (cp1 > so_dst.sa.sa_data) 13021558Srgrimes *--cp1 &= *--cp2; 13031558Srgrimes} 13041558Srgrimes 13051558Srgrimeschar *msgtypes[] = { 13061558Srgrimes "", 13071558Srgrimes "RTM_ADD: Add Route", 13081558Srgrimes "RTM_DELETE: Delete Route", 13091558Srgrimes "RTM_CHANGE: Change Metrics or flags", 13101558Srgrimes "RTM_GET: Report Metrics", 13111558Srgrimes "RTM_LOSING: Kernel Suspects Partitioning", 13121558Srgrimes "RTM_REDIRECT: Told to use different route", 13131558Srgrimes "RTM_MISS: Lookup failed on this address", 13141558Srgrimes "RTM_LOCK: fix specified metrics", 13151558Srgrimes "RTM_OLDADD: caused by SIOCADDRT", 13161558Srgrimes "RTM_OLDDEL: caused by SIOCDELRT", 13171558Srgrimes "RTM_RESOLVE: Route created by cloning", 13181558Srgrimes "RTM_NEWADDR: address being added to iface", 13191558Srgrimes "RTM_DELADDR: address being removed from iface", 13201558Srgrimes "RTM_IFINFO: iface status change", 132121465Swollman "RTM_NEWMADDR: new multicast group membership on iface", 132221465Swollman "RTM_DELMADDR: multicast group membership removed from iface", 13231558Srgrimes 0, 13241558Srgrimes}; 13251558Srgrimes 13261558Srgrimeschar metricnames[] = 132715690Swollman"\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount" 132815690Swollman"\1mtu"; 13291558Srgrimeschar routeflags[] = 133015690Swollman"\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT" 133115690Swollman"\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE\016b016" 133215690Swollman"\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3\024CHAINDELETE" 133315690Swollman"\025PINNED\026LOCAL\027BROADCAST\030MULTICAST"; 13341558Srgrimeschar ifnetflags[] = 133515690Swollman"\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP" 133615690Swollman"\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1" 133715690Swollman"\017LINK2\020MULTICAST"; 13381558Srgrimeschar addrnames[] = 13391558Srgrimes"\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD"; 13401558Srgrimes 13411558Srgrimesvoid 13421558Srgrimesprint_rtmsg(rtm, msglen) 13431558Srgrimes register struct rt_msghdr *rtm; 13441558Srgrimes int msglen; 13451558Srgrimes{ 13461558Srgrimes struct if_msghdr *ifm; 13471558Srgrimes struct ifa_msghdr *ifam; 134821465Swollman#ifdef RTM_NEWMADDR 134921465Swollman struct ifma_msghdr *ifmam; 135021465Swollman#endif 13511558Srgrimes 13521558Srgrimes if (verbose == 0) 13531558Srgrimes return; 13541558Srgrimes if (rtm->rtm_version != RTM_VERSION) { 13551558Srgrimes (void) printf("routing message version %d not understood\n", 13561558Srgrimes rtm->rtm_version); 13571558Srgrimes return; 13581558Srgrimes } 13591558Srgrimes (void)printf("%s: len %d, ", msgtypes[rtm->rtm_type], rtm->rtm_msglen); 13601558Srgrimes switch (rtm->rtm_type) { 13611558Srgrimes case RTM_IFINFO: 13621558Srgrimes ifm = (struct if_msghdr *)rtm; 13631558Srgrimes (void) printf("if# %d, flags:", ifm->ifm_index); 13641558Srgrimes bprintf(stdout, ifm->ifm_flags, ifnetflags); 13651558Srgrimes pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs); 13661558Srgrimes break; 13671558Srgrimes case RTM_NEWADDR: 13681558Srgrimes case RTM_DELADDR: 13691558Srgrimes ifam = (struct ifa_msghdr *)rtm; 13701558Srgrimes (void) printf("metric %d, flags:", ifam->ifam_metric); 13711558Srgrimes bprintf(stdout, ifam->ifam_flags, routeflags); 13721558Srgrimes pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs); 13731558Srgrimes break; 137421465Swollman#ifdef RTM_NEWMADDR 137521465Swollman case RTM_NEWMADDR: 137621465Swollman case RTM_DELMADDR: 137721465Swollman ifmam = (struct ifma_msghdr *)rtm; 137821465Swollman pmsg_addrs((char *)(ifmam + 1), ifmam->ifmam_addrs); 137921465Swollman break; 138021465Swollman#endif 13811558Srgrimes default: 138213171Swollman (void) printf("pid: %ld, seq %d, errno %d, flags:", 138313171Swollman (long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno); 13841558Srgrimes bprintf(stdout, rtm->rtm_flags, routeflags); 13851558Srgrimes pmsg_common(rtm); 13861558Srgrimes } 13871558Srgrimes} 13881558Srgrimes 13891558Srgrimesvoid 13901558Srgrimesprint_getmsg(rtm, msglen) 13911558Srgrimes register struct rt_msghdr *rtm; 13921558Srgrimes int msglen; 13931558Srgrimes{ 13941558Srgrimes struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL; 13951558Srgrimes struct sockaddr_dl *ifp = NULL; 13961558Srgrimes register struct sockaddr *sa; 13971558Srgrimes register char *cp; 13981558Srgrimes register int i; 13991558Srgrimes 14001558Srgrimes (void) printf(" route to: %s\n", routename(&so_dst)); 14011558Srgrimes if (rtm->rtm_version != RTM_VERSION) { 140213171Swollman warnx("routing message version %d not understood", 140313171Swollman rtm->rtm_version); 14041558Srgrimes return; 14051558Srgrimes } 14061558Srgrimes if (rtm->rtm_msglen > msglen) { 140737907Scharnier warnx("message length mismatch, in packet %d, returned %d", 140813171Swollman rtm->rtm_msglen, msglen); 14091558Srgrimes } 14101558Srgrimes if (rtm->rtm_errno) { 141113171Swollman errno = rtm->rtm_errno; 141213171Swollman warn("message indicates error %d", errno); 14131558Srgrimes return; 14141558Srgrimes } 14151558Srgrimes cp = ((char *)(rtm + 1)); 14161558Srgrimes if (rtm->rtm_addrs) 14171558Srgrimes for (i = 1; i; i <<= 1) 14181558Srgrimes if (i & rtm->rtm_addrs) { 14191558Srgrimes sa = (struct sockaddr *)cp; 14201558Srgrimes switch (i) { 14211558Srgrimes case RTA_DST: 14221558Srgrimes dst = sa; 14231558Srgrimes break; 14241558Srgrimes case RTA_GATEWAY: 14251558Srgrimes gate = sa; 14261558Srgrimes break; 14271558Srgrimes case RTA_NETMASK: 14281558Srgrimes mask = sa; 14291558Srgrimes break; 14301558Srgrimes case RTA_IFP: 14311558Srgrimes if (sa->sa_family == AF_LINK && 14321558Srgrimes ((struct sockaddr_dl *)sa)->sdl_nlen) 14331558Srgrimes ifp = (struct sockaddr_dl *)sa; 14341558Srgrimes break; 14351558Srgrimes } 14361558Srgrimes ADVANCE(cp, sa); 14371558Srgrimes } 14381558Srgrimes if (dst && mask) 14391558Srgrimes mask->sa_family = dst->sa_family; /* XXX */ 14401558Srgrimes if (dst) 14411558Srgrimes (void)printf("destination: %s\n", routename(dst)); 14421558Srgrimes if (mask) { 14431558Srgrimes int savenflag = nflag; 14441558Srgrimes 14451558Srgrimes nflag = 1; 14461558Srgrimes (void)printf(" mask: %s\n", routename(mask)); 14471558Srgrimes nflag = savenflag; 14481558Srgrimes } 14491558Srgrimes if (gate && rtm->rtm_flags & RTF_GATEWAY) 14501558Srgrimes (void)printf(" gateway: %s\n", routename(gate)); 14511558Srgrimes if (ifp) 14521558Srgrimes (void)printf(" interface: %.*s\n", 14531558Srgrimes ifp->sdl_nlen, ifp->sdl_data); 14541558Srgrimes (void)printf(" flags: "); 14551558Srgrimes bprintf(stdout, rtm->rtm_flags, routeflags); 14561558Srgrimes 14571558Srgrimes#define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ') 14581558Srgrimes#define msec(u) (((u) + 500) / 1000) /* usec to msec */ 14591558Srgrimes 14601558Srgrimes (void) printf("\n%s\n", "\ 14611558Srgrimes recvpipe sendpipe ssthresh rtt,msec rttvar hopcount mtu expire"); 146213171Swollman printf("%8ld%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE)); 146313171Swollman printf("%8ld%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE)); 146413171Swollman printf("%8ld%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH)); 146513171Swollman printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT)); 146613171Swollman printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR)); 146713171Swollman printf("%8ld%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT)); 146813171Swollman printf("%8ld%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU)); 14691558Srgrimes if (rtm->rtm_rmx.rmx_expire) 14701558Srgrimes rtm->rtm_rmx.rmx_expire -= time(0); 147113171Swollman printf("%8ld%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE)); 14721558Srgrimes#undef lock 14731558Srgrimes#undef msec 14741558Srgrimes#define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD) 14751558Srgrimes if (verbose) 14761558Srgrimes pmsg_common(rtm); 14771558Srgrimes else if (rtm->rtm_addrs &~ RTA_IGN) { 14781558Srgrimes (void) printf("sockaddrs: "); 14791558Srgrimes bprintf(stdout, rtm->rtm_addrs, addrnames); 14801558Srgrimes putchar('\n'); 14811558Srgrimes } 14821558Srgrimes#undef RTA_IGN 14831558Srgrimes} 14841558Srgrimes 14851558Srgrimesvoid 14861558Srgrimespmsg_common(rtm) 14871558Srgrimes register struct rt_msghdr *rtm; 14881558Srgrimes{ 14891558Srgrimes (void) printf("\nlocks: "); 14901558Srgrimes bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames); 14911558Srgrimes (void) printf(" inits: "); 14921558Srgrimes bprintf(stdout, rtm->rtm_inits, metricnames); 14931558Srgrimes pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs); 14941558Srgrimes} 14951558Srgrimes 14961558Srgrimesvoid 14971558Srgrimespmsg_addrs(cp, addrs) 14981558Srgrimes char *cp; 14991558Srgrimes int addrs; 15001558Srgrimes{ 15011558Srgrimes register struct sockaddr *sa; 15021558Srgrimes int i; 15031558Srgrimes 150471061Sphk if (addrs == 0) { 150571061Sphk (void) putchar('\n'); 15061558Srgrimes return; 150771061Sphk } 15081558Srgrimes (void) printf("\nsockaddrs: "); 15091558Srgrimes bprintf(stdout, addrs, addrnames); 15101558Srgrimes (void) putchar('\n'); 15111558Srgrimes for (i = 1; i; i <<= 1) 15121558Srgrimes if (i & addrs) { 15131558Srgrimes sa = (struct sockaddr *)cp; 15141558Srgrimes (void) printf(" %s", routename(sa)); 15151558Srgrimes ADVANCE(cp, sa); 15161558Srgrimes } 15171558Srgrimes (void) putchar('\n'); 15181558Srgrimes (void) fflush(stdout); 15191558Srgrimes} 15201558Srgrimes 15211558Srgrimesvoid 15221558Srgrimesbprintf(fp, b, s) 15231558Srgrimes register FILE *fp; 15241558Srgrimes register int b; 15251558Srgrimes register u_char *s; 15261558Srgrimes{ 15271558Srgrimes register int i; 15281558Srgrimes int gotsome = 0; 15291558Srgrimes 15301558Srgrimes if (b == 0) 15311558Srgrimes return; 153213171Swollman while ((i = *s++) != 0) { 15331558Srgrimes if (b & (1 << (i-1))) { 15341558Srgrimes if (gotsome == 0) 15351558Srgrimes i = '<'; 15361558Srgrimes else 15371558Srgrimes i = ','; 15381558Srgrimes (void) putc(i, fp); 15391558Srgrimes gotsome = 1; 15401558Srgrimes for (; (i = *s) > 32; s++) 15411558Srgrimes (void) putc(i, fp); 15421558Srgrimes } else 15431558Srgrimes while (*s > 32) 15441558Srgrimes s++; 15451558Srgrimes } 15461558Srgrimes if (gotsome) 15471558Srgrimes (void) putc('>', fp); 15481558Srgrimes} 15491558Srgrimes 15501558Srgrimesint 15511558Srgrimeskeyword(cp) 15521558Srgrimes char *cp; 15531558Srgrimes{ 15541558Srgrimes register struct keytab *kt = keywords; 15551558Srgrimes 15561558Srgrimes while (kt->kt_cp && strcmp(kt->kt_cp, cp)) 15571558Srgrimes kt++; 15581558Srgrimes return kt->kt_i; 15591558Srgrimes} 15601558Srgrimes 15611558Srgrimesvoid 15621558Srgrimessodump(su, which) 15631558Srgrimes register sup su; 15641558Srgrimes char *which; 15651558Srgrimes{ 15661558Srgrimes switch (su->sa.sa_family) { 15671558Srgrimes case AF_LINK: 15681558Srgrimes (void) printf("%s: link %s; ", 15691558Srgrimes which, link_ntoa(&su->sdl)); 15701558Srgrimes break; 15711558Srgrimes case AF_INET: 15721558Srgrimes (void) printf("%s: inet %s; ", 15731558Srgrimes which, inet_ntoa(su->sin.sin_addr)); 15741558Srgrimes break; 157517046Sjulian case AF_APPLETALK: 157617046Sjulian (void) printf("%s: atalk %s; ", 157717046Sjulian which, atalk_ntoa(su->sat.sat_addr)); 157817046Sjulian break; 157914092Swollman#ifdef NS 15801558Srgrimes case AF_NS: 15811558Srgrimes (void) printf("%s: xns %s; ", 15821558Srgrimes which, ns_ntoa(su->sns.sns_addr)); 15831558Srgrimes break; 158414092Swollman#endif 15851558Srgrimes } 15861558Srgrimes (void) fflush(stdout); 15871558Srgrimes} 15881558Srgrimes 15891558Srgrimes/* States*/ 15901558Srgrimes#define VIRGIN 0 15911558Srgrimes#define GOTONE 1 15921558Srgrimes#define GOTTWO 2 15931558Srgrimes/* Inputs */ 15941558Srgrimes#define DIGIT (4*0) 15951558Srgrimes#define END (4*1) 15961558Srgrimes#define DELIM (4*2) 15971558Srgrimes 15981558Srgrimesvoid 15991558Srgrimessockaddr(addr, sa) 16001558Srgrimes register char *addr; 16011558Srgrimes register struct sockaddr *sa; 16021558Srgrimes{ 16031558Srgrimes register char *cp = (char *)sa; 16041558Srgrimes int size = sa->sa_len; 16051558Srgrimes char *cplim = cp + size; 160613171Swollman register int byte = 0, state = VIRGIN, new = 0 /* foil gcc */; 16071558Srgrimes 16081558Srgrimes bzero(cp, size); 16091558Srgrimes cp++; 16101558Srgrimes do { 16111558Srgrimes if ((*addr >= '0') && (*addr <= '9')) { 16121558Srgrimes new = *addr - '0'; 16131558Srgrimes } else if ((*addr >= 'a') && (*addr <= 'f')) { 16141558Srgrimes new = *addr - 'a' + 10; 16151558Srgrimes } else if ((*addr >= 'A') && (*addr <= 'F')) { 16161558Srgrimes new = *addr - 'A' + 10; 16171558Srgrimes } else if (*addr == 0) 16181558Srgrimes state |= END; 16191558Srgrimes else 16201558Srgrimes state |= DELIM; 16211558Srgrimes addr++; 16221558Srgrimes switch (state /* | INPUT */) { 16231558Srgrimes case GOTTWO | DIGIT: 16241558Srgrimes *cp++ = byte; /*FALLTHROUGH*/ 16251558Srgrimes case VIRGIN | DIGIT: 16261558Srgrimes state = GOTONE; byte = new; continue; 16271558Srgrimes case GOTONE | DIGIT: 16281558Srgrimes state = GOTTWO; byte = new + (byte << 4); continue; 16291558Srgrimes default: /* | DELIM */ 16301558Srgrimes state = VIRGIN; *cp++ = byte; byte = 0; continue; 16311558Srgrimes case GOTONE | END: 16321558Srgrimes case GOTTWO | END: 16331558Srgrimes *cp++ = byte; /* FALLTHROUGH */ 16341558Srgrimes case VIRGIN | END: 16351558Srgrimes break; 16361558Srgrimes } 16371558Srgrimes break; 16381558Srgrimes } while (cp < cplim); 16391558Srgrimes sa->sa_len = cp - (char *)sa; 16401558Srgrimes} 164117046Sjulian 164217046Sjulianint 164317046Sjulianatalk_aton(const char *text, struct at_addr *addr) 164417046Sjulian{ 164517046Sjulian u_int net, node; 164617046Sjulian 164717046Sjulian if (sscanf(text, "%u.%u", &net, &node) != 2 164817046Sjulian || net > 0xffff || node > 0xff) 164917046Sjulian return(0); 165017254Sjulian addr->s_net = htons(net); 165117046Sjulian addr->s_node = node; 165217046Sjulian return(1); 165317046Sjulian} 165417046Sjulian 165517046Sjulianchar * 165617046Sjulianatalk_ntoa(struct at_addr at) 165717046Sjulian{ 165817046Sjulian static char buf[20]; 165917046Sjulian 166017254Sjulian (void) snprintf(buf, sizeof(buf), "%u.%u", ntohs(at.s_net), at.s_node); 166117046Sjulian return(buf); 166217046Sjulian} 1663