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