Sync some manuals from bin & sbin with NetBSD-8
[minix.git] / sbin / route / route.c
blob71addfa4f3fa0d88f063003546efdd11a8d9042a
1 /* $NetBSD: route.c,v 1.151 2015/03/23 18:33:17 roy Exp $ */
3 /*
4 * Copyright (c) 1983, 1989, 1991, 1993
5 * The Regents of the University of California. All rights reserved.
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. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __COPYRIGHT("@(#) Copyright (c) 1983, 1989, 1991, 1993\
35 The Regents of the University of California. All rights reserved.");
36 #endif /* not lint */
38 #ifndef lint
39 #if 0
40 static char sccsid[] = "@(#)route.c 8.6 (Berkeley) 4/28/95";
41 #else
42 __RCSID("$NetBSD: route.c,v 1.151 2015/03/23 18:33:17 roy Exp $");
43 #endif
44 #endif /* not lint */
46 #include <sys/param.h>
47 #include <sys/file.h>
48 #include <sys/socket.h>
49 #include <sys/ioctl.h>
50 #include <sys/mbuf.h>
51 #include <sys/sysctl.h>
53 #include <net/if.h>
54 #include <net/route.h>
55 #include <net/if_dl.h>
56 #include <net80211/ieee80211_netbsd.h>
57 #include <netinet/in.h>
58 #include <netatalk/at.h>
59 #include <netmpls/mpls.h>
60 #include <arpa/inet.h>
61 #include <netdb.h>
63 #include <errno.h>
64 #include <unistd.h>
65 #include <stdio.h>
66 #include <ctype.h>
67 #include <stdlib.h>
68 #include <string.h>
69 #include <time.h>
70 #include <paths.h>
71 #include <err.h>
73 #include "keywords.h"
74 #include "extern.h"
75 #include "prog_ops.h"
76 #include "rtutil.h"
78 union sockunion {
79 struct sockaddr sa;
80 struct sockaddr_in sin;
81 #ifdef INET6
82 struct sockaddr_in6 sin6;
83 #endif
84 struct sockaddr_at sat;
85 struct sockaddr_dl sdl;
86 #ifndef SMALL
87 struct sockaddr_mpls smpls;
88 #endif /* SMALL */
89 struct sockaddr_storage sstorage;
92 typedef union sockunion *sup;
94 struct sou {
95 union sockunion *so_dst, *so_gate, *so_mask, *so_genmask, *so_ifa,
96 *so_ifp, *so_mpls;
99 static const char *route_strerror(int);
100 static void set_metric(const char *, int);
101 static int newroute(int, char *const *);
102 static void inet_makenetandmask(u_int32_t, struct sockaddr_in *, struct sou *);
103 #ifdef INET6
104 static int inet6_makenetandmask(const struct sockaddr_in6 *, struct sou *);
105 #endif
106 static int getaddr(int, const char *, struct hostent **, struct sou *);
107 static int flushroutes(int, char *const [], int);
108 static char *netmask_string(const struct sockaddr *, int, int);
109 static int prefixlen(const char *, struct sou *);
110 #ifndef SMALL
111 static void interfaces(void);
112 __dead static void monitor(void);
113 static int print_getmsg(struct rt_msghdr *, int, struct sou *);
114 static const char *linkstate(struct if_msghdr *);
115 static sup readtag(sup, const char *);
116 static void addtag(sup, const char *, int);
117 #endif /* SMALL */
118 static int rtmsg(int, int, struct sou *);
119 static void mask_addr(struct sou *);
120 static void print_rtmsg(struct rt_msghdr *, int);
121 static void pmsg_common(struct rt_msghdr *);
122 static void pmsg_addrs(const char *, int);
123 static void bprintf(FILE *, int, const char *);
124 static void sodump(sup, const char *);
125 static void sockaddr(const char *, struct sockaddr *);
127 int pid, rtm_addrs;
128 int sock;
129 int forcehost, forcenet, doflush, af;
130 int iflag, Lflag, nflag, qflag, tflag, Sflag, Tflag;
131 int verbose, aflen = sizeof(struct sockaddr_in), rtag;
132 int locking, lockrest, debugonly, shortoutput;
133 struct rt_metrics rt_metrics;
134 int rtm_inits;
135 short ns_nullh[] = {0,0,0};
136 short ns_bh[] = {-1,-1,-1};
138 static const char opts[] = "dfLnqSsTtv";
140 void
141 usage(const char *cp)
144 if (cp)
145 warnx("botched keyword: %s", cp);
146 (void)fprintf(stderr,
147 "Usage: %s [-%s] cmd [[-<qualifers>] args]\n", getprogname(), opts);
148 exit(1);
149 /* NOTREACHED */
152 #define PRIETHER "02x:%02x:%02x:%02x:%02x:%02x"
153 #define PRIETHER_ARGS(__enaddr) (__enaddr)[0], (__enaddr)[1], (__enaddr)[2], \
154 (__enaddr)[3], (__enaddr)[4], (__enaddr)[5]
157 main(int argc, char * const *argv)
159 int ch;
161 if (argc < 2)
162 usage(NULL);
164 while ((ch = getopt(argc, argv, opts)) != -1)
165 switch (ch) {
166 case 'd':
167 debugonly = 1;
168 break;
169 case 'f':
170 doflush = 1;
171 break;
172 case 'L':
173 Lflag = RT_LFLAG;
174 break;
175 case 'n':
176 nflag = RT_NFLAG;
177 break;
178 case 'q':
179 qflag = 1;
180 break;
181 case 'S':
182 Sflag = 1;
183 break;
184 case 's':
185 shortoutput = 1;
186 break;
187 case 'T':
188 Tflag = RT_TFLAG;
189 break;
190 case 't':
191 tflag = 1;
192 break;
193 case 'v':
194 verbose = RT_VFLAG;
195 break;
196 case '?':
197 default:
198 usage(NULL);
199 /*NOTREACHED*/
201 argc -= optind;
202 argv += optind;
204 if (prog_init && prog_init() == -1)
205 err(1, "init failed");
207 pid = prog_getpid();
208 if (tflag)
209 sock = prog_open("/dev/null", O_WRONLY, 0);
210 else
211 sock = prog_socket(PF_ROUTE, SOCK_RAW, 0);
212 if (sock < 0)
213 err(EXIT_FAILURE, "socket");
215 if (*argv == NULL) {
216 if (doflush)
217 ch = K_FLUSH;
218 else
219 goto no_cmd;
220 } else
221 ch = keyword(*argv);
223 switch (ch) {
224 #ifndef SMALL
225 case K_GET:
226 #endif /* SMALL */
227 case K_CHANGE:
228 case K_ADD:
229 case K_DELETE:
230 if (doflush)
231 (void)flushroutes(1, argv, 0);
232 return newroute(argc, argv);
234 case K_SHOW:
235 show(argc, argv, Lflag|nflag|Tflag|verbose);
236 return 0;
238 #ifndef SMALL
239 case K_MONITOR:
240 monitor();
241 return 0;
243 #endif /* SMALL */
244 case K_FLUSH:
245 return flushroutes(argc, argv, 0);
247 case K_FLUSHALL:
248 return flushroutes(argc, argv, 1);
249 no_cmd:
250 default:
251 usage(*argv);
252 /*NOTREACHED*/
256 static char *
257 netmask_string(const struct sockaddr *mask, int len, int family)
259 static char smask[INET6_ADDRSTRLEN];
260 struct sockaddr_in nsin;
261 struct sockaddr_in6 nsin6;
263 if (len >= 0)
264 snprintf(smask, sizeof(smask), "%d", len);
265 else {
266 switch (family) {
267 case AF_INET:
268 memset(&nsin, 0, sizeof(nsin));
269 memcpy(&nsin, mask, mask->sa_len);
270 snprintf(smask, sizeof(smask), "%s",
271 inet_ntoa(nsin.sin_addr));
272 break;
273 case AF_INET6:
274 memset(&nsin6, 0, sizeof(nsin6));
275 memcpy(&nsin6, mask, mask->sa_len);
276 inet_ntop(family, &nsin6.sin6_addr, smask,
277 sizeof(smask));
278 break;
279 default:
280 snprintf(smask, sizeof(smask), "%s", any_ntoa(mask));
284 return smask;
287 * Purge all entries in the routing tables not
288 * associated with network interfaces.
290 static int
291 flushroutes(int argc, char * const argv[], int doall)
293 struct sockaddr *sa;
294 size_t needed;
295 int flags, mib[6], rlen, seqno;
296 char *buf, *next, *lim;
297 const char *afname;
298 struct rt_msghdr *rtm;
300 flags = 0;
301 af = AF_UNSPEC;
302 /* Don't want to read back our messages */
303 prog_shutdown(sock, SHUT_RD);
304 parse_show_opts(argc, argv, &af, &flags, &afname, false);
305 mib[0] = CTL_NET;
306 mib[1] = PF_ROUTE;
307 mib[2] = 0; /* protocol */
308 mib[3] = 0; /* wildcard address family */
309 mib[4] = NET_RT_DUMP;
310 mib[5] = 0; /* no flags */
311 if (prog_sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
312 err(EXIT_FAILURE, "route-sysctl-estimate");
313 buf = lim = NULL;
314 if (needed) {
315 if ((buf = malloc(needed)) == NULL)
316 err(EXIT_FAILURE, "malloc");
317 if (prog_sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
318 err(EXIT_FAILURE, "actual retrieval of routing table");
319 lim = buf + needed;
321 if (verbose) {
322 (void)printf("Examining routing table from sysctl\n");
323 if (af != AF_UNSPEC)
324 printf("(address family %s)\n", afname);
326 if (needed == 0)
327 return 0;
328 seqno = 0; /* ??? */
329 for (next = buf; next < lim; next += rtm->rtm_msglen) {
330 rtm = (struct rt_msghdr *)next;
331 sa = (struct sockaddr *)(rtm + 1);
332 if (verbose)
333 print_rtmsg(rtm, rtm->rtm_msglen);
334 if ((rtm->rtm_flags & flags) != flags)
335 continue;
336 if (!(rtm->rtm_flags & (RTF_GATEWAY | RTF_STATIC |
337 RTF_LLINFO)) && !doall)
338 continue;
339 #if defined(__minix)
341 * MINIX3 only: routes with the RTF_LOCAL flag are immutable,
342 * so do not try to delete them.
344 if (rtm->rtm_flags & RTF_LOCAL)
345 continue;
346 #endif /* defined(__minix) */
347 if (af != AF_UNSPEC && sa->sa_family != af)
348 continue;
349 if (debugonly)
350 continue;
351 rtm->rtm_type = RTM_DELETE;
352 rtm->rtm_seq = seqno;
353 if ((rlen = prog_write(sock, next,
354 rtm->rtm_msglen)) < 0) {
355 warnx("writing to routing socket: %s",
356 route_strerror(errno));
357 return 1;
359 if (rlen < (int)rtm->rtm_msglen) {
360 warnx("write to routing socket, got %d for rlen", rlen);
361 return 1;
363 seqno++;
364 if (qflag)
365 continue;
366 if (verbose)
367 print_rtmsg(rtm, rlen);
368 else {
369 (void)printf("%-20.20s ", netname(sa, NULL, nflag));
370 sa = (struct sockaddr *)(RT_ROUNDUP(sa->sa_len) +
371 (char *)sa);
372 (void)printf("%-20.20s ", routename(sa, nflag));
373 (void)printf("done\n");
376 free(buf);
377 return 0;
380 static const char *
381 route_strerror(int error)
384 switch (error) {
385 case ESRCH:
386 return "not in table";
387 case EBUSY:
388 return "entry in use";
389 case ENOBUFS:
390 return "routing table overflow";
391 default:
392 return strerror(error);
396 static void
397 set_metric(const char *value, int key)
399 int flag = 0;
400 uint64_t noval, *valp = &noval;
402 switch (key) {
403 #define caseof(x, y, z) \
404 case x: valp = (uint64_t *)&rt_metrics.z; flag = y; break
405 caseof(K_MTU, RTV_MTU, rmx_mtu);
406 caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount);
407 caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire);
408 caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe);
409 caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe);
410 caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh);
411 caseof(K_RTT, RTV_RTT, rmx_rtt);
412 caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar);
414 rtm_inits |= flag;
415 if (lockrest || locking)
416 rt_metrics.rmx_locks |= flag;
417 if (locking)
418 locking = 0;
419 *valp = strtoul(value, NULL, 0);
422 static int
423 newroute(int argc, char *const *argv)
425 const char *cmd, *dest = "", *gateway = "";
426 int ishost = 0, ret, attempts, oerrno, flags = RTF_STATIC;
427 int key;
428 struct hostent *hp = 0;
429 struct sou sou, *soup = &sou;
431 sou.so_dst = calloc(1, sizeof(union sockunion));
432 sou.so_gate = calloc(1, sizeof(union sockunion));
433 sou.so_mask = calloc(1, sizeof(union sockunion));
434 sou.so_genmask = calloc(1, sizeof(union sockunion));
435 sou.so_ifa = calloc(1, sizeof(union sockunion));
436 sou.so_ifp = calloc(1, sizeof(union sockunion));
437 sou.so_mpls = calloc(1, sizeof(union sockunion));
439 if (sou.so_dst == NULL || sou.so_gate == NULL || sou.so_mask == NULL ||
440 sou.so_genmask == NULL || sou.so_ifa == NULL || sou.so_ifp == NULL ||
441 sou.so_mpls == NULL)
442 errx(EXIT_FAILURE, "Cannot allocate memory");
444 cmd = argv[0];
445 af = AF_UNSPEC;
446 if (*cmd != 'g') {
447 /* Don't want to read back our messages */
448 prog_shutdown(sock, SHUT_RD);
450 while (--argc > 0) {
451 if (**(++argv)== '-') {
452 switch (key = keyword(1 + *argv)) {
454 case K_SA:
455 af = PF_ROUTE;
456 aflen = sizeof(union sockunion);
457 break;
459 #ifndef SMALL
460 case K_ATALK:
461 af = AF_APPLETALK;
462 aflen = sizeof(struct sockaddr_at);
463 break;
464 #endif
466 case K_INET:
467 af = AF_INET;
468 aflen = sizeof(struct sockaddr_in);
469 break;
471 #ifdef INET6
472 case K_INET6:
473 af = AF_INET6;
474 aflen = sizeof(struct sockaddr_in6);
475 break;
476 #endif
478 case K_LINK:
479 af = AF_LINK;
480 aflen = sizeof(struct sockaddr_dl);
481 break;
483 #ifndef SMALL
484 case K_MPLS:
485 af = AF_MPLS;
486 aflen = sizeof(struct sockaddr_mpls);
487 break;
488 case K_TAG:
489 if (!--argc)
490 usage(1+*argv);
491 af = AF_MPLS;
492 aflen = sizeof(struct sockaddr_mpls);
493 (void)getaddr(RTA_TAG, *++argv, 0, soup);
494 break;
495 #endif /* SMALL */
497 case K_IFACE:
498 case K_INTERFACE:
499 iflag++;
500 break;
501 case K_NOSTATIC:
502 flags &= ~RTF_STATIC;
503 break;
504 case K_LLINFO:
505 flags |= RTF_LLINFO;
506 break;
507 case K_LOCK:
508 locking = 1;
509 break;
510 case K_LOCKREST:
511 lockrest = 1;
512 break;
513 case K_HOST:
514 forcehost++;
515 break;
516 case K_REJECT:
517 flags |= RTF_REJECT;
518 break;
519 case K_NOREJECT:
520 flags &= ~RTF_REJECT;
521 break;
522 case K_BLACKHOLE:
523 flags |= RTF_BLACKHOLE;
524 break;
525 case K_NOBLACKHOLE:
526 flags &= ~RTF_BLACKHOLE;
527 break;
528 case K_CLONED:
529 flags |= RTF_CLONED;
530 break;
531 case K_NOCLONED:
532 flags &= ~RTF_CLONED;
533 break;
534 case K_PROTO1:
535 flags |= RTF_PROTO1;
536 break;
537 case K_PROTO2:
538 flags |= RTF_PROTO2;
539 break;
540 case K_PROXY:
541 flags |= RTF_ANNOUNCE;
542 break;
543 case K_CLONING:
544 flags |= RTF_CLONING;
545 break;
546 case K_NOCLONING:
547 flags &= ~RTF_CLONING;
548 break;
549 case K_XRESOLVE:
550 flags |= RTF_XRESOLVE;
551 break;
552 case K_STATIC:
553 flags |= RTF_STATIC;
554 break;
555 case K_IFA:
556 if (!--argc)
557 usage(1+*argv);
558 (void)getaddr(RTA_IFA, *++argv, 0, soup);
559 break;
560 case K_IFP:
561 if (!--argc)
562 usage(1+*argv);
563 (void)getaddr(RTA_IFP, *++argv, 0, soup);
564 break;
565 case K_GENMASK:
566 if (!--argc)
567 usage(1+*argv);
568 (void)getaddr(RTA_GENMASK, *++argv, 0, soup);
569 break;
570 case K_GATEWAY:
571 if (!--argc)
572 usage(1+*argv);
573 (void)getaddr(RTA_GATEWAY, *++argv, 0, soup);
574 break;
575 case K_DST:
576 if (!--argc)
577 usage(1+*argv);
578 ishost = getaddr(RTA_DST, *++argv, &hp, soup);
579 dest = *argv;
580 break;
581 case K_NETMASK:
582 if (!--argc)
583 usage(1+*argv);
584 (void)getaddr(RTA_NETMASK, *++argv, 0, soup);
585 /* FALLTHROUGH */
586 case K_NET:
587 forcenet++;
588 break;
589 case K_PREFIXLEN:
590 if (!--argc)
591 usage(1+*argv);
592 ishost = prefixlen(*++argv, soup);
593 break;
594 case K_MTU:
595 case K_HOPCOUNT:
596 case K_EXPIRE:
597 case K_RECVPIPE:
598 case K_SENDPIPE:
599 case K_SSTHRESH:
600 case K_RTT:
601 case K_RTTVAR:
602 if (!--argc)
603 usage(1+*argv);
604 set_metric(*++argv, key);
605 break;
606 default:
607 usage(1+*argv);
609 } else {
610 if ((rtm_addrs & RTA_DST) == 0) {
611 dest = *argv;
612 ishost = getaddr(RTA_DST, *argv, &hp, soup);
613 } else if ((rtm_addrs & RTA_GATEWAY) == 0) {
614 gateway = *argv;
615 (void)getaddr(RTA_GATEWAY, *argv, &hp, soup);
616 } else {
617 ret = atoi(*argv);
619 if (ret == 0) {
620 if (strcmp(*argv, "0") == 0) {
621 if (!qflag) {
622 warnx("%s, %s",
623 "old usage of trailing 0",
624 "assuming route to if");
626 } else
627 usage(NULL);
628 iflag = 1;
629 continue;
630 } else if (ret > 0 && ret < 10) {
631 if (!qflag) {
632 warnx("%s, %s",
633 "old usage of trailing digit",
634 "assuming route via gateway");
636 iflag = 0;
637 continue;
639 (void)getaddr(RTA_NETMASK, *argv, 0, soup);
643 if ((rtm_addrs & RTA_DST) == 0)
644 errx(EXIT_FAILURE, "missing destination specification");
645 if (*cmd == 'a' && (rtm_addrs & RTA_GATEWAY) == 0)
646 errx(EXIT_FAILURE, "missing gateway specification");
647 if (forcehost && forcenet)
648 errx(EXIT_FAILURE, "-host and -net conflict");
649 else if (forcehost)
650 ishost = 1;
651 else if (forcenet)
652 ishost = 0;
653 flags |= RTF_UP;
654 if (ishost)
655 flags |= RTF_HOST;
656 if (iflag == 0)
657 flags |= RTF_GATEWAY;
658 for (attempts = 1; ; attempts++) {
659 errno = 0;
660 if ((ret = rtmsg(*cmd, flags, soup)) == 0)
661 break;
662 if (errno != ENETUNREACH && errno != ESRCH)
663 break;
664 if (af == AF_INET && *gateway && hp && hp->h_addr_list[1]) {
665 hp->h_addr_list++;
666 memmove(&soup->so_gate->sin.sin_addr, hp->h_addr_list[0],
667 hp->h_length);
668 } else
669 break;
671 if (*cmd == 'g')
672 return ret != 0;
673 if (!qflag) {
674 oerrno = errno;
675 (void)printf("%s %s %s", cmd, ishost? "host" : "net", dest);
676 if (*gateway) {
677 (void)printf(": gateway %s", gateway);
678 if (attempts > 1 && ret == 0 && af == AF_INET)
679 (void)printf(" (%s)",
680 inet_ntoa(soup->so_gate->sin.sin_addr));
682 if (ret == 0)
683 (void)printf("\n");
684 else
685 (void)printf(": %s\n", route_strerror(oerrno));
687 free(sou.so_dst);
688 free(sou.so_gate);
689 free(sou.so_mask);
690 free(sou.so_genmask);
691 free(sou.so_ifa);
692 free(sou.so_ifp);
693 free(sou.so_mpls);
695 return ret != 0;
698 static void
699 inet_makenetandmask(const u_int32_t net, struct sockaddr_in * const isin,
700 struct sou *soup)
702 struct sockaddr_in *sin;
703 u_int32_t addr, mask = 0;
704 char *cp;
706 rtm_addrs |= RTA_NETMASK;
707 if (net == 0)
708 mask = addr = 0;
709 else if (net < 128) {
710 addr = net << IN_CLASSA_NSHIFT;
711 mask = IN_CLASSA_NET;
712 } else if (net < 192) {
713 addr = net << IN_CLASSA_NSHIFT;
714 mask = IN_CLASSB_NET;
715 } else if (net < 224) {
716 addr = net << IN_CLASSA_NSHIFT;
717 mask = IN_CLASSC_NET;
718 } else if (net < 256) {
719 addr = net << IN_CLASSA_NSHIFT;
720 mask = IN_CLASSD_NET;
721 } else if (net < 49152) { /* 192 * 256 */
722 addr = net << IN_CLASSB_NSHIFT;
723 mask = IN_CLASSB_NET;
724 } else if (net < 57344) { /* 224 * 256 */
725 addr = net << IN_CLASSB_NSHIFT;
726 mask = IN_CLASSC_NET;
727 } else if (net < 65536) {
728 addr = net << IN_CLASSB_NSHIFT;
729 mask = IN_CLASSB_NET;
730 } else if (net < 14680064L) { /* 224 * 65536 */
731 addr = net << IN_CLASSC_NSHIFT;
732 mask = IN_CLASSC_NET;
733 } else if (net < 16777216L) {
734 addr = net << IN_CLASSC_NSHIFT;
735 mask = IN_CLASSD_NET;
736 } else {
737 addr = net;
738 if ((addr & IN_CLASSA_HOST) == 0)
739 mask = IN_CLASSA_NET;
740 else if ((addr & IN_CLASSB_HOST) == 0)
741 mask = IN_CLASSB_NET;
742 else if ((addr & IN_CLASSC_HOST) == 0)
743 mask = IN_CLASSC_NET;
744 else
745 mask = -1;
747 isin->sin_addr.s_addr = htonl(addr);
748 sin = &soup->so_mask->sin;
749 sin->sin_addr.s_addr = htonl(mask);
750 sin->sin_len = 0;
751 sin->sin_family = 0;
752 cp = (char *)(&sin->sin_addr + 1);
753 while (*--cp == 0 && cp > (char *)sin)
755 sin->sin_len = 1 + cp - (char *)sin;
756 sin->sin_family = AF_INET;
759 #ifdef INET6
761 * XXX the function may need more improvement...
763 static int
764 inet6_makenetandmask(const struct sockaddr_in6 * const sin6, struct sou *soup)
766 const char *plen;
767 struct in6_addr in6;
769 plen = NULL;
770 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
771 sin6->sin6_scope_id == 0) {
772 plen = "0";
773 } else if ((sin6->sin6_addr.s6_addr[0] & 0xe0) == 0x20) {
774 /* aggregatable global unicast - RFC2374 */
775 memset(&in6, 0, sizeof(in6));
776 if (!memcmp(&sin6->sin6_addr.s6_addr[8], &in6.s6_addr[8], 8))
777 plen = "64";
780 if (!plen || strcmp(plen, "128") == 0)
781 return 1;
782 else {
783 rtm_addrs |= RTA_NETMASK;
784 (void)prefixlen(plen, soup);
785 return 0;
788 #endif
791 * Interpret an argument as a network address of some kind,
792 * returning 1 if a host address, 0 if a network address.
794 static int
795 getaddr(int which, const char *s, struct hostent **hpp, struct sou *soup)
797 sup su;
798 struct hostent *hp;
799 struct netent *np;
800 u_int32_t val;
801 char *t;
802 int afamily; /* local copy of af so we can change it */
804 if (af == AF_UNSPEC) {
805 af = AF_INET;
806 aflen = sizeof(struct sockaddr_in);
808 afamily = af;
809 rtm_addrs |= which;
810 switch (which) {
811 case RTA_DST:
812 su = soup->so_dst;
813 break;
814 case RTA_GATEWAY:
815 su = soup->so_gate;
816 break;
817 case RTA_NETMASK:
818 su = soup->so_mask;
819 break;
820 case RTA_GENMASK:
821 su = soup->so_genmask;
822 break;
823 case RTA_IFP:
824 su = soup->so_ifp;
825 afamily = AF_LINK;
826 break;
827 case RTA_IFA:
828 su = soup->so_ifa;
829 su->sa.sa_family = af;
830 break;
831 #ifndef SMALL
832 case RTA_TAG:
833 su = soup->so_mpls;
834 afamily = AF_MPLS;
835 break;
836 #endif
837 default:
838 su = NULL;
839 usage("Internal Error");
840 /*NOTREACHED*/
842 su->sa.sa_len = aflen;
843 su->sa.sa_family = afamily; /* cases that don't want it have left already */
844 if (strcmp(s, "default") == 0) {
845 switch (which) {
846 case RTA_DST:
847 forcenet++;
848 (void)getaddr(RTA_NETMASK, s, 0, soup);
849 break;
850 case RTA_NETMASK:
851 case RTA_GENMASK:
852 su->sa.sa_len = 0;
854 return 0;
856 switch (afamily) {
857 #ifdef INET6
858 case AF_INET6:
860 struct addrinfo hints, *res;
861 char *slash = 0;
863 if (which == RTA_DST && (slash = (strrchr(s, '/'))) != 0)
864 *slash = '\0';
865 memset(&hints, 0, sizeof(hints));
866 hints.ai_family = afamily; /*AF_INET6*/
867 hints.ai_flags = AI_NUMERICHOST;
868 hints.ai_socktype = SOCK_DGRAM; /*dummy*/
869 if (getaddrinfo(s, "0", &hints, &res) != 0) {
870 hints.ai_flags = 0;
871 if (slash) {
872 *slash = '/';
873 slash = 0;
875 if (getaddrinfo(s, "0", &hints, &res) != 0)
876 errx(EXIT_FAILURE, "%s: bad value", s);
878 if (slash)
879 *slash = '/';
880 if (sizeof(su->sin6) != res->ai_addrlen)
881 errx(EXIT_FAILURE, "%s: bad value", s);
882 if (res->ai_next) {
883 errx(EXIT_FAILURE,
884 "%s: address resolved to multiple values", s);
886 memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6));
887 freeaddrinfo(res);
888 inet6_putscopeid(&su->sin6, INET6_IS_ADDR_LINKLOCAL|
889 INET6_IS_ADDR_MC_LINKLOCAL);
890 if (hints.ai_flags == AI_NUMERICHOST) {
891 if (slash)
892 return prefixlen(slash + 1, soup);
893 if (which == RTA_DST)
894 return inet6_makenetandmask(&su->sin6, soup);
895 return 0;
896 } else
897 return 1;
899 #endif
901 case PF_ROUTE:
902 su->sa.sa_len = sizeof(*su);
903 sockaddr(s, &su->sa);
904 return 1;
906 #ifndef SMALL
907 case AF_APPLETALK:
908 t = strchr (s, '.');
909 if (!t) {
910 badataddr:
911 errx(EXIT_FAILURE, "bad address: %s", s);
913 val = atoi (s);
914 if (val > 65535)
915 goto badataddr;
916 su->sat.sat_addr.s_net = val;
917 val = atoi (t);
918 if (val > 256)
919 goto badataddr;
920 su->sat.sat_addr.s_node = val;
921 rtm_addrs |= RTA_NETMASK;
922 return(forcehost || su->sat.sat_addr.s_node != 0);
923 case AF_MPLS:
924 if (which == RTA_DST)
925 soup->so_dst = readtag(su, s);
926 else if (which == RTA_TAG)
927 soup->so_mpls = readtag(su, s);
928 else
929 errx(EXIT_FAILURE, "MPLS can be used only as "
930 "DST or TAG");
931 return 1;
932 #endif
934 case AF_LINK:
935 link_addr(s, &su->sdl);
936 return 1;
938 case AF_INET:
939 default:
940 break;
943 if (hpp == NULL)
944 hpp = &hp;
945 *hpp = NULL;
947 if ((t = strchr(s, '/')) != NULL && which == RTA_DST) {
948 *t = '\0';
949 if (forcenet == 0) {
950 if ((val = inet_addr(s)) != INADDR_NONE) {
951 inet_makenetandmask(htonl(val), &su->sin, soup);
952 return prefixlen(&t[1], soup);
954 } else {
955 if ((val = inet_network(s)) != INADDR_NONE) {
956 inet_makenetandmask(val, &su->sin, soup);
957 return prefixlen(&t[1], soup);
960 *t = '/';
962 if (inet_aton(s, &su->sin.sin_addr) &&
963 (which != RTA_DST || forcenet == 0)) {
964 val = su->sin.sin_addr.s_addr;
965 if (inet_lnaof(su->sin.sin_addr) != INADDR_ANY)
966 return 1;
967 else {
968 val = ntohl(val);
969 goto netdone;
972 if ((val = inet_network(s)) != INADDR_NONE ||
973 ((np = getnetbyname(s)) != NULL && (val = np->n_net) != 0)) {
974 netdone:
975 if (which == RTA_DST)
976 inet_makenetandmask(val, &su->sin, soup);
977 return 0;
979 hp = gethostbyname(s);
980 if (hp) {
981 *hpp = hp;
982 su->sin.sin_family = hp->h_addrtype;
983 memmove(&su->sin.sin_addr, hp->h_addr, hp->h_length);
984 return 1;
986 errx(EXIT_FAILURE, "%s: bad value", s);
987 /*NOTREACHED*/
990 #ifndef SMALL
991 static sup
992 readtag(sup su, const char *s)
994 char *p, *n, *norig;
995 int mplssize = 0;
996 sup retsu = su;
998 n = strdup(s);
999 if (n == NULL)
1000 errx(EXIT_FAILURE, "%s: Cannot allocate memory", s);
1001 norig = n;
1002 for (uint i = 0; i < strlen(n); i++)
1003 if(n[i] == ',')
1004 mplssize++;
1006 #define MPLS_NEW_SIZE (sizeof(struct sockaddr_mpls) + \
1007 mplssize * sizeof(union mpls_shim))
1009 if (mplssize != 0 && sizeof(union sockunion) < MPLS_NEW_SIZE) {
1010 free(su);
1011 retsu = malloc(MPLS_NEW_SIZE);
1012 retsu->smpls.smpls_family = AF_MPLS;
1014 retsu->smpls.smpls_len = MPLS_NEW_SIZE;
1015 mplssize = 0;
1016 while ((p = strchr(n, ',')) != NULL) {
1017 p[0] = '\0';
1018 addtag(retsu, n, mplssize);
1019 n = p + 1;
1020 mplssize++;
1022 addtag(retsu, n, mplssize);
1024 free(norig);
1025 return retsu;
1028 static void
1029 addtag(sup su, const char *s, int where)
1031 union mpls_shim *ms = &su->smpls.smpls_addr;
1033 if (atoi(s) < 0 || atoi(s) >= (1 << 20))
1034 errx(EXIT_FAILURE, "%s: Bad tag", s);
1035 ms[where].s_addr = 0;
1036 ms[where].shim.label = atoi(s);
1037 ms[where].s_addr = htonl(ms[where].s_addr);
1039 #endif /* SMALL */
1042 prefixlen(const char *s, struct sou *soup)
1044 int max, len = atoi(s);
1045 #ifdef INET6
1046 int q, r;
1047 #endif
1049 switch (af) {
1050 case AF_INET:
1051 max = sizeof(struct in_addr) * 8;
1052 break;
1053 #ifdef INET6
1054 case AF_INET6:
1055 max = sizeof(struct in6_addr) * 8;
1056 break;
1057 #endif
1058 default:
1059 errx(EXIT_FAILURE, "prefixlen is not supported with af %d", af);
1060 /*NOTREACHED*/
1063 rtm_addrs |= RTA_NETMASK;
1064 if (len < -1 || len > max)
1065 errx(EXIT_FAILURE, "%s: bad value", s);
1067 #ifdef INET6
1068 q = len >> 3;
1069 r = len & 7;
1070 #endif
1071 switch (af) {
1072 case AF_INET:
1073 memset(soup->so_mask, 0, sizeof(*soup->so_mask));
1074 soup->so_mask->sin.sin_family = AF_INET;
1075 soup->so_mask->sin.sin_len = sizeof(struct sockaddr_in);
1076 soup->so_mask->sin.sin_addr.s_addr = (len == 0 ? 0
1077 : htonl(0xffffffff << (32 - len)));
1078 break;
1079 #ifdef INET6
1080 case AF_INET6:
1081 soup->so_mask->sin6.sin6_family = AF_INET6;
1082 soup->so_mask->sin6.sin6_len = sizeof(struct sockaddr_in6);
1083 memset(&soup->so_mask->sin6.sin6_addr, 0,
1084 sizeof(soup->so_mask->sin6.sin6_addr));
1085 if (q > 0)
1086 memset(&soup->so_mask->sin6.sin6_addr, 0xff, q);
1087 if (r > 0)
1088 *((u_char *)&soup->so_mask->sin6.sin6_addr + q) =
1089 (0xff00 >> r) & 0xff;
1090 break;
1091 #endif
1093 return len == max;
1096 #ifndef SMALL
1097 static void
1098 interfaces(void)
1100 size_t needed;
1101 int mib[6];
1102 char *buf, *lim, *next;
1103 struct rt_msghdr *rtm;
1105 mib[0] = CTL_NET;
1106 mib[1] = PF_ROUTE;
1107 mib[2] = 0; /* protocol */
1108 mib[3] = 0; /* wildcard address family */
1109 mib[4] = NET_RT_IFLIST;
1110 mib[5] = 0; /* no flags */
1111 if (prog_sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
1112 err(EXIT_FAILURE, "route-sysctl-estimate");
1113 if (needed) {
1114 if ((buf = malloc(needed)) == NULL)
1115 err(EXIT_FAILURE, "malloc");
1116 if (prog_sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
1117 err(EXIT_FAILURE,
1118 "actual retrieval of interface table");
1120 lim = buf + needed;
1121 for (next = buf; next < lim; next += rtm->rtm_msglen) {
1122 rtm = (struct rt_msghdr *)next;
1123 print_rtmsg(rtm, rtm->rtm_msglen);
1125 free(buf);
1129 static void
1130 monitor(void)
1132 int n;
1133 union {
1134 char msg[2048];
1135 struct rt_msghdr hdr;
1136 } u;
1138 verbose = 1;
1139 if (debugonly) {
1140 interfaces();
1141 exit(0);
1143 for(;;) {
1144 time_t now;
1145 n = prog_read(sock, &u, sizeof(u));
1146 now = time(NULL);
1147 (void)printf("got message of size %d on %s", n, ctime(&now));
1148 print_rtmsg(&u.hdr, n);
1152 #endif /* SMALL */
1155 struct {
1156 struct rt_msghdr m_rtm;
1157 char m_space[512];
1158 } m_rtmsg;
1160 static int
1161 rtmsg(int cmd, int flags, struct sou *soup)
1163 static int seq;
1164 int rlen;
1165 char *cp = m_rtmsg.m_space;
1166 int l;
1168 #define NEXTADDR(w, u) \
1169 if (rtm_addrs & (w)) {\
1170 l = RT_ROUNDUP(u->sa.sa_len); memmove(cp, u, l); cp += l;\
1171 if (verbose && ! shortoutput) sodump(u,#u);\
1174 errno = 0;
1175 memset(&m_rtmsg, 0, sizeof(m_rtmsg));
1176 if (cmd == 'a')
1177 cmd = RTM_ADD;
1178 else if (cmd == 'c')
1179 cmd = RTM_CHANGE;
1180 else if (cmd == 'g') {
1181 #ifdef SMALL
1182 return -1;
1183 #else /* SMALL */
1184 cmd = RTM_GET;
1185 if (soup->so_ifp->sa.sa_family == AF_UNSPEC) {
1186 soup->so_ifp->sa.sa_family = AF_LINK;
1187 soup->so_ifp->sa.sa_len = sizeof(struct sockaddr_dl);
1188 rtm_addrs |= RTA_IFP;
1190 #endif /* SMALL */
1191 } else
1192 cmd = RTM_DELETE;
1193 #define rtm m_rtmsg.m_rtm
1194 rtm.rtm_type = cmd;
1195 rtm.rtm_flags = flags;
1196 rtm.rtm_version = RTM_VERSION;
1197 rtm.rtm_seq = ++seq;
1198 rtm.rtm_addrs = rtm_addrs;
1199 rtm.rtm_rmx = rt_metrics;
1200 rtm.rtm_inits = rtm_inits;
1202 if (rtm_addrs & RTA_NETMASK)
1203 mask_addr(soup);
1204 NEXTADDR(RTA_DST, soup->so_dst);
1205 NEXTADDR(RTA_GATEWAY, soup->so_gate);
1206 NEXTADDR(RTA_NETMASK, soup->so_mask);
1207 NEXTADDR(RTA_GENMASK, soup->so_genmask);
1208 NEXTADDR(RTA_IFP, soup->so_ifp);
1209 NEXTADDR(RTA_IFA, soup->so_ifa);
1210 #ifndef SMALL
1211 NEXTADDR(RTA_TAG, soup->so_mpls);
1212 #endif
1213 rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
1214 if (verbose && ! shortoutput) {
1215 if (rtm_addrs)
1216 putchar('\n');
1217 print_rtmsg(&rtm, l);
1219 if (debugonly)
1220 return 0;
1221 if ((rlen = prog_write(sock, (char *)&m_rtmsg, l)) < 0) {
1222 warnx("writing to routing socket: %s", route_strerror(errno));
1223 return -1;
1225 if (rlen < l) {
1226 warnx("write to routing socket, got %d for rlen", rlen);
1227 return 1;
1229 #ifndef SMALL
1230 if (cmd == RTM_GET) {
1231 do {
1232 l = prog_read(sock,
1233 (char *)&m_rtmsg, sizeof(m_rtmsg));
1234 } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
1235 if (l < 0)
1236 err(EXIT_FAILURE, "read from routing socket");
1237 else
1238 return print_getmsg(&rtm, l, soup);
1240 #endif /* SMALL */
1241 #undef rtm
1242 return 0;
1245 static void
1246 mask_addr(struct sou *soup)
1248 int olen = soup->so_mask->sa.sa_len;
1249 char *cp1 = olen + (char *)soup->so_mask, *cp2;
1251 for (soup->so_mask->sa.sa_len = 0; cp1 > (char *)soup->so_mask; )
1252 if (*--cp1 != 0) {
1253 soup->so_mask->sa.sa_len = 1 + cp1 - (char *)soup->so_mask;
1254 break;
1256 if ((rtm_addrs & RTA_DST) == 0)
1257 return;
1258 switch (soup->so_dst->sa.sa_family) {
1259 case AF_INET:
1260 #ifdef INET6
1261 case AF_INET6:
1262 #endif
1263 #ifndef SMALL
1264 case AF_APPLETALK:
1265 #endif /* SMALL */
1266 case 0:
1267 return;
1269 cp1 = soup->so_mask->sa.sa_len + 1 + (char *)soup->so_dst;
1270 cp2 = soup->so_dst->sa.sa_len + 1 + (char *)soup->so_dst;
1271 while (cp2 > cp1)
1272 *--cp2 = 0;
1273 cp2 = soup->so_mask->sa.sa_len + 1 + (char *)soup->so_mask;
1274 while (cp1 > soup->so_dst->sa.sa_data)
1275 *--cp1 &= *--cp2;
1278 const char * const msgtypes[] = {
1279 [RTM_ADD] = "RTM_ADD: Add Route",
1280 [RTM_DELETE] = "RTM_DELETE: Delete Route",
1281 [RTM_CHANGE] = "RTM_CHANGE: Change Metrics, Flags or Gateway",
1282 [RTM_GET] = "RTM_GET: Report Metrics",
1283 [RTM_LOSING] = "RTM_LOSING: Kernel Suspects Partitioning",
1284 [RTM_REDIRECT] = "RTM_REDIRECT: Told to use different route",
1285 [RTM_MISS] = "RTM_MISS: Lookup failed on this address",
1286 [RTM_LOCK] = "RTM_LOCK: fix specified metrics",
1287 [RTM_OLDADD] = "RTM_OLDADD: caused by SIOCADDRT",
1288 [RTM_OLDDEL] = "RTM_OLDDEL: caused by SIOCDELRT",
1289 [RTM_RESOLVE] = "RTM_RESOLVE: Route created by cloning",
1290 [RTM_NEWADDR] = "RTM_NEWADDR: address being added to iface",
1291 [RTM_DELADDR] = "RTM_DELADDR: address being removed from iface",
1292 [RTM_OOIFINFO] = "RTM_OOIFINFO: iface status change (pre-1.5)",
1293 [RTM_OIFINFO] = "RTM_OIFINFO: iface status change (pre-64bit time)",
1294 [RTM_IFANNOUNCE] = "RTM_IFANNOUNCE: iface arrival/departure",
1295 [RTM_IEEE80211] = "RTM_IEEE80211: IEEE80211 wireless event",
1296 [RTM_IFINFO] = "RTM_IFINFO: iface status change",
1297 [RTM_CHGADDR] = "RTM_CHGADDR: address being changed on iface",
1300 const char metricnames[] =
1301 "\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount\1mtu";
1302 const char routeflags[] =
1303 "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE\016CLONED\017PROTO2\020PROTO1\023LOCAL\024BROADCAST";
1304 const char ifnetflags[] =
1305 "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6NOTRAILERS\7RUNNING\010NOARP\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1\017LINK2\020MULTICAST";
1306 const char addrnames[] =
1307 "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD\011TAG";
1310 #ifndef SMALL
1311 static const char *
1312 linkstate(struct if_msghdr *ifm)
1314 static char buf[64];
1316 switch (ifm->ifm_data.ifi_link_state) {
1317 case LINK_STATE_UNKNOWN:
1318 return "carrier: unknown";
1319 case LINK_STATE_DOWN:
1320 return "carrier: no carrier";
1321 case LINK_STATE_UP:
1322 return "carrier: active";
1323 default:
1324 (void)snprintf(buf, sizeof(buf), "carrier: 0x%x",
1325 ifm->ifm_data.ifi_link_state);
1326 return buf;
1329 #endif /* SMALL */
1331 static void
1332 print_rtmsg(struct rt_msghdr *rtm, int msglen)
1334 struct if_msghdr *ifm;
1335 struct ifa_msghdr *ifam;
1336 struct if_announcemsghdr *ifan;
1337 union {
1338 struct ieee80211_join_event join;
1339 struct ieee80211_leave_event leave;
1340 struct ieee80211_replay_event replay;
1341 struct ieee80211_michael_event michael;
1342 } ev;
1343 size_t evlen = 0;
1345 if (verbose == 0)
1346 return;
1347 if (rtm->rtm_version != RTM_VERSION) {
1348 (void)printf("routing message version %d not understood\n",
1349 rtm->rtm_version);
1350 return;
1352 if (msgtypes[rtm->rtm_type])
1353 (void)printf("%s: ", msgtypes[rtm->rtm_type]);
1354 else
1355 (void)printf("#%d: ", rtm->rtm_type);
1356 (void)printf("len %d, ", rtm->rtm_msglen);
1357 switch (rtm->rtm_type) {
1358 case RTM_IFINFO:
1359 ifm = (struct if_msghdr *)rtm;
1360 (void)printf("if# %d, %s, flags: ", ifm->ifm_index,
1361 #ifdef SMALL
1363 #else
1364 linkstate(ifm)
1365 #endif /* SMALL */
1367 bprintf(stdout, ifm->ifm_flags, ifnetflags);
1368 pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs);
1369 break;
1370 case RTM_NEWADDR:
1371 case RTM_DELADDR:
1372 case RTM_CHGADDR:
1373 ifam = (struct ifa_msghdr *)rtm;
1374 (void)printf("metric %d, flags: ", ifam->ifam_metric);
1375 bprintf(stdout, ifam->ifam_flags, routeflags);
1376 pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs);
1377 break;
1378 case RTM_IEEE80211:
1379 ifan = (struct if_announcemsghdr *)rtm;
1380 (void)printf("if# %d, what: ", ifan->ifan_index);
1381 switch (ifan->ifan_what) {
1382 case RTM_IEEE80211_ASSOC:
1383 printf("associate");
1384 break;
1385 case RTM_IEEE80211_REASSOC:
1386 printf("re-associate");
1387 break;
1388 case RTM_IEEE80211_DISASSOC:
1389 printf("disassociate");
1390 break;
1391 case RTM_IEEE80211_SCAN:
1392 printf("scan complete");
1393 break;
1394 case RTM_IEEE80211_JOIN:
1395 evlen = sizeof(ev.join);
1396 printf("join");
1397 break;
1398 case RTM_IEEE80211_LEAVE:
1399 evlen = sizeof(ev.leave);
1400 printf("leave");
1401 break;
1402 case RTM_IEEE80211_MICHAEL:
1403 evlen = sizeof(ev.michael);
1404 printf("michael");
1405 break;
1406 case RTM_IEEE80211_REPLAY:
1407 evlen = sizeof(ev.replay);
1408 printf("replay");
1409 break;
1410 default:
1411 evlen = 0;
1412 printf("#%d", ifan->ifan_what);
1413 break;
1415 if (sizeof(*ifan) + evlen > ifan->ifan_msglen) {
1416 printf(" (truncated)\n");
1417 break;
1419 (void)memcpy(&ev, (ifan + 1), evlen);
1420 switch (ifan->ifan_what) {
1421 case RTM_IEEE80211_JOIN:
1422 case RTM_IEEE80211_LEAVE:
1423 printf(" mac %" PRIETHER,
1424 PRIETHER_ARGS(ev.join.iev_addr));
1425 break;
1426 case RTM_IEEE80211_REPLAY:
1427 case RTM_IEEE80211_MICHAEL:
1428 printf(" src %" PRIETHER " dst %" PRIETHER
1429 " cipher %" PRIu8 " keyix %" PRIu8,
1430 PRIETHER_ARGS(ev.replay.iev_src),
1431 PRIETHER_ARGS(ev.replay.iev_dst),
1432 ev.replay.iev_cipher,
1433 ev.replay.iev_keyix);
1434 if (ifan->ifan_what == RTM_IEEE80211_REPLAY) {
1435 printf(" key rsc %#" PRIx64
1436 " frame rsc %#" PRIx64,
1437 ev.replay.iev_keyrsc, ev.replay.iev_rsc);
1439 break;
1440 default:
1441 break;
1443 printf("\n");
1444 break;
1445 case RTM_IFANNOUNCE:
1446 ifan = (struct if_announcemsghdr *)rtm;
1447 (void)printf("if# %d, what: ", ifan->ifan_index);
1448 switch (ifan->ifan_what) {
1449 case IFAN_ARRIVAL:
1450 printf("arrival");
1451 break;
1452 case IFAN_DEPARTURE:
1453 printf("departure");
1454 break;
1455 default:
1456 printf("#%d", ifan->ifan_what);
1457 break;
1459 printf("\n");
1460 break;
1461 default:
1462 (void)printf("pid %d, seq %d, errno %d, flags: ",
1463 rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno);
1464 bprintf(stdout, rtm->rtm_flags, routeflags);
1465 pmsg_common(rtm);
1469 #ifndef SMALL
1470 static int
1471 print_getmsg(struct rt_msghdr *rtm, int msglen, struct sou *soup)
1473 struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL, *ifa = NULL, *mpls = NULL;
1474 struct sockaddr_dl *ifp = NULL;
1475 struct sockaddr *sa;
1476 char *cp;
1477 int i;
1479 if (! shortoutput) {
1480 (void)printf(" route to: %s\n",
1481 routename(&soup->so_dst->sa, nflag));
1483 if (rtm->rtm_version != RTM_VERSION) {
1484 warnx("routing message version %d not understood",
1485 rtm->rtm_version);
1486 return 1;
1488 if (rtm->rtm_msglen > msglen) {
1489 warnx("message length mismatch, in packet %d, returned %d",
1490 rtm->rtm_msglen, msglen);
1492 if (rtm->rtm_errno) {
1493 warnx("RTM_GET: %s (errno %d)",
1494 strerror(rtm->rtm_errno), rtm->rtm_errno);
1495 return 1;
1497 cp = ((char *)(rtm + 1));
1498 if (rtm->rtm_addrs)
1499 for (i = 1; i; i <<= 1)
1500 if (i & rtm->rtm_addrs) {
1501 sa = (struct sockaddr *)cp;
1502 switch (i) {
1503 case RTA_DST:
1504 dst = sa;
1505 break;
1506 case RTA_GATEWAY:
1507 gate = sa;
1508 break;
1509 case RTA_NETMASK:
1510 mask = sa;
1511 break;
1512 case RTA_IFP:
1513 if (sa->sa_family == AF_LINK &&
1514 ((struct sockaddr_dl *)sa)->sdl_nlen)
1515 ifp = (struct sockaddr_dl *)sa;
1516 break;
1517 case RTA_IFA:
1518 ifa = sa;
1519 break;
1520 case RTA_TAG:
1521 mpls = sa;
1522 break;
1524 RT_ADVANCE(cp, sa);
1526 if (dst && mask)
1527 mask->sa_family = dst->sa_family; /* XXX */
1528 if (dst && ! shortoutput)
1529 (void)printf("destination: %s\n",
1530 routename(dst, nflag));
1531 if (mask && ! shortoutput) {
1532 int savenflag = nflag;
1534 nflag = RT_NFLAG;
1535 (void)printf(" mask: %s\n",
1536 routename(mask, nflag));
1537 nflag = savenflag;
1539 if (gate && rtm->rtm_flags & RTF_GATEWAY) {
1540 const char *name;
1542 name = routename(gate, nflag);
1543 if (shortoutput) {
1544 if (*name == '\0')
1545 return 1;
1546 (void)printf("%s\n", name);
1547 } else
1548 (void)printf(" gateway: %s\n", name);
1550 if (mpls) {
1551 const char *name;
1552 name = routename(mpls, nflag);
1553 if(shortoutput) {
1554 if (*name == '\0')
1555 return 1;
1556 printf("%s\n", name);
1557 } else
1558 printf(" Tag: %s\n", name);
1561 if (ifa && ! shortoutput)
1562 (void)printf(" local addr: %s\n",
1563 routename(ifa, nflag));
1564 if (ifp && ! shortoutput)
1565 (void)printf(" interface: %.*s\n",
1566 ifp->sdl_nlen, ifp->sdl_data);
1567 if (! shortoutput) {
1568 (void)printf(" flags: ");
1569 bprintf(stdout, rtm->rtm_flags, routeflags);
1572 #define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ')
1573 #define msec(u) (((u) + 500) / 1000) /* usec to msec */
1575 if (! shortoutput) {
1576 (void)printf("\n%s\n", "\
1577 recvpipe sendpipe ssthresh rtt,msec rttvar hopcount mtu expire");
1578 printf("%8"PRId64"%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE));
1579 printf("%8"PRId64"%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE));
1580 printf("%8"PRId64"%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH));
1581 printf("%8"PRId64"%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT));
1582 printf("%8"PRId64"%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR));
1583 printf("%8"PRId64"%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT));
1584 printf("%8"PRId64"%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU));
1585 if (rtm->rtm_rmx.rmx_expire)
1586 rtm->rtm_rmx.rmx_expire -= time(0);
1587 printf("%8"PRId64"%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE));
1589 #undef lock
1590 #undef msec
1591 #define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD)
1593 if (shortoutput)
1594 return (rtm->rtm_addrs & RTF_GATEWAY) == 0;
1595 else if (verbose)
1596 pmsg_common(rtm);
1597 else if (rtm->rtm_addrs &~ RTA_IGN) {
1598 (void)printf("sockaddrs: ");
1599 bprintf(stdout, rtm->rtm_addrs, addrnames);
1600 putchar('\n');
1602 return 0;
1603 #undef RTA_IGN
1605 #endif /* SMALL */
1607 void
1608 pmsg_common(struct rt_msghdr *rtm)
1610 (void)printf("\nlocks: ");
1611 bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames);
1612 (void)printf(" inits: ");
1613 bprintf(stdout, rtm->rtm_inits, metricnames);
1614 pmsg_addrs((char *)(rtm + 1), rtm->rtm_addrs);
1617 static void
1618 extract_addrs(const char *cp, int addrs, const struct sockaddr *sa[], int *nmfp)
1620 int i, nmf = -1;
1622 for (i = 0; i < RTAX_MAX; i++) {
1623 if ((1 << i) & addrs) {
1624 sa[i] = (const struct sockaddr *)cp;
1625 if ((i == RTAX_DST || i == RTAX_IFA) &&
1626 nmf == -1)
1627 nmf = sa[i]->sa_family;
1628 RT_ADVANCE(cp, sa[i]);
1629 } else
1630 sa[i] = NULL;
1633 if (nmfp != NULL)
1634 *nmfp = nmf;
1637 static void
1638 pmsg_addrs(const char *cp, int addrs)
1640 const struct sockaddr *sa[RTAX_MAX];
1641 int i, nmf;
1643 if (addrs != 0) {
1644 (void)printf("\nsockaddrs: ");
1645 bprintf(stdout, addrs, addrnames);
1646 (void)putchar('\n');
1647 extract_addrs(cp, addrs, sa, &nmf);
1648 for (i = 0; i < RTAX_MAX; i++) {
1649 if (sa[i] == NULL)
1650 continue;
1652 if (i == RTAX_NETMASK && sa[i]->sa_len)
1653 (void)printf(" %s",
1654 netmask_string(sa[i], -1, nmf));
1655 else
1656 (void)printf(" %s",
1657 routename(sa[i], nflag));
1660 (void)putchar('\n');
1661 (void)fflush(stdout);
1664 static void
1665 bprintf(FILE *fp, int b, const char *f)
1667 int i;
1668 int gotsome = 0;
1669 const uint8_t *s = (const uint8_t *)f;
1671 if (b == 0) {
1672 fputs("none", fp);
1673 return;
1675 while ((i = *s++) != 0) {
1676 if (b & (1 << (i-1))) {
1677 if (gotsome == 0)
1678 i = '<';
1679 else
1680 i = ',';
1681 (void)putc(i, fp);
1682 gotsome = 1;
1683 for (; (i = *s) > 32; s++)
1684 (void)putc(i, fp);
1685 } else
1686 while (*s > 32)
1687 s++;
1689 if (gotsome)
1690 (void)putc('>', fp);
1694 keyword(const char *cp)
1696 struct keytab *kt = keywords;
1698 while (kt->kt_cp && strcmp(kt->kt_cp, cp))
1699 kt++;
1700 return kt->kt_i;
1703 static void
1704 sodump(sup su, const char *which)
1706 #ifdef INET6
1707 char ntop_buf[NI_MAXHOST];
1708 #endif
1710 switch (su->sa.sa_family) {
1711 case AF_INET:
1712 (void)printf("%s: inet %s; ",
1713 which, inet_ntoa(su->sin.sin_addr));
1714 break;
1715 #ifndef SMALL
1716 case AF_APPLETALK:
1717 (void)printf("%s: atalk %d.%d; ",
1718 which, su->sat.sat_addr.s_net, su->sat.sat_addr.s_node);
1719 break;
1720 #endif
1721 case AF_LINK:
1722 (void)printf("%s: link %s; ",
1723 which, link_ntoa(&su->sdl));
1724 break;
1725 #ifdef INET6
1726 case AF_INET6:
1727 (void)printf("%s: inet6 %s; ",
1728 which, inet_ntop(AF_INET6, &su->sin6.sin6_addr,
1729 ntop_buf, sizeof(ntop_buf)));
1730 break;
1731 #endif
1732 #ifndef SMALL
1733 case AF_MPLS:
1735 union mpls_shim ms;
1736 const union mpls_shim *pms;
1737 int psize = sizeof(struct sockaddr_mpls);
1739 ms.s_addr = ntohl(su->smpls.smpls_addr.s_addr);
1740 printf("%s: mpls %u; ",
1741 which, ms.shim.label);
1743 pms = &su->smpls.smpls_addr;
1744 while(psize < su->smpls.smpls_len) {
1745 pms++;
1746 ms.s_addr = ntohl(pms->s_addr);
1747 printf("%u; ", ms.shim.label);
1748 psize += sizeof(ms);
1750 break;
1752 #endif /* SMALL */
1753 default:
1754 (void)printf("%s: (%d) %s; ",
1755 which, su->sa.sa_family, any_ntoa(&su->sa));
1757 (void)fflush(stdout);
1760 /* States*/
1761 #define VIRGIN 0
1762 #define GOTONE 1
1763 #define GOTTWO 2
1764 /* Inputs */
1765 #define DIGIT (4*0)
1766 #define END (4*1)
1767 #define DELIM (4*2)
1769 static void
1770 sockaddr(const char *addr, struct sockaddr *sa)
1772 char *cp = (char *)sa;
1773 int size = sa->sa_len;
1774 char *cplim = cp + size;
1775 int byte = 0, state = VIRGIN, new = 0;
1777 (void)memset(cp, 0, size);
1778 cp++;
1779 do {
1780 if ((*addr >= '0') && (*addr <= '9')) {
1781 new = *addr - '0';
1782 } else if ((*addr >= 'a') && (*addr <= 'f')) {
1783 new = *addr - 'a' + 10;
1784 } else if ((*addr >= 'A') && (*addr <= 'F')) {
1785 new = *addr - 'A' + 10;
1786 } else if (*addr == 0)
1787 state |= END;
1788 else
1789 state |= DELIM;
1790 addr++;
1791 switch (state /* | INPUT */) {
1792 case GOTTWO | DIGIT:
1793 *cp++ = byte; /*FALLTHROUGH*/
1794 case VIRGIN | DIGIT:
1795 state = GOTONE; byte = new; continue;
1796 case GOTONE | DIGIT:
1797 state = GOTTWO; byte = new + (byte << 4); continue;
1798 default: /* | DELIM */
1799 state = VIRGIN; *cp++ = byte; byte = 0; continue;
1800 case GOTONE | END:
1801 case GOTTWO | END:
1802 *cp++ = byte; /* FALLTHROUGH */
1803 case VIRGIN | END:
1804 break;
1806 break;
1807 } while (cp < cplim);
1808 sa->sa_len = cp - (char *)sa;