xref: /original-bsd/sbin/route/route.c (revision 6ab384a1)
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.28 (Berkeley) 07/26/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_ifa, &so_ifp, 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 #define kget(p, d) \
67 	(lseek(kmem, (off_t)(p), 0), read(kmem, (char *)&(d), sizeof (d)))
68 
69 usage(cp)
70 char *cp;
71 {
72 	fprintf(stderr,
73 	    "usage: route [ -nqCv ]  cmd [[ -<qualifers> ] args ]\n");
74 	if (cp) fprintf(stderr, "(botched keyword: %s)\n", cp);
75 
76 	exit(1);
77 }
78 
79 main(argc, argv)
80 	int argc;
81 	char *argv[];
82 {
83 
84 	char *argvp;
85 	if (argc < 2)
86 		usage((char *)0);
87 	argc--, argv++;
88 	for (; argc >  0 && argv[0][0] == '-'; argc--, argv++) {
89 		for (argvp = argv[0]++; *argvp; argvp++)
90 			switch (*argv[0]) {
91 			case 'n':
92 				nflag++;
93 				break;
94 			case 'q':
95 				qflag++;
96 				break;
97 			case 'C':
98 				Cflag++; /* Use old ioctls */
99 				break;
100 			case 'v':
101 				verbose++;
102 			}
103 	}
104 	pid = getpid();
105 	if (Cflag)
106 		s = socket(AF_INET, SOCK_RAW, 0);
107 	else
108 		s = socket(PF_ROUTE, SOCK_RAW, 0);
109 	if (s < 0) {
110 		perror("route: socket");
111 		exit(1);
112 	}
113 	if (argc > 0) switch (keyword(*argv)) {
114 		case K_ADD:
115 		case K_CHANGE:
116 		case K_DELETE:
117 			newroute(argc, argv);
118 		case K_MONITOR:
119 			monitor();
120 		case K_FLUSH:
121 			flushroutes(argc, argv);
122 	}
123 	usage(*argv);
124 }
125 
126 /*
127  * Purge all entries in the routing tables not
128  * associated with network interfaces.
129  */
130 flushroutes(argc, argv)
131 char *argv[];
132 {
133 	int bufsize, needed, seqno, rlen;
134 	char *buf, *next, *lim;
135 	register struct rt_msghdr *rtm;
136 
137 	shutdown(s, 0); /* Don't want to read back our messages */
138 	if (argc > 1) {
139 		argv++;
140 		if (argc == 2 && **argv == '-') switch (keyword(1 + *argv)) {
141 			case K_INET:	af = AF_INET;	break;
142 			case K_XNS:	af = AF_NS;	break;
143 			case K_LINK:	af = AF_LINK;	break;
144 			case K_ISO: case K_OSI:	af = AF_ISO; break;
145 			default: goto bad;
146 		} else
147 			bad: usage(*argv);
148 	}
149 	if ((needed = getkerninfo(KINFO_RT_DUMP, 0, 0, 0)) < 0)
150 		{ perror("route-getkerninfo-estimate"); exit(1);}
151 	if ((buf = malloc(needed)) == 0)
152 		{ printf("out of space\n");; exit(1);}
153 	if ((rlen = getkerninfo(KINFO_RT_DUMP, buf, &needed, 0)) < 0)
154 		{ perror("actual retrieval of routing table"); exit(1);}
155 	lim = buf + rlen;
156 	for (next = buf; next < lim; next += rtm->rtm_msglen) {
157 		rtm = (struct rt_msghdr *)next;
158 		if ((rtm->rtm_flags & RTF_GATEWAY) == 0)
159 			continue;
160 		if (af) {
161 			struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
162 			if (sa->sa_family != af)
163 				continue;
164 		}
165 		rtm->rtm_type = RTM_DELETE;
166 		rtm->rtm_seq = seqno;
167 		if ((rlen = write(s, next, rtm->rtm_msglen)) < 0) {
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 	shutdown(s, 0); /* Don't want to read back our messages */
399 	cmd = argv[0];
400 	while (--argc > 0) {
401 		if (**(++argv)== '-') {
402 			switch(key = keyword(1 + *argv)) {
403 			case K_LINK:
404 				af = AF_LINK;
405 				aflen = sizeof(struct sockaddr_dl);
406 				break;
407 			case K_OSI:
408 			case K_ISO:
409 				af = AF_ISO;
410 				aflen = sizeof(struct sockaddr_iso);
411 				break;
412 			case K_INET:
413 				af = AF_INET;
414 				aflen = sizeof(struct sockaddr_in);
415 				break;
416 			case K_XNS:
417 				af = AF_NS;
418 				aflen = sizeof(struct sockaddr_ns);
419 				break;
420 			case K_IFACE:
421 			case K_INTERFACE:
422 				iflag++;
423 				break;
424 			case K_LOCK:
425 				locking = 1;
426 				break;
427 			case K_LOCKREST:
428 				lockrest = 1;
429 				break;
430 			case K_HOST:
431 				forcehost++;
432 				break;
433 			case K_NETMASK:
434 				argc--;
435 				(void) getaddr(RTA_NETMASK, *++argv, 0);
436 				/* FALLTHROUGH */
437 			case K_NET:
438 				forcenet++;
439 				break;
440 			case K_REJECT:
441 				flags |= RTF_REJECT;
442 				break;
443 			case K_CLONING:
444 				flags |= RTF_CLONING;
445 				break;
446 			case K_XRESOLVE:
447 				flags |= RTF_XRESOLVE;
448 				break;
449 			case K_GENMASK:
450 				argc--;
451 				(void) getaddr(RTA_GENMASK, *++argv, 0);
452 				break;
453 			case K_MTU:
454 			case K_HOPCOUNT:
455 			case K_EXPIRE:
456 			case K_RECVPIPE:
457 			case K_SENDPIPE:
458 			case K_SSTHRESH:
459 			case K_RTT:
460 			case K_RTTVAR:
461 				argc--;
462 				set_metric(*++argv, key);
463 				break;
464 			default:
465 				usage(1+*argv);
466 			}
467 		} else {
468 			if ((rtm_addrs & RTA_DST) == 0) {
469 				dest = *argv;
470 				ishost = getaddr(RTA_DST, *argv, &hp);
471 			} else if ((rtm_addrs & RTA_GATEWAY) == 0) {
472 				gateway = *argv;
473 				(void) getaddr(RTA_GATEWAY, *argv, &hp);
474 			} else {
475 				int ret = atoi(*argv);
476 				if (ret == 0) {
477 				    printf("%s,%s", "old usage of trailing 0",
478 					   "assuming route to if\n");
479 				    iflag = 1;
480 				    continue;
481 				} else if (ret > 0 && ret < 10) {
482 				    printf("old usage of trailing digit, ");
483 				    printf("assuming route via gateway\n");
484 				    iflag = 0;
485 				    continue;
486 				}
487 				(void) getaddr(RTA_NETMASK, *argv, 0);
488 			}
489 		}
490 	}
491 	if (forcehost)
492 		ishost = 1;
493 	if (forcenet)
494 		ishost = 0;
495 	flags |= RTF_UP;
496 	if (ishost)
497 		flags |= RTF_HOST;
498 	if (iflag == 0)
499 		flags |= RTF_GATEWAY;
500 	for (attempts = 1; ; attempts++) {
501 		errno = 0;
502 		if (Cflag && (af == AF_INET || af == AF_NS)) {
503 			route.rt_flags = flags;
504 			route.rt_dst = so_dst.sa;
505 			route.rt_gateway = so_gate.sa;
506 			if ((ret = ioctl(s, *cmd == 'a' ? SIOCADDRT : SIOCDELRT,
507 			     (caddr_t)&route)) == 0)
508 				break;
509 		} else {
510 		    if ((ret = rtmsg(*cmd, flags)) == 0);
511 				break;
512 		}
513 		if (errno != ENETUNREACH && errno != ESRCH)
514 			break;
515 		if (hp && hp->h_addr_list[1]) {
516 			hp->h_addr_list++;
517 			bcopy(hp->h_addr_list[0], (caddr_t)&so_dst.sin.sin_addr,
518 			    hp->h_length);
519 		} else
520 			break;
521 	}
522 	oerrno = errno;
523 	printf("%s %s %s: gateway %s", cmd, ishost? "host" : "net",
524 		dest, gateway);
525 	if (attempts > 1 && ret == 0)
526 	    printf(" (%s)",
527 		inet_ntoa(((struct sockaddr_in *)&route.rt_gateway)->sin_addr));
528 	if (ret == 0)
529 		printf("\n");
530 	else {
531 		printf(": ");
532 		fflush(stdout);
533 		errno = oerrno;
534 		error("");
535 	}
536 	exit(0);
537 }
538 
539 error(cmd)
540 	char *cmd;
541 {
542 	extern int errno;
543 
544 	switch(errno) {
545 	case ESRCH:
546 		printf("not in table\n");
547 		break;
548 	case EBUSY:
549 		printf("entry in use\n");
550 		break;
551 	case ENOBUFS:
552 		printf("routing table overflow\n");
553 		break;
554 	default:
555 		printf("ioctl returns %d\n", errno);
556 		perror(cmd);
557 	}
558 	fflush(stdout);
559 	errno = 0;
560 }
561 
562 char *
563 savestr(s)
564 	char *s;
565 {
566 	char *sav;
567 
568 	sav = malloc(strlen(s) + 1);
569 	if (sav == NULL) {
570 		fprintf("route: out of memory\n");
571 		exit(1);
572 	}
573 	strcpy(sav, s);
574 	return (sav);
575 }
576 
577 inet_makenetandmask(net, sin)
578 u_long net;
579 register struct sockaddr_in *sin;
580 {
581 	u_long addr;
582 	u_long mask = 0;
583 	register char *cp;
584 
585 	rtm_addrs |= RTA_NETMASK;
586 	if (net == 0)
587 		mask = addr = 0;
588 	else if (net < 128) {
589 		addr = net << IN_CLASSA_NSHIFT;
590 		mask = IN_CLASSA_NET;
591 	} else if (net < 65536) {
592 		addr = net << IN_CLASSB_NSHIFT;
593 		mask = IN_CLASSB_NET;
594 	} else if (net < 16777216L) {
595 		addr = net << IN_CLASSC_NSHIFT;
596 		mask = IN_CLASSC_NET;
597 	} else {
598 		addr = net;
599 		if ((addr & IN_CLASSA_HOST) == 0)
600 			mask =  IN_CLASSA_NET;
601 		else if ((addr & IN_CLASSB_HOST) == 0)
602 			mask =  IN_CLASSB_NET;
603 		else if ((addr & IN_CLASSC_HOST) == 0)
604 			mask =  IN_CLASSC_NET;
605 		else
606 			mask = -1;
607 	}
608 	sin->sin_addr.s_addr = htonl(addr);
609 	sin = &so_mask.sin;
610 	sin->sin_addr.s_addr = htonl(mask);
611 	sin->sin_len = 0;
612 	sin->sin_family = 0;
613 	cp = (char *)(1 + &(sin->sin_addr));
614 	while (*--cp == 0 && cp > (char *)sin)
615 		;
616 	sin->sin_len = 1 + cp - (char *)sin;
617 }
618 
619 /*
620  * Interpret an argument as a network address of some kind,
621  * returning 1 if a host address, 0 if a network address.
622  */
623 getaddr(which, s, hpp)
624 	char *s;
625 	struct hostent **hpp;
626 {
627 	register union sockunion *su;
628 	struct	ns_addr ns_addr();
629 	struct iso_addr *iso_addr();
630 	struct hostent *hp;
631 	struct netent *np;
632 	u_long val;
633 
634 	if (af == 0) {
635 		af = AF_INET;
636 		aflen = sizeof(struct sockaddr_in);
637 	}
638 	rtm_addrs |= which;
639 	switch (which) {
640 	case RTA_DST:		su = so_addrs[0]; su->sa.sa_family = af; break;
641 	case RTA_GATEWAY:	su = so_addrs[1]; su->sa.sa_family = af; break;
642 	case RTA_NETMASK:	su = so_addrs[2]; break;
643 	case RTA_GENMASK:	su = so_addrs[3]; break;
644 	default:		usage("Internal Error"); /*NOTREACHED*/
645 	}
646 	su->sa.sa_len = aflen;
647 	if (strcmp(s, "default") == 0) {
648 		switch (which) {
649 		case RTA_DST:
650 			forcenet++;
651 			getaddr(RTA_NETMASK, s, 0);
652 			break;
653 		case RTA_NETMASK:
654 		case RTA_GENMASK:
655 			su->sa.sa_len = 0;
656 		}
657 		return 0;
658 	}
659 	if (af == AF_NS)
660 		goto do_xns;
661 	if (af == AF_OSI)
662 		goto do_osi;
663 	if (af == AF_LINK)
664 		goto do_link;
665 	if (hpp == 0) hpp = &hp;
666 	*hpp = 0;
667 	if (((val = inet_addr(s)) != -1) &&
668 	    (which != RTA_DST || forcenet == 0)) {
669 		su->sin.sin_addr.s_addr = val;
670 		if (inet_lnaof(su->sin.sin_addr) != INADDR_ANY)
671 			return (1);
672 		else {
673 			val = ntohl(val);
674 		out:	if (which == RTA_DST)
675 				inet_makenetandmask(val, &su->sin);
676 			return (0);
677 		}
678 	}
679 	val = inet_network(s);
680 	if (val != -1) {
681 		goto out;
682 	}
683 	np = getnetbyname(s);
684 	if (np) {
685 		val = np->n_net;
686 		goto out;
687 	}
688 	hp = gethostbyname(s);
689 	if (hp) {
690 		*hpp = hp;
691 		su->sin.sin_family = hp->h_addrtype;
692 		bcopy(hp->h_addr, &su->sin.sin_addr, hp->h_length);
693 		return (1);
694 	}
695 	fprintf(stderr, "%s: bad value\n", s);
696 	exit(1);
697 do_xns:
698 	if (val == 0)
699 		return(0);
700 	if (which == RTA_DST) {
701 		extern short ns_bh[3];
702 		struct sockaddr_ns *sms = &(so_mask.sns);
703 		bzero((char *)sms, sizeof(*sms));
704 		sms->sns_family = 0;
705 		sms->sns_len = 6;
706 		sms->sns_addr.x_net = *(union ns_net *)ns_bh;
707 		rtm_addrs |= RTA_NETMASK;
708 	}
709 	su->sns.sns_addr = ns_addr(s);
710 	return (!ns_nullhost(su->sns.sns_addr));
711 do_osi:
712 	su->siso.siso_addr = *iso_addr(s);
713 	if (which == RTA_NETMASK || which == RTA_GENMASK) {
714 		register char *cp = (char *)TSEL(&su->siso);
715 		su->siso.siso_nlen = 0;
716 		do {--cp ;} while ((cp > (char *)su) && (*cp == 0));
717 		su->siso.siso_len = 1 + cp - (char *)su;
718 	}
719 	return (1);
720 do_link:
721 	link_addr(s, &su->sdl);
722 	return (1);
723 }
724 
725 short ns_nullh[] = {0,0,0};
726 short ns_bh[] = {-1,-1,-1};
727 
728 char *
729 ns_print(sns)
730 struct sockaddr_ns *sns;
731 {
732 	struct ns_addr work;
733 	union { union ns_net net_e; u_long long_e; } net;
734 	u_short port;
735 	static char mybuf[50], cport[10], chost[25];
736 	char *host = "";
737 	register char *p; register u_char *q; u_char *q_lim;
738 
739 	work = sns->sns_addr;
740 	port = ntohs(work.x_port);
741 	work.x_port = 0;
742 	net.net_e  = work.x_net;
743 	if (ns_nullhost(work) && net.long_e == 0) {
744 		if (port ) {
745 			(void)sprintf(mybuf, "*.%xH", port);
746 			upHex(mybuf);
747 		} else
748 			(void)sprintf(mybuf, "*.*");
749 		return (mybuf);
750 	}
751 
752 	if (bcmp(ns_bh, work.x_host.c_host, 6) == 0) {
753 		host = "any";
754 	} else if (bcmp(ns_nullh, work.x_host.c_host, 6) == 0) {
755 		host = "*";
756 	} else {
757 		q = work.x_host.c_host;
758 		(void)sprintf(chost, "%02x%02x%02x%02x%02x%02xH",
759 			q[0], q[1], q[2], q[3], q[4], q[5]);
760 		for (p = chost; *p == '0' && p < chost + 12; p++);
761 		host = p;
762 	}
763 	if (port)
764 		(void)sprintf(cport, ".%xH", htons(port));
765 	else
766 		*cport = 0;
767 
768 	(void)sprintf(mybuf,"%xH.%s%s", ntohl(net.long_e), host, cport);
769 	upHex(mybuf);
770 	return(mybuf);
771 }
772 
773 upHex(p0)
774 char *p0;
775 {
776 	register char *p = p0;
777 	for (; *p; p++) switch (*p) {
778 
779 	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
780 		*p += ('A' - 'a');
781 	}
782 }
783 
784 monitor()
785 {
786 	int n;
787 	char msg[2048];
788 	verbose = 1;
789 	for(;;) {
790 		n = read(s, msg, 2048);
791 		printf("got message of size %d\n", n);
792 		print_rtmsg((struct rt_msghdr *)msg);
793 	}
794 }
795 
796 struct {
797 	struct	rt_msghdr m_rtm;
798 	char m_space[512];
799 } m_rtmsg;
800 
801 rtmsg(cmd, flags)
802 {
803 	static int seq;
804 	int rlen;
805 	extern int errno;
806 	register char *cp = m_rtmsg.m_space;
807 	register int l;
808 
809 	errno = 0;
810 	bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
811 	if (cmd == 'a')
812 		cmd = RTM_ADD;
813 	else if (cmd == 'c')
814 		cmd = RTM_CHANGE;
815 	else
816 		cmd = RTM_DELETE;
817 	m_rtmsg.m_rtm.rtm_flags = flags;
818 	m_rtmsg.m_rtm.rtm_version = RTM_VERSION;
819 	m_rtmsg.m_rtm.rtm_seq = ++seq;
820 	m_rtmsg.m_rtm.rtm_addrs = rtm_addrs;
821 	m_rtmsg.m_rtm.rtm_rmx = rt_metrics;
822 	m_rtmsg.m_rtm.rtm_inits = rtm_inits;
823 
824 #define ROUND(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
825 #define NEXTADDR(w, u) { if (rtm_addrs & (w)) {l = (u).sa.sa_len;\
826 	if(verbose)sodump(&(u),"u");if(l == 0) l = sizeof(int); l = ROUND(l);\
827 		bcopy((char *)&(u), cp, l); cp += l;}}
828 
829 	NEXTADDR(RTA_DST, so_dst);
830 	NEXTADDR(RTA_GATEWAY, so_gate);
831 	NEXTADDR(RTA_NETMASK, so_mask);
832 	NEXTADDR(RTA_GENMASK, so_genmask);
833 	m_rtmsg.m_rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
834 	m_rtmsg.m_rtm.rtm_type = cmd;
835 	if (verbose)
836 		print_rtmsg(&m_rtmsg.m_rtm, l);
837 	if (debugonly)
838 		return 0;
839 	if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
840 		perror("writing to routing socket");
841 		printf("got only %d for rlen\n", rlen);
842 		return (-1);
843 	}
844 	return (0);
845 }
846 
847 char *msgtypes[] = {
848 "",
849 "RTM_ADD: Add Route",
850 "RTM_DELETE: Delete Route",
851 "RTM_CHANGE: Change Metrics or flags",
852 "RTM_GET: Report Metrics",
853 "RTM_LOSING: Kernel Suspects Partitioning",
854 "RTM_REDIRECT: Told to use different route",
855 "RTM_MISS: Lookup failed on this address",
856 "RTM_LOCK: fix specified metrics",
857 "RTM_OLDADD: caused by SIOCADDRT",
858 "RTM_OLDDEL: caused by SIOCDELRT",
859 0, };
860 
861 char metricnames[] =
862 "\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount\1mtu";
863 char routeflags[] =
864 "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT\011CLONING\012XRESOLVE";
865 
866 #define ROUNDUP(a) ((char *)(1 + (((((int)a)) - 1) | (sizeof(long) - 1))))
867 
868 print_rtmsg(rtm, n)
869 register struct rt_msghdr *rtm;
870 {
871 	char *cp;
872 	register struct sockaddr *sa;
873 	int i;
874 
875 	if (verbose == 0)
876 		return;
877 	if (rtm->rtm_version != RTM_VERSION) {
878 	    printf("routing message version %d not understood\n",
879 							rtm->rtm_version);
880 	} else {
881 	    printf("%s\npid: %d, len %d, seq %d, errno %d, flags:",
882 		    msgtypes[rtm->rtm_type], rtm->rtm_pid, rtm->rtm_msglen,
883 		    rtm->rtm_seq, rtm->rtm_errno);
884 	    bprintf(stdout, rtm->rtm_flags, routeflags);
885 	    printf("\nlocks: "); bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames);
886 	    printf(" inits: "); bprintf(stdout, rtm->rtm_inits, metricnames);
887 	    printf("\nsockaddrs: ");
888 	    bprintf(stdout, rtm->rtm_addrs,
889 		"\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR");
890 	    putchar('\n');
891 	    cp = ((char *)(rtm + 1));
892 	    if (rtm->rtm_addrs)
893 		for (i = 1; i; i <<= 1)
894 		    if (i & rtm->rtm_addrs) {
895 			    sa = (struct sockaddr *)cp;
896 			    printf(" %s", routename(sa));
897 			    cp = ROUNDUP(cp + sa->sa_len);
898 		    }
899 	    putchar('\n');
900 	}
901 	fflush(stdout);
902 }
903 
904 bprintf(fp, b, s)
905 register FILE *fp;
906 register int b;
907 register u_char *s;
908 {
909 	register int i;
910 	int gotsome = 0;
911 
912 	if (b == 0)
913 		return;
914 	while (i = *s++) {
915 		if (b & (1 << (i-1))) {
916 			if (gotsome == 0) i = '<'; else i = ',';
917 			putc(i, fp);
918 			gotsome = 1;
919 			for (; (i = *s) > 32; s++)
920 				putc(i, fp);
921 		} else
922 			while (*s > 32)
923 				s++;
924 	}
925 	if (gotsome)
926 		putc('>', fp);
927 }
928 int
929 keyword(cp)
930 char *cp;
931 {
932 	register struct keytab *kt = keywords;
933 	while (kt->kt_cp && strcmp(kt->kt_cp, cp))
934 		kt++;
935 	return kt->kt_i;
936 }
937 
938 sodump(su, which)
939 register union sockunion *su;
940 char *which;
941 {
942 	switch (su->sa.sa_family) {
943 	case AF_LINK:
944 		printf("%s: link %s; ", which, link_ntoa(&su->sdl));
945 		break;
946 	case AF_ISO:
947 		printf("%s: iso %s; ", which, iso_ntoa(&su->siso.siso_addr));
948 		break;
949 	case AF_INET:
950 		printf("%s: inet %s; ", which, inet_ntoa(su->sin.sin_addr));
951 		break;
952 	case AF_NS:
953 		printf("%s: xns %s; ", which, ns_ntoa(&su->sns.sns_addr));
954 		break;
955 	}
956 	fflush(stdout);
957 }
958