route.c revision 243860
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 243860 2012-12-04 11:10:01Z glebius $"); 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; 263243185Shrs char *str, *token, *endptr; 264243185Shrs int fib[2], i, error; 265243185Shrs 266243185Shrs str = strdup(arg); 267243185Shrs error = 0; 268243185Shrs i = 0; 269243185Shrs while ((token = strsep(&str, "-")) != NULL) { 270243185Shrs switch (i) { 271243185Shrs case 0: 272243185Shrs case 1: 273243185Shrs fib[i] = strtol(token, &endptr, 0); 274243185Shrs if (*endptr != '\0' || (fib[i] == 0 && 275243185Shrs (errno == EINVAL || errno == ERANGE))) 276243185Shrs error = 1; 277243185Shrs break; 278243185Shrs default: 279243185Shrs error = 1; 280243185Shrs } 281243185Shrs if (error) 282243185Shrs goto fiboptlist_range_ret; 283243185Shrs i++; 284243185Shrs } 285243185Shrs if (fib[0] >= fib[1]) { 286243185Shrs error = 1; 287243185Shrs goto fiboptlist_range_ret; 288243185Shrs } 289243185Shrs for (i = fib[0]; i <= fib[1]; i++) { 290243185Shrs fl = calloc(1, sizeof(*fl)); 291243185Shrs if (fl == NULL) { 292243185Shrs error = 1; 293243185Shrs goto fiboptlist_range_ret; 294243185Shrs } 295243185Shrs fl->fl_num = i; 296243185Shrs TAILQ_INSERT_TAIL(flh, fl, fl_next); 297243185Shrs } 298243185Shrsfiboptlist_range_ret: 299243185Shrs free(str); 300243185Shrs return (error); 301243185Shrs} 302243185Shrs 303243185Shrs#define ALLSTRLEN 64 304243185Shrsstatic int 305243185Shrsfiboptlist_csv(const char *arg, struct fibl_head_t *flh) 306243185Shrs{ 307243185Shrs struct fibl *fl; 308243185Shrs char *str, *token, *endptr; 309243185Shrs int fib, error; 310243185Shrs 311243185Shrs if (strcmp("all", arg) == 0) { 312243185Shrs str = calloc(1, ALLSTRLEN); 313243185Shrs if (str == NULL) { 314243185Shrs error = 1; 315243185Shrs goto fiboptlist_csv_ret; 316243185Shrs } 317243185Shrs if (numfibs > 1) 318243185Shrs snprintf(str, ALLSTRLEN - 1, "%d-%d", 0, numfibs - 1); 319243185Shrs else 320243185Shrs snprintf(str, ALLSTRLEN - 1, "%d", 0); 321243185Shrs } else if (strcmp("default", arg) == 0) { 322243185Shrs str = calloc(1, ALLSTRLEN); 323243185Shrs if (str == NULL) { 324243185Shrs error = 1; 325243185Shrs goto fiboptlist_csv_ret; 326243185Shrs } 327243185Shrs snprintf(str, ALLSTRLEN - 1, "%d", defaultfib); 328243185Shrs } else 329243185Shrs str = strdup(arg); 330243185Shrs 331243185Shrs error = 0; 332243185Shrs while ((token = strsep(&str, ",")) != NULL) { 333243185Shrs if (*token != '-' && strchr(token, '-') != NULL) { 334243185Shrs error = fiboptlist_range(token, flh); 335243185Shrs if (error) 336243185Shrs goto fiboptlist_csv_ret; 337243185Shrs } else { 338243185Shrs fib = strtol(token, &endptr, 0); 339243185Shrs if (*endptr != '\0' || (fib == 0 && 340243185Shrs (errno == EINVAL || errno == ERANGE))) { 341243185Shrs error = 1; 342243185Shrs goto fiboptlist_csv_ret; 343243185Shrs } 344243185Shrs fl = calloc(1, sizeof(*fl)); 345243185Shrs if (fl == NULL) { 346243185Shrs error = 1; 347243185Shrs goto fiboptlist_csv_ret; 348243185Shrs } 349243185Shrs fl->fl_num = fib; 350243185Shrs TAILQ_INSERT_TAIL(flh, fl, fl_next); 351243185Shrs } 352243185Shrs } 353243185Shrsfiboptlist_csv_ret: 354243185Shrs free(str); 355243185Shrs return (error); 356243185Shrs} 357243185Shrs 3581558Srgrimes/* 3591558Srgrimes * Purge all entries in the routing tables not 3601558Srgrimes * associated with network interfaces. 3611558Srgrimes */ 362204406Suqsstatic void 363196527Scharnierflushroutes(int argc, char *argv[]) 3641558Srgrimes{ 365243185Shrs struct fibl *fl; 366243185Shrs int error; 3671558Srgrimes 368243859Sglebius if (uid != 0 && !debugonly && !tflag) { 36913171Swollman errx(EX_NOPERM, "must be root to alter routing table"); 3701558Srgrimes } 371146079Sjmallett shutdown(s, SHUT_RD); /* Don't want to read back our messages */ 372243185Shrs 373243185Shrs TAILQ_INIT(&fibl_head); 374243185Shrs while (argc > 1) { 375243185Shrs argc--; 3761558Srgrimes argv++; 377243185Shrs if (**argv != '-') 378243185Shrs usage(*argv); 379243185Shrs switch (keyword(*argv + 1)) { 380243185Shrs case K_INET: 381243185Shrs af = AF_INET; 382243185Shrs break; 38354263Sshin#ifdef INET6 384243185Shrs case K_INET6: 385243185Shrs af = AF_INET6; 386243185Shrs break; 38754263Sshin#endif 388243185Shrs case K_ATALK: 389243185Shrs af = AF_APPLETALK; 390243185Shrs break; 391243185Shrs case K_LINK: 392243185Shrs af = AF_LINK; 393243185Shrs break; 394243185Shrs case K_FIB: 395243185Shrs if (!--argc) 396243185Shrs usage(*argv); 397243185Shrs error = fiboptlist_csv(*++argv, &fibl_head); 398243185Shrs if (error) 399243185Shrs usage(*argv); 400243185Shrs break; 401243185Shrs default: 402243185Shrs usage(*argv); 403243185Shrs } 4041558Srgrimes } 405243185Shrs if (TAILQ_EMPTY(&fibl_head)) { 406243185Shrs error = fiboptlist_csv("default", &fibl_head); 407243185Shrs if (error) 408243185Shrs errx(EX_OSERR, "fiboptlist_csv failed."); 409243185Shrs } 410243185Shrs TAILQ_FOREACH(fl, &fibl_head, fl_next) 411243185Shrs flushroutes_fib(fl->fl_num); 412243185Shrs} 413243185Shrs 414243185Shrsstatic int 415243185Shrsflushroutes_fib(int fib) 416243185Shrs{ 417243185Shrs struct rt_msghdr *rtm; 418243185Shrs size_t needed; 419243185Shrs char *buf, *next, *lim; 420243185Shrs int mib[6], rlen, seqno, count = 0; 421243185Shrs int error; 422243185Shrs 423243185Shrs error = set_sofib(fib); 424243185Shrs error += set_procfib(fib); 425243185Shrs if (error) { 426243185Shrs warn("fib number %d is ignored", fib); 427243185Shrs return (error); 428243185Shrs } 429243185Shrs 430128782Sambriskoretry: 4311558Srgrimes mib[0] = CTL_NET; 4321558Srgrimes mib[1] = PF_ROUTE; 4331558Srgrimes mib[2] = 0; /* protocol */ 4341558Srgrimes mib[3] = 0; /* wildcard address family */ 4351558Srgrimes mib[4] = NET_RT_DUMP; 4361558Srgrimes mib[5] = 0; /* no flags */ 4371558Srgrimes if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 43813171Swollman err(EX_OSERR, "route-sysctl-estimate"); 4391558Srgrimes if ((buf = malloc(needed)) == NULL) 44037907Scharnier errx(EX_OSERR, "malloc failed"); 441128782Sambrisko if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 442128782Sambrisko if (errno == ENOMEM && count++ < 10) { 443204406Suqs warnx("Routing table grew, retrying"); 444128782Sambrisko sleep(1); 445128782Sambrisko free(buf); 446128782Sambrisko goto retry; 447128782Sambrisko } 44813171Swollman err(EX_OSERR, "route-sysctl-get"); 449128782Sambrisko } 4501558Srgrimes lim = buf + needed; 4511558Srgrimes if (verbose) 4521558Srgrimes (void) printf("Examining routing table from sysctl\n"); 4531558Srgrimes seqno = 0; /* ??? */ 4541558Srgrimes for (next = buf; next < lim; next += rtm->rtm_msglen) { 4551558Srgrimes rtm = (struct rt_msghdr *)next; 4561558Srgrimes if (verbose) 4571558Srgrimes print_rtmsg(rtm, rtm->rtm_msglen); 4581558Srgrimes if ((rtm->rtm_flags & RTF_GATEWAY) == 0) 4591558Srgrimes continue; 460204406Suqs if (af != 0) { 4611558Srgrimes struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 4621558Srgrimes 4631558Srgrimes if (sa->sa_family != af) 4641558Srgrimes continue; 4651558Srgrimes } 4661558Srgrimes if (debugonly) 4671558Srgrimes continue; 4681558Srgrimes rtm->rtm_type = RTM_DELETE; 4691558Srgrimes rtm->rtm_seq = seqno; 4701558Srgrimes rlen = write(s, next, rtm->rtm_msglen); 471129034Scsjp if (rlen < 0 && errno == EPERM) 472129034Scsjp err(1, "write to routing socket"); 4731558Srgrimes if (rlen < (int)rtm->rtm_msglen) { 47413171Swollman warn("write to routing socket"); 4751558Srgrimes (void) printf("got only %d for rlen\n", rlen); 476128782Sambrisko free(buf); 477128782Sambrisko goto retry; 4781558Srgrimes break; 4791558Srgrimes } 4801558Srgrimes seqno++; 4811558Srgrimes if (qflag) 4821558Srgrimes continue; 4831558Srgrimes if (verbose) 4841558Srgrimes print_rtmsg(rtm, rlen); 4851558Srgrimes else { 4861558Srgrimes struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 487243185Shrs 488243185Shrs printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ? 4891558Srgrimes routename(sa) : netname(sa)); 490128186Sluigi sa = (struct sockaddr *)(SA_SIZE(sa) + (char *)sa); 491243185Shrs printf("%-20.20s ", routename(sa)); 492243185Shrs if (fib >= 0) 493243185Shrs printf("-fib %-3d ", fib); 494243185Shrs printf("done\n"); 4951558Srgrimes } 4961558Srgrimes } 497243185Shrs return (error); 4981558Srgrimes} 4991558Srgrimes 50078064Sumeconst char * 501196527Scharnierroutename(struct sockaddr *sa) 5021558Srgrimes{ 503204406Suqs const char *cp; 50419209Sfenner static char line[MAXHOSTNAMELEN + 1]; 5051558Srgrimes struct hostent *hp; 5061558Srgrimes static char domain[MAXHOSTNAMELEN + 1]; 50781976Sbrian static int first = 1, n; 5081558Srgrimes 5091558Srgrimes if (first) { 5101558Srgrimes first = 0; 5111558Srgrimes if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 51285048Sru (cp = strchr(domain, '.'))) { 51319209Sfenner domain[MAXHOSTNAMELEN] = '\0'; 5141558Srgrimes (void) strcpy(domain, cp + 1); 51519209Sfenner } else 5161558Srgrimes domain[0] = 0; 5171558Srgrimes } 5181558Srgrimes 5191558Srgrimes if (sa->sa_len == 0) 5201558Srgrimes strcpy(line, "default"); 5211558Srgrimes else switch (sa->sa_family) { 5221558Srgrimes 5231558Srgrimes case AF_INET: 5241558Srgrimes { struct in_addr in; 5251558Srgrimes in = ((struct sockaddr_in *)sa)->sin_addr; 5261558Srgrimes 527204406Suqs cp = NULL; 5281558Srgrimes if (in.s_addr == INADDR_ANY || sa->sa_len < 4) 5291558Srgrimes cp = "default"; 530204406Suqs if (cp == NULL && !nflag) { 5311558Srgrimes hp = gethostbyaddr((char *)&in, sizeof (struct in_addr), 5321558Srgrimes AF_INET); 533204406Suqs if (hp != NULL) { 534204406Suqs char *cptr; 535204406Suqs cptr = strchr(hp->h_name, '.'); 536204406Suqs if (cptr != NULL && 537204406Suqs strcmp(cptr + 1, domain) == 0) 538204406Suqs *cptr = '\0'; 5391558Srgrimes cp = hp->h_name; 5401558Srgrimes } 5411558Srgrimes } 542204406Suqs if (cp != NULL) { 54331958Simp strncpy(line, cp, sizeof(line) - 1); 54431958Simp line[sizeof(line) - 1] = '\0'; 54577873Sru } else 54677873Sru (void) sprintf(line, "%s", inet_ntoa(in)); 5471558Srgrimes break; 5481558Srgrimes } 5491558Srgrimes 55054263Sshin#ifdef INET6 55154263Sshin case AF_INET6: 55278064Sume { 55378064Sume struct sockaddr_in6 sin6; /* use static var for safety */ 55478064Sume int niflags = 0; 55554263Sshin 55678064Sume memset(&sin6, 0, sizeof(sin6)); 55778064Sume memcpy(&sin6, sa, sa->sa_len); 55878064Sume sin6.sin6_len = sizeof(struct sockaddr_in6); 55978064Sume sin6.sin6_family = AF_INET6; 56078064Sume if (nflag) 56178064Sume niflags |= NI_NUMERICHOST; 56278064Sume if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, 56378064Sume line, sizeof(line), NULL, 0, niflags) != 0) 56478064Sume strncpy(line, "invalid", sizeof(line)); 56578064Sume 56678064Sume return(line); 56778064Sume } 56878064Sume#endif 56978064Sume 57017046Sjulian case AF_APPLETALK: 57117046Sjulian (void) snprintf(line, sizeof(line), "atalk %s", 57217046Sjulian atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr)); 57317046Sjulian break; 57417046Sjulian 5751558Srgrimes case AF_LINK: 5761558Srgrimes return (link_ntoa((struct sockaddr_dl *)sa)); 5771558Srgrimes 5781558Srgrimes default: 579204406Suqs { 580204406Suqs u_short *sp = (u_short *)sa; 581204406Suqs u_short *splim = sp + ((sa->sa_len + 1) >> 1); 582204406Suqs char *cps = line + sprintf(line, "(%d)", sa->sa_family); 58319209Sfenner char *cpe = line + sizeof(line); 5841558Srgrimes 585204406Suqs while (++sp < splim && cps < cpe) /* start with sa->sa_data */ 586204406Suqs if ((n = snprintf(cps, cpe - cps, " %x", *sp)) > 0) 587204406Suqs cps += n; 58881980Sbrian else 589204406Suqs *cps = '\0'; 5901558Srgrimes break; 5911558Srgrimes } 5921558Srgrimes } 5931558Srgrimes return (line); 5941558Srgrimes} 5951558Srgrimes 5961558Srgrimes/* 5971558Srgrimes * Return the name of the network whose address is given. 598243019Sglebius * The address is assumed to be that of a net, not a host. 5991558Srgrimes */ 60078064Sumeconst char * 601196527Scharniernetname(struct sockaddr *sa) 6021558Srgrimes{ 603204406Suqs const char *cp = NULL; 60419209Sfenner static char line[MAXHOSTNAMELEN + 1]; 605204406Suqs struct netent *np = NULL; 60692806Sobrien u_long i; 607243019Sglebius int n; 6081558Srgrimes 6091558Srgrimes switch (sa->sa_family) { 6101558Srgrimes 6111558Srgrimes case AF_INET: 6121558Srgrimes { struct in_addr in; 6131558Srgrimes in = ((struct sockaddr_in *)sa)->sin_addr; 6141558Srgrimes 6151558Srgrimes i = in.s_addr = ntohl(in.s_addr); 6161558Srgrimes if (in.s_addr == 0) 6171558Srgrimes cp = "default"; 6181558Srgrimes else if (!nflag) { 619243019Sglebius np = getnetbyaddr(i, AF_INET); 620204406Suqs if (np != NULL) 6211558Srgrimes cp = np->n_name; 6221558Srgrimes } 62377873Sru#define C(x) (unsigned)((x) & 0xff) 624204406Suqs if (cp != NULL) 62519209Sfenner strncpy(line, cp, sizeof(line)); 6261558Srgrimes else if ((in.s_addr & 0xffffff) == 0) 6271558Srgrimes (void) sprintf(line, "%u", C(in.s_addr >> 24)); 6281558Srgrimes else if ((in.s_addr & 0xffff) == 0) 6291558Srgrimes (void) sprintf(line, "%u.%u", C(in.s_addr >> 24), 6301558Srgrimes C(in.s_addr >> 16)); 6311558Srgrimes else if ((in.s_addr & 0xff) == 0) 6321558Srgrimes (void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24), 6331558Srgrimes C(in.s_addr >> 16), C(in.s_addr >> 8)); 6341558Srgrimes else 6351558Srgrimes (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), 6361558Srgrimes C(in.s_addr >> 16), C(in.s_addr >> 8), 6371558Srgrimes C(in.s_addr)); 63877873Sru#undef C 6391558Srgrimes break; 6401558Srgrimes } 6411558Srgrimes 64254263Sshin#ifdef INET6 64354263Sshin case AF_INET6: 64478064Sume { 64578064Sume struct sockaddr_in6 sin6; /* use static var for safety */ 64678064Sume int niflags = 0; 64754263Sshin 64878064Sume memset(&sin6, 0, sizeof(sin6)); 64978064Sume memcpy(&sin6, sa, sa->sa_len); 65078064Sume sin6.sin6_len = sizeof(struct sockaddr_in6); 65178064Sume sin6.sin6_family = AF_INET6; 65278064Sume if (nflag) 65378064Sume niflags |= NI_NUMERICHOST; 65478064Sume if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, 65578064Sume line, sizeof(line), NULL, 0, niflags) != 0) 65678064Sume strncpy(line, "invalid", sizeof(line)); 65778064Sume 65878064Sume return(line); 65978064Sume } 66078064Sume#endif 66178064Sume 66217046Sjulian case AF_APPLETALK: 66317046Sjulian (void) snprintf(line, sizeof(line), "atalk %s", 66417046Sjulian atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr)); 66517046Sjulian break; 66617046Sjulian 6671558Srgrimes case AF_LINK: 6681558Srgrimes return (link_ntoa((struct sockaddr_dl *)sa)); 6691558Srgrimes 6701558Srgrimes 6711558Srgrimes default: 672204406Suqs { 673204406Suqs u_short *sp = (u_short *)sa->sa_data; 674204406Suqs u_short *splim = sp + ((sa->sa_len + 1)>>1); 675204406Suqs char *cps = line + sprintf(line, "af %d:", sa->sa_family); 67619209Sfenner char *cpe = line + sizeof(line); 6771558Srgrimes 678204406Suqs while (sp < splim && cps < cpe) 679204406Suqs if ((n = snprintf(cps, cpe - cps, " %x", *sp++)) > 0) 680204406Suqs cps += n; 68181980Sbrian else 682204406Suqs *cps = '\0'; 6831558Srgrimes break; 6841558Srgrimes } 6851558Srgrimes } 6861558Srgrimes return (line); 6871558Srgrimes} 6881558Srgrimes 689204406Suqsstatic void 690196527Scharnierset_metric(char *value, int key) 6911558Srgrimes{ 6921558Srgrimes int flag = 0; 6931558Srgrimes u_long noval, *valp = &noval; 6941558Srgrimes 6951558Srgrimes switch (key) { 6961558Srgrimes#define caseof(x, y, z) case x: valp = &rt_metrics.z; flag = y; break 6971558Srgrimes caseof(K_MTU, RTV_MTU, rmx_mtu); 6981558Srgrimes caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount); 6991558Srgrimes caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire); 7001558Srgrimes caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe); 7011558Srgrimes caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe); 7021558Srgrimes caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh); 7031558Srgrimes caseof(K_RTT, RTV_RTT, rmx_rtt); 7041558Srgrimes caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar); 705191080Skmacy caseof(K_WEIGHT, RTV_WEIGHT, rmx_weight); 7061558Srgrimes } 7071558Srgrimes rtm_inits |= flag; 7081558Srgrimes if (lockrest || locking) 7091558Srgrimes rt_metrics.rmx_locks |= flag; 7101558Srgrimes if (locking) 7111558Srgrimes locking = 0; 7121558Srgrimes *valp = atoi(value); 7131558Srgrimes} 7141558Srgrimes 715243185Shrs#define F_ISHOST 0x01 716243185Shrs#define F_FORCENET 0x02 717243185Shrs#define F_FORCEHOST 0x04 718243185Shrs#define F_PROXY 0x08 719243185Shrs#define F_INTERFACE 0x10 720243185Shrs 721204406Suqsstatic void 722196527Scharniernewroute(int argc, char **argv) 7231558Srgrimes{ 724243185Shrs struct hostent *hp; 725243185Shrs struct fibl *fl; 726204406Suqs char *cmd; 727243185Shrs const char *dest, *gateway, *errmsg; 728243185Shrs int key, error, flags, nrflags, fibnum; 7291558Srgrimes 730243859Sglebius if (uid != 0 && !debugonly && !tflag) { 73113171Swollman errx(EX_NOPERM, "must be root to alter routing table"); 7321558Srgrimes } 733243185Shrs 734243185Shrs dest = NULL; 735243185Shrs gateway = NULL; 736243185Shrs flags = RTF_STATIC; 737243185Shrs nrflags = 0; 738243185Shrs hp = NULL; 739243185Shrs TAILQ_INIT(&fibl_head); 740243185Shrs 7411558Srgrimes cmd = argv[0]; 742191080Skmacy if (*cmd != 'g' && *cmd != 's') 743146079Sjmallett shutdown(s, SHUT_RD); /* Don't want to read back our messages */ 744191080Skmacy 7451558Srgrimes while (--argc > 0) { 7461558Srgrimes if (**(++argv)== '-') { 7471558Srgrimes switch (key = keyword(1 + *argv)) { 7481558Srgrimes case K_LINK: 7491558Srgrimes af = AF_LINK; 7501558Srgrimes aflen = sizeof(struct sockaddr_dl); 7511558Srgrimes break; 7521558Srgrimes case K_INET: 7531558Srgrimes af = AF_INET; 7541558Srgrimes aflen = sizeof(struct sockaddr_in); 7551558Srgrimes break; 75654263Sshin#ifdef INET6 75754263Sshin case K_INET6: 75854263Sshin af = AF_INET6; 75954263Sshin aflen = sizeof(struct sockaddr_in6); 76054263Sshin break; 76154263Sshin#endif 76217046Sjulian case K_ATALK: 76317046Sjulian af = AF_APPLETALK; 76417046Sjulian aflen = sizeof(struct sockaddr_at); 76517046Sjulian break; 7661558Srgrimes case K_SA: 7671558Srgrimes af = PF_ROUTE; 7681558Srgrimes aflen = sizeof(union sockunion); 7691558Srgrimes break; 7701558Srgrimes case K_IFACE: 7711558Srgrimes case K_INTERFACE: 772243185Shrs nrflags |= F_INTERFACE; 7732787Spst break; 7741558Srgrimes case K_NOSTATIC: 7751558Srgrimes flags &= ~RTF_STATIC; 7761558Srgrimes break; 7771558Srgrimes case K_LOCK: 7781558Srgrimes locking = 1; 7791558Srgrimes break; 7801558Srgrimes case K_LOCKREST: 7811558Srgrimes lockrest = 1; 7821558Srgrimes break; 7831558Srgrimes case K_HOST: 784243185Shrs nrflags |= F_FORCEHOST; 7851558Srgrimes break; 7861558Srgrimes case K_REJECT: 7871558Srgrimes flags |= RTF_REJECT; 7881558Srgrimes break; 7891558Srgrimes case K_BLACKHOLE: 7901558Srgrimes flags |= RTF_BLACKHOLE; 7911558Srgrimes break; 7921558Srgrimes case K_PROTO1: 7931558Srgrimes flags |= RTF_PROTO1; 7941558Srgrimes break; 7951558Srgrimes case K_PROTO2: 7961558Srgrimes flags |= RTF_PROTO2; 7971558Srgrimes break; 79878140Sru case K_PROXY: 799243185Shrs nrflags |= F_PROXY; 80078140Sru break; 8011558Srgrimes case K_XRESOLVE: 8021558Srgrimes flags |= RTF_XRESOLVE; 8031558Srgrimes break; 8041558Srgrimes case K_STATIC: 8051558Srgrimes flags |= RTF_STATIC; 8061558Srgrimes break; 807191080Skmacy case K_STICKY: 808191080Skmacy flags |= RTF_STICKY; 809191080Skmacy break; 810191080Skmacy case K_NOSTICK: 811191080Skmacy flags &= ~RTF_STICKY; 812191080Skmacy break; 813243185Shrs case K_FIB: 814243185Shrs if (!--argc) 815243185Shrs usage(NULL); 816243185Shrs error = fiboptlist_csv(*++argv, &fibl_head); 817243185Shrs if (error) 818243185Shrs usage(NULL); 819243185Shrs break; 8201558Srgrimes case K_IFA: 82147668Sru if (!--argc) 822204406Suqs usage(NULL); 8231558Srgrimes (void) getaddr(RTA_IFA, *++argv, 0); 8241558Srgrimes break; 8251558Srgrimes case K_IFP: 82647668Sru if (!--argc) 827204406Suqs usage(NULL); 8281558Srgrimes (void) getaddr(RTA_IFP, *++argv, 0); 8291558Srgrimes break; 8301558Srgrimes case K_GENMASK: 83147668Sru if (!--argc) 832204406Suqs usage(NULL); 8331558Srgrimes (void) getaddr(RTA_GENMASK, *++argv, 0); 8341558Srgrimes break; 8351558Srgrimes case K_GATEWAY: 83647668Sru if (!--argc) 837204406Suqs usage(NULL); 8381558Srgrimes (void) getaddr(RTA_GATEWAY, *++argv, 0); 8391558Srgrimes break; 8401558Srgrimes case K_DST: 84147668Sru if (!--argc) 842204406Suqs usage(NULL); 843243185Shrs if (getaddr(RTA_DST, *++argv, &hp)) 844243185Shrs nrflags |= F_ISHOST; 8451558Srgrimes dest = *argv; 8461558Srgrimes break; 8471558Srgrimes case K_NETMASK: 84847668Sru if (!--argc) 849204406Suqs usage(NULL); 8501558Srgrimes (void) getaddr(RTA_NETMASK, *++argv, 0); 8511558Srgrimes /* FALLTHROUGH */ 8521558Srgrimes case K_NET: 853243185Shrs nrflags |= F_FORCENET; 8541558Srgrimes break; 85554263Sshin case K_PREFIXLEN: 85654263Sshin if (!--argc) 857204406Suqs usage(NULL); 85854263Sshin if (prefixlen(*++argv) == -1) { 859243185Shrs nrflags &= ~F_FORCENET; 860243185Shrs nrflags |= F_ISHOST; 86154263Sshin } else { 862243185Shrs nrflags |= F_FORCENET; 863243185Shrs nrflags &= ~F_ISHOST; 86454263Sshin } 86554263Sshin break; 8661558Srgrimes case K_MTU: 8671558Srgrimes case K_HOPCOUNT: 8681558Srgrimes case K_EXPIRE: 8691558Srgrimes case K_RECVPIPE: 8701558Srgrimes case K_SENDPIPE: 8711558Srgrimes case K_SSTHRESH: 8721558Srgrimes case K_RTT: 8731558Srgrimes case K_RTTVAR: 874191080Skmacy case K_WEIGHT: 87547668Sru if (!--argc) 876204406Suqs usage(NULL); 8771558Srgrimes set_metric(*++argv, key); 8781558Srgrimes break; 8791558Srgrimes default: 8801558Srgrimes usage(1+*argv); 8811558Srgrimes } 8821558Srgrimes } else { 8831558Srgrimes if ((rtm_addrs & RTA_DST) == 0) { 8841558Srgrimes dest = *argv; 885243185Shrs if (getaddr(RTA_DST, *argv, &hp)) 886243185Shrs nrflags |= F_ISHOST; 8871558Srgrimes } else if ((rtm_addrs & RTA_GATEWAY) == 0) { 8881558Srgrimes gateway = *argv; 8891558Srgrimes (void) getaddr(RTA_GATEWAY, *argv, &hp); 8901558Srgrimes } else { 8911558Srgrimes (void) getaddr(RTA_NETMASK, *argv, 0); 892243185Shrs nrflags |= F_FORCENET; 8931558Srgrimes } 8941558Srgrimes } 8951558Srgrimes } 896243185Shrs 897243185Shrs if (nrflags & F_FORCEHOST) { 898243185Shrs nrflags |= F_ISHOST; 89954263Sshin#ifdef INET6 90054263Sshin if (af == AF_INET6) { 90154263Sshin rtm_addrs &= ~RTA_NETMASK; 902204406Suqs memset((void *)&so_mask, 0, sizeof(so_mask)); 90354263Sshin } 904204406Suqs#endif 90554263Sshin } 906243185Shrs if (nrflags & F_FORCENET) 907243185Shrs nrflags &= ~F_ISHOST; 9081558Srgrimes flags |= RTF_UP; 909243185Shrs if (nrflags & F_ISHOST) 9101558Srgrimes flags |= RTF_HOST; 911243185Shrs if ((nrflags & F_INTERFACE) == 0) 9121558Srgrimes flags |= RTF_GATEWAY; 913243185Shrs if (nrflags & F_PROXY) { 91478140Sru so_dst.sinarp.sin_other = SIN_PROXY; 91578140Sru flags |= RTF_ANNOUNCE; 91678140Sru } 917243185Shrs if (dest == NULL) 918243185Shrs dest = ""; 919243185Shrs if (gateway == NULL) 920243185Shrs gateway = ""; 921243185Shrs 922243185Shrs if (TAILQ_EMPTY(&fibl_head)) { 923243185Shrs error = fiboptlist_csv("default", &fibl_head); 924243185Shrs if (error) 925243185Shrs errx(EX_OSERR, "fiboptlist_csv failed."); 9261558Srgrimes } 927243185Shrs error = 0; 928243185Shrs TAILQ_FOREACH(fl, &fibl_head, fl_next) { 929243185Shrs fl->fl_error = newroute_fib(fl->fl_num, cmd, flags); 930243185Shrs if (fl->fl_error) 931243185Shrs fl->fl_errno = errno; 932243185Shrs error += fl->fl_error; 933243185Shrs } 934191080Skmacy if (*cmd == 'g' || *cmd == 's') 935243185Shrs exit(error); 936243185Shrs 937243185Shrs error = 0; 93897278Sru if (!qflag) { 939243185Shrs fibnum = 0; 940243185Shrs TAILQ_FOREACH(fl, &fibl_head, fl_next) { 941243185Shrs if (fl->fl_error == 0) 942243185Shrs fibnum++; 9431558Srgrimes } 944243185Shrs if (fibnum > 0) { 945243185Shrs int firstfib = 1; 946243185Shrs 947243185Shrs printf("%s %s %s", cmd, 948243185Shrs (nrflags & F_ISHOST) ? "host" : "net", dest); 949243185Shrs if (*gateway) 950243185Shrs printf(": gateway %s", gateway); 951243185Shrs 952243185Shrs if (numfibs > 1) { 953243185Shrs TAILQ_FOREACH(fl, &fibl_head, fl_next) { 954243185Shrs if (fl->fl_error == 0 955243185Shrs && fl->fl_num >= 0) { 956243185Shrs if (firstfib) { 957243185Shrs printf(" fib "); 958243185Shrs firstfib = 0; 959243185Shrs } 960243185Shrs printf("%d", fl->fl_num); 961243185Shrs if (fibnum-- > 1) 962243185Shrs printf(","); 963243185Shrs } 964243185Shrs } 96597278Sru } 966243185Shrs printf("\n"); 96797278Sru } 968243185Shrs 969243185Shrs fibnum = 0; 970243185Shrs TAILQ_FOREACH(fl, &fibl_head, fl_next) { 971243185Shrs if (fl->fl_error != 0) { 972243185Shrs printf("%s %s %s", cmd, (nrflags & F_ISHOST) 973243185Shrs ? "host" : "net", dest); 974243185Shrs if (*gateway) 975243185Shrs printf(": gateway %s", gateway); 976243185Shrs 977243185Shrs if (fl->fl_num >= 0) 978243185Shrs printf(" fib %d", fl->fl_num); 979243185Shrs 980243185Shrs switch (fl->fl_errno) { 981243185Shrs case ESRCH: 982243185Shrs errmsg = "not in table"; 983243185Shrs break; 984243185Shrs case EBUSY: 985243185Shrs errmsg = "entry in use"; 986243185Shrs break; 987243185Shrs case ENOBUFS: 988243185Shrs errmsg = "not enough memory"; 989243185Shrs break; 990243185Shrs case EADDRINUSE: 991243185Shrs /* 992243185Shrs * handle recursion avoidance 993243185Shrs * in rt_setgate() 994243185Shrs */ 995243185Shrs errmsg = "gateway uses the same route"; 996243185Shrs break; 997243185Shrs case EEXIST: 998243185Shrs errmsg = "route already in table"; 999243185Shrs break; 1000243185Shrs default: 1001243185Shrs errmsg = strerror(fl->fl_errno); 1002243185Shrs break; 1003243185Shrs } 1004243185Shrs printf(": %s\n", errmsg); 1005243185Shrs error = 1; 1006243185Shrs } 1007243185Shrs } 10081558Srgrimes } 1009243185Shrs exit(error); 10101558Srgrimes} 10111558Srgrimes 1012243185Shrsstatic int 1013243185Shrsnewroute_fib(int fib, char *cmd, int flags) 1014243185Shrs{ 1015243185Shrs int error; 1016243185Shrs 1017243185Shrs error = set_sofib(fib); 1018243185Shrs if (error) { 1019243185Shrs warn("fib number %d is ignored", fib); 1020243185Shrs return (error); 1021243185Shrs } 1022243185Shrs 1023243185Shrs error = rtmsg(*cmd, flags, fib); 1024243185Shrs return (error); 1025243185Shrs} 1026243185Shrs 1027204406Suqsstatic void 1028196527Scharnierinet_makenetandmask(u_long net, struct sockaddr_in *sin, u_long bits) 10291558Srgrimes{ 1030243019Sglebius u_long mask = 0; 103192806Sobrien char *cp; 10321558Srgrimes 10331558Srgrimes rtm_addrs |= RTA_NETMASK; 1034243019Sglebius 1035204406Suqs /* 1036204406Suqs * If no /xx was specified we must calculate the 1037190758Srrs * CIDR address. 1038190758Srrs */ 1039243019Sglebius if ((bits == 0) && (net != 0)) { 1040190775Srrs u_long i, j; 1041190775Srrs for(i=0,j=0xff; i<4; i++) { 1042243019Sglebius if (net & j) { 1043190758Srrs break; 1044190758Srrs } 1045190775Srrs j <<= 8; 1046190758Srrs } 1047190758Srrs /* i holds the first non zero bit */ 1048190775Srrs bits = 32 - (i*8); 1049190758Srrs } 1050190913Srrs if (bits != 0) 1051190913Srrs mask = 0xffffffff << (32 - bits); 1052173124Smtm 1053243019Sglebius sin->sin_addr.s_addr = htonl(net); 10541558Srgrimes sin = &so_mask.sin; 10551558Srgrimes sin->sin_addr.s_addr = htonl(mask); 10561558Srgrimes sin->sin_len = 0; 10571558Srgrimes sin->sin_family = 0; 10581558Srgrimes cp = (char *)(&sin->sin_addr + 1); 10591558Srgrimes while (*--cp == 0 && cp > (char *)sin) 10601558Srgrimes ; 10611558Srgrimes sin->sin_len = 1 + cp - (char *)sin; 10621558Srgrimes} 10631558Srgrimes 106496997Sume#ifdef INET6 10651558Srgrimes/* 106696997Sume * XXX the function may need more improvement... 106796997Sume */ 106897062Sumestatic int 1069204406Suqsinet6_makenetandmask(struct sockaddr_in6 *sin6, const char *plen) 107096997Sume{ 107196997Sume struct in6_addr in6; 107296997Sume 1073204406Suqs if (plen == NULL) { 107497073Sume if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && 107597073Sume sin6->sin6_scope_id == 0) { 107697073Sume plen = "0"; 107797073Sume } else if ((sin6->sin6_addr.s6_addr[0] & 0xe0) == 0x20) { 107897073Sume /* aggregatable global unicast - RFC2374 */ 107997073Sume memset(&in6, 0, sizeof(in6)); 108097073Sume if (!memcmp(&sin6->sin6_addr.s6_addr[8], 108197073Sume &in6.s6_addr[8], 8)) 108297073Sume plen = "64"; 108397073Sume } 108496997Sume } 108596997Sume 1086204406Suqs if (plen == NULL || strcmp(plen, "128") == 0) 1087204406Suqs return (1); 108898053Sume rtm_addrs |= RTA_NETMASK; 1089204406Suqs prefixlen(plen); 1090204406Suqs return (0); 109196997Sume} 109296997Sume#endif 109396997Sume 109496997Sume/* 10951558Srgrimes * Interpret an argument as a network address of some kind, 10961558Srgrimes * returning 1 if a host address, 0 if a network address. 10971558Srgrimes */ 1098204406Suqsstatic int 1099204406Suqsgetaddr(int which, char *str, struct hostent **hpp) 11001558Srgrimes{ 110192806Sobrien sup su; 11021558Srgrimes struct hostent *hp; 11031558Srgrimes struct netent *np; 11041558Srgrimes u_long val; 110566449Sru char *q; 110654263Sshin int afamily; /* local copy of af so we can change it */ 11071558Srgrimes 11081558Srgrimes if (af == 0) { 11091558Srgrimes af = AF_INET; 11101558Srgrimes aflen = sizeof(struct sockaddr_in); 11111558Srgrimes } 111254263Sshin afamily = af; 11131558Srgrimes rtm_addrs |= which; 11141558Srgrimes switch (which) { 11151558Srgrimes case RTA_DST: 11161558Srgrimes su = &so_dst; 11171558Srgrimes break; 11181558Srgrimes case RTA_GATEWAY: 11191558Srgrimes su = &so_gate; 112017486Sjulian if (iflag) { 112178064Sume struct ifaddrs *ifap, *ifa; 112278064Sume struct sockaddr_dl *sdl = NULL; 112317486Sjulian 112478064Sume if (getifaddrs(&ifap)) 112578064Sume err(1, "getifaddrs"); 112617486Sjulian 1127204406Suqs for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 112878064Sume if (ifa->ifa_addr->sa_family != AF_LINK) 112978064Sume continue; 113017486Sjulian 1131204406Suqs if (strcmp(str, ifa->ifa_name) != 0) 113278064Sume continue; 113378064Sume 113478064Sume sdl = (struct sockaddr_dl *)ifa->ifa_addr; 113517486Sjulian } 113617486Sjulian /* If we found it, then use it */ 1137204406Suqs if (sdl != NULL) { 113878064Sume /* 113978064Sume * Copy is safe since we have a 114078064Sume * sockaddr_storage member in sockunion{}. 114178064Sume * Note that we need to copy before calling 114278064Sume * freeifaddrs(). 114378064Sume */ 114478064Sume memcpy(&su->sdl, sdl, sdl->sdl_len); 114578064Sume } 114678064Sume freeifaddrs(ifap); 1147204406Suqs if (sdl != NULL) 114817486Sjulian return(1); 114917486Sjulian } 11501558Srgrimes break; 11511558Srgrimes case RTA_NETMASK: 11521558Srgrimes su = &so_mask; 11531558Srgrimes break; 11541558Srgrimes case RTA_GENMASK: 11551558Srgrimes su = &so_genmask; 11561558Srgrimes break; 11571558Srgrimes case RTA_IFP: 11581558Srgrimes su = &so_ifp; 115954263Sshin afamily = AF_LINK; 11601558Srgrimes break; 11611558Srgrimes case RTA_IFA: 11621558Srgrimes su = &so_ifa; 11631558Srgrimes break; 11641558Srgrimes default: 116537907Scharnier usage("internal error"); 11661558Srgrimes /*NOTREACHED*/ 11671558Srgrimes } 11681558Srgrimes su->sa.sa_len = aflen; 116954263Sshin su->sa.sa_family = afamily; /* cases that don't want it have left already */ 1170204406Suqs if (strcmp(str, "default") == 0) { 117127500Sjulian /* 1172204406Suqs * Default is net 0.0.0.0/0 117327500Sjulian */ 11741558Srgrimes switch (which) { 11751558Srgrimes case RTA_DST: 11761558Srgrimes forcenet++; 117797637Swollman#if 0 117897637Swollman bzero(su, sizeof(*su)); /* for readability */ 117997637Swollman#endif 1180204406Suqs getaddr(RTA_NETMASK, str, 0); 11811558Srgrimes break; 118297637Swollman#if 0 11831558Srgrimes case RTA_NETMASK: 11841558Srgrimes case RTA_GENMASK: 118597637Swollman bzero(su, sizeof(*su)); /* for readability */ 118697637Swollman#endif 11871558Srgrimes } 11881558Srgrimes return (0); 11891558Srgrimes } 119054263Sshin switch (afamily) { 119154263Sshin#ifdef INET6 119254263Sshin case AF_INET6: 119378064Sume { 119457108Sshin struct addrinfo hints, *res; 1195146546Sume int ecode; 119657108Sshin 119797073Sume q = NULL; 1198204406Suqs if (which == RTA_DST && (q = strchr(str, '/')) != NULL) 119997073Sume *q = '\0'; 120078064Sume memset(&hints, 0, sizeof(hints)); 120178064Sume hints.ai_family = afamily; /*AF_INET6*/ 120278064Sume hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 1203204406Suqs ecode = getaddrinfo(str, NULL, &hints, &res); 1204146546Sume if (ecode != 0 || res->ai_family != AF_INET6 || 120578064Sume res->ai_addrlen != sizeof(su->sin6)) { 1206204406Suqs (void) fprintf(stderr, "%s: %s\n", str, 1207146546Sume gai_strerror(ecode)); 120854263Sshin exit(1); 120954263Sshin } 121078064Sume memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6)); 121197062Sume freeaddrinfo(res); 121297073Sume if (q != NULL) 121397073Sume *q++ = '/'; 121496997Sume if (which == RTA_DST) 121598053Sume return (inet6_makenetandmask(&su->sin6, q)); 121678064Sume return (0); 121778064Sume } 121878064Sume#endif /* INET6 */ 121954263Sshin 122017046Sjulian case AF_APPLETALK: 1221204406Suqs if (!atalk_aton(str, &su->sat.sat_addr)) 1222204406Suqs errx(EX_NOHOST, "bad address: %s", str); 122317265Sjulian rtm_addrs |= RTA_NETMASK; 122417265Sjulian return(forcehost || su->sat.sat_addr.s_node != 0); 122517046Sjulian 12261558Srgrimes case AF_LINK: 1227204406Suqs link_addr(str, &su->sdl); 12281558Srgrimes return (1); 12291558Srgrimes 12301558Srgrimes 12311558Srgrimes case PF_ROUTE: 12321558Srgrimes su->sa.sa_len = sizeof(*su); 1233204406Suqs sockaddr(str, &su->sa); 12341558Srgrimes return (1); 12351558Srgrimes 12361558Srgrimes case AF_INET: 12371558Srgrimes default: 12381558Srgrimes break; 12391558Srgrimes } 12401558Srgrimes 12411558Srgrimes if (hpp == NULL) 12421558Srgrimes hpp = &hp; 12431558Srgrimes *hpp = NULL; 124424558Sphk 1245204406Suqs q = strchr(str,'/'); 1246204406Suqs if (q != NULL && which == RTA_DST) { 124724558Sphk *q = '\0'; 1248204406Suqs if ((val = inet_network(str)) != INADDR_NONE) { 124924558Sphk inet_makenetandmask( 125077904Sru val, &su->sin, strtoul(q+1, 0, 0)); 125124558Sphk return (0); 125224558Sphk } 125366449Sru *q = '/'; 125424558Sphk } 125566449Sru if ((which != RTA_DST || forcenet == 0) && 1256204406Suqs inet_aton(str, &su->sin.sin_addr)) { 125779588Sru val = su->sin.sin_addr.s_addr; 1258130569Sbms if (which != RTA_DST || forcehost || 125966449Sru inet_lnaof(su->sin.sin_addr) != INADDR_ANY) 12601558Srgrimes return (1); 12611558Srgrimes else { 12621558Srgrimes val = ntohl(val); 12631558Srgrimes goto netdone; 12641558Srgrimes } 12651558Srgrimes } 126666449Sru if (which == RTA_DST && forcehost == 0 && 1267204406Suqs ((val = inet_network(str)) != INADDR_NONE || 1268204406Suqs ((np = getnetbyname(str)) != NULL && (val = np->n_net) != 0))) { 12691558Srgrimesnetdone: 127066449Sru inet_makenetandmask(val, &su->sin, 0); 12711558Srgrimes return (0); 12721558Srgrimes } 1273204406Suqs hp = gethostbyname(str); 1274204406Suqs if (hp != NULL) { 12751558Srgrimes *hpp = hp; 12761558Srgrimes su->sin.sin_family = hp->h_addrtype; 127785048Sru memmove((char *)&su->sin.sin_addr, hp->h_addr, 1278204406Suqs MIN((size_t)hp->h_length, sizeof(su->sin.sin_addr))); 12791558Srgrimes return (1); 12801558Srgrimes } 1281204406Suqs errx(EX_NOHOST, "bad address: %s", str); 12821558Srgrimes} 12831558Srgrimes 1284204406Suqsstatic int 1285204406Suqsprefixlen(const char *str) 128654263Sshin{ 1287204406Suqs int len = atoi(str), q, r; 128854263Sshin int max; 128954263Sshin char *p; 12901558Srgrimes 129154263Sshin rtm_addrs |= RTA_NETMASK; 129254263Sshin switch (af) { 129354263Sshin#ifdef INET6 129454263Sshin case AF_INET6: 129554263Sshin max = 128; 129654263Sshin p = (char *)&so_mask.sin6.sin6_addr; 129754263Sshin break; 129854263Sshin#endif 129954263Sshin case AF_INET: 130054263Sshin max = 32; 130154263Sshin p = (char *)&so_mask.sin.sin_addr; 130254263Sshin break; 130354263Sshin default: 1304204406Suqs fprintf(stderr, "prefixlen not supported in this af\n"); 130554263Sshin exit(1); 130654263Sshin } 130754263Sshin 130854263Sshin if (len < 0 || max < len) { 1309204406Suqs fprintf(stderr, "%s: bad value\n", str); 131054263Sshin exit(1); 131154263Sshin } 131254263Sshin 131354263Sshin q = len >> 3; 131454263Sshin r = len & 7; 131554263Sshin so_mask.sa.sa_family = af; 131654263Sshin so_mask.sa.sa_len = aflen; 131754263Sshin memset((void *)p, 0, max / 8); 131854263Sshin if (q > 0) 131954263Sshin memset((void *)p, 0xff, q); 132054263Sshin if (r > 0) 132154263Sshin *((u_char *)p + q) = (0xff00 >> r) & 0xff; 132254263Sshin if (len == max) 1323204406Suqs return (-1); 132454263Sshin else 1325204406Suqs return (len); 132654263Sshin} 132754263Sshin 1328204406Suqsstatic void 1329196527Scharnierinterfaces(void) 13301558Srgrimes{ 13311558Srgrimes size_t needed; 13321558Srgrimes int mib[6]; 1333128782Sambrisko char *buf, *lim, *next, count = 0; 133492806Sobrien struct rt_msghdr *rtm; 13351558Srgrimes 1336128782Sambriskoretry2: 13371558Srgrimes mib[0] = CTL_NET; 13381558Srgrimes mib[1] = PF_ROUTE; 13391558Srgrimes mib[2] = 0; /* protocol */ 13401558Srgrimes mib[3] = 0; /* wildcard address family */ 13411558Srgrimes mib[4] = NET_RT_IFLIST; 13421558Srgrimes mib[5] = 0; /* no flags */ 13431558Srgrimes if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 134413171Swollman err(EX_OSERR, "route-sysctl-estimate"); 13451558Srgrimes if ((buf = malloc(needed)) == NULL) 134637907Scharnier errx(EX_OSERR, "malloc failed"); 1347128782Sambrisko if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 1348128782Sambrisko if (errno == ENOMEM && count++ < 10) { 1349128782Sambrisko warnx("Routing table grew, retrying"); 1350128782Sambrisko sleep(1); 1351128782Sambrisko free(buf); 1352128782Sambrisko goto retry2; 1353128782Sambrisko } 135413171Swollman err(EX_OSERR, "actual retrieval of interface table"); 1355128782Sambrisko } 13561558Srgrimes lim = buf + needed; 13571558Srgrimes for (next = buf; next < lim; next += rtm->rtm_msglen) { 13581558Srgrimes rtm = (struct rt_msghdr *)next; 13591558Srgrimes print_rtmsg(rtm, rtm->rtm_msglen); 13601558Srgrimes } 13611558Srgrimes} 13621558Srgrimes 1363204406Suqsstatic void 1364243185Shrsmonitor(int argc, char *argv[]) 13651558Srgrimes{ 1366243185Shrs int n, fib, error; 1367243185Shrs char msg[2048], *endptr; 13681558Srgrimes 1369243185Shrs fib = defaultfib; 1370243185Shrs while (argc > 1) { 1371243185Shrs argc--; 1372243185Shrs argv++; 1373243185Shrs if (**argv != '-') 1374243185Shrs usage(*argv); 1375243185Shrs switch (keyword(*argv + 1)) { 1376243185Shrs case K_FIB: 1377243185Shrs if (!--argc) 1378243185Shrs usage(*argv); 1379243185Shrs fib = strtol(*++argv, &endptr, 0); 1380243185Shrs if (*endptr != '\0' || (fib == 0 && 1381243185Shrs (errno == EINVAL || errno == ERANGE))) 1382243185Shrs usage(*argv); 1383243185Shrs break; 1384243185Shrs default: 1385243185Shrs usage(*argv); 1386243185Shrs } 1387243185Shrs } 1388243185Shrs error = set_sofib(fib); 1389243185Shrs if (error) 1390243185Shrs errx(EX_USAGE, "invalid fib number: %d", fib); 1391243185Shrs 13921558Srgrimes verbose = 1; 13931558Srgrimes if (debugonly) { 13941558Srgrimes interfaces(); 13951558Srgrimes exit(0); 13961558Srgrimes } 1397204406Suqs for (;;) { 139854263Sshin time_t now; 13991558Srgrimes n = read(s, msg, 2048); 140054263Sshin now = time(NULL); 140171061Sphk (void) printf("\ngot message of size %d on %s", n, ctime(&now)); 14021558Srgrimes print_rtmsg((struct rt_msghdr *)msg, n); 14031558Srgrimes } 14041558Srgrimes} 14051558Srgrimes 14061558Srgrimesstruct { 14071558Srgrimes struct rt_msghdr m_rtm; 14081558Srgrimes char m_space[512]; 14091558Srgrimes} m_rtmsg; 14101558Srgrimes 1411204406Suqsstatic int 1412243185Shrsrtmsg(int cmd, int flags, int fib) 14131558Srgrimes{ 14141558Srgrimes static int seq; 14151558Srgrimes int rlen; 141692806Sobrien char *cp = m_rtmsg.m_space; 141792806Sobrien int l; 14181558Srgrimes 14191558Srgrimes#define NEXTADDR(w, u) \ 14201558Srgrimes if (rtm_addrs & (w)) {\ 1421128186Sluigi l = SA_SIZE(&(u.sa)); memmove(cp, &(u), l); cp += l;\ 1422178065Sru if (verbose) sodump(&(u),#u);\ 14231558Srgrimes } 14241558Srgrimes 14251558Srgrimes errno = 0; 142685048Sru memset(&m_rtmsg, 0, sizeof(m_rtmsg)); 14271558Srgrimes if (cmd == 'a') 14281558Srgrimes cmd = RTM_ADD; 14291558Srgrimes else if (cmd == 'c') 14301558Srgrimes cmd = RTM_CHANGE; 1431191080Skmacy else if (cmd == 'g' || cmd == 's') { 14321558Srgrimes cmd = RTM_GET; 14331558Srgrimes if (so_ifp.sa.sa_family == 0) { 143413171Swollman so_ifp.sa.sa_family = AF_LINK; 143513171Swollman so_ifp.sa.sa_len = sizeof(struct sockaddr_dl); 14361558Srgrimes rtm_addrs |= RTA_IFP; 14371558Srgrimes } 14381558Srgrimes } else 14391558Srgrimes cmd = RTM_DELETE; 14401558Srgrimes#define rtm m_rtmsg.m_rtm 14411558Srgrimes rtm.rtm_type = cmd; 14421558Srgrimes rtm.rtm_flags = flags; 14431558Srgrimes rtm.rtm_version = RTM_VERSION; 14441558Srgrimes rtm.rtm_seq = ++seq; 14451558Srgrimes rtm.rtm_addrs = rtm_addrs; 14461558Srgrimes rtm.rtm_rmx = rt_metrics; 14471558Srgrimes rtm.rtm_inits = rtm_inits; 14481558Srgrimes 14491558Srgrimes if (rtm_addrs & RTA_NETMASK) 14501558Srgrimes mask_addr(); 14511558Srgrimes NEXTADDR(RTA_DST, so_dst); 14521558Srgrimes NEXTADDR(RTA_GATEWAY, so_gate); 14531558Srgrimes NEXTADDR(RTA_NETMASK, so_mask); 14541558Srgrimes NEXTADDR(RTA_GENMASK, so_genmask); 14551558Srgrimes NEXTADDR(RTA_IFP, so_ifp); 14561558Srgrimes NEXTADDR(RTA_IFA, so_ifa); 14571558Srgrimes rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; 14581558Srgrimes if (verbose) 14591558Srgrimes print_rtmsg(&rtm, l); 14601558Srgrimes if (debugonly) 14611558Srgrimes return (0); 14621558Srgrimes if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { 1463129034Scsjp if (errno == EPERM) 1464129034Scsjp err(1, "writing to routing socket"); 146537907Scharnier warn("writing to routing socket"); 14661558Srgrimes return (-1); 14671558Srgrimes } 14681558Srgrimes if (cmd == RTM_GET) { 14691558Srgrimes do { 14701558Srgrimes l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); 14711558Srgrimes } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid)); 14721558Srgrimes if (l < 0) 147313171Swollman warn("read from routing socket"); 14741558Srgrimes else 1475243185Shrs print_getmsg(&rtm, l, fib); 14761558Srgrimes } 14771558Srgrimes#undef rtm 14781558Srgrimes return (0); 14791558Srgrimes} 14801558Srgrimes 1481204406Suqsstatic void 1482196527Scharniermask_addr(void) 14831558Srgrimes{ 14841558Srgrimes int olen = so_mask.sa.sa_len; 148592806Sobrien char *cp1 = olen + (char *)&so_mask, *cp2; 14861558Srgrimes 14871558Srgrimes for (so_mask.sa.sa_len = 0; cp1 > (char *)&so_mask; ) 14881558Srgrimes if (*--cp1 != 0) { 14891558Srgrimes so_mask.sa.sa_len = 1 + cp1 - (char *)&so_mask; 14901558Srgrimes break; 14911558Srgrimes } 14921558Srgrimes if ((rtm_addrs & RTA_DST) == 0) 14931558Srgrimes return; 14941558Srgrimes switch (so_dst.sa.sa_family) { 14951558Srgrimes case AF_INET: 149654263Sshin#ifdef INET6 149754263Sshin case AF_INET6: 149854263Sshin#endif 149917046Sjulian case AF_APPLETALK: 15001558Srgrimes case 0: 15011558Srgrimes return; 15021558Srgrimes } 15031558Srgrimes cp1 = so_mask.sa.sa_len + 1 + (char *)&so_dst; 15041558Srgrimes cp2 = so_dst.sa.sa_len + 1 + (char *)&so_dst; 15051558Srgrimes while (cp2 > cp1) 15061558Srgrimes *--cp2 = 0; 15071558Srgrimes cp2 = so_mask.sa.sa_len + 1 + (char *)&so_mask; 15081558Srgrimes while (cp1 > so_dst.sa.sa_data) 15091558Srgrimes *--cp1 &= *--cp2; 15101558Srgrimes} 15111558Srgrimes 1512204406Suqsconst char *msgtypes[] = { 15131558Srgrimes "", 15141558Srgrimes "RTM_ADD: Add Route", 15151558Srgrimes "RTM_DELETE: Delete Route", 15161558Srgrimes "RTM_CHANGE: Change Metrics or flags", 15171558Srgrimes "RTM_GET: Report Metrics", 15181558Srgrimes "RTM_LOSING: Kernel Suspects Partitioning", 15191558Srgrimes "RTM_REDIRECT: Told to use different route", 15201558Srgrimes "RTM_MISS: Lookup failed on this address", 15211558Srgrimes "RTM_LOCK: fix specified metrics", 15221558Srgrimes "RTM_OLDADD: caused by SIOCADDRT", 15231558Srgrimes "RTM_OLDDEL: caused by SIOCDELRT", 15241558Srgrimes "RTM_RESOLVE: Route created by cloning", 15251558Srgrimes "RTM_NEWADDR: address being added to iface", 15261558Srgrimes "RTM_DELADDR: address being removed from iface", 15271558Srgrimes "RTM_IFINFO: iface status change", 152821465Swollman "RTM_NEWMADDR: new multicast group membership on iface", 152921465Swollman "RTM_DELMADDR: multicast group membership removed from iface", 153089498Sru "RTM_IFANNOUNCE: interface arrival/departure", 1531216296Sglebius "RTM_IEEE80211: IEEE 802.11 wireless event", 15321558Srgrimes}; 15331558Srgrimes 15341558Srgrimeschar metricnames[] = 1535191080Skmacy"\011weight\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire" 153615690Swollman"\1mtu"; 15371558Srgrimeschar routeflags[] = 1538191080Skmacy"\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE" 1539191080Skmacy"\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE" 1540191080Skmacy"\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3" 1541191080Skmacy"\025PINNED\026LOCAL\027BROADCAST\030MULTICAST\035STICKY"; 15421558Srgrimeschar ifnetflags[] = 154315690Swollman"\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP" 154415690Swollman"\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1" 154515690Swollman"\017LINK2\020MULTICAST"; 15461558Srgrimeschar addrnames[] = 15471558Srgrimes"\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD"; 15481558Srgrimes 1549216297Sglebiusstatic const char errfmt[] = 1550216297Sglebius"\n%s: truncated route message, only %zu bytes left\n"; 1551216297Sglebius 1552204406Suqsstatic void 1553216297Sglebiusprint_rtmsg(struct rt_msghdr *rtm, size_t msglen) 15541558Srgrimes{ 15551558Srgrimes struct if_msghdr *ifm; 15561558Srgrimes struct ifa_msghdr *ifam; 155721465Swollman#ifdef RTM_NEWMADDR 155821465Swollman struct ifma_msghdr *ifmam; 155921465Swollman#endif 156089498Sru struct if_announcemsghdr *ifan; 1561204406Suqs const char *state; 15621558Srgrimes 15631558Srgrimes if (verbose == 0) 15641558Srgrimes return; 15651558Srgrimes if (rtm->rtm_version != RTM_VERSION) { 15661558Srgrimes (void) printf("routing message version %d not understood\n", 15671558Srgrimes rtm->rtm_version); 15681558Srgrimes return; 15691558Srgrimes } 1570216297Sglebius if (rtm->rtm_type < sizeof(msgtypes) / sizeof(msgtypes[0])) 157189498Sru (void)printf("%s: ", msgtypes[rtm->rtm_type]); 157289498Sru else 1573216297Sglebius (void)printf("unknown type %d: ", rtm->rtm_type); 157489498Sru (void)printf("len %d, ", rtm->rtm_msglen); 1575216297Sglebius 1576216297Sglebius#define REQUIRE(x) do { \ 1577216297Sglebius if (msglen < sizeof(x)) \ 1578216297Sglebius goto badlen; \ 1579216297Sglebius else \ 1580216297Sglebius msglen -= sizeof(x); \ 1581216297Sglebius } while (0) 1582216297Sglebius 15831558Srgrimes switch (rtm->rtm_type) { 15841558Srgrimes case RTM_IFINFO: 1585216297Sglebius REQUIRE(struct if_msghdr); 15861558Srgrimes ifm = (struct if_msghdr *)rtm; 1587128878Sandre (void) printf("if# %d, ", ifm->ifm_index); 1588128878Sandre switch (ifm->ifm_data.ifi_link_state) { 1589128878Sandre case LINK_STATE_DOWN: 1590128878Sandre state = "down"; 1591128878Sandre break; 1592128878Sandre case LINK_STATE_UP: 1593128878Sandre state = "up"; 1594128878Sandre break; 1595128878Sandre default: 1596128878Sandre state = "unknown"; 1597128878Sandre break; 1598128878Sandre } 1599128878Sandre (void) printf("link: %s, flags:", state); 16001558Srgrimes bprintf(stdout, ifm->ifm_flags, ifnetflags); 1601216297Sglebius pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs, msglen); 16021558Srgrimes break; 16031558Srgrimes case RTM_NEWADDR: 16041558Srgrimes case RTM_DELADDR: 1605216297Sglebius REQUIRE(struct ifa_msghdr); 16061558Srgrimes ifam = (struct ifa_msghdr *)rtm; 16071558Srgrimes (void) printf("metric %d, flags:", ifam->ifam_metric); 16081558Srgrimes bprintf(stdout, ifam->ifam_flags, routeflags); 1609216297Sglebius pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs, msglen); 16101558Srgrimes break; 161121465Swollman#ifdef RTM_NEWMADDR 161221465Swollman case RTM_NEWMADDR: 161321465Swollman case RTM_DELMADDR: 1614216297Sglebius REQUIRE(struct ifma_msghdr); 161521465Swollman ifmam = (struct ifma_msghdr *)rtm; 1616216297Sglebius pmsg_addrs((char *)(ifmam + 1), ifmam->ifmam_addrs, msglen); 161721465Swollman break; 161821465Swollman#endif 161989498Sru case RTM_IFANNOUNCE: 1620216297Sglebius REQUIRE(struct if_announcemsghdr); 162189498Sru ifan = (struct if_announcemsghdr *)rtm; 162289498Sru (void) printf("if# %d, what: ", ifan->ifan_index); 162389498Sru switch (ifan->ifan_what) { 162489498Sru case IFAN_ARRIVAL: 162589498Sru printf("arrival"); 162689498Sru break; 162789498Sru case IFAN_DEPARTURE: 162889498Sru printf("departure"); 162989498Sru break; 163089498Sru default: 163189498Sru printf("#%d", ifan->ifan_what); 163289498Sru break; 163389498Sru } 163489498Sru printf("\n"); 1635243860Sglebius fflush(stdout); 163689498Sru break; 163789498Sru 16381558Srgrimes default: 163913171Swollman (void) printf("pid: %ld, seq %d, errno %d, flags:", 164013171Swollman (long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno); 16411558Srgrimes bprintf(stdout, rtm->rtm_flags, routeflags); 1642216297Sglebius pmsg_common(rtm, msglen); 16431558Srgrimes } 1644216297Sglebius 1645216297Sglebius return; 1646216297Sglebius 1647216297Sglebiusbadlen: 1648216297Sglebius (void)printf(errfmt, __func__, msglen); 1649216297Sglebius#undef REQUIRE 16501558Srgrimes} 16511558Srgrimes 1652204406Suqsstatic void 1653243185Shrsprint_getmsg(struct rt_msghdr *rtm, int msglen, int fib) 16541558Srgrimes{ 16551558Srgrimes struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL; 16561558Srgrimes struct sockaddr_dl *ifp = NULL; 165792806Sobrien struct sockaddr *sa; 165892806Sobrien char *cp; 165992806Sobrien int i; 16601558Srgrimes 1661196527Scharnier (void) printf(" route to: %s\n", 1662196527Scharnier routename((struct sockaddr *)&so_dst)); 16631558Srgrimes if (rtm->rtm_version != RTM_VERSION) { 166413171Swollman warnx("routing message version %d not understood", 166513171Swollman rtm->rtm_version); 16661558Srgrimes return; 16671558Srgrimes } 16681558Srgrimes if (rtm->rtm_msglen > msglen) { 166937907Scharnier warnx("message length mismatch, in packet %d, returned %d", 167013171Swollman rtm->rtm_msglen, msglen); 16711558Srgrimes } 16721558Srgrimes if (rtm->rtm_errno) { 167313171Swollman errno = rtm->rtm_errno; 167413171Swollman warn("message indicates error %d", errno); 16751558Srgrimes return; 16761558Srgrimes } 16771558Srgrimes cp = ((char *)(rtm + 1)); 16781558Srgrimes if (rtm->rtm_addrs) 16791558Srgrimes for (i = 1; i; i <<= 1) 16801558Srgrimes if (i & rtm->rtm_addrs) { 16811558Srgrimes sa = (struct sockaddr *)cp; 16821558Srgrimes switch (i) { 16831558Srgrimes case RTA_DST: 16841558Srgrimes dst = sa; 16851558Srgrimes break; 16861558Srgrimes case RTA_GATEWAY: 16871558Srgrimes gate = sa; 16881558Srgrimes break; 16891558Srgrimes case RTA_NETMASK: 16901558Srgrimes mask = sa; 16911558Srgrimes break; 16921558Srgrimes case RTA_IFP: 16931558Srgrimes if (sa->sa_family == AF_LINK && 16941558Srgrimes ((struct sockaddr_dl *)sa)->sdl_nlen) 16951558Srgrimes ifp = (struct sockaddr_dl *)sa; 16961558Srgrimes break; 16971558Srgrimes } 1698128186Sluigi cp += SA_SIZE(sa); 16991558Srgrimes } 17001558Srgrimes if (dst && mask) 17011558Srgrimes mask->sa_family = dst->sa_family; /* XXX */ 17021558Srgrimes if (dst) 17031558Srgrimes (void)printf("destination: %s\n", routename(dst)); 17041558Srgrimes if (mask) { 17051558Srgrimes int savenflag = nflag; 17061558Srgrimes 17071558Srgrimes nflag = 1; 17081558Srgrimes (void)printf(" mask: %s\n", routename(mask)); 17091558Srgrimes nflag = savenflag; 17101558Srgrimes } 17111558Srgrimes if (gate && rtm->rtm_flags & RTF_GATEWAY) 17121558Srgrimes (void)printf(" gateway: %s\n", routename(gate)); 1713243185Shrs if (fib >= 0) 1714243185Shrs (void)printf(" fib: %u\n", (unsigned int)fib); 17151558Srgrimes if (ifp) 17161558Srgrimes (void)printf(" interface: %.*s\n", 17171558Srgrimes ifp->sdl_nlen, ifp->sdl_data); 17181558Srgrimes (void)printf(" flags: "); 17191558Srgrimes bprintf(stdout, rtm->rtm_flags, routeflags); 17201558Srgrimes 17211558Srgrimes#define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ') 17221558Srgrimes#define msec(u) (((u) + 500) / 1000) /* usec to msec */ 17231558Srgrimes 17241558Srgrimes (void) printf("\n%s\n", "\ 1725191080Skmacy recvpipe sendpipe ssthresh rtt,msec mtu weight expire"); 172613171Swollman printf("%8ld%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE)); 172713171Swollman printf("%8ld%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE)); 172813171Swollman printf("%8ld%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH)); 172913171Swollman printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT)); 173013171Swollman printf("%8ld%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU)); 1731191080Skmacy printf("%8ld%c ", rtm->rtm_rmx.rmx_weight, lock(WEIGHT)); 17321558Srgrimes if (rtm->rtm_rmx.rmx_expire) 17331558Srgrimes rtm->rtm_rmx.rmx_expire -= time(0); 173413171Swollman printf("%8ld%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE)); 17351558Srgrimes#undef lock 17361558Srgrimes#undef msec 17371558Srgrimes#define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD) 17381558Srgrimes if (verbose) 1739216297Sglebius pmsg_common(rtm, msglen); 17401558Srgrimes else if (rtm->rtm_addrs &~ RTA_IGN) { 17411558Srgrimes (void) printf("sockaddrs: "); 17421558Srgrimes bprintf(stdout, rtm->rtm_addrs, addrnames); 17431558Srgrimes putchar('\n'); 17441558Srgrimes } 17451558Srgrimes#undef RTA_IGN 17461558Srgrimes} 17471558Srgrimes 1748204406Suqsstatic void 1749216297Sglebiuspmsg_common(struct rt_msghdr *rtm, size_t msglen) 17501558Srgrimes{ 17511558Srgrimes (void) printf("\nlocks: "); 17521558Srgrimes bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames); 17531558Srgrimes (void) printf(" inits: "); 17541558Srgrimes bprintf(stdout, rtm->rtm_inits, metricnames); 1755216297Sglebius if (msglen > sizeof(struct rt_msghdr)) 1756216297Sglebius pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs, 1757216297Sglebius msglen - sizeof(struct rt_msghdr)); 1758216297Sglebius else 1759216297Sglebius (void) fflush(stdout); 17601558Srgrimes} 17611558Srgrimes 1762204406Suqsstatic void 1763216297Sglebiuspmsg_addrs(char *cp, int addrs, size_t len) 17641558Srgrimes{ 176592806Sobrien struct sockaddr *sa; 17661558Srgrimes int i; 17671558Srgrimes 176871061Sphk if (addrs == 0) { 176971061Sphk (void) putchar('\n'); 17701558Srgrimes return; 177171061Sphk } 17721558Srgrimes (void) printf("\nsockaddrs: "); 17731558Srgrimes bprintf(stdout, addrs, addrnames); 17741558Srgrimes (void) putchar('\n'); 1775204406Suqs for (i = 1; i != 0; i <<= 1) 17761558Srgrimes if (i & addrs) { 17771558Srgrimes sa = (struct sockaddr *)cp; 1778216297Sglebius if (len == 0 || len < SA_SIZE(sa)) { 1779216297Sglebius (void) printf(errfmt, __func__, len); 1780216297Sglebius break; 1781216297Sglebius } 17821558Srgrimes (void) printf(" %s", routename(sa)); 1783216297Sglebius len -= SA_SIZE(sa); 1784128186Sluigi cp += SA_SIZE(sa); 17851558Srgrimes } 17861558Srgrimes (void) putchar('\n'); 17871558Srgrimes (void) fflush(stdout); 17881558Srgrimes} 17891558Srgrimes 1790204406Suqsstatic void 1791204406Suqsbprintf(FILE *fp, int b, u_char *str) 17921558Srgrimes{ 179392806Sobrien int i; 17941558Srgrimes int gotsome = 0; 17951558Srgrimes 17961558Srgrimes if (b == 0) 17971558Srgrimes return; 1798204406Suqs while ((i = *str++) != 0) { 17991558Srgrimes if (b & (1 << (i-1))) { 18001558Srgrimes if (gotsome == 0) 18011558Srgrimes i = '<'; 18021558Srgrimes else 18031558Srgrimes i = ','; 18041558Srgrimes (void) putc(i, fp); 18051558Srgrimes gotsome = 1; 1806204406Suqs for (; (i = *str) > 32; str++) 18071558Srgrimes (void) putc(i, fp); 18081558Srgrimes } else 1809204406Suqs while (*str > 32) 1810204406Suqs str++; 18111558Srgrimes } 18121558Srgrimes if (gotsome) 18131558Srgrimes (void) putc('>', fp); 18141558Srgrimes} 18151558Srgrimes 18161558Srgrimesint 1817204406Suqskeyword(const char *cp) 18181558Srgrimes{ 181992806Sobrien struct keytab *kt = keywords; 18201558Srgrimes 1821204406Suqs while (kt->kt_cp != NULL && strcmp(kt->kt_cp, cp) != 0) 18221558Srgrimes kt++; 1823204406Suqs return (kt->kt_i); 18241558Srgrimes} 18251558Srgrimes 1826204406Suqsstatic void 1827204406Suqssodump(sup su, const char *which) 18281558Srgrimes{ 18291558Srgrimes switch (su->sa.sa_family) { 18301558Srgrimes case AF_LINK: 18311558Srgrimes (void) printf("%s: link %s; ", 18321558Srgrimes which, link_ntoa(&su->sdl)); 18331558Srgrimes break; 18341558Srgrimes case AF_INET: 18351558Srgrimes (void) printf("%s: inet %s; ", 18361558Srgrimes which, inet_ntoa(su->sin.sin_addr)); 18371558Srgrimes break; 183817046Sjulian case AF_APPLETALK: 183917046Sjulian (void) printf("%s: atalk %s; ", 184017046Sjulian which, atalk_ntoa(su->sat.sat_addr)); 184117046Sjulian break; 18421558Srgrimes } 18431558Srgrimes (void) fflush(stdout); 18441558Srgrimes} 18451558Srgrimes 18461558Srgrimes/* States*/ 18471558Srgrimes#define VIRGIN 0 18481558Srgrimes#define GOTONE 1 18491558Srgrimes#define GOTTWO 2 18501558Srgrimes/* Inputs */ 18511558Srgrimes#define DIGIT (4*0) 18521558Srgrimes#define END (4*1) 18531558Srgrimes#define DELIM (4*2) 18541558Srgrimes 1855204406Suqsstatic void 1856196527Scharniersockaddr(char *addr, struct sockaddr *sa) 18571558Srgrimes{ 185892806Sobrien char *cp = (char *)sa; 18591558Srgrimes int size = sa->sa_len; 18601558Srgrimes char *cplim = cp + size; 186192806Sobrien int byte = 0, state = VIRGIN, new = 0 /* foil gcc */; 18621558Srgrimes 186385048Sru memset(cp, 0, size); 18641558Srgrimes cp++; 18651558Srgrimes do { 18661558Srgrimes if ((*addr >= '0') && (*addr <= '9')) { 18671558Srgrimes new = *addr - '0'; 18681558Srgrimes } else if ((*addr >= 'a') && (*addr <= 'f')) { 18691558Srgrimes new = *addr - 'a' + 10; 18701558Srgrimes } else if ((*addr >= 'A') && (*addr <= 'F')) { 18711558Srgrimes new = *addr - 'A' + 10; 1872204406Suqs } else if (*addr == '\0') 18731558Srgrimes state |= END; 18741558Srgrimes else 18751558Srgrimes state |= DELIM; 18761558Srgrimes addr++; 18771558Srgrimes switch (state /* | INPUT */) { 18781558Srgrimes case GOTTWO | DIGIT: 18791558Srgrimes *cp++ = byte; /*FALLTHROUGH*/ 18801558Srgrimes case VIRGIN | DIGIT: 18811558Srgrimes state = GOTONE; byte = new; continue; 18821558Srgrimes case GOTONE | DIGIT: 18831558Srgrimes state = GOTTWO; byte = new + (byte << 4); continue; 18841558Srgrimes default: /* | DELIM */ 18851558Srgrimes state = VIRGIN; *cp++ = byte; byte = 0; continue; 18861558Srgrimes case GOTONE | END: 18871558Srgrimes case GOTTWO | END: 18881558Srgrimes *cp++ = byte; /* FALLTHROUGH */ 18891558Srgrimes case VIRGIN | END: 18901558Srgrimes break; 18911558Srgrimes } 18921558Srgrimes break; 18931558Srgrimes } while (cp < cplim); 18941558Srgrimes sa->sa_len = cp - (char *)sa; 18951558Srgrimes} 189617046Sjulian 1897204406Suqsstatic int 189817046Sjulianatalk_aton(const char *text, struct at_addr *addr) 189917046Sjulian{ 190017046Sjulian u_int net, node; 190117046Sjulian 190217046Sjulian if (sscanf(text, "%u.%u", &net, &node) != 2 190317046Sjulian || net > 0xffff || node > 0xff) 190417046Sjulian return(0); 190517254Sjulian addr->s_net = htons(net); 190617046Sjulian addr->s_node = node; 190717046Sjulian return(1); 190817046Sjulian} 190917046Sjulian 1910204406Suqsstatic char * 191117046Sjulianatalk_ntoa(struct at_addr at) 191217046Sjulian{ 191317046Sjulian static char buf[20]; 191417046Sjulian 191517254Sjulian (void) snprintf(buf, sizeof(buf), "%u.%u", ntohs(at.s_net), at.s_node); 191617046Sjulian return(buf); 191717046Sjulian} 1918