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$"); 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 73253427Shrsstatic struct keytab { 74204406Suqs const char *kt_cp; 751558Srgrimes int kt_i; 761558Srgrimes} keywords[] = { 771558Srgrimes#include "keywords.h" 781558Srgrimes {0, 0} 791558Srgrimes}; 801558Srgrimes 81253427Shrsstatic struct sockaddr_storage so[RTAX_MAX]; 82253427Shrsstatic int pid, rtm_addrs; 83253427Shrsstatic int s; 84253427Shrsstatic int forcehost, forcenet, nflag, af, qflag, tflag; 85253427Shrsstatic int verbose, aflen; 86253427Shrsstatic int locking, lockrest, debugonly; 87253427Shrsstatic struct rt_metrics rt_metrics; 88253427Shrsstatic u_long rtm_inits; 89253427Shrsstatic uid_t uid; 90243185Shrsstatic int defaultfib; 91243185Shrsstatic int numfibs; 92196527Scharnier 93204406Suqsstatic int atalk_aton(const char *, struct at_addr *); 94204406Suqsstatic char *atalk_ntoa(struct at_addr); 95253427Shrsstatic void printb(int, const char *); 96204406Suqsstatic void flushroutes(int argc, char *argv[]); 97243185Shrsstatic int flushroutes_fib(int); 98245168Shrsstatic int getaddr(int, char *, struct hostent **, int); 99204406Suqsstatic int keyword(const char *); 100253427Shrs#ifdef INET 101253427Shrsstatic void inet_makenetandmask(u_long, struct sockaddr_in *, 102253427Shrs struct sockaddr_in *, u_long); 103253427Shrs#endif 10497062Sume#ifdef INET6 105253427Shrsstatic int inet6_makenetandmask(struct sockaddr_in6 *, const char *); 10697062Sume#endif 107204406Suqsstatic void interfaces(void); 108243185Shrsstatic void monitor(int, char*[]); 109204406Suqsstatic const char *netname(struct sockaddr *); 110204406Suqsstatic void newroute(int, char **); 111243185Shrsstatic int newroute_fib(int, char *, int); 112216297Sglebiusstatic void pmsg_addrs(char *, int, size_t); 113216297Sglebiusstatic void pmsg_common(struct rt_msghdr *, size_t); 114204406Suqsstatic int prefixlen(const char *); 115243185Shrsstatic void print_getmsg(struct rt_msghdr *, int, int); 116216297Sglebiusstatic void print_rtmsg(struct rt_msghdr *, size_t); 117204406Suqsstatic const char *routename(struct sockaddr *); 118243185Shrsstatic int rtmsg(int, int, int); 119204406Suqsstatic void set_metric(char *, int); 120243185Shrsstatic int set_sofib(int); 121253427Shrsstatic void sockaddr(char *, struct sockaddr *, size_t); 122253427Shrsstatic void sodump(struct sockaddr *, const char *); 1231558Srgrimes 124243185Shrsstruct fibl { 125243185Shrs TAILQ_ENTRY(fibl) fl_next; 126243185Shrs 127243185Shrs int fl_num; 128243185Shrs int fl_error; 129243185Shrs int fl_errno; 130243185Shrs}; 131253427Shrsstatic TAILQ_HEAD(fibl_head_t, fibl) fibl_head; 132243185Shrs 133243185Shrsstatic int fiboptlist_csv(const char *, struct fibl_head_t *); 134243185Shrsstatic int fiboptlist_range(const char *, struct fibl_head_t *); 135243185Shrs 136204406Suqsstatic void usage(const char *) __dead2; 13713171Swollman 138253519Shrsstatic void 139196527Scharnierusage(const char *cp) 1401558Srgrimes{ 141204406Suqs if (cp != NULL) 14213171Swollman warnx("bad keyword: %s", cp); 143253427Shrs errx(EX_USAGE, "usage: route [-dnqtv] command [[modifiers] args]"); 1441558Srgrimes /* NOTREACHED */ 1451558Srgrimes} 1461558Srgrimes 1471558Srgrimesint 148196527Scharniermain(int argc, char **argv) 1491558Srgrimes{ 1501558Srgrimes int ch; 151243185Shrs size_t len; 1521558Srgrimes 1531558Srgrimes if (argc < 2) 154204406Suqs usage(NULL); 1551558Srgrimes 15637907Scharnier while ((ch = getopt(argc, argv, "nqdtv")) != -1) 1571558Srgrimes switch(ch) { 1581558Srgrimes case 'n': 1591558Srgrimes nflag = 1; 1601558Srgrimes break; 1611558Srgrimes case 'q': 1621558Srgrimes qflag = 1; 1631558Srgrimes break; 1641558Srgrimes case 'v': 1651558Srgrimes verbose = 1; 1661558Srgrimes break; 1671558Srgrimes case 't': 1681558Srgrimes tflag = 1; 1691558Srgrimes break; 1701558Srgrimes case 'd': 1711558Srgrimes debugonly = 1; 1721558Srgrimes break; 1731558Srgrimes case '?': 1741558Srgrimes default: 175204406Suqs usage(NULL); 1761558Srgrimes } 1771558Srgrimes argc -= optind; 1781558Srgrimes argv += optind; 1791558Srgrimes 1801558Srgrimes pid = getpid(); 181109811Skbyanc uid = geteuid(); 1821558Srgrimes if (tflag) 18369793Sobrien s = open(_PATH_DEVNULL, O_WRONLY, 0); 1841558Srgrimes else 1851558Srgrimes s = socket(PF_ROUTE, SOCK_RAW, 0); 1861558Srgrimes if (s < 0) 18713171Swollman err(EX_OSERR, "socket"); 188243185Shrs 189243185Shrs len = sizeof(numfibs); 190243185Shrs if (sysctlbyname("net.fibs", (void *)&numfibs, &len, NULL, 0) == -1) 191243185Shrs numfibs = -1; 192243185Shrs 193243185Shrs len = sizeof(defaultfib); 194243185Shrs if (numfibs != -1 && 195243185Shrs sysctlbyname("net.my_fibnum", (void *)&defaultfib, &len, NULL, 196243185Shrs 0) == -1) 197243185Shrs defaultfib = -1; 198243185Shrs 199204406Suqs if (*argv != NULL) 2001558Srgrimes switch (keyword(*argv)) { 2011558Srgrimes case K_GET: 202191080Skmacy case K_SHOW: 2031558Srgrimes uid = 0; 2041558Srgrimes /* FALLTHROUGH */ 2051558Srgrimes 2061558Srgrimes case K_CHANGE: 2071558Srgrimes case K_ADD: 208150679Stobez case K_DEL: 2091558Srgrimes case K_DELETE: 2101558Srgrimes newroute(argc, argv); 2111558Srgrimes /* NOTREACHED */ 2121558Srgrimes 2131558Srgrimes case K_MONITOR: 214243185Shrs monitor(argc, argv); 2151558Srgrimes /* NOTREACHED */ 2161558Srgrimes 2171558Srgrimes case K_FLUSH: 2181558Srgrimes flushroutes(argc, argv); 2191558Srgrimes exit(0); 2201558Srgrimes /* NOTREACHED */ 2211558Srgrimes } 2221558Srgrimes usage(*argv); 2231558Srgrimes /* NOTREACHED */ 2241558Srgrimes} 2251558Srgrimes 226243185Shrsstatic int 227243185Shrsset_sofib(int fib) 228243185Shrs{ 229243185Shrs 230243185Shrs if (fib < 0) 231243185Shrs return (0); 232243185Shrs return (setsockopt(s, SOL_SOCKET, SO_SETFIB, (void *)&fib, 233243185Shrs sizeof(fib))); 234243185Shrs} 235243185Shrs 236243185Shrsstatic int 237243185Shrsfiboptlist_range(const char *arg, struct fibl_head_t *flh) 238243185Shrs{ 239243185Shrs struct fibl *fl; 240244325Shrs char *str0, *str, *token, *endptr; 241243185Shrs int fib[2], i, error; 242243185Shrs 243244325Shrs str0 = str = strdup(arg); 244243185Shrs error = 0; 245243185Shrs i = 0; 246243185Shrs while ((token = strsep(&str, "-")) != NULL) { 247243185Shrs switch (i) { 248243185Shrs case 0: 249243185Shrs case 1: 250244325Shrs errno = 0; 251243185Shrs fib[i] = strtol(token, &endptr, 0); 252244325Shrs if (errno == 0) { 253244325Shrs if (*endptr != '\0' || 254244325Shrs fib[i] < 0 || 255244325Shrs (numfibs != -1 && fib[i] > numfibs - 1)) 256244325Shrs errno = EINVAL; 257244325Shrs } 258244325Shrs if (errno) 259243185Shrs error = 1; 260243185Shrs break; 261243185Shrs default: 262243185Shrs error = 1; 263243185Shrs } 264243185Shrs if (error) 265243185Shrs goto fiboptlist_range_ret; 266243185Shrs i++; 267243185Shrs } 268243185Shrs if (fib[0] >= fib[1]) { 269243185Shrs error = 1; 270243185Shrs goto fiboptlist_range_ret; 271243185Shrs } 272243185Shrs for (i = fib[0]; i <= fib[1]; i++) { 273243185Shrs fl = calloc(1, sizeof(*fl)); 274243185Shrs if (fl == NULL) { 275243185Shrs error = 1; 276243185Shrs goto fiboptlist_range_ret; 277243185Shrs } 278243185Shrs fl->fl_num = i; 279243185Shrs TAILQ_INSERT_TAIL(flh, fl, fl_next); 280243185Shrs } 281243185Shrsfiboptlist_range_ret: 282244325Shrs free(str0); 283243185Shrs return (error); 284243185Shrs} 285243185Shrs 286243185Shrs#define ALLSTRLEN 64 287243185Shrsstatic int 288243185Shrsfiboptlist_csv(const char *arg, struct fibl_head_t *flh) 289243185Shrs{ 290243185Shrs struct fibl *fl; 291244325Shrs char *str0, *str, *token, *endptr; 292243185Shrs int fib, error; 293243185Shrs 294253427Shrs str0 = str = NULL; 295243185Shrs if (strcmp("all", arg) == 0) { 296243185Shrs str = calloc(1, ALLSTRLEN); 297243185Shrs if (str == NULL) { 298243185Shrs error = 1; 299243185Shrs goto fiboptlist_csv_ret; 300243185Shrs } 301243185Shrs if (numfibs > 1) 302243185Shrs snprintf(str, ALLSTRLEN - 1, "%d-%d", 0, numfibs - 1); 303243185Shrs else 304243185Shrs snprintf(str, ALLSTRLEN - 1, "%d", 0); 305243185Shrs } else if (strcmp("default", arg) == 0) { 306244325Shrs str0 = str = calloc(1, ALLSTRLEN); 307243185Shrs if (str == NULL) { 308243185Shrs error = 1; 309243185Shrs goto fiboptlist_csv_ret; 310243185Shrs } 311243185Shrs snprintf(str, ALLSTRLEN - 1, "%d", defaultfib); 312243185Shrs } else 313244325Shrs str0 = str = strdup(arg); 314243185Shrs 315243185Shrs error = 0; 316243185Shrs while ((token = strsep(&str, ",")) != NULL) { 317243185Shrs if (*token != '-' && strchr(token, '-') != NULL) { 318243185Shrs error = fiboptlist_range(token, flh); 319243185Shrs if (error) 320243185Shrs goto fiboptlist_csv_ret; 321243185Shrs } else { 322244325Shrs errno = 0; 323243185Shrs fib = strtol(token, &endptr, 0); 324244325Shrs if (errno == 0) { 325244325Shrs if (*endptr != '\0' || 326244325Shrs fib < 0 || 327244325Shrs (numfibs != -1 && fib > numfibs - 1)) 328244325Shrs errno = EINVAL; 329244325Shrs } 330244325Shrs if (errno) { 331243185Shrs error = 1; 332243185Shrs goto fiboptlist_csv_ret; 333243185Shrs } 334243185Shrs fl = calloc(1, sizeof(*fl)); 335243185Shrs if (fl == NULL) { 336243185Shrs error = 1; 337243185Shrs goto fiboptlist_csv_ret; 338243185Shrs } 339243185Shrs fl->fl_num = fib; 340243185Shrs TAILQ_INSERT_TAIL(flh, fl, fl_next); 341243185Shrs } 342243185Shrs } 343243185Shrsfiboptlist_csv_ret: 344253427Shrs if (str0 != NULL) 345253427Shrs free(str0); 346243185Shrs return (error); 347243185Shrs} 348243185Shrs 3491558Srgrimes/* 3501558Srgrimes * Purge all entries in the routing tables not 3511558Srgrimes * associated with network interfaces. 3521558Srgrimes */ 353204406Suqsstatic void 354196527Scharnierflushroutes(int argc, char *argv[]) 3551558Srgrimes{ 356243185Shrs struct fibl *fl; 357243185Shrs int error; 3581558Srgrimes 359253427Shrs if (uid != 0 && !debugonly && !tflag) 36013171Swollman errx(EX_NOPERM, "must be root to alter routing table"); 361146079Sjmallett shutdown(s, SHUT_RD); /* Don't want to read back our messages */ 362243185Shrs 363243185Shrs TAILQ_INIT(&fibl_head); 364243185Shrs while (argc > 1) { 365243185Shrs argc--; 3661558Srgrimes argv++; 367243185Shrs if (**argv != '-') 368243185Shrs usage(*argv); 369243185Shrs switch (keyword(*argv + 1)) { 370253427Shrs#ifdef INET 371243185Shrs case K_INET: 372243185Shrs af = AF_INET; 373243185Shrs break; 374253427Shrs#endif 37554263Sshin#ifdef INET6 376243185Shrs case K_INET6: 377243185Shrs af = AF_INET6; 378243185Shrs break; 37954263Sshin#endif 380243185Shrs case K_ATALK: 381243185Shrs af = AF_APPLETALK; 382243185Shrs break; 383243185Shrs case K_LINK: 384243185Shrs af = AF_LINK; 385243185Shrs break; 386243185Shrs case K_FIB: 387243185Shrs if (!--argc) 388243185Shrs usage(*argv); 389243185Shrs error = fiboptlist_csv(*++argv, &fibl_head); 390243185Shrs if (error) 391244325Shrs errx(EX_USAGE, "invalid fib number: %s", *argv); 392243185Shrs break; 393243185Shrs default: 394243185Shrs usage(*argv); 395243185Shrs } 3961558Srgrimes } 397243185Shrs if (TAILQ_EMPTY(&fibl_head)) { 398243185Shrs error = fiboptlist_csv("default", &fibl_head); 399243185Shrs if (error) 400243185Shrs errx(EX_OSERR, "fiboptlist_csv failed."); 401243185Shrs } 402243185Shrs TAILQ_FOREACH(fl, &fibl_head, fl_next) 403243185Shrs flushroutes_fib(fl->fl_num); 404243185Shrs} 405243185Shrs 406243185Shrsstatic int 407243185Shrsflushroutes_fib(int fib) 408243185Shrs{ 409243185Shrs struct rt_msghdr *rtm; 410243185Shrs size_t needed; 411243185Shrs char *buf, *next, *lim; 412253429Shrs int mib[7], rlen, seqno, count = 0; 413243185Shrs int error; 414243185Shrs 415243185Shrs error = set_sofib(fib); 416243185Shrs if (error) { 417243185Shrs warn("fib number %d is ignored", fib); 418243185Shrs return (error); 419243185Shrs } 420243185Shrs 421128782Sambriskoretry: 4221558Srgrimes mib[0] = CTL_NET; 4231558Srgrimes mib[1] = PF_ROUTE; 4241558Srgrimes mib[2] = 0; /* protocol */ 425253427Shrs mib[3] = AF_UNSPEC; 4261558Srgrimes mib[4] = NET_RT_DUMP; 4271558Srgrimes mib[5] = 0; /* no flags */ 428253429Shrs mib[6] = fib; 429253427Shrs if (sysctl(mib, nitems(mib), NULL, &needed, NULL, 0) < 0) 43013171Swollman err(EX_OSERR, "route-sysctl-estimate"); 4311558Srgrimes if ((buf = malloc(needed)) == NULL) 43237907Scharnier errx(EX_OSERR, "malloc failed"); 433253427Shrs if (sysctl(mib, nitems(mib), buf, &needed, NULL, 0) < 0) { 434128782Sambrisko if (errno == ENOMEM && count++ < 10) { 435204406Suqs warnx("Routing table grew, retrying"); 436128782Sambrisko sleep(1); 437128782Sambrisko free(buf); 438128782Sambrisko goto retry; 439128782Sambrisko } 44013171Swollman err(EX_OSERR, "route-sysctl-get"); 441128782Sambrisko } 4421558Srgrimes lim = buf + needed; 4431558Srgrimes if (verbose) 444253427Shrs (void)printf("Examining routing table from sysctl\n"); 4451558Srgrimes seqno = 0; /* ??? */ 4461558Srgrimes for (next = buf; next < lim; next += rtm->rtm_msglen) { 447253502Shrs rtm = (struct rt_msghdr *)(void *)next; 4481558Srgrimes if (verbose) 4491558Srgrimes print_rtmsg(rtm, rtm->rtm_msglen); 4501558Srgrimes if ((rtm->rtm_flags & RTF_GATEWAY) == 0) 4511558Srgrimes continue; 452204406Suqs if (af != 0) { 4531558Srgrimes struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 4541558Srgrimes 4551558Srgrimes if (sa->sa_family != af) 4561558Srgrimes continue; 4571558Srgrimes } 4581558Srgrimes if (debugonly) 4591558Srgrimes continue; 4601558Srgrimes rtm->rtm_type = RTM_DELETE; 4611558Srgrimes rtm->rtm_seq = seqno; 4621558Srgrimes rlen = write(s, next, rtm->rtm_msglen); 463129034Scsjp if (rlen < 0 && errno == EPERM) 464129034Scsjp err(1, "write to routing socket"); 4651558Srgrimes if (rlen < (int)rtm->rtm_msglen) { 46613171Swollman warn("write to routing socket"); 467253427Shrs (void)printf("got only %d for rlen\n", rlen); 468128782Sambrisko free(buf); 469128782Sambrisko goto retry; 4701558Srgrimes break; 4711558Srgrimes } 4721558Srgrimes seqno++; 4731558Srgrimes if (qflag) 4741558Srgrimes continue; 4751558Srgrimes if (verbose) 4761558Srgrimes print_rtmsg(rtm, rlen); 4771558Srgrimes else { 4781558Srgrimes struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 479243185Shrs 480243185Shrs printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ? 4811558Srgrimes routename(sa) : netname(sa)); 482128186Sluigi sa = (struct sockaddr *)(SA_SIZE(sa) + (char *)sa); 483243185Shrs printf("%-20.20s ", routename(sa)); 484243185Shrs if (fib >= 0) 485243185Shrs printf("-fib %-3d ", fib); 486243185Shrs printf("done\n"); 4871558Srgrimes } 4881558Srgrimes } 489243185Shrs return (error); 4901558Srgrimes} 4911558Srgrimes 492253519Shrsstatic const char * 493196527Scharnierroutename(struct sockaddr *sa) 4941558Srgrimes{ 495253517Shrs struct sockaddr_dl *sdl; 496204406Suqs const char *cp; 497253519Shrs static char line[NI_MAXHOST]; 4981558Srgrimes static char domain[MAXHOSTNAMELEN + 1]; 49981976Sbrian static int first = 1, n; 5001558Srgrimes 5011558Srgrimes if (first) { 5021558Srgrimes first = 0; 5031558Srgrimes if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 50485048Sru (cp = strchr(domain, '.'))) { 50519209Sfenner domain[MAXHOSTNAMELEN] = '\0'; 506253427Shrs (void)strcpy(domain, cp + 1); 50719209Sfenner } else 508253427Shrs domain[0] = '\0'; 5091558Srgrimes } 5101558Srgrimes 511253519Shrs /* If the address is zero-filled, use "default". */ 512253503Shrs if (sa->sa_len == 0 && nflag == 0) 513253503Shrs return ("default"); 514253519Shrs#if defined(INET) || defined(INET6) 515253427Shrs switch (sa->sa_family) { 516253427Shrs#ifdef INET 517253427Shrs case AF_INET: 518253519Shrs /* If the address is zero-filled, use "default". */ 519253519Shrs if (nflag == 0 && 520253519Shrs ((struct sockaddr_in *)(void *)sa)->sin_addr.s_addr == 521253519Shrs INADDR_ANY) 522253519Shrs return("default"); 5231558Srgrimes break; 524253519Shrs#endif 525253519Shrs#ifdef INET6 526253519Shrs case AF_INET6: 527253519Shrs /* If the address is zero-filled, use "default". */ 528253519Shrs if (nflag == 0 && 529253519Shrs IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(void *)sa)->sin6_addr)) 530253519Shrs return("default"); 531253519Shrs break; 532253519Shrs#endif 533253427Shrs } 534253519Shrs#endif 5351558Srgrimes 536253519Shrs switch (sa->sa_family) { 537253519Shrs#if defined(INET) || defined(INET6) 538253519Shrs#ifdef INET 539253519Shrs case AF_INET: 540253427Shrs#endif 54154263Sshin#ifdef INET6 54254263Sshin case AF_INET6: 543253519Shrs#endif 54478064Sume { 545253519Shrs struct sockaddr_storage ss; 546253519Shrs int error; 547253519Shrs char *p; 54854263Sshin 549253519Shrs memset(&ss, 0, sizeof(ss)); 550253519Shrs if (sa->sa_len == 0) 551253519Shrs ss.ss_family = sa->sa_family; 552253519Shrs else 553253519Shrs memcpy(&ss, sa, sa->sa_len); 554253519Shrs /* Expand sa->sa_len because it could be shortened. */ 555253519Shrs if (sa->sa_family == AF_INET) 556253519Shrs ss.ss_len = sizeof(struct sockaddr_in); 557253519Shrs else if (sa->sa_family == AF_INET6) 558253519Shrs ss.ss_len = sizeof(struct sockaddr_in6); 559253519Shrs error = getnameinfo((struct sockaddr *)&ss, ss.ss_len, 560253519Shrs line, sizeof(line), NULL, 0, 561253519Shrs (nflag == 0) ? 0 : NI_NUMERICHOST); 562253519Shrs if (error) { 563253519Shrs warnx("getnameinfo(): %s", gai_strerror(error)); 56478064Sume strncpy(line, "invalid", sizeof(line)); 565253519Shrs } 56678064Sume 567253519Shrs /* Remove the domain part if any. */ 568253519Shrs p = strchr(line, '.'); 569253519Shrs if (p != NULL && strcmp(p + 1, domain) == 0) 570253519Shrs *p = '\0'; 571253519Shrs 572253427Shrs return (line); 573253519Shrs break; 57478064Sume } 57578064Sume#endif 57617046Sjulian case AF_APPLETALK: 577253427Shrs (void)snprintf(line, sizeof(line), "atalk %s", 578253502Shrs atalk_ntoa(((struct sockaddr_at *)(void *)sa)->sat_addr)); 57917046Sjulian break; 58017046Sjulian 5811558Srgrimes case AF_LINK: 582253517Shrs sdl = (struct sockaddr_dl *)(void *)sa; 583253517Shrs 584253517Shrs if (sdl->sdl_nlen == 0 && 585253517Shrs sdl->sdl_alen == 0 && 586253517Shrs sdl->sdl_slen == 0) { 587253517Shrs n = snprintf(line, sizeof(line), "link#%d", 588253517Shrs sdl->sdl_index); 589253517Shrs if (n > (int)sizeof(line)) 590253517Shrs line[0] = '\0'; 591253517Shrs return (line); 592253517Shrs } else 593253517Shrs return (link_ntoa(sdl)); 594253427Shrs break; 5951558Srgrimes 5961558Srgrimes default: 597204406Suqs { 598253502Shrs u_short *sp = (u_short *)(void *)sa; 599204406Suqs u_short *splim = sp + ((sa->sa_len + 1) >> 1); 600204406Suqs char *cps = line + sprintf(line, "(%d)", sa->sa_family); 60119209Sfenner char *cpe = line + sizeof(line); 6021558Srgrimes 603204406Suqs while (++sp < splim && cps < cpe) /* start with sa->sa_data */ 604204406Suqs if ((n = snprintf(cps, cpe - cps, " %x", *sp)) > 0) 605204406Suqs cps += n; 60681980Sbrian else 607204406Suqs *cps = '\0'; 6081558Srgrimes break; 6091558Srgrimes } 6101558Srgrimes } 6111558Srgrimes return (line); 6121558Srgrimes} 6131558Srgrimes 6141558Srgrimes/* 6151558Srgrimes * Return the name of the network whose address is given. 616243019Sglebius * The address is assumed to be that of a net, not a host. 6171558Srgrimes */ 618253519Shrsstatic const char * 619196527Scharniernetname(struct sockaddr *sa) 6201558Srgrimes{ 621253517Shrs struct sockaddr_dl *sdl; 62219209Sfenner static char line[MAXHOSTNAMELEN + 1]; 623253427Shrs int n; 624253427Shrs#ifdef INET 625204406Suqs struct netent *np = NULL; 626253427Shrs const char *cp = NULL; 62792806Sobrien u_long i; 628253427Shrs#endif 6291558Srgrimes 6301558Srgrimes switch (sa->sa_family) { 631253427Shrs#ifdef INET 632253427Shrs case AF_INET: 633253427Shrs { 634253427Shrs struct in_addr in; 6351558Srgrimes 636253502Shrs in = ((struct sockaddr_in *)(void *)sa)->sin_addr; 6371558Srgrimes i = in.s_addr = ntohl(in.s_addr); 6381558Srgrimes if (in.s_addr == 0) 6391558Srgrimes cp = "default"; 6401558Srgrimes else if (!nflag) { 641243019Sglebius np = getnetbyaddr(i, AF_INET); 642204406Suqs if (np != NULL) 6431558Srgrimes cp = np->n_name; 6441558Srgrimes } 64577873Sru#define C(x) (unsigned)((x) & 0xff) 646204406Suqs if (cp != NULL) 64719209Sfenner strncpy(line, cp, sizeof(line)); 6481558Srgrimes else if ((in.s_addr & 0xffffff) == 0) 649253427Shrs (void)sprintf(line, "%u", C(in.s_addr >> 24)); 6501558Srgrimes else if ((in.s_addr & 0xffff) == 0) 651253427Shrs (void)sprintf(line, "%u.%u", C(in.s_addr >> 24), 6521558Srgrimes C(in.s_addr >> 16)); 6531558Srgrimes else if ((in.s_addr & 0xff) == 0) 654253427Shrs (void)sprintf(line, "%u.%u.%u", C(in.s_addr >> 24), 6551558Srgrimes C(in.s_addr >> 16), C(in.s_addr >> 8)); 6561558Srgrimes else 657253427Shrs (void)sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), 6581558Srgrimes C(in.s_addr >> 16), C(in.s_addr >> 8), 6591558Srgrimes C(in.s_addr)); 66077873Sru#undef C 6611558Srgrimes break; 662253427Shrs } 663253427Shrs#endif 66454263Sshin#ifdef INET6 66554263Sshin case AF_INET6: 66678064Sume { 667253427Shrs struct sockaddr_in6 sin6; 66878064Sume int niflags = 0; 66954263Sshin 67078064Sume memset(&sin6, 0, sizeof(sin6)); 67178064Sume memcpy(&sin6, sa, sa->sa_len); 672253427Shrs sin6.sin6_len = sizeof(sin6); 67378064Sume sin6.sin6_family = AF_INET6; 67478064Sume if (nflag) 67578064Sume niflags |= NI_NUMERICHOST; 67678064Sume if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, 67778064Sume line, sizeof(line), NULL, 0, niflags) != 0) 67878064Sume strncpy(line, "invalid", sizeof(line)); 67978064Sume 68078064Sume return(line); 68178064Sume } 68278064Sume#endif 68378064Sume 68417046Sjulian case AF_APPLETALK: 685253427Shrs (void)snprintf(line, sizeof(line), "atalk %s", 686253502Shrs atalk_ntoa(((struct sockaddr_at *)(void *)sa)->sat_addr)); 68717046Sjulian break; 68817046Sjulian 6891558Srgrimes case AF_LINK: 690253517Shrs sdl = (struct sockaddr_dl *)(void *)sa; 691253517Shrs 692253517Shrs if (sdl->sdl_nlen == 0 && 693253517Shrs sdl->sdl_alen == 0 && 694253517Shrs sdl->sdl_slen == 0) { 695253517Shrs n = snprintf(line, sizeof(line), "link#%d", 696253517Shrs sdl->sdl_index); 697253517Shrs if (n > (int)sizeof(line)) 698253517Shrs line[0] = '\0'; 699253517Shrs return (line); 700253517Shrs } else 701253517Shrs return (link_ntoa(sdl)); 702253427Shrs break; 7031558Srgrimes 7041558Srgrimes default: 705204406Suqs { 706253502Shrs u_short *sp = (u_short *)(void *)sa->sa_data; 707204406Suqs u_short *splim = sp + ((sa->sa_len + 1)>>1); 708204406Suqs char *cps = line + sprintf(line, "af %d:", sa->sa_family); 70919209Sfenner char *cpe = line + sizeof(line); 7101558Srgrimes 711204406Suqs while (sp < splim && cps < cpe) 712204406Suqs if ((n = snprintf(cps, cpe - cps, " %x", *sp++)) > 0) 713204406Suqs cps += n; 71481980Sbrian else 715204406Suqs *cps = '\0'; 7161558Srgrimes break; 7171558Srgrimes } 7181558Srgrimes } 7191558Srgrimes return (line); 7201558Srgrimes} 7211558Srgrimes 722204406Suqsstatic void 723196527Scharnierset_metric(char *value, int key) 7241558Srgrimes{ 7251558Srgrimes int flag = 0; 7261558Srgrimes u_long noval, *valp = &noval; 7271558Srgrimes 7281558Srgrimes switch (key) { 7291558Srgrimes#define caseof(x, y, z) case x: valp = &rt_metrics.z; flag = y; break 7301558Srgrimes caseof(K_MTU, RTV_MTU, rmx_mtu); 7311558Srgrimes caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount); 7321558Srgrimes caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire); 7331558Srgrimes caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe); 7341558Srgrimes caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe); 7351558Srgrimes caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh); 7361558Srgrimes caseof(K_RTT, RTV_RTT, rmx_rtt); 7371558Srgrimes caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar); 738191080Skmacy caseof(K_WEIGHT, RTV_WEIGHT, rmx_weight); 7391558Srgrimes } 7401558Srgrimes rtm_inits |= flag; 7411558Srgrimes if (lockrest || locking) 7421558Srgrimes rt_metrics.rmx_locks |= flag; 7431558Srgrimes if (locking) 7441558Srgrimes locking = 0; 7451558Srgrimes *valp = atoi(value); 7461558Srgrimes} 7471558Srgrimes 748243185Shrs#define F_ISHOST 0x01 749243185Shrs#define F_FORCENET 0x02 750243185Shrs#define F_FORCEHOST 0x04 751243185Shrs#define F_PROXY 0x08 752243185Shrs#define F_INTERFACE 0x10 753243185Shrs 754204406Suqsstatic void 755196527Scharniernewroute(int argc, char **argv) 7561558Srgrimes{ 757243185Shrs struct hostent *hp; 758243185Shrs struct fibl *fl; 759204406Suqs char *cmd; 760243185Shrs const char *dest, *gateway, *errmsg; 761243185Shrs int key, error, flags, nrflags, fibnum; 7621558Srgrimes 763253427Shrs if (uid != 0 && !debugonly && !tflag) 76413171Swollman errx(EX_NOPERM, "must be root to alter routing table"); 765243185Shrs dest = NULL; 766243185Shrs gateway = NULL; 767243185Shrs flags = RTF_STATIC; 768243185Shrs nrflags = 0; 769243185Shrs hp = NULL; 770243185Shrs TAILQ_INIT(&fibl_head); 771243185Shrs 7721558Srgrimes cmd = argv[0]; 773191080Skmacy if (*cmd != 'g' && *cmd != 's') 774146079Sjmallett shutdown(s, SHUT_RD); /* Don't want to read back our messages */ 7751558Srgrimes while (--argc > 0) { 7761558Srgrimes if (**(++argv)== '-') { 7771558Srgrimes switch (key = keyword(1 + *argv)) { 7781558Srgrimes case K_LINK: 7791558Srgrimes af = AF_LINK; 7801558Srgrimes aflen = sizeof(struct sockaddr_dl); 7811558Srgrimes break; 782253427Shrs#ifdef INET 7831558Srgrimes case K_INET: 7841558Srgrimes af = AF_INET; 7851558Srgrimes aflen = sizeof(struct sockaddr_in); 7861558Srgrimes break; 787253427Shrs#endif 78854263Sshin#ifdef INET6 78954263Sshin case K_INET6: 79054263Sshin af = AF_INET6; 79154263Sshin aflen = sizeof(struct sockaddr_in6); 79254263Sshin break; 79354263Sshin#endif 79417046Sjulian case K_ATALK: 79517046Sjulian af = AF_APPLETALK; 79617046Sjulian aflen = sizeof(struct sockaddr_at); 79717046Sjulian break; 7981558Srgrimes case K_SA: 7991558Srgrimes af = PF_ROUTE; 800253427Shrs aflen = sizeof(struct sockaddr_storage); 8011558Srgrimes break; 8021558Srgrimes case K_IFACE: 8031558Srgrimes case K_INTERFACE: 804243185Shrs nrflags |= F_INTERFACE; 8052787Spst break; 8061558Srgrimes case K_NOSTATIC: 8071558Srgrimes flags &= ~RTF_STATIC; 8081558Srgrimes break; 8091558Srgrimes case K_LOCK: 8101558Srgrimes locking = 1; 8111558Srgrimes break; 8121558Srgrimes case K_LOCKREST: 8131558Srgrimes lockrest = 1; 8141558Srgrimes break; 8151558Srgrimes case K_HOST: 816243185Shrs nrflags |= F_FORCEHOST; 8171558Srgrimes break; 8181558Srgrimes case K_REJECT: 8191558Srgrimes flags |= RTF_REJECT; 8201558Srgrimes break; 8211558Srgrimes case K_BLACKHOLE: 8221558Srgrimes flags |= RTF_BLACKHOLE; 8231558Srgrimes break; 8241558Srgrimes case K_PROTO1: 8251558Srgrimes flags |= RTF_PROTO1; 8261558Srgrimes break; 8271558Srgrimes case K_PROTO2: 8281558Srgrimes flags |= RTF_PROTO2; 8291558Srgrimes break; 83078140Sru case K_PROXY: 831243185Shrs nrflags |= F_PROXY; 83278140Sru break; 8331558Srgrimes case K_XRESOLVE: 8341558Srgrimes flags |= RTF_XRESOLVE; 8351558Srgrimes break; 8361558Srgrimes case K_STATIC: 8371558Srgrimes flags |= RTF_STATIC; 8381558Srgrimes break; 839191080Skmacy case K_STICKY: 840191080Skmacy flags |= RTF_STICKY; 841191080Skmacy break; 842191080Skmacy case K_NOSTICK: 843191080Skmacy flags &= ~RTF_STICKY; 844191080Skmacy break; 845243185Shrs case K_FIB: 846243185Shrs if (!--argc) 847243185Shrs usage(NULL); 848243185Shrs error = fiboptlist_csv(*++argv, &fibl_head); 849243185Shrs if (error) 850244325Shrs errx(EX_USAGE, 851244325Shrs "invalid fib number: %s", *argv); 852243185Shrs break; 8531558Srgrimes case K_IFA: 85447668Sru if (!--argc) 855204406Suqs usage(NULL); 856253504Shrs getaddr(RTAX_IFA, *++argv, 0, nrflags); 8571558Srgrimes break; 8581558Srgrimes case K_IFP: 85947668Sru if (!--argc) 860204406Suqs usage(NULL); 861253504Shrs getaddr(RTAX_IFP, *++argv, 0, nrflags); 8621558Srgrimes break; 8631558Srgrimes case K_GENMASK: 86447668Sru if (!--argc) 865204406Suqs usage(NULL); 866253504Shrs getaddr(RTAX_GENMASK, *++argv, 0, nrflags); 8671558Srgrimes break; 8681558Srgrimes case K_GATEWAY: 86947668Sru if (!--argc) 870204406Suqs usage(NULL); 871253504Shrs getaddr(RTAX_GATEWAY, *++argv, 0, nrflags); 872251581Shrs gateway = *argv; 8731558Srgrimes break; 8741558Srgrimes case K_DST: 87547668Sru if (!--argc) 876204406Suqs usage(NULL); 877253504Shrs if (getaddr(RTAX_DST, *++argv, &hp, nrflags)) 878243185Shrs nrflags |= F_ISHOST; 8791558Srgrimes dest = *argv; 8801558Srgrimes break; 8811558Srgrimes case K_NETMASK: 88247668Sru if (!--argc) 883204406Suqs usage(NULL); 884253504Shrs getaddr(RTAX_NETMASK, *++argv, 0, nrflags); 8851558Srgrimes /* FALLTHROUGH */ 8861558Srgrimes case K_NET: 887243185Shrs nrflags |= F_FORCENET; 8881558Srgrimes break; 88954263Sshin case K_PREFIXLEN: 89054263Sshin if (!--argc) 891204406Suqs usage(NULL); 89254263Sshin if (prefixlen(*++argv) == -1) { 893243185Shrs nrflags &= ~F_FORCENET; 894243185Shrs nrflags |= F_ISHOST; 89554263Sshin } else { 896243185Shrs nrflags |= F_FORCENET; 897243185Shrs nrflags &= ~F_ISHOST; 89854263Sshin } 89954263Sshin break; 9001558Srgrimes case K_MTU: 9011558Srgrimes case K_HOPCOUNT: 9021558Srgrimes case K_EXPIRE: 9031558Srgrimes case K_RECVPIPE: 9041558Srgrimes case K_SENDPIPE: 9051558Srgrimes case K_SSTHRESH: 9061558Srgrimes case K_RTT: 9071558Srgrimes case K_RTTVAR: 908191080Skmacy case K_WEIGHT: 90947668Sru if (!--argc) 910204406Suqs usage(NULL); 9111558Srgrimes set_metric(*++argv, key); 9121558Srgrimes break; 9131558Srgrimes default: 9141558Srgrimes usage(1+*argv); 9151558Srgrimes } 9161558Srgrimes } else { 9171558Srgrimes if ((rtm_addrs & RTA_DST) == 0) { 9181558Srgrimes dest = *argv; 919253504Shrs if (getaddr(RTAX_DST, *argv, &hp, nrflags)) 920243185Shrs nrflags |= F_ISHOST; 9211558Srgrimes } else if ((rtm_addrs & RTA_GATEWAY) == 0) { 9221558Srgrimes gateway = *argv; 923253504Shrs getaddr(RTAX_GATEWAY, *argv, &hp, nrflags); 9241558Srgrimes } else { 925253504Shrs getaddr(RTAX_NETMASK, *argv, 0, nrflags); 926243185Shrs nrflags |= F_FORCENET; 9271558Srgrimes } 9281558Srgrimes } 9291558Srgrimes } 930243185Shrs 931256137Sglebius if (so[RTAX_DST].ss_len == 0) { 932256137Sglebius warnx("destination parameter required"); 933256137Sglebius usage(NULL); 934256137Sglebius } 935256137Sglebius 936243185Shrs if (nrflags & F_FORCEHOST) { 937243185Shrs nrflags |= F_ISHOST; 93854263Sshin#ifdef INET6 93954263Sshin if (af == AF_INET6) { 94054263Sshin rtm_addrs &= ~RTA_NETMASK; 941253427Shrs memset(&so[RTAX_NETMASK], 0, sizeof(so[RTAX_NETMASK])); 94254263Sshin } 943204406Suqs#endif 94454263Sshin } 945243185Shrs if (nrflags & F_FORCENET) 946243185Shrs nrflags &= ~F_ISHOST; 9471558Srgrimes flags |= RTF_UP; 948243185Shrs if (nrflags & F_ISHOST) 9491558Srgrimes flags |= RTF_HOST; 950243185Shrs if ((nrflags & F_INTERFACE) == 0) 9511558Srgrimes flags |= RTF_GATEWAY; 952246143Sglebius if (nrflags & F_PROXY) 95378140Sru flags |= RTF_ANNOUNCE; 954243185Shrs if (dest == NULL) 955243185Shrs dest = ""; 956243185Shrs if (gateway == NULL) 957243185Shrs gateway = ""; 958243185Shrs 959243185Shrs if (TAILQ_EMPTY(&fibl_head)) { 960243185Shrs error = fiboptlist_csv("default", &fibl_head); 961243185Shrs if (error) 962243185Shrs errx(EX_OSERR, "fiboptlist_csv failed."); 9631558Srgrimes } 964243185Shrs error = 0; 965243185Shrs TAILQ_FOREACH(fl, &fibl_head, fl_next) { 966243185Shrs fl->fl_error = newroute_fib(fl->fl_num, cmd, flags); 967243185Shrs if (fl->fl_error) 968243185Shrs fl->fl_errno = errno; 969243185Shrs error += fl->fl_error; 970243185Shrs } 971191080Skmacy if (*cmd == 'g' || *cmd == 's') 972243185Shrs exit(error); 973243185Shrs 974243185Shrs error = 0; 97597278Sru if (!qflag) { 976243185Shrs fibnum = 0; 977243185Shrs TAILQ_FOREACH(fl, &fibl_head, fl_next) { 978243185Shrs if (fl->fl_error == 0) 979243185Shrs fibnum++; 9801558Srgrimes } 981243185Shrs if (fibnum > 0) { 982243185Shrs int firstfib = 1; 983243185Shrs 984243185Shrs printf("%s %s %s", cmd, 985243185Shrs (nrflags & F_ISHOST) ? "host" : "net", dest); 986243185Shrs if (*gateway) 987243185Shrs printf(": gateway %s", gateway); 988243185Shrs 989243185Shrs if (numfibs > 1) { 990243185Shrs TAILQ_FOREACH(fl, &fibl_head, fl_next) { 991243185Shrs if (fl->fl_error == 0 992243185Shrs && fl->fl_num >= 0) { 993243185Shrs if (firstfib) { 994243185Shrs printf(" fib "); 995243185Shrs firstfib = 0; 996243185Shrs } 997243185Shrs printf("%d", fl->fl_num); 998243185Shrs if (fibnum-- > 1) 999243185Shrs printf(","); 1000243185Shrs } 1001243185Shrs } 100297278Sru } 1003243185Shrs printf("\n"); 100497278Sru } 1005243185Shrs 1006243185Shrs fibnum = 0; 1007243185Shrs TAILQ_FOREACH(fl, &fibl_head, fl_next) { 1008243185Shrs if (fl->fl_error != 0) { 1009243185Shrs printf("%s %s %s", cmd, (nrflags & F_ISHOST) 1010243185Shrs ? "host" : "net", dest); 1011243185Shrs if (*gateway) 1012243185Shrs printf(": gateway %s", gateway); 1013243185Shrs 1014243185Shrs if (fl->fl_num >= 0) 1015243185Shrs printf(" fib %d", fl->fl_num); 1016243185Shrs 1017243185Shrs switch (fl->fl_errno) { 1018243185Shrs case ESRCH: 1019243185Shrs errmsg = "not in table"; 1020243185Shrs break; 1021243185Shrs case EBUSY: 1022243185Shrs errmsg = "entry in use"; 1023243185Shrs break; 1024243185Shrs case ENOBUFS: 1025243185Shrs errmsg = "not enough memory"; 1026243185Shrs break; 1027243185Shrs case EADDRINUSE: 1028243185Shrs /* 1029243185Shrs * handle recursion avoidance 1030243185Shrs * in rt_setgate() 1031243185Shrs */ 1032243185Shrs errmsg = "gateway uses the same route"; 1033243185Shrs break; 1034243185Shrs case EEXIST: 1035243185Shrs errmsg = "route already in table"; 1036243185Shrs break; 1037243185Shrs default: 1038243185Shrs errmsg = strerror(fl->fl_errno); 1039243185Shrs break; 1040243185Shrs } 1041243185Shrs printf(": %s\n", errmsg); 1042243185Shrs error = 1; 1043243185Shrs } 1044243185Shrs } 10451558Srgrimes } 1046243185Shrs exit(error); 10471558Srgrimes} 10481558Srgrimes 1049243185Shrsstatic int 1050243185Shrsnewroute_fib(int fib, char *cmd, int flags) 1051243185Shrs{ 1052243185Shrs int error; 1053243185Shrs 1054243185Shrs error = set_sofib(fib); 1055243185Shrs if (error) { 1056243185Shrs warn("fib number %d is ignored", fib); 1057243185Shrs return (error); 1058243185Shrs } 1059243185Shrs 1060243185Shrs error = rtmsg(*cmd, flags, fib); 1061243185Shrs return (error); 1062243185Shrs} 1063243185Shrs 1064253427Shrs#ifdef INET 1065204406Suqsstatic void 1066253427Shrsinet_makenetandmask(u_long net, struct sockaddr_in *sin, 1067253427Shrs struct sockaddr_in *sin_mask, u_long bits) 10681558Srgrimes{ 1069243019Sglebius u_long mask = 0; 10701558Srgrimes 10711558Srgrimes rtm_addrs |= RTA_NETMASK; 1072243019Sglebius 1073204406Suqs /* 1074243867Sglebius * MSB of net should be meaningful. 0/0 is exception. 1075243867Sglebius */ 1076243867Sglebius if (net > 0) 1077243867Sglebius while ((net & 0xff000000) == 0) 1078243867Sglebius net <<= 8; 1079243867Sglebius 1080243867Sglebius /* 1081204406Suqs * If no /xx was specified we must calculate the 1082190758Srrs * CIDR address. 1083190758Srrs */ 1084243019Sglebius if ((bits == 0) && (net != 0)) { 1085190775Srrs u_long i, j; 1086253427Shrs 1087253427Shrs for(i = 0, j = 0xff; i < 4; i++) { 1088243019Sglebius if (net & j) { 1089190758Srrs break; 1090190758Srrs } 1091190775Srrs j <<= 8; 1092190758Srrs } 1093190758Srrs /* i holds the first non zero bit */ 1094190775Srrs bits = 32 - (i*8); 1095190758Srrs } 1096190913Srrs if (bits != 0) 1097190913Srrs mask = 0xffffffff << (32 - bits); 1098173124Smtm 1099243019Sglebius sin->sin_addr.s_addr = htonl(net); 1100253427Shrs sin_mask->sin_addr.s_addr = htonl(mask); 1101253427Shrs sin_mask->sin_len = sizeof(struct sockaddr_in); 1102253427Shrs sin_mask->sin_family = AF_INET; 11031558Srgrimes} 1104253427Shrs#endif 11051558Srgrimes 110696997Sume#ifdef INET6 11071558Srgrimes/* 110896997Sume * XXX the function may need more improvement... 110996997Sume */ 111097062Sumestatic int 1111204406Suqsinet6_makenetandmask(struct sockaddr_in6 *sin6, const char *plen) 111296997Sume{ 111396997Sume struct in6_addr in6; 111496997Sume 1115204406Suqs if (plen == NULL) { 111697073Sume if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && 111797073Sume sin6->sin6_scope_id == 0) { 111897073Sume plen = "0"; 111997073Sume } else if ((sin6->sin6_addr.s6_addr[0] & 0xe0) == 0x20) { 112097073Sume /* aggregatable global unicast - RFC2374 */ 112197073Sume memset(&in6, 0, sizeof(in6)); 112297073Sume if (!memcmp(&sin6->sin6_addr.s6_addr[8], 112397073Sume &in6.s6_addr[8], 8)) 112497073Sume plen = "64"; 112597073Sume } 112696997Sume } 112796997Sume 1128204406Suqs if (plen == NULL || strcmp(plen, "128") == 0) 1129204406Suqs return (1); 113098053Sume rtm_addrs |= RTA_NETMASK; 1131204406Suqs prefixlen(plen); 1132204406Suqs return (0); 113396997Sume} 113496997Sume#endif 113596997Sume 113696997Sume/* 11371558Srgrimes * Interpret an argument as a network address of some kind, 11381558Srgrimes * returning 1 if a host address, 0 if a network address. 11391558Srgrimes */ 1140204406Suqsstatic int 1141253504Shrsgetaddr(int idx, char *str, struct hostent **hpp, int nrflags) 11421558Srgrimes{ 1143253427Shrs struct sockaddr *sa; 1144253427Shrs#if defined(INET) 1145253427Shrs struct sockaddr_in *sin; 11461558Srgrimes struct hostent *hp; 11471558Srgrimes struct netent *np; 11481558Srgrimes u_long val; 114966449Sru char *q; 1150253427Shrs#elif defined(INET6) 1151253427Shrs char *q; 1152253427Shrs#endif 11531558Srgrimes 1154253852Shrs if (idx < 0 || idx >= RTAX_MAX) 1155253852Shrs usage("internal error"); 11561558Srgrimes if (af == 0) { 1157253427Shrs#if defined(INET) 11581558Srgrimes af = AF_INET; 11591558Srgrimes aflen = sizeof(struct sockaddr_in); 1160253427Shrs#elif defined(INET6) 1161253427Shrs af = AF_INET6; 1162253427Shrs aflen = sizeof(struct sockaddr_in6); 1163253427Shrs#else 1164253427Shrs af = AF_LINK; 1165253427Shrs aflen = sizeof(struct sockaddr_dl); 1166253427Shrs#endif 11671558Srgrimes } 1168253519Shrs#ifndef INET 1169253519Shrs hpp = NULL; 1170253519Shrs#endif 1171253504Shrs rtm_addrs |= (1 << idx); 1172253504Shrs sa = (struct sockaddr *)&so[idx]; 1173253427Shrs sa->sa_family = af; 1174253427Shrs sa->sa_len = aflen; 1175253427Shrs 1176253504Shrs switch (idx) { 1177253504Shrs case RTAX_GATEWAY: 1178245168Shrs if (nrflags & F_INTERFACE) { 117978064Sume struct ifaddrs *ifap, *ifa; 1180253502Shrs struct sockaddr_dl *sdl0 = (struct sockaddr_dl *)(void *)sa; 118178064Sume struct sockaddr_dl *sdl = NULL; 118217486Sjulian 118378064Sume if (getifaddrs(&ifap)) 1184253427Shrs err(EX_OSERR, "getifaddrs"); 118517486Sjulian 1186204406Suqs for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 118778064Sume if (ifa->ifa_addr->sa_family != AF_LINK) 118878064Sume continue; 118917486Sjulian 1190204406Suqs if (strcmp(str, ifa->ifa_name) != 0) 119178064Sume continue; 119278064Sume 1193253502Shrs sdl = (struct sockaddr_dl *)(void *)ifa->ifa_addr; 119417486Sjulian } 119517486Sjulian /* If we found it, then use it */ 1196204406Suqs if (sdl != NULL) { 119778064Sume /* 119878064Sume * Note that we need to copy before calling 119978064Sume * freeifaddrs(). 120078064Sume */ 1201253427Shrs memcpy(sdl0, sdl, sdl->sdl_len); 120278064Sume } 120378064Sume freeifaddrs(ifap); 1204204406Suqs if (sdl != NULL) 120517486Sjulian return(1); 120617486Sjulian } 12071558Srgrimes break; 1208253504Shrs case RTAX_IFP: 1209253427Shrs sa->sa_family = AF_LINK; 12101558Srgrimes break; 12111558Srgrimes } 1212204406Suqs if (strcmp(str, "default") == 0) { 121327500Sjulian /* 1214204406Suqs * Default is net 0.0.0.0/0 121527500Sjulian */ 1216253504Shrs switch (idx) { 1217253504Shrs case RTAX_DST: 12181558Srgrimes forcenet++; 1219253504Shrs getaddr(RTAX_NETMASK, str, 0, nrflags); 12201558Srgrimes break; 12211558Srgrimes } 12221558Srgrimes return (0); 12231558Srgrimes } 1224253427Shrs switch (sa->sa_family) { 122554263Sshin#ifdef INET6 122654263Sshin case AF_INET6: 122778064Sume { 122857108Sshin struct addrinfo hints, *res; 1229146546Sume int ecode; 123057108Sshin 123197073Sume q = NULL; 1232253504Shrs if (idx == RTAX_DST && (q = strchr(str, '/')) != NULL) 123397073Sume *q = '\0'; 123478064Sume memset(&hints, 0, sizeof(hints)); 1235253427Shrs hints.ai_family = sa->sa_family; 1236253427Shrs hints.ai_socktype = SOCK_DGRAM; 1237204406Suqs ecode = getaddrinfo(str, NULL, &hints, &res); 1238146546Sume if (ecode != 0 || res->ai_family != AF_INET6 || 1239253427Shrs res->ai_addrlen != sizeof(struct sockaddr_in6)) 1240253427Shrs errx(EX_OSERR, "%s: %s", str, gai_strerror(ecode)); 1241253427Shrs memcpy(sa, res->ai_addr, res->ai_addrlen); 124297062Sume freeaddrinfo(res); 124397073Sume if (q != NULL) 124497073Sume *q++ = '/'; 1245253504Shrs if (idx == RTAX_DST) 1246253502Shrs return (inet6_makenetandmask((struct sockaddr_in6 *)(void *)sa, q)); 124778064Sume return (0); 124878064Sume } 124978064Sume#endif /* INET6 */ 125054263Sshin 125117046Sjulian case AF_APPLETALK: 1252253427Shrs { 1253253502Shrs struct sockaddr_at *sat = (struct sockaddr_at *)(void *)sa; 1254253427Shrs 1255253427Shrs if (!atalk_aton(str, &sat->sat_addr)) 1256204406Suqs errx(EX_NOHOST, "bad address: %s", str); 125717265Sjulian rtm_addrs |= RTA_NETMASK; 1258253427Shrs return(forcehost || sat->sat_addr.s_node != 0); 1259253427Shrs } 12601558Srgrimes case AF_LINK: 1261253502Shrs link_addr(str, (struct sockaddr_dl *)(void *)sa); 12621558Srgrimes return (1); 12631558Srgrimes 12641558Srgrimes case PF_ROUTE: 1265253427Shrs sockaddr(str, sa, sizeof(struct sockaddr_storage)); 12661558Srgrimes return (1); 1267253427Shrs#ifdef INET 12681558Srgrimes case AF_INET: 1269253427Shrs#endif 12701558Srgrimes default: 12711558Srgrimes break; 12721558Srgrimes } 12731558Srgrimes 1274253427Shrs#ifdef INET 1275253502Shrs sin = (struct sockaddr_in *)(void *)sa; 12761558Srgrimes if (hpp == NULL) 12771558Srgrimes hpp = &hp; 12781558Srgrimes *hpp = NULL; 127924558Sphk 1280204406Suqs q = strchr(str,'/'); 1281253504Shrs if (q != NULL && idx == RTAX_DST) { 128224558Sphk *q = '\0'; 1283204406Suqs if ((val = inet_network(str)) != INADDR_NONE) { 1284253427Shrs inet_makenetandmask(val, sin, 1285253427Shrs (struct sockaddr_in *)&so[RTAX_NETMASK], 1286253427Shrs strtoul(q+1, 0, 0)); 128724558Sphk return (0); 128824558Sphk } 128966449Sru *q = '/'; 129024558Sphk } 1291253504Shrs if ((idx != RTAX_DST || forcenet == 0) && 1292253427Shrs inet_aton(str, &sin->sin_addr)) { 1293253427Shrs val = sin->sin_addr.s_addr; 1294253504Shrs if (idx != RTAX_DST || forcehost || 1295253427Shrs inet_lnaof(sin->sin_addr) != INADDR_ANY) 12961558Srgrimes return (1); 12971558Srgrimes else { 12981558Srgrimes val = ntohl(val); 12991558Srgrimes goto netdone; 13001558Srgrimes } 13011558Srgrimes } 1302253504Shrs if (idx == RTAX_DST && forcehost == 0 && 1303204406Suqs ((val = inet_network(str)) != INADDR_NONE || 1304204406Suqs ((np = getnetbyname(str)) != NULL && (val = np->n_net) != 0))) { 13051558Srgrimesnetdone: 1306253427Shrs inet_makenetandmask(val, sin, 1307253427Shrs (struct sockaddr_in *)&so[RTAX_NETMASK], 0); 13081558Srgrimes return (0); 13091558Srgrimes } 1310204406Suqs hp = gethostbyname(str); 1311204406Suqs if (hp != NULL) { 13121558Srgrimes *hpp = hp; 1313253427Shrs sin->sin_family = hp->h_addrtype; 1314253427Shrs memmove((char *)&sin->sin_addr, hp->h_addr, 1315253427Shrs MIN((size_t)hp->h_length, sizeof(sin->sin_addr))); 13161558Srgrimes return (1); 13171558Srgrimes } 1318253427Shrs#endif 1319204406Suqs errx(EX_NOHOST, "bad address: %s", str); 13201558Srgrimes} 13211558Srgrimes 1322204406Suqsstatic int 1323204406Suqsprefixlen(const char *str) 132454263Sshin{ 1325204406Suqs int len = atoi(str), q, r; 132654263Sshin int max; 132754263Sshin char *p; 13281558Srgrimes 132954263Sshin rtm_addrs |= RTA_NETMASK; 133054263Sshin switch (af) { 133154263Sshin#ifdef INET6 133254263Sshin case AF_INET6: 1333253427Shrs { 1334253427Shrs struct sockaddr_in6 *sin6 = 1335253427Shrs (struct sockaddr_in6 *)&so[RTAX_NETMASK]; 1336253427Shrs 133754263Sshin max = 128; 1338253427Shrs p = (char *)&sin6->sin6_addr; 1339253427Shrs sin6->sin6_family = AF_INET6; 1340253427Shrs sin6->sin6_len = sizeof(*sin6); 134154263Sshin break; 1342253427Shrs } 134354263Sshin#endif 1344253427Shrs#ifdef INET 134554263Sshin case AF_INET: 1346253427Shrs { 1347253427Shrs struct sockaddr_in *sin = 1348253427Shrs (struct sockaddr_in *)&so[RTAX_NETMASK]; 1349253427Shrs 135054263Sshin max = 32; 1351253427Shrs p = (char *)&sin->sin_addr; 1352253427Shrs sin->sin_family = AF_INET; 1353253427Shrs sin->sin_len = sizeof(*sin); 135454263Sshin break; 1355253427Shrs } 1356253427Shrs#endif 135754263Sshin default: 1358253427Shrs errx(EX_OSERR, "prefixlen not supported in this af"); 135954263Sshin } 136054263Sshin 1361253427Shrs if (len < 0 || max < len) 1362253427Shrs errx(EX_USAGE, "%s: invalid prefixlen", str); 136354263Sshin 136454263Sshin q = len >> 3; 136554263Sshin r = len & 7; 136654263Sshin memset((void *)p, 0, max / 8); 136754263Sshin if (q > 0) 136854263Sshin memset((void *)p, 0xff, q); 136954263Sshin if (r > 0) 137054263Sshin *((u_char *)p + q) = (0xff00 >> r) & 0xff; 137154263Sshin if (len == max) 1372204406Suqs return (-1); 137354263Sshin else 1374204406Suqs return (len); 137554263Sshin} 137654263Sshin 1377204406Suqsstatic void 1378196527Scharnierinterfaces(void) 13791558Srgrimes{ 13801558Srgrimes size_t needed; 13811558Srgrimes int mib[6]; 1382128782Sambrisko char *buf, *lim, *next, count = 0; 138392806Sobrien struct rt_msghdr *rtm; 13841558Srgrimes 1385128782Sambriskoretry2: 13861558Srgrimes mib[0] = CTL_NET; 13871558Srgrimes mib[1] = PF_ROUTE; 13881558Srgrimes mib[2] = 0; /* protocol */ 1389253427Shrs mib[3] = AF_UNSPEC; 13901558Srgrimes mib[4] = NET_RT_IFLIST; 13911558Srgrimes mib[5] = 0; /* no flags */ 1392253427Shrs if (sysctl(mib, nitems(mib), NULL, &needed, NULL, 0) < 0) 139313171Swollman err(EX_OSERR, "route-sysctl-estimate"); 13941558Srgrimes if ((buf = malloc(needed)) == NULL) 139537907Scharnier errx(EX_OSERR, "malloc failed"); 1396253427Shrs if (sysctl(mib, nitems(mib), buf, &needed, NULL, 0) < 0) { 1397128782Sambrisko if (errno == ENOMEM && count++ < 10) { 1398128782Sambrisko warnx("Routing table grew, retrying"); 1399128782Sambrisko sleep(1); 1400128782Sambrisko free(buf); 1401128782Sambrisko goto retry2; 1402128782Sambrisko } 140313171Swollman err(EX_OSERR, "actual retrieval of interface table"); 1404128782Sambrisko } 14051558Srgrimes lim = buf + needed; 14061558Srgrimes for (next = buf; next < lim; next += rtm->rtm_msglen) { 1407253502Shrs rtm = (struct rt_msghdr *)(void *)next; 14081558Srgrimes print_rtmsg(rtm, rtm->rtm_msglen); 14091558Srgrimes } 14101558Srgrimes} 14111558Srgrimes 1412204406Suqsstatic void 1413243185Shrsmonitor(int argc, char *argv[]) 14141558Srgrimes{ 1415243185Shrs int n, fib, error; 1416243185Shrs char msg[2048], *endptr; 14171558Srgrimes 1418243185Shrs fib = defaultfib; 1419243185Shrs while (argc > 1) { 1420243185Shrs argc--; 1421243185Shrs argv++; 1422243185Shrs if (**argv != '-') 1423243185Shrs usage(*argv); 1424243185Shrs switch (keyword(*argv + 1)) { 1425243185Shrs case K_FIB: 1426243185Shrs if (!--argc) 1427243185Shrs usage(*argv); 1428244325Shrs errno = 0; 1429243185Shrs fib = strtol(*++argv, &endptr, 0); 1430244325Shrs if (errno == 0) { 1431244325Shrs if (*endptr != '\0' || 1432244325Shrs fib < 0 || 1433244325Shrs (numfibs != -1 && fib > numfibs - 1)) 1434244325Shrs errno = EINVAL; 1435244325Shrs } 1436244325Shrs if (errno) 1437244325Shrs errx(EX_USAGE, "invalid fib number: %s", *argv); 1438243185Shrs break; 1439243185Shrs default: 1440243185Shrs usage(*argv); 1441243185Shrs } 1442243185Shrs } 1443243185Shrs error = set_sofib(fib); 1444243185Shrs if (error) 1445243185Shrs errx(EX_USAGE, "invalid fib number: %d", fib); 1446243185Shrs 14471558Srgrimes verbose = 1; 14481558Srgrimes if (debugonly) { 14491558Srgrimes interfaces(); 14501558Srgrimes exit(0); 14511558Srgrimes } 1452204406Suqs for (;;) { 145354263Sshin time_t now; 14541558Srgrimes n = read(s, msg, 2048); 145554263Sshin now = time(NULL); 1456253427Shrs (void)printf("\ngot message of size %d on %s", n, ctime(&now)); 1457253502Shrs print_rtmsg((struct rt_msghdr *)(void *)msg, n); 14581558Srgrimes } 14591558Srgrimes} 14601558Srgrimes 1461253427Shrsstatic struct { 14621558Srgrimes struct rt_msghdr m_rtm; 14631558Srgrimes char m_space[512]; 14641558Srgrimes} m_rtmsg; 14651558Srgrimes 1466204406Suqsstatic int 1467243185Shrsrtmsg(int cmd, int flags, int fib) 14681558Srgrimes{ 14691558Srgrimes static int seq; 14701558Srgrimes int rlen; 147192806Sobrien char *cp = m_rtmsg.m_space; 147292806Sobrien int l; 14731558Srgrimes 1474253427Shrs#define NEXTADDR(w, u) \ 1475253427Shrs if (rtm_addrs & (w)) { \ 1476253443Shrs l = (((struct sockaddr *)&(u))->sa_len == 0) ? \ 1477253443Shrs sizeof(long) : \ 1478253443Shrs 1 + ((((struct sockaddr *)&(u))->sa_len - 1) \ 1479253443Shrs | (sizeof(long) - 1)); \ 1480253427Shrs memmove(cp, (char *)&(u), l); \ 1481253427Shrs cp += l; \ 1482253427Shrs if (verbose) \ 1483253427Shrs sodump((struct sockaddr *)&(u), #w); \ 14841558Srgrimes } 14851558Srgrimes 14861558Srgrimes errno = 0; 148785048Sru memset(&m_rtmsg, 0, sizeof(m_rtmsg)); 14881558Srgrimes if (cmd == 'a') 14891558Srgrimes cmd = RTM_ADD; 14901558Srgrimes else if (cmd == 'c') 14911558Srgrimes cmd = RTM_CHANGE; 1492191080Skmacy else if (cmd == 'g' || cmd == 's') { 14931558Srgrimes cmd = RTM_GET; 1494253427Shrs if (so[RTAX_IFP].ss_family == 0) { 1495253427Shrs so[RTAX_IFP].ss_family = AF_LINK; 1496253427Shrs so[RTAX_IFP].ss_len = sizeof(struct sockaddr_dl); 14971558Srgrimes rtm_addrs |= RTA_IFP; 14981558Srgrimes } 14991558Srgrimes } else 15001558Srgrimes cmd = RTM_DELETE; 15011558Srgrimes#define rtm m_rtmsg.m_rtm 15021558Srgrimes rtm.rtm_type = cmd; 15031558Srgrimes rtm.rtm_flags = flags; 15041558Srgrimes rtm.rtm_version = RTM_VERSION; 15051558Srgrimes rtm.rtm_seq = ++seq; 15061558Srgrimes rtm.rtm_addrs = rtm_addrs; 15071558Srgrimes rtm.rtm_rmx = rt_metrics; 15081558Srgrimes rtm.rtm_inits = rtm_inits; 15091558Srgrimes 1510253427Shrs NEXTADDR(RTA_DST, so[RTAX_DST]); 1511253427Shrs NEXTADDR(RTA_GATEWAY, so[RTAX_GATEWAY]); 1512253427Shrs NEXTADDR(RTA_NETMASK, so[RTAX_NETMASK]); 1513253427Shrs NEXTADDR(RTA_GENMASK, so[RTAX_GENMASK]); 1514253427Shrs NEXTADDR(RTA_IFP, so[RTAX_IFP]); 1515253427Shrs NEXTADDR(RTA_IFA, so[RTAX_IFA]); 15161558Srgrimes rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; 15171558Srgrimes if (verbose) 15181558Srgrimes print_rtmsg(&rtm, l); 15191558Srgrimes if (debugonly) 15201558Srgrimes return (0); 15211558Srgrimes if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { 1522129034Scsjp if (errno == EPERM) 1523129034Scsjp err(1, "writing to routing socket"); 152437907Scharnier warn("writing to routing socket"); 15251558Srgrimes return (-1); 15261558Srgrimes } 15271558Srgrimes if (cmd == RTM_GET) { 15281558Srgrimes do { 15291558Srgrimes l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); 15301558Srgrimes } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid)); 15311558Srgrimes if (l < 0) 153213171Swollman warn("read from routing socket"); 15331558Srgrimes else 1534243185Shrs print_getmsg(&rtm, l, fib); 15351558Srgrimes } 15361558Srgrimes#undef rtm 15371558Srgrimes return (0); 15381558Srgrimes} 15391558Srgrimes 1540253427Shrsstatic const char *msgtypes[] = { 15411558Srgrimes "", 15421558Srgrimes "RTM_ADD: Add Route", 15431558Srgrimes "RTM_DELETE: Delete Route", 15441558Srgrimes "RTM_CHANGE: Change Metrics or flags", 15451558Srgrimes "RTM_GET: Report Metrics", 15461558Srgrimes "RTM_LOSING: Kernel Suspects Partitioning", 15471558Srgrimes "RTM_REDIRECT: Told to use different route", 15481558Srgrimes "RTM_MISS: Lookup failed on this address", 15491558Srgrimes "RTM_LOCK: fix specified metrics", 15501558Srgrimes "RTM_OLDADD: caused by SIOCADDRT", 15511558Srgrimes "RTM_OLDDEL: caused by SIOCDELRT", 15521558Srgrimes "RTM_RESOLVE: Route created by cloning", 15531558Srgrimes "RTM_NEWADDR: address being added to iface", 15541558Srgrimes "RTM_DELADDR: address being removed from iface", 15551558Srgrimes "RTM_IFINFO: iface status change", 155621465Swollman "RTM_NEWMADDR: new multicast group membership on iface", 155721465Swollman "RTM_DELMADDR: multicast group membership removed from iface", 155889498Sru "RTM_IFANNOUNCE: interface arrival/departure", 1559216296Sglebius "RTM_IEEE80211: IEEE 802.11 wireless event", 15601558Srgrimes}; 15611558Srgrimes 1562253427Shrsstatic const char metricnames[] = 1563253427Shrs "\011weight\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire" 1564253427Shrs "\1mtu"; 1565253427Shrsstatic const char routeflags[] = 1566253427Shrs "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE" 1567253427Shrs "\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE" 1568253427Shrs "\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3" 1569253427Shrs "\025PINNED\026LOCAL\027BROADCAST\030MULTICAST\035STICKY"; 1570253427Shrsstatic const char ifnetflags[] = 1571253427Shrs "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP" 1572253427Shrs "\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1" 1573253427Shrs "\017LINK2\020MULTICAST"; 1574253427Shrsstatic const char addrnames[] = 1575253427Shrs "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD"; 15761558Srgrimes 1577216297Sglebiusstatic const char errfmt[] = 1578253427Shrs "\n%s: truncated route message, only %zu bytes left\n"; 1579216297Sglebius 1580204406Suqsstatic void 1581216297Sglebiusprint_rtmsg(struct rt_msghdr *rtm, size_t msglen) 15821558Srgrimes{ 15831558Srgrimes struct if_msghdr *ifm; 15841558Srgrimes struct ifa_msghdr *ifam; 158521465Swollman#ifdef RTM_NEWMADDR 158621465Swollman struct ifma_msghdr *ifmam; 158721465Swollman#endif 158889498Sru struct if_announcemsghdr *ifan; 1589204406Suqs const char *state; 15901558Srgrimes 15911558Srgrimes if (verbose == 0) 15921558Srgrimes return; 15931558Srgrimes if (rtm->rtm_version != RTM_VERSION) { 1594253427Shrs (void)printf("routing message version %d not understood\n", 15951558Srgrimes rtm->rtm_version); 15961558Srgrimes return; 15971558Srgrimes } 1598253517Shrs if (rtm->rtm_type < nitems(msgtypes)) 159989498Sru (void)printf("%s: ", msgtypes[rtm->rtm_type]); 160089498Sru else 1601216297Sglebius (void)printf("unknown type %d: ", rtm->rtm_type); 160289498Sru (void)printf("len %d, ", rtm->rtm_msglen); 1603216297Sglebius 1604216297Sglebius#define REQUIRE(x) do { \ 1605216297Sglebius if (msglen < sizeof(x)) \ 1606216297Sglebius goto badlen; \ 1607216297Sglebius else \ 1608216297Sglebius msglen -= sizeof(x); \ 1609216297Sglebius } while (0) 1610216297Sglebius 16111558Srgrimes switch (rtm->rtm_type) { 16121558Srgrimes case RTM_IFINFO: 1613216297Sglebius REQUIRE(struct if_msghdr); 16141558Srgrimes ifm = (struct if_msghdr *)rtm; 1615253427Shrs (void)printf("if# %d, ", ifm->ifm_index); 1616128878Sandre switch (ifm->ifm_data.ifi_link_state) { 1617128878Sandre case LINK_STATE_DOWN: 1618128878Sandre state = "down"; 1619128878Sandre break; 1620128878Sandre case LINK_STATE_UP: 1621128878Sandre state = "up"; 1622128878Sandre break; 1623128878Sandre default: 1624128878Sandre state = "unknown"; 1625128878Sandre break; 1626128878Sandre } 1627253427Shrs (void)printf("link: %s, flags:", state); 1628253427Shrs printb(ifm->ifm_flags, ifnetflags); 1629216297Sglebius pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs, msglen); 16301558Srgrimes break; 16311558Srgrimes case RTM_NEWADDR: 16321558Srgrimes case RTM_DELADDR: 1633216297Sglebius REQUIRE(struct ifa_msghdr); 16341558Srgrimes ifam = (struct ifa_msghdr *)rtm; 1635253427Shrs (void)printf("metric %d, flags:", ifam->ifam_metric); 1636253427Shrs printb(ifam->ifam_flags, routeflags); 1637216297Sglebius pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs, msglen); 16381558Srgrimes break; 163921465Swollman#ifdef RTM_NEWMADDR 164021465Swollman case RTM_NEWMADDR: 164121465Swollman case RTM_DELMADDR: 1642216297Sglebius REQUIRE(struct ifma_msghdr); 164321465Swollman ifmam = (struct ifma_msghdr *)rtm; 1644216297Sglebius pmsg_addrs((char *)(ifmam + 1), ifmam->ifmam_addrs, msglen); 164521465Swollman break; 164621465Swollman#endif 164789498Sru case RTM_IFANNOUNCE: 1648216297Sglebius REQUIRE(struct if_announcemsghdr); 164989498Sru ifan = (struct if_announcemsghdr *)rtm; 1650253427Shrs (void)printf("if# %d, what: ", ifan->ifan_index); 165189498Sru switch (ifan->ifan_what) { 165289498Sru case IFAN_ARRIVAL: 1653253427Shrs (void)printf("arrival"); 165489498Sru break; 165589498Sru case IFAN_DEPARTURE: 165689498Sru printf("departure"); 165789498Sru break; 165889498Sru default: 165989498Sru printf("#%d", ifan->ifan_what); 166089498Sru break; 166189498Sru } 166289498Sru printf("\n"); 1663243860Sglebius fflush(stdout); 166489498Sru break; 166589498Sru 16661558Srgrimes default: 1667253427Shrs printf("pid: %ld, seq %d, errno %d, flags:", 166813171Swollman (long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno); 1669253427Shrs printb(rtm->rtm_flags, routeflags); 1670216297Sglebius pmsg_common(rtm, msglen); 16711558Srgrimes } 1672216297Sglebius 1673216297Sglebius return; 1674216297Sglebius 1675216297Sglebiusbadlen: 1676216297Sglebius (void)printf(errfmt, __func__, msglen); 1677216297Sglebius#undef REQUIRE 16781558Srgrimes} 16791558Srgrimes 1680204406Suqsstatic void 1681243185Shrsprint_getmsg(struct rt_msghdr *rtm, int msglen, int fib) 16821558Srgrimes{ 1683253504Shrs struct sockaddr *sp[RTAX_MAX]; 168492806Sobrien char *cp; 168592806Sobrien int i; 16861558Srgrimes 1687253504Shrs memset(sp, 0, sizeof(sp)); 1688253427Shrs (void)printf(" route to: %s\n", 1689253427Shrs routename((struct sockaddr *)&so[RTAX_DST])); 16901558Srgrimes if (rtm->rtm_version != RTM_VERSION) { 169113171Swollman warnx("routing message version %d not understood", 169213171Swollman rtm->rtm_version); 16931558Srgrimes return; 16941558Srgrimes } 16951558Srgrimes if (rtm->rtm_msglen > msglen) { 169637907Scharnier warnx("message length mismatch, in packet %d, returned %d", 169713171Swollman rtm->rtm_msglen, msglen); 1698253517Shrs return; 16991558Srgrimes } 17001558Srgrimes if (rtm->rtm_errno) { 170113171Swollman errno = rtm->rtm_errno; 170213171Swollman warn("message indicates error %d", errno); 17031558Srgrimes return; 17041558Srgrimes } 17051558Srgrimes cp = ((char *)(rtm + 1)); 1706253589Shrs for (i = 0; i < RTAX_MAX; i++) 1707253589Shrs if (rtm->rtm_addrs & (1 << i)) { 1708253504Shrs sp[i] = (struct sockaddr *)cp; 1709253589Shrs cp += SA_SIZE((struct sockaddr *)cp); 1710253589Shrs } 1711253589Shrs if ((rtm->rtm_addrs & RTA_IFP) && 1712253589Shrs (sp[RTAX_IFP]->sa_family != AF_LINK || 1713253589Shrs ((struct sockaddr_dl *)(void *)sp[RTAX_IFP])->sdl_nlen == 0)) 1714253504Shrs sp[RTAX_IFP] = NULL; 1715253504Shrs if (sp[RTAX_DST] && sp[RTAX_NETMASK]) 1716253504Shrs sp[RTAX_NETMASK]->sa_family = sp[RTAX_DST]->sa_family; /* XXX */ 1717253504Shrs if (sp[RTAX_DST]) 1718253504Shrs (void)printf("destination: %s\n", routename(sp[RTAX_DST])); 1719253504Shrs if (sp[RTAX_NETMASK]) 1720253504Shrs (void)printf(" mask: %s\n", routename(sp[RTAX_NETMASK])); 1721253504Shrs if (sp[RTAX_GATEWAY] && (rtm->rtm_flags & RTF_GATEWAY)) 1722253504Shrs (void)printf(" gateway: %s\n", routename(sp[RTAX_GATEWAY])); 1723243185Shrs if (fib >= 0) 1724243185Shrs (void)printf(" fib: %u\n", (unsigned int)fib); 1725253504Shrs if (sp[RTAX_IFP]) 17261558Srgrimes (void)printf(" interface: %.*s\n", 1727253504Shrs ((struct sockaddr_dl *)(void *)sp[RTAX_IFP])->sdl_nlen, 1728253504Shrs ((struct sockaddr_dl *)(void *)sp[RTAX_IFP])->sdl_data); 17291558Srgrimes (void)printf(" flags: "); 1730253427Shrs printb(rtm->rtm_flags, routeflags); 17311558Srgrimes 17321558Srgrimes#define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ') 17331558Srgrimes#define msec(u) (((u) + 500) / 1000) /* usec to msec */ 1734253517Shrs printf("\n%9s %9s %9s %9s %9s %10s %9s\n", "recvpipe", 1735253517Shrs "sendpipe", "ssthresh", "rtt,msec", "mtu ", "weight", "expire"); 173613171Swollman printf("%8ld%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE)); 173713171Swollman printf("%8ld%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE)); 173813171Swollman printf("%8ld%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH)); 173913171Swollman printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT)); 174013171Swollman printf("%8ld%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU)); 1741191080Skmacy printf("%8ld%c ", rtm->rtm_rmx.rmx_weight, lock(WEIGHT)); 17421558Srgrimes if (rtm->rtm_rmx.rmx_expire) 17431558Srgrimes rtm->rtm_rmx.rmx_expire -= time(0); 174413171Swollman printf("%8ld%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE)); 17451558Srgrimes#undef lock 17461558Srgrimes#undef msec 17471558Srgrimes#define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD) 17481558Srgrimes if (verbose) 1749216297Sglebius pmsg_common(rtm, msglen); 17501558Srgrimes else if (rtm->rtm_addrs &~ RTA_IGN) { 1751253427Shrs (void)printf("sockaddrs: "); 1752253427Shrs printb(rtm->rtm_addrs, addrnames); 17531558Srgrimes putchar('\n'); 17541558Srgrimes } 17551558Srgrimes#undef RTA_IGN 17561558Srgrimes} 17571558Srgrimes 1758204406Suqsstatic void 1759216297Sglebiuspmsg_common(struct rt_msghdr *rtm, size_t msglen) 17601558Srgrimes{ 1761253427Shrs 1762253427Shrs (void)printf("\nlocks: "); 1763253427Shrs printb(rtm->rtm_rmx.rmx_locks, metricnames); 1764253427Shrs (void)printf(" inits: "); 1765253427Shrs printb(rtm->rtm_inits, metricnames); 1766216297Sglebius if (msglen > sizeof(struct rt_msghdr)) 1767216297Sglebius pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs, 1768216297Sglebius msglen - sizeof(struct rt_msghdr)); 1769216297Sglebius else 1770253427Shrs (void)fflush(stdout); 17711558Srgrimes} 17721558Srgrimes 1773204406Suqsstatic void 1774216297Sglebiuspmsg_addrs(char *cp, int addrs, size_t len) 17751558Srgrimes{ 177692806Sobrien struct sockaddr *sa; 17771558Srgrimes int i; 17781558Srgrimes 177971061Sphk if (addrs == 0) { 1780253427Shrs (void)putchar('\n'); 17811558Srgrimes return; 178271061Sphk } 1783253427Shrs (void)printf("\nsockaddrs: "); 1784253427Shrs printb(addrs, addrnames); 1785253427Shrs putchar('\n'); 1786253517Shrs for (i = 0; i < RTAX_MAX; i++) 1787253517Shrs if (addrs & (1 << i)) { 17881558Srgrimes sa = (struct sockaddr *)cp; 1789216297Sglebius if (len == 0 || len < SA_SIZE(sa)) { 1790253427Shrs (void)printf(errfmt, __func__, len); 1791216297Sglebius break; 1792216297Sglebius } 1793253427Shrs (void)printf(" %s", routename(sa)); 1794216297Sglebius len -= SA_SIZE(sa); 1795128186Sluigi cp += SA_SIZE(sa); 17961558Srgrimes } 1797253427Shrs (void)putchar('\n'); 1798253427Shrs (void)fflush(stdout); 17991558Srgrimes} 18001558Srgrimes 1801204406Suqsstatic void 1802253427Shrsprintb(int b, const char *str) 18031558Srgrimes{ 180492806Sobrien int i; 18051558Srgrimes int gotsome = 0; 18061558Srgrimes 18071558Srgrimes if (b == 0) 18081558Srgrimes return; 1809204406Suqs while ((i = *str++) != 0) { 18101558Srgrimes if (b & (1 << (i-1))) { 18111558Srgrimes if (gotsome == 0) 18121558Srgrimes i = '<'; 18131558Srgrimes else 18141558Srgrimes i = ','; 1815253427Shrs putchar(i); 18161558Srgrimes gotsome = 1; 1817204406Suqs for (; (i = *str) > 32; str++) 1818253427Shrs putchar(i); 18191558Srgrimes } else 1820204406Suqs while (*str > 32) 1821204406Suqs str++; 18221558Srgrimes } 18231558Srgrimes if (gotsome) 1824253427Shrs putchar('>'); 18251558Srgrimes} 18261558Srgrimes 18271558Srgrimesint 1828204406Suqskeyword(const char *cp) 18291558Srgrimes{ 183092806Sobrien struct keytab *kt = keywords; 18311558Srgrimes 1832204406Suqs while (kt->kt_cp != NULL && strcmp(kt->kt_cp, cp) != 0) 18331558Srgrimes kt++; 1834204406Suqs return (kt->kt_i); 18351558Srgrimes} 18361558Srgrimes 1837204406Suqsstatic void 1838253427Shrssodump(struct sockaddr *sa, const char *which) 18391558Srgrimes{ 1840253427Shrs#ifdef INET6 1841253427Shrs char nbuf[INET6_ADDRSTRLEN]; 1842253427Shrs#endif 1843253427Shrs 1844253427Shrs switch (sa->sa_family) { 18451558Srgrimes case AF_LINK: 1846253427Shrs (void)printf("%s: link %s; ", which, 1847253502Shrs link_ntoa((struct sockaddr_dl *)(void *)sa)); 18481558Srgrimes break; 1849253427Shrs#ifdef INET 18501558Srgrimes case AF_INET: 1851253427Shrs (void)printf("%s: inet %s; ", which, 1852253502Shrs inet_ntoa(((struct sockaddr_in *)(void *)sa)->sin_addr)); 18531558Srgrimes break; 1854253427Shrs#endif 1855253427Shrs#ifdef INET6 1856253427Shrs case AF_INET6: 1857253427Shrs (void)printf("%s: inet6 %s; ", which, inet_ntop(sa->sa_family, 1858253502Shrs &((struct sockaddr_in6 *)(void *)sa)->sin6_addr, nbuf, 1859253427Shrs sizeof(nbuf))); 1860253427Shrs break; 1861253427Shrs#endif 186217046Sjulian case AF_APPLETALK: 1863253427Shrs (void)printf("%s: atalk %s; ", which, 1864253502Shrs atalk_ntoa(((struct sockaddr_at *)(void *)sa)->sat_addr)); 186517046Sjulian break; 18661558Srgrimes } 1867253427Shrs (void)fflush(stdout); 18681558Srgrimes} 18691558Srgrimes 18701558Srgrimes/* States*/ 18711558Srgrimes#define VIRGIN 0 18721558Srgrimes#define GOTONE 1 18731558Srgrimes#define GOTTWO 2 18741558Srgrimes/* Inputs */ 18751558Srgrimes#define DIGIT (4*0) 18761558Srgrimes#define END (4*1) 18771558Srgrimes#define DELIM (4*2) 18781558Srgrimes 1879204406Suqsstatic void 1880253427Shrssockaddr(char *addr, struct sockaddr *sa, size_t size) 18811558Srgrimes{ 188292806Sobrien char *cp = (char *)sa; 18831558Srgrimes char *cplim = cp + size; 188492806Sobrien int byte = 0, state = VIRGIN, new = 0 /* foil gcc */; 18851558Srgrimes 188685048Sru memset(cp, 0, size); 18871558Srgrimes cp++; 18881558Srgrimes do { 18891558Srgrimes if ((*addr >= '0') && (*addr <= '9')) { 18901558Srgrimes new = *addr - '0'; 18911558Srgrimes } else if ((*addr >= 'a') && (*addr <= 'f')) { 18921558Srgrimes new = *addr - 'a' + 10; 18931558Srgrimes } else if ((*addr >= 'A') && (*addr <= 'F')) { 18941558Srgrimes new = *addr - 'A' + 10; 1895204406Suqs } else if (*addr == '\0') 18961558Srgrimes state |= END; 18971558Srgrimes else 18981558Srgrimes state |= DELIM; 18991558Srgrimes addr++; 19001558Srgrimes switch (state /* | INPUT */) { 19011558Srgrimes case GOTTWO | DIGIT: 19021558Srgrimes *cp++ = byte; /*FALLTHROUGH*/ 19031558Srgrimes case VIRGIN | DIGIT: 19041558Srgrimes state = GOTONE; byte = new; continue; 19051558Srgrimes case GOTONE | DIGIT: 19061558Srgrimes state = GOTTWO; byte = new + (byte << 4); continue; 19071558Srgrimes default: /* | DELIM */ 19081558Srgrimes state = VIRGIN; *cp++ = byte; byte = 0; continue; 19091558Srgrimes case GOTONE | END: 19101558Srgrimes case GOTTWO | END: 19111558Srgrimes *cp++ = byte; /* FALLTHROUGH */ 19121558Srgrimes case VIRGIN | END: 19131558Srgrimes break; 19141558Srgrimes } 19151558Srgrimes break; 19161558Srgrimes } while (cp < cplim); 19171558Srgrimes sa->sa_len = cp - (char *)sa; 19181558Srgrimes} 191917046Sjulian 1920204406Suqsstatic int 192117046Sjulianatalk_aton(const char *text, struct at_addr *addr) 192217046Sjulian{ 192317046Sjulian u_int net, node; 192417046Sjulian 192517046Sjulian if (sscanf(text, "%u.%u", &net, &node) != 2 192617046Sjulian || net > 0xffff || node > 0xff) 192717046Sjulian return(0); 192817254Sjulian addr->s_net = htons(net); 192917046Sjulian addr->s_node = node; 193017046Sjulian return(1); 193117046Sjulian} 193217046Sjulian 1933204406Suqsstatic char * 193417046Sjulianatalk_ntoa(struct at_addr at) 193517046Sjulian{ 193617046Sjulian static char buf[20]; 193717046Sjulian 1938253427Shrs (void)snprintf(buf, sizeof(buf), "%u.%u", ntohs(at.s_net), at.s_node); 1939253427Shrs buf[sizeof(buf) - 1] = '\0'; 194017046Sjulian return(buf); 194117046Sjulian} 1942