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