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