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