Home | History | Annotate | Line # | Download | only in route
route.c revision 1.1
      1 /*
      2  * Copyright (c) 1983, 1989 The Regents of the University of California.
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  * 3. All advertising materials mentioning features or use of this software
     14  *    must display the following acknowledgement:
     15  *	This product includes software developed by the University of
     16  *	California, Berkeley and its contributors.
     17  * 4. Neither the name of the University nor the names of its contributors
     18  *    may be used to endorse or promote products derived from this software
     19  *    without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31  * SUCH DAMAGE.
     32  */
     33 
     34 #ifndef lint
     35 char copyright[] =
     36 "@(#) Copyright (c) 1983 The Regents of the University of California.\n\
     37  All rights reserved.\n";
     38 #endif /* not lint */
     39 
     40 #ifndef lint
     41 static char sccsid[] = "@(#)route.c	5.35 (Berkeley) 6/27/91";
     42 #endif /* not lint */
     43 
     44 #include <sys/param.h>
     45 #include <sys/file.h>
     46 #include <sys/socket.h>
     47 #include <sys/ioctl.h>
     48 #include <sys/mbuf.h>
     49 #include <sys/kinfo.h>
     50 
     51 #include <net/route.h>
     52 #include <net/if_dl.h>
     53 #include <netinet/in.h>
     54 #ifdef notyet
     55 #include <netns/ns.h>
     56 #include <netiso/iso.h>
     57 #include <netccitt/x25.h>
     58 #endif
     59 #include <arpa/inet.h>
     60 #include <netdb.h>
     61 
     62 #include <errno.h>
     63 #include <unistd.h>
     64 #include <stdio.h>
     65 #include <ctype.h>
     66 #include <stdlib.h>
     67 #include <string.h>
     68 #include <paths.h>
     69 
     70 struct keytab {
     71 	char	*kt_cp;
     72 	int	kt_i;
     73 } keywords[] = {
     74 #include "keywords.h"
     75 {0, 0}
     76 };
     77 
     78 struct	ortentry route;
     79 union	sockunion {
     80 	struct	sockaddr sa;
     81 	struct	sockaddr_in sin;
     82 #ifdef notdef
     83 	struct	sockaddr_ns sns;
     84 	struct	sockaddr_iso siso;
     85 #endif
     86 	struct	sockaddr_dl sdl;
     87 #ifdef notdef
     88 	struct	sockaddr_x25 sx25;
     89 #endif
     90 } so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp;
     91 
     92 union sockunion *so_addrs[] =
     93 	{ &so_dst, &so_gate, &so_mask, &so_genmask, &so_ifp, &so_ifa, 0};
     94 
     95 typedef union sockunion *sup;
     96 int	pid, rtm_addrs, uid;
     97 int	s;
     98 int	forcehost, forcenet, doflush, nflag, af, qflag, tflag, Cflag, keyword();
     99 int	iflag, verbose, aflen = sizeof (struct sockaddr_in);
    100 int	locking, lockrest, debugonly;
    101 struct	sockaddr_in sin = { sizeof(sin), AF_INET };
    102 struct	rt_metrics rt_metrics;
    103 u_long  rtm_inits;
    104 struct	in_addr inet_makeaddr();
    105 char	*routename(), *netname();
    106 void	flushroutes(), newroute(), monitor(), sockaddr();
    107 void	print_getmsg(), print_rtmsg(), pmsg_common(), sodump(), bprintf();
    108 int	getaddr(), rtmsg();
    109 extern	char *inet_ntoa(),
    110 #ifdef notdef
    111 *iso_ntoa(),
    112 #endif
    113 *link_ntoa();
    114 
    115 void
    116 usage(cp)
    117 	char *cp;
    118 {
    119 	if (cp)
    120 		(void) fprintf(stderr, "route: botched keyword: %s\n", cp);
    121 	(void) fprintf(stderr,
    122 	    "usage: route [ -Cnqv ] cmd [[ -<qualifers> ] args ]\n");
    123 	exit(1);
    124 	/* NOTREACHED */
    125 }
    126 
    127 void
    128 quit(s)
    129 	char *s;
    130 {
    131 	int sverrno = errno;
    132 
    133 	(void) fprintf(stderr, "route: ");
    134 	if (s)
    135 		(void) fprintf(stderr, "%s: ", s);
    136 	(void) fprintf(stderr, "%s\n", strerror(sverrno));
    137 	exit(1);
    138 	/* NOTREACHED */
    139 }
    140 
    141 #define ROUNDUP(a) \
    142 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
    143 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
    144 
    145 main(argc, argv)
    146 	int argc;
    147 	char **argv;
    148 {
    149 	extern int optind;
    150 	int ch;
    151 	char *argvp;
    152 
    153 	if (argc < 2)
    154 		usage((char *)NULL);
    155 
    156 	while ((ch = getopt(argc, argv, "Cnqtv")) != EOF)
    157 		switch(ch) {
    158 		case 'C':
    159 			Cflag = 1;	/* Use old ioctls. */
    160 			break;
    161 		case 'n':
    162 			nflag = 1;
    163 			break;
    164 		case 'q':
    165 			qflag = 1;
    166 			break;
    167 		case 'v':
    168 			verbose = 1;
    169 			break;
    170 		case 't':
    171 			tflag = 1;
    172 			break;
    173 		case '?':
    174 		default:
    175 			usage();
    176 		}
    177 	argc -= optind;
    178 	argv += optind;
    179 
    180 	pid = getpid();
    181 	uid = getuid();
    182 	if (tflag)
    183 		s = open("/dev/null", O_WRONLY, 0);
    184 	else if (Cflag)
    185 		s = socket(AF_INET, SOCK_RAW, 0);
    186 	else
    187 		s = socket(PF_ROUTE, SOCK_RAW, 0);
    188 	if (s < 0)
    189 		quit("socket");
    190 	if (*argv)
    191 		switch (keyword(*argv)) {
    192 		case K_GET:
    193 			uid = 0;
    194 			/* FALLTHROUGH */
    195 
    196 		case K_CHANGE:
    197 			if (Cflag)
    198 				usage("change or get with -C");
    199 			/* FALLTHROUGH */
    200 
    201 		case K_ADD:
    202 		case K_DELETE:
    203 			newroute(argc, argv);
    204 			exit(0);
    205 			/* NOTREACHED */
    206 
    207 		case K_MONITOR:
    208 			monitor();
    209 			/* NOTREACHED */
    210 
    211 		case K_FLUSH:
    212 			flushroutes(argc, argv);
    213 			exit(0);
    214 			/* NOTREACHED */
    215 		}
    216 	usage(*argv);
    217 	/* NOTREACHED */
    218 }
    219 
    220 /*
    221  * Purge all entries in the routing tables not
    222  * associated with network interfaces.
    223  */
    224 void
    225 flushroutes(argc, argv)
    226 	int argc;
    227 	char *argv[];
    228 {
    229 	int needed, seqno, rlen;
    230 	char *buf, *next, *lim;
    231 	register struct rt_msghdr *rtm;
    232 
    233 	if (uid)
    234 		quit("must be root to alter routing table");
    235 	shutdown(s, 0); /* Don't want to read back our messages */
    236 	if (argc > 1) {
    237 		argv++;
    238 		if (argc == 2 && **argv == '-')
    239 		    switch (keyword(*argv + 1)) {
    240 			case K_INET:
    241 				af = AF_INET;
    242 				break;
    243 			case K_XNS:
    244 				af = AF_NS;
    245 				break;
    246 			case K_LINK:
    247 				af = AF_LINK;
    248 				break;
    249 			case K_ISO:
    250 			case K_OSI:
    251 				af = AF_ISO;
    252 				break;
    253 			case K_X25:
    254 				af = AF_CCITT;
    255 			default:
    256 				goto bad;
    257 		} else
    258 bad:			usage(*argv);
    259 	}
    260 	if ((needed = getkerninfo(KINFO_RT_DUMP, 0, 0, 0)) < 0)
    261 		quit("route-getkerninfo-estimate");
    262 	if ((buf = malloc(needed)) == NULL)
    263 		quit("malloc");
    264 	if ((rlen = getkerninfo(KINFO_RT_DUMP, buf, &needed, 0)) < 0)
    265 		quit("actual retrieval of routing table");
    266 	lim = buf + rlen;
    267 	seqno = 0;		/* ??? */
    268 	for (next = buf; next < lim; next += rtm->rtm_msglen) {
    269 		rtm = (struct rt_msghdr *)next;
    270 		if ((rtm->rtm_flags & RTF_GATEWAY) == 0)
    271 			continue;
    272 		if (af) {
    273 			struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
    274 
    275 			if (sa->sa_family != af)
    276 				continue;
    277 		}
    278 		rtm->rtm_type = RTM_DELETE;
    279 		rtm->rtm_seq = seqno;
    280 		rlen = write(s, next, rtm->rtm_msglen);
    281 		if (rlen < (int)rtm->rtm_msglen) {
    282 			(void) fprintf(stderr,
    283 			    "route: write to routing socket: %s\n",
    284 			    strerror(errno));
    285 			(void) printf("got only %d for rlen\n", rlen);
    286 			break;
    287 		}
    288 		seqno++;
    289 		if (qflag)
    290 			continue;
    291 		if (verbose)
    292 			print_rtmsg(rtm, rlen);
    293 		else {
    294 			struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
    295 			(void) printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ?
    296 			    routename(sa) : netname(sa));
    297 			sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
    298 			(void) printf("%-20.20s ", routename(sa));
    299 			(void) printf("done\n");
    300 		}
    301 	}
    302 }
    303 
    304 char *
    305 routename(sa)
    306 	struct sockaddr *sa;
    307 {
    308 	register char *cp;
    309 	static char line[50];
    310 	struct hostent *hp;
    311 	static char domain[MAXHOSTNAMELEN + 1];
    312 	static int first = 1;
    313 	char *ns_print();
    314 
    315 	if (first) {
    316 		first = 0;
    317 		if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
    318 		    (cp = index(domain, '.')))
    319 			(void) strcpy(domain, cp + 1);
    320 		else
    321 			domain[0] = 0;
    322 	}
    323 	switch (sa->sa_family) {
    324 
    325 	case AF_INET:
    326 	    {	struct in_addr in;
    327 		in = ((struct sockaddr_in *)sa)->sin_addr;
    328 
    329 		cp = 0;
    330 		if (in.s_addr == INADDR_ANY)
    331 			cp = "default";
    332 		if (cp == 0 && !nflag) {
    333 			hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
    334 				AF_INET);
    335 			if (hp) {
    336 				if ((cp = index(hp->h_name, '.')) &&
    337 				    !strcmp(cp + 1, domain))
    338 					*cp = 0;
    339 				cp = hp->h_name;
    340 			}
    341 		}
    342 		if (cp)
    343 			strcpy(line, cp);
    344 		else {
    345 #define C(x)	((x) & 0xff)
    346 			in.s_addr = ntohl(in.s_addr);
    347 			(void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
    348 			   C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
    349 		}
    350 		break;
    351 	    }
    352 
    353 #ifdef notdef
    354 	case AF_NS:
    355 		return (ns_print((struct sockaddr_ns *)sa));
    356 #endif
    357 
    358 	case AF_LINK:
    359 		return (link_ntoa((struct sockaddr_dl *)sa));
    360 
    361 #ifdef notdef
    362 	case AF_ISO:
    363 		(void) sprintf(line, "iso %s",
    364 		    iso_ntoa(&((struct sockaddr_iso *)sa)->siso_addr));
    365 		break;
    366 
    367 #endif
    368 	default:
    369 	    {	u_short *s = (u_short *)sa->sa_data;
    370 		u_short *slim = s + ((sa->sa_len + 1) >> 1);
    371 		char *cp = line + sprintf(line, "(%d)", sa->sa_family);
    372 
    373 		while (s < slim)
    374 			cp += sprintf(cp, " %x", *s++);
    375 		break;
    376 	    }
    377 	}
    378 	return (line);
    379 }
    380 
    381 /*
    382  * Return the name of the network whose address is given.
    383  * The address is assumed to be that of a net or subnet, not a host.
    384  */
    385 char *
    386 netname(sa)
    387 	struct sockaddr *sa;
    388 {
    389 	char *cp = 0;
    390 	static char line[50];
    391 	struct netent *np = 0;
    392 	u_long net, mask;
    393 	register u_long i;
    394 	int subnetshift;
    395 	char *ns_print();
    396 
    397 	switch (sa->sa_family) {
    398 
    399 	case AF_INET:
    400 	    {	struct in_addr in;
    401 		in = ((struct sockaddr_in *)sa)->sin_addr;
    402 
    403 		i = in.s_addr = ntohl(in.s_addr);
    404 		if (in.s_addr == 0)
    405 			cp = "default";
    406 		else if (!nflag) {
    407 			if (IN_CLASSA(i)) {
    408 				mask = IN_CLASSA_NET;
    409 				subnetshift = 8;
    410 			} else if (IN_CLASSB(i)) {
    411 				mask = IN_CLASSB_NET;
    412 				subnetshift = 8;
    413 			} else {
    414 				mask = IN_CLASSC_NET;
    415 				subnetshift = 4;
    416 			}
    417 			/*
    418 			 * If there are more bits than the standard mask
    419 			 * would suggest, subnets must be in use.
    420 			 * Guess at the subnet mask, assuming reasonable
    421 			 * width subnet fields.
    422 			 */
    423 			while (in.s_addr &~ mask)
    424 				mask = (long)mask >> subnetshift;
    425 			net = in.s_addr & mask;
    426 			while ((mask & 1) == 0)
    427 				mask >>= 1, net >>= 1;
    428 			np = getnetbyaddr(net, AF_INET);
    429 			if (np)
    430 				cp = np->n_name;
    431 		}
    432 		if (cp)
    433 			strcpy(line, cp);
    434 		else if ((in.s_addr & 0xffffff) == 0)
    435 			(void) sprintf(line, "%u", C(in.s_addr >> 24));
    436 		else if ((in.s_addr & 0xffff) == 0)
    437 			(void) sprintf(line, "%u.%u", C(in.s_addr >> 24),
    438 			    C(in.s_addr >> 16));
    439 		else if ((in.s_addr & 0xff) == 0)
    440 			(void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24),
    441 			    C(in.s_addr >> 16), C(in.s_addr >> 8));
    442 		else
    443 			(void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
    444 			    C(in.s_addr >> 16), C(in.s_addr >> 8),
    445 			    C(in.s_addr));
    446 		break;
    447 	    }
    448 
    449 #ifdef notdef
    450 	case AF_NS:
    451 		return (ns_print((struct sockaddr_ns *)sa));
    452 		break;
    453 #endif
    454 
    455 	case AF_LINK:
    456 		return (link_ntoa((struct sockaddr_dl *)sa));
    457 
    458 #ifdef notdef
    459 	case AF_ISO:
    460 		(void) sprintf(line, "iso %s",
    461 		    iso_ntoa(&((struct sockaddr_iso *)sa)->siso_addr));
    462 		break;
    463 #endif
    464 
    465 	default:
    466 	    {	u_short *s = (u_short *)sa->sa_data;
    467 		u_short *slim = s + ((sa->sa_len + 1)>>1);
    468 		char *cp = line + sprintf(line, "af %d:", sa->sa_family);
    469 
    470 		while (s < slim)
    471 			cp += sprintf(cp, " %x", *s++);
    472 		break;
    473 	    }
    474 	}
    475 	return (line);
    476 }
    477 
    478 void
    479 set_metric(value, key)
    480 	char *value;
    481 	int key;
    482 {
    483 	int flag = 0;
    484 	u_long noval, *valp = &noval;
    485 
    486 	switch (key) {
    487 #define caseof(x, y, z)	case x: valp = &rt_metrics.z; flag = y; break
    488 	caseof(K_MTU, RTV_MTU, rmx_mtu);
    489 	caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount);
    490 	caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire);
    491 	caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe);
    492 	caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe);
    493 	caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh);
    494 	caseof(K_RTT, RTV_RTT, rmx_rtt);
    495 	caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar);
    496 	}
    497 	rtm_inits |= flag;
    498 	if (lockrest || locking)
    499 		rt_metrics.rmx_locks |= flag;
    500 	if (locking)
    501 		locking = 0;
    502 	*valp = atoi(value);
    503 }
    504 
    505 void
    506 newroute(argc, argv)
    507 	int argc;
    508 	register char **argv;
    509 {
    510 	char *cmd, *dest = "", *gateway = "", *err;
    511 	int ishost = 0, ret, attempts, oerrno, flags = 0;
    512 	int key;
    513 	struct hostent *hp = 0;
    514 
    515 	if (uid)
    516 		quit("must be root to alter routing table");
    517 	cmd = argv[0];
    518 	if (*cmd != 'g')
    519 		shutdown(s, 0); /* Don't want to read back our messages */
    520 	while (--argc > 0) {
    521 		if (**(++argv)== '-') {
    522 			switch (key = keyword(1 + *argv)) {
    523 			case K_LINK:
    524 				af = AF_LINK;
    525 				aflen = sizeof(struct sockaddr_dl);
    526 				break;
    527 #ifdef notdef
    528 			case K_OSI:
    529 			case K_ISO:
    530 				af = AF_ISO;
    531 				aflen = sizeof(struct sockaddr_iso);
    532 				break;
    533 #endif
    534 			case K_INET:
    535 				af = AF_INET;
    536 				aflen = sizeof(struct sockaddr_in);
    537 				break;
    538 #ifdef notdef
    539 			case K_X25:
    540 				af = AF_CCITT;
    541 				aflen = sizeof(struct sockaddr_x25);
    542 				break;
    543 #endif
    544 			case K_SA:
    545 				af = 0;
    546 				aflen = sizeof(union sockunion);
    547 				break;
    548 #ifdef notdef
    549 			case K_XNS:
    550 				af = AF_NS;
    551 				aflen = sizeof(struct sockaddr_ns);
    552 				break;
    553 #endif
    554 			case K_IFACE:
    555 			case K_INTERFACE:
    556 				iflag++;
    557 				break;
    558 			case K_LOCK:
    559 				locking = 1;
    560 				break;
    561 			case K_LOCKREST:
    562 				lockrest = 1;
    563 				break;
    564 			case K_HOST:
    565 				forcehost++;
    566 				break;
    567 			case K_REJECT:
    568 				flags |= RTF_REJECT;
    569 				break;
    570 			case K_PROTO1:
    571 				flags |= RTF_PROTO1;
    572 				break;
    573 			case K_PROTO2:
    574 				flags |= RTF_PROTO2;
    575 				break;
    576 			case K_CLONING:
    577 				flags |= RTF_CLONING;
    578 				break;
    579 			case K_XRESOLVE:
    580 				flags |= RTF_XRESOLVE;
    581 				break;
    582 			case K_IFA:
    583 				argc--;
    584 				(void) getaddr(RTA_IFA, *++argv, 0);
    585 				break;
    586 			case K_IFP:
    587 				argc--;
    588 				(void) getaddr(RTA_IFP, *++argv, 0);
    589 				break;
    590 			case K_GENMASK:
    591 				argc--;
    592 				(void) getaddr(RTA_GENMASK, *++argv, 0);
    593 				break;
    594 			case K_GATEWAY:
    595 				argc--;
    596 				(void) getaddr(RTA_GATEWAY, *++argv, 0);
    597 				break;
    598 			case K_DST:
    599 				argc--;
    600 				ishost = getaddr(RTA_DST, *++argv, &hp);
    601 				dest = *argv;
    602 				break;
    603 			case K_NETMASK:
    604 				argc--;
    605 				(void) getaddr(RTA_NETMASK, *++argv, 0);
    606 				/* FALLTHROUGH */
    607 			case K_NET:
    608 				forcenet++;
    609 				break;
    610 			case K_MTU:
    611 			case K_HOPCOUNT:
    612 			case K_EXPIRE:
    613 			case K_RECVPIPE:
    614 			case K_SENDPIPE:
    615 			case K_SSTHRESH:
    616 			case K_RTT:
    617 			case K_RTTVAR:
    618 				argc--;
    619 				set_metric(*++argv, key);
    620 				break;
    621 			default:
    622 				usage(1+*argv);
    623 			}
    624 		} else {
    625 			if ((rtm_addrs & RTA_DST) == 0) {
    626 				dest = *argv;
    627 				ishost = getaddr(RTA_DST, *argv, &hp);
    628 			} else if ((rtm_addrs & RTA_GATEWAY) == 0) {
    629 				gateway = *argv;
    630 				(void) getaddr(RTA_GATEWAY, *argv, &hp);
    631 			} else {
    632 				int ret = atoi(*argv);
    633 				if (ret == 0) {
    634 				    printf("%s,%s", "old usage of trailing 0",
    635 					   "assuming route to if\n");
    636 				    iflag = 1;
    637 				    continue;
    638 				} else if (ret > 0 && ret < 10) {
    639 				    printf("old usage of trailing digit, ");
    640 				    printf("assuming route via gateway\n");
    641 				    iflag = 0;
    642 				    continue;
    643 				}
    644 				(void) getaddr(RTA_NETMASK, *argv, 0);
    645 			}
    646 		}
    647 	}
    648 	if (forcehost)
    649 		ishost = 1;
    650 	if (forcenet)
    651 		ishost = 0;
    652 	flags |= RTF_UP;
    653 	if (ishost)
    654 		flags |= RTF_HOST;
    655 	if (iflag == 0)
    656 		flags |= RTF_GATEWAY;
    657 	for (attempts = 1; ; attempts++) {
    658 		errno = 0;
    659 		if (Cflag && (af == AF_INET || af == AF_NS)) {
    660 			route.rt_flags = flags;
    661 			route.rt_dst = so_dst.sa;
    662 			route.rt_gateway = so_gate.sa;
    663 			if ((ret = ioctl(s, *cmd == 'a' ? SIOCADDRT : SIOCDELRT,
    664 			     (caddr_t)&route)) == 0)
    665 				break;
    666 		} else {
    667 		    if ((ret = rtmsg(*cmd, flags)) == 0)
    668 				break;
    669 		}
    670 		if (errno != ENETUNREACH && errno != ESRCH)
    671 			break;
    672 		if (af == AF_INET && hp && hp->h_addr_list[1]) {
    673 			hp->h_addr_list++;
    674 			bcopy(hp->h_addr_list[0], (caddr_t)&so_dst.sin.sin_addr,
    675 			    hp->h_length);
    676 		} else
    677 			break;
    678 	}
    679 	if (*cmd == 'g')
    680 		exit(0);
    681 	oerrno = errno;
    682 	(void) printf("%s %s %s: gateway %s", cmd, ishost? "host" : "net",
    683 		dest, gateway);
    684 	if (attempts > 1 && ret == 0)
    685 	    (void) printf(" (%s)",
    686 		inet_ntoa(((struct sockaddr_in *)&route.rt_gateway)->sin_addr));
    687 	if (ret == 0)
    688 		(void) printf("\n");
    689 	else {
    690 		switch (oerrno) {
    691 		case ESRCH:
    692 			err = "not in table";
    693 			break;
    694 		case EBUSY:
    695 			err = "entry in use";
    696 			break;
    697 		case ENOBUFS:
    698 			err = "routing table overflow";
    699 			break;
    700 		default:
    701 			err = strerror(oerrno);
    702 			break;
    703 		}
    704 		(void) printf(": %s\n", err);
    705 	}
    706 }
    707 
    708 void
    709 inet_makenetandmask(net, sin)
    710 	u_long net;
    711 	register struct sockaddr_in *sin;
    712 {
    713 	u_long addr, mask = 0;
    714 	register char *cp;
    715 
    716 	rtm_addrs |= RTA_NETMASK;
    717 	if (net == 0)
    718 		mask = addr = 0;
    719 	else if (net < 128) {
    720 		addr = net << IN_CLASSA_NSHIFT;
    721 		mask = IN_CLASSA_NET;
    722 	} else if (net < 65536) {
    723 		addr = net << IN_CLASSB_NSHIFT;
    724 		mask = IN_CLASSB_NET;
    725 	} else if (net < 16777216L) {
    726 		addr = net << IN_CLASSC_NSHIFT;
    727 		mask = IN_CLASSC_NET;
    728 	} else {
    729 		addr = net;
    730 		if ((addr & IN_CLASSA_HOST) == 0)
    731 			mask =  IN_CLASSA_NET;
    732 		else if ((addr & IN_CLASSB_HOST) == 0)
    733 			mask =  IN_CLASSB_NET;
    734 		else if ((addr & IN_CLASSC_HOST) == 0)
    735 			mask =  IN_CLASSC_NET;
    736 		else
    737 			mask = -1;
    738 	}
    739 	sin->sin_addr.s_addr = htonl(addr);
    740 	sin = &so_mask.sin;
    741 	sin->sin_addr.s_addr = htonl(mask);
    742 	sin->sin_len = 0;
    743 	sin->sin_family = 0;
    744 	cp = (char *)(&sin->sin_addr + 1);
    745 	while (*--cp == 0 && cp > (char *)sin)
    746 		;
    747 	sin->sin_len = 1 + cp - (char *)sin;
    748 }
    749 
    750 /*
    751  * Interpret an argument as a network address of some kind,
    752  * returning 1 if a host address, 0 if a network address.
    753  */
    754 int
    755 getaddr(which, s, hpp)
    756 	int which;
    757 	char *s;
    758 	struct hostent **hpp;
    759 {
    760 	register sup su;
    761 #ifdef notdef
    762 	struct ns_addr ns_addr();
    763 	struct iso_addr *iso_addr();
    764 #endif
    765 	struct hostent *hp;
    766 	struct netent *np;
    767 	u_long val;
    768 
    769 	if (af == 0) {
    770 		af = AF_INET;
    771 		aflen = sizeof(struct sockaddr_in);
    772 	}
    773 	rtm_addrs |= which;
    774 	switch (which) {
    775 	case RTA_DST:		su = so_addrs[0]; su->sa.sa_family = af; break;
    776 	case RTA_GATEWAY:	su = so_addrs[1]; su->sa.sa_family = af; break;
    777 	case RTA_NETMASK:	su = so_addrs[2]; break;
    778 	case RTA_GENMASK:	su = so_addrs[3]; break;
    779 	case RTA_IFP:		su = so_addrs[4]; su->sa.sa_family = af; break;
    780 	case RTA_IFA:		su = so_addrs[5]; su->sa.sa_family = af; break;
    781 	default:		usage("Internal Error"); /*NOTREACHED*/
    782 	}
    783 	su->sa.sa_len = aflen;
    784 	if (strcmp(s, "default") == 0) {
    785 		switch (which) {
    786 		case RTA_DST:
    787 			forcenet++;
    788 			(void) getaddr(RTA_NETMASK, s, 0);
    789 			break;
    790 		case RTA_NETMASK:
    791 		case RTA_GENMASK:
    792 			su->sa.sa_len = 0;
    793 		}
    794 		return 0;
    795 	}
    796 #ifdef notdef
    797 	if (af == AF_NS)
    798 		goto do_xns;
    799 	if (af == AF_OSI)
    800 		goto do_osi;
    801 #endif
    802 	if (af == AF_LINK)
    803 		goto do_link;
    804 #ifdef notdef
    805 	if (af == AF_CCITT)
    806 		goto do_ccitt;
    807 #endif
    808 	if (af == 0)
    809 		goto do_sa;
    810 	if (hpp == NULL)
    811 		hpp = &hp;
    812 	*hpp = NULL;
    813 	if (((val = inet_addr(s)) != -1) &&
    814 	    (which != RTA_DST || forcenet == 0)) {
    815 		su->sin.sin_addr.s_addr = val;
    816 		if (inet_lnaof(su->sin.sin_addr) != INADDR_ANY)
    817 			return (1);
    818 		else {
    819 			val = ntohl(val);
    820 		out:	if (which == RTA_DST)
    821 				inet_makenetandmask(val, &su->sin);
    822 			return (0);
    823 		}
    824 	}
    825 	val = inet_network(s);
    826 	if (val != -1) {
    827 		goto out;
    828 	}
    829 	np = getnetbyname(s);
    830 	if (np) {
    831 		val = np->n_net;
    832 		goto out;
    833 	}
    834 	hp = gethostbyname(s);
    835 	if (hp) {
    836 		*hpp = hp;
    837 		su->sin.sin_family = hp->h_addrtype;
    838 		bcopy(hp->h_addr, (char *)&su->sin.sin_addr, hp->h_length);
    839 		return (1);
    840 	}
    841 	(void) fprintf(stderr, "%s: bad value\n", s);
    842 	exit(1);
    843 #ifdef notdef
    844 do_xns:
    845 	if (which == RTA_DST) {
    846 		extern short ns_bh[3];
    847 		struct sockaddr_ns *sms = &(so_mask.sns);
    848 		bzero((char *)sms, sizeof(*sms));
    849 		sms->sns_family = 0;
    850 		sms->sns_len = 6;
    851 		sms->sns_addr.x_net = *(union ns_net *)ns_bh;
    852 		rtm_addrs |= RTA_NETMASK;
    853 	}
    854 	su->sns.sns_addr = ns_addr(s);
    855 	return (!ns_nullhost(su->sns.sns_addr));
    856 do_osi:
    857 	su->siso.siso_addr = *iso_addr(s);
    858 	if (which == RTA_NETMASK || which == RTA_GENMASK) {
    859 		register char *cp = (char *)TSEL(&su->siso);
    860 		su->siso.siso_nlen = 0;
    861 		do {--cp ;} while ((cp > (char *)su) && (*cp == 0));
    862 		su->siso.siso_len = 1 + cp - (char *)su;
    863 	}
    864 	return (1);
    865 do_ccitt:
    866 	ccitt_addr(s, &su->sx25);
    867 	return (1);
    868 #endif
    869 do_link:
    870 	link_addr(s, &su->sdl);
    871 	return (1);
    872 do_sa:
    873 	su->sa.sa_len = sizeof(*su);
    874 	sockaddr(s, &su->sa);
    875 	return (1);
    876 }
    877 
    878 #ifdef notdef
    879 short ns_nullh[] = {0,0,0};
    880 short ns_bh[] = {-1,-1,-1};
    881 
    882 char *
    883 ns_print(sns)
    884 	struct sockaddr_ns *sns;
    885 {
    886 	struct ns_addr work;
    887 	union { union ns_net net_e; u_long long_e; } net;
    888 	u_short port;
    889 	static char mybuf[50], cport[10], chost[25];
    890 	char *host = "";
    891 	register char *p;
    892 	register u_char *q;
    893 
    894 	work = sns->sns_addr;
    895 	port = ntohs(work.x_port);
    896 	work.x_port = 0;
    897 	net.net_e  = work.x_net;
    898 	if (ns_nullhost(work) && net.long_e == 0) {
    899 		if (!port)
    900 			return ("*.*");
    901 		(void) sprintf(mybuf, "*.%XH", port);
    902 		return (mybuf);
    903 	}
    904 
    905 	if (bcmp((char *)ns_bh, (char *)work.x_host.c_host, 6) == 0)
    906 		host = "any";
    907 	else if (bcmp((char *)ns_nullh, (char *)work.x_host.c_host, 6) == 0)
    908 		host = "*";
    909 	else {
    910 		q = work.x_host.c_host;
    911 		(void) sprintf(chost, "%02X%02X%02X%02X%02X%02XH",
    912 			q[0], q[1], q[2], q[3], q[4], q[5]);
    913 		for (p = chost; *p == '0' && p < chost + 12; p++)
    914 			/* void */;
    915 		host = p;
    916 	}
    917 	if (port)
    918 		(void) sprintf(cport, ".%XH", htons(port));
    919 	else
    920 		*cport = 0;
    921 
    922 	(void) sprintf(mybuf,"%XH.%s%s", ntohl(net.long_e), host, cport);
    923 	return (mybuf);
    924 }
    925 #endif
    926 
    927 void
    928 monitor()
    929 {
    930 	int n;
    931 	char msg[2048];
    932 
    933 	verbose = 1;
    934 	for(;;) {
    935 		n = read(s, msg, 2048);
    936 		(void) printf("got message of size %d\n", n);
    937 		print_rtmsg((struct rt_msghdr *)msg);
    938 	}
    939 }
    940 
    941 struct {
    942 	struct	rt_msghdr m_rtm;
    943 	char	m_space[512];
    944 } m_rtmsg;
    945 
    946 int
    947 rtmsg(cmd, flags)
    948 	int cmd, flags;
    949 {
    950 	static int seq;
    951 	int rlen;
    952 	register char *cp = m_rtmsg.m_space;
    953 	register int l;
    954 
    955 #define NEXTADDR(w, u) \
    956 	if (rtm_addrs & (w)) {\
    957 	    l = ROUNDUP(u.sa.sa_len); bcopy((char *)&(u), cp, l); cp += l;\
    958 	    if (verbose) sodump(&(u),"u");\
    959 	}
    960 
    961 	errno = 0;
    962 	bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
    963 	if (cmd == 'a')
    964 		cmd = RTM_ADD;
    965 	else if (cmd == 'c')
    966 		cmd = RTM_CHANGE;
    967 	else if (cmd == 'g')
    968 		cmd = RTM_GET;
    969 	else
    970 		cmd = RTM_DELETE;
    971 #define rtm m_rtmsg.m_rtm
    972 	rtm.rtm_type = cmd;
    973 	rtm.rtm_flags = flags;
    974 	rtm.rtm_version = RTM_VERSION;
    975 	rtm.rtm_seq = ++seq;
    976 	rtm.rtm_addrs = rtm_addrs;
    977 	rtm.rtm_rmx = rt_metrics;
    978 	rtm.rtm_inits = rtm_inits;
    979 
    980 	if (rtm_addrs & RTA_NETMASK)
    981 		mask_addr();
    982 	NEXTADDR(RTA_DST, so_dst);
    983 	NEXTADDR(RTA_GATEWAY, so_gate);
    984 	NEXTADDR(RTA_NETMASK, so_mask);
    985 	NEXTADDR(RTA_GENMASK, so_genmask);
    986 	NEXTADDR(RTA_IFP, so_ifp);
    987 	NEXTADDR(RTA_IFA, so_ifa);
    988 	rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
    989 	if (verbose)
    990 		print_rtmsg(&rtm, l);
    991 	if (debugonly)
    992 		return 0;
    993 	if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
    994 		perror("writing to routing socket");
    995 		return (-1);
    996 	}
    997 	if (cmd == RTM_GET) {
    998 		do {
    999 			l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
   1000 		} while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
   1001 		if (l < 0)
   1002 			(void) fprintf(stderr,
   1003 			    "route: read from routing socket: %s\n",
   1004 			    strerror(errno));
   1005 		else
   1006 			print_getmsg(&rtm, l);
   1007 	}
   1008 #undef rtm
   1009 	return (0);
   1010 }
   1011 
   1012 mask_addr() {
   1013 	register char *cp1, *cp2;
   1014 	int olen;
   1015 
   1016 	if ((rtm_addrs & RTA_DST) == 0)
   1017 		return;
   1018 	switch(so_dst.sa.sa_family) {
   1019 #ifdef notdef
   1020 	case AF_NS:
   1021 #endif
   1022  case AF_INET: case 0:
   1023 		return;
   1024 #ifdef notdef
   1025 	case AF_ISO:
   1026 		olen = MIN(so_dst.siso.siso_nlen, so_mask.sa.sa_len - 6);
   1027 #endif
   1028 	}
   1029 	cp1 = so_mask.sa.sa_len + 1 + (char *)&so_dst;
   1030 	cp2 = so_dst.sa.sa_len + 1 + (char *)&so_dst;
   1031 	while (cp2 > cp1)
   1032 		*--cp2 = 0;
   1033 	cp2 = so_mask.sa.sa_len + 1 + (char *)&so_mask;
   1034 	while (cp1 > so_dst.sa.sa_data)
   1035 		*--cp1 &= *--cp2;
   1036 #ifdef notdef
   1037 	switch(so_dst.sa.sa_family) {
   1038 	case AF_ISO:
   1039 		so_dst.siso.siso_nlen = olen;
   1040 	}
   1041 #endif
   1042 }
   1043 
   1044 char *msgtypes[] = {
   1045 	"",
   1046 	"RTM_ADD: Add Route",
   1047 	"RTM_DELETE: Delete Route",
   1048 	"RTM_CHANGE: Change Metrics or flags",
   1049 	"RTM_GET: Report Metrics",
   1050 	"RTM_LOSING: Kernel Suspects Partitioning",
   1051 	"RTM_REDIRECT: Told to use different route",
   1052 	"RTM_MISS: Lookup failed on this address",
   1053 	"RTM_LOCK: fix specified metrics",
   1054 	"RTM_OLDADD: caused by SIOCADDRT",
   1055 	"RTM_OLDDEL: caused by SIOCDELRT",
   1056 	0,
   1057 };
   1058 
   1059 char metricnames[] =
   1060 "\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount\1mtu";
   1061 char routeflags[] =
   1062 "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT\011CLONING\012XRESOLVE\013LLINFO\017PROTO2\020PROTO1";
   1063 
   1064 
   1065 void
   1066 print_rtmsg(rtm, msglen)
   1067 	register struct rt_msghdr *rtm;
   1068 	int msglen;
   1069 {
   1070 	if (verbose == 0)
   1071 		return;
   1072 	if (rtm->rtm_version != RTM_VERSION) {
   1073 		(void) printf("routing message version %d not understood\n",
   1074 		    rtm->rtm_version);
   1075 		return;
   1076 	}
   1077 	(void) printf("%s\npid: %d, len %d, seq %d, errno %d, flags:",
   1078 		msgtypes[rtm->rtm_type], rtm->rtm_pid, rtm->rtm_msglen,
   1079 		rtm->rtm_seq, rtm->rtm_errno);
   1080 	bprintf(stdout, rtm->rtm_flags, routeflags);
   1081 	pmsg_common(rtm);
   1082 }
   1083 
   1084 void
   1085 print_getmsg(rtm, msglen)
   1086 	register struct rt_msghdr *rtm;
   1087 	int msglen;
   1088 {
   1089 	if (rtm->rtm_version != RTM_VERSION) {
   1090 		(void)printf("routing message version %d not understood\n",
   1091 		    rtm->rtm_version);
   1092 		return;
   1093 	}
   1094 	if (rtm->rtm_msglen > msglen) {
   1095 		(void)printf("get length mismatch, in packet %d, returned %d\n",
   1096 		    rtm->rtm_msglen, msglen);
   1097 	}
   1098 	(void) printf("RTM_GET: errno %d, flags:", rtm->rtm_errno);
   1099 	bprintf(stdout, rtm->rtm_flags, routeflags);
   1100 	(void) printf("\nmetric values:\n  ");
   1101 #define metric(f, e)\
   1102     printf("%s: %d%s", __STRING(f), rtm->rtm_rmx.__CONCAT(rmx_,f), e)
   1103 	metric(recvpipe, ", ");
   1104 	metric(sendpipe, ", ");
   1105 	metric(ssthresh, ", ");
   1106 	metric(rtt, "\n  ");
   1107 	metric(rttvar, ", ");
   1108 	metric(hopcount, ", ");
   1109 	metric(mtu, ", ");
   1110 	metric(expire, "\n");
   1111 #undef metric
   1112 	pmsg_common(rtm);
   1113 }
   1114 
   1115 void
   1116 pmsg_common(rtm)
   1117 	register struct rt_msghdr *rtm;
   1118 {
   1119 	char *cp;
   1120 	register struct sockaddr *sa;
   1121 	int i;
   1122 
   1123 	(void) printf("\nlocks: ");
   1124 	bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames);
   1125 	(void) printf(" inits: ");
   1126 	bprintf(stdout, rtm->rtm_inits, metricnames);
   1127 	(void) printf("\nsockaddrs: ");
   1128 	bprintf(stdout, rtm->rtm_addrs,
   1129 	    "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR");
   1130 	(void) putchar('\n');
   1131 	cp = ((char *)(rtm + 1));
   1132 	if (rtm->rtm_addrs)
   1133 		for (i = 1; i; i <<= 1)
   1134 			if (i & rtm->rtm_addrs) {
   1135 				sa = (struct sockaddr *)cp;
   1136 				(void) printf(" %s", routename(sa));
   1137 				ADVANCE(cp, sa);
   1138 			}
   1139 	(void) putchar('\n');
   1140 	(void) fflush(stdout);
   1141 }
   1142 
   1143 void
   1144 bprintf(fp, b, s)
   1145 	register FILE *fp;
   1146 	register int b;
   1147 	register u_char *s;
   1148 {
   1149 	register int i;
   1150 	int gotsome = 0;
   1151 
   1152 	if (b == 0)
   1153 		return;
   1154 	while (i = *s++) {
   1155 		if (b & (1 << (i-1))) {
   1156 			if (gotsome == 0)
   1157 				i = '<';
   1158 			else
   1159 				i = ',';
   1160 			(void) putc(i, fp);
   1161 			gotsome = 1;
   1162 			for (; (i = *s) > 32; s++)
   1163 				(void) putc(i, fp);
   1164 		} else
   1165 			while (*s > 32)
   1166 				s++;
   1167 	}
   1168 	if (gotsome)
   1169 		(void) putc('>', fp);
   1170 }
   1171 
   1172 int
   1173 keyword(cp)
   1174 	char *cp;
   1175 {
   1176 	register struct keytab *kt = keywords;
   1177 
   1178 	while (kt->kt_cp && strcmp(kt->kt_cp, cp))
   1179 		kt++;
   1180 	return kt->kt_i;
   1181 }
   1182 
   1183 void
   1184 sodump(su, which)
   1185 	register sup su;
   1186 	char *which;
   1187 {
   1188 	switch (su->sa.sa_family) {
   1189 	case AF_LINK:
   1190 		(void) printf("%s: link %s; ",
   1191 		    which, link_ntoa(&su->sdl));
   1192 		break;
   1193 #ifdef notdef
   1194 	case AF_ISO:
   1195 		(void) printf("%s: iso %s; ",
   1196 		    which, iso_ntoa(&su->siso.siso_addr));
   1197 		break;
   1198 #endif
   1199 	case AF_INET:
   1200 		(void) printf("%s: inet %s; ",
   1201 		    which, inet_ntoa(su->sin.sin_addr));
   1202 		break;
   1203 #ifdef notdef
   1204 	case AF_NS:
   1205 		(void) printf("%s: xns %s; ",
   1206 		    which, ns_ntoa(su->sns.sns_addr));
   1207 		break;
   1208 #endif
   1209 	}
   1210 	(void) fflush(stdout);
   1211 }
   1212 /* States*/
   1213 #define VIRGIN	0
   1214 #define GOTONE	1
   1215 #define GOTTWO	2
   1216 /* Inputs */
   1217 #define	DIGIT	(4*0)
   1218 #define	END	(4*1)
   1219 #define DELIM	(4*2)
   1220 
   1221 void
   1222 sockaddr(addr, sa)
   1223 register char *addr;
   1224 register struct sockaddr *sa;
   1225 {
   1226 	register char *cp = (char *)sa;
   1227 	int size = sa->sa_len;
   1228 	char *cplim = cp + size;
   1229 	register int byte = 0, state = VIRGIN, new;
   1230 
   1231 	bzero(cp, size);
   1232 	do {
   1233 		if ((*addr >= '0') && (*addr <= '9')) {
   1234 			new = *addr - '0';
   1235 		} else if ((*addr >= 'a') && (*addr <= 'f')) {
   1236 			new = *addr - 'a' + 10;
   1237 		} else if ((*addr >= 'A') && (*addr <= 'F')) {
   1238 			new = *addr - 'A' + 10;
   1239 		} else if (*addr == 0)
   1240 			state |= END;
   1241 		else
   1242 			state |= DELIM;
   1243 		addr++;
   1244 		switch (state /* | INPUT */) {
   1245 		case GOTTWO | DIGIT:
   1246 			*cp++ = byte; /*FALLTHROUGH*/
   1247 		case VIRGIN | DIGIT:
   1248 			state = GOTONE; byte = new; continue;
   1249 		case GOTONE | DIGIT:
   1250 			state = GOTTWO; byte = new + (byte << 4); continue;
   1251 		default: /* | DELIM */
   1252 			state = VIRGIN; *cp++ = byte; byte = 0; continue;
   1253 		case GOTONE | END:
   1254 		case GOTTWO | END:
   1255 			*cp++ = byte; /* FALLTHROUGH */
   1256 		case VIRGIN | END:
   1257 			break;
   1258 		}
   1259 		break;
   1260 	} while (cp < cplim);
   1261 	sa->sa_len = cp - (char *)sa;
   1262 }
   1263