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