route.c revision 1.62 1 /* $NetBSD: route.c,v 1.62 2003/04/03 02:39:50 jrf Exp $ */
2
3 /*
4 * Copyright (c) 1983, 1989, 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include <sys/cdefs.h>
37 #ifndef lint
38 __COPYRIGHT("@(#) Copyright (c) 1983, 1989, 1991, 1993\n\
39 The Regents of the University of California. All rights reserved.\n");
40 #endif /* not lint */
41
42 #ifndef lint
43 #if 0
44 static char sccsid[] = "@(#)route.c 8.6 (Berkeley) 4/28/95";
45 #else
46 __RCSID("$NetBSD: route.c,v 1.62 2003/04/03 02:39:50 jrf Exp $");
47 #endif
48 #endif /* not lint */
49
50 #include <sys/param.h>
51 #include <sys/file.h>
52 #include <sys/socket.h>
53 #include <sys/ioctl.h>
54 #include <sys/mbuf.h>
55 #include <sys/sysctl.h>
56
57 #include <net/if.h>
58 #include <net/route.h>
59 #include <net/if_dl.h>
60 #include <netinet/in.h>
61 #include <netatalk/at.h>
62 #include <netns/ns.h>
63 #include <netiso/iso.h>
64 #include <netccitt/x25.h>
65 #include <arpa/inet.h>
66 #include <netdb.h>
67
68 #include <errno.h>
69 #include <unistd.h>
70 #include <stdio.h>
71 #include <ctype.h>
72 #include <stdlib.h>
73 #include <string.h>
74 #include <time.h>
75 #include <paths.h>
76 #include <err.h>
77
78 #include "keywords.h"
79 #include "extern.h"
80
81 typedef union sockunion *sup;
82
83 int main __P((int, char **));
84 static void usage __P((char *)) __attribute__((__noreturn__));
85 static char *any_ntoa __P((const struct sockaddr *));
86 static void set_metric __P((char *, int));
87 static int newroute __P((int, char **));
88 static void inet_makenetandmask __P((u_int32_t, struct sockaddr_in *));
89 #ifdef INET6
90 static int inet6_makenetandmask __P((struct sockaddr_in6 *));
91 #endif
92 static int getaddr __P((int, char *, struct hostent **));
93 static int flushroutes __P((int, char *[]));
94 #ifndef SMALL
95 static int prefixlen __P((char *));
96 static int x25_makemask __P((void));
97 static void interfaces __P((void));
98 static void monitor __P((void));
99 static void print_getmsg __P((struct rt_msghdr *, int));
100 static const char *linkstate __P((struct if_msghdr *));
101 #endif /* SMALL */
102 static int rtmsg __P((int, int ));
103 static void mask_addr __P((void));
104 static void print_rtmsg __P((struct rt_msghdr *, int));
105 static void pmsg_common __P((struct rt_msghdr *));
106 static void pmsg_addrs __P((char *, int));
107 static void bprintf __P((FILE *, int, u_char *));
108 static int keyword __P((char *));
109 static void sodump __P((sup, char *));
110 static void sockaddr __P((char *, struct sockaddr *));
111
112 union sockunion {
113 struct sockaddr sa;
114 struct sockaddr_in sin;
115 #ifdef INET6
116 struct sockaddr_in6 sin6;
117 #endif
118 struct sockaddr_at sat;
119 struct sockaddr_dl sdl;
120 #ifndef SMALL
121 struct sockaddr_ns sns;
122 struct sockaddr_iso siso;
123 struct sockaddr_x25 sx25;
124 #endif /* SMALL */
125 } so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp;
126
127 int pid, rtm_addrs;
128 int sock;
129 int forcehost, forcenet, doflush, nflag, af, qflag, tflag;
130 int iflag, verbose, aflen = sizeof (struct sockaddr_in);
131 int locking, lockrest, debugonly, shortoutput, rv;
132 struct rt_metrics rt_metrics;
133 u_int32_t rtm_inits;
134 short ns_nullh[] = {0,0,0};
135 short ns_bh[] = {-1,-1,-1};
136
137
138 static void
139 usage(cp)
140 char *cp;
141 {
142
143 if (cp)
144 warnx("botched keyword: %s", cp);
145 (void) fprintf(stderr,
146 "Usage: %s [ -fnqvs ] cmd [[ -<qualifers> ] args ]\n",
147 getprogname());
148 exit(1);
149 /* NOTREACHED */
150 }
151
152 #define ROUNDUP(a) \
153 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
154 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
155
156 int
157 main(argc, argv)
158 int argc;
159 char **argv;
160 {
161 int ch;
162
163 if (argc < 2)
164 usage(NULL);
165
166 /* The -d (debugonly) and -t (tflag) are for program debugging
167 * and are deliberately not documented.
168 *
169 * debugonly fakes the operation. If it is manipulating a route
170 * it will flush all routes not associated with a network interface.
171 * tflag uses /dev/null instead of a real socket.
172 */
173 while ((ch = getopt(argc, argv, "fnqvdts")) != -1)
174 switch(ch) {
175 case 'f':
176 doflush = 1;
177 break;
178 case 'n':
179 nflag = 1;
180 break;
181 case 'q':
182 qflag = 1;
183 break;
184 case 'v':
185 verbose = 1;
186 break;
187 case 't':
188 tflag = 1;
189 break;
190 case 'd':
191 debugonly = 1;
192 break;
193 case 's':
194 shortoutput = 1;
195 break;
196 case '?':
197 default:
198 usage(NULL);
199 /*NOTREACHED*/
200 }
201 argc -= optind;
202 argv += optind;
203
204 pid = getpid();
205 if (tflag)
206 sock = open("/dev/null", O_WRONLY, 0);
207 else
208 sock = socket(PF_ROUTE, SOCK_RAW, 0);
209 if (sock < 0)
210 err(1, "socket");
211
212 if (*argv == NULL) {
213 if (doflush)
214 ch = K_FLUSH;
215 else
216 goto no_cmd;
217 } else
218 ch = keyword(*argv);
219
220 switch (ch) {
221 #ifndef SMALL
222 case K_GET:
223 #endif /* SMALL */
224 case K_CHANGE:
225 case K_ADD:
226 case K_DELETE:
227 if (doflush)
228 (void)flushroutes(1, argv);
229 return newroute(argc, argv);
230
231 case K_SHOW:
232 show(argc, argv);
233 return 0;
234
235 #ifndef SMALL
236 case K_MONITOR:
237 monitor();
238 return 0;
239
240 #endif /* SMALL */
241 case K_FLUSH:
242 return flushroutes(argc, argv);
243
244 no_cmd:
245 default:
246 usage(*argv);
247 /*NOTREACHED*/
248 }
249 }
250
251 /*
252 * Purge all entries in the routing tables not
253 * associated with network interfaces.
254 */
255 static int
256 flushroutes(argc, argv)
257 int argc;
258 char *argv[];
259 {
260 size_t needed;
261 int mib[6], rlen, seqno;
262 char *buf, *next, *lim;
263 struct rt_msghdr *rtm;
264
265 af = 0;
266 shutdown(sock, SHUT_RD); /* Don't want to read back our messages */
267 if (argc > 1) {
268 argv++;
269 if (argc == 2 && **argv == '-')
270 switch (keyword(*argv + 1)) {
271 case K_INET:
272 af = AF_INET;
273 break;
274 #ifdef INET6
275 case K_INET6:
276 af = AF_INET6;
277 break;
278 #endif
279 case K_ATALK:
280 af = AF_APPLETALK;
281 break;
282 #ifndef SMALL
283 case K_XNS:
284 af = AF_NS;
285 break;
286 #endif /* SMALL */
287 case K_LINK:
288 af = AF_LINK;
289 break;
290 #ifndef SMALL
291 case K_ISO:
292 case K_OSI:
293 af = AF_ISO;
294 break;
295 case K_X25:
296 af = AF_CCITT;
297 #endif /* SMALL */
298 default:
299 goto bad;
300 } else
301 bad: usage(*argv);
302 }
303 mib[0] = CTL_NET;
304 mib[1] = PF_ROUTE;
305 mib[2] = 0; /* protocol */
306 mib[3] = 0; /* wildcard address family */
307 mib[4] = NET_RT_DUMP;
308 mib[5] = 0; /* no flags */
309 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
310 err(1, "route-sysctl-estimate");
311 if (needed == 0)
312 return 0;
313 if ((buf = malloc(needed)) == NULL)
314 err(1, "malloc");
315 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
316 err(1, "actual retrieval of routing table");
317 lim = buf + needed;
318 if (verbose) {
319 (void) printf("Examining routing table from sysctl\n");
320 if (af) printf("(address family %s)\n", (*argv + 1));
321 }
322 seqno = 0; /* ??? */
323 for (next = buf; next < lim; next += rtm->rtm_msglen) {
324 rtm = (struct rt_msghdr *)next;
325 if (verbose)
326 print_rtmsg(rtm, rtm->rtm_msglen);
327 if ((rtm->rtm_flags & RTF_GATEWAY) == 0)
328 continue;
329 if (af) {
330 struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
331
332 if (sa->sa_family != af)
333 continue;
334 }
335 if (debugonly)
336 continue;
337 rtm->rtm_type = RTM_DELETE;
338 rtm->rtm_seq = seqno;
339 rlen = write(sock, next, rtm->rtm_msglen);
340 if (rlen < (int)rtm->rtm_msglen) {
341 warn("write to routing socket, got %d for rlen", rlen);
342 break;
343 }
344 seqno++;
345 if (qflag)
346 continue;
347 if (verbose)
348 print_rtmsg(rtm, rlen);
349 else {
350 struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
351 (void) printf("%-20.20s ",
352 routename(sa, NULL, rtm->rtm_flags));
353 sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa);
354 (void) printf("%-20.20s ",
355 routename(sa, NULL, RTF_HOST));
356 (void) printf("done\n");
357 }
358 }
359 return 0;
360 }
361
362
363 static char hexlist[] = "0123456789abcdef";
364
365 static char *
366 any_ntoa(sa)
367 const struct sockaddr *sa;
368 {
369 static char obuf[64];
370 const char *in;
371 char *out;
372 int len;
373
374 len = sa->sa_len;
375 in = sa->sa_data;
376 out = obuf;
377
378 do {
379 *out++ = hexlist[(*in >> 4) & 15];
380 *out++ = hexlist[(*in++) & 15];
381 *out++ = '.';
382 } while (--len > 0);
383 out[-1] = '\0';
384 return obuf;
385 }
386
387
388 int
389 netmask_length(nm, family)
390 struct sockaddr *nm;
391 int family;
392 {
393 static int
394 /* number of bits in a nibble */
395 _t[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 },
396 /* good nibbles are 1111, 1110, 1100, 1000, 0000 */
397 _g[] = { 1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,1 };
398 int mask, good, zeroes, maskbytes, bit, i;
399 unsigned char *maskdata;
400
401 if (nm == NULL)
402 return 0;
403
404 mask = 0;
405 good = 1;
406 zeroes = 0;
407
408 switch (family) {
409 case AF_INET: {
410 struct sockaddr_in *nsin = (struct sockaddr_in *)nm;
411 maskdata = (unsigned char *) &nsin->sin_addr;
412 maskbytes = nsin->sin_len -
413 ((caddr_t)&nsin->sin_addr - (caddr_t)nsin);
414 break;
415 }
416 case AF_INET6: {
417 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nm;
418 maskdata = (unsigned char *) &sin6->sin6_addr;
419 maskbytes = sin6->sin6_len -
420 ((caddr_t)&sin6->sin6_addr - (caddr_t)sin6);
421 break;
422 }
423 default:
424 return 0;
425 }
426
427 /*
428 * Count the bits in the nibbles of the mask, and marking the
429 * netmask as not good (or at best, non-standard and very
430 * discouraged, in the case of AF_INET) if we find either of
431 * a nibble with non-contiguous bits, or a non-zero nibble
432 * after we've found a zero nibble.
433 */
434 for (i = 0; i < maskbytes; i++) {
435 /* high nibble */
436 mask += bit = _t[maskdata[i] >> 4];
437 good &= _g[maskdata[i] >> 4];
438 if (zeroes && bit)
439 good = 0;
440 if (bit == 0)
441 zeroes = 1;
442 /* low nibble */
443 mask += bit = _t[maskdata[i] & 0xf];
444 good &= _g[maskdata[i] & 0xf];
445 if (zeroes && bit)
446 good = 0;
447 if (bit == 0)
448 zeroes = 1;
449 }
450
451 /*
452 * Always return the number of bits found, but as a negative
453 * if the mask wasn't one we like.
454 */
455 return good ? mask : -mask;
456 }
457
458 char *
459 netmask_string(mask, len)
460 struct sockaddr *mask;
461 int len;
462 {
463 static char smask[16];
464
465 if (len >= 0)
466 snprintf(smask, sizeof(smask), "%d", len);
467 else {
468 /* XXX AF_INET only?! */
469 struct sockaddr_in nsin;
470
471 memset(&nsin, 0, sizeof(nsin));
472 memcpy(&nsin, mask, mask->sa_len);
473 snprintf(smask, sizeof(smask), "%s", inet_ntoa(nsin.sin_addr));
474 }
475
476 return smask;
477 }
478
479
480 char *
481 routename(sa, nm, flags)
482 struct sockaddr *sa, *nm;
483 int flags;
484 {
485 char *cp;
486 static char line[50];
487 struct hostent *hp;
488 static char domain[MAXHOSTNAMELEN + 1];
489 static int first = 1;
490 struct in_addr in;
491 int nml;
492
493 if ((flags & RTF_HOST) == 0)
494 return netname(sa, nm);
495
496 if (first) {
497 first = 0;
498 if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
499 (cp = strchr(domain, '.'))) {
500 (void)strncpy(domain, cp + 1, sizeof(domain) - 1);
501 domain[sizeof(domain) - 1] = '\0';
502 } else
503 domain[0] = 0;
504 }
505
506 if (sa->sa_len == 0) {
507 strncpy(line, "default", sizeof(line) - 1);
508 line[sizeof(line) - 1] = '\0';
509 } else switch (sa->sa_family) {
510
511 case AF_INET:
512 in = ((struct sockaddr_in *)sa)->sin_addr;
513 nml = netmask_length(nm, AF_INET);
514
515 cp = 0;
516 if (in.s_addr == INADDR_ANY || sa->sa_len < 4) {
517 if (nml == 0)
518 cp = "default";
519 else {
520 static char notdefault[sizeof(NOTDEFSTRING)];
521
522 snprintf(notdefault, sizeof(notdefault),
523 "0.0.0.0/%s", netmask_string(nm, nml));
524 cp = notdefault;
525 }
526 }
527 if (cp == 0 && !nflag) {
528 hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
529 AF_INET);
530 if (hp) {
531 if ((cp = strchr(hp->h_name, '.')) &&
532 !strcmp(cp + 1, domain))
533 *cp = 0;
534 cp = hp->h_name;
535 }
536 }
537 if (cp)
538 (void)strncpy(line, cp, sizeof(line) - 1);
539 else
540 (void)strncpy(line, inet_ntoa(in), sizeof(line) - 1);
541 line[sizeof(line) - 1] = '\0';
542 break;
543
544 case AF_LINK:
545 return (link_ntoa((struct sockaddr_dl *)sa));
546
547 #ifndef SMALL
548 #ifdef INET6
549 case AF_INET6:
550 {
551 struct sockaddr_in6 sin6;
552 int niflags;
553
554 #ifdef NI_WITHSCOPEID
555 niflags = NI_WITHSCOPEID;
556 #else
557 niflags = 0;
558 #endif
559 if (nflag)
560 niflags |= NI_NUMERICHOST;
561 memset(&sin6, 0, sizeof(sin6));
562 memcpy(&sin6, sa, sa->sa_len);
563 sin6.sin6_len = sizeof(struct sockaddr_in6);
564 sin6.sin6_family = AF_INET6;
565 #ifdef __KAME__
566 if (sa->sa_len == sizeof(struct sockaddr_in6) &&
567 (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
568 IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
569 sin6.sin6_scope_id == 0) {
570 sin6.sin6_scope_id =
571 ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
572 sin6.sin6_addr.s6_addr[2] = 0;
573 sin6.sin6_addr.s6_addr[3] = 0;
574 }
575 #endif
576 nml = netmask_length(nm, AF_INET6);
577 if (IN6_IS_ADDR_UNSPECIFIED(&sin6.sin6_addr)) {
578 if (nml == 0) {
579 strncpy(line, "::", sizeof(line) - 1);
580 line[sizeof(line) - 1] = '\0';
581 }
582 else
583 /* noncontiguous never happens in ipv6 */
584 snprintf(line, sizeof(line), "::/%d", nml);
585 }
586
587 else if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
588 line, sizeof(line), NULL, 0, niflags) != 0)
589 strncpy(line, "invalid", sizeof(line));
590 break;
591 }
592 #endif
593
594 case AF_NS:
595 return (ns_print((struct sockaddr_ns *)sa));
596
597 case AF_ISO:
598 (void)snprintf(line, sizeof line, "iso %s",
599 iso_ntoa(&((struct sockaddr_iso *)sa)->siso_addr));
600 break;
601 #endif /* SMALL */
602
603 case AF_APPLETALK:
604 (void) snprintf(line, sizeof(line), "atalk %d.%d",
605 ((struct sockaddr_at *)sa)->sat_addr.s_net,
606 ((struct sockaddr_at *)sa)->sat_addr.s_node);
607 break;
608
609 default:
610 (void)snprintf(line, sizeof line, "(%d) %s",
611 sa->sa_family, any_ntoa(sa));
612 break;
613
614 }
615 return (line);
616 }
617
618 /*
619 * Return the name of the network whose address is given.
620 * The address is assumed to be that of a net or subnet, not a host.
621 */
622 char *
623 netname(sa, nm)
624 struct sockaddr *sa, *nm;
625 {
626 char *cp = 0;
627 static char line[50];
628 struct netent *np = 0;
629 u_int32_t net, mask;
630 u_int32_t i;
631 int subnetshift, nml;
632 struct in_addr in;
633
634 switch (sa->sa_family) {
635
636 case AF_INET:
637 in = ((struct sockaddr_in *)sa)->sin_addr;
638 i = ntohl(in.s_addr);
639 nml = netmask_length(nm, AF_INET);
640 if (i == 0) {
641 if (nml == 0)
642 cp = "default";
643 else {
644 static char notdefault[sizeof(NOTDEFSTRING)];
645
646 snprintf(notdefault, sizeof(notdefault),
647 "0.0.0.0/%s", netmask_string(nm, nml));
648 cp = notdefault;
649 }
650 }
651 else if (!nflag) {
652 if (IN_CLASSA(i)) {
653 mask = IN_CLASSA_NET;
654 subnetshift = 8;
655 } else if (IN_CLASSB(i)) {
656 mask = IN_CLASSB_NET;
657 subnetshift = 8;
658 } else {
659 mask = IN_CLASSC_NET;
660 subnetshift = 4;
661 }
662 /*
663 * If there are more bits than the standard mask
664 * would suggest, subnets must be in use.
665 * Guess at the subnet mask, assuming reasonable
666 * width subnet fields.
667 */
668 while (i &~ mask)
669 mask = (int32_t)mask >> subnetshift;
670 net = i & mask;
671 while ((mask & 1) == 0)
672 mask >>= 1, net >>= 1;
673 np = getnetbyaddr(net, AF_INET);
674 if (np)
675 cp = np->n_name;
676 }
677 if (cp) {
678 (void)strncpy(line, cp, sizeof(line) - 1);
679 line[sizeof(line) - 1] = '\0';
680 } else {
681 #if 0 /* XXX - This is silly... */
682 #define C(x) ((x) & 0xff)
683 if ((i & 0xffffff) == 0)
684 (void)snprintf(line, sizeof line, "%u",
685 C(i >> 24));
686 else if ((i & 0xffff) == 0)
687 (void)snprintf(line, sizeof line, "%u.%u",
688 C(i >> 24), C(i >> 16));
689 else if ((i & 0xff) == 0)
690 (void)snprintf(line, sizeof line, "%u.%u.%u",
691 C(i >> 24), C(i >> 16), C(i >> 8));
692 else
693 (void)snprintf(line, sizeof line, "%u.%u.%u.%u",
694 C(i >> 24), C(i >> 16), C(i >> 8), C(i));
695 #undef C
696 #else /* XXX */
697 (void)strncpy(line, inet_ntoa(in), sizeof(line) - 1);
698 #endif /* XXX */
699 }
700 break;
701
702 case AF_LINK:
703 return (link_ntoa((struct sockaddr_dl *)sa));
704
705 #ifndef SMALL
706 #ifdef INET6
707 case AF_INET6:
708 {
709 struct sockaddr_in6 sin6;
710 int niflags;
711
712 #ifdef NI_WITHSCOPEID
713 niflags = NI_WITHSCOPEID;
714 #else
715 niflags = 0;
716 #endif
717 if (nflag)
718 niflags |= NI_NUMERICHOST;
719 memset(&sin6, 0, sizeof(sin6));
720 memcpy(&sin6, sa, sa->sa_len);
721 sin6.sin6_len = sizeof(struct sockaddr_in6);
722 sin6.sin6_family = AF_INET6;
723 #ifdef __KAME__
724 if (sa->sa_len == sizeof(struct sockaddr_in6) &&
725 (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
726 IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
727 sin6.sin6_scope_id == 0) {
728 sin6.sin6_scope_id =
729 ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
730 sin6.sin6_addr.s6_addr[2] = 0;
731 sin6.sin6_addr.s6_addr[3] = 0;
732 }
733 #endif
734 nml = netmask_length(nm, AF_INET6);
735 if (IN6_IS_ADDR_UNSPECIFIED(&sin6.sin6_addr)) {
736 if (nml == 0) {
737 strncpy(line, "::", sizeof(line) - 1);
738 line[sizeof(line) - 1] = '\0';
739 }
740 else
741 /* noncontiguous never happens in ipv6 */
742 snprintf(line, sizeof(line), "::/%d", nml);
743 }
744
745 else if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
746 line, sizeof(line), NULL, 0, niflags) != 0)
747 strncpy(line, "invalid", sizeof(line));
748 break;
749 }
750 #endif
751
752 case AF_NS:
753 return (ns_print((struct sockaddr_ns *)sa));
754
755 case AF_ISO:
756 (void)snprintf(line, sizeof line, "iso %s",
757 iso_ntoa(&((struct sockaddr_iso *)sa)->siso_addr));
758 break;
759 #endif /* SMALL */
760
761 case AF_APPLETALK:
762 (void) snprintf(line, sizeof(line), "atalk %d.%d",
763 ((struct sockaddr_at *)sa)->sat_addr.s_net,
764 ((struct sockaddr_at *)sa)->sat_addr.s_node);
765 break;
766
767 default:
768 (void)snprintf(line, sizeof line, "af %d: %s",
769 sa->sa_family, any_ntoa(sa));
770 break;
771 }
772 return (line);
773 }
774
775 static void
776 set_metric(value, key)
777 char *value;
778 int key;
779 {
780 int flag = 0;
781 u_long noval, *valp = &noval;
782
783 switch (key) {
784 #define caseof(x, y, z) case x: valp = &rt_metrics.z; flag = y; break
785 caseof(K_MTU, RTV_MTU, rmx_mtu);
786 caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount);
787 caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire);
788 caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe);
789 caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe);
790 caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh);
791 caseof(K_RTT, RTV_RTT, rmx_rtt);
792 caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar);
793 }
794 rtm_inits |= flag;
795 if (lockrest || locking)
796 rt_metrics.rmx_locks |= flag;
797 if (locking)
798 locking = 0;
799 *valp = atoi(value);
800 }
801
802 static int
803 newroute(argc, argv)
804 int argc;
805 char **argv;
806 {
807 char *cmd, *dest = "", *gateway = "";
808 const char *error;
809 int ishost = 0, ret, attempts, oerrno, flags = RTF_STATIC;
810 int key;
811 struct hostent *hp = 0;
812
813 cmd = argv[0];
814 af = 0;
815 if (*cmd != 'g')
816 shutdown(sock, SHUT_RD); /* Don't want to read back our messages */
817 while (--argc > 0) {
818 if (**(++argv)== '-') {
819 switch (key = keyword(1 + *argv)) {
820
821 case K_SA:
822 af = PF_ROUTE;
823 aflen = sizeof(union sockunion);
824 break;
825
826 case K_ATALK:
827 af = AF_APPLETALK;
828 aflen = sizeof(struct sockaddr_at);
829 break;
830
831 case K_INET:
832 af = AF_INET;
833 aflen = sizeof(struct sockaddr_in);
834 break;
835
836 #ifdef INET6
837 case K_INET6:
838 af = AF_INET6;
839 aflen = sizeof(struct sockaddr_in6);
840 break;
841 #endif
842
843 case K_LINK:
844 af = AF_LINK;
845 aflen = sizeof(struct sockaddr_dl);
846 break;
847
848 #ifndef SMALL
849 case K_OSI:
850 case K_ISO:
851 af = AF_ISO;
852 aflen = sizeof(struct sockaddr_iso);
853 break;
854
855 case K_X25:
856 af = AF_CCITT;
857 aflen = sizeof(struct sockaddr_x25);
858 break;
859
860 case K_XNS:
861 af = AF_NS;
862 aflen = sizeof(struct sockaddr_ns);
863 break;
864 #endif /* SMALL */
865
866 case K_IFACE:
867 case K_INTERFACE:
868 iflag++;
869 break;
870 case K_NOSTATIC:
871 flags &= ~RTF_STATIC;
872 break;
873 case K_LLINFO:
874 flags |= RTF_LLINFO;
875 break;
876 case K_LOCK:
877 locking = 1;
878 break;
879 case K_LOCKREST:
880 lockrest = 1;
881 break;
882 case K_HOST:
883 forcehost++;
884 break;
885 case K_REJECT:
886 flags |= RTF_REJECT;
887 break;
888 case K_BLACKHOLE:
889 flags |= RTF_BLACKHOLE;
890 break;
891 case K_CLONED:
892 flags |= RTF_CLONED;
893 break;
894 case K_PROTO1:
895 flags |= RTF_PROTO1;
896 break;
897 case K_PROTO2:
898 flags |= RTF_PROTO2;
899 break;
900 case K_CLONING:
901 flags |= RTF_CLONING;
902 break;
903 case K_XRESOLVE:
904 flags |= RTF_XRESOLVE;
905 break;
906 case K_STATIC:
907 flags |= RTF_STATIC;
908 break;
909 case K_IFA:
910 if (!--argc)
911 usage(1+*argv);
912 (void) getaddr(RTA_IFA, *++argv, 0);
913 break;
914 case K_IFP:
915 if (!--argc)
916 usage(1+*argv);
917 (void) getaddr(RTA_IFP, *++argv, 0);
918 break;
919 case K_GENMASK:
920 if (!--argc)
921 usage(1+*argv);
922 (void) getaddr(RTA_GENMASK, *++argv, 0);
923 break;
924 case K_GATEWAY:
925 if (!--argc)
926 usage(1+*argv);
927 (void) getaddr(RTA_GATEWAY, *++argv, 0);
928 break;
929 case K_DST:
930 if (!--argc)
931 usage(1+*argv);
932 ishost = getaddr(RTA_DST, *++argv, &hp);
933 dest = *argv;
934 break;
935 case K_NETMASK:
936 if (!--argc)
937 usage(1+*argv);
938 (void) getaddr(RTA_NETMASK, *++argv, 0);
939 /* FALLTHROUGH */
940 case K_NET:
941 forcenet++;
942 break;
943 case K_PREFIXLEN:
944 if (!--argc)
945 usage(1+*argv);
946 ishost = prefixlen(*++argv);
947 break;
948 case K_MTU:
949 case K_HOPCOUNT:
950 case K_EXPIRE:
951 case K_RECVPIPE:
952 case K_SENDPIPE:
953 case K_SSTHRESH:
954 case K_RTT:
955 case K_RTTVAR:
956 if (!--argc)
957 usage(1+*argv);
958 set_metric(*++argv, key);
959 break;
960 default:
961 usage(1+*argv);
962 }
963 } else {
964 if ((rtm_addrs & RTA_DST) == 0) {
965 dest = *argv;
966 ishost = getaddr(RTA_DST, *argv, &hp);
967 } else if ((rtm_addrs & RTA_GATEWAY) == 0) {
968 gateway = *argv;
969 (void) getaddr(RTA_GATEWAY, *argv, &hp);
970 } else {
971 ret = atoi(*argv);
972
973 if (ret == 0) {
974 if (!qflag && strcmp(*argv, "0") == 0)
975 warnx("%s, %s",
976 "old usage of trailing 0",
977 "assuming route to if");
978 else
979 usage((char *)NULL);
980 iflag = 1;
981 continue;
982 } else if (ret > 0 && ret < 10) {
983 if (!qflag) {
984 warnx("%s, %s",
985 "old usage of trailing digit",
986 "assuming route via gateway");
987 }
988 iflag = 0;
989 continue;
990 }
991 (void) getaddr(RTA_NETMASK, *argv, 0);
992 }
993 }
994 }
995 if (forcehost)
996 ishost = 1;
997 if (forcenet)
998 ishost = 0;
999 flags |= RTF_UP;
1000 if (ishost)
1001 flags |= RTF_HOST;
1002 if (iflag == 0)
1003 flags |= RTF_GATEWAY;
1004 for (attempts = 1; ; attempts++) {
1005 errno = 0;
1006 if ((ret = rtmsg(*cmd, flags)) == 0)
1007 break;
1008 if (errno != ENETUNREACH && errno != ESRCH)
1009 break;
1010 if (af == AF_INET && *gateway && hp && hp->h_addr_list[1]) {
1011 hp->h_addr_list++;
1012 memmove(&so_gate.sin.sin_addr, hp->h_addr_list[0],
1013 hp->h_length);
1014 } else
1015 break;
1016 }
1017 if (*cmd == 'g')
1018 return rv;
1019 oerrno = errno;
1020 if (!qflag) {
1021 (void) printf("%s %s %s", cmd, ishost? "host" : "net", dest);
1022 if (*gateway) {
1023 (void) printf(": gateway %s", gateway);
1024 if (attempts > 1 && ret == 0 && af == AF_INET)
1025 (void) printf(" (%s)",
1026 inet_ntoa(so_gate.sin.sin_addr));
1027 }
1028 if (ret == 0)
1029 (void) printf("\n");
1030 }
1031 if (ret != 0) {
1032 switch (oerrno) {
1033 case ESRCH:
1034 error = "not in table";
1035 break;
1036 case EBUSY:
1037 error = "entry in use";
1038 break;
1039 case ENOBUFS:
1040 error = "routing table overflow";
1041 break;
1042 default:
1043 error = strerror(oerrno);
1044 break;
1045 }
1046 (void) printf(": %s\n", error);
1047 return 1;
1048 }
1049 return 0;
1050 }
1051
1052 static void
1053 inet_makenetandmask(net, isin)
1054 u_int32_t net;
1055 struct sockaddr_in *isin;
1056 {
1057 u_int32_t addr, mask = 0;
1058 char *cp;
1059
1060 rtm_addrs |= RTA_NETMASK;
1061 if (net == 0)
1062 mask = addr = 0;
1063 else if (net < 128) {
1064 addr = net << IN_CLASSA_NSHIFT;
1065 mask = IN_CLASSA_NET;
1066 } else if (net < 65536) {
1067 addr = net << IN_CLASSB_NSHIFT;
1068 mask = IN_CLASSB_NET;
1069 } else if (net < 16777216L) {
1070 addr = net << IN_CLASSC_NSHIFT;
1071 mask = IN_CLASSC_NET;
1072 } else {
1073 addr = net;
1074 if ((addr & IN_CLASSA_HOST) == 0)
1075 mask = IN_CLASSA_NET;
1076 else if ((addr & IN_CLASSB_HOST) == 0)
1077 mask = IN_CLASSB_NET;
1078 else if ((addr & IN_CLASSC_HOST) == 0)
1079 mask = IN_CLASSC_NET;
1080 else
1081 mask = -1;
1082 }
1083 isin->sin_addr.s_addr = htonl(addr);
1084 isin = &so_mask.sin;
1085 isin->sin_addr.s_addr = htonl(mask);
1086 isin->sin_len = 0;
1087 isin->sin_family = 0;
1088 cp = (char *)(&isin->sin_addr + 1);
1089 while (*--cp == 0 && cp > (char *)isin)
1090 ;
1091 isin->sin_len = 1 + cp - (char *)isin;
1092 }
1093
1094 #ifdef INET6
1095 /*
1096 * XXX the function may need more improvement...
1097 */
1098 static int
1099 inet6_makenetandmask(sin6)
1100 struct sockaddr_in6 *sin6;
1101 {
1102 char *plen;
1103 struct in6_addr in6;
1104
1105 plen = NULL;
1106 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
1107 sin6->sin6_scope_id == 0) {
1108 plen = "0";
1109 } else if ((sin6->sin6_addr.s6_addr[0] & 0xe0) == 0x20) {
1110 /* aggregatable global unicast - RFC2374 */
1111 memset(&in6, 0, sizeof(in6));
1112 if (!memcmp(&sin6->sin6_addr.s6_addr[8], &in6.s6_addr[8], 8))
1113 plen = "64";
1114 }
1115
1116 if (!plen || strcmp(plen, "128") == 0)
1117 return 1;
1118 else {
1119 rtm_addrs |= RTA_NETMASK;
1120 (void)prefixlen(plen);
1121 return 0;
1122 }
1123 }
1124 #endif
1125
1126 /*
1127 * Interpret an argument as a network address of some kind,
1128 * returning 1 if a host address, 0 if a network address.
1129 */
1130 static int
1131 getaddr(which, s, hpp)
1132 int which;
1133 char *s;
1134 struct hostent **hpp;
1135 {
1136 sup su;
1137 struct hostent *hp;
1138 struct netent *np;
1139 u_int32_t val;
1140 char *t;
1141 int afamily; /* local copy of af so we can change it */
1142
1143 if (af == 0) {
1144 af = AF_INET;
1145 aflen = sizeof(struct sockaddr_in);
1146 }
1147 afamily = af;
1148 rtm_addrs |= which;
1149 switch (which) {
1150 case RTA_DST:
1151 su = &so_dst;
1152 break;
1153 case RTA_GATEWAY:
1154 su = &so_gate;
1155 break;
1156 case RTA_NETMASK:
1157 su = &so_mask;
1158 break;
1159 case RTA_GENMASK:
1160 su = &so_genmask;
1161 break;
1162 case RTA_IFP:
1163 su = &so_ifp;
1164 afamily = AF_LINK;
1165 break;
1166 case RTA_IFA:
1167 su = &so_ifa;
1168 su->sa.sa_family = af;
1169 break;
1170 default:
1171 su = NULL;
1172 usage("Internal Error");
1173 /*NOTREACHED*/
1174 }
1175 su->sa.sa_len = aflen;
1176 su->sa.sa_family = afamily; /* cases that don't want it have left already */
1177 if (strcmp(s, "default") == 0) {
1178 switch (which) {
1179 case RTA_DST:
1180 forcenet++;
1181 (void) getaddr(RTA_NETMASK, s, 0);
1182 break;
1183 case RTA_NETMASK:
1184 case RTA_GENMASK:
1185 su->sa.sa_len = 0;
1186 }
1187 return (0);
1188 }
1189 switch (afamily) {
1190 #ifndef SMALL
1191 #ifdef INET6
1192 case AF_INET6:
1193 {
1194 struct addrinfo hints, *res;
1195
1196 memset(&hints, 0, sizeof(hints));
1197 hints.ai_family = afamily; /*AF_INET6*/
1198 hints.ai_flags = AI_NUMERICHOST;
1199 hints.ai_socktype = SOCK_DGRAM; /*dummy*/
1200 if (getaddrinfo(s, "0", &hints, &res) != 0) {
1201 hints.ai_flags = 0;
1202 if (getaddrinfo(s, "0", &hints, &res) != 0) {
1203 (void) fprintf(stderr, "%s: bad value\n", s);
1204 exit(1);
1205 }
1206 }
1207 if (sizeof(su->sin6) != res->ai_addrlen) {
1208 (void) fprintf(stderr, "%s: bad value\n", s);
1209 exit(1);
1210 }
1211 if (res->ai_next) {
1212 (void) fprintf(stderr,
1213 "%s: resolved to multiple values\n", s);
1214 exit(1);
1215 }
1216 memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6));
1217 freeaddrinfo(res);
1218 #ifdef __KAME__
1219 if ((IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr) ||
1220 IN6_IS_ADDR_MC_LINKLOCAL(&su->sin6.sin6_addr)) &&
1221 su->sin6.sin6_scope_id) {
1222 *(u_int16_t *)&su->sin6.sin6_addr.s6_addr[2] =
1223 htons(su->sin6.sin6_scope_id);
1224 su->sin6.sin6_scope_id = 0;
1225 }
1226 #endif
1227 if (hints.ai_flags == AI_NUMERICHOST) {
1228 if (which == RTA_DST)
1229 return (inet6_makenetandmask(&su->sin6));
1230 return (0);
1231 } else
1232 return (1);
1233 }
1234 #endif
1235
1236 case AF_NS:
1237 if (which == RTA_DST) {
1238 struct sockaddr_ns *sms = &(so_mask.sns);
1239 memset(sms, 0, sizeof(*sms));
1240 sms->sns_family = 0;
1241 sms->sns_len = 6;
1242 sms->sns_addr.x_net = *(union ns_net *)ns_bh;
1243 rtm_addrs |= RTA_NETMASK;
1244 }
1245 su->sns.sns_addr = ns_addr(s);
1246 return (!ns_nullhost(su->sns.sns_addr));
1247
1248 case AF_OSI:
1249 su->siso.siso_addr = *iso_addr(s);
1250 if (which == RTA_NETMASK || which == RTA_GENMASK) {
1251 char *cp = (char *)TSEL(&su->siso);
1252 su->siso.siso_nlen = 0;
1253 do {--cp ;} while ((cp > (char *)su) && (*cp == 0));
1254 su->siso.siso_len = 1 + cp - (char *)su;
1255 }
1256 return (1);
1257
1258 case AF_CCITT:
1259 ccitt_addr(s, &su->sx25);
1260 return (which == RTA_DST ? x25_makemask() : 1);
1261 #endif /* SMALL */
1262
1263 case PF_ROUTE:
1264 su->sa.sa_len = sizeof(*su);
1265 sockaddr(s, &su->sa);
1266 return (1);
1267
1268 case AF_APPLETALK:
1269 t = strchr (s, '.');
1270 if (!t) {
1271 badataddr:
1272 errx(1, "bad address: %s", s);
1273 }
1274 val = atoi (s);
1275 if (val > 65535)
1276 goto badataddr;
1277 su->sat.sat_addr.s_net = val;
1278 val = atoi (t);
1279 if (val > 256)
1280 goto badataddr;
1281 su->sat.sat_addr.s_node = val;
1282 rtm_addrs |= RTA_NETMASK;
1283 return(forcehost || su->sat.sat_addr.s_node != 0);
1284
1285 case AF_LINK:
1286 link_addr(s, &su->sdl);
1287 return (1);
1288
1289 case AF_INET:
1290 default:
1291 break;
1292 }
1293
1294 if (hpp == NULL)
1295 hpp = &hp;
1296 *hpp = NULL;
1297 if (((val = inet_addr(s)) != INADDR_NONE) &&
1298 (which != RTA_DST || forcenet == 0)) {
1299 su->sin.sin_addr.s_addr = val;
1300 if (inet_lnaof(su->sin.sin_addr) != INADDR_ANY)
1301 return (1);
1302 else {
1303 val = ntohl(val);
1304 goto netdone;
1305 }
1306 }
1307 if ((val = inet_network(s)) != INADDR_NONE ||
1308 ((np = getnetbyname(s)) != NULL && (val = np->n_net) != 0)) {
1309 netdone:
1310 if (which == RTA_DST)
1311 inet_makenetandmask(val, &su->sin);
1312 return (0);
1313 }
1314 hp = gethostbyname(s);
1315 if (hp) {
1316 *hpp = hp;
1317 su->sin.sin_family = hp->h_addrtype;
1318 memmove(&su->sin.sin_addr, hp->h_addr, hp->h_length);
1319 return (1);
1320 }
1321 errx(1, "bad value: %s", s);
1322 }
1323
1324 int
1325 prefixlen(s)
1326 char *s;
1327 {
1328 int len = atoi(s), q, r;
1329 int max;
1330
1331 switch (af) {
1332 case AF_INET:
1333 max = sizeof(struct in_addr) * 8;
1334 break;
1335 #ifdef INET6
1336 case AF_INET6:
1337 max = sizeof(struct in6_addr) * 8;
1338 break;
1339 #endif
1340 default:
1341 (void) fprintf(stderr,
1342 "prefixlen is not supported with af %d\n", af);
1343 exit(1);
1344 }
1345
1346 rtm_addrs |= RTA_NETMASK;
1347 if (len < -1 || len > max) {
1348 (void) fprintf(stderr, "%s: bad value\n", s);
1349 exit(1);
1350 }
1351
1352 q = len >> 3;
1353 r = len & 7;
1354 switch (af) {
1355 case AF_INET:
1356 memset(&so_mask, 0, sizeof(so_mask));
1357 so_mask.sin.sin_family = AF_INET;
1358 so_mask.sin.sin_len = sizeof(struct sockaddr_in);
1359 so_mask.sin.sin_addr.s_addr = htonl(0xffffffff << (32 - len));
1360 break;
1361 #ifdef INET6
1362 case AF_INET6:
1363 so_mask.sin6.sin6_family = AF_INET6;
1364 so_mask.sin6.sin6_len = sizeof(struct sockaddr_in6);
1365 memset((void *)&so_mask.sin6.sin6_addr, 0,
1366 sizeof(so_mask.sin6.sin6_addr));
1367 if (q > 0)
1368 memset((void *)&so_mask.sin6.sin6_addr, 0xff, q);
1369 if (r > 0)
1370 *((u_char *)&so_mask.sin6.sin6_addr + q) =
1371 (0xff00 >> r) & 0xff;
1372 break;
1373 #endif
1374 }
1375 return (len == max);
1376 }
1377
1378 #ifndef SMALL
1379 int
1380 x25_makemask()
1381 {
1382 char *cp;
1383
1384 if ((rtm_addrs & RTA_NETMASK) == 0) {
1385 rtm_addrs |= RTA_NETMASK;
1386 for (cp = (char *)&so_mask.sx25.x25_net;
1387 cp < &so_mask.sx25.x25_opts.op_flags; cp++)
1388 *cp = -1;
1389 so_mask.sx25.x25_len = (u_char)&(((sup)0)->sx25.x25_opts);
1390 }
1391 return 0;
1392 }
1393
1394
1395 char *
1396 ns_print(sns)
1397 struct sockaddr_ns *sns;
1398 {
1399 struct ns_addr work;
1400 union { union ns_net net_e; u_int32_t int32_t_e; } net;
1401 u_short port;
1402 static char mybuf[50], cport[10], chost[25];
1403 char *host = "";
1404 char *p;
1405 u_char *q;
1406
1407 work = sns->sns_addr;
1408 port = ntohs(work.x_port);
1409 work.x_port = 0;
1410 net.net_e = work.x_net;
1411 if (ns_nullhost(work) && net.int32_t_e == 0) {
1412 if (!port)
1413 return ("*.*");
1414 (void)snprintf(mybuf, sizeof mybuf, "*.%XH", port);
1415 return (mybuf);
1416 }
1417
1418 if (memcmp(ns_bh, work.x_host.c_host, 6) == 0)
1419 host = "any";
1420 else if (memcmp(ns_nullh, work.x_host.c_host, 6) == 0)
1421 host = "*";
1422 else {
1423 q = work.x_host.c_host;
1424 (void)snprintf(chost, sizeof chost, "%02X%02X%02X%02X%02X%02XH",
1425 q[0], q[1], q[2], q[3], q[4], q[5]);
1426 for (p = chost; *p == '0' && p < chost + 12; p++)
1427 /* void */;
1428 host = p;
1429 }
1430 if (port)
1431 (void)snprintf(cport, sizeof cport, ".%XH", htons(port));
1432 else
1433 *cport = 0;
1434
1435 (void)snprintf(mybuf, sizeof mybuf, "%XH.%s%s",
1436 (u_int32_t)ntohl(net.int32_t_e), host, cport);
1437 return (mybuf);
1438 }
1439
1440 static void
1441 interfaces()
1442 {
1443 size_t needed;
1444 int mib[6];
1445 char *buf, *lim, *next;
1446 struct rt_msghdr *rtm;
1447
1448 mib[0] = CTL_NET;
1449 mib[1] = PF_ROUTE;
1450 mib[2] = 0; /* protocol */
1451 mib[3] = 0; /* wildcard address family */
1452 mib[4] = NET_RT_IFLIST;
1453 mib[5] = 0; /* no flags */
1454 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
1455 err(1, "route-sysctl-estimate");
1456 if ((buf = malloc(needed)) == NULL)
1457 err(1, "malloc");
1458 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
1459 err(1, "actual retrieval of interface table");
1460 lim = buf + needed;
1461 for (next = buf; next < lim; next += rtm->rtm_msglen) {
1462 rtm = (struct rt_msghdr *)next;
1463 print_rtmsg(rtm, rtm->rtm_msglen);
1464 }
1465 }
1466
1467 static void
1468 monitor()
1469 {
1470 int n;
1471 char msg[2048];
1472
1473 verbose = 1;
1474 if (debugonly) {
1475 interfaces();
1476 exit(0);
1477 }
1478 for(;;) {
1479 time_t now;
1480 n = read(sock, msg, 2048);
1481 now = time(NULL);
1482 (void) printf("got message of size %d on %s", n, ctime(&now));
1483 print_rtmsg((struct rt_msghdr *)msg, n);
1484 }
1485 }
1486
1487 #endif /* SMALL */
1488
1489
1490 struct {
1491 struct rt_msghdr m_rtm;
1492 char m_space[512];
1493 } m_rtmsg;
1494
1495 static int
1496 rtmsg(cmd, flags)
1497 int cmd, flags;
1498 {
1499 static int seq;
1500 int rlen;
1501 char *cp = m_rtmsg.m_space;
1502 int l;
1503
1504 #define NEXTADDR(w, u) \
1505 if (rtm_addrs & (w)) {\
1506 l = ROUNDUP(u.sa.sa_len); memmove(cp, &(u), l); cp += l;\
1507 if (verbose && ! shortoutput) sodump(&(u),"u");\
1508 }
1509
1510 errno = 0;
1511 memset(&m_rtmsg, 0, sizeof(m_rtmsg));
1512 if (cmd == 'a')
1513 cmd = RTM_ADD;
1514 else if (cmd == 'c')
1515 cmd = RTM_CHANGE;
1516 else if (cmd == 'g') {
1517 #ifdef SMALL
1518 return (-1);
1519 #else /* SMALL */
1520 cmd = RTM_GET;
1521 if (so_ifp.sa.sa_family == 0) {
1522 so_ifp.sa.sa_family = AF_LINK;
1523 so_ifp.sa.sa_len = sizeof(struct sockaddr_dl);
1524 rtm_addrs |= RTA_IFP;
1525 }
1526 #endif /* SMALL */
1527 } else
1528 cmd = RTM_DELETE;
1529 #define rtm m_rtmsg.m_rtm
1530 rtm.rtm_type = cmd;
1531 rtm.rtm_flags = flags;
1532 rtm.rtm_version = RTM_VERSION;
1533 rtm.rtm_seq = ++seq;
1534 rtm.rtm_addrs = rtm_addrs;
1535 rtm.rtm_rmx = rt_metrics;
1536 rtm.rtm_inits = rtm_inits;
1537
1538 if (rtm_addrs & RTA_NETMASK)
1539 mask_addr();
1540 NEXTADDR(RTA_DST, so_dst);
1541 NEXTADDR(RTA_GATEWAY, so_gate);
1542 NEXTADDR(RTA_NETMASK, so_mask);
1543 NEXTADDR(RTA_GENMASK, so_genmask);
1544 NEXTADDR(RTA_IFP, so_ifp);
1545 NEXTADDR(RTA_IFA, so_ifa);
1546 rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
1547 if (verbose && ! shortoutput)
1548 print_rtmsg(&rtm, l);
1549 if (debugonly)
1550 return (0);
1551 if ((rlen = write(sock, (char *)&m_rtmsg, l)) < 0) {
1552 perror("writing to routing socket");
1553 return (-1);
1554 }
1555 #ifndef SMALL
1556 if (cmd == RTM_GET) {
1557 do {
1558 l = read(sock, (char *)&m_rtmsg, sizeof(m_rtmsg));
1559 } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
1560 if (l < 0)
1561 err(1, "read from routing socket");
1562 else
1563 print_getmsg(&rtm, l);
1564 }
1565 #endif /* SMALL */
1566 #undef rtm
1567 return (0);
1568 }
1569
1570 static void
1571 mask_addr()
1572 {
1573 int olen = so_mask.sa.sa_len;
1574 char *cp1 = olen + (char *)&so_mask, *cp2;
1575
1576 for (so_mask.sa.sa_len = 0; cp1 > (char *)&so_mask; )
1577 if (*--cp1 != 0) {
1578 so_mask.sa.sa_len = 1 + cp1 - (char *)&so_mask;
1579 break;
1580 }
1581 if ((rtm_addrs & RTA_DST) == 0)
1582 return;
1583 switch (so_dst.sa.sa_family) {
1584 case AF_INET:
1585 #ifdef INET6
1586 case AF_INET6:
1587 #endif
1588 case AF_APPLETALK:
1589 #ifndef SMALL
1590 case AF_NS:
1591 case AF_CCITT:
1592 #endif /* SMALL */
1593 case 0:
1594 return;
1595 #ifndef SMALL
1596 case AF_ISO:
1597 olen = MIN(so_dst.siso.siso_nlen,
1598 MAX(so_mask.sa.sa_len - 6, 0));
1599 break;
1600 #endif /* SMALL */
1601 }
1602 cp1 = so_mask.sa.sa_len + 1 + (char *)&so_dst;
1603 cp2 = so_dst.sa.sa_len + 1 + (char *)&so_dst;
1604 while (cp2 > cp1)
1605 *--cp2 = 0;
1606 cp2 = so_mask.sa.sa_len + 1 + (char *)&so_mask;
1607 while (cp1 > so_dst.sa.sa_data)
1608 *--cp1 &= *--cp2;
1609 #ifndef SMALL
1610 switch (so_dst.sa.sa_family) {
1611 case AF_ISO:
1612 so_dst.siso.siso_nlen = olen;
1613 break;
1614 }
1615 #endif /* SMALL */
1616 }
1617
1618 char *msgtypes[] = {
1619 "",
1620 "RTM_ADD: Add Route",
1621 "RTM_DELETE: Delete Route",
1622 "RTM_CHANGE: Change Metrics or flags",
1623 "RTM_GET: Report Metrics",
1624 "RTM_LOSING: Kernel Suspects Partitioning",
1625 "RTM_REDIRECT: Told to use different route",
1626 "RTM_MISS: Lookup failed on this address",
1627 "RTM_LOCK: fix specified metrics",
1628 "RTM_OLDADD: caused by SIOCADDRT",
1629 "RTM_OLDDEL: caused by SIOCDELRT",
1630 "RTM_RESOLVE: Route created by cloning",
1631 "RTM_NEWADDR: address being added to iface",
1632 "RTM_DELADDR: address being removed from iface",
1633 "RTM_OIFINFO: iface status change (pre-1.5)",
1634 "RTM_IFINFO: iface status change",
1635 "RTM_IFANNOUNCE: iface arrival/departure",
1636 0,
1637 };
1638
1639 char metricnames[] =
1640 "\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount\1mtu";
1641 char routeflags[] =
1642 "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE\016CLONED\017PROTO2\020PROTO1";
1643 char ifnetflags[] =
1644 "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6NOTRAILERS\7RUNNING\010NOARP\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1\017LINK2\020MULTICAST";
1645 char addrnames[] =
1646 "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
1647
1648
1649 #ifndef SMALL
1650 static const char *
1651 linkstate(ifm)
1652 struct if_msghdr *ifm;
1653 {
1654 static char buf[64];
1655
1656 switch (ifm->ifm_data.ifi_link_state) {
1657 case LINK_STATE_UNKNOWN:
1658 return "carrier: unknown";
1659 case LINK_STATE_DOWN:
1660 return "carrier: no carrier";
1661 case LINK_STATE_UP:
1662 return "carrier: active";
1663 default:
1664 (void)snprintf(buf, sizeof(buf), "carrier: 0x%x",
1665 ifm->ifm_data.ifi_link_state);
1666 return buf;
1667 }
1668 }
1669 #endif /* SMALL */
1670
1671 static void
1672 print_rtmsg(rtm, msglen)
1673 struct rt_msghdr *rtm;
1674 int msglen;
1675 {
1676 struct if_msghdr *ifm;
1677 struct ifa_msghdr *ifam;
1678 struct if_announcemsghdr *ifan;
1679
1680 if (verbose == 0)
1681 return;
1682 if (rtm->rtm_version != RTM_VERSION) {
1683 (void) printf("routing message version %d not understood\n",
1684 rtm->rtm_version);
1685 return;
1686 }
1687 if (msgtypes[rtm->rtm_type])
1688 (void)printf("%s: ", msgtypes[rtm->rtm_type]);
1689 else
1690 (void)printf("#%d: ", rtm->rtm_type);
1691 (void)printf("len %d, ", rtm->rtm_msglen);
1692 switch (rtm->rtm_type) {
1693 case RTM_IFINFO:
1694 ifm = (struct if_msghdr *)rtm;
1695 (void) printf("if# %d, %s, flags:", ifm->ifm_index,
1696 #ifdef SMALL
1697 ""
1698 #else
1699 linkstate(ifm)
1700 #endif /* SMALL */
1701 );
1702 bprintf(stdout, ifm->ifm_flags, ifnetflags);
1703 pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs);
1704 break;
1705 case RTM_NEWADDR:
1706 case RTM_DELADDR:
1707 ifam = (struct ifa_msghdr *)rtm;
1708 (void) printf("metric %d, flags:", ifam->ifam_metric);
1709 bprintf(stdout, ifam->ifam_flags, routeflags);
1710 pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs);
1711 break;
1712 case RTM_IFANNOUNCE:
1713 ifan = (struct if_announcemsghdr *)rtm;
1714 (void) printf("if# %d, what: ", ifan->ifan_index);
1715 switch (ifan->ifan_what) {
1716 case IFAN_ARRIVAL:
1717 printf("arrival");
1718 break;
1719 case IFAN_DEPARTURE:
1720 printf("departure");
1721 break;
1722 default:
1723 printf("#%d", ifan->ifan_what);
1724 break;
1725 }
1726 printf("\n");
1727 break;
1728 default:
1729 (void) printf("pid: %d, seq %d, errno %d, flags:",
1730 rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno);
1731 bprintf(stdout, rtm->rtm_flags, routeflags);
1732 pmsg_common(rtm);
1733 }
1734 }
1735
1736 #ifndef SMALL
1737 static void
1738 print_getmsg(rtm, msglen)
1739 struct rt_msghdr *rtm;
1740 int msglen;
1741 {
1742 struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL, *ifa = NULL;
1743 struct sockaddr_dl *ifp = NULL;
1744 struct sockaddr *sa;
1745 char *cp;
1746 int i;
1747
1748 if (! shortoutput)
1749 (void) printf(" route to: %s\n",
1750 routename((struct sockaddr *) &so_dst, NULL, RTF_HOST));
1751 if (rtm->rtm_version != RTM_VERSION) {
1752 warnx("routing message version %d not understood",
1753 rtm->rtm_version);
1754 return;
1755 }
1756 if (rtm->rtm_msglen > msglen) {
1757 warnx("message length mismatch, in packet %d, returned %d",
1758 rtm->rtm_msglen, msglen);
1759 }
1760 if (rtm->rtm_errno) {
1761 warn("RTM_GET");
1762 return;
1763 }
1764 cp = ((char *)(rtm + 1));
1765 if (rtm->rtm_addrs)
1766 for (i = 1; i; i <<= 1)
1767 if (i & rtm->rtm_addrs) {
1768 sa = (struct sockaddr *)cp;
1769 switch (i) {
1770 case RTA_DST:
1771 dst = sa;
1772 break;
1773 case RTA_GATEWAY:
1774 gate = sa;
1775 break;
1776 case RTA_NETMASK:
1777 mask = sa;
1778 break;
1779 case RTA_IFP:
1780 if (sa->sa_family == AF_LINK &&
1781 ((struct sockaddr_dl *)sa)->sdl_nlen)
1782 ifp = (struct sockaddr_dl *)sa;
1783 break;
1784 case RTA_IFA:
1785 ifa = sa;
1786 break;
1787 }
1788 ADVANCE(cp, sa);
1789 }
1790 if (dst && mask)
1791 mask->sa_family = dst->sa_family; /* XXX */
1792 if (dst && ! shortoutput)
1793 (void)printf("destination: %s\n",
1794 routename(dst, mask, RTF_HOST));
1795 if (mask && ! shortoutput) {
1796 int savenflag = nflag;
1797
1798 nflag = 1;
1799 (void)printf(" mask: %s\n",
1800 routename(mask, NULL, RTF_HOST));
1801 nflag = savenflag;
1802 }
1803 if (gate && rtm->rtm_flags & RTF_GATEWAY && ! shortoutput)
1804 (void)printf(" gateway: %s\n",
1805 routename(gate, NULL, RTF_HOST));
1806 if (ifa && ! shortoutput)
1807 (void)printf(" local addr: %s\n",
1808 routename(ifa, NULL, RTF_HOST));
1809 if (ifp && ! shortoutput)
1810 (void)printf(" interface: %.*s\n",
1811 ifp->sdl_nlen, ifp->sdl_data);
1812 if (! shortoutput) {
1813 (void)printf(" flags: ");
1814 bprintf(stdout, rtm->rtm_flags, routeflags);
1815 }
1816
1817 #define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ')
1818 #define msec(u) (((u) + 500) / 1000) /* usec to msec */
1819
1820 if (! shortoutput) {
1821 (void) printf("\n%s\n", "\
1822 recvpipe sendpipe ssthresh rtt,msec rttvar hopcount mtu expire");
1823 printf("%8ld%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE));
1824 printf("%8ld%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE));
1825 printf("%8ld%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH));
1826 printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT));
1827 printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR));
1828 printf("%8ld%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT));
1829 printf("%8ld%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU));
1830 if (rtm->rtm_rmx.rmx_expire)
1831 rtm->rtm_rmx.rmx_expire -= time(0);
1832 printf("%8ld%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE));
1833 }
1834 #undef lock
1835 #undef msec
1836 #define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD)
1837
1838 if ((rtm->rtm_addrs & RTF_GATEWAY) == 0)
1839 rv = 1;
1840 else {
1841 char *name;
1842 int addrs;
1843
1844 cp = (char *)(rtm + 1);
1845 addrs = rtm->rtm_addrs;
1846
1847 for (i = 1; i; i <<= 1) {
1848 sa = (struct sockaddr *)cp;
1849 if (i == RTF_GATEWAY) {
1850 name = routename(sa, NULL, RTF_HOST);
1851 if (name[0] == '\0')
1852 rv = 1;
1853 else if (shortoutput)
1854 printf("%s\n", name);
1855 }
1856 if (i & addrs)
1857 ADVANCE(cp, sa);
1858 }
1859 }
1860
1861 if (shortoutput)
1862 return;
1863 else if (verbose)
1864 pmsg_common(rtm);
1865 else if (rtm->rtm_addrs &~ RTA_IGN) {
1866 (void) printf("sockaddrs: ");
1867 bprintf(stdout, rtm->rtm_addrs, addrnames);
1868 putchar('\n');
1869 }
1870 #undef RTA_IGN
1871 }
1872 #endif /* SMALL */
1873
1874 void
1875 pmsg_common(rtm)
1876 struct rt_msghdr *rtm;
1877 {
1878 (void) printf("\nlocks: ");
1879 bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames);
1880 (void) printf(" inits: ");
1881 bprintf(stdout, rtm->rtm_inits, metricnames);
1882 pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs);
1883 }
1884
1885 static void
1886 pmsg_addrs(cp, addrs)
1887 char *cp;
1888 int addrs;
1889 {
1890 struct sockaddr *sa;
1891 int i;
1892
1893 if (addrs != 0) {
1894 (void) printf("\nsockaddrs: ");
1895 bprintf(stdout, addrs, addrnames);
1896 (void) putchar('\n');
1897 for (i = 1; i; i <<= 1)
1898 if (i & addrs) {
1899 sa = (struct sockaddr *)cp;
1900 (void) printf(" %s",
1901 routename(sa, NULL, RTF_HOST));
1902 ADVANCE(cp, sa);
1903 }
1904 }
1905 (void) putchar('\n');
1906 (void) fflush(stdout);
1907 }
1908
1909 static void
1910 bprintf(fp, b, s)
1911 FILE *fp;
1912 int b;
1913 u_char *s;
1914 {
1915 int i;
1916 int gotsome = 0;
1917
1918 if (b == 0)
1919 return;
1920 while ((i = *s++) != 0) {
1921 if (b & (1 << (i-1))) {
1922 if (gotsome == 0)
1923 i = '<';
1924 else
1925 i = ',';
1926 (void) putc(i, fp);
1927 gotsome = 1;
1928 for (; (i = *s) > 32; s++)
1929 (void) putc(i, fp);
1930 } else
1931 while (*s > 32)
1932 s++;
1933 }
1934 if (gotsome)
1935 (void) putc('>', fp);
1936 }
1937
1938 static int
1939 keyword(cp)
1940 char *cp;
1941 {
1942 struct keytab *kt = keywords;
1943
1944 while (kt->kt_cp && strcmp(kt->kt_cp, cp))
1945 kt++;
1946 return kt->kt_i;
1947 }
1948
1949 static void
1950 sodump(su, which)
1951 sup su;
1952 char *which;
1953 {
1954 #ifdef INET6
1955 char ntop_buf[NI_MAXHOST];
1956 #endif
1957
1958 switch (su->sa.sa_family) {
1959 case AF_INET:
1960 (void) printf("%s: inet %s; ",
1961 which, inet_ntoa(su->sin.sin_addr));
1962 break;
1963 case AF_APPLETALK:
1964 (void) printf("%s: atalk %d.%d; ",
1965 which, su->sat.sat_addr.s_net, su->sat.sat_addr.s_node);
1966 break;
1967 case AF_LINK:
1968 (void) printf("%s: link %s; ",
1969 which, link_ntoa(&su->sdl));
1970 break;
1971 #ifndef SMALL
1972 #ifdef INET6
1973 case AF_INET6:
1974 (void) printf("%s: inet6 %s; ",
1975 which, inet_ntop(AF_INET6, &su->sin6.sin6_addr,
1976 ntop_buf, sizeof(ntop_buf)));
1977 break;
1978 #endif
1979 case AF_ISO:
1980 (void) printf("%s: iso %s; ",
1981 which, iso_ntoa(&su->siso.siso_addr));
1982 break;
1983 case AF_NS:
1984 (void) printf("%s: xns %s; ",
1985 which, ns_ntoa(su->sns.sns_addr));
1986 break;
1987 #endif /* SMALL */
1988 default:
1989 (void) printf("af %p: %s; ",
1990 which, any_ntoa(&su->sa));
1991 }
1992 (void) fflush(stdout);
1993 }
1994
1995 /* States*/
1996 #define VIRGIN 0
1997 #define GOTONE 1
1998 #define GOTTWO 2
1999 /* Inputs */
2000 #define DIGIT (4*0)
2001 #define END (4*1)
2002 #define DELIM (4*2)
2003
2004 static void
2005 sockaddr(addr, sa)
2006 char *addr;
2007 struct sockaddr *sa;
2008 {
2009 char *cp = (char *)sa;
2010 int size = sa->sa_len;
2011 char *cplim = cp + size;
2012 int byte = 0, state = VIRGIN, new = 0;
2013
2014 (void) memset(cp, 0, size);
2015 cp++;
2016 do {
2017 if ((*addr >= '0') && (*addr <= '9')) {
2018 new = *addr - '0';
2019 } else if ((*addr >= 'a') && (*addr <= 'f')) {
2020 new = *addr - 'a' + 10;
2021 } else if ((*addr >= 'A') && (*addr <= 'F')) {
2022 new = *addr - 'A' + 10;
2023 } else if (*addr == 0)
2024 state |= END;
2025 else
2026 state |= DELIM;
2027 addr++;
2028 switch (state /* | INPUT */) {
2029 case GOTTWO | DIGIT:
2030 *cp++ = byte; /*FALLTHROUGH*/
2031 case VIRGIN | DIGIT:
2032 state = GOTONE; byte = new; continue;
2033 case GOTONE | DIGIT:
2034 state = GOTTWO; byte = new + (byte << 4); continue;
2035 default: /* | DELIM */
2036 state = VIRGIN; *cp++ = byte; byte = 0; continue;
2037 case GOTONE | END:
2038 case GOTTWO | END:
2039 *cp++ = byte; /* FALLTHROUGH */
2040 case VIRGIN | END:
2041 break;
2042 }
2043 break;
2044 } while (cp < cplim);
2045 sa->sa_len = cp - (char *)sa;
2046 }
2047