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