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