route.c revision 244325
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 * 4. Neither the name of the University nor the names of its contributors 141558Srgrimes * may be used to endorse or promote products derived from this software 151558Srgrimes * without specific prior written permission. 161558Srgrimes * 171558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271558Srgrimes * SUCH DAMAGE. 281558Srgrimes */ 291558Srgrimes 301558Srgrimes#ifndef lint 3113171Swollmanstatic const char copyright[] = 321558Srgrimes"@(#) Copyright (c) 1983, 1989, 1991, 1993\n\ 331558Srgrimes The Regents of the University of California. All rights reserved.\n"; 341558Srgrimes#endif /* not lint */ 351558Srgrimes 361558Srgrimes#ifndef lint 3737907Scharnier#if 0 3885048Srustatic char sccsid[] = "@(#)route.c 8.6 (Berkeley) 4/28/95"; 3937907Scharnier#endif 401558Srgrimes#endif /* not lint */ 411558Srgrimes 42196527Scharnier#include <sys/cdefs.h> 43196527Scharnier__FBSDID("$FreeBSD: head/sbin/route/route.c 244325 2012-12-16 23:46:59Z hrs $"); 44196527Scharnier 451558Srgrimes#include <sys/param.h> 461558Srgrimes#include <sys/file.h> 471558Srgrimes#include <sys/socket.h> 481558Srgrimes#include <sys/ioctl.h> 491558Srgrimes#include <sys/sysctl.h> 5051639Sbillf#include <sys/types.h> 51243185Shrs#include <sys/queue.h> 521558Srgrimes 531558Srgrimes#include <net/if.h> 541558Srgrimes#include <net/route.h> 551558Srgrimes#include <net/if_dl.h> 561558Srgrimes#include <netinet/in.h> 5778140Sru#include <netinet/if_ether.h> 5817046Sjulian#include <netatalk/at.h> 591558Srgrimes#include <arpa/inet.h> 601558Srgrimes#include <netdb.h> 611558Srgrimes 6220287Swollman#include <ctype.h> 6320287Swollman#include <err.h> 641558Srgrimes#include <errno.h> 6569793Sobrien#include <paths.h> 661558Srgrimes#include <stdio.h> 671558Srgrimes#include <stdlib.h> 681558Srgrimes#include <string.h> 6913171Swollman#include <sysexits.h> 7020287Swollman#include <unistd.h> 7178064Sume#include <ifaddrs.h> 721558Srgrimes 731558Srgrimesstruct keytab { 74204406Suqs const char *kt_cp; 751558Srgrimes int kt_i; 761558Srgrimes} keywords[] = { 771558Srgrimes#include "keywords.h" 781558Srgrimes {0, 0} 791558Srgrimes}; 801558Srgrimes 811558Srgrimesunion sockunion { 821558Srgrimes struct sockaddr sa; 831558Srgrimes struct sockaddr_in sin; 8454263Sshin#ifdef INET6 8554263Sshin struct sockaddr_in6 sin6; 8654263Sshin#endif 8717046Sjulian struct sockaddr_at sat; 881558Srgrimes struct sockaddr_dl sdl; 8978140Sru struct sockaddr_inarp sinarp; 9078064Sume struct sockaddr_storage ss; /* added to avoid memory overrun */ 911558Srgrimes} so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp; 921558Srgrimes 931558Srgrimestypedef union sockunion *sup; 9482651Sruint pid, rtm_addrs; 951558Srgrimesint s; 96196527Scharnierint forcehost, forcenet, doflush, nflag, af, qflag, tflag; 971558Srgrimesint iflag, verbose, aflen = sizeof (struct sockaddr_in); 981558Srgrimesint locking, lockrest, debugonly; 991558Srgrimesstruct rt_metrics rt_metrics; 1001558Srgrimesu_long rtm_inits; 10182651Sruuid_t uid; 102243185Shrsstatic int defaultfib; 103243185Shrsstatic int numfibs; 104196527Scharnier 105204406Suqsstatic int atalk_aton(const char *, struct at_addr *); 106204406Suqsstatic char *atalk_ntoa(struct at_addr); 107204406Suqsstatic void bprintf(FILE *, int, u_char *); 108204406Suqsstatic void flushroutes(int argc, char *argv[]); 109243185Shrsstatic int flushroutes_fib(int); 110204406Suqsstatic int getaddr(int, char *, struct hostent **); 111204406Suqsstatic int keyword(const char *); 112204406Suqsstatic void inet_makenetandmask(u_long, struct sockaddr_in *, u_long); 11397062Sume#ifdef INET6 114204406Suqsstatic int inet6_makenetandmask(struct sockaddr_in6 *, const char *); 11597062Sume#endif 116204406Suqsstatic void interfaces(void); 117204406Suqsstatic void mask_addr(void); 118243185Shrsstatic void monitor(int, char*[]); 119204406Suqsstatic const char *netname(struct sockaddr *); 120204406Suqsstatic void newroute(int, char **); 121243185Shrsstatic int newroute_fib(int, char *, int); 122216297Sglebiusstatic void pmsg_addrs(char *, int, size_t); 123216297Sglebiusstatic void pmsg_common(struct rt_msghdr *, size_t); 124204406Suqsstatic int prefixlen(const char *); 125243185Shrsstatic void print_getmsg(struct rt_msghdr *, int, int); 126216297Sglebiusstatic void print_rtmsg(struct rt_msghdr *, size_t); 127204406Suqsstatic const char *routename(struct sockaddr *); 128243185Shrsstatic int rtmsg(int, int, int); 129204406Suqsstatic void set_metric(char *, int); 130243185Shrsstatic int set_sofib(int); 131243185Shrsstatic int set_procfib(int); 132204406Suqsstatic void sockaddr(char *, struct sockaddr *); 133204406Suqsstatic void sodump(sup, const char *); 134204406Suqsextern char *iso_ntoa(void); 1351558Srgrimes 136243185Shrsstruct fibl { 137243185Shrs TAILQ_ENTRY(fibl) fl_next; 138243185Shrs 139243185Shrs int fl_num; 140243185Shrs int fl_error; 141243185Shrs int fl_errno; 142243185Shrs}; 143243185ShrsTAILQ_HEAD(fibl_head_t, fibl) fibl_head; 144243185Shrs 145243185Shrsstatic int fiboptlist_csv(const char *, struct fibl_head_t *); 146243185Shrsstatic int fiboptlist_range(const char *, struct fibl_head_t *); 147243185Shrs 148204406Suqsstatic void usage(const char *) __dead2; 14913171Swollman 15018286Sbdevoid 151196527Scharnierusage(const char *cp) 1521558Srgrimes{ 153204406Suqs if (cp != NULL) 15413171Swollman warnx("bad keyword: %s", cp); 1551558Srgrimes (void) fprintf(stderr, 15637907Scharnier "usage: route [-dnqtv] command [[modifiers] args]\n"); 15713171Swollman exit(EX_USAGE); 1581558Srgrimes /* NOTREACHED */ 1591558Srgrimes} 1601558Srgrimes 1611558Srgrimesint 162196527Scharniermain(int argc, char **argv) 1631558Srgrimes{ 1641558Srgrimes int ch; 165243185Shrs size_t len; 1661558Srgrimes 1671558Srgrimes if (argc < 2) 168204406Suqs usage(NULL); 1691558Srgrimes 17037907Scharnier while ((ch = getopt(argc, argv, "nqdtv")) != -1) 1711558Srgrimes switch(ch) { 1721558Srgrimes case 'n': 1731558Srgrimes nflag = 1; 1741558Srgrimes break; 1751558Srgrimes case 'q': 1761558Srgrimes qflag = 1; 1771558Srgrimes break; 1781558Srgrimes case 'v': 1791558Srgrimes verbose = 1; 1801558Srgrimes break; 1811558Srgrimes case 't': 1821558Srgrimes tflag = 1; 1831558Srgrimes break; 1841558Srgrimes case 'd': 1851558Srgrimes debugonly = 1; 1861558Srgrimes break; 1871558Srgrimes case '?': 1881558Srgrimes default: 189204406Suqs usage(NULL); 1901558Srgrimes } 1911558Srgrimes argc -= optind; 1921558Srgrimes argv += optind; 1931558Srgrimes 1941558Srgrimes pid = getpid(); 195109811Skbyanc uid = geteuid(); 1961558Srgrimes if (tflag) 19769793Sobrien s = open(_PATH_DEVNULL, O_WRONLY, 0); 1981558Srgrimes else 1991558Srgrimes s = socket(PF_ROUTE, SOCK_RAW, 0); 2001558Srgrimes if (s < 0) 20113171Swollman err(EX_OSERR, "socket"); 202243185Shrs 203243185Shrs len = sizeof(numfibs); 204243185Shrs if (sysctlbyname("net.fibs", (void *)&numfibs, &len, NULL, 0) == -1) 205243185Shrs numfibs = -1; 206243185Shrs 207243185Shrs len = sizeof(defaultfib); 208243185Shrs if (numfibs != -1 && 209243185Shrs sysctlbyname("net.my_fibnum", (void *)&defaultfib, &len, NULL, 210243185Shrs 0) == -1) 211243185Shrs defaultfib = -1; 212243185Shrs 213204406Suqs if (*argv != NULL) 2141558Srgrimes switch (keyword(*argv)) { 2151558Srgrimes case K_GET: 216191080Skmacy case K_SHOW: 2171558Srgrimes uid = 0; 2181558Srgrimes /* FALLTHROUGH */ 2191558Srgrimes 2201558Srgrimes case K_CHANGE: 2211558Srgrimes case K_ADD: 222150679Stobez case K_DEL: 2231558Srgrimes case K_DELETE: 2241558Srgrimes newroute(argc, argv); 2251558Srgrimes /* NOTREACHED */ 2261558Srgrimes 2271558Srgrimes case K_MONITOR: 228243185Shrs monitor(argc, argv); 2291558Srgrimes /* NOTREACHED */ 2301558Srgrimes 2311558Srgrimes case K_FLUSH: 2321558Srgrimes flushroutes(argc, argv); 2331558Srgrimes exit(0); 2341558Srgrimes /* NOTREACHED */ 2351558Srgrimes } 2361558Srgrimes usage(*argv); 2371558Srgrimes /* NOTREACHED */ 2381558Srgrimes} 2391558Srgrimes 240243185Shrsstatic int 241243185Shrsset_sofib(int fib) 242243185Shrs{ 243243185Shrs 244243185Shrs if (fib < 0) 245243185Shrs return (0); 246243185Shrs return (setsockopt(s, SOL_SOCKET, SO_SETFIB, (void *)&fib, 247243185Shrs sizeof(fib))); 248243185Shrs} 249243185Shrs 250243185Shrsstatic int 251243185Shrsset_procfib(int fib) 252243185Shrs{ 253243185Shrs 254243185Shrs if (fib < 0) 255243185Shrs return (0); 256243185Shrs return (setfib(fib)); 257243185Shrs} 258243185Shrs 259243185Shrsstatic int 260243185Shrsfiboptlist_range(const char *arg, struct fibl_head_t *flh) 261243185Shrs{ 262243185Shrs struct fibl *fl; 263244325Shrs char *str0, *str, *token, *endptr; 264243185Shrs int fib[2], i, error; 265243185Shrs 266244325Shrs str0 = str = strdup(arg); 267243185Shrs error = 0; 268243185Shrs i = 0; 269243185Shrs while ((token = strsep(&str, "-")) != NULL) { 270243185Shrs switch (i) { 271243185Shrs case 0: 272243185Shrs case 1: 273244325Shrs errno = 0; 274243185Shrs fib[i] = strtol(token, &endptr, 0); 275244325Shrs if (errno == 0) { 276244325Shrs if (*endptr != '\0' || 277244325Shrs fib[i] < 0 || 278244325Shrs (numfibs != -1 && fib[i] > numfibs - 1)) 279244325Shrs errno = EINVAL; 280244325Shrs } 281244325Shrs if (errno) 282243185Shrs error = 1; 283243185Shrs break; 284243185Shrs default: 285243185Shrs error = 1; 286243185Shrs } 287243185Shrs if (error) 288243185Shrs goto fiboptlist_range_ret; 289243185Shrs i++; 290243185Shrs } 291243185Shrs if (fib[0] >= fib[1]) { 292243185Shrs error = 1; 293243185Shrs goto fiboptlist_range_ret; 294243185Shrs } 295243185Shrs for (i = fib[0]; i <= fib[1]; i++) { 296243185Shrs fl = calloc(1, sizeof(*fl)); 297243185Shrs if (fl == NULL) { 298243185Shrs error = 1; 299243185Shrs goto fiboptlist_range_ret; 300243185Shrs } 301243185Shrs fl->fl_num = i; 302243185Shrs TAILQ_INSERT_TAIL(flh, fl, fl_next); 303243185Shrs } 304243185Shrsfiboptlist_range_ret: 305244325Shrs free(str0); 306243185Shrs return (error); 307243185Shrs} 308243185Shrs 309243185Shrs#define ALLSTRLEN 64 310243185Shrsstatic int 311243185Shrsfiboptlist_csv(const char *arg, struct fibl_head_t *flh) 312243185Shrs{ 313243185Shrs struct fibl *fl; 314244325Shrs char *str0, *str, *token, *endptr; 315243185Shrs int fib, error; 316243185Shrs 317243185Shrs if (strcmp("all", arg) == 0) { 318243185Shrs str = calloc(1, ALLSTRLEN); 319243185Shrs if (str == NULL) { 320243185Shrs error = 1; 321243185Shrs goto fiboptlist_csv_ret; 322243185Shrs } 323243185Shrs if (numfibs > 1) 324243185Shrs snprintf(str, ALLSTRLEN - 1, "%d-%d", 0, numfibs - 1); 325243185Shrs else 326243185Shrs snprintf(str, ALLSTRLEN - 1, "%d", 0); 327243185Shrs } else if (strcmp("default", arg) == 0) { 328244325Shrs str0 = str = calloc(1, ALLSTRLEN); 329243185Shrs if (str == NULL) { 330243185Shrs error = 1; 331243185Shrs goto fiboptlist_csv_ret; 332243185Shrs } 333243185Shrs snprintf(str, ALLSTRLEN - 1, "%d", defaultfib); 334243185Shrs } else 335244325Shrs str0 = str = strdup(arg); 336243185Shrs 337243185Shrs error = 0; 338243185Shrs while ((token = strsep(&str, ",")) != NULL) { 339243185Shrs if (*token != '-' && strchr(token, '-') != NULL) { 340243185Shrs error = fiboptlist_range(token, flh); 341243185Shrs if (error) 342243185Shrs goto fiboptlist_csv_ret; 343243185Shrs } else { 344244325Shrs errno = 0; 345243185Shrs fib = strtol(token, &endptr, 0); 346244325Shrs if (errno == 0) { 347244325Shrs if (*endptr != '\0' || 348244325Shrs fib < 0 || 349244325Shrs (numfibs != -1 && fib > numfibs - 1)) 350244325Shrs errno = EINVAL; 351244325Shrs } 352244325Shrs if (errno) { 353243185Shrs error = 1; 354243185Shrs goto fiboptlist_csv_ret; 355243185Shrs } 356243185Shrs fl = calloc(1, sizeof(*fl)); 357243185Shrs if (fl == NULL) { 358243185Shrs error = 1; 359243185Shrs goto fiboptlist_csv_ret; 360243185Shrs } 361243185Shrs fl->fl_num = fib; 362243185Shrs TAILQ_INSERT_TAIL(flh, fl, fl_next); 363243185Shrs } 364243185Shrs } 365243185Shrsfiboptlist_csv_ret: 366244325Shrs free(str0); 367243185Shrs return (error); 368243185Shrs} 369243185Shrs 3701558Srgrimes/* 3711558Srgrimes * Purge all entries in the routing tables not 3721558Srgrimes * associated with network interfaces. 3731558Srgrimes */ 374204406Suqsstatic void 375196527Scharnierflushroutes(int argc, char *argv[]) 3761558Srgrimes{ 377243185Shrs struct fibl *fl; 378243185Shrs int error; 3791558Srgrimes 380243859Sglebius if (uid != 0 && !debugonly && !tflag) { 38113171Swollman errx(EX_NOPERM, "must be root to alter routing table"); 3821558Srgrimes } 383146079Sjmallett shutdown(s, SHUT_RD); /* Don't want to read back our messages */ 384243185Shrs 385243185Shrs TAILQ_INIT(&fibl_head); 386243185Shrs while (argc > 1) { 387243185Shrs argc--; 3881558Srgrimes argv++; 389243185Shrs if (**argv != '-') 390243185Shrs usage(*argv); 391243185Shrs switch (keyword(*argv + 1)) { 392243185Shrs case K_INET: 393243185Shrs af = AF_INET; 394243185Shrs break; 39554263Sshin#ifdef INET6 396243185Shrs case K_INET6: 397243185Shrs af = AF_INET6; 398243185Shrs break; 39954263Sshin#endif 400243185Shrs case K_ATALK: 401243185Shrs af = AF_APPLETALK; 402243185Shrs break; 403243185Shrs case K_LINK: 404243185Shrs af = AF_LINK; 405243185Shrs break; 406243185Shrs case K_FIB: 407243185Shrs if (!--argc) 408243185Shrs usage(*argv); 409243185Shrs error = fiboptlist_csv(*++argv, &fibl_head); 410243185Shrs if (error) 411244325Shrs errx(EX_USAGE, "invalid fib number: %s", *argv); 412243185Shrs break; 413243185Shrs default: 414243185Shrs usage(*argv); 415243185Shrs } 4161558Srgrimes } 417243185Shrs if (TAILQ_EMPTY(&fibl_head)) { 418243185Shrs error = fiboptlist_csv("default", &fibl_head); 419243185Shrs if (error) 420243185Shrs errx(EX_OSERR, "fiboptlist_csv failed."); 421243185Shrs } 422243185Shrs TAILQ_FOREACH(fl, &fibl_head, fl_next) 423243185Shrs flushroutes_fib(fl->fl_num); 424243185Shrs} 425243185Shrs 426243185Shrsstatic int 427243185Shrsflushroutes_fib(int fib) 428243185Shrs{ 429243185Shrs struct rt_msghdr *rtm; 430243185Shrs size_t needed; 431243185Shrs char *buf, *next, *lim; 432243185Shrs int mib[6], rlen, seqno, count = 0; 433243185Shrs int error; 434243185Shrs 435243185Shrs error = set_sofib(fib); 436243185Shrs error += set_procfib(fib); 437243185Shrs if (error) { 438243185Shrs warn("fib number %d is ignored", fib); 439243185Shrs return (error); 440243185Shrs } 441243185Shrs 442128782Sambriskoretry: 4431558Srgrimes mib[0] = CTL_NET; 4441558Srgrimes mib[1] = PF_ROUTE; 4451558Srgrimes mib[2] = 0; /* protocol */ 4461558Srgrimes mib[3] = 0; /* wildcard address family */ 4471558Srgrimes mib[4] = NET_RT_DUMP; 4481558Srgrimes mib[5] = 0; /* no flags */ 4491558Srgrimes if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 45013171Swollman err(EX_OSERR, "route-sysctl-estimate"); 4511558Srgrimes if ((buf = malloc(needed)) == NULL) 45237907Scharnier errx(EX_OSERR, "malloc failed"); 453128782Sambrisko if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 454128782Sambrisko if (errno == ENOMEM && count++ < 10) { 455204406Suqs warnx("Routing table grew, retrying"); 456128782Sambrisko sleep(1); 457128782Sambrisko free(buf); 458128782Sambrisko goto retry; 459128782Sambrisko } 46013171Swollman err(EX_OSERR, "route-sysctl-get"); 461128782Sambrisko } 4621558Srgrimes lim = buf + needed; 4631558Srgrimes if (verbose) 4641558Srgrimes (void) printf("Examining routing table from sysctl\n"); 4651558Srgrimes seqno = 0; /* ??? */ 4661558Srgrimes for (next = buf; next < lim; next += rtm->rtm_msglen) { 4671558Srgrimes rtm = (struct rt_msghdr *)next; 4681558Srgrimes if (verbose) 4691558Srgrimes print_rtmsg(rtm, rtm->rtm_msglen); 4701558Srgrimes if ((rtm->rtm_flags & RTF_GATEWAY) == 0) 4711558Srgrimes continue; 472204406Suqs if (af != 0) { 4731558Srgrimes struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 4741558Srgrimes 4751558Srgrimes if (sa->sa_family != af) 4761558Srgrimes continue; 4771558Srgrimes } 4781558Srgrimes if (debugonly) 4791558Srgrimes continue; 4801558Srgrimes rtm->rtm_type = RTM_DELETE; 4811558Srgrimes rtm->rtm_seq = seqno; 4821558Srgrimes rlen = write(s, next, rtm->rtm_msglen); 483129034Scsjp if (rlen < 0 && errno == EPERM) 484129034Scsjp err(1, "write to routing socket"); 4851558Srgrimes if (rlen < (int)rtm->rtm_msglen) { 48613171Swollman warn("write to routing socket"); 4871558Srgrimes (void) printf("got only %d for rlen\n", rlen); 488128782Sambrisko free(buf); 489128782Sambrisko goto retry; 4901558Srgrimes break; 4911558Srgrimes } 4921558Srgrimes seqno++; 4931558Srgrimes if (qflag) 4941558Srgrimes continue; 4951558Srgrimes if (verbose) 4961558Srgrimes print_rtmsg(rtm, rlen); 4971558Srgrimes else { 4981558Srgrimes struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 499243185Shrs 500243185Shrs printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ? 5011558Srgrimes routename(sa) : netname(sa)); 502128186Sluigi sa = (struct sockaddr *)(SA_SIZE(sa) + (char *)sa); 503243185Shrs printf("%-20.20s ", routename(sa)); 504243185Shrs if (fib >= 0) 505243185Shrs printf("-fib %-3d ", fib); 506243185Shrs printf("done\n"); 5071558Srgrimes } 5081558Srgrimes } 509243185Shrs return (error); 5101558Srgrimes} 5111558Srgrimes 51278064Sumeconst char * 513196527Scharnierroutename(struct sockaddr *sa) 5141558Srgrimes{ 515204406Suqs const char *cp; 51619209Sfenner static char line[MAXHOSTNAMELEN + 1]; 5171558Srgrimes struct hostent *hp; 5181558Srgrimes static char domain[MAXHOSTNAMELEN + 1]; 51981976Sbrian static int first = 1, n; 5201558Srgrimes 5211558Srgrimes if (first) { 5221558Srgrimes first = 0; 5231558Srgrimes if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 52485048Sru (cp = strchr(domain, '.'))) { 52519209Sfenner domain[MAXHOSTNAMELEN] = '\0'; 5261558Srgrimes (void) strcpy(domain, cp + 1); 52719209Sfenner } else 5281558Srgrimes domain[0] = 0; 5291558Srgrimes } 5301558Srgrimes 5311558Srgrimes if (sa->sa_len == 0) 5321558Srgrimes strcpy(line, "default"); 5331558Srgrimes else switch (sa->sa_family) { 5341558Srgrimes 5351558Srgrimes case AF_INET: 5361558Srgrimes { struct in_addr in; 5371558Srgrimes in = ((struct sockaddr_in *)sa)->sin_addr; 5381558Srgrimes 539204406Suqs cp = NULL; 5401558Srgrimes if (in.s_addr == INADDR_ANY || sa->sa_len < 4) 5411558Srgrimes cp = "default"; 542204406Suqs if (cp == NULL && !nflag) { 5431558Srgrimes hp = gethostbyaddr((char *)&in, sizeof (struct in_addr), 5441558Srgrimes AF_INET); 545204406Suqs if (hp != NULL) { 546204406Suqs char *cptr; 547204406Suqs cptr = strchr(hp->h_name, '.'); 548204406Suqs if (cptr != NULL && 549204406Suqs strcmp(cptr + 1, domain) == 0) 550204406Suqs *cptr = '\0'; 5511558Srgrimes cp = hp->h_name; 5521558Srgrimes } 5531558Srgrimes } 554204406Suqs if (cp != NULL) { 55531958Simp strncpy(line, cp, sizeof(line) - 1); 55631958Simp line[sizeof(line) - 1] = '\0'; 55777873Sru } else 55877873Sru (void) sprintf(line, "%s", inet_ntoa(in)); 5591558Srgrimes break; 5601558Srgrimes } 5611558Srgrimes 56254263Sshin#ifdef INET6 56354263Sshin case AF_INET6: 56478064Sume { 56578064Sume struct sockaddr_in6 sin6; /* use static var for safety */ 56678064Sume int niflags = 0; 56754263Sshin 56878064Sume memset(&sin6, 0, sizeof(sin6)); 56978064Sume memcpy(&sin6, sa, sa->sa_len); 57078064Sume sin6.sin6_len = sizeof(struct sockaddr_in6); 57178064Sume sin6.sin6_family = AF_INET6; 57278064Sume if (nflag) 57378064Sume niflags |= NI_NUMERICHOST; 57478064Sume if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, 57578064Sume line, sizeof(line), NULL, 0, niflags) != 0) 57678064Sume strncpy(line, "invalid", sizeof(line)); 57778064Sume 57878064Sume return(line); 57978064Sume } 58078064Sume#endif 58178064Sume 58217046Sjulian case AF_APPLETALK: 58317046Sjulian (void) snprintf(line, sizeof(line), "atalk %s", 58417046Sjulian atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr)); 58517046Sjulian break; 58617046Sjulian 5871558Srgrimes case AF_LINK: 5881558Srgrimes return (link_ntoa((struct sockaddr_dl *)sa)); 5891558Srgrimes 5901558Srgrimes default: 591204406Suqs { 592204406Suqs u_short *sp = (u_short *)sa; 593204406Suqs u_short *splim = sp + ((sa->sa_len + 1) >> 1); 594204406Suqs char *cps = line + sprintf(line, "(%d)", sa->sa_family); 59519209Sfenner char *cpe = line + sizeof(line); 5961558Srgrimes 597204406Suqs while (++sp < splim && cps < cpe) /* start with sa->sa_data */ 598204406Suqs if ((n = snprintf(cps, cpe - cps, " %x", *sp)) > 0) 599204406Suqs cps += n; 60081980Sbrian else 601204406Suqs *cps = '\0'; 6021558Srgrimes break; 6031558Srgrimes } 6041558Srgrimes } 6051558Srgrimes return (line); 6061558Srgrimes} 6071558Srgrimes 6081558Srgrimes/* 6091558Srgrimes * Return the name of the network whose address is given. 610243019Sglebius * The address is assumed to be that of a net, not a host. 6111558Srgrimes */ 61278064Sumeconst char * 613196527Scharniernetname(struct sockaddr *sa) 6141558Srgrimes{ 615204406Suqs const char *cp = NULL; 61619209Sfenner static char line[MAXHOSTNAMELEN + 1]; 617204406Suqs struct netent *np = NULL; 61892806Sobrien u_long i; 619243019Sglebius int n; 6201558Srgrimes 6211558Srgrimes switch (sa->sa_family) { 6221558Srgrimes 6231558Srgrimes case AF_INET: 6241558Srgrimes { struct in_addr in; 6251558Srgrimes in = ((struct sockaddr_in *)sa)->sin_addr; 6261558Srgrimes 6271558Srgrimes i = in.s_addr = ntohl(in.s_addr); 6281558Srgrimes if (in.s_addr == 0) 6291558Srgrimes cp = "default"; 6301558Srgrimes else if (!nflag) { 631243019Sglebius np = getnetbyaddr(i, AF_INET); 632204406Suqs if (np != NULL) 6331558Srgrimes cp = np->n_name; 6341558Srgrimes } 63577873Sru#define C(x) (unsigned)((x) & 0xff) 636204406Suqs if (cp != NULL) 63719209Sfenner strncpy(line, cp, sizeof(line)); 6381558Srgrimes else if ((in.s_addr & 0xffffff) == 0) 6391558Srgrimes (void) sprintf(line, "%u", C(in.s_addr >> 24)); 6401558Srgrimes else if ((in.s_addr & 0xffff) == 0) 6411558Srgrimes (void) sprintf(line, "%u.%u", C(in.s_addr >> 24), 6421558Srgrimes C(in.s_addr >> 16)); 6431558Srgrimes else if ((in.s_addr & 0xff) == 0) 6441558Srgrimes (void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24), 6451558Srgrimes C(in.s_addr >> 16), C(in.s_addr >> 8)); 6461558Srgrimes else 6471558Srgrimes (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), 6481558Srgrimes C(in.s_addr >> 16), C(in.s_addr >> 8), 6491558Srgrimes C(in.s_addr)); 65077873Sru#undef C 6511558Srgrimes break; 6521558Srgrimes } 6531558Srgrimes 65454263Sshin#ifdef INET6 65554263Sshin case AF_INET6: 65678064Sume { 65778064Sume struct sockaddr_in6 sin6; /* use static var for safety */ 65878064Sume int niflags = 0; 65954263Sshin 66078064Sume memset(&sin6, 0, sizeof(sin6)); 66178064Sume memcpy(&sin6, sa, sa->sa_len); 66278064Sume sin6.sin6_len = sizeof(struct sockaddr_in6); 66378064Sume sin6.sin6_family = AF_INET6; 66478064Sume if (nflag) 66578064Sume niflags |= NI_NUMERICHOST; 66678064Sume if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, 66778064Sume line, sizeof(line), NULL, 0, niflags) != 0) 66878064Sume strncpy(line, "invalid", sizeof(line)); 66978064Sume 67078064Sume return(line); 67178064Sume } 67278064Sume#endif 67378064Sume 67417046Sjulian case AF_APPLETALK: 67517046Sjulian (void) snprintf(line, sizeof(line), "atalk %s", 67617046Sjulian atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr)); 67717046Sjulian break; 67817046Sjulian 6791558Srgrimes case AF_LINK: 6801558Srgrimes return (link_ntoa((struct sockaddr_dl *)sa)); 6811558Srgrimes 6821558Srgrimes 6831558Srgrimes default: 684204406Suqs { 685204406Suqs u_short *sp = (u_short *)sa->sa_data; 686204406Suqs u_short *splim = sp + ((sa->sa_len + 1)>>1); 687204406Suqs char *cps = line + sprintf(line, "af %d:", sa->sa_family); 68819209Sfenner char *cpe = line + sizeof(line); 6891558Srgrimes 690204406Suqs while (sp < splim && cps < cpe) 691204406Suqs if ((n = snprintf(cps, cpe - cps, " %x", *sp++)) > 0) 692204406Suqs cps += n; 69381980Sbrian else 694204406Suqs *cps = '\0'; 6951558Srgrimes break; 6961558Srgrimes } 6971558Srgrimes } 6981558Srgrimes return (line); 6991558Srgrimes} 7001558Srgrimes 701204406Suqsstatic void 702196527Scharnierset_metric(char *value, int key) 7031558Srgrimes{ 7041558Srgrimes int flag = 0; 7051558Srgrimes u_long noval, *valp = &noval; 7061558Srgrimes 7071558Srgrimes switch (key) { 7081558Srgrimes#define caseof(x, y, z) case x: valp = &rt_metrics.z; flag = y; break 7091558Srgrimes caseof(K_MTU, RTV_MTU, rmx_mtu); 7101558Srgrimes caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount); 7111558Srgrimes caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire); 7121558Srgrimes caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe); 7131558Srgrimes caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe); 7141558Srgrimes caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh); 7151558Srgrimes caseof(K_RTT, RTV_RTT, rmx_rtt); 7161558Srgrimes caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar); 717191080Skmacy caseof(K_WEIGHT, RTV_WEIGHT, rmx_weight); 7181558Srgrimes } 7191558Srgrimes rtm_inits |= flag; 7201558Srgrimes if (lockrest || locking) 7211558Srgrimes rt_metrics.rmx_locks |= flag; 7221558Srgrimes if (locking) 7231558Srgrimes locking = 0; 7241558Srgrimes *valp = atoi(value); 7251558Srgrimes} 7261558Srgrimes 727243185Shrs#define F_ISHOST 0x01 728243185Shrs#define F_FORCENET 0x02 729243185Shrs#define F_FORCEHOST 0x04 730243185Shrs#define F_PROXY 0x08 731243185Shrs#define F_INTERFACE 0x10 732243185Shrs 733204406Suqsstatic void 734196527Scharniernewroute(int argc, char **argv) 7351558Srgrimes{ 736243185Shrs struct hostent *hp; 737243185Shrs struct fibl *fl; 738204406Suqs char *cmd; 739243185Shrs const char *dest, *gateway, *errmsg; 740243185Shrs int key, error, flags, nrflags, fibnum; 7411558Srgrimes 742243859Sglebius if (uid != 0 && !debugonly && !tflag) { 74313171Swollman errx(EX_NOPERM, "must be root to alter routing table"); 7441558Srgrimes } 745243185Shrs 746243185Shrs dest = NULL; 747243185Shrs gateway = NULL; 748243185Shrs flags = RTF_STATIC; 749243185Shrs nrflags = 0; 750243185Shrs hp = NULL; 751243185Shrs TAILQ_INIT(&fibl_head); 752243185Shrs 7531558Srgrimes cmd = argv[0]; 754191080Skmacy if (*cmd != 'g' && *cmd != 's') 755146079Sjmallett shutdown(s, SHUT_RD); /* Don't want to read back our messages */ 756191080Skmacy 7571558Srgrimes while (--argc > 0) { 7581558Srgrimes if (**(++argv)== '-') { 7591558Srgrimes switch (key = keyword(1 + *argv)) { 7601558Srgrimes case K_LINK: 7611558Srgrimes af = AF_LINK; 7621558Srgrimes aflen = sizeof(struct sockaddr_dl); 7631558Srgrimes break; 7641558Srgrimes case K_INET: 7651558Srgrimes af = AF_INET; 7661558Srgrimes aflen = sizeof(struct sockaddr_in); 7671558Srgrimes break; 76854263Sshin#ifdef INET6 76954263Sshin case K_INET6: 77054263Sshin af = AF_INET6; 77154263Sshin aflen = sizeof(struct sockaddr_in6); 77254263Sshin break; 77354263Sshin#endif 77417046Sjulian case K_ATALK: 77517046Sjulian af = AF_APPLETALK; 77617046Sjulian aflen = sizeof(struct sockaddr_at); 77717046Sjulian break; 7781558Srgrimes case K_SA: 7791558Srgrimes af = PF_ROUTE; 7801558Srgrimes aflen = sizeof(union sockunion); 7811558Srgrimes break; 7821558Srgrimes case K_IFACE: 7831558Srgrimes case K_INTERFACE: 784243185Shrs nrflags |= F_INTERFACE; 7852787Spst break; 7861558Srgrimes case K_NOSTATIC: 7871558Srgrimes flags &= ~RTF_STATIC; 7881558Srgrimes break; 7891558Srgrimes case K_LOCK: 7901558Srgrimes locking = 1; 7911558Srgrimes break; 7921558Srgrimes case K_LOCKREST: 7931558Srgrimes lockrest = 1; 7941558Srgrimes break; 7951558Srgrimes case K_HOST: 796243185Shrs nrflags |= F_FORCEHOST; 7971558Srgrimes break; 7981558Srgrimes case K_REJECT: 7991558Srgrimes flags |= RTF_REJECT; 8001558Srgrimes break; 8011558Srgrimes case K_BLACKHOLE: 8021558Srgrimes flags |= RTF_BLACKHOLE; 8031558Srgrimes break; 8041558Srgrimes case K_PROTO1: 8051558Srgrimes flags |= RTF_PROTO1; 8061558Srgrimes break; 8071558Srgrimes case K_PROTO2: 8081558Srgrimes flags |= RTF_PROTO2; 8091558Srgrimes break; 81078140Sru case K_PROXY: 811243185Shrs nrflags |= F_PROXY; 81278140Sru break; 8131558Srgrimes case K_XRESOLVE: 8141558Srgrimes flags |= RTF_XRESOLVE; 8151558Srgrimes break; 8161558Srgrimes case K_STATIC: 8171558Srgrimes flags |= RTF_STATIC; 8181558Srgrimes break; 819191080Skmacy case K_STICKY: 820191080Skmacy flags |= RTF_STICKY; 821191080Skmacy break; 822191080Skmacy case K_NOSTICK: 823191080Skmacy flags &= ~RTF_STICKY; 824191080Skmacy break; 825243185Shrs case K_FIB: 826243185Shrs if (!--argc) 827243185Shrs usage(NULL); 828243185Shrs error = fiboptlist_csv(*++argv, &fibl_head); 829243185Shrs if (error) 830244325Shrs errx(EX_USAGE, 831244325Shrs "invalid fib number: %s", *argv); 832243185Shrs break; 8331558Srgrimes case K_IFA: 83447668Sru if (!--argc) 835204406Suqs usage(NULL); 8361558Srgrimes (void) getaddr(RTA_IFA, *++argv, 0); 8371558Srgrimes break; 8381558Srgrimes case K_IFP: 83947668Sru if (!--argc) 840204406Suqs usage(NULL); 8411558Srgrimes (void) getaddr(RTA_IFP, *++argv, 0); 8421558Srgrimes break; 8431558Srgrimes case K_GENMASK: 84447668Sru if (!--argc) 845204406Suqs usage(NULL); 8461558Srgrimes (void) getaddr(RTA_GENMASK, *++argv, 0); 8471558Srgrimes break; 8481558Srgrimes case K_GATEWAY: 84947668Sru if (!--argc) 850204406Suqs usage(NULL); 8511558Srgrimes (void) getaddr(RTA_GATEWAY, *++argv, 0); 8521558Srgrimes break; 8531558Srgrimes case K_DST: 85447668Sru if (!--argc) 855204406Suqs usage(NULL); 856243185Shrs if (getaddr(RTA_DST, *++argv, &hp)) 857243185Shrs nrflags |= F_ISHOST; 8581558Srgrimes dest = *argv; 8591558Srgrimes break; 8601558Srgrimes case K_NETMASK: 86147668Sru if (!--argc) 862204406Suqs usage(NULL); 8631558Srgrimes (void) getaddr(RTA_NETMASK, *++argv, 0); 8641558Srgrimes /* FALLTHROUGH */ 8651558Srgrimes case K_NET: 866243185Shrs nrflags |= F_FORCENET; 8671558Srgrimes break; 86854263Sshin case K_PREFIXLEN: 86954263Sshin if (!--argc) 870204406Suqs usage(NULL); 87154263Sshin if (prefixlen(*++argv) == -1) { 872243185Shrs nrflags &= ~F_FORCENET; 873243185Shrs nrflags |= F_ISHOST; 87454263Sshin } else { 875243185Shrs nrflags |= F_FORCENET; 876243185Shrs nrflags &= ~F_ISHOST; 87754263Sshin } 87854263Sshin break; 8791558Srgrimes case K_MTU: 8801558Srgrimes case K_HOPCOUNT: 8811558Srgrimes case K_EXPIRE: 8821558Srgrimes case K_RECVPIPE: 8831558Srgrimes case K_SENDPIPE: 8841558Srgrimes case K_SSTHRESH: 8851558Srgrimes case K_RTT: 8861558Srgrimes case K_RTTVAR: 887191080Skmacy case K_WEIGHT: 88847668Sru if (!--argc) 889204406Suqs usage(NULL); 8901558Srgrimes set_metric(*++argv, key); 8911558Srgrimes break; 8921558Srgrimes default: 8931558Srgrimes usage(1+*argv); 8941558Srgrimes } 8951558Srgrimes } else { 8961558Srgrimes if ((rtm_addrs & RTA_DST) == 0) { 8971558Srgrimes dest = *argv; 898243185Shrs if (getaddr(RTA_DST, *argv, &hp)) 899243185Shrs nrflags |= F_ISHOST; 9001558Srgrimes } else if ((rtm_addrs & RTA_GATEWAY) == 0) { 9011558Srgrimes gateway = *argv; 9021558Srgrimes (void) getaddr(RTA_GATEWAY, *argv, &hp); 9031558Srgrimes } else { 9041558Srgrimes (void) getaddr(RTA_NETMASK, *argv, 0); 905243185Shrs nrflags |= F_FORCENET; 9061558Srgrimes } 9071558Srgrimes } 9081558Srgrimes } 909243185Shrs 910243185Shrs if (nrflags & F_FORCEHOST) { 911243185Shrs nrflags |= F_ISHOST; 91254263Sshin#ifdef INET6 91354263Sshin if (af == AF_INET6) { 91454263Sshin rtm_addrs &= ~RTA_NETMASK; 915204406Suqs memset((void *)&so_mask, 0, sizeof(so_mask)); 91654263Sshin } 917204406Suqs#endif 91854263Sshin } 919243185Shrs if (nrflags & F_FORCENET) 920243185Shrs nrflags &= ~F_ISHOST; 9211558Srgrimes flags |= RTF_UP; 922243185Shrs if (nrflags & F_ISHOST) 9231558Srgrimes flags |= RTF_HOST; 924243185Shrs if ((nrflags & F_INTERFACE) == 0) 9251558Srgrimes flags |= RTF_GATEWAY; 926243185Shrs if (nrflags & F_PROXY) { 92778140Sru so_dst.sinarp.sin_other = SIN_PROXY; 92878140Sru flags |= RTF_ANNOUNCE; 92978140Sru } 930243185Shrs if (dest == NULL) 931243185Shrs dest = ""; 932243185Shrs if (gateway == NULL) 933243185Shrs gateway = ""; 934243185Shrs 935243185Shrs if (TAILQ_EMPTY(&fibl_head)) { 936243185Shrs error = fiboptlist_csv("default", &fibl_head); 937243185Shrs if (error) 938243185Shrs errx(EX_OSERR, "fiboptlist_csv failed."); 9391558Srgrimes } 940243185Shrs error = 0; 941243185Shrs TAILQ_FOREACH(fl, &fibl_head, fl_next) { 942243185Shrs fl->fl_error = newroute_fib(fl->fl_num, cmd, flags); 943243185Shrs if (fl->fl_error) 944243185Shrs fl->fl_errno = errno; 945243185Shrs error += fl->fl_error; 946243185Shrs } 947191080Skmacy if (*cmd == 'g' || *cmd == 's') 948243185Shrs exit(error); 949243185Shrs 950243185Shrs error = 0; 95197278Sru if (!qflag) { 952243185Shrs fibnum = 0; 953243185Shrs TAILQ_FOREACH(fl, &fibl_head, fl_next) { 954243185Shrs if (fl->fl_error == 0) 955243185Shrs fibnum++; 9561558Srgrimes } 957243185Shrs if (fibnum > 0) { 958243185Shrs int firstfib = 1; 959243185Shrs 960243185Shrs printf("%s %s %s", cmd, 961243185Shrs (nrflags & F_ISHOST) ? "host" : "net", dest); 962243185Shrs if (*gateway) 963243185Shrs printf(": gateway %s", gateway); 964243185Shrs 965243185Shrs if (numfibs > 1) { 966243185Shrs TAILQ_FOREACH(fl, &fibl_head, fl_next) { 967243185Shrs if (fl->fl_error == 0 968243185Shrs && fl->fl_num >= 0) { 969243185Shrs if (firstfib) { 970243185Shrs printf(" fib "); 971243185Shrs firstfib = 0; 972243185Shrs } 973243185Shrs printf("%d", fl->fl_num); 974243185Shrs if (fibnum-- > 1) 975243185Shrs printf(","); 976243185Shrs } 977243185Shrs } 97897278Sru } 979243185Shrs printf("\n"); 98097278Sru } 981243185Shrs 982243185Shrs fibnum = 0; 983243185Shrs TAILQ_FOREACH(fl, &fibl_head, fl_next) { 984243185Shrs if (fl->fl_error != 0) { 985243185Shrs printf("%s %s %s", cmd, (nrflags & F_ISHOST) 986243185Shrs ? "host" : "net", dest); 987243185Shrs if (*gateway) 988243185Shrs printf(": gateway %s", gateway); 989243185Shrs 990243185Shrs if (fl->fl_num >= 0) 991243185Shrs printf(" fib %d", fl->fl_num); 992243185Shrs 993243185Shrs switch (fl->fl_errno) { 994243185Shrs case ESRCH: 995243185Shrs errmsg = "not in table"; 996243185Shrs break; 997243185Shrs case EBUSY: 998243185Shrs errmsg = "entry in use"; 999243185Shrs break; 1000243185Shrs case ENOBUFS: 1001243185Shrs errmsg = "not enough memory"; 1002243185Shrs break; 1003243185Shrs case EADDRINUSE: 1004243185Shrs /* 1005243185Shrs * handle recursion avoidance 1006243185Shrs * in rt_setgate() 1007243185Shrs */ 1008243185Shrs errmsg = "gateway uses the same route"; 1009243185Shrs break; 1010243185Shrs case EEXIST: 1011243185Shrs errmsg = "route already in table"; 1012243185Shrs break; 1013243185Shrs default: 1014243185Shrs errmsg = strerror(fl->fl_errno); 1015243185Shrs break; 1016243185Shrs } 1017243185Shrs printf(": %s\n", errmsg); 1018243185Shrs error = 1; 1019243185Shrs } 1020243185Shrs } 10211558Srgrimes } 1022243185Shrs exit(error); 10231558Srgrimes} 10241558Srgrimes 1025243185Shrsstatic int 1026243185Shrsnewroute_fib(int fib, char *cmd, int flags) 1027243185Shrs{ 1028243185Shrs int error; 1029243185Shrs 1030243185Shrs error = set_sofib(fib); 1031243185Shrs if (error) { 1032243185Shrs warn("fib number %d is ignored", fib); 1033243185Shrs return (error); 1034243185Shrs } 1035243185Shrs 1036243185Shrs error = rtmsg(*cmd, flags, fib); 1037243185Shrs return (error); 1038243185Shrs} 1039243185Shrs 1040204406Suqsstatic void 1041196527Scharnierinet_makenetandmask(u_long net, struct sockaddr_in *sin, u_long bits) 10421558Srgrimes{ 1043243019Sglebius u_long mask = 0; 104492806Sobrien char *cp; 10451558Srgrimes 10461558Srgrimes rtm_addrs |= RTA_NETMASK; 1047243019Sglebius 1048204406Suqs /* 1049243867Sglebius * MSB of net should be meaningful. 0/0 is exception. 1050243867Sglebius */ 1051243867Sglebius if (net > 0) 1052243867Sglebius while ((net & 0xff000000) == 0) 1053243867Sglebius net <<= 8; 1054243867Sglebius 1055243867Sglebius /* 1056204406Suqs * If no /xx was specified we must calculate the 1057190758Srrs * CIDR address. 1058190758Srrs */ 1059243019Sglebius if ((bits == 0) && (net != 0)) { 1060190775Srrs u_long i, j; 1061190775Srrs for(i=0,j=0xff; i<4; i++) { 1062243019Sglebius if (net & j) { 1063190758Srrs break; 1064190758Srrs } 1065190775Srrs j <<= 8; 1066190758Srrs } 1067190758Srrs /* i holds the first non zero bit */ 1068190775Srrs bits = 32 - (i*8); 1069190758Srrs } 1070190913Srrs if (bits != 0) 1071190913Srrs mask = 0xffffffff << (32 - bits); 1072173124Smtm 1073243019Sglebius sin->sin_addr.s_addr = htonl(net); 10741558Srgrimes sin = &so_mask.sin; 10751558Srgrimes sin->sin_addr.s_addr = htonl(mask); 10761558Srgrimes sin->sin_len = 0; 10771558Srgrimes sin->sin_family = 0; 10781558Srgrimes cp = (char *)(&sin->sin_addr + 1); 10791558Srgrimes while (*--cp == 0 && cp > (char *)sin) 10801558Srgrimes ; 10811558Srgrimes sin->sin_len = 1 + cp - (char *)sin; 10821558Srgrimes} 10831558Srgrimes 108496997Sume#ifdef INET6 10851558Srgrimes/* 108696997Sume * XXX the function may need more improvement... 108796997Sume */ 108897062Sumestatic int 1089204406Suqsinet6_makenetandmask(struct sockaddr_in6 *sin6, const char *plen) 109096997Sume{ 109196997Sume struct in6_addr in6; 109296997Sume 1093204406Suqs if (plen == NULL) { 109497073Sume if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && 109597073Sume sin6->sin6_scope_id == 0) { 109697073Sume plen = "0"; 109797073Sume } else if ((sin6->sin6_addr.s6_addr[0] & 0xe0) == 0x20) { 109897073Sume /* aggregatable global unicast - RFC2374 */ 109997073Sume memset(&in6, 0, sizeof(in6)); 110097073Sume if (!memcmp(&sin6->sin6_addr.s6_addr[8], 110197073Sume &in6.s6_addr[8], 8)) 110297073Sume plen = "64"; 110397073Sume } 110496997Sume } 110596997Sume 1106204406Suqs if (plen == NULL || strcmp(plen, "128") == 0) 1107204406Suqs return (1); 110898053Sume rtm_addrs |= RTA_NETMASK; 1109204406Suqs prefixlen(plen); 1110204406Suqs return (0); 111196997Sume} 111296997Sume#endif 111396997Sume 111496997Sume/* 11151558Srgrimes * Interpret an argument as a network address of some kind, 11161558Srgrimes * returning 1 if a host address, 0 if a network address. 11171558Srgrimes */ 1118204406Suqsstatic int 1119204406Suqsgetaddr(int which, char *str, struct hostent **hpp) 11201558Srgrimes{ 112192806Sobrien sup su; 11221558Srgrimes struct hostent *hp; 11231558Srgrimes struct netent *np; 11241558Srgrimes u_long val; 112566449Sru char *q; 112654263Sshin int afamily; /* local copy of af so we can change it */ 11271558Srgrimes 11281558Srgrimes if (af == 0) { 11291558Srgrimes af = AF_INET; 11301558Srgrimes aflen = sizeof(struct sockaddr_in); 11311558Srgrimes } 113254263Sshin afamily = af; 11331558Srgrimes rtm_addrs |= which; 11341558Srgrimes switch (which) { 11351558Srgrimes case RTA_DST: 11361558Srgrimes su = &so_dst; 11371558Srgrimes break; 11381558Srgrimes case RTA_GATEWAY: 11391558Srgrimes su = &so_gate; 114017486Sjulian if (iflag) { 114178064Sume struct ifaddrs *ifap, *ifa; 114278064Sume struct sockaddr_dl *sdl = NULL; 114317486Sjulian 114478064Sume if (getifaddrs(&ifap)) 114578064Sume err(1, "getifaddrs"); 114617486Sjulian 1147204406Suqs for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 114878064Sume if (ifa->ifa_addr->sa_family != AF_LINK) 114978064Sume continue; 115017486Sjulian 1151204406Suqs if (strcmp(str, ifa->ifa_name) != 0) 115278064Sume continue; 115378064Sume 115478064Sume sdl = (struct sockaddr_dl *)ifa->ifa_addr; 115517486Sjulian } 115617486Sjulian /* If we found it, then use it */ 1157204406Suqs if (sdl != NULL) { 115878064Sume /* 115978064Sume * Copy is safe since we have a 116078064Sume * sockaddr_storage member in sockunion{}. 116178064Sume * Note that we need to copy before calling 116278064Sume * freeifaddrs(). 116378064Sume */ 116478064Sume memcpy(&su->sdl, sdl, sdl->sdl_len); 116578064Sume } 116678064Sume freeifaddrs(ifap); 1167204406Suqs if (sdl != NULL) 116817486Sjulian return(1); 116917486Sjulian } 11701558Srgrimes break; 11711558Srgrimes case RTA_NETMASK: 11721558Srgrimes su = &so_mask; 11731558Srgrimes break; 11741558Srgrimes case RTA_GENMASK: 11751558Srgrimes su = &so_genmask; 11761558Srgrimes break; 11771558Srgrimes case RTA_IFP: 11781558Srgrimes su = &so_ifp; 117954263Sshin afamily = AF_LINK; 11801558Srgrimes break; 11811558Srgrimes case RTA_IFA: 11821558Srgrimes su = &so_ifa; 11831558Srgrimes break; 11841558Srgrimes default: 118537907Scharnier usage("internal error"); 11861558Srgrimes /*NOTREACHED*/ 11871558Srgrimes } 11881558Srgrimes su->sa.sa_len = aflen; 118954263Sshin su->sa.sa_family = afamily; /* cases that don't want it have left already */ 1190204406Suqs if (strcmp(str, "default") == 0) { 119127500Sjulian /* 1192204406Suqs * Default is net 0.0.0.0/0 119327500Sjulian */ 11941558Srgrimes switch (which) { 11951558Srgrimes case RTA_DST: 11961558Srgrimes forcenet++; 119797637Swollman#if 0 119897637Swollman bzero(su, sizeof(*su)); /* for readability */ 119997637Swollman#endif 1200204406Suqs getaddr(RTA_NETMASK, str, 0); 12011558Srgrimes break; 120297637Swollman#if 0 12031558Srgrimes case RTA_NETMASK: 12041558Srgrimes case RTA_GENMASK: 120597637Swollman bzero(su, sizeof(*su)); /* for readability */ 120697637Swollman#endif 12071558Srgrimes } 12081558Srgrimes return (0); 12091558Srgrimes } 121054263Sshin switch (afamily) { 121154263Sshin#ifdef INET6 121254263Sshin case AF_INET6: 121378064Sume { 121457108Sshin struct addrinfo hints, *res; 1215146546Sume int ecode; 121657108Sshin 121797073Sume q = NULL; 1218204406Suqs if (which == RTA_DST && (q = strchr(str, '/')) != NULL) 121997073Sume *q = '\0'; 122078064Sume memset(&hints, 0, sizeof(hints)); 122178064Sume hints.ai_family = afamily; /*AF_INET6*/ 122278064Sume hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 1223204406Suqs ecode = getaddrinfo(str, NULL, &hints, &res); 1224146546Sume if (ecode != 0 || res->ai_family != AF_INET6 || 122578064Sume res->ai_addrlen != sizeof(su->sin6)) { 1226204406Suqs (void) fprintf(stderr, "%s: %s\n", str, 1227146546Sume gai_strerror(ecode)); 122854263Sshin exit(1); 122954263Sshin } 123078064Sume memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6)); 123197062Sume freeaddrinfo(res); 123297073Sume if (q != NULL) 123397073Sume *q++ = '/'; 123496997Sume if (which == RTA_DST) 123598053Sume return (inet6_makenetandmask(&su->sin6, q)); 123678064Sume return (0); 123778064Sume } 123878064Sume#endif /* INET6 */ 123954263Sshin 124017046Sjulian case AF_APPLETALK: 1241204406Suqs if (!atalk_aton(str, &su->sat.sat_addr)) 1242204406Suqs errx(EX_NOHOST, "bad address: %s", str); 124317265Sjulian rtm_addrs |= RTA_NETMASK; 124417265Sjulian return(forcehost || su->sat.sat_addr.s_node != 0); 124517046Sjulian 12461558Srgrimes case AF_LINK: 1247204406Suqs link_addr(str, &su->sdl); 12481558Srgrimes return (1); 12491558Srgrimes 12501558Srgrimes 12511558Srgrimes case PF_ROUTE: 12521558Srgrimes su->sa.sa_len = sizeof(*su); 1253204406Suqs sockaddr(str, &su->sa); 12541558Srgrimes return (1); 12551558Srgrimes 12561558Srgrimes case AF_INET: 12571558Srgrimes default: 12581558Srgrimes break; 12591558Srgrimes } 12601558Srgrimes 12611558Srgrimes if (hpp == NULL) 12621558Srgrimes hpp = &hp; 12631558Srgrimes *hpp = NULL; 126424558Sphk 1265204406Suqs q = strchr(str,'/'); 1266204406Suqs if (q != NULL && which == RTA_DST) { 126724558Sphk *q = '\0'; 1268204406Suqs if ((val = inet_network(str)) != INADDR_NONE) { 126924558Sphk inet_makenetandmask( 127077904Sru val, &su->sin, strtoul(q+1, 0, 0)); 127124558Sphk return (0); 127224558Sphk } 127366449Sru *q = '/'; 127424558Sphk } 127566449Sru if ((which != RTA_DST || forcenet == 0) && 1276204406Suqs inet_aton(str, &su->sin.sin_addr)) { 127779588Sru val = su->sin.sin_addr.s_addr; 1278130569Sbms if (which != RTA_DST || forcehost || 127966449Sru inet_lnaof(su->sin.sin_addr) != INADDR_ANY) 12801558Srgrimes return (1); 12811558Srgrimes else { 12821558Srgrimes val = ntohl(val); 12831558Srgrimes goto netdone; 12841558Srgrimes } 12851558Srgrimes } 128666449Sru if (which == RTA_DST && forcehost == 0 && 1287204406Suqs ((val = inet_network(str)) != INADDR_NONE || 1288204406Suqs ((np = getnetbyname(str)) != NULL && (val = np->n_net) != 0))) { 12891558Srgrimesnetdone: 129066449Sru inet_makenetandmask(val, &su->sin, 0); 12911558Srgrimes return (0); 12921558Srgrimes } 1293204406Suqs hp = gethostbyname(str); 1294204406Suqs if (hp != NULL) { 12951558Srgrimes *hpp = hp; 12961558Srgrimes su->sin.sin_family = hp->h_addrtype; 129785048Sru memmove((char *)&su->sin.sin_addr, hp->h_addr, 1298204406Suqs MIN((size_t)hp->h_length, sizeof(su->sin.sin_addr))); 12991558Srgrimes return (1); 13001558Srgrimes } 1301204406Suqs errx(EX_NOHOST, "bad address: %s", str); 13021558Srgrimes} 13031558Srgrimes 1304204406Suqsstatic int 1305204406Suqsprefixlen(const char *str) 130654263Sshin{ 1307204406Suqs int len = atoi(str), q, r; 130854263Sshin int max; 130954263Sshin char *p; 13101558Srgrimes 131154263Sshin rtm_addrs |= RTA_NETMASK; 131254263Sshin switch (af) { 131354263Sshin#ifdef INET6 131454263Sshin case AF_INET6: 131554263Sshin max = 128; 131654263Sshin p = (char *)&so_mask.sin6.sin6_addr; 131754263Sshin break; 131854263Sshin#endif 131954263Sshin case AF_INET: 132054263Sshin max = 32; 132154263Sshin p = (char *)&so_mask.sin.sin_addr; 132254263Sshin break; 132354263Sshin default: 1324204406Suqs fprintf(stderr, "prefixlen not supported in this af\n"); 132554263Sshin exit(1); 132654263Sshin } 132754263Sshin 132854263Sshin if (len < 0 || max < len) { 1329204406Suqs fprintf(stderr, "%s: bad value\n", str); 133054263Sshin exit(1); 133154263Sshin } 133254263Sshin 133354263Sshin q = len >> 3; 133454263Sshin r = len & 7; 133554263Sshin so_mask.sa.sa_family = af; 133654263Sshin so_mask.sa.sa_len = aflen; 133754263Sshin memset((void *)p, 0, max / 8); 133854263Sshin if (q > 0) 133954263Sshin memset((void *)p, 0xff, q); 134054263Sshin if (r > 0) 134154263Sshin *((u_char *)p + q) = (0xff00 >> r) & 0xff; 134254263Sshin if (len == max) 1343204406Suqs return (-1); 134454263Sshin else 1345204406Suqs return (len); 134654263Sshin} 134754263Sshin 1348204406Suqsstatic void 1349196527Scharnierinterfaces(void) 13501558Srgrimes{ 13511558Srgrimes size_t needed; 13521558Srgrimes int mib[6]; 1353128782Sambrisko char *buf, *lim, *next, count = 0; 135492806Sobrien struct rt_msghdr *rtm; 13551558Srgrimes 1356128782Sambriskoretry2: 13571558Srgrimes mib[0] = CTL_NET; 13581558Srgrimes mib[1] = PF_ROUTE; 13591558Srgrimes mib[2] = 0; /* protocol */ 13601558Srgrimes mib[3] = 0; /* wildcard address family */ 13611558Srgrimes mib[4] = NET_RT_IFLIST; 13621558Srgrimes mib[5] = 0; /* no flags */ 13631558Srgrimes if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 136413171Swollman err(EX_OSERR, "route-sysctl-estimate"); 13651558Srgrimes if ((buf = malloc(needed)) == NULL) 136637907Scharnier errx(EX_OSERR, "malloc failed"); 1367128782Sambrisko if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 1368128782Sambrisko if (errno == ENOMEM && count++ < 10) { 1369128782Sambrisko warnx("Routing table grew, retrying"); 1370128782Sambrisko sleep(1); 1371128782Sambrisko free(buf); 1372128782Sambrisko goto retry2; 1373128782Sambrisko } 137413171Swollman err(EX_OSERR, "actual retrieval of interface table"); 1375128782Sambrisko } 13761558Srgrimes lim = buf + needed; 13771558Srgrimes for (next = buf; next < lim; next += rtm->rtm_msglen) { 13781558Srgrimes rtm = (struct rt_msghdr *)next; 13791558Srgrimes print_rtmsg(rtm, rtm->rtm_msglen); 13801558Srgrimes } 13811558Srgrimes} 13821558Srgrimes 1383204406Suqsstatic void 1384243185Shrsmonitor(int argc, char *argv[]) 13851558Srgrimes{ 1386243185Shrs int n, fib, error; 1387243185Shrs char msg[2048], *endptr; 13881558Srgrimes 1389243185Shrs fib = defaultfib; 1390243185Shrs while (argc > 1) { 1391243185Shrs argc--; 1392243185Shrs argv++; 1393243185Shrs if (**argv != '-') 1394243185Shrs usage(*argv); 1395243185Shrs switch (keyword(*argv + 1)) { 1396243185Shrs case K_FIB: 1397243185Shrs if (!--argc) 1398243185Shrs usage(*argv); 1399244325Shrs errno = 0; 1400243185Shrs fib = strtol(*++argv, &endptr, 0); 1401244325Shrs if (errno == 0) { 1402244325Shrs if (*endptr != '\0' || 1403244325Shrs fib < 0 || 1404244325Shrs (numfibs != -1 && fib > numfibs - 1)) 1405244325Shrs errno = EINVAL; 1406244325Shrs } 1407244325Shrs if (errno) 1408244325Shrs errx(EX_USAGE, "invalid fib number: %s", *argv); 1409243185Shrs break; 1410243185Shrs default: 1411243185Shrs usage(*argv); 1412243185Shrs } 1413243185Shrs } 1414243185Shrs error = set_sofib(fib); 1415243185Shrs if (error) 1416243185Shrs errx(EX_USAGE, "invalid fib number: %d", fib); 1417243185Shrs 14181558Srgrimes verbose = 1; 14191558Srgrimes if (debugonly) { 14201558Srgrimes interfaces(); 14211558Srgrimes exit(0); 14221558Srgrimes } 1423204406Suqs for (;;) { 142454263Sshin time_t now; 14251558Srgrimes n = read(s, msg, 2048); 142654263Sshin now = time(NULL); 142771061Sphk (void) printf("\ngot message of size %d on %s", n, ctime(&now)); 14281558Srgrimes print_rtmsg((struct rt_msghdr *)msg, n); 14291558Srgrimes } 14301558Srgrimes} 14311558Srgrimes 14321558Srgrimesstruct { 14331558Srgrimes struct rt_msghdr m_rtm; 14341558Srgrimes char m_space[512]; 14351558Srgrimes} m_rtmsg; 14361558Srgrimes 1437204406Suqsstatic int 1438243185Shrsrtmsg(int cmd, int flags, int fib) 14391558Srgrimes{ 14401558Srgrimes static int seq; 14411558Srgrimes int rlen; 144292806Sobrien char *cp = m_rtmsg.m_space; 144392806Sobrien int l; 14441558Srgrimes 14451558Srgrimes#define NEXTADDR(w, u) \ 14461558Srgrimes if (rtm_addrs & (w)) {\ 1447128186Sluigi l = SA_SIZE(&(u.sa)); memmove(cp, &(u), l); cp += l;\ 1448178065Sru if (verbose) sodump(&(u),#u);\ 14491558Srgrimes } 14501558Srgrimes 14511558Srgrimes errno = 0; 145285048Sru memset(&m_rtmsg, 0, sizeof(m_rtmsg)); 14531558Srgrimes if (cmd == 'a') 14541558Srgrimes cmd = RTM_ADD; 14551558Srgrimes else if (cmd == 'c') 14561558Srgrimes cmd = RTM_CHANGE; 1457191080Skmacy else if (cmd == 'g' || cmd == 's') { 14581558Srgrimes cmd = RTM_GET; 14591558Srgrimes if (so_ifp.sa.sa_family == 0) { 146013171Swollman so_ifp.sa.sa_family = AF_LINK; 146113171Swollman so_ifp.sa.sa_len = sizeof(struct sockaddr_dl); 14621558Srgrimes rtm_addrs |= RTA_IFP; 14631558Srgrimes } 14641558Srgrimes } else 14651558Srgrimes cmd = RTM_DELETE; 14661558Srgrimes#define rtm m_rtmsg.m_rtm 14671558Srgrimes rtm.rtm_type = cmd; 14681558Srgrimes rtm.rtm_flags = flags; 14691558Srgrimes rtm.rtm_version = RTM_VERSION; 14701558Srgrimes rtm.rtm_seq = ++seq; 14711558Srgrimes rtm.rtm_addrs = rtm_addrs; 14721558Srgrimes rtm.rtm_rmx = rt_metrics; 14731558Srgrimes rtm.rtm_inits = rtm_inits; 14741558Srgrimes 14751558Srgrimes if (rtm_addrs & RTA_NETMASK) 14761558Srgrimes mask_addr(); 14771558Srgrimes NEXTADDR(RTA_DST, so_dst); 14781558Srgrimes NEXTADDR(RTA_GATEWAY, so_gate); 14791558Srgrimes NEXTADDR(RTA_NETMASK, so_mask); 14801558Srgrimes NEXTADDR(RTA_GENMASK, so_genmask); 14811558Srgrimes NEXTADDR(RTA_IFP, so_ifp); 14821558Srgrimes NEXTADDR(RTA_IFA, so_ifa); 14831558Srgrimes rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; 14841558Srgrimes if (verbose) 14851558Srgrimes print_rtmsg(&rtm, l); 14861558Srgrimes if (debugonly) 14871558Srgrimes return (0); 14881558Srgrimes if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { 1489129034Scsjp if (errno == EPERM) 1490129034Scsjp err(1, "writing to routing socket"); 149137907Scharnier warn("writing to routing socket"); 14921558Srgrimes return (-1); 14931558Srgrimes } 14941558Srgrimes if (cmd == RTM_GET) { 14951558Srgrimes do { 14961558Srgrimes l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); 14971558Srgrimes } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid)); 14981558Srgrimes if (l < 0) 149913171Swollman warn("read from routing socket"); 15001558Srgrimes else 1501243185Shrs print_getmsg(&rtm, l, fib); 15021558Srgrimes } 15031558Srgrimes#undef rtm 15041558Srgrimes return (0); 15051558Srgrimes} 15061558Srgrimes 1507204406Suqsstatic void 1508196527Scharniermask_addr(void) 15091558Srgrimes{ 15101558Srgrimes int olen = so_mask.sa.sa_len; 151192806Sobrien char *cp1 = olen + (char *)&so_mask, *cp2; 15121558Srgrimes 15131558Srgrimes for (so_mask.sa.sa_len = 0; cp1 > (char *)&so_mask; ) 15141558Srgrimes if (*--cp1 != 0) { 15151558Srgrimes so_mask.sa.sa_len = 1 + cp1 - (char *)&so_mask; 15161558Srgrimes break; 15171558Srgrimes } 15181558Srgrimes if ((rtm_addrs & RTA_DST) == 0) 15191558Srgrimes return; 15201558Srgrimes switch (so_dst.sa.sa_family) { 15211558Srgrimes case AF_INET: 152254263Sshin#ifdef INET6 152354263Sshin case AF_INET6: 152454263Sshin#endif 152517046Sjulian case AF_APPLETALK: 15261558Srgrimes case 0: 15271558Srgrimes return; 15281558Srgrimes } 15291558Srgrimes cp1 = so_mask.sa.sa_len + 1 + (char *)&so_dst; 15301558Srgrimes cp2 = so_dst.sa.sa_len + 1 + (char *)&so_dst; 15311558Srgrimes while (cp2 > cp1) 15321558Srgrimes *--cp2 = 0; 15331558Srgrimes cp2 = so_mask.sa.sa_len + 1 + (char *)&so_mask; 15341558Srgrimes while (cp1 > so_dst.sa.sa_data) 15351558Srgrimes *--cp1 &= *--cp2; 15361558Srgrimes} 15371558Srgrimes 1538204406Suqsconst char *msgtypes[] = { 15391558Srgrimes "", 15401558Srgrimes "RTM_ADD: Add Route", 15411558Srgrimes "RTM_DELETE: Delete Route", 15421558Srgrimes "RTM_CHANGE: Change Metrics or flags", 15431558Srgrimes "RTM_GET: Report Metrics", 15441558Srgrimes "RTM_LOSING: Kernel Suspects Partitioning", 15451558Srgrimes "RTM_REDIRECT: Told to use different route", 15461558Srgrimes "RTM_MISS: Lookup failed on this address", 15471558Srgrimes "RTM_LOCK: fix specified metrics", 15481558Srgrimes "RTM_OLDADD: caused by SIOCADDRT", 15491558Srgrimes "RTM_OLDDEL: caused by SIOCDELRT", 15501558Srgrimes "RTM_RESOLVE: Route created by cloning", 15511558Srgrimes "RTM_NEWADDR: address being added to iface", 15521558Srgrimes "RTM_DELADDR: address being removed from iface", 15531558Srgrimes "RTM_IFINFO: iface status change", 155421465Swollman "RTM_NEWMADDR: new multicast group membership on iface", 155521465Swollman "RTM_DELMADDR: multicast group membership removed from iface", 155689498Sru "RTM_IFANNOUNCE: interface arrival/departure", 1557216296Sglebius "RTM_IEEE80211: IEEE 802.11 wireless event", 15581558Srgrimes}; 15591558Srgrimes 15601558Srgrimeschar metricnames[] = 1561191080Skmacy"\011weight\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire" 156215690Swollman"\1mtu"; 15631558Srgrimeschar routeflags[] = 1564191080Skmacy"\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE" 1565191080Skmacy"\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE" 1566191080Skmacy"\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3" 1567191080Skmacy"\025PINNED\026LOCAL\027BROADCAST\030MULTICAST\035STICKY"; 15681558Srgrimeschar ifnetflags[] = 156915690Swollman"\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP" 157015690Swollman"\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1" 157115690Swollman"\017LINK2\020MULTICAST"; 15721558Srgrimeschar addrnames[] = 15731558Srgrimes"\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD"; 15741558Srgrimes 1575216297Sglebiusstatic const char errfmt[] = 1576216297Sglebius"\n%s: truncated route message, only %zu bytes left\n"; 1577216297Sglebius 1578204406Suqsstatic void 1579216297Sglebiusprint_rtmsg(struct rt_msghdr *rtm, size_t msglen) 15801558Srgrimes{ 15811558Srgrimes struct if_msghdr *ifm; 15821558Srgrimes struct ifa_msghdr *ifam; 158321465Swollman#ifdef RTM_NEWMADDR 158421465Swollman struct ifma_msghdr *ifmam; 158521465Swollman#endif 158689498Sru struct if_announcemsghdr *ifan; 1587204406Suqs const char *state; 15881558Srgrimes 15891558Srgrimes if (verbose == 0) 15901558Srgrimes return; 15911558Srgrimes if (rtm->rtm_version != RTM_VERSION) { 15921558Srgrimes (void) printf("routing message version %d not understood\n", 15931558Srgrimes rtm->rtm_version); 15941558Srgrimes return; 15951558Srgrimes } 1596216297Sglebius if (rtm->rtm_type < sizeof(msgtypes) / sizeof(msgtypes[0])) 159789498Sru (void)printf("%s: ", msgtypes[rtm->rtm_type]); 159889498Sru else 1599216297Sglebius (void)printf("unknown type %d: ", rtm->rtm_type); 160089498Sru (void)printf("len %d, ", rtm->rtm_msglen); 1601216297Sglebius 1602216297Sglebius#define REQUIRE(x) do { \ 1603216297Sglebius if (msglen < sizeof(x)) \ 1604216297Sglebius goto badlen; \ 1605216297Sglebius else \ 1606216297Sglebius msglen -= sizeof(x); \ 1607216297Sglebius } while (0) 1608216297Sglebius 16091558Srgrimes switch (rtm->rtm_type) { 16101558Srgrimes case RTM_IFINFO: 1611216297Sglebius REQUIRE(struct if_msghdr); 16121558Srgrimes ifm = (struct if_msghdr *)rtm; 1613128878Sandre (void) printf("if# %d, ", ifm->ifm_index); 1614128878Sandre switch (ifm->ifm_data.ifi_link_state) { 1615128878Sandre case LINK_STATE_DOWN: 1616128878Sandre state = "down"; 1617128878Sandre break; 1618128878Sandre case LINK_STATE_UP: 1619128878Sandre state = "up"; 1620128878Sandre break; 1621128878Sandre default: 1622128878Sandre state = "unknown"; 1623128878Sandre break; 1624128878Sandre } 1625128878Sandre (void) printf("link: %s, flags:", state); 16261558Srgrimes bprintf(stdout, ifm->ifm_flags, ifnetflags); 1627216297Sglebius pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs, msglen); 16281558Srgrimes break; 16291558Srgrimes case RTM_NEWADDR: 16301558Srgrimes case RTM_DELADDR: 1631216297Sglebius REQUIRE(struct ifa_msghdr); 16321558Srgrimes ifam = (struct ifa_msghdr *)rtm; 16331558Srgrimes (void) printf("metric %d, flags:", ifam->ifam_metric); 16341558Srgrimes bprintf(stdout, ifam->ifam_flags, routeflags); 1635216297Sglebius pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs, msglen); 16361558Srgrimes break; 163721465Swollman#ifdef RTM_NEWMADDR 163821465Swollman case RTM_NEWMADDR: 163921465Swollman case RTM_DELMADDR: 1640216297Sglebius REQUIRE(struct ifma_msghdr); 164121465Swollman ifmam = (struct ifma_msghdr *)rtm; 1642216297Sglebius pmsg_addrs((char *)(ifmam + 1), ifmam->ifmam_addrs, msglen); 164321465Swollman break; 164421465Swollman#endif 164589498Sru case RTM_IFANNOUNCE: 1646216297Sglebius REQUIRE(struct if_announcemsghdr); 164789498Sru ifan = (struct if_announcemsghdr *)rtm; 164889498Sru (void) printf("if# %d, what: ", ifan->ifan_index); 164989498Sru switch (ifan->ifan_what) { 165089498Sru case IFAN_ARRIVAL: 165189498Sru printf("arrival"); 165289498Sru break; 165389498Sru case IFAN_DEPARTURE: 165489498Sru printf("departure"); 165589498Sru break; 165689498Sru default: 165789498Sru printf("#%d", ifan->ifan_what); 165889498Sru break; 165989498Sru } 166089498Sru printf("\n"); 1661243860Sglebius fflush(stdout); 166289498Sru break; 166389498Sru 16641558Srgrimes default: 166513171Swollman (void) printf("pid: %ld, seq %d, errno %d, flags:", 166613171Swollman (long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno); 16671558Srgrimes bprintf(stdout, rtm->rtm_flags, routeflags); 1668216297Sglebius pmsg_common(rtm, msglen); 16691558Srgrimes } 1670216297Sglebius 1671216297Sglebius return; 1672216297Sglebius 1673216297Sglebiusbadlen: 1674216297Sglebius (void)printf(errfmt, __func__, msglen); 1675216297Sglebius#undef REQUIRE 16761558Srgrimes} 16771558Srgrimes 1678204406Suqsstatic void 1679243185Shrsprint_getmsg(struct rt_msghdr *rtm, int msglen, int fib) 16801558Srgrimes{ 16811558Srgrimes struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL; 16821558Srgrimes struct sockaddr_dl *ifp = NULL; 168392806Sobrien struct sockaddr *sa; 168492806Sobrien char *cp; 168592806Sobrien int i; 16861558Srgrimes 1687196527Scharnier (void) printf(" route to: %s\n", 1688196527Scharnier routename((struct sockaddr *)&so_dst)); 16891558Srgrimes if (rtm->rtm_version != RTM_VERSION) { 169013171Swollman warnx("routing message version %d not understood", 169113171Swollman rtm->rtm_version); 16921558Srgrimes return; 16931558Srgrimes } 16941558Srgrimes if (rtm->rtm_msglen > msglen) { 169537907Scharnier warnx("message length mismatch, in packet %d, returned %d", 169613171Swollman rtm->rtm_msglen, msglen); 16971558Srgrimes } 16981558Srgrimes if (rtm->rtm_errno) { 169913171Swollman errno = rtm->rtm_errno; 170013171Swollman warn("message indicates error %d", errno); 17011558Srgrimes return; 17021558Srgrimes } 17031558Srgrimes cp = ((char *)(rtm + 1)); 17041558Srgrimes if (rtm->rtm_addrs) 17051558Srgrimes for (i = 1; i; i <<= 1) 17061558Srgrimes if (i & rtm->rtm_addrs) { 17071558Srgrimes sa = (struct sockaddr *)cp; 17081558Srgrimes switch (i) { 17091558Srgrimes case RTA_DST: 17101558Srgrimes dst = sa; 17111558Srgrimes break; 17121558Srgrimes case RTA_GATEWAY: 17131558Srgrimes gate = sa; 17141558Srgrimes break; 17151558Srgrimes case RTA_NETMASK: 17161558Srgrimes mask = sa; 17171558Srgrimes break; 17181558Srgrimes case RTA_IFP: 17191558Srgrimes if (sa->sa_family == AF_LINK && 17201558Srgrimes ((struct sockaddr_dl *)sa)->sdl_nlen) 17211558Srgrimes ifp = (struct sockaddr_dl *)sa; 17221558Srgrimes break; 17231558Srgrimes } 1724128186Sluigi cp += SA_SIZE(sa); 17251558Srgrimes } 17261558Srgrimes if (dst && mask) 17271558Srgrimes mask->sa_family = dst->sa_family; /* XXX */ 17281558Srgrimes if (dst) 17291558Srgrimes (void)printf("destination: %s\n", routename(dst)); 17301558Srgrimes if (mask) { 17311558Srgrimes int savenflag = nflag; 17321558Srgrimes 17331558Srgrimes nflag = 1; 17341558Srgrimes (void)printf(" mask: %s\n", routename(mask)); 17351558Srgrimes nflag = savenflag; 17361558Srgrimes } 17371558Srgrimes if (gate && rtm->rtm_flags & RTF_GATEWAY) 17381558Srgrimes (void)printf(" gateway: %s\n", routename(gate)); 1739243185Shrs if (fib >= 0) 1740243185Shrs (void)printf(" fib: %u\n", (unsigned int)fib); 17411558Srgrimes if (ifp) 17421558Srgrimes (void)printf(" interface: %.*s\n", 17431558Srgrimes ifp->sdl_nlen, ifp->sdl_data); 17441558Srgrimes (void)printf(" flags: "); 17451558Srgrimes bprintf(stdout, rtm->rtm_flags, routeflags); 17461558Srgrimes 17471558Srgrimes#define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ') 17481558Srgrimes#define msec(u) (((u) + 500) / 1000) /* usec to msec */ 17491558Srgrimes 17501558Srgrimes (void) printf("\n%s\n", "\ 1751191080Skmacy recvpipe sendpipe ssthresh rtt,msec mtu weight expire"); 175213171Swollman printf("%8ld%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE)); 175313171Swollman printf("%8ld%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE)); 175413171Swollman printf("%8ld%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH)); 175513171Swollman printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT)); 175613171Swollman printf("%8ld%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU)); 1757191080Skmacy printf("%8ld%c ", rtm->rtm_rmx.rmx_weight, lock(WEIGHT)); 17581558Srgrimes if (rtm->rtm_rmx.rmx_expire) 17591558Srgrimes rtm->rtm_rmx.rmx_expire -= time(0); 176013171Swollman printf("%8ld%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE)); 17611558Srgrimes#undef lock 17621558Srgrimes#undef msec 17631558Srgrimes#define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD) 17641558Srgrimes if (verbose) 1765216297Sglebius pmsg_common(rtm, msglen); 17661558Srgrimes else if (rtm->rtm_addrs &~ RTA_IGN) { 17671558Srgrimes (void) printf("sockaddrs: "); 17681558Srgrimes bprintf(stdout, rtm->rtm_addrs, addrnames); 17691558Srgrimes putchar('\n'); 17701558Srgrimes } 17711558Srgrimes#undef RTA_IGN 17721558Srgrimes} 17731558Srgrimes 1774204406Suqsstatic void 1775216297Sglebiuspmsg_common(struct rt_msghdr *rtm, size_t msglen) 17761558Srgrimes{ 17771558Srgrimes (void) printf("\nlocks: "); 17781558Srgrimes bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames); 17791558Srgrimes (void) printf(" inits: "); 17801558Srgrimes bprintf(stdout, rtm->rtm_inits, metricnames); 1781216297Sglebius if (msglen > sizeof(struct rt_msghdr)) 1782216297Sglebius pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs, 1783216297Sglebius msglen - sizeof(struct rt_msghdr)); 1784216297Sglebius else 1785216297Sglebius (void) fflush(stdout); 17861558Srgrimes} 17871558Srgrimes 1788204406Suqsstatic void 1789216297Sglebiuspmsg_addrs(char *cp, int addrs, size_t len) 17901558Srgrimes{ 179192806Sobrien struct sockaddr *sa; 17921558Srgrimes int i; 17931558Srgrimes 179471061Sphk if (addrs == 0) { 179571061Sphk (void) putchar('\n'); 17961558Srgrimes return; 179771061Sphk } 17981558Srgrimes (void) printf("\nsockaddrs: "); 17991558Srgrimes bprintf(stdout, addrs, addrnames); 18001558Srgrimes (void) putchar('\n'); 1801204406Suqs for (i = 1; i != 0; i <<= 1) 18021558Srgrimes if (i & addrs) { 18031558Srgrimes sa = (struct sockaddr *)cp; 1804216297Sglebius if (len == 0 || len < SA_SIZE(sa)) { 1805216297Sglebius (void) printf(errfmt, __func__, len); 1806216297Sglebius break; 1807216297Sglebius } 18081558Srgrimes (void) printf(" %s", routename(sa)); 1809216297Sglebius len -= SA_SIZE(sa); 1810128186Sluigi cp += SA_SIZE(sa); 18111558Srgrimes } 18121558Srgrimes (void) putchar('\n'); 18131558Srgrimes (void) fflush(stdout); 18141558Srgrimes} 18151558Srgrimes 1816204406Suqsstatic void 1817204406Suqsbprintf(FILE *fp, int b, u_char *str) 18181558Srgrimes{ 181992806Sobrien int i; 18201558Srgrimes int gotsome = 0; 18211558Srgrimes 18221558Srgrimes if (b == 0) 18231558Srgrimes return; 1824204406Suqs while ((i = *str++) != 0) { 18251558Srgrimes if (b & (1 << (i-1))) { 18261558Srgrimes if (gotsome == 0) 18271558Srgrimes i = '<'; 18281558Srgrimes else 18291558Srgrimes i = ','; 18301558Srgrimes (void) putc(i, fp); 18311558Srgrimes gotsome = 1; 1832204406Suqs for (; (i = *str) > 32; str++) 18331558Srgrimes (void) putc(i, fp); 18341558Srgrimes } else 1835204406Suqs while (*str > 32) 1836204406Suqs str++; 18371558Srgrimes } 18381558Srgrimes if (gotsome) 18391558Srgrimes (void) putc('>', fp); 18401558Srgrimes} 18411558Srgrimes 18421558Srgrimesint 1843204406Suqskeyword(const char *cp) 18441558Srgrimes{ 184592806Sobrien struct keytab *kt = keywords; 18461558Srgrimes 1847204406Suqs while (kt->kt_cp != NULL && strcmp(kt->kt_cp, cp) != 0) 18481558Srgrimes kt++; 1849204406Suqs return (kt->kt_i); 18501558Srgrimes} 18511558Srgrimes 1852204406Suqsstatic void 1853204406Suqssodump(sup su, const char *which) 18541558Srgrimes{ 18551558Srgrimes switch (su->sa.sa_family) { 18561558Srgrimes case AF_LINK: 18571558Srgrimes (void) printf("%s: link %s; ", 18581558Srgrimes which, link_ntoa(&su->sdl)); 18591558Srgrimes break; 18601558Srgrimes case AF_INET: 18611558Srgrimes (void) printf("%s: inet %s; ", 18621558Srgrimes which, inet_ntoa(su->sin.sin_addr)); 18631558Srgrimes break; 186417046Sjulian case AF_APPLETALK: 186517046Sjulian (void) printf("%s: atalk %s; ", 186617046Sjulian which, atalk_ntoa(su->sat.sat_addr)); 186717046Sjulian break; 18681558Srgrimes } 18691558Srgrimes (void) fflush(stdout); 18701558Srgrimes} 18711558Srgrimes 18721558Srgrimes/* States*/ 18731558Srgrimes#define VIRGIN 0 18741558Srgrimes#define GOTONE 1 18751558Srgrimes#define GOTTWO 2 18761558Srgrimes/* Inputs */ 18771558Srgrimes#define DIGIT (4*0) 18781558Srgrimes#define END (4*1) 18791558Srgrimes#define DELIM (4*2) 18801558Srgrimes 1881204406Suqsstatic void 1882196527Scharniersockaddr(char *addr, struct sockaddr *sa) 18831558Srgrimes{ 188492806Sobrien char *cp = (char *)sa; 18851558Srgrimes int size = sa->sa_len; 18861558Srgrimes char *cplim = cp + size; 188792806Sobrien int byte = 0, state = VIRGIN, new = 0 /* foil gcc */; 18881558Srgrimes 188985048Sru memset(cp, 0, size); 18901558Srgrimes cp++; 18911558Srgrimes do { 18921558Srgrimes if ((*addr >= '0') && (*addr <= '9')) { 18931558Srgrimes new = *addr - '0'; 18941558Srgrimes } else if ((*addr >= 'a') && (*addr <= 'f')) { 18951558Srgrimes new = *addr - 'a' + 10; 18961558Srgrimes } else if ((*addr >= 'A') && (*addr <= 'F')) { 18971558Srgrimes new = *addr - 'A' + 10; 1898204406Suqs } else if (*addr == '\0') 18991558Srgrimes state |= END; 19001558Srgrimes else 19011558Srgrimes state |= DELIM; 19021558Srgrimes addr++; 19031558Srgrimes switch (state /* | INPUT */) { 19041558Srgrimes case GOTTWO | DIGIT: 19051558Srgrimes *cp++ = byte; /*FALLTHROUGH*/ 19061558Srgrimes case VIRGIN | DIGIT: 19071558Srgrimes state = GOTONE; byte = new; continue; 19081558Srgrimes case GOTONE | DIGIT: 19091558Srgrimes state = GOTTWO; byte = new + (byte << 4); continue; 19101558Srgrimes default: /* | DELIM */ 19111558Srgrimes state = VIRGIN; *cp++ = byte; byte = 0; continue; 19121558Srgrimes case GOTONE | END: 19131558Srgrimes case GOTTWO | END: 19141558Srgrimes *cp++ = byte; /* FALLTHROUGH */ 19151558Srgrimes case VIRGIN | END: 19161558Srgrimes break; 19171558Srgrimes } 19181558Srgrimes break; 19191558Srgrimes } while (cp < cplim); 19201558Srgrimes sa->sa_len = cp - (char *)sa; 19211558Srgrimes} 192217046Sjulian 1923204406Suqsstatic int 192417046Sjulianatalk_aton(const char *text, struct at_addr *addr) 192517046Sjulian{ 192617046Sjulian u_int net, node; 192717046Sjulian 192817046Sjulian if (sscanf(text, "%u.%u", &net, &node) != 2 192917046Sjulian || net > 0xffff || node > 0xff) 193017046Sjulian return(0); 193117254Sjulian addr->s_net = htons(net); 193217046Sjulian addr->s_node = node; 193317046Sjulian return(1); 193417046Sjulian} 193517046Sjulian 1936204406Suqsstatic char * 193717046Sjulianatalk_ntoa(struct at_addr at) 193817046Sjulian{ 193917046Sjulian static char buf[20]; 194017046Sjulian 194117254Sjulian (void) snprintf(buf, sizeof(buf), "%u.%u", ntohs(at.s_net), at.s_node); 194217046Sjulian return(buf); 194317046Sjulian} 1944