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