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