1331722Seadler/* 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: stable/11/sbin/route/route.c 340943 2018-11-26 11:08:38Z eugen $"); 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> 581558Srgrimes#include <arpa/inet.h> 591558Srgrimes#include <netdb.h> 601558Srgrimes 6120287Swollman#include <ctype.h> 6220287Swollman#include <err.h> 631558Srgrimes#include <errno.h> 6469793Sobrien#include <paths.h> 65304100Sae#include <signal.h> 66258934Seadler#include <stdbool.h> 671558Srgrimes#include <stdio.h> 681558Srgrimes#include <stdlib.h> 691558Srgrimes#include <string.h> 7013171Swollman#include <sysexits.h> 71256695Shrs#include <time.h> 7220287Swollman#include <unistd.h> 7378064Sume#include <ifaddrs.h> 741558Srgrimes 75258940Seadlerstruct fibl { 76258940Seadler TAILQ_ENTRY(fibl) fl_next; 77258940Seadler 78258940Seadler int fl_num; 79258940Seadler int fl_error; 80258940Seadler int fl_errno; 81258940Seadler}; 82258940Seadler 83253427Shrsstatic struct keytab { 84204406Suqs const char *kt_cp; 851558Srgrimes int kt_i; 86258907Seadler} const keywords[] = { 871558Srgrimes#include "keywords.h" 881558Srgrimes {0, 0} 891558Srgrimes}; 901558Srgrimes 91253427Shrsstatic struct sockaddr_storage so[RTAX_MAX]; 92253427Shrsstatic int pid, rtm_addrs; 93253427Shrsstatic int s; 94264539Sbzstatic int nflag, af, qflag, tflag; 95253427Shrsstatic int verbose, aflen; 96253427Shrsstatic int locking, lockrest, debugonly; 97253427Shrsstatic struct rt_metrics rt_metrics; 98253427Shrsstatic u_long rtm_inits; 99253427Shrsstatic uid_t uid; 100243185Shrsstatic int defaultfib; 101243185Shrsstatic int numfibs; 102258934Seadlerstatic char domain[MAXHOSTNAMELEN + 1]; 103258934Seadlerstatic bool domain_initialized; 104258937Seadlerstatic int rtm_seq; 105258938Seadlerstatic char rt_line[NI_MAXHOST]; 106258939Seadlerstatic char net_line[MAXHOSTNAMELEN + 1]; 107196527Scharnier 108258940Seadlerstatic struct { 109258940Seadler struct rt_msghdr m_rtm; 110258940Seadler char m_space[512]; 111258940Seadler} m_rtmsg; 112258940Seadler 113258940Seadlerstatic TAILQ_HEAD(fibl_head_t, fibl) fibl_head; 114258940Seadler 115253427Shrsstatic void printb(int, const char *); 116204406Suqsstatic void flushroutes(int argc, char *argv[]); 117243185Shrsstatic int flushroutes_fib(int); 118245168Shrsstatic int getaddr(int, char *, struct hostent **, int); 119204406Suqsstatic int keyword(const char *); 120253427Shrs#ifdef INET 121253427Shrsstatic void inet_makenetandmask(u_long, struct sockaddr_in *, 122253427Shrs struct sockaddr_in *, u_long); 123253427Shrs#endif 12497062Sume#ifdef INET6 125253427Shrsstatic int inet6_makenetandmask(struct sockaddr_in6 *, const char *); 12697062Sume#endif 127204406Suqsstatic void interfaces(void); 128243185Shrsstatic void monitor(int, char*[]); 129204406Suqsstatic const char *netname(struct sockaddr *); 130204406Suqsstatic void newroute(int, char **); 131243185Shrsstatic int newroute_fib(int, char *, int); 132216297Sglebiusstatic void pmsg_addrs(char *, int, size_t); 133216297Sglebiusstatic void pmsg_common(struct rt_msghdr *, size_t); 134204406Suqsstatic int prefixlen(const char *); 135243185Shrsstatic void print_getmsg(struct rt_msghdr *, int, int); 136216297Sglebiusstatic void print_rtmsg(struct rt_msghdr *, size_t); 137204406Suqsstatic const char *routename(struct sockaddr *); 138243185Shrsstatic int rtmsg(int, int, int); 139204406Suqsstatic void set_metric(char *, int); 140243185Shrsstatic int set_sofib(int); 141253427Shrsstatic void sockaddr(char *, struct sockaddr *, size_t); 142253427Shrsstatic void sodump(struct sockaddr *, const char *); 143243185Shrsstatic int fiboptlist_csv(const char *, struct fibl_head_t *); 144243185Shrsstatic int fiboptlist_range(const char *, struct fibl_head_t *); 145243185Shrs 146204406Suqsstatic void usage(const char *) __dead2; 14713171Swollman 148304100Sae#define READ_TIMEOUT 10 149304100Saestatic volatile sig_atomic_t stop_read; 150304100Sae 151253519Shrsstatic void 152304100Saestopit(int sig __unused) 153304100Sae{ 154304100Sae 155304100Sae stop_read = 1; 156304100Sae} 157304100Sae 158304100Saestatic void 159196527Scharnierusage(const char *cp) 1601558Srgrimes{ 161204406Suqs if (cp != NULL) 16213171Swollman warnx("bad keyword: %s", cp); 163260524Smelifaro errx(EX_USAGE, "usage: route [-46dnqtv] command [[modifiers] args]"); 1641558Srgrimes /* NOTREACHED */ 1651558Srgrimes} 1661558Srgrimes 1671558Srgrimesint 168196527Scharniermain(int argc, char **argv) 1691558Srgrimes{ 1701558Srgrimes int ch; 171243185Shrs size_t len; 1721558Srgrimes 1731558Srgrimes if (argc < 2) 174204406Suqs usage(NULL); 1751558Srgrimes 176260524Smelifaro while ((ch = getopt(argc, argv, "46nqdtv")) != -1) 1771558Srgrimes switch(ch) { 178260524Smelifaro case '4': 179260524Smelifaro#ifdef INET 180260524Smelifaro af = AF_INET; 181260524Smelifaro aflen = sizeof(struct sockaddr_in); 182260524Smelifaro#else 183260524Smelifaro errx(1, "IPv4 support is not compiled in"); 184260524Smelifaro#endif 185260524Smelifaro break; 186260524Smelifaro case '6': 187260524Smelifaro#ifdef INET6 188260524Smelifaro af = AF_INET6; 189260524Smelifaro aflen = sizeof(struct sockaddr_in6); 190260524Smelifaro#else 191260524Smelifaro errx(1, "IPv6 support is not compiled in"); 192260524Smelifaro#endif 193260524Smelifaro break; 1941558Srgrimes case 'n': 1951558Srgrimes nflag = 1; 1961558Srgrimes break; 1971558Srgrimes case 'q': 1981558Srgrimes qflag = 1; 1991558Srgrimes break; 2001558Srgrimes case 'v': 2011558Srgrimes verbose = 1; 2021558Srgrimes break; 2031558Srgrimes case 't': 2041558Srgrimes tflag = 1; 2051558Srgrimes break; 2061558Srgrimes case 'd': 2071558Srgrimes debugonly = 1; 2081558Srgrimes break; 2091558Srgrimes case '?': 2101558Srgrimes default: 211204406Suqs usage(NULL); 2121558Srgrimes } 2131558Srgrimes argc -= optind; 2141558Srgrimes argv += optind; 2151558Srgrimes 2161558Srgrimes pid = getpid(); 217109811Skbyanc uid = geteuid(); 2181558Srgrimes if (tflag) 21969793Sobrien s = open(_PATH_DEVNULL, O_WRONLY, 0); 2201558Srgrimes else 2211558Srgrimes s = socket(PF_ROUTE, SOCK_RAW, 0); 2221558Srgrimes if (s < 0) 22313171Swollman err(EX_OSERR, "socket"); 224243185Shrs 225243185Shrs len = sizeof(numfibs); 226243185Shrs if (sysctlbyname("net.fibs", (void *)&numfibs, &len, NULL, 0) == -1) 227243185Shrs numfibs = -1; 228243185Shrs 229243185Shrs len = sizeof(defaultfib); 230243185Shrs if (numfibs != -1 && 231243185Shrs sysctlbyname("net.my_fibnum", (void *)&defaultfib, &len, NULL, 232243185Shrs 0) == -1) 233243185Shrs defaultfib = -1; 234243185Shrs 235204406Suqs if (*argv != NULL) 2361558Srgrimes switch (keyword(*argv)) { 2371558Srgrimes case K_GET: 238191080Skmacy case K_SHOW: 2391558Srgrimes uid = 0; 2401558Srgrimes /* FALLTHROUGH */ 2411558Srgrimes 2421558Srgrimes case K_CHANGE: 2431558Srgrimes case K_ADD: 244150679Stobez case K_DEL: 2451558Srgrimes case K_DELETE: 2461558Srgrimes newroute(argc, argv); 2471558Srgrimes /* NOTREACHED */ 2481558Srgrimes 2491558Srgrimes case K_MONITOR: 250243185Shrs monitor(argc, argv); 2511558Srgrimes /* NOTREACHED */ 2521558Srgrimes 2531558Srgrimes case K_FLUSH: 2541558Srgrimes flushroutes(argc, argv); 2551558Srgrimes exit(0); 2561558Srgrimes /* NOTREACHED */ 2571558Srgrimes } 2581558Srgrimes usage(*argv); 2591558Srgrimes /* NOTREACHED */ 2601558Srgrimes} 2611558Srgrimes 262243185Shrsstatic int 263243185Shrsset_sofib(int fib) 264243185Shrs{ 265243185Shrs 266243185Shrs if (fib < 0) 267243185Shrs return (0); 268243185Shrs return (setsockopt(s, SOL_SOCKET, SO_SETFIB, (void *)&fib, 269243185Shrs sizeof(fib))); 270243185Shrs} 271243185Shrs 272243185Shrsstatic int 273243185Shrsfiboptlist_range(const char *arg, struct fibl_head_t *flh) 274243185Shrs{ 275243185Shrs struct fibl *fl; 276244325Shrs char *str0, *str, *token, *endptr; 277243185Shrs int fib[2], i, error; 278243185Shrs 279244325Shrs str0 = str = strdup(arg); 280243185Shrs error = 0; 281243185Shrs i = 0; 282243185Shrs while ((token = strsep(&str, "-")) != NULL) { 283243185Shrs switch (i) { 284243185Shrs case 0: 285243185Shrs case 1: 286244325Shrs errno = 0; 287243185Shrs fib[i] = strtol(token, &endptr, 0); 288244325Shrs if (errno == 0) { 289244325Shrs if (*endptr != '\0' || 290244325Shrs fib[i] < 0 || 291316041Sngie (numfibs != -1 && fib[i] > numfibs - 1)) 292244325Shrs errno = EINVAL; 293244325Shrs } 294244325Shrs if (errno) 295243185Shrs error = 1; 296243185Shrs break; 297243185Shrs default: 298243185Shrs error = 1; 299243185Shrs } 300243185Shrs if (error) 301243185Shrs goto fiboptlist_range_ret; 302243185Shrs i++; 303243185Shrs } 304243185Shrs if (fib[0] >= fib[1]) { 305243185Shrs error = 1; 306243185Shrs goto fiboptlist_range_ret; 307243185Shrs } 308243185Shrs for (i = fib[0]; i <= fib[1]; i++) { 309243185Shrs fl = calloc(1, sizeof(*fl)); 310243185Shrs if (fl == NULL) { 311243185Shrs error = 1; 312243185Shrs goto fiboptlist_range_ret; 313243185Shrs } 314243185Shrs fl->fl_num = i; 315243185Shrs TAILQ_INSERT_TAIL(flh, fl, fl_next); 316243185Shrs } 317243185Shrsfiboptlist_range_ret: 318244325Shrs free(str0); 319243185Shrs return (error); 320243185Shrs} 321243185Shrs 322243185Shrs#define ALLSTRLEN 64 323243185Shrsstatic int 324243185Shrsfiboptlist_csv(const char *arg, struct fibl_head_t *flh) 325243185Shrs{ 326243185Shrs struct fibl *fl; 327244325Shrs char *str0, *str, *token, *endptr; 328243185Shrs int fib, error; 329243185Shrs 330253427Shrs str0 = str = NULL; 331243185Shrs if (strcmp("all", arg) == 0) { 332243185Shrs str = calloc(1, ALLSTRLEN); 333243185Shrs if (str == NULL) { 334243185Shrs error = 1; 335243185Shrs goto fiboptlist_csv_ret; 336243185Shrs } 337243185Shrs if (numfibs > 1) 338243185Shrs snprintf(str, ALLSTRLEN - 1, "%d-%d", 0, numfibs - 1); 339243185Shrs else 340243185Shrs snprintf(str, ALLSTRLEN - 1, "%d", 0); 341243185Shrs } else if (strcmp("default", arg) == 0) { 342244325Shrs str0 = str = calloc(1, ALLSTRLEN); 343243185Shrs if (str == NULL) { 344243185Shrs error = 1; 345243185Shrs goto fiboptlist_csv_ret; 346243185Shrs } 347243185Shrs snprintf(str, ALLSTRLEN - 1, "%d", defaultfib); 348243185Shrs } else 349244325Shrs str0 = str = strdup(arg); 350243185Shrs 351243185Shrs error = 0; 352243185Shrs while ((token = strsep(&str, ",")) != NULL) { 353243185Shrs if (*token != '-' && strchr(token, '-') != NULL) { 354243185Shrs error = fiboptlist_range(token, flh); 355243185Shrs if (error) 356243185Shrs goto fiboptlist_csv_ret; 357243185Shrs } else { 358244325Shrs errno = 0; 359243185Shrs fib = strtol(token, &endptr, 0); 360244325Shrs if (errno == 0) { 361244325Shrs if (*endptr != '\0' || 362244325Shrs fib < 0 || 363244325Shrs (numfibs != -1 && fib > numfibs - 1)) 364244325Shrs errno = EINVAL; 365244325Shrs } 366244325Shrs if (errno) { 367243185Shrs error = 1; 368243185Shrs goto fiboptlist_csv_ret; 369243185Shrs } 370243185Shrs fl = calloc(1, sizeof(*fl)); 371243185Shrs if (fl == NULL) { 372243185Shrs error = 1; 373243185Shrs goto fiboptlist_csv_ret; 374243185Shrs } 375243185Shrs fl->fl_num = fib; 376243185Shrs TAILQ_INSERT_TAIL(flh, fl, fl_next); 377243185Shrs } 378243185Shrs } 379243185Shrsfiboptlist_csv_ret: 380253427Shrs if (str0 != NULL) 381253427Shrs free(str0); 382243185Shrs return (error); 383243185Shrs} 384243185Shrs 3851558Srgrimes/* 3861558Srgrimes * Purge all entries in the routing tables not 3871558Srgrimes * associated with network interfaces. 3881558Srgrimes */ 389204406Suqsstatic void 390196527Scharnierflushroutes(int argc, char *argv[]) 3911558Srgrimes{ 392243185Shrs struct fibl *fl; 393243185Shrs int error; 3941558Srgrimes 395253427Shrs if (uid != 0 && !debugonly && !tflag) 39613171Swollman errx(EX_NOPERM, "must be root to alter routing table"); 397146079Sjmallett shutdown(s, SHUT_RD); /* Don't want to read back our messages */ 398243185Shrs 399243185Shrs TAILQ_INIT(&fibl_head); 400243185Shrs while (argc > 1) { 401243185Shrs argc--; 4021558Srgrimes argv++; 403243185Shrs if (**argv != '-') 404243185Shrs usage(*argv); 405243185Shrs switch (keyword(*argv + 1)) { 406253427Shrs#ifdef INET 407260524Smelifaro case K_4: 408243185Shrs case K_INET: 409243185Shrs af = AF_INET; 410243185Shrs break; 411253427Shrs#endif 41254263Sshin#ifdef INET6 413260524Smelifaro case K_6: 414243185Shrs case K_INET6: 415243185Shrs af = AF_INET6; 416243185Shrs break; 41754263Sshin#endif 418243185Shrs case K_LINK: 419243185Shrs af = AF_LINK; 420243185Shrs break; 421243185Shrs case K_FIB: 422243185Shrs if (!--argc) 423243185Shrs usage(*argv); 424243185Shrs error = fiboptlist_csv(*++argv, &fibl_head); 425243185Shrs if (error) 426244325Shrs errx(EX_USAGE, "invalid fib number: %s", *argv); 427243185Shrs break; 428243185Shrs default: 429243185Shrs usage(*argv); 430243185Shrs } 4311558Srgrimes } 432243185Shrs if (TAILQ_EMPTY(&fibl_head)) { 433243185Shrs error = fiboptlist_csv("default", &fibl_head); 434243185Shrs if (error) 435243185Shrs errx(EX_OSERR, "fiboptlist_csv failed."); 436243185Shrs } 437243185Shrs TAILQ_FOREACH(fl, &fibl_head, fl_next) 438243185Shrs flushroutes_fib(fl->fl_num); 439243185Shrs} 440243185Shrs 441243185Shrsstatic int 442243185Shrsflushroutes_fib(int fib) 443243185Shrs{ 444243185Shrs struct rt_msghdr *rtm; 445243185Shrs size_t needed; 446243185Shrs char *buf, *next, *lim; 447253429Shrs int mib[7], rlen, seqno, count = 0; 448243185Shrs int error; 449243185Shrs 450243185Shrs error = set_sofib(fib); 451243185Shrs if (error) { 452243185Shrs warn("fib number %d is ignored", fib); 453243185Shrs return (error); 454243185Shrs } 455243185Shrs 456128782Sambriskoretry: 4571558Srgrimes mib[0] = CTL_NET; 4581558Srgrimes mib[1] = PF_ROUTE; 4591558Srgrimes mib[2] = 0; /* protocol */ 460253427Shrs mib[3] = AF_UNSPEC; 4611558Srgrimes mib[4] = NET_RT_DUMP; 4621558Srgrimes mib[5] = 0; /* no flags */ 463253429Shrs mib[6] = fib; 464253427Shrs if (sysctl(mib, nitems(mib), NULL, &needed, NULL, 0) < 0) 46513171Swollman err(EX_OSERR, "route-sysctl-estimate"); 4661558Srgrimes if ((buf = malloc(needed)) == NULL) 46737907Scharnier errx(EX_OSERR, "malloc failed"); 468253427Shrs if (sysctl(mib, nitems(mib), buf, &needed, NULL, 0) < 0) { 469128782Sambrisko if (errno == ENOMEM && count++ < 10) { 470204406Suqs warnx("Routing table grew, retrying"); 471128782Sambrisko sleep(1); 472128782Sambrisko free(buf); 473128782Sambrisko goto retry; 474128782Sambrisko } 47513171Swollman err(EX_OSERR, "route-sysctl-get"); 476128782Sambrisko } 4771558Srgrimes lim = buf + needed; 4781558Srgrimes if (verbose) 479253427Shrs (void)printf("Examining routing table from sysctl\n"); 4801558Srgrimes seqno = 0; /* ??? */ 4811558Srgrimes for (next = buf; next < lim; next += rtm->rtm_msglen) { 482253502Shrs rtm = (struct rt_msghdr *)(void *)next; 4831558Srgrimes if (verbose) 4841558Srgrimes print_rtmsg(rtm, rtm->rtm_msglen); 4851558Srgrimes if ((rtm->rtm_flags & RTF_GATEWAY) == 0) 4861558Srgrimes continue; 487204406Suqs if (af != 0) { 4881558Srgrimes struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 4891558Srgrimes 4901558Srgrimes if (sa->sa_family != af) 4911558Srgrimes continue; 4921558Srgrimes } 4931558Srgrimes if (debugonly) 4941558Srgrimes continue; 4951558Srgrimes rtm->rtm_type = RTM_DELETE; 4961558Srgrimes rtm->rtm_seq = seqno; 4971558Srgrimes rlen = write(s, next, rtm->rtm_msglen); 498129034Scsjp if (rlen < 0 && errno == EPERM) 499129034Scsjp err(1, "write to routing socket"); 5001558Srgrimes if (rlen < (int)rtm->rtm_msglen) { 50113171Swollman warn("write to routing socket"); 502253427Shrs (void)printf("got only %d for rlen\n", rlen); 503128782Sambrisko free(buf); 504128782Sambrisko goto retry; 5051558Srgrimes break; 5061558Srgrimes } 5071558Srgrimes seqno++; 5081558Srgrimes if (qflag) 5091558Srgrimes continue; 5101558Srgrimes if (verbose) 5111558Srgrimes print_rtmsg(rtm, rlen); 5121558Srgrimes else { 5131558Srgrimes struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 514243185Shrs 515243185Shrs printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ? 5161558Srgrimes routename(sa) : netname(sa)); 517128186Sluigi sa = (struct sockaddr *)(SA_SIZE(sa) + (char *)sa); 518243185Shrs printf("%-20.20s ", routename(sa)); 519243185Shrs if (fib >= 0) 520243185Shrs printf("-fib %-3d ", fib); 521243185Shrs printf("done\n"); 5221558Srgrimes } 5231558Srgrimes } 524243185Shrs return (error); 5251558Srgrimes} 5261558Srgrimes 527253519Shrsstatic const char * 528196527Scharnierroutename(struct sockaddr *sa) 5291558Srgrimes{ 530253517Shrs struct sockaddr_dl *sdl; 531204406Suqs const char *cp; 532258905Seadler int n; 5331558Srgrimes 534258934Seadler if (!domain_initialized) { 535258934Seadler domain_initialized = true; 5361558Srgrimes if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 53785048Sru (cp = strchr(domain, '.'))) { 53819209Sfenner domain[MAXHOSTNAMELEN] = '\0'; 539253427Shrs (void)strcpy(domain, cp + 1); 54019209Sfenner } else 541253427Shrs domain[0] = '\0'; 5421558Srgrimes } 5431558Srgrimes 544253519Shrs /* If the address is zero-filled, use "default". */ 545253503Shrs if (sa->sa_len == 0 && nflag == 0) 546253503Shrs return ("default"); 547253519Shrs#if defined(INET) || defined(INET6) 548253427Shrs switch (sa->sa_family) { 549253427Shrs#ifdef INET 550253427Shrs case AF_INET: 551253519Shrs /* If the address is zero-filled, use "default". */ 552253519Shrs if (nflag == 0 && 553253519Shrs ((struct sockaddr_in *)(void *)sa)->sin_addr.s_addr == 554253519Shrs INADDR_ANY) 555253519Shrs return("default"); 5561558Srgrimes break; 557253519Shrs#endif 558253519Shrs#ifdef INET6 559253519Shrs case AF_INET6: 560253519Shrs /* If the address is zero-filled, use "default". */ 561253519Shrs if (nflag == 0 && 562253519Shrs IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(void *)sa)->sin6_addr)) 563253519Shrs return("default"); 564253519Shrs break; 565253519Shrs#endif 566253427Shrs } 567253519Shrs#endif 5681558Srgrimes 569253519Shrs switch (sa->sa_family) { 570253519Shrs#if defined(INET) || defined(INET6) 571253519Shrs#ifdef INET 572253519Shrs case AF_INET: 573253427Shrs#endif 57454263Sshin#ifdef INET6 57554263Sshin case AF_INET6: 576253519Shrs#endif 57778064Sume { 578253519Shrs struct sockaddr_storage ss; 579253519Shrs int error; 580253519Shrs char *p; 58154263Sshin 582253519Shrs memset(&ss, 0, sizeof(ss)); 583253519Shrs if (sa->sa_len == 0) 584253519Shrs ss.ss_family = sa->sa_family; 585253519Shrs else 586253519Shrs memcpy(&ss, sa, sa->sa_len); 587253519Shrs /* Expand sa->sa_len because it could be shortened. */ 588253519Shrs if (sa->sa_family == AF_INET) 589253519Shrs ss.ss_len = sizeof(struct sockaddr_in); 590253519Shrs else if (sa->sa_family == AF_INET6) 591253519Shrs ss.ss_len = sizeof(struct sockaddr_in6); 592253519Shrs error = getnameinfo((struct sockaddr *)&ss, ss.ss_len, 593258938Seadler rt_line, sizeof(rt_line), NULL, 0, 594253519Shrs (nflag == 0) ? 0 : NI_NUMERICHOST); 595253519Shrs if (error) { 596253519Shrs warnx("getnameinfo(): %s", gai_strerror(error)); 597258938Seadler strncpy(rt_line, "invalid", sizeof(rt_line)); 598253519Shrs } 59978064Sume 600253519Shrs /* Remove the domain part if any. */ 601258938Seadler p = strchr(rt_line, '.'); 602253519Shrs if (p != NULL && strcmp(p + 1, domain) == 0) 603253519Shrs *p = '\0'; 604253519Shrs 605258938Seadler return (rt_line); 606253519Shrs break; 60778064Sume } 60878064Sume#endif 6091558Srgrimes case AF_LINK: 610253517Shrs sdl = (struct sockaddr_dl *)(void *)sa; 611253517Shrs 612253517Shrs if (sdl->sdl_nlen == 0 && 613253517Shrs sdl->sdl_alen == 0 && 614253517Shrs sdl->sdl_slen == 0) { 615258938Seadler n = snprintf(rt_line, sizeof(rt_line), "link#%d", 616253517Shrs sdl->sdl_index); 617258938Seadler if (n > (int)sizeof(rt_line)) 618258938Seadler rt_line[0] = '\0'; 619258938Seadler return (rt_line); 620253517Shrs } else 621253517Shrs return (link_ntoa(sdl)); 622253427Shrs break; 6231558Srgrimes 6241558Srgrimes default: 625204406Suqs { 626253502Shrs u_short *sp = (u_short *)(void *)sa; 627204406Suqs u_short *splim = sp + ((sa->sa_len + 1) >> 1); 628258938Seadler char *cps = rt_line + sprintf(rt_line, "(%d)", sa->sa_family); 629258938Seadler char *cpe = rt_line + sizeof(rt_line); 6301558Srgrimes 631204406Suqs while (++sp < splim && cps < cpe) /* start with sa->sa_data */ 632204406Suqs if ((n = snprintf(cps, cpe - cps, " %x", *sp)) > 0) 633204406Suqs cps += n; 63481980Sbrian else 635204406Suqs *cps = '\0'; 6361558Srgrimes break; 6371558Srgrimes } 6381558Srgrimes } 639258938Seadler return (rt_line); 6401558Srgrimes} 6411558Srgrimes 6421558Srgrimes/* 6431558Srgrimes * Return the name of the network whose address is given. 644243019Sglebius * The address is assumed to be that of a net, not a host. 6451558Srgrimes */ 646253519Shrsstatic const char * 647196527Scharniernetname(struct sockaddr *sa) 6481558Srgrimes{ 649253517Shrs struct sockaddr_dl *sdl; 650253427Shrs int n; 651253427Shrs#ifdef INET 652204406Suqs struct netent *np = NULL; 653253427Shrs const char *cp = NULL; 65492806Sobrien u_long i; 655253427Shrs#endif 6561558Srgrimes 6571558Srgrimes switch (sa->sa_family) { 658253427Shrs#ifdef INET 659253427Shrs case AF_INET: 660253427Shrs { 661253427Shrs struct in_addr in; 6621558Srgrimes 663253502Shrs in = ((struct sockaddr_in *)(void *)sa)->sin_addr; 6641558Srgrimes i = in.s_addr = ntohl(in.s_addr); 6651558Srgrimes if (in.s_addr == 0) 6661558Srgrimes cp = "default"; 6671558Srgrimes else if (!nflag) { 668243019Sglebius np = getnetbyaddr(i, AF_INET); 669204406Suqs if (np != NULL) 6701558Srgrimes cp = np->n_name; 6711558Srgrimes } 67277873Sru#define C(x) (unsigned)((x) & 0xff) 673204406Suqs if (cp != NULL) 674258939Seadler strncpy(net_line, cp, sizeof(net_line)); 6751558Srgrimes else if ((in.s_addr & 0xffffff) == 0) 676258939Seadler (void)sprintf(net_line, "%u", C(in.s_addr >> 24)); 6771558Srgrimes else if ((in.s_addr & 0xffff) == 0) 678258939Seadler (void)sprintf(net_line, "%u.%u", C(in.s_addr >> 24), 6791558Srgrimes C(in.s_addr >> 16)); 6801558Srgrimes else if ((in.s_addr & 0xff) == 0) 681258939Seadler (void)sprintf(net_line, "%u.%u.%u", C(in.s_addr >> 24), 6821558Srgrimes C(in.s_addr >> 16), C(in.s_addr >> 8)); 6831558Srgrimes else 684258939Seadler (void)sprintf(net_line, "%u.%u.%u.%u", C(in.s_addr >> 24), 6851558Srgrimes C(in.s_addr >> 16), C(in.s_addr >> 8), 6861558Srgrimes C(in.s_addr)); 68777873Sru#undef C 6881558Srgrimes break; 689253427Shrs } 690253427Shrs#endif 69154263Sshin#ifdef INET6 69254263Sshin case AF_INET6: 69378064Sume { 694253427Shrs struct sockaddr_in6 sin6; 69578064Sume int niflags = 0; 69654263Sshin 69778064Sume memset(&sin6, 0, sizeof(sin6)); 69878064Sume memcpy(&sin6, sa, sa->sa_len); 699253427Shrs sin6.sin6_len = sizeof(sin6); 70078064Sume sin6.sin6_family = AF_INET6; 70178064Sume if (nflag) 70278064Sume niflags |= NI_NUMERICHOST; 70378064Sume if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, 704258939Seadler net_line, sizeof(net_line), NULL, 0, niflags) != 0) 705258939Seadler strncpy(net_line, "invalid", sizeof(net_line)); 70678064Sume 707258939Seadler return(net_line); 70878064Sume } 70978064Sume#endif 7101558Srgrimes case AF_LINK: 711253517Shrs sdl = (struct sockaddr_dl *)(void *)sa; 712253517Shrs 713253517Shrs if (sdl->sdl_nlen == 0 && 714253517Shrs sdl->sdl_alen == 0 && 715253517Shrs sdl->sdl_slen == 0) { 716258939Seadler n = snprintf(net_line, sizeof(net_line), "link#%d", 717253517Shrs sdl->sdl_index); 718258939Seadler if (n > (int)sizeof(net_line)) 719258939Seadler net_line[0] = '\0'; 720258939Seadler return (net_line); 721253517Shrs } else 722253517Shrs return (link_ntoa(sdl)); 723253427Shrs break; 7241558Srgrimes 7251558Srgrimes default: 726204406Suqs { 727253502Shrs u_short *sp = (u_short *)(void *)sa->sa_data; 728204406Suqs u_short *splim = sp + ((sa->sa_len + 1)>>1); 729258939Seadler char *cps = net_line + sprintf(net_line, "af %d:", sa->sa_family); 730258939Seadler char *cpe = net_line + sizeof(net_line); 7311558Srgrimes 732204406Suqs while (sp < splim && cps < cpe) 733204406Suqs if ((n = snprintf(cps, cpe - cps, " %x", *sp++)) > 0) 734204406Suqs cps += n; 73581980Sbrian else 736204406Suqs *cps = '\0'; 7371558Srgrimes break; 7381558Srgrimes } 7391558Srgrimes } 740258939Seadler return (net_line); 7411558Srgrimes} 7421558Srgrimes 743204406Suqsstatic void 744196527Scharnierset_metric(char *value, int key) 7451558Srgrimes{ 7461558Srgrimes int flag = 0; 747256695Shrs char *endptr; 7481558Srgrimes u_long noval, *valp = &noval; 7491558Srgrimes 7501558Srgrimes switch (key) { 7511558Srgrimes#define caseof(x, y, z) case x: valp = &rt_metrics.z; flag = y; break 7521558Srgrimes caseof(K_MTU, RTV_MTU, rmx_mtu); 7531558Srgrimes caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount); 7541558Srgrimes caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire); 7551558Srgrimes caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe); 7561558Srgrimes caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe); 7571558Srgrimes caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh); 7581558Srgrimes caseof(K_RTT, RTV_RTT, rmx_rtt); 7591558Srgrimes caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar); 760191080Skmacy caseof(K_WEIGHT, RTV_WEIGHT, rmx_weight); 7611558Srgrimes } 7621558Srgrimes rtm_inits |= flag; 7631558Srgrimes if (lockrest || locking) 7641558Srgrimes rt_metrics.rmx_locks |= flag; 7651558Srgrimes if (locking) 7661558Srgrimes locking = 0; 767256695Shrs errno = 0; 768256695Shrs *valp = strtol(value, &endptr, 0); 769256695Shrs if (errno == 0 && *endptr != '\0') 770256695Shrs errno = EINVAL; 771256695Shrs if (errno) 772256695Shrs err(EX_USAGE, "%s", value); 773256695Shrs if (flag & RTV_EXPIRE && (value[0] == '+' || value[0] == '-')) { 774256695Shrs struct timespec ts; 775256695Shrs 776256695Shrs clock_gettime(CLOCK_REALTIME_FAST, &ts); 777256695Shrs *valp += ts.tv_sec; 778256695Shrs } 7791558Srgrimes} 7801558Srgrimes 781243185Shrs#define F_ISHOST 0x01 782243185Shrs#define F_FORCENET 0x02 783243185Shrs#define F_FORCEHOST 0x04 784243185Shrs#define F_PROXY 0x08 785243185Shrs#define F_INTERFACE 0x10 786243185Shrs 787204406Suqsstatic void 788196527Scharniernewroute(int argc, char **argv) 7891558Srgrimes{ 790304100Sae struct sigaction sa; 791243185Shrs struct hostent *hp; 792243185Shrs struct fibl *fl; 793204406Suqs char *cmd; 794243185Shrs const char *dest, *gateway, *errmsg; 795243185Shrs int key, error, flags, nrflags, fibnum; 7961558Srgrimes 797253427Shrs if (uid != 0 && !debugonly && !tflag) 79813171Swollman errx(EX_NOPERM, "must be root to alter routing table"); 799243185Shrs dest = NULL; 800243185Shrs gateway = NULL; 801243185Shrs flags = RTF_STATIC; 802243185Shrs nrflags = 0; 803243185Shrs hp = NULL; 804243185Shrs TAILQ_INIT(&fibl_head); 805243185Shrs 806304100Sae sigemptyset(&sa.sa_mask); 807304100Sae sa.sa_flags = 0; 808304100Sae sa.sa_handler = stopit; 809304100Sae if (sigaction(SIGALRM, &sa, 0) == -1) 810304100Sae warn("sigaction SIGALRM"); 811304100Sae 8121558Srgrimes cmd = argv[0]; 813191080Skmacy if (*cmd != 'g' && *cmd != 's') 814146079Sjmallett shutdown(s, SHUT_RD); /* Don't want to read back our messages */ 8151558Srgrimes while (--argc > 0) { 8161558Srgrimes if (**(++argv)== '-') { 8171558Srgrimes switch (key = keyword(1 + *argv)) { 8181558Srgrimes case K_LINK: 8191558Srgrimes af = AF_LINK; 8201558Srgrimes aflen = sizeof(struct sockaddr_dl); 8211558Srgrimes break; 822253427Shrs#ifdef INET 823260524Smelifaro case K_4: 8241558Srgrimes case K_INET: 8251558Srgrimes af = AF_INET; 8261558Srgrimes aflen = sizeof(struct sockaddr_in); 8271558Srgrimes break; 828253427Shrs#endif 82954263Sshin#ifdef INET6 830260524Smelifaro case K_6: 83154263Sshin case K_INET6: 83254263Sshin af = AF_INET6; 83354263Sshin aflen = sizeof(struct sockaddr_in6); 83454263Sshin break; 83554263Sshin#endif 8361558Srgrimes case K_SA: 8371558Srgrimes af = PF_ROUTE; 838253427Shrs aflen = sizeof(struct sockaddr_storage); 8391558Srgrimes break; 8401558Srgrimes case K_IFACE: 8411558Srgrimes case K_INTERFACE: 842243185Shrs nrflags |= F_INTERFACE; 8432787Spst break; 8441558Srgrimes case K_NOSTATIC: 8451558Srgrimes flags &= ~RTF_STATIC; 8461558Srgrimes break; 8471558Srgrimes case K_LOCK: 8481558Srgrimes locking = 1; 8491558Srgrimes break; 8501558Srgrimes case K_LOCKREST: 8511558Srgrimes lockrest = 1; 8521558Srgrimes break; 8531558Srgrimes case K_HOST: 854243185Shrs nrflags |= F_FORCEHOST; 8551558Srgrimes break; 8561558Srgrimes case K_REJECT: 8571558Srgrimes flags |= RTF_REJECT; 8581558Srgrimes break; 8591558Srgrimes case K_BLACKHOLE: 8601558Srgrimes flags |= RTF_BLACKHOLE; 8611558Srgrimes break; 8621558Srgrimes case K_PROTO1: 8631558Srgrimes flags |= RTF_PROTO1; 8641558Srgrimes break; 8651558Srgrimes case K_PROTO2: 8661558Srgrimes flags |= RTF_PROTO2; 8671558Srgrimes break; 86878140Sru case K_PROXY: 869243185Shrs nrflags |= F_PROXY; 87078140Sru break; 8711558Srgrimes case K_XRESOLVE: 8721558Srgrimes flags |= RTF_XRESOLVE; 8731558Srgrimes break; 8741558Srgrimes case K_STATIC: 8751558Srgrimes flags |= RTF_STATIC; 8761558Srgrimes break; 877191080Skmacy case K_STICKY: 878191080Skmacy flags |= RTF_STICKY; 879191080Skmacy break; 880191080Skmacy case K_NOSTICK: 881191080Skmacy flags &= ~RTF_STICKY; 882191080Skmacy break; 883243185Shrs case K_FIB: 884243185Shrs if (!--argc) 885243185Shrs usage(NULL); 886243185Shrs error = fiboptlist_csv(*++argv, &fibl_head); 887243185Shrs if (error) 888244325Shrs errx(EX_USAGE, 889244325Shrs "invalid fib number: %s", *argv); 890243185Shrs break; 8911558Srgrimes case K_IFA: 89247668Sru if (!--argc) 893204406Suqs usage(NULL); 894253504Shrs getaddr(RTAX_IFA, *++argv, 0, nrflags); 8951558Srgrimes break; 8961558Srgrimes case K_IFP: 89747668Sru if (!--argc) 898204406Suqs usage(NULL); 899253504Shrs getaddr(RTAX_IFP, *++argv, 0, nrflags); 9001558Srgrimes break; 9011558Srgrimes case K_GENMASK: 90247668Sru if (!--argc) 903204406Suqs usage(NULL); 904253504Shrs getaddr(RTAX_GENMASK, *++argv, 0, nrflags); 9051558Srgrimes break; 9061558Srgrimes case K_GATEWAY: 90747668Sru if (!--argc) 908204406Suqs usage(NULL); 909253504Shrs getaddr(RTAX_GATEWAY, *++argv, 0, nrflags); 910251581Shrs gateway = *argv; 9111558Srgrimes break; 9121558Srgrimes case K_DST: 91347668Sru if (!--argc) 914204406Suqs usage(NULL); 915253504Shrs if (getaddr(RTAX_DST, *++argv, &hp, nrflags)) 916243185Shrs nrflags |= F_ISHOST; 9171558Srgrimes dest = *argv; 9181558Srgrimes break; 9191558Srgrimes case K_NETMASK: 92047668Sru if (!--argc) 921204406Suqs usage(NULL); 922253504Shrs getaddr(RTAX_NETMASK, *++argv, 0, nrflags); 9231558Srgrimes /* FALLTHROUGH */ 9241558Srgrimes case K_NET: 925243185Shrs nrflags |= F_FORCENET; 9261558Srgrimes break; 92754263Sshin case K_PREFIXLEN: 92854263Sshin if (!--argc) 929204406Suqs usage(NULL); 93054263Sshin if (prefixlen(*++argv) == -1) { 931243185Shrs nrflags &= ~F_FORCENET; 932243185Shrs nrflags |= F_ISHOST; 93354263Sshin } else { 934243185Shrs nrflags |= F_FORCENET; 935243185Shrs nrflags &= ~F_ISHOST; 93654263Sshin } 93754263Sshin break; 9381558Srgrimes case K_MTU: 9391558Srgrimes case K_HOPCOUNT: 9401558Srgrimes case K_EXPIRE: 9411558Srgrimes case K_RECVPIPE: 9421558Srgrimes case K_SENDPIPE: 9431558Srgrimes case K_SSTHRESH: 9441558Srgrimes case K_RTT: 9451558Srgrimes case K_RTTVAR: 946191080Skmacy case K_WEIGHT: 94747668Sru if (!--argc) 948204406Suqs usage(NULL); 9491558Srgrimes set_metric(*++argv, key); 9501558Srgrimes break; 9511558Srgrimes default: 9521558Srgrimes usage(1+*argv); 9531558Srgrimes } 9541558Srgrimes } else { 9551558Srgrimes if ((rtm_addrs & RTA_DST) == 0) { 9561558Srgrimes dest = *argv; 957253504Shrs if (getaddr(RTAX_DST, *argv, &hp, nrflags)) 958243185Shrs nrflags |= F_ISHOST; 9591558Srgrimes } else if ((rtm_addrs & RTA_GATEWAY) == 0) { 9601558Srgrimes gateway = *argv; 961253504Shrs getaddr(RTAX_GATEWAY, *argv, &hp, nrflags); 9621558Srgrimes } else { 963253504Shrs getaddr(RTAX_NETMASK, *argv, 0, nrflags); 964243185Shrs nrflags |= F_FORCENET; 9651558Srgrimes } 9661558Srgrimes } 9671558Srgrimes } 968243185Shrs 969260472Smelifaro /* Do some sanity checks on resulting request */ 970256137Sglebius if (so[RTAX_DST].ss_len == 0) { 971256137Sglebius warnx("destination parameter required"); 972256137Sglebius usage(NULL); 973256137Sglebius } 974256137Sglebius 975260472Smelifaro if (so[RTAX_NETMASK].ss_len != 0 && 976260472Smelifaro so[RTAX_DST].ss_family != so[RTAX_NETMASK].ss_family) { 977260472Smelifaro warnx("destination and netmask family need to be the same"); 978260472Smelifaro usage(NULL); 979260472Smelifaro } 980260472Smelifaro 981243185Shrs if (nrflags & F_FORCEHOST) { 982243185Shrs nrflags |= F_ISHOST; 98354263Sshin#ifdef INET6 98454263Sshin if (af == AF_INET6) { 98554263Sshin rtm_addrs &= ~RTA_NETMASK; 986253427Shrs memset(&so[RTAX_NETMASK], 0, sizeof(so[RTAX_NETMASK])); 98754263Sshin } 988204406Suqs#endif 98954263Sshin } 990243185Shrs if (nrflags & F_FORCENET) 991243185Shrs nrflags &= ~F_ISHOST; 9921558Srgrimes flags |= RTF_UP; 993243185Shrs if (nrflags & F_ISHOST) 9941558Srgrimes flags |= RTF_HOST; 995243185Shrs if ((nrflags & F_INTERFACE) == 0) 9961558Srgrimes flags |= RTF_GATEWAY; 997246143Sglebius if (nrflags & F_PROXY) 99878140Sru flags |= RTF_ANNOUNCE; 999243185Shrs if (dest == NULL) 1000243185Shrs dest = ""; 1001243185Shrs if (gateway == NULL) 1002243185Shrs gateway = ""; 1003243185Shrs 1004243185Shrs if (TAILQ_EMPTY(&fibl_head)) { 1005243185Shrs error = fiboptlist_csv("default", &fibl_head); 1006243185Shrs if (error) 1007243185Shrs errx(EX_OSERR, "fiboptlist_csv failed."); 10081558Srgrimes } 1009243185Shrs error = 0; 1010243185Shrs TAILQ_FOREACH(fl, &fibl_head, fl_next) { 1011243185Shrs fl->fl_error = newroute_fib(fl->fl_num, cmd, flags); 1012243185Shrs if (fl->fl_error) 1013243185Shrs fl->fl_errno = errno; 1014243185Shrs error += fl->fl_error; 1015243185Shrs } 1016191080Skmacy if (*cmd == 'g' || *cmd == 's') 1017243185Shrs exit(error); 1018243185Shrs 1019243185Shrs error = 0; 102097278Sru if (!qflag) { 1021243185Shrs fibnum = 0; 1022243185Shrs TAILQ_FOREACH(fl, &fibl_head, fl_next) { 1023243185Shrs if (fl->fl_error == 0) 1024243185Shrs fibnum++; 10251558Srgrimes } 1026243185Shrs if (fibnum > 0) { 1027243185Shrs int firstfib = 1; 1028243185Shrs 1029243185Shrs printf("%s %s %s", cmd, 1030243185Shrs (nrflags & F_ISHOST) ? "host" : "net", dest); 1031243185Shrs if (*gateway) 1032243185Shrs printf(": gateway %s", gateway); 1033243185Shrs 1034243185Shrs if (numfibs > 1) { 1035243185Shrs TAILQ_FOREACH(fl, &fibl_head, fl_next) { 1036243185Shrs if (fl->fl_error == 0 1037243185Shrs && fl->fl_num >= 0) { 1038243185Shrs if (firstfib) { 1039243185Shrs printf(" fib "); 1040243185Shrs firstfib = 0; 1041243185Shrs } 1042243185Shrs printf("%d", fl->fl_num); 1043243185Shrs if (fibnum-- > 1) 1044243185Shrs printf(","); 1045243185Shrs } 1046243185Shrs } 104797278Sru } 1048243185Shrs printf("\n"); 104997278Sru } 1050340943Seugen } 1051243185Shrs 1052340943Seugen fibnum = 0; 1053340943Seugen TAILQ_FOREACH(fl, &fibl_head, fl_next) { 1054340943Seugen if (fl->fl_error != 0) { 1055340943Seugen error = 1; 1056340943Seugen if (!qflag) { 1057243185Shrs printf("%s %s %s", cmd, (nrflags & F_ISHOST) 1058243185Shrs ? "host" : "net", dest); 1059243185Shrs if (*gateway) 1060243185Shrs printf(": gateway %s", gateway); 1061243185Shrs 1062243185Shrs if (fl->fl_num >= 0) 1063243185Shrs printf(" fib %d", fl->fl_num); 1064243185Shrs 1065243185Shrs switch (fl->fl_errno) { 1066243185Shrs case ESRCH: 1067243185Shrs errmsg = "not in table"; 1068243185Shrs break; 1069243185Shrs case EBUSY: 1070243185Shrs errmsg = "entry in use"; 1071243185Shrs break; 1072243185Shrs case ENOBUFS: 1073243185Shrs errmsg = "not enough memory"; 1074243185Shrs break; 1075243185Shrs case EADDRINUSE: 1076243185Shrs /* 1077243185Shrs * handle recursion avoidance 1078243185Shrs * in rt_setgate() 1079243185Shrs */ 1080243185Shrs errmsg = "gateway uses the same route"; 1081243185Shrs break; 1082243185Shrs case EEXIST: 1083243185Shrs errmsg = "route already in table"; 1084243185Shrs break; 1085243185Shrs default: 1086243185Shrs errmsg = strerror(fl->fl_errno); 1087243185Shrs break; 1088243185Shrs } 1089243185Shrs printf(": %s\n", errmsg); 1090243185Shrs } 1091243185Shrs } 10921558Srgrimes } 1093243185Shrs exit(error); 10941558Srgrimes} 10951558Srgrimes 1096243185Shrsstatic int 1097243185Shrsnewroute_fib(int fib, char *cmd, int flags) 1098243185Shrs{ 1099243185Shrs int error; 1100243185Shrs 1101243185Shrs error = set_sofib(fib); 1102243185Shrs if (error) { 1103243185Shrs warn("fib number %d is ignored", fib); 1104243185Shrs return (error); 1105243185Shrs } 1106243185Shrs 1107243185Shrs error = rtmsg(*cmd, flags, fib); 1108243185Shrs return (error); 1109243185Shrs} 1110243185Shrs 1111253427Shrs#ifdef INET 1112204406Suqsstatic void 1113253427Shrsinet_makenetandmask(u_long net, struct sockaddr_in *sin, 1114253427Shrs struct sockaddr_in *sin_mask, u_long bits) 11151558Srgrimes{ 1116243019Sglebius u_long mask = 0; 11171558Srgrimes 11181558Srgrimes rtm_addrs |= RTA_NETMASK; 1119243019Sglebius 1120204406Suqs /* 1121243867Sglebius * MSB of net should be meaningful. 0/0 is exception. 1122243867Sglebius */ 1123243867Sglebius if (net > 0) 1124243867Sglebius while ((net & 0xff000000) == 0) 1125243867Sglebius net <<= 8; 1126243867Sglebius 1127243867Sglebius /* 1128204406Suqs * If no /xx was specified we must calculate the 1129190758Srrs * CIDR address. 1130190758Srrs */ 1131243019Sglebius if ((bits == 0) && (net != 0)) { 1132190775Srrs u_long i, j; 1133253427Shrs 1134253427Shrs for(i = 0, j = 0xff; i < 4; i++) { 1135243019Sglebius if (net & j) { 1136190758Srrs break; 1137190758Srrs } 1138190775Srrs j <<= 8; 1139190758Srrs } 1140190758Srrs /* i holds the first non zero bit */ 1141316041Sngie bits = 32 - (i*8); 1142190758Srrs } 1143190913Srrs if (bits != 0) 1144190913Srrs mask = 0xffffffff << (32 - bits); 1145173124Smtm 1146243019Sglebius sin->sin_addr.s_addr = htonl(net); 1147253427Shrs sin_mask->sin_addr.s_addr = htonl(mask); 1148253427Shrs sin_mask->sin_len = sizeof(struct sockaddr_in); 1149253427Shrs sin_mask->sin_family = AF_INET; 11501558Srgrimes} 1151253427Shrs#endif 11521558Srgrimes 115396997Sume#ifdef INET6 11541558Srgrimes/* 115596997Sume * XXX the function may need more improvement... 115696997Sume */ 115797062Sumestatic int 1158204406Suqsinet6_makenetandmask(struct sockaddr_in6 *sin6, const char *plen) 115996997Sume{ 116096997Sume 1161204406Suqs if (plen == NULL) { 116297073Sume if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && 1163277241Smelifaro sin6->sin6_scope_id == 0) 116497073Sume plen = "0"; 116596997Sume } 116696997Sume 1167204406Suqs if (plen == NULL || strcmp(plen, "128") == 0) 1168204406Suqs return (1); 116998053Sume rtm_addrs |= RTA_NETMASK; 1170204406Suqs prefixlen(plen); 1171204406Suqs return (0); 117296997Sume} 117396997Sume#endif 117496997Sume 117596997Sume/* 11761558Srgrimes * Interpret an argument as a network address of some kind, 11771558Srgrimes * returning 1 if a host address, 0 if a network address. 11781558Srgrimes */ 1179204406Suqsstatic int 1180253504Shrsgetaddr(int idx, char *str, struct hostent **hpp, int nrflags) 11811558Srgrimes{ 1182253427Shrs struct sockaddr *sa; 1183253427Shrs#if defined(INET) 1184253427Shrs struct sockaddr_in *sin; 11851558Srgrimes struct hostent *hp; 11861558Srgrimes struct netent *np; 11871558Srgrimes u_long val; 118866449Sru char *q; 1189253427Shrs#elif defined(INET6) 1190253427Shrs char *q; 1191253427Shrs#endif 11921558Srgrimes 1193253852Shrs if (idx < 0 || idx >= RTAX_MAX) 1194253852Shrs usage("internal error"); 11951558Srgrimes if (af == 0) { 1196253427Shrs#if defined(INET) 11971558Srgrimes af = AF_INET; 11981558Srgrimes aflen = sizeof(struct sockaddr_in); 1199253427Shrs#elif defined(INET6) 1200253427Shrs af = AF_INET6; 1201253427Shrs aflen = sizeof(struct sockaddr_in6); 1202253427Shrs#else 1203253427Shrs af = AF_LINK; 1204253427Shrs aflen = sizeof(struct sockaddr_dl); 1205253427Shrs#endif 12061558Srgrimes } 1207253519Shrs#ifndef INET 1208253519Shrs hpp = NULL; 1209253519Shrs#endif 1210253504Shrs rtm_addrs |= (1 << idx); 1211253504Shrs sa = (struct sockaddr *)&so[idx]; 1212253427Shrs sa->sa_family = af; 1213253427Shrs sa->sa_len = aflen; 1214253427Shrs 1215253504Shrs switch (idx) { 1216253504Shrs case RTAX_GATEWAY: 1217245168Shrs if (nrflags & F_INTERFACE) { 121878064Sume struct ifaddrs *ifap, *ifa; 1219253502Shrs struct sockaddr_dl *sdl0 = (struct sockaddr_dl *)(void *)sa; 122078064Sume struct sockaddr_dl *sdl = NULL; 122117486Sjulian 122278064Sume if (getifaddrs(&ifap)) 1223253427Shrs err(EX_OSERR, "getifaddrs"); 122417486Sjulian 1225204406Suqs for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 122678064Sume if (ifa->ifa_addr->sa_family != AF_LINK) 122778064Sume continue; 122817486Sjulian 1229204406Suqs if (strcmp(str, ifa->ifa_name) != 0) 123078064Sume continue; 123178064Sume 1232253502Shrs sdl = (struct sockaddr_dl *)(void *)ifa->ifa_addr; 123317486Sjulian } 123417486Sjulian /* If we found it, then use it */ 1235204406Suqs if (sdl != NULL) { 123678064Sume /* 123778064Sume * Note that we need to copy before calling 123878064Sume * freeifaddrs(). 123978064Sume */ 1240253427Shrs memcpy(sdl0, sdl, sdl->sdl_len); 124178064Sume } 124278064Sume freeifaddrs(ifap); 1243204406Suqs if (sdl != NULL) 124417486Sjulian return(1); 1245287920Srstone else 1246287920Srstone errx(EX_DATAERR, 1247287920Srstone "interface '%s' does not exist", str); 124817486Sjulian } 12491558Srgrimes break; 1250253504Shrs case RTAX_IFP: 1251253427Shrs sa->sa_family = AF_LINK; 12521558Srgrimes break; 12531558Srgrimes } 1254204406Suqs if (strcmp(str, "default") == 0) { 125527500Sjulian /* 1256204406Suqs * Default is net 0.0.0.0/0 125727500Sjulian */ 1258253504Shrs switch (idx) { 1259253504Shrs case RTAX_DST: 1260264539Sbz nrflags |= F_FORCENET; 1261253504Shrs getaddr(RTAX_NETMASK, str, 0, nrflags); 12621558Srgrimes break; 12631558Srgrimes } 12641558Srgrimes return (0); 12651558Srgrimes } 1266253427Shrs switch (sa->sa_family) { 126754263Sshin#ifdef INET6 126854263Sshin case AF_INET6: 126978064Sume { 127057108Sshin struct addrinfo hints, *res; 1271146546Sume int ecode; 127257108Sshin 127397073Sume q = NULL; 1274253504Shrs if (idx == RTAX_DST && (q = strchr(str, '/')) != NULL) 127597073Sume *q = '\0'; 127678064Sume memset(&hints, 0, sizeof(hints)); 1277253427Shrs hints.ai_family = sa->sa_family; 1278253427Shrs hints.ai_socktype = SOCK_DGRAM; 1279204406Suqs ecode = getaddrinfo(str, NULL, &hints, &res); 1280146546Sume if (ecode != 0 || res->ai_family != AF_INET6 || 1281253427Shrs res->ai_addrlen != sizeof(struct sockaddr_in6)) 1282253427Shrs errx(EX_OSERR, "%s: %s", str, gai_strerror(ecode)); 1283253427Shrs memcpy(sa, res->ai_addr, res->ai_addrlen); 128497062Sume freeaddrinfo(res); 128597073Sume if (q != NULL) 128697073Sume *q++ = '/'; 1287253504Shrs if (idx == RTAX_DST) 1288253502Shrs return (inet6_makenetandmask((struct sockaddr_in6 *)(void *)sa, q)); 128978064Sume return (0); 129078064Sume } 129178064Sume#endif /* INET6 */ 12921558Srgrimes case AF_LINK: 1293253502Shrs link_addr(str, (struct sockaddr_dl *)(void *)sa); 12941558Srgrimes return (1); 12951558Srgrimes 12961558Srgrimes case PF_ROUTE: 1297253427Shrs sockaddr(str, sa, sizeof(struct sockaddr_storage)); 12981558Srgrimes return (1); 1299253427Shrs#ifdef INET 13001558Srgrimes case AF_INET: 1301253427Shrs#endif 13021558Srgrimes default: 13031558Srgrimes break; 13041558Srgrimes } 13051558Srgrimes 1306253427Shrs#ifdef INET 1307253502Shrs sin = (struct sockaddr_in *)(void *)sa; 13081558Srgrimes if (hpp == NULL) 13091558Srgrimes hpp = &hp; 13101558Srgrimes *hpp = NULL; 131124558Sphk 1312204406Suqs q = strchr(str,'/'); 1313253504Shrs if (q != NULL && idx == RTAX_DST) { 131424558Sphk *q = '\0'; 1315204406Suqs if ((val = inet_network(str)) != INADDR_NONE) { 1316253427Shrs inet_makenetandmask(val, sin, 1317253427Shrs (struct sockaddr_in *)&so[RTAX_NETMASK], 1318253427Shrs strtoul(q+1, 0, 0)); 131924558Sphk return (0); 132024558Sphk } 132166449Sru *q = '/'; 132224558Sphk } 1323264539Sbz if ((idx != RTAX_DST || (nrflags & F_FORCENET) == 0) && 1324253427Shrs inet_aton(str, &sin->sin_addr)) { 1325253427Shrs val = sin->sin_addr.s_addr; 1326264539Sbz if (idx != RTAX_DST || nrflags & F_FORCEHOST || 1327253427Shrs inet_lnaof(sin->sin_addr) != INADDR_ANY) 13281558Srgrimes return (1); 13291558Srgrimes else { 13301558Srgrimes val = ntohl(val); 13311558Srgrimes goto netdone; 13321558Srgrimes } 13331558Srgrimes } 1334264539Sbz if (idx == RTAX_DST && (nrflags & F_FORCEHOST) == 0 && 1335204406Suqs ((val = inet_network(str)) != INADDR_NONE || 1336204406Suqs ((np = getnetbyname(str)) != NULL && (val = np->n_net) != 0))) { 13371558Srgrimesnetdone: 1338253427Shrs inet_makenetandmask(val, sin, 1339253427Shrs (struct sockaddr_in *)&so[RTAX_NETMASK], 0); 13401558Srgrimes return (0); 13411558Srgrimes } 1342204406Suqs hp = gethostbyname(str); 1343204406Suqs if (hp != NULL) { 13441558Srgrimes *hpp = hp; 1345253427Shrs sin->sin_family = hp->h_addrtype; 1346253427Shrs memmove((char *)&sin->sin_addr, hp->h_addr, 1347253427Shrs MIN((size_t)hp->h_length, sizeof(sin->sin_addr))); 13481558Srgrimes return (1); 13491558Srgrimes } 1350253427Shrs#endif 1351204406Suqs errx(EX_NOHOST, "bad address: %s", str); 13521558Srgrimes} 13531558Srgrimes 1354204406Suqsstatic int 1355204406Suqsprefixlen(const char *str) 135654263Sshin{ 1357204406Suqs int len = atoi(str), q, r; 135854263Sshin int max; 135954263Sshin char *p; 13601558Srgrimes 1361316041Sngie rtm_addrs |= RTA_NETMASK; 136254263Sshin switch (af) { 136354263Sshin#ifdef INET6 136454263Sshin case AF_INET6: 1365253427Shrs { 1366253427Shrs struct sockaddr_in6 *sin6 = 1367253427Shrs (struct sockaddr_in6 *)&so[RTAX_NETMASK]; 1368253427Shrs 136954263Sshin max = 128; 1370253427Shrs p = (char *)&sin6->sin6_addr; 1371253427Shrs sin6->sin6_family = AF_INET6; 1372253427Shrs sin6->sin6_len = sizeof(*sin6); 137354263Sshin break; 1374253427Shrs } 137554263Sshin#endif 1376253427Shrs#ifdef INET 137754263Sshin case AF_INET: 1378253427Shrs { 1379253427Shrs struct sockaddr_in *sin = 1380253427Shrs (struct sockaddr_in *)&so[RTAX_NETMASK]; 1381253427Shrs 138254263Sshin max = 32; 1383253427Shrs p = (char *)&sin->sin_addr; 1384253427Shrs sin->sin_family = AF_INET; 1385253427Shrs sin->sin_len = sizeof(*sin); 138654263Sshin break; 1387253427Shrs } 1388253427Shrs#endif 138954263Sshin default: 1390253427Shrs errx(EX_OSERR, "prefixlen not supported in this af"); 139154263Sshin } 139254263Sshin 1393253427Shrs if (len < 0 || max < len) 1394253427Shrs errx(EX_USAGE, "%s: invalid prefixlen", str); 1395316041Sngie 139654263Sshin q = len >> 3; 139754263Sshin r = len & 7; 139854263Sshin memset((void *)p, 0, max / 8); 139954263Sshin if (q > 0) 140054263Sshin memset((void *)p, 0xff, q); 140154263Sshin if (r > 0) 140254263Sshin *((u_char *)p + q) = (0xff00 >> r) & 0xff; 140354263Sshin if (len == max) 1404204406Suqs return (-1); 140554263Sshin else 1406204406Suqs return (len); 140754263Sshin} 140854263Sshin 1409204406Suqsstatic void 1410196527Scharnierinterfaces(void) 14111558Srgrimes{ 14121558Srgrimes size_t needed; 14131558Srgrimes int mib[6]; 1414128782Sambrisko char *buf, *lim, *next, count = 0; 141592806Sobrien struct rt_msghdr *rtm; 14161558Srgrimes 1417128782Sambriskoretry2: 14181558Srgrimes mib[0] = CTL_NET; 14191558Srgrimes mib[1] = PF_ROUTE; 14201558Srgrimes mib[2] = 0; /* protocol */ 1421253427Shrs mib[3] = AF_UNSPEC; 14221558Srgrimes mib[4] = NET_RT_IFLIST; 14231558Srgrimes mib[5] = 0; /* no flags */ 1424253427Shrs if (sysctl(mib, nitems(mib), NULL, &needed, NULL, 0) < 0) 142513171Swollman err(EX_OSERR, "route-sysctl-estimate"); 14261558Srgrimes if ((buf = malloc(needed)) == NULL) 142737907Scharnier errx(EX_OSERR, "malloc failed"); 1428253427Shrs if (sysctl(mib, nitems(mib), buf, &needed, NULL, 0) < 0) { 1429128782Sambrisko if (errno == ENOMEM && count++ < 10) { 1430128782Sambrisko warnx("Routing table grew, retrying"); 1431128782Sambrisko sleep(1); 1432128782Sambrisko free(buf); 1433128782Sambrisko goto retry2; 1434128782Sambrisko } 143513171Swollman err(EX_OSERR, "actual retrieval of interface table"); 1436128782Sambrisko } 14371558Srgrimes lim = buf + needed; 14381558Srgrimes for (next = buf; next < lim; next += rtm->rtm_msglen) { 1439253502Shrs rtm = (struct rt_msghdr *)(void *)next; 14401558Srgrimes print_rtmsg(rtm, rtm->rtm_msglen); 14411558Srgrimes } 14421558Srgrimes} 14431558Srgrimes 1444204406Suqsstatic void 1445243185Shrsmonitor(int argc, char *argv[]) 14461558Srgrimes{ 1447243185Shrs int n, fib, error; 1448243185Shrs char msg[2048], *endptr; 14491558Srgrimes 1450243185Shrs fib = defaultfib; 1451243185Shrs while (argc > 1) { 1452243185Shrs argc--; 1453243185Shrs argv++; 1454243185Shrs if (**argv != '-') 1455243185Shrs usage(*argv); 1456243185Shrs switch (keyword(*argv + 1)) { 1457243185Shrs case K_FIB: 1458243185Shrs if (!--argc) 1459243185Shrs usage(*argv); 1460244325Shrs errno = 0; 1461243185Shrs fib = strtol(*++argv, &endptr, 0); 1462244325Shrs if (errno == 0) { 1463244325Shrs if (*endptr != '\0' || 1464244325Shrs fib < 0 || 1465244325Shrs (numfibs != -1 && fib > numfibs - 1)) 1466244325Shrs errno = EINVAL; 1467244325Shrs } 1468244325Shrs if (errno) 1469244325Shrs errx(EX_USAGE, "invalid fib number: %s", *argv); 1470243185Shrs break; 1471243185Shrs default: 1472243185Shrs usage(*argv); 1473243185Shrs } 1474243185Shrs } 1475243185Shrs error = set_sofib(fib); 1476243185Shrs if (error) 1477243185Shrs errx(EX_USAGE, "invalid fib number: %d", fib); 1478243185Shrs 14791558Srgrimes verbose = 1; 14801558Srgrimes if (debugonly) { 14811558Srgrimes interfaces(); 14821558Srgrimes exit(0); 14831558Srgrimes } 1484204406Suqs for (;;) { 148554263Sshin time_t now; 14861558Srgrimes n = read(s, msg, 2048); 148754263Sshin now = time(NULL); 1488253427Shrs (void)printf("\ngot message of size %d on %s", n, ctime(&now)); 1489253502Shrs print_rtmsg((struct rt_msghdr *)(void *)msg, n); 14901558Srgrimes } 14911558Srgrimes} 14921558Srgrimes 1493204406Suqsstatic int 1494243185Shrsrtmsg(int cmd, int flags, int fib) 14951558Srgrimes{ 14961558Srgrimes int rlen; 149792806Sobrien char *cp = m_rtmsg.m_space; 149892806Sobrien int l; 14991558Srgrimes 1500253427Shrs#define NEXTADDR(w, u) \ 1501253427Shrs if (rtm_addrs & (w)) { \ 1502253443Shrs l = (((struct sockaddr *)&(u))->sa_len == 0) ? \ 1503253443Shrs sizeof(long) : \ 1504253443Shrs 1 + ((((struct sockaddr *)&(u))->sa_len - 1) \ 1505253443Shrs | (sizeof(long) - 1)); \ 1506253427Shrs memmove(cp, (char *)&(u), l); \ 1507253427Shrs cp += l; \ 1508253427Shrs if (verbose) \ 1509253427Shrs sodump((struct sockaddr *)&(u), #w); \ 15101558Srgrimes } 15111558Srgrimes 15121558Srgrimes errno = 0; 151385048Sru memset(&m_rtmsg, 0, sizeof(m_rtmsg)); 15141558Srgrimes if (cmd == 'a') 15151558Srgrimes cmd = RTM_ADD; 15161558Srgrimes else if (cmd == 'c') 15171558Srgrimes cmd = RTM_CHANGE; 1518191080Skmacy else if (cmd == 'g' || cmd == 's') { 15191558Srgrimes cmd = RTM_GET; 1520253427Shrs if (so[RTAX_IFP].ss_family == 0) { 1521253427Shrs so[RTAX_IFP].ss_family = AF_LINK; 1522253427Shrs so[RTAX_IFP].ss_len = sizeof(struct sockaddr_dl); 15231558Srgrimes rtm_addrs |= RTA_IFP; 15241558Srgrimes } 1525330497Seugen } else { 15261558Srgrimes cmd = RTM_DELETE; 1527330497Seugen flags |= RTF_PINNED; 1528330497Seugen } 15291558Srgrimes#define rtm m_rtmsg.m_rtm 15301558Srgrimes rtm.rtm_type = cmd; 15311558Srgrimes rtm.rtm_flags = flags; 15321558Srgrimes rtm.rtm_version = RTM_VERSION; 1533258937Seadler rtm.rtm_seq = ++rtm_seq; 15341558Srgrimes rtm.rtm_addrs = rtm_addrs; 15351558Srgrimes rtm.rtm_rmx = rt_metrics; 15361558Srgrimes rtm.rtm_inits = rtm_inits; 15371558Srgrimes 1538253427Shrs NEXTADDR(RTA_DST, so[RTAX_DST]); 1539253427Shrs NEXTADDR(RTA_GATEWAY, so[RTAX_GATEWAY]); 1540253427Shrs NEXTADDR(RTA_NETMASK, so[RTAX_NETMASK]); 1541253427Shrs NEXTADDR(RTA_GENMASK, so[RTAX_GENMASK]); 1542253427Shrs NEXTADDR(RTA_IFP, so[RTAX_IFP]); 1543253427Shrs NEXTADDR(RTA_IFA, so[RTAX_IFA]); 15441558Srgrimes rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; 15451558Srgrimes if (verbose) 15461558Srgrimes print_rtmsg(&rtm, l); 15471558Srgrimes if (debugonly) 15481558Srgrimes return (0); 15491558Srgrimes if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { 1550273906Smelifaro switch (errno) { 1551273906Smelifaro case EPERM: 1552129034Scsjp err(1, "writing to routing socket"); 1553274086Smelifaro break; 1554273906Smelifaro case ESRCH: 1555273906Smelifaro warnx("route has not been found"); 1556273906Smelifaro break; 1557273906Smelifaro case EEXIST: 1558273906Smelifaro /* Handled by newroute() */ 1559273906Smelifaro break; 1560273906Smelifaro default: 1561273906Smelifaro warn("writing to routing socket"); 1562273906Smelifaro } 15631558Srgrimes return (-1); 15641558Srgrimes } 15651558Srgrimes if (cmd == RTM_GET) { 1566304100Sae stop_read = 0; 1567304100Sae alarm(READ_TIMEOUT); 15681558Srgrimes do { 15691558Srgrimes l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); 1570304100Sae } while (l > 0 && stop_read == 0 && 1571304100Sae (rtm.rtm_seq != rtm_seq || rtm.rtm_pid != pid)); 1572304100Sae if (stop_read != 0) { 1573304100Sae warnx("read from routing socket timed out"); 1574304100Sae return (-1); 1575304100Sae } else 1576304100Sae alarm(0); 15771558Srgrimes if (l < 0) 157813171Swollman warn("read from routing socket"); 15791558Srgrimes else 1580243185Shrs print_getmsg(&rtm, l, fib); 15811558Srgrimes } 15821558Srgrimes#undef rtm 15831558Srgrimes return (0); 15841558Srgrimes} 15851558Srgrimes 1586258906Seadlerstatic const char *const msgtypes[] = { 15871558Srgrimes "", 15881558Srgrimes "RTM_ADD: Add Route", 15891558Srgrimes "RTM_DELETE: Delete Route", 15901558Srgrimes "RTM_CHANGE: Change Metrics or flags", 15911558Srgrimes "RTM_GET: Report Metrics", 15921558Srgrimes "RTM_LOSING: Kernel Suspects Partitioning", 15931558Srgrimes "RTM_REDIRECT: Told to use different route", 15941558Srgrimes "RTM_MISS: Lookup failed on this address", 15951558Srgrimes "RTM_LOCK: fix specified metrics", 15961558Srgrimes "RTM_OLDADD: caused by SIOCADDRT", 15971558Srgrimes "RTM_OLDDEL: caused by SIOCDELRT", 15981558Srgrimes "RTM_RESOLVE: Route created by cloning", 15991558Srgrimes "RTM_NEWADDR: address being added to iface", 16001558Srgrimes "RTM_DELADDR: address being removed from iface", 16011558Srgrimes "RTM_IFINFO: iface status change", 160221465Swollman "RTM_NEWMADDR: new multicast group membership on iface", 160321465Swollman "RTM_DELMADDR: multicast group membership removed from iface", 160489498Sru "RTM_IFANNOUNCE: interface arrival/departure", 1605216296Sglebius "RTM_IEEE80211: IEEE 802.11 wireless event", 16061558Srgrimes}; 16071558Srgrimes 1608253427Shrsstatic const char metricnames[] = 1609253427Shrs "\011weight\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire" 1610253427Shrs "\1mtu"; 1611253427Shrsstatic const char routeflags[] = 1612253427Shrs "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE" 1613253427Shrs "\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE" 1614253427Shrs "\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3" 1615274611Smelifaro "\024FIXEDMTU\025PINNED\026LOCAL\027BROADCAST\030MULTICAST\035STICKY"; 1616253427Shrsstatic const char ifnetflags[] = 1617253427Shrs "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP" 1618253427Shrs "\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1" 1619253427Shrs "\017LINK2\020MULTICAST"; 1620253427Shrsstatic const char addrnames[] = 1621253427Shrs "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD"; 16221558Srgrimes 1623216297Sglebiusstatic const char errfmt[] = 1624253427Shrs "\n%s: truncated route message, only %zu bytes left\n"; 1625216297Sglebius 1626204406Suqsstatic void 1627216297Sglebiusprint_rtmsg(struct rt_msghdr *rtm, size_t msglen) 16281558Srgrimes{ 16291558Srgrimes struct if_msghdr *ifm; 16301558Srgrimes struct ifa_msghdr *ifam; 163121465Swollman#ifdef RTM_NEWMADDR 163221465Swollman struct ifma_msghdr *ifmam; 163321465Swollman#endif 163489498Sru struct if_announcemsghdr *ifan; 1635204406Suqs const char *state; 16361558Srgrimes 16371558Srgrimes if (verbose == 0) 16381558Srgrimes return; 16391558Srgrimes if (rtm->rtm_version != RTM_VERSION) { 1640253427Shrs (void)printf("routing message version %d not understood\n", 16411558Srgrimes rtm->rtm_version); 16421558Srgrimes return; 16431558Srgrimes } 1644253517Shrs if (rtm->rtm_type < nitems(msgtypes)) 164589498Sru (void)printf("%s: ", msgtypes[rtm->rtm_type]); 164689498Sru else 1647216297Sglebius (void)printf("unknown type %d: ", rtm->rtm_type); 164889498Sru (void)printf("len %d, ", rtm->rtm_msglen); 1649216297Sglebius 1650216297Sglebius#define REQUIRE(x) do { \ 1651216297Sglebius if (msglen < sizeof(x)) \ 1652216297Sglebius goto badlen; \ 1653216297Sglebius else \ 1654216297Sglebius msglen -= sizeof(x); \ 1655216297Sglebius } while (0) 1656216297Sglebius 16571558Srgrimes switch (rtm->rtm_type) { 16581558Srgrimes case RTM_IFINFO: 1659216297Sglebius REQUIRE(struct if_msghdr); 16601558Srgrimes ifm = (struct if_msghdr *)rtm; 1661253427Shrs (void)printf("if# %d, ", ifm->ifm_index); 1662128878Sandre switch (ifm->ifm_data.ifi_link_state) { 1663128878Sandre case LINK_STATE_DOWN: 1664128878Sandre state = "down"; 1665128878Sandre break; 1666128878Sandre case LINK_STATE_UP: 1667128878Sandre state = "up"; 1668128878Sandre break; 1669128878Sandre default: 1670128878Sandre state = "unknown"; 1671128878Sandre break; 1672128878Sandre } 1673253427Shrs (void)printf("link: %s, flags:", state); 1674253427Shrs printb(ifm->ifm_flags, ifnetflags); 1675216297Sglebius pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs, msglen); 16761558Srgrimes break; 16771558Srgrimes case RTM_NEWADDR: 16781558Srgrimes case RTM_DELADDR: 1679216297Sglebius REQUIRE(struct ifa_msghdr); 16801558Srgrimes ifam = (struct ifa_msghdr *)rtm; 1681253427Shrs (void)printf("metric %d, flags:", ifam->ifam_metric); 1682253427Shrs printb(ifam->ifam_flags, routeflags); 1683216297Sglebius pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs, msglen); 16841558Srgrimes break; 168521465Swollman#ifdef RTM_NEWMADDR 168621465Swollman case RTM_NEWMADDR: 168721465Swollman case RTM_DELMADDR: 1688216297Sglebius REQUIRE(struct ifma_msghdr); 168921465Swollman ifmam = (struct ifma_msghdr *)rtm; 1690216297Sglebius pmsg_addrs((char *)(ifmam + 1), ifmam->ifmam_addrs, msglen); 169121465Swollman break; 169221465Swollman#endif 169389498Sru case RTM_IFANNOUNCE: 1694216297Sglebius REQUIRE(struct if_announcemsghdr); 169589498Sru ifan = (struct if_announcemsghdr *)rtm; 1696253427Shrs (void)printf("if# %d, what: ", ifan->ifan_index); 169789498Sru switch (ifan->ifan_what) { 169889498Sru case IFAN_ARRIVAL: 1699253427Shrs (void)printf("arrival"); 170089498Sru break; 170189498Sru case IFAN_DEPARTURE: 170289498Sru printf("departure"); 170389498Sru break; 170489498Sru default: 170589498Sru printf("#%d", ifan->ifan_what); 170689498Sru break; 170789498Sru } 170889498Sru printf("\n"); 1709243860Sglebius fflush(stdout); 171089498Sru break; 171189498Sru 17121558Srgrimes default: 1713253427Shrs printf("pid: %ld, seq %d, errno %d, flags:", 171413171Swollman (long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno); 1715253427Shrs printb(rtm->rtm_flags, routeflags); 1716216297Sglebius pmsg_common(rtm, msglen); 17171558Srgrimes } 1718216297Sglebius 1719216297Sglebius return; 1720216297Sglebius 1721216297Sglebiusbadlen: 1722216297Sglebius (void)printf(errfmt, __func__, msglen); 1723216297Sglebius#undef REQUIRE 17241558Srgrimes} 17251558Srgrimes 1726204406Suqsstatic void 1727243185Shrsprint_getmsg(struct rt_msghdr *rtm, int msglen, int fib) 17281558Srgrimes{ 1729253504Shrs struct sockaddr *sp[RTAX_MAX]; 1730256695Shrs struct timespec ts; 173192806Sobrien char *cp; 173292806Sobrien int i; 17331558Srgrimes 1734253504Shrs memset(sp, 0, sizeof(sp)); 1735253427Shrs (void)printf(" route to: %s\n", 1736253427Shrs routename((struct sockaddr *)&so[RTAX_DST])); 17371558Srgrimes if (rtm->rtm_version != RTM_VERSION) { 173813171Swollman warnx("routing message version %d not understood", 173913171Swollman rtm->rtm_version); 17401558Srgrimes return; 17411558Srgrimes } 17421558Srgrimes if (rtm->rtm_msglen > msglen) { 174337907Scharnier warnx("message length mismatch, in packet %d, returned %d", 174413171Swollman rtm->rtm_msglen, msglen); 1745253517Shrs return; 17461558Srgrimes } 17471558Srgrimes if (rtm->rtm_errno) { 174813171Swollman errno = rtm->rtm_errno; 174913171Swollman warn("message indicates error %d", errno); 17501558Srgrimes return; 17511558Srgrimes } 17521558Srgrimes cp = ((char *)(rtm + 1)); 1753253589Shrs for (i = 0; i < RTAX_MAX; i++) 1754253589Shrs if (rtm->rtm_addrs & (1 << i)) { 1755253504Shrs sp[i] = (struct sockaddr *)cp; 1756253589Shrs cp += SA_SIZE((struct sockaddr *)cp); 1757253589Shrs } 1758253589Shrs if ((rtm->rtm_addrs & RTA_IFP) && 1759253589Shrs (sp[RTAX_IFP]->sa_family != AF_LINK || 1760253589Shrs ((struct sockaddr_dl *)(void *)sp[RTAX_IFP])->sdl_nlen == 0)) 1761253504Shrs sp[RTAX_IFP] = NULL; 1762253504Shrs if (sp[RTAX_DST]) 1763253504Shrs (void)printf("destination: %s\n", routename(sp[RTAX_DST])); 1764253504Shrs if (sp[RTAX_NETMASK]) 1765253504Shrs (void)printf(" mask: %s\n", routename(sp[RTAX_NETMASK])); 1766253504Shrs if (sp[RTAX_GATEWAY] && (rtm->rtm_flags & RTF_GATEWAY)) 1767253504Shrs (void)printf(" gateway: %s\n", routename(sp[RTAX_GATEWAY])); 1768243185Shrs if (fib >= 0) 1769243185Shrs (void)printf(" fib: %u\n", (unsigned int)fib); 1770253504Shrs if (sp[RTAX_IFP]) 17711558Srgrimes (void)printf(" interface: %.*s\n", 1772253504Shrs ((struct sockaddr_dl *)(void *)sp[RTAX_IFP])->sdl_nlen, 1773253504Shrs ((struct sockaddr_dl *)(void *)sp[RTAX_IFP])->sdl_data); 17741558Srgrimes (void)printf(" flags: "); 1775253427Shrs printb(rtm->rtm_flags, routeflags); 17761558Srgrimes 17771558Srgrimes#define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ') 17781558Srgrimes#define msec(u) (((u) + 500) / 1000) /* usec to msec */ 1779253517Shrs printf("\n%9s %9s %9s %9s %9s %10s %9s\n", "recvpipe", 1780253517Shrs "sendpipe", "ssthresh", "rtt,msec", "mtu ", "weight", "expire"); 1781256695Shrs printf("%8lu%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE)); 1782256695Shrs printf("%8lu%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE)); 1783256695Shrs printf("%8lu%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH)); 1784256695Shrs printf("%8lu%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT)); 1785256695Shrs printf("%8lu%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU)); 1786256695Shrs printf("%8lu%c ", rtm->rtm_rmx.rmx_weight, lock(WEIGHT)); 1787256695Shrs if (rtm->rtm_rmx.rmx_expire > 0) 1788256695Shrs clock_gettime(CLOCK_REALTIME_FAST, &ts); 1789256695Shrs else 1790256695Shrs ts.tv_sec = 0; 1791256715Shrs printf("%8ld%c\n", (long)(rtm->rtm_rmx.rmx_expire - ts.tv_sec), 1792256715Shrs lock(EXPIRE)); 17931558Srgrimes#undef lock 17941558Srgrimes#undef msec 17951558Srgrimes#define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD) 17961558Srgrimes if (verbose) 1797216297Sglebius pmsg_common(rtm, msglen); 17981558Srgrimes else if (rtm->rtm_addrs &~ RTA_IGN) { 1799253427Shrs (void)printf("sockaddrs: "); 1800253427Shrs printb(rtm->rtm_addrs, addrnames); 18011558Srgrimes putchar('\n'); 18021558Srgrimes } 18031558Srgrimes#undef RTA_IGN 18041558Srgrimes} 18051558Srgrimes 1806204406Suqsstatic void 1807216297Sglebiuspmsg_common(struct rt_msghdr *rtm, size_t msglen) 18081558Srgrimes{ 1809253427Shrs 1810253427Shrs (void)printf("\nlocks: "); 1811253427Shrs printb(rtm->rtm_rmx.rmx_locks, metricnames); 1812253427Shrs (void)printf(" inits: "); 1813253427Shrs printb(rtm->rtm_inits, metricnames); 1814216297Sglebius if (msglen > sizeof(struct rt_msghdr)) 1815216297Sglebius pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs, 1816216297Sglebius msglen - sizeof(struct rt_msghdr)); 1817216297Sglebius else 1818253427Shrs (void)fflush(stdout); 18191558Srgrimes} 18201558Srgrimes 1821204406Suqsstatic void 1822216297Sglebiuspmsg_addrs(char *cp, int addrs, size_t len) 18231558Srgrimes{ 182492806Sobrien struct sockaddr *sa; 18251558Srgrimes int i; 18261558Srgrimes 182771061Sphk if (addrs == 0) { 1828253427Shrs (void)putchar('\n'); 18291558Srgrimes return; 183071061Sphk } 1831253427Shrs (void)printf("\nsockaddrs: "); 1832253427Shrs printb(addrs, addrnames); 1833253427Shrs putchar('\n'); 1834253517Shrs for (i = 0; i < RTAX_MAX; i++) 1835253517Shrs if (addrs & (1 << i)) { 18361558Srgrimes sa = (struct sockaddr *)cp; 1837216297Sglebius if (len == 0 || len < SA_SIZE(sa)) { 1838253427Shrs (void)printf(errfmt, __func__, len); 1839216297Sglebius break; 1840216297Sglebius } 1841253427Shrs (void)printf(" %s", routename(sa)); 1842216297Sglebius len -= SA_SIZE(sa); 1843128186Sluigi cp += SA_SIZE(sa); 18441558Srgrimes } 1845253427Shrs (void)putchar('\n'); 1846253427Shrs (void)fflush(stdout); 18471558Srgrimes} 18481558Srgrimes 1849204406Suqsstatic void 1850253427Shrsprintb(int b, const char *str) 18511558Srgrimes{ 185292806Sobrien int i; 18531558Srgrimes int gotsome = 0; 18541558Srgrimes 18551558Srgrimes if (b == 0) 18561558Srgrimes return; 1857204406Suqs while ((i = *str++) != 0) { 18581558Srgrimes if (b & (1 << (i-1))) { 18591558Srgrimes if (gotsome == 0) 18601558Srgrimes i = '<'; 18611558Srgrimes else 18621558Srgrimes i = ','; 1863253427Shrs putchar(i); 18641558Srgrimes gotsome = 1; 1865204406Suqs for (; (i = *str) > 32; str++) 1866253427Shrs putchar(i); 18671558Srgrimes } else 1868204406Suqs while (*str > 32) 1869204406Suqs str++; 18701558Srgrimes } 18711558Srgrimes if (gotsome) 1872253427Shrs putchar('>'); 18731558Srgrimes} 18741558Srgrimes 18751558Srgrimesint 1876204406Suqskeyword(const char *cp) 18771558Srgrimes{ 1878258907Seadler const struct keytab *kt = keywords; 18791558Srgrimes 1880204406Suqs while (kt->kt_cp != NULL && strcmp(kt->kt_cp, cp) != 0) 18811558Srgrimes kt++; 1882204406Suqs return (kt->kt_i); 18831558Srgrimes} 18841558Srgrimes 1885204406Suqsstatic void 1886253427Shrssodump(struct sockaddr *sa, const char *which) 18871558Srgrimes{ 1888253427Shrs#ifdef INET6 1889253427Shrs char nbuf[INET6_ADDRSTRLEN]; 1890253427Shrs#endif 1891253427Shrs 1892253427Shrs switch (sa->sa_family) { 18931558Srgrimes case AF_LINK: 1894253427Shrs (void)printf("%s: link %s; ", which, 1895253502Shrs link_ntoa((struct sockaddr_dl *)(void *)sa)); 18961558Srgrimes break; 1897253427Shrs#ifdef INET 18981558Srgrimes case AF_INET: 1899253427Shrs (void)printf("%s: inet %s; ", which, 1900253502Shrs inet_ntoa(((struct sockaddr_in *)(void *)sa)->sin_addr)); 19011558Srgrimes break; 1902253427Shrs#endif 1903253427Shrs#ifdef INET6 1904253427Shrs case AF_INET6: 1905253427Shrs (void)printf("%s: inet6 %s; ", which, inet_ntop(sa->sa_family, 1906253502Shrs &((struct sockaddr_in6 *)(void *)sa)->sin6_addr, nbuf, 1907253427Shrs sizeof(nbuf))); 1908253427Shrs break; 1909253427Shrs#endif 19101558Srgrimes } 1911253427Shrs (void)fflush(stdout); 19121558Srgrimes} 19131558Srgrimes 19141558Srgrimes/* States*/ 19151558Srgrimes#define VIRGIN 0 19161558Srgrimes#define GOTONE 1 19171558Srgrimes#define GOTTWO 2 19181558Srgrimes/* Inputs */ 19191558Srgrimes#define DIGIT (4*0) 19201558Srgrimes#define END (4*1) 19211558Srgrimes#define DELIM (4*2) 19221558Srgrimes 1923204406Suqsstatic void 1924253427Shrssockaddr(char *addr, struct sockaddr *sa, size_t size) 19251558Srgrimes{ 192692806Sobrien char *cp = (char *)sa; 19271558Srgrimes char *cplim = cp + size; 192892806Sobrien int byte = 0, state = VIRGIN, new = 0 /* foil gcc */; 19291558Srgrimes 193085048Sru memset(cp, 0, size); 19311558Srgrimes cp++; 19321558Srgrimes do { 19331558Srgrimes if ((*addr >= '0') && (*addr <= '9')) { 19341558Srgrimes new = *addr - '0'; 19351558Srgrimes } else if ((*addr >= 'a') && (*addr <= 'f')) { 19361558Srgrimes new = *addr - 'a' + 10; 19371558Srgrimes } else if ((*addr >= 'A') && (*addr <= 'F')) { 19381558Srgrimes new = *addr - 'A' + 10; 1939204406Suqs } else if (*addr == '\0') 19401558Srgrimes state |= END; 19411558Srgrimes else 19421558Srgrimes state |= DELIM; 19431558Srgrimes addr++; 19441558Srgrimes switch (state /* | INPUT */) { 19451558Srgrimes case GOTTWO | DIGIT: 19461558Srgrimes *cp++ = byte; /*FALLTHROUGH*/ 19471558Srgrimes case VIRGIN | DIGIT: 19481558Srgrimes state = GOTONE; byte = new; continue; 19491558Srgrimes case GOTONE | DIGIT: 19501558Srgrimes state = GOTTWO; byte = new + (byte << 4); continue; 19511558Srgrimes default: /* | DELIM */ 19521558Srgrimes state = VIRGIN; *cp++ = byte; byte = 0; continue; 19531558Srgrimes case GOTONE | END: 19541558Srgrimes case GOTTWO | END: 19551558Srgrimes *cp++ = byte; /* FALLTHROUGH */ 19561558Srgrimes case VIRGIN | END: 19571558Srgrimes break; 19581558Srgrimes } 19591558Srgrimes break; 19601558Srgrimes } while (cp < cplim); 19611558Srgrimes sa->sa_len = cp - (char *)sa; 19621558Srgrimes} 1963