Bug Summary

File:src/sbin/route/route.c
Warning:line 496, column 12
Although the value stored to 'key' is used in the enclosing expression, the value is never actually read from 'key'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name route.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sbin/route/obj -resource-dir /usr/local/llvm16/lib/clang/16 -D BFD -internal-isystem /usr/local/llvm16/lib/clang/16/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/sbin/route/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fno-jump-tables -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/scan/2024-01-11-140451-98009-1 -x c /usr/src/sbin/route/route.c
1/* $OpenBSD: route.c,v 1.265 2023/03/17 16:11:09 claudio Exp $ */
2/* $NetBSD: route.c,v 1.16 1996/04/15 18:27:05 cgd Exp $ */
3
4/*
5 * Copyright (c) 1983, 1989, 1991, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include <sys/socket.h>
34#include <sys/sysctl.h>
35
36#include <net/if.h>
37#include <net/if_dl.h>
38#include <net/if_media.h>
39#include <net/if_types.h>
40#include <net/route.h>
41#include <netinet/in.h>
42#include <netmpls/mpls.h>
43
44#ifdef BFD1
45#include <sys/time.h>
46#include <net/bfd.h>
47#endif
48
49#include <arpa/inet.h>
50#include <netdb.h>
51
52#include <ifaddrs.h>
53#include <errno(*__errno()).h>
54#include <fcntl.h>
55#include <unistd.h>
56#include <limits.h>
57#include <stdio.h>
58#include <ctype.h>
59#include <stddef.h>
60#include <stdlib.h>
61#include <string.h>
62#include <time.h>
63#include <paths.h>
64#include <err.h>
65
66#include "keywords.h"
67#include "show.h"
68
69const struct if_status_description
70 if_status_descriptions[] = LINK_STATE_DESCRIPTIONS{ { 0x06, 2, "no carrier" }, { 0x47, 2, "no network" }, { 0x17
, 2, "no carrier" }, { 0xf7, 2, "backup" }, { 0xf7, 4, "master"
}, { 0xf7, 5, "master" }, { 0xf7, 6, "master" }, { 0, 4, "active"
}, { 0, 5, "active" }, { 0, 6, "active" }, { 0, 0, "unknown"
}, { 0, 1, "invalid" }, { 0, 2, "down" }, { 0, 3, "keepalive down"
}, { 0, 0, ((void *)0) } }
;
71
72union sockunion so_dst, so_gate, so_mask, so_ifa, so_ifp, so_src, so_label,
73 so_source;
74
75typedef union sockunion *sup;
76pid_t pid;
77int rtm_addrs, s;
78int forcehost, forcenet, Fflag, nflag, qflag, tflag, Tflag;
79int iflag, verbose, aflen = sizeof(struct sockaddr_in);
80int locking, lockrest, debugonly;
81u_long mpls_flags = MPLS_OP_LOCAL0x0;
82u_long rtm_inits;
83uid_t uid;
84u_int tableid;
85
86struct rt_metrics rt_metrics;
87
88int flushroutes(int, char **);
89int newroute(int, char **);
90int setsource(int, char **);
91int pushsrc(int, char *, int);
92int show(int, char *[]);
93int keycmp(const void *, const void *);
94int keyword(char *);
95void monitor(int, char *[]);
96int nameserver(int, char **);
97int prefixlen(int, char *);
98void sockaddr(char *, struct sockaddr *);
99void sodump(sup, char *);
100char *priorityname(uint8_t);
101uint8_t getpriority(char *);
102void print_getmsg(struct rt_msghdr *, int);
103#ifdef BFD1
104const char *bfd_state(unsigned int);
105const char *bfd_diag(unsigned int);
106const char *bfd_calc_uptime(time_t);
107void print_bfdmsg(struct rt_msghdr *);
108void print_sabfd(struct sockaddr_bfd *, int);
109#endif
110const char *get_linkstate(int, int);
111void print_rtmsg(struct rt_msghdr *, int);
112void pmsg_common(struct rt_msghdr *);
113void pmsg_addrs(char *, int);
114void bprintf(FILE *, int, char *);
115int getaddr(int, int, char *, struct hostent **);
116void getmplslabel(char *, int);
117int rtmsg(int, int, int, uint8_t);
118__dead__attribute__((__noreturn__)) void usage(char *);
119void set_metric(char *, int);
120void inet_makenetandmask(u_int32_t, struct sockaddr_in *, int);
121void getlabel(char *);
122int gettable(const char *);
123int rdomain(int, char **);
124void print_rtdns(struct sockaddr_rtdns *);
125void print_rtstatic(struct sockaddr_rtstatic *);
126void print_rtsearch(struct sockaddr_rtsearch *);
127void print_80211info(struct if_ieee80211_msghdr *);
128
129__dead__attribute__((__noreturn__)) void
130usage(char *cp)
131{
132 extern char *__progname;
133
134 if (cp)
135 warnx("botched keyword: %s", cp);
136 fprintf(stderr(&__sF[2]),
137#ifndef SMALL
138 "usage: %s [-dnqtv] [-T rtable] command [[modifier ...] arg ...]\n",
139#else
140 "usage: %s [-dnqtv] command [[modifier ...] arg ...]\n",
141#endif
142 __progname);
143 exit(1);
144}
145
146#define ROUNDUP(a)((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof
(long))
\
147 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
148#define ADVANCE(x, n)(x += (((n)->sa_len) > 0 ? (1 + ((((n)->sa_len) - 1)
| (sizeof(long) - 1))) : sizeof(long)))
(x += ROUNDUP((n)->sa_len)(((n)->sa_len) > 0 ? (1 + ((((n)->sa_len) - 1) | (sizeof
(long) - 1))) : sizeof(long))
)
149
150int
151main(int argc, char **argv)
152{
153 unsigned int filter = 0;
154 int ch;
155 int rval = 0;
156 int kw;
157 int af = AF_UNSPEC0;
158#ifndef SMALL
159 int Terr = 0;
160 u_int rtable_any = RTABLE_ANY0xffffffff;
161#endif
162
163 if (argc < 2)
164 usage(NULL((void *)0));
165
166#ifndef SMALL
167 tableid = getrtable();
168#endif
169 while ((ch = getopt(argc, argv, "dnqtT:v")) != -1)
170 switch (ch) {
171 case 'n':
172 nflag = 1;
173 break;
174 case 'q':
175 qflag = 1;
176 break;
177 case 'v':
178 verbose = 1;
179 break;
180 case 't':
181 tflag = 1;
182 break;
183#ifndef SMALL
184 case 'T':
185 Terr = gettable(optarg);
186 Tflag = 1;
187 break;
188#endif
189 case 'd':
190 debugonly = 1;
191 break;
192 default:
193 usage(NULL((void *)0));
194 /* NOTREACHED */
195 }
196 argc -= optind;
197 argv += optind;
198
199 pid = getpid();
200 uid = geteuid();
201 if (*argv == NULL((void *)0))
202 usage(NULL((void *)0));
203
204 kw = keyword(*argv);
205#ifndef SMALL
206 if (Tflag && Terr != 0 && kw != K_ADD) {
207 errno(*__errno()) = Terr;
208 err(1, "routing table %u", tableid);
209 }
210 if (kw == K_EXEC)
211 exit(rdomain(argc - 1, argv + 1));
212#endif
213
214 if (kw == K_MONITOR) {
215 while (--argc > 0) {
216 if (**(++argv)== '-')
217 switch (keyword(*argv + 1)) {
218 case K_INET:
219 af = AF_INET2;
220 break;
221 case K_INET6:
222 af = AF_INET624;
223 break;
224 case K_MPLS:
225 af = AF_MPLS33;
226 break;
227 case K_IFACE:
228 case K_INTERFACE:
229 filter = ROUTE_FILTER(RTM_IFINFO)(1 << (0xe)) |
230 ROUTE_FILTER(RTM_IFANNOUNCE)(1 << (0xf)) |
231 ROUTE_FILTER(RTM_80211INFO)(1 << (0x15));
232 break;
233 default:
234 usage(*argv);
235 /* NOTREACHED */
236 }
237 else
238 usage(*argv);
239 }
240 }
241
242 if (tflag)
243 s = open(_PATH_DEVNULL"/dev/null", O_WRONLY0x0001);
244 else
245 s = socket(AF_ROUTE17, SOCK_RAW3, af);
246 if (s == -1)
247 err(1, "socket");
248
249 if (filter != 0) {
250 if (setsockopt(s, AF_ROUTE17, ROUTE_MSGFILTER1, &filter,
251 sizeof(filter)) == -1)
252 err(1, "setsockopt(ROUTE_MSGFILTER)");
253 }
254
255#ifndef SMALL
256 if (!tflag) {
257 /* force socket onto table user requested */
258 if (Tflag == 1 && Terr == 0) {
259 if (setsockopt(s, AF_ROUTE17, ROUTE_TABLEFILTER2,
260 &tableid, sizeof(tableid)) == -1)
261 err(1, "setsockopt(ROUTE_TABLEFILTER)");
262 } else {
263 if (setsockopt(s, AF_ROUTE17, ROUTE_TABLEFILTER2,
264 &rtable_any, sizeof(tableid)) == -1)
265 err(1, "setsockopt(ROUTE_TABLEFILTER)");
266 }
267 }
268#endif
269
270 if (pledge("stdio dns route", NULL((void *)0)) == -1)
271 err(1, "pledge");
272
273 switch (kw) {
274 case K_SHOW:
275 uid = 0;
276 exit(show(argc, argv));
277 break;
278 case K_FLUSH:
279 exit(flushroutes(argc, argv));
280 break;
281 case K_SOURCEADDR:
282 nflag = 1;
283 exit(setsource(argc, argv));
284 break;
285 }
286
287 if (pledge("stdio dns", NULL((void *)0)) == -1)
288 err(1, "pledge");
289
290 switch (kw) {
291 case K_GET:
292 uid = 0;
293 /* FALLTHROUGH */
294 case K_CHANGE:
295 case K_ADD:
296 case K_DEL:
297 case K_DELETE:
298 rval = newroute(argc, argv);
299 break;
300 case K_MONITOR:
301 monitor(argc, argv);
302 break;
303 case K_NAMESERVER:
304 rval = nameserver(argc, argv);
305 break;
306 default:
307 usage(*argv);
308 /* NOTREACHED */
309 }
310 exit(rval);
311}
312
313/*
314 * Purge all entries in the routing tables not
315 * associated with network interfaces.
316 */
317int
318flushroutes(int argc, char **argv)
319{
320 size_t needed;
321 int mib[7], mcnt, rlen, seqno, af = AF_UNSPEC0;
322 char *buf = NULL((void *)0), *next, *lim = NULL((void *)0);
323 struct rt_msghdr *rtm;
324 struct sockaddr *sa;
325 uint8_t prio = 0;
326 unsigned int ifindex = 0;
327
328 if (uid)
329 errx(1, "must be root to alter routing table");
330 shutdown(s, SHUT_RD0); /* Don't want to read back our messages */
331 while (--argc > 0) {
332 if (**(++argv) == '-')
333 switch (keyword(*argv + 1)) {
334 case K_INET:
335 af = AF_INET2;
336 break;
337 case K_INET6:
338 af = AF_INET624;
339 break;
340 case K_LINK:
341 af = AF_LINK18;
342 break;
343 case K_MPLS:
344 af = AF_MPLS33;
345 break;
346 case K_IFACE:
347 case K_INTERFACE:
348 if (!--argc)
349 usage(1+*argv);
350 ifindex = if_nametoindex(*++argv);
351 if (ifindex == 0)
352 errx(1, "no such interface %s", *argv);
353 break;
354 case K_PRIORITY:
355 if (!--argc)
356 usage(1+*argv);
357 prio = getpriority(*++argv);
358 break;
359 default:
360 usage(*argv);
361 /* NOTREACHED */
362 }
363 else
364 usage(*argv);
365 }
366 mib[0] = CTL_NET4;
367 mib[1] = PF_ROUTE17;
368 mib[2] = 0; /* protocol */
369 mib[3] = af;
370 mib[4] = NET_RT_DUMP1;
371 mib[5] = prio;
372 mib[6] = tableid;
373 mcnt = 7;
374
375 needed = get_sysctl(mib, mcnt, &buf);
376 lim = buf + needed;
377
378 if (pledge("stdio dns", NULL((void *)0)) == -1)
379 err(1, "pledge");
380
381 if (verbose) {
382 printf("Examining routing table from sysctl\n");
383 if (af)
384 printf("(address family %s)\n", (*argv + 1));
385 }
386 if (buf == NULL((void *)0))
387 return (1);
388
389 seqno = 0;
390 for (next = buf; next < lim; next += rtm->rtm_msglen) {
391 rtm = (struct rt_msghdr *)next;
392 if (rtm->rtm_version != RTM_VERSION5)
393 continue;
394 if (verbose)
395 print_rtmsg(rtm, rtm->rtm_msglen);
396 if ((rtm->rtm_flags & (RTF_GATEWAY0x2|RTF_STATIC0x800|RTF_LLINFO0x400)) == 0)
397 continue;
398 if ((rtm->rtm_flags & (RTF_LOCAL0x200000|RTF_BROADCAST0x400000)) != 0)
399 continue;
400 sa = (struct sockaddr *)(next + rtm->rtm_hdrlen);
401 if (ifindex && rtm->rtm_index != ifindex)
402 continue;
403 if (sa->sa_family == AF_KEY30)
404 continue; /* Don't flush SPD */
405 if (debugonly)
406 continue;
407 rtm->rtm_type = RTM_DELETE0x2;
408 rtm->rtm_seq = seqno;
409 rtm->rtm_tableid = tableid;
410 rlen = write(s, next, rtm->rtm_msglen);
411 if (rlen < (int)rtm->rtm_msglen) {
412 warn("write to routing socket");
413 printf("got only %d for rlen\n", rlen);
414 break;
415 }
416 seqno++;
417 if (qflag)
418 continue;
419 if (verbose)
420 print_rtmsg(rtm, rlen);
421 else {
422 struct sockaddr *mask, *rti_info[RTAX_MAX15];
423
424 sa = (struct sockaddr *)(next + rtm->rtm_hdrlen);
425
426 get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
427
428 sa = rti_info[RTAX_DST0];
429 mask = rti_info[RTAX_NETMASK2];
430
431 p_sockaddr(sa, mask, rtm->rtm_flags, 20);
432 p_sockaddr(rti_info[RTAX_GATEWAY1], NULL((void *)0), RTF_HOST0x4, 20);
433 printf("done\n");
434 }
435 }
436 free(buf);
437 return (0);
438}
439
440void
441set_metric(char *value, int key)
442{
443 long long relative_expire;
444 const char *errstr;
445 int flag = 0;
446
447 switch (key) {
448 case K_MTU:
449 rt_metrics.rmx_mtu = strtonum(value, 0, UINT_MAX0xffffffffU, &errstr);
450 if (errstr)
451 errx(1, "set_metric mtu: %s is %s", value, errstr);
452 flag = RTV_MTU0x1;
453 break;
454 case K_EXPIRE:
455 relative_expire = strtonum(value, 0, INT_MAX0x7fffffff, &errstr);
456 if (errstr)
457 errx(1, "set_metric expire: %s is %s", value, errstr);
458 rt_metrics.rmx_expire = relative_expire ?
459 relative_expire + time(NULL((void *)0)) : 0;
460 flag = RTV_EXPIRE0x4;
461 break;
462 case K_HOPCOUNT:
463 case K_RECVPIPE:
464 case K_SENDPIPE:
465 case K_SSTHRESH:
466 case K_RTT:
467 case K_RTTVAR:
468 /* no longer used, only for compatibility */
469 return;
470 default:
471 errx(1, "king bula sez: set_metric with invalid key");
472 }
473 rtm_inits |= flag;
474 if (lockrest || locking)
475 rt_metrics.rmx_locks |= flag;
476 if (locking)
477 locking = 0;
478}
479
480
481int
482setsource(int argc, char **argv)
483{
484 struct ifaddrs *ifap, *ifa = NULL((void *)0);
485 char *cmd;
486 int af = AF_UNSPEC0, ret = 0, key;
487 unsigned int ifindex = 0;
488
489 cmd = argv[0];
490
491 if (argc == 1)
492 printsource(AF_UNSPEC0, tableid);
493
494 while (--argc > 0) {
495 if (**(++argv)== '-') {
496 switch (key = keyword(1 + *argv)) {
Although the value stored to 'key' is used in the enclosing expression, the value is never actually read from 'key'
497 case K_INET:
498 af = AF_INET2;
499 aflen = sizeof(struct sockaddr_in);
500 break;
501 case K_INET6:
502 af = AF_INET624;
503 aflen = sizeof(struct sockaddr_in6);
504 break;
505 case K_IFP:
506 if (!--argc)
507 usage(1+*argv);
508 ifindex = if_nametoindex(*++argv);
509 if (ifindex == 0)
510 errx(1, "no such interface %s", *argv);
511 break;
512 default:
513 usage(NULL((void *)0));
514 }
515 } else
516 break;
517 }
518
519 if (!(argc == 1 && ifindex == 0) && !(argc == 0 && ifindex != 0))
520 usage(NULL((void *)0));
521
522 if (uid)
523 errx(1, "must be root to alter source address");
524
525 if (ifindex) {
526 if (getifaddrs(&ifap) == -1)
527 err(1, "getifaddrs");
528 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
529 if (if_nametoindex(ifa->ifa_name) != ifindex)
530 continue;
531 if (ifa->ifa_addr == NULL((void *)0) ||
532 !(ifa->ifa_addr->sa_family == AF_INET2 ||
533 ifa->ifa_addr->sa_family == AF_INET624))
534 continue;
535 if ((af != AF_UNSPEC0) &&
536 (ifa->ifa_addr->sa_family != af))
537 continue;
538 if (ifa->ifa_addr->sa_family == AF_INET624) {
539 struct sockaddr_in6 *sin6 =
540 (struct sockaddr_in6 *)ifa->ifa_addr;
541 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)(((&sin6->sin6_addr)->__u6_addr.__u6_addr8[0] == 0xfe
) && (((&sin6->sin6_addr)->__u6_addr.__u6_addr8
[1] & 0xc0) == 0x80))
||
542 IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)((&sin6->sin6_addr)->__u6_addr.__u6_addr8[0] == 0xff
)
)
543 continue;
544 }
545 if (pushsrc(*cmd, routename(ifa->ifa_addr),
546 ifa->ifa_addr->sa_family))
547 break;
548 }
549 freeifaddrs(ifap);
550 } else {
551 ret = pushsrc(*cmd, *argv, af);
552 }
553
554 return (ret != 0);
555}
556
557int
558pushsrc(int cmd, char *src, int af)
559{
560 int ret = 0;
561
562 getaddr(RTA_IFA0x20, af, src, NULL((void *)0));
563
564 errno(*__errno()) = 0;
565 ret = rtmsg(cmd, 0, 0, 0);
566 if (!qflag && ret != 0)
567 printf("sourceaddr %s: %s\n", src, strerror(errno(*__errno())));
568
569 return (ret);
570}
571int
572newroute(int argc, char **argv)
573{
574 char *cmd, *dest = "", *gateway = "", *error;
575 int ishost = 0, ret = 0, attempts, oerrno, flags = RTF_STATIC0x800;
576 int fmask = 0, af = AF_UNSPEC0;
577 int key;
578 uint8_t prio = 0;
579 struct hostent *hp = NULL((void *)0);
580 int sawdest = 0;
581
582 if (uid)
583 errx(1, "must be root to alter routing table");
584 cmd = argv[0];
585 if (*cmd != 'g')
586 shutdown(s, SHUT_RD0); /* Don't want to read back our messages */
587 while (--argc > 0) {
588 if (**(++argv) == '-') {
589 switch (key = keyword(1 + *argv)) {
590 case K_LINK:
591 af = AF_LINK18;
592 aflen = sizeof(struct sockaddr_dl);
593 break;
594 case K_INET:
595 af = AF_INET2;
596 aflen = sizeof(struct sockaddr_in);
597 break;
598 case K_INET6:
599 af = AF_INET624;
600 aflen = sizeof(struct sockaddr_in6);
601 break;
602 case K_SA:
603 af = PF_ROUTE17;
604 aflen = sizeof(struct sockaddr_storage) - 1;
605 break;
606 case K_MPLS:
607 af = AF_MPLS33;
608 aflen = sizeof(struct sockaddr_mpls);
609 fmask |= RTF_MPLS0x100000;
610 break;
611 case K_MPLSLABEL:
612 if (!--argc)
613 usage(1+*argv);
614 if (af != AF_INET2 && af != AF_INET624)
615 errx(1, "-mplslabel requires "
616 "-inet or -inet6");
617 getmplslabel(*++argv, 0);
618 mpls_flags = MPLS_OP_PUSH0x2;
619 flags |= RTF_MPLS0x100000;
620 break;
621 case K_IN:
622 if (!--argc)
623 usage(1+*argv);
624 if (af != AF_MPLS33)
625 errx(1, "-in requires -mpls");
626 getmplslabel(*++argv, 1);
627 break;
628 case K_OUT:
629 if (!--argc)
630 usage(1+*argv);
631 if (af != AF_MPLS33)
632 errx(1, "-out requires -mpls");
633 if (mpls_flags == MPLS_OP_LOCAL0x0)
634 errx(1, "-out requires -push, -pop, "
635 "-swap");
636 getmplslabel(*++argv, 0);
637 flags |= RTF_MPLS0x100000;
638 break;
639 case K_POP:
640 if (af != AF_MPLS33)
641 errx(1, "-pop requires -mpls");
642 mpls_flags = MPLS_OP_POP0x1;
643 break;
644 case K_PUSH:
645 if (af != AF_MPLS33)
646 errx(1, "-push requires -mpls");
647 mpls_flags = MPLS_OP_PUSH0x2;
648 break;
649 case K_SWAP:
650 if (af != AF_MPLS33)
651 errx(1, "-swap requires -mpls");
652 mpls_flags = MPLS_OP_SWAP0x4;
653 break;
654 case K_IFACE:
655 case K_INTERFACE:
656 iflag++;
657 break;
658 case K_NOSTATIC:
659 flags &= ~RTF_STATIC0x800;
660 break;
661 case K_LLINFO:
662 flags |= RTF_LLINFO0x400;
663 break;
664 case K_LOCK:
665 locking = 1;
666 break;
667 case K_LOCKREST:
668 lockrest = 1;
669 break;
670 case K_HOST:
671 forcehost++;
672 break;
673 case K_REJECT:
674 flags |= RTF_REJECT0x8;
675 break;
676 case K_BLACKHOLE:
677 flags |= RTF_BLACKHOLE0x1000;
678 break;
679 case K_PROTO1:
680 flags |= RTF_PROTO10x8000;
681 break;
682 case K_PROTO2:
683 flags |= RTF_PROTO20x4000;
684 break;
685 case K_CLONING:
686 flags |= RTF_CLONING0x100;
687 break;
688 case K_STATIC:
689 flags |= RTF_STATIC0x800;
690 break;
691 case K_IFA:
692 if (!--argc)
693 usage(1+*argv);
694 getaddr(RTA_IFA0x20, af, *++argv, NULL((void *)0));
695 break;
696 case K_IFP:
697 if (!--argc)
698 usage(1+*argv);
699 getaddr(RTA_IFP0x10, AF_LINK18, *++argv, NULL((void *)0));
700 break;
701 case K_GATEWAY:
702 if (!--argc)
703 usage(1+*argv);
704 getaddr(RTA_GATEWAY0x2, af, *++argv, NULL((void *)0));
705 gateway = *argv;
706 break;
707 case K_DST:
708 if (!--argc)
709 usage(1+*argv);
710 ishost = getaddr(RTA_DST0x1, af, *++argv, &hp);
711 dest = *argv;
712 sawdest = 1;
713 break;
714 case K_LABEL:
715 if (!--argc)
716 usage(1+*argv);
717 getlabel(*++argv);
718 break;
719 case K_NETMASK:
720 if (!sawdest)
721 errx(1, "-netmask must follow "
722 "destination parameter");
723 if (!--argc)
724 usage(1+*argv);
725 getaddr(RTA_NETMASK0x4, af, *++argv, NULL((void *)0));
726 /* FALLTHROUGH */
727 case K_NET:
728 forcenet++;
729 break;
730 case K_PREFIXLEN:
731 if (!sawdest)
732 errx(1, "-prefixlen must follow "
733 "destination parameter");
734 if (!--argc)
735 usage(1+*argv);
736 ishost = prefixlen(af, *++argv);
737 break;
738 case K_MPATH:
739 flags |= RTF_MPATH0x40000;
740 break;
741 case K_MTU:
742 case K_HOPCOUNT:
743 case K_EXPIRE:
744 case K_RECVPIPE:
745 case K_SENDPIPE:
746 case K_SSTHRESH:
747 case K_RTT:
748 case K_RTTVAR:
749 if (!--argc)
750 usage(1+*argv);
751 set_metric(*++argv, key);
752 break;
753 case K_PRIORITY:
754 if (!--argc)
755 usage(1+*argv);
756 prio = getpriority(*++argv);
757 break;
758 case K_BFD:
759 flags |= RTF_BFD0x1000000;
760 fmask |= RTF_BFD0x1000000;
761 break;
762 case K_NOBFD:
763 flags &= ~RTF_BFD0x1000000;
764 fmask |= RTF_BFD0x1000000;
765 break;
766 default:
767 usage(1+*argv);
768 /* NOTREACHED */
769 }
770 } else {
771 if ((rtm_addrs & RTA_DST0x1) == 0) {
772 dest = *argv;
773 sawdest = 1;
774 ishost = getaddr(RTA_DST0x1, af, *argv, &hp);
775 } else if ((rtm_addrs & RTA_GATEWAY0x2) == 0) {
776 gateway = *argv;
777 getaddr(RTA_GATEWAY0x2, af, *argv, &hp);
778 } else
779 usage(NULL((void *)0));
780 }
781 }
782 if (forcehost)
783 ishost = 1;
784 if (forcenet)
785 ishost = 0;
786 if (forcenet && !(rtm_addrs & RTA_NETMASK0x4))
787 errx(1, "netmask missing");
788 flags |= RTF_UP0x1;
789 if (ishost)
790 flags |= RTF_HOST0x4;
791 if (iflag == 0)
792 flags |= RTF_GATEWAY0x2;
793 for (attempts = 1; ; attempts++) {
794 errno(*__errno()) = 0;
795 if ((ret = rtmsg(*cmd, flags, fmask, prio)) == 0)
796 break;
797 if (errno(*__errno()) != ENETUNREACH51 && errno(*__errno()) != ESRCH3)
798 break;
799 if (af == AF_INET2 && *gateway && hp && hp->h_addr_list[1]) {
800 hp->h_addr_list++;
801 memcpy(&so_gate.sin.sin_addr, hp->h_addr_list[0],
802 hp->h_length);
803 } else
804 break;
805 }
806 oerrno = errno(*__errno());
807 if (!qflag && (*cmd != 'g' || ret != 0)) {
808 printf("%s %s %s", cmd, ishost ? "host" : "net", dest);
809 if (*gateway) {
810 printf(": gateway %s", gateway);
811 if (attempts > 1 && ret == 0 && af == AF_INET2)
812 printf(" (%s)", inet_ntoa(so_gate.sin.sin_addr));
813 }
814 if (ret == 0)
815 printf("\n");
816 if (ret != 0) {
817 switch (oerrno) {
818 case ESRCH3:
819 error = "not in table";
820 break;
821 case EBUSY16:
822 error = "entry in use";
823 break;
824 case ENOBUFS55:
825 error = "routing table overflow";
826 break;
827 default:
828 error = strerror(oerrno);
829 break;
830 }
831 printf(": %s\n", error);
832 }
833 }
834 return (ret != 0);
835}
836
837int
838show(int argc, char *argv[])
839{
840 int af = AF_UNSPEC0;
841 char prio = 0;
842
843 while (--argc > 0) {
844 if (**(++argv)== '-')
845 switch (keyword(*argv + 1)) {
846 case K_INET:
847 af = AF_INET2;
848 break;
849 case K_INET6:
850 af = AF_INET624;
851 break;
852 case K_LINK:
853 af = AF_LINK18;
854 break;
855 case K_MPLS:
856 af = AF_MPLS33;
857 break;
858 case K_GATEWAY:
859 Fflag = 1;
860 break;
861 case K_LABEL:
862 if (!--argc)
863 usage(1+*argv);
864 getlabel(*++argv);
865 break;
866 case K_PRIORITY:
867 if (!--argc)
868 usage(1+*argv);
869 prio = getpriority(*++argv);
870 break;
871 default:
872 usage(*argv);
873 /* NOTREACHED */
874 }
875 else
876 usage(*argv);
877 }
878
879 p_rttables(af, tableid, prio);
880 return (0);
881}
882
883void
884inet_makenetandmask(u_int32_t net, struct sockaddr_in *sin, int bits)
885{
886 u_int32_t mask;
887
888 rtm_addrs |= RTA_NETMASK0x4;
889 if (bits == 0 && net == 0)
890 mask = 0;
891 else {
892 if (bits == 0)
893 bits = 32;
894 mask = 0xffffffff << (32 - bits);
895 net &= mask;
896 }
897 sin->sin_addr.s_addr = htonl(net)(__uint32_t)(__builtin_constant_p(net) ? (__uint32_t)(((__uint32_t
)(net) & 0xff) << 24 | ((__uint32_t)(net) & 0xff00
) << 8 | ((__uint32_t)(net) & 0xff0000) >> 8 |
((__uint32_t)(net) & 0xff000000) >> 24) : __swap32md
(net))
;
898 sin = &so_mask.sin;
899 sin->sin_addr.s_addr = htonl(mask)(__uint32_t)(__builtin_constant_p(mask) ? (__uint32_t)(((__uint32_t
)(mask) & 0xff) << 24 | ((__uint32_t)(mask) & 0xff00
) << 8 | ((__uint32_t)(mask) & 0xff0000) >> 8
| ((__uint32_t)(mask) & 0xff000000) >> 24) : __swap32md
(mask))
;
900 sin->sin_family = AF_INET2;
901 sin->sin_len = sizeof(struct sockaddr_in);
902}
903
904/*
905 * Interpret an argument as a network address of some kind,
906 * returning 1 if a host address, 0 if a network address.
907 */
908int
909getaddr(int which, int af, char *s, struct hostent **hpp)
910{
911 sup su = NULL((void *)0);
912 struct hostent *hp;
913 int aflength, afamily, bits;
914
915 if (af == AF_UNSPEC0) {
916 if (strchr(s, ':') != NULL((void *)0)) {
917 af = AF_INET624;
918 aflen = sizeof(struct sockaddr_in6);
919 } else {
920 af = AF_INET2;
921 aflen = sizeof(struct sockaddr_in);
922 }
923 }
924 /* local copy of len and af so we can change it */
925 aflength = aflen;
926 afamily = af;
927
928 rtm_addrs |= which;
929 switch (which) {
930 case RTA_DST0x1:
931 su = &so_dst;
932 break;
933 case RTA_GATEWAY0x2:
934 su = &so_gate;
935 break;
936 case RTA_NETMASK0x4:
937 su = &so_mask;
938 break;
939 case RTA_IFP0x10:
940 su = &so_ifp;
941 aflength = sizeof(struct sockaddr_dl);
942 afamily = AF_LINK18;
943 break;
944 case RTA_IFA0x20:
945 su = &so_ifa;
946 break;
947 default:
948 errx(1, "internal error");
949 /* NOTREACHED */
950 }
951 memset(su, 0, sizeof(union sockunion));
952 su->sa.sa_len = aflength;
953 su->sa.sa_family = afamily;
954
955 if (strcmp(s, "default") == 0) {
956 switch (which) {
957 case RTA_DST0x1:
958 forcenet++;
959 getaddr(RTA_NETMASK0x4, af, s, NULL((void *)0));
960 break;
961 case RTA_NETMASK0x4:
962 su->sa.sa_len = 0;
963 }
964 return (0);
965 }
966
967 switch (afamily) {
968 case AF_INET624:
969 {
970 struct addrinfo hints, *res;
971 char buf[
972 sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255:255:255:255/128")
973 ];
974 char *sep;
975 int error;
976
977 if (strlcpy(buf, s, sizeof buf) >= sizeof buf) {
978 errx(1, "%s: bad value", s);
979 }
980
981 sep = strchr(buf, '/');
982 if (sep != NULL((void *)0))
983 *sep++ = '\0';
984 memset(&hints, 0, sizeof(hints));
985 hints.ai_family = afamily; /*AF_INET6*/
986 hints.ai_flags = AI_NUMERICHOST4;
987 hints.ai_socktype = SOCK_DGRAM2; /*dummy*/
988 error = getaddrinfo(buf, "0", &hints, &res);
989 if (error) {
990 hints.ai_flags = 0;
991 error = getaddrinfo(buf, "0", &hints, &res);
992 if (error)
993 errx(1, "%s: %s", s, gai_strerror(error));
994 }
995 if (res->ai_next)
996 errx(1, "%s: resolved to multiple values", s);
997 memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6));
998 freeaddrinfo(res);
999#ifdef __KAME__
1000 if ((IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr)(((&su->sin6.sin6_addr)->__u6_addr.__u6_addr8[0] ==
0xfe) && (((&su->sin6.sin6_addr)->__u6_addr
.__u6_addr8[1] & 0xc0) == 0x80))
||
1001 IN6_IS_ADDR_MC_LINKLOCAL(&su->sin6.sin6_addr)(((&su->sin6.sin6_addr)->__u6_addr.__u6_addr8[0] ==
0xff) && (((&su->sin6.sin6_addr)->__u6_addr
.__u6_addr8[1] & 0x0f) == 0x02))
||
1002 IN6_IS_ADDR_MC_INTFACELOCAL(&su->sin6.sin6_addr)(((&su->sin6.sin6_addr)->__u6_addr.__u6_addr8[0] ==
0xff) && (((&su->sin6.sin6_addr)->__u6_addr
.__u6_addr8[1] & 0x0f) == 0x01))
) &&
1003 su->sin6.sin6_scope_id) {
1004 *(u_int16_t *)&su->sin6.sin6_addr.s6_addr__u6_addr.__u6_addr8[2] =
1005 htons(su->sin6.sin6_scope_id)(__uint16_t)(__builtin_constant_p(su->sin6.sin6_scope_id) ?
(__uint16_t)(((__uint16_t)(su->sin6.sin6_scope_id) & 0xffU
) << 8 | ((__uint16_t)(su->sin6.sin6_scope_id) &
0xff00U) >> 8) : __swap16md(su->sin6.sin6_scope_id)
)
;
1006 su->sin6.sin6_scope_id = 0;
1007 }
1008#endif
1009 if (hints.ai_flags == AI_NUMERICHOST4) {
1010 if (which == RTA_DST0x1) {
1011 if (sep == NULL((void *)0) && su->sin6.sin6_scope_id == 0 &&
1012 IN6_IS_ADDR_UNSPECIFIED(&su->sin6.sin6_addr)((*(const u_int32_t *)(const void *)(&(&su->sin6.sin6_addr
)->__u6_addr.__u6_addr8[0]) == 0) && (*(const u_int32_t
*)(const void *)(&(&su->sin6.sin6_addr)->__u6_addr
.__u6_addr8[4]) == 0) && (*(const u_int32_t *)(const void
*)(&(&su->sin6.sin6_addr)->__u6_addr.__u6_addr8
[8]) == 0) && (*(const u_int32_t *)(const void *)(&
(&su->sin6.sin6_addr)->__u6_addr.__u6_addr8[12]) ==
0))
)
1013 sep = "0";
1014 if (sep == NULL((void *)0) || prefixlen(AF_INET624, sep))
1015 return (1);
1016 }
1017 return (0);
1018 } else
1019 return (1);
1020 }
1021
1022 case AF_LINK18:
1023 su->sdl.sdl_index = if_nametoindex(s);
1024 memset(&su->sdl.sdl_data, 0, sizeof(su->sdl.sdl_data));
1025 return (1);
1026 case AF_MPLS33:
1027 errx(1, "mpls labels require -in or -out switch");
1028 case PF_ROUTE17:
1029 su->sa.sa_len = sizeof(struct sockaddr_storage) - 1;
1030 sockaddr(s, &su->sa);
1031 return (1);
1032
1033 case AF_INET2:
1034 if (hpp != NULL((void *)0))
1035 *hpp = NULL((void *)0);
1036 if (which == RTA_DST0x1 && !forcehost) {
1037 bits = inet_net_pton(AF_INET2, s, &su->sin.sin_addr,
1038 sizeof(su->sin.sin_addr));
1039 if (bits == 32)
1040 return (1);
1041 if (bits >= 0) {
1042 inet_makenetandmask(ntohl((__uint32_t)(__builtin_constant_p(su->sin.sin_addr.s_addr)
? (__uint32_t)(((__uint32_t)(su->sin.sin_addr.s_addr) &
0xff) << 24 | ((__uint32_t)(su->sin.sin_addr.s_addr
) & 0xff00) << 8 | ((__uint32_t)(su->sin.sin_addr
.s_addr) & 0xff0000) >> 8 | ((__uint32_t)(su->sin
.sin_addr.s_addr) & 0xff000000) >> 24) : __swap32md
(su->sin.sin_addr.s_addr))
1043 su->sin.sin_addr.s_addr)(__uint32_t)(__builtin_constant_p(su->sin.sin_addr.s_addr)
? (__uint32_t)(((__uint32_t)(su->sin.sin_addr.s_addr) &
0xff) << 24 | ((__uint32_t)(su->sin.sin_addr.s_addr
) & 0xff00) << 8 | ((__uint32_t)(su->sin.sin_addr
.s_addr) & 0xff0000) >> 8 | ((__uint32_t)(su->sin
.sin_addr.s_addr) & 0xff000000) >> 24) : __swap32md
(su->sin.sin_addr.s_addr))
,
1044 &su->sin, bits);
1045 return (0);
1046 }
1047 } else if (which != RTA_DST0x1 || !forcenet)
1048 if (inet_pton(AF_INET2, s, &su->sin.sin_addr) == 1)
1049 return (1);
1050 hp = gethostbyname(s);
1051 if (hp == NULL((void *)0))
1052 errx(1, "%s: bad address", s);
1053 if (hpp != NULL((void *)0))
1054 *hpp = hp;
1055 su->sin.sin_addr = *(struct in_addr *)hp->h_addrh_addr_list[0];
1056 return (1);
1057
1058 default:
1059 errx(1, "%d: bad address family", afamily);
1060 /* NOTREACHED */
1061 }
1062}
1063
1064void
1065getmplslabel(char *s, int in)
1066{
1067 sup su = NULL((void *)0);
1068 const char *errstr;
1069 u_int32_t label;
1070
1071 label = strtonum(s, 0, MPLS_LABEL_MAX((1 << 20) - 1), &errstr);
1072 if (errstr)
1073 errx(1, "bad label: %s is %s", s, errstr);
1074 if (in) {
1075 rtm_addrs |= RTA_DST0x1;
1076 su = &so_dst;
1077 su->smpls.smpls_label = htonl(label << MPLS_LABEL_OFFSET)(__uint32_t)(__builtin_constant_p(label << 12) ? (__uint32_t
)(((__uint32_t)(label << 12) & 0xff) << 24 | (
(__uint32_t)(label << 12) & 0xff00) << 8 | ((
__uint32_t)(label << 12) & 0xff0000) >> 8 | (
(__uint32_t)(label << 12) & 0xff000000) >> 24
) : __swap32md(label << 12))
;
1078 } else {
1079 rtm_addrs |= RTA_SRC0x100;
1080 su = &so_src;
1081 su->smpls.smpls_label = htonl(label << MPLS_LABEL_OFFSET)(__uint32_t)(__builtin_constant_p(label << 12) ? (__uint32_t
)(((__uint32_t)(label << 12) & 0xff) << 24 | (
(__uint32_t)(label << 12) & 0xff00) << 8 | ((
__uint32_t)(label << 12) & 0xff0000) >> 8 | (
(__uint32_t)(label << 12) & 0xff000000) >> 24
) : __swap32md(label << 12))
;
1082 }
1083
1084 su->sa.sa_len = sizeof(struct sockaddr_mpls);
1085 su->sa.sa_family = AF_MPLS33;
1086}
1087
1088int
1089prefixlen(int af, char *s)
1090{
1091 const char *errstr;
1092 int len, q, r;
1093 int max;
1094
1095 switch (af) {
1096 case AF_INET2:
1097 max = sizeof(struct in_addr) * 8;
1098 break;
1099 case AF_INET624:
1100 max = sizeof(struct in6_addr) * 8;
1101 break;
1102 default:
1103 errx(1, "prefixlen is not supported with af %d", af);
1104 /* NOTREACHED */
1105 }
1106
1107 rtm_addrs |= RTA_NETMASK0x4;
1108 len = strtonum(s, 0, max, &errstr);
1109 if (errstr)
1110 errx(1, "prefixlen %s is %s", s, errstr);
1111
1112 q = len >> 3;
1113 r = len & 7;
1114 switch (af) {
1115 case AF_INET2:
1116 memset(&so_mask, 0, sizeof(so_mask));
1117 so_mask.sin.sin_family = AF_INET2;
1118 so_mask.sin.sin_len = sizeof(struct sockaddr_in);
1119 if (len != 0)
1120 so_mask.sin.sin_addr.s_addr = htonl(0xffffffff << (32 - len))(__uint32_t)(__builtin_constant_p(0xffffffff << (32 - len
)) ? (__uint32_t)(((__uint32_t)(0xffffffff << (32 - len
)) & 0xff) << 24 | ((__uint32_t)(0xffffffff <<
(32 - len)) & 0xff00) << 8 | ((__uint32_t)(0xffffffff
<< (32 - len)) & 0xff0000) >> 8 | ((__uint32_t
)(0xffffffff << (32 - len)) & 0xff000000) >> 24
) : __swap32md(0xffffffff << (32 - len)))
;
1121 break;
1122 case AF_INET624:
1123 so_mask.sin6.sin6_family = AF_INET624;
1124 so_mask.sin6.sin6_len = sizeof(struct sockaddr_in6);
1125 memset((void *)&so_mask.sin6.sin6_addr, 0,
1126 sizeof(so_mask.sin6.sin6_addr));
1127 if (q > 0)
1128 memset((void *)&so_mask.sin6.sin6_addr, 0xff, q);
1129 if (r > 0)
1130 *((u_char *)&so_mask.sin6.sin6_addr + q) =
1131 (0xff00 >> r) & 0xff;
1132 break;
1133 }
1134 return (len == max);
1135}
1136
1137void
1138monitor(int argc, char *argv[])
1139{
1140 int n;
1141 char msg[2048];
1142 time_t now;
1143
1144 verbose = 1;
1145 for (;;) {
1146 if ((n = read(s, msg, sizeof(msg))) == -1) {
1147 if (errno(*__errno()) == EINTR4)
1148 continue;
1149 err(1, "read");
1150 }
1151 now = time(NULL((void *)0));
1152 printf("got message of size %d on %s", n, ctime(&now));
1153 print_rtmsg((struct rt_msghdr *)msg, n);
1154 }
1155}
1156
1157
1158int
1159nameserver(int argc, char *argv[])
1160{
1161 struct rt_msghdr rtm;
1162 struct sockaddr_rtdns rtdns;
1163 struct iovec iov[3];
1164 struct addrinfo hints, *res;
1165 struct in_addr ns4[5];
1166 struct in6_addr ns6[5];
1167 size_t ns4_count = 0, ns6_count = 0;
1168 long pad = 0;
1169 unsigned int if_index;
1170 int error = 0, iovcnt = 0, padlen, i;
1171 char *if_name, buf[INET6_ADDRSTRLEN46];
1172
1173
1174 argc--;
1175 argv++;
1176 if (argc == 0)
1177 usage(NULL((void *)0));
1178
1179 if_name = *argv;
1180 argc--;
1181 argv++;
1182
1183 if ((if_index = if_nametoindex(if_name)) == 0)
1184 errx(1, "unknown interface: %s", if_name);
1185
1186 memset(&hints, 0, sizeof(hints));
1187 hints.ai_family = AF_UNSPEC0;
1188 hints.ai_socktype = SOCK_STREAM1;
1189 hints.ai_flags = AI_NUMERICHOST4 | AI_NUMERICSERV16;
1190
1191#ifndef nitems
1192#define nitems(_a)(sizeof((_a)) / sizeof((_a)[0])) (sizeof((_a)) / sizeof((_a)[0]))
1193#endif
1194
1195 for (; argc > 0 && ns4_count + ns6_count < 5; argc--, argv++) {
1196 error = getaddrinfo(*argv, NULL((void *)0), &hints, &res);
1197 if (error) {
1198 errx(1, "%s", gai_strerror(error));
1199 }
1200 if (res == NULL((void *)0)) {
1201 errx(1, "%s: unknown", *argv);
1202 }
1203
1204 switch (res->ai_addr->sa_family) {
1205 case AF_INET2:
1206 memcpy(&ns4[ns4_count++],
1207 &((struct sockaddr_in *)res->ai_addr)->sin_addr,
1208 sizeof(struct in_addr));
1209 break;
1210 case AF_INET624:
1211 memcpy(&ns6[ns6_count++],
1212 &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr,
1213 sizeof(struct in6_addr));
1214 break;
1215 default:
1216 errx(1, "unknown address family");
1217 }
1218 freeaddrinfo(res);
1219 }
1220
1221 if (argc > 0)
1222 warnx("ignoring additional nameservers");
1223
1224 if (verbose) {
1225 for (i = 0; i < ns4_count; i++)
1226 warnx("v4: %s", inet_ntop(AF_INET2, &ns4[i], buf,
1227 sizeof(buf)));
1228 for (i = 0; i < ns6_count; i++)
1229 warnx("v6: %s", inet_ntop(AF_INET624, &ns6[i], buf,
1230 sizeof(buf)));
1231 }
1232
1233 memset(&rtm, 0, sizeof(rtm));
1234
1235 rtm.rtm_version = RTM_VERSION5;
1236 rtm.rtm_type = RTM_PROPOSAL0x13;
1237 rtm.rtm_msglen = sizeof(rtm);
1238 rtm.rtm_tableid = tableid;
1239 rtm.rtm_index = if_index;
1240 rtm.rtm_seq = 1;
1241 rtm.rtm_priority = RTP_PROPOSAL_STATIC57;
1242 rtm.rtm_addrs = RTA_DNS0x1000;
1243 rtm.rtm_flags = RTF_UP0x1;
1244
1245 iov[iovcnt].iov_base = &rtm;
1246 iov[iovcnt++].iov_len = sizeof(rtm);
1247
1248 iov[iovcnt].iov_base = &rtdns;
1249 iov[iovcnt++].iov_len = sizeof(rtdns);
1250 rtm.rtm_msglen += sizeof(rtdns);
1251
1252 padlen = ROUNDUP(sizeof(rtdns))((sizeof(rtdns)) > 0 ? (1 + (((sizeof(rtdns)) - 1) | (sizeof
(long) - 1))) : sizeof(long))
- sizeof(rtdns);
1253 if (padlen > 0) {
1254 iov[iovcnt].iov_base = &pad;
1255 iov[iovcnt++].iov_len = padlen;
1256 rtm.rtm_msglen += padlen;
1257 }
1258
1259 memset(&rtdns, 0, sizeof(rtdns));
1260 rtdns.sr_family = AF_INET2;
1261 rtdns.sr_len = 2 + ns4_count * sizeof(struct in_addr);
1262 memcpy(rtdns.sr_dns, ns4, rtdns.sr_len - 2);
1263
1264 if (debugonly)
1265 return (0);
1266
1267 if (writev(s, iov, iovcnt) == -1) {
1268 warn("failed to send route message");
1269 error = 1;
1270 }
1271
1272 rtm.rtm_seq++;
1273
1274 memset(&rtdns, 0, sizeof(rtdns));
1275 rtdns.sr_family = AF_INET624;
1276 rtdns.sr_len = 2 + ns6_count * sizeof(struct in6_addr);
1277 memcpy(rtdns.sr_dns, ns6, rtdns.sr_len - 2);
1278
1279 if (writev(s, iov, iovcnt) == -1) {
1280 warn("failed to send route message");
1281 error = 1;
1282 }
1283
1284 return (error);
1285}
1286
1287struct {
1288 struct rt_msghdr m_rtm;
1289 char m_space[512];
1290} m_rtmsg;
1291
1292int
1293rtmsg(int cmd, int flags, int fmask, uint8_t prio)
1294{
1295 static int seq;
1296 char *cp = m_rtmsg.m_space;
1297 int l;
1298
1299#define NEXTADDR(w, u)if (rtm_addrs & (w)) { l = ((u.sa.sa_len) > 0 ? (1 + (
((u.sa.sa_len) - 1) | (sizeof(long) - 1))) : sizeof(long)); memcpy
(cp, &(u), l); cp += l; if (verbose) sodump(&(u), "u"
); }
\
1300 if (rtm_addrs & (w)) { \
1301 l = ROUNDUP(u.sa.sa_len)((u.sa.sa_len) > 0 ? (1 + (((u.sa.sa_len) - 1) | (sizeof(long
) - 1))) : sizeof(long))
; \
1302 memcpy(cp, &(u), l); \
1303 cp += l; \
1304 if (verbose) \
1305 sodump(&(u), #u); \
1306 }
1307
1308 errno(*__errno()) = 0;
1309 memset(&m_rtmsg, 0, sizeof(m_rtmsg));
1310 if (cmd == 'a')
1311 cmd = RTM_ADD0x1;
1312 else if (cmd == 'c')
1313 cmd = RTM_CHANGE0x3;
1314 else if (cmd == 'g') {
1315 cmd = RTM_GET0x4;
1316 if (so_ifp.sa.sa_family == AF_UNSPEC0) {
1317 so_ifp.sa.sa_family = AF_LINK18;
1318 so_ifp.sa.sa_len = sizeof(struct sockaddr_dl);
1319 rtm_addrs |= RTA_IFP0x10;
1320 }
1321 } else if (cmd == 's') {
1322 cmd = RTM_SOURCE0x16;
1323 } else
1324 cmd = RTM_DELETE0x2;
1325#define rtm m_rtmsg.m_rtm
1326 rtm.rtm_type = cmd;
1327 rtm.rtm_flags = flags;
1328 rtm.rtm_fmask = fmask;
1329 rtm.rtm_version = RTM_VERSION5;
1330 rtm.rtm_seq = ++seq;
1331 rtm.rtm_addrs = rtm_addrs;
1332 rtm.rtm_rmx = rt_metrics;
1333 rtm.rtm_inits = rtm_inits;
1334 rtm.rtm_tableid = tableid;
1335 rtm.rtm_priority = prio;
1336 rtm.rtm_mpls = mpls_flags;
1337 rtm.rtm_hdrlen = sizeof(rtm);
1338
1339 /* store addresses in ascending order of RTA values */
1340 NEXTADDR(RTA_DST, so_dst)if (rtm_addrs & (0x1)) { l = ((so_dst.sa.sa_len) > 0 ?
(1 + (((so_dst.sa.sa_len) - 1) | (sizeof(long) - 1))) : sizeof
(long)); memcpy(cp, &(so_dst), l); cp += l; if (verbose) sodump
(&(so_dst), "so_dst"); }
;
1341 NEXTADDR(RTA_GATEWAY, so_gate)if (rtm_addrs & (0x2)) { l = ((so_gate.sa.sa_len) > 0 ?
(1 + (((so_gate.sa.sa_len) - 1) | (sizeof(long) - 1))) : sizeof
(long)); memcpy(cp, &(so_gate), l); cp += l; if (verbose)
sodump(&(so_gate), "so_gate"); }
;
1342 NEXTADDR(RTA_NETMASK, so_mask)if (rtm_addrs & (0x4)) { l = ((so_mask.sa.sa_len) > 0 ?
(1 + (((so_mask.sa.sa_len) - 1) | (sizeof(long) - 1))) : sizeof
(long)); memcpy(cp, &(so_mask), l); cp += l; if (verbose)
sodump(&(so_mask), "so_mask"); }
;
1343 NEXTADDR(RTA_IFP, so_ifp)if (rtm_addrs & (0x10)) { l = ((so_ifp.sa.sa_len) > 0 ?
(1 + (((so_ifp.sa.sa_len) - 1) | (sizeof(long) - 1))) : sizeof
(long)); memcpy(cp, &(so_ifp), l); cp += l; if (verbose) sodump
(&(so_ifp), "so_ifp"); }
;
1344 NEXTADDR(RTA_IFA, so_ifa)if (rtm_addrs & (0x20)) { l = ((so_ifa.sa.sa_len) > 0 ?
(1 + (((so_ifa.sa.sa_len) - 1) | (sizeof(long) - 1))) : sizeof
(long)); memcpy(cp, &(so_ifa), l); cp += l; if (verbose) sodump
(&(so_ifa), "so_ifa"); }
;
1345 NEXTADDR(RTA_SRC, so_src)if (rtm_addrs & (0x100)) { l = ((so_src.sa.sa_len) > 0
? (1 + (((so_src.sa.sa_len) - 1) | (sizeof(long) - 1))) : sizeof
(long)); memcpy(cp, &(so_src), l); cp += l; if (verbose) sodump
(&(so_src), "so_src"); }
;
1346 NEXTADDR(RTA_LABEL, so_label)if (rtm_addrs & (0x400)) { l = ((so_label.sa.sa_len) >
0 ? (1 + (((so_label.sa.sa_len) - 1) | (sizeof(long) - 1))) :
sizeof(long)); memcpy(cp, &(so_label), l); cp += l; if (
verbose) sodump(&(so_label), "so_label"); }
;
1347 rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
1348 if (verbose)
1349 print_rtmsg(&rtm, l);
1350 if (debugonly)
1351 return (0);
1352 if (write(s, &m_rtmsg, l) != l) {
1353 return (-1);
1354 }
1355 if (cmd == RTM_GET0x4) {
1356 do {
1357 l = read(s, &m_rtmsg, sizeof(m_rtmsg));
1358 } while (l > 0 && (rtm.rtm_version != RTM_VERSION5 ||
1359 rtm.rtm_seq != seq || rtm.rtm_pid != pid));
1360 if (l == -1)
1361 warn("read from routing socket");
1362 else
1363 print_getmsg(&rtm, l);
1364 }
1365#undef rtm
1366 return (0);
1367}
1368
1369char *msgtypes[] = {
1370 "",
1371 "RTM_ADD: Add Route",
1372 "RTM_DELETE: Delete Route",
1373 "RTM_CHANGE: Change Metrics or flags",
1374 "RTM_GET: Report Metrics",
1375 "RTM_LOSING: Kernel Suspects Partitioning",
1376 "RTM_REDIRECT: Told to use different route",
1377 "RTM_MISS: Lookup failed on this address",
1378 "",
1379 "",
1380 "",
1381 "RTM_RESOLVE: Route created by cloning",
1382 "RTM_NEWADDR: address being added to iface",
1383 "RTM_DELADDR: address being removed from iface",
1384 "RTM_IFINFO: iface status change",
1385 "RTM_IFANNOUNCE: iface arrival/departure",
1386 "RTM_DESYNC: route socket overflow",
1387 "RTM_INVALIDATE: invalidate cache of L2 route",
1388 "RTM_BFD: bidirectional forwarding detection",
1389 "RTM_PROPOSAL: config proposal",
1390 "RTM_CHGADDRATTR: address attributes being changed",
1391 "RTM_80211INFO: 802.11 iface status change"
1392};
1393
1394char metricnames[] =
1395"\011priority\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount\1mtu";
1396char routeflags[] =
1397"\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010XMASK_PRESENT"
1398"\011CLONING\012MULTICAST\013LLINFO\014STATIC\015BLACKHOLE\016PROTO3\017PROTO2"
1399"\020PROTO1\021CLONED\022CACHED\023MPATH\025MPLS\026LOCAL\027BROADCAST"
1400"\030CONNECTED\031BFD";
1401char ifnetflags[] =
1402"\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6STATICARP\7RUNNING\010NOARP\011PPROMISC"
1403"\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1\017LINK2\020MULTICAST"
1404"\23AUTOCONF6TEMP\24MPLS\25WOL\26AUTOCONF6\27INET6_NOSOII\30AUTOCONF4";
1405char addrnames[] =
1406"\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD\011SRC\012SRCMASK\013LABEL\014BFD\015DNS\016STATIC\017SEARCH";
1407char ieee80211flags[] =
1408 "\1ASCAN\2SIBSS\011WEPON\012IBSSON\013PMGTON\014DESBSSID\016ROAMING"
1409 "\020TXPOW_FIXED\021TXPOW_AUTO\022SHSLOT\023SHPREAMBLE\024QOS"
1410 "\025USEPROT\026RSNON\027PSK\030COUNTERM\031MFPR\032HTON\033PBAR"
1411 "\034BGSCAN\035AUTO_JOIN\036VHTON";
1412char ieee80211xflags[] =
1413 "\1TX_MGMT_ONLY";
1414
1415const char *
1416get_linkstate(int mt, int link_state)
1417{
1418 const struct if_status_description *p;
1419 static char buf[8];
1420
1421 for (p = if_status_descriptions; p->ifs_string != NULL((void *)0); p++) {
1422 if (LINK_STATE_DESC_MATCH(p, mt, link_state)(((p)->ifs_type == (mt) || (p)->ifs_type == 0) &&
(p)->ifs_state == (link_state))
)
1423 return (p->ifs_string);
1424 }
1425 snprintf(buf, sizeof(buf), "[#%d]", link_state);
1426 return buf;
1427}
1428
1429void
1430print_rtmsg(struct rt_msghdr *rtm, int msglen)
1431{
1432 long long relative_expire;
1433 struct if_msghdr *ifm;
1434 struct ifa_msghdr *ifam;
1435 struct if_announcemsghdr *ifan;
1436 char ifname[IF_NAMESIZE16];
1437
1438 if (verbose == 0)
1439 return;
1440 if (rtm->rtm_version != RTM_VERSION5) {
1441 warnx("routing message version %u not understood",
1442 rtm->rtm_version);
1443 return;
1444 }
1445 if (rtm->rtm_type > 0 &&
1446 rtm->rtm_type < sizeof(msgtypes)/sizeof(msgtypes[0]))
1447 printf("%s", msgtypes[rtm->rtm_type]);
1448 else
1449 printf("[rtm_type %u out of range]", rtm->rtm_type);
1450
1451 printf(": len %u", rtm->rtm_msglen);
1452 switch (rtm->rtm_type) {
1453 case RTM_DESYNC0x10:
1454 printf("\n");
1455 break;
1456 case RTM_IFINFO0xe:
1457 ifm = (struct if_msghdr *)rtm;
1458 printf(", if# %u, ", ifm->ifm_index);
1459 if (if_indextoname(ifm->ifm_index, ifname) != NULL((void *)0))
1460 printf("name %s, ", ifname);
1461 printf("link: %s, mtu: %u, flags:",
1462 get_linkstate(ifm->ifm_data.ifi_type,
1463 ifm->ifm_data.ifi_link_state),
1464 ifm->ifm_data.ifi_mtu);
1465 bprintf(stdout(&__sF[1]), ifm->ifm_flags | (ifm->ifm_xflags << 16),
1466 ifnetflags);
1467 pmsg_addrs((char *)ifm + ifm->ifm_hdrlen, ifm->ifm_addrs);
1468 break;
1469 case RTM_80211INFO0x15:
1470 printf(", if# %u, ", rtm->rtm_index);
1471 if (if_indextoname(rtm->rtm_index, ifname) != NULL((void *)0))
1472 printf("name %s, ", ifname);
1473 print_80211info((struct if_ieee80211_msghdr *)rtm);
1474 break;
1475 case RTM_NEWADDR0xc:
1476 case RTM_DELADDR0xd:
1477 case RTM_CHGADDRATTR0x14:
1478 ifam = (struct ifa_msghdr *)rtm;
1479 printf(", if# %u, ", ifam->ifam_index);
1480 if (if_indextoname(ifam->ifam_index, ifname) != NULL((void *)0))
1481 printf("name %s, ", ifname);
1482 printf("metric %d, flags:", ifam->ifam_metric);
1483 bprintf(stdout(&__sF[1]), ifam->ifam_flags, routeflags);
1484 pmsg_addrs((char *)ifam + ifam->ifam_hdrlen, ifam->ifam_addrs);
1485 break;
1486 case RTM_IFANNOUNCE0xf:
1487 ifan = (struct if_announcemsghdr *)rtm;
1488 printf(", if# %u, name %s, what: ",
1489 ifan->ifan_index, ifan->ifan_name);
1490 switch (ifan->ifan_what) {
1491 case IFAN_ARRIVAL0:
1492 printf("arrival");
1493 break;
1494 case IFAN_DEPARTURE1:
1495 printf("departure");
1496 break;
1497 default:
1498 printf("#%u", ifan->ifan_what);
1499 break;
1500 }
1501 printf("\n");
1502 break;
1503#ifdef BFD1
1504 case RTM_BFD0x12:
1505 print_bfdmsg(rtm);
1506 break;
1507#endif
1508 case RTM_PROPOSAL0x13:
1509 printf(", source ");
1510 switch (rtm->rtm_priority) {
1511 case RTP_PROPOSAL_STATIC57:
1512 printf("static");
1513 break;
1514 case RTP_PROPOSAL_DHCLIENT58:
1515 printf("dhcp");
1516 break;
1517 case RTP_PROPOSAL_SLAAC59:
1518 printf("slaac");
1519 break;
1520 case RTP_PROPOSAL_UMB60:
1521 printf("umb");
1522 break;
1523 case RTP_PROPOSAL_PPP61:
1524 printf("ppp");
1525 break;
1526 case RTP_PROPOSAL_SOLICIT62:
1527 printf("solicit");
1528 break;
1529 default:
1530 printf("unknown");
1531 break;
1532 }
1533 printf(", table %u, if# %u, ",
1534 rtm->rtm_tableid, rtm->rtm_index);
1535 if (if_indextoname(rtm->rtm_index, ifname) != NULL((void *)0))
1536 printf("name %s, ", ifname);
1537 printf("pid: %ld, seq %d, errno %d\nflags:",
1538 (long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno);
1539 bprintf(stdout(&__sF[1]), rtm->rtm_flags, routeflags);
1540 printf("\nfmask:");
1541 bprintf(stdout(&__sF[1]), rtm->rtm_fmask, routeflags);
1542 if (verbose) {
1543#define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)RTV_f) ? 'L' : ' ')
1544 relative_expire = rtm->rtm_rmx.rmx_expire ?
1545 rtm->rtm_rmx.rmx_expire - time(NULL((void *)0)) : 0;
1546 printf("\nuse: %8llu mtu: %8u%c expire: %8lld%c",
1547 rtm->rtm_rmx.rmx_pksent,
1548 rtm->rtm_rmx.rmx_mtu, lock(MTU),
1549 relative_expire, lock(EXPIRE));
1550#undef lock
1551 }
1552 printf("\nlocks: ");
1553 bprintf(stdout(&__sF[1]), rtm->rtm_rmx.rmx_locks, metricnames);
1554 printf(" inits: ");
1555 bprintf(stdout(&__sF[1]), rtm->rtm_inits, metricnames);
1556 pmsg_addrs(((char *)rtm + rtm->rtm_hdrlen),
1557 rtm->rtm_addrs & ~(RTA_STATIC0x2000 | RTA_SEARCH0x4000 | RTA_DNS0x1000));
1558
1559 if(!(rtm->rtm_addrs & (RTA_STATIC0x2000 | RTA_SEARCH0x4000 | RTA_DNS0x1000)))
1560 break;
1561
1562 printf("proposals: ");
1563 bprintf(stdout(&__sF[1]), rtm->rtm_addrs & (RTA_STATIC0x2000 | RTA_SEARCH0x4000 |
1564 RTA_DNS0x1000), addrnames);
1565 putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n',
(&__sF[1])))
;
1566
1567 if (rtm->rtm_addrs & RTA_STATIC0x2000) {
1568 char *next = (char *)rtm + rtm->rtm_hdrlen;
1569 struct sockaddr *sa, *rti_info[RTAX_MAX15];
1570 struct sockaddr_rtstatic *rtstatic;
1571 sa = (struct sockaddr *)next;
1572 get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
1573 rtstatic = (struct sockaddr_rtstatic *)
1574 rti_info[RTAX_STATIC13];
1575 if (rtstatic != NULL((void *)0))
1576 print_rtstatic(rtstatic);
1577 }
1578
1579 if (rtm->rtm_addrs & RTA_SEARCH0x4000) {
1580 char *next = (char *)rtm + rtm->rtm_hdrlen;
1581 struct sockaddr *sa, *rti_info[RTAX_MAX15];
1582 struct sockaddr_rtsearch *rtsearch;
1583 sa = (struct sockaddr *)next;
1584 get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
1585 rtsearch = (struct sockaddr_rtsearch *)
1586 rti_info[RTAX_SEARCH14];
1587 if (rtsearch != NULL((void *)0))
1588 print_rtsearch(rtsearch);
1589 }
1590
1591 if (rtm->rtm_addrs & RTA_DNS0x1000) {
1592 char *next = (char *)rtm + rtm->rtm_hdrlen;
1593 struct sockaddr *sa, *rti_info[RTAX_MAX15];
1594 struct sockaddr_rtdns *rtdns;
1595 sa = (struct sockaddr *)next;
1596 get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
1597 rtdns = (struct sockaddr_rtdns *)rti_info[RTAX_DNS12];
1598 if (rtdns != NULL((void *)0))
1599 print_rtdns(rtdns);
1600 }
1601 putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n',
(&__sF[1])))
;
1602 break;
1603 default:
1604 printf(", priority %u, table %u, if# %u, ",
1605 rtm->rtm_priority, rtm->rtm_tableid, rtm->rtm_index);
1606 if (if_indextoname(rtm->rtm_index, ifname) != NULL((void *)0))
1607 printf("name %s, ", ifname);
1608 printf("pid: %ld, seq %d, errno %d\nflags:",
1609 (long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno);
1610 bprintf(stdout(&__sF[1]), rtm->rtm_flags, routeflags);
1611 printf("\nfmask:");
1612 bprintf(stdout(&__sF[1]), rtm->rtm_fmask, routeflags);
1613 if (verbose) {
1614#define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)RTV_f) ? 'L' : ' ')
1615 relative_expire = rtm->rtm_rmx.rmx_expire ?
1616 rtm->rtm_rmx.rmx_expire - time(NULL((void *)0)) : 0;
1617 printf("\nuse: %8llu mtu: %8u%c expire: %8lld%c",
1618 rtm->rtm_rmx.rmx_pksent,
1619 rtm->rtm_rmx.rmx_mtu, lock(MTU),
1620 relative_expire, lock(EXPIRE));
1621#undef lock
1622 }
1623 pmsg_common(rtm);
1624 }
1625}
1626
1627char *
1628priorityname(uint8_t prio)
1629{
1630 switch (prio) {
1631 case RTP_NONE0:
1632 return ("none");
1633 case RTP_LOCAL1:
1634 return ("local");
1635 case RTP_CONNECTED4:
1636 return ("connected");
1637 case RTP_STATIC8:
1638 return ("static");
1639 case RTP_OSPF32:
1640 return ("ospf");
1641 case RTP_ISIS36:
1642 return ("is-is");
1643 case RTP_RIP40:
1644 return ("rip");
1645 case RTP_BGP48:
1646 return ("bgp");
1647 case RTP_DEFAULT56:
1648 return ("default");
1649 default:
1650 return ("");
1651 }
1652}
1653
1654uint8_t
1655getpriority(char *priostr)
1656{
1657 const char *errstr;
1658 uint8_t prio;
1659
1660 switch (keyword(priostr)) {
1661 case K_LOCAL:
1662 prio = RTP_LOCAL1;
1663 break;
1664 case K_CONNECTED:
1665 prio = RTP_CONNECTED4;
1666 break;
1667 case K_STATIC:
1668 prio = RTP_STATIC8;
1669 break;
1670 case K_OSPF:
1671 prio = RTP_OSPF32;
1672 break;
1673 case K_RIP:
1674 prio = RTP_RIP40;
1675 break;
1676 case K_BGP:
1677 prio = RTP_BGP48;
1678 break;
1679 default:
1680 prio = strtonum(priostr, -RTP_MAX63, RTP_MAX63, &errstr);
1681 if (errstr)
1682 errx(1, "priority is %s: %s", errstr, priostr);
1683 }
1684
1685 return (prio);
1686}
1687
1688void
1689print_getmsg(struct rt_msghdr *rtm, int msglen)
1690{
1691 long long relative_expire;
1692 struct sockaddr *dst = NULL((void *)0), *gate = NULL((void *)0), *mask = NULL((void *)0), *ifa = NULL((void *)0);
1693 struct sockaddr_dl *ifp = NULL((void *)0);
1694 struct sockaddr_rtlabel *sa_rl = NULL((void *)0);
1695#ifdef BFD1
1696 struct sockaddr_bfd *sa_bfd = NULL((void *)0);
1697#endif
1698 struct sockaddr *mpls = NULL((void *)0);
1699 struct sockaddr *sa;
1700 char *cp;
1701 int i;
1702
1703 printf(" route to: %s\n", routename(&so_dst.sa));
1704 if (rtm->rtm_version != RTM_VERSION5) {
1705 warnx("routing message version %u not understood",
1706 rtm->rtm_version);
1707 return;
1708 }
1709 if (rtm->rtm_msglen > msglen)
1710 warnx("message length mismatch, in packet %u, returned %d",
1711 rtm->rtm_msglen, msglen);
1712 if (rtm->rtm_errno) {
1713 warnx("RTM_GET: %s (errno %d)",
1714 strerror(rtm->rtm_errno), rtm->rtm_errno);
1715 return;
1716 }
1717 cp = ((char *)rtm + rtm->rtm_hdrlen);
1718 if (rtm->rtm_addrs)
1719 for (i = 1; i; i <<= 1)
1720 if (i & rtm->rtm_addrs) {
1721 sa = (struct sockaddr *)cp;
1722 switch (i) {
1723 case RTA_DST0x1:
1724 dst = sa;
1725 break;
1726 case RTA_GATEWAY0x2:
1727 gate = sa;
1728 break;
1729 case RTA_NETMASK0x4:
1730 mask = sa;
1731 break;
1732 case RTA_IFA0x20:
1733 ifa = sa;
1734 break;
1735 case RTA_IFP0x10:
1736 if (sa->sa_family == AF_LINK18 &&
1737 ((struct sockaddr_dl *)sa)->sdl_nlen)
1738 ifp = (struct sockaddr_dl *)sa;
1739 break;
1740 case RTA_SRC0x100:
1741 mpls = sa;
1742 break;
1743 case RTA_LABEL0x400:
1744 sa_rl = (struct sockaddr_rtlabel *)sa;
1745 break;
1746#ifdef BFD1
1747 case RTA_BFD0x800:
1748 sa_bfd = (struct sockaddr_bfd *)sa;
1749 break;
1750#endif
1751 }
1752 ADVANCE(cp, sa)(cp += (((sa)->sa_len) > 0 ? (1 + ((((sa)->sa_len) -
1) | (sizeof(long) - 1))) : sizeof(long)))
;
1753 }
1754 if (dst && mask)
1755 mask->sa_family = dst->sa_family; /* XXX */
1756 if (dst)
1757 printf("destination: %s\n", routename(dst));
1758 if (mask) {
1759 int savenflag = nflag;
1760
1761 nflag = 1;
1762 printf(" mask: %s\n", routename(mask));
1763 nflag = savenflag;
1764 }
1765 if (gate && rtm->rtm_flags & RTF_GATEWAY0x2)
1766 printf(" gateway: %s\n", routename(gate));
1767 if (ifp)
1768 printf(" interface: %.*s\n",
1769 ifp->sdl_nlen, ifp->sdl_data);
1770 if (ifa)
1771 printf(" if address: %s\n", routename(ifa));
1772 if (mpls) {
1773 printf(" mpls label: %s %s\n", mpls_op(rtm->rtm_mpls),
1774 routename(mpls));
1775 }
1776 printf(" priority: %u (%s)\n", rtm->rtm_priority,
1777 priorityname(rtm->rtm_priority));
1778 printf(" flags: ");
1779 bprintf(stdout(&__sF[1]), rtm->rtm_flags, routeflags);
1780 printf("\n");
1781 if (sa_rl != NULL((void *)0))
1782 printf(" label: %s\n", sa_rl->sr_label);
1783#ifdef BFD1
1784 if (sa_bfd)
1785 print_sabfd(sa_bfd, rtm->rtm_fmask);
1786#endif
1787
1788#define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)RTV_f) ? 'L' : ' ')
1789 relative_expire = rtm->rtm_rmx.rmx_expire ?
1790 rtm->rtm_rmx.rmx_expire - time(NULL((void *)0)) : 0;
1791 printf(" use mtu expire\n");
1792 printf("%8llu %8u%c %8lld%c\n",
1793 rtm->rtm_rmx.rmx_pksent,
1794 rtm->rtm_rmx.rmx_mtu, lock(MTU),
1795 relative_expire, lock(EXPIRE));
1796#undef lock
1797#define RTA_IGN (RTA_DST0x1|RTA_GATEWAY0x2|RTA_NETMASK0x4|RTA_IFP0x10|RTA_IFA0x20|RTA_BRD0x80)
1798 if (verbose)
1799 pmsg_common(rtm);
1800 else if (rtm->rtm_addrs &~ RTA_IGN) {
1801 printf("sockaddrs: ");
1802 bprintf(stdout(&__sF[1]), rtm->rtm_addrs, addrnames);
1803 putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n',
(&__sF[1])))
;
1804 }
1805#undef RTA_IGN
1806}
1807
1808#ifdef BFD1
1809const char *
1810bfd_state(unsigned int state)
1811{
1812 switch (state) {
1813 case BFD_STATE_ADMINDOWN0:
1814 return("admindown");
1815 break;
1816 case BFD_STATE_DOWN1:
1817 return("down");
1818 break;
1819 case BFD_STATE_INIT2:
1820 return("init");
1821 break;
1822 case BFD_STATE_UP3:
1823 return("up");
1824 break;
1825 }
1826 return "invalid";
1827}
1828
1829const char *
1830bfd_diag(unsigned int diag)
1831{
1832 switch (diag) {
1833 case BFD_DIAG_NONE0:
1834 return("none");
1835 break;
1836 case BFD_DIAG_EXPIRED1:
1837 return("expired");
1838 break;
1839 case BFD_DIAG_ECHO_FAILED2:
1840 return("echo-failed");
1841 break;
1842 case BFD_DIAG_NEIGHBOR_SIGDOWN3:
1843 return("neighbor-down");
1844 break;
1845 case BFD_DIAG_FIB_RESET4:
1846 return("fib-reset");
1847 break;
1848 case BFD_DIAG_PATH_DOWN5:
1849 return("path-down");
1850 break;
1851 case BFD_DIAG_CONCAT_PATH_DOWN6:
1852 return("concat-path-down");
1853 break;
1854 case BFD_DIAG_ADMIN_DOWN7:
1855 return("admindown");
1856 break;
1857 case BFD_DIAG_CONCAT_REVERSE_DOWN8:
1858 return("concat-reverse-down");
1859 break;
1860 }
1861 return "invalid";
1862}
1863
1864const char *
1865bfd_calc_uptime(time_t time)
1866{
1867 static char buf[256];
1868 struct tm *tp;
1869 const char *fmt;
1870
1871 if (time > 2*86400)
1872 fmt = "%dd%kh%Mm%Ss";
1873 else if (time > 2*3600)
1874 fmt = "%kh%Mm%Ss";
1875 else if (time > 2*60)
1876 fmt = "%Mm%Ss";
1877 else
1878 fmt = "%Ss";
1879
1880 tp = localtime(&time);
1881 (void)strftime(buf, sizeof(buf), fmt, tp);
1882 return (buf);
1883}
1884
1885void
1886print_bfdmsg(struct rt_msghdr *rtm)
1887{
1888 struct bfd_msghdr *bfdm = (struct bfd_msghdr *)rtm;
1889
1890 printf("\n");
1891 print_sabfd(&bfdm->bm_sa, rtm->rtm_fmask);
1892 pmsg_addrs(((char *)rtm + rtm->rtm_hdrlen), rtm->rtm_addrs);
1893}
1894
1895void
1896print_sabfd(struct sockaddr_bfd *sa_bfd, int fmask)
1897{
1898 struct timeval tv;
1899
1900 gettimeofday(&tv, NULL((void *)0));
1901
1902 printf(" BFD:");
1903
1904 /* only show the state, unless verbose or -bfd */
1905 if (!verbose && ((fmask & RTF_BFD0x1000000) != RTF_BFD0x1000000)) {
1906 printf(" %s\n", bfd_state(sa_bfd->bs_state));
1907 return;
1908 }
1909
1910 switch (sa_bfd->bs_mode) {
1911 case BFD_MODE_ASYNC1:
1912 printf(" async");
1913 break;
1914 case BFD_MODE_DEMAND2:
1915 printf(" demand");
1916 break;
1917 default:
1918 printf(" unknown %u", sa_bfd->bs_mode);
1919 break;
1920 }
1921
1922 printf(" state %s", bfd_state(sa_bfd->bs_state));
1923 printf(" remote %s", bfd_state(sa_bfd->bs_remotestate));
1924 printf(" laststate %s", bfd_state(sa_bfd->bs_laststate));
1925
1926 printf(" error %u", sa_bfd->bs_error);
1927 printf("\n ");
1928 printf(" diag %s", bfd_diag(sa_bfd->bs_localdiag));
1929 printf(" remote %s", bfd_diag(sa_bfd->bs_remotediag));
1930 printf("\n ");
1931 printf(" discr %u", sa_bfd->bs_localdiscr);
1932 printf(" remote %u", sa_bfd->bs_remotediscr);
1933 printf("\n ");
1934 printf(" uptime %s", bfd_calc_uptime(tv.tv_sec - sa_bfd->bs_uptime));
1935 if (sa_bfd->bs_lastuptime)
1936 printf(" last state time %s",
1937 bfd_calc_uptime(sa_bfd->bs_lastuptime));
1938 printf("\n ");
1939 printf(" mintx %u", sa_bfd->bs_mintx);
1940 printf(" minrx %u", sa_bfd->bs_minrx);
1941 printf(" minecho %u", sa_bfd->bs_minecho);
1942 printf(" multiplier %u", sa_bfd->bs_multiplier);
1943 printf("\n");
1944}
1945#endif /* BFD */
1946
1947void
1948pmsg_common(struct rt_msghdr *rtm)
1949{
1950 printf("\nlocks: ");
1951 bprintf(stdout(&__sF[1]), rtm->rtm_rmx.rmx_locks, metricnames);
1952 printf(" inits: ");
1953 bprintf(stdout(&__sF[1]), rtm->rtm_inits, metricnames);
1954 pmsg_addrs(((char *)rtm + rtm->rtm_hdrlen), rtm->rtm_addrs);
1955}
1956
1957void
1958pmsg_addrs(char *cp, int addrs)
1959{
1960 struct sockaddr *sa;
1961 int family = AF_UNSPEC0;
1962 int i;
1963 char *p;
1964
1965 if (addrs != 0) {
1966 printf("\nsockaddrs: ");
1967 bprintf(stdout(&__sF[1]), addrs, addrnames);
1968 putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n',
(&__sF[1])))
;
1969 /* first run, search for address family */
1970 p = cp;
1971 for (i = 1; i; i <<= 1)
1972 if (i & addrs) {
1973 sa = (struct sockaddr *)p;
1974 if (family == AF_UNSPEC0)
1975 switch (i) {
1976 case RTA_DST0x1:
1977 case RTA_IFA0x20:
1978 family = sa->sa_family;
1979 }
1980 ADVANCE(p, sa)(p += (((sa)->sa_len) > 0 ? (1 + ((((sa)->sa_len) - 1
) | (sizeof(long) - 1))) : sizeof(long)))
;
1981 }
1982 /* second run, set address family for mask and print */
1983 p = cp;
1984 for (i = 1; i; i <<= 1)
1985 if (i & addrs) {
1986 sa = (struct sockaddr *)p;
1987 if (family != AF_UNSPEC0)
1988 switch (i) {
1989 case RTA_NETMASK0x4:
1990 sa->sa_family = family;
1991 }
1992 printf(" %s", routename(sa));
1993 ADVANCE(p, sa)(p += (((sa)->sa_len) > 0 ? (1 + ((((sa)->sa_len) - 1
) | (sizeof(long) - 1))) : sizeof(long)))
;
1994 }
1995 }
1996 putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n',
(&__sF[1])))
;
1997 fflush(stdout(&__sF[1]));
1998}
1999
2000void
2001bprintf(FILE *fp, int b, char *s)
2002{
2003 int i;
2004 int gotsome = 0;
2005
2006 if (b == 0)
2007 return;
2008 while ((i = *s++)) {
2009 if ((b & (1 << (i-1)))) {
2010 if (gotsome == 0)
2011 i = '<';
2012 else
2013 i = ',';
2014 putc(i, fp)(!__isthreaded ? __sputc(i, fp) : (putc)(i, fp));
2015 gotsome = 1;
2016 for (; (i = *s) > 32; s++)
2017 putc(i, fp)(!__isthreaded ? __sputc(i, fp) : (putc)(i, fp));
2018 } else
2019 while (*s > 32)
2020 s++;
2021 }
2022 if (gotsome)
2023 putc('>', fp)(!__isthreaded ? __sputc('>', fp) : (putc)('>', fp));
2024}
2025
2026int
2027keycmp(const void *key, const void *kt)
2028{
2029 return (strcmp(key, ((struct keytab *)kt)->kt_cp));
2030}
2031
2032int
2033keyword(char *cp)
2034{
2035 struct keytab *kt;
2036
2037 kt = bsearch(cp, keywords, sizeof(keywords)/sizeof(keywords[0]),
2038 sizeof(keywords[0]), keycmp);
2039 if (!kt)
2040 return (0);
2041
2042 return (kt->kt_i);
2043}
2044
2045void
2046sodump(sup su, char *which)
2047{
2048 switch (su->sa.sa_family) {
2049 case AF_LINK18:
2050 printf("%s: link %s; ", which, link_ntoa(&su->sdl));
2051 break;
2052 case AF_INET2:
2053 printf("%s: inet %s; ", which, inet_ntoa(su->sin.sin_addr));
2054 break;
2055 case AF_INET624:
2056 {
2057 char ntop_buf[NI_MAXHOST256];
2058
2059 printf("%s: inet6 %s; ",
2060 which, inet_ntop(AF_INET624, &su->sin6.sin6_addr,
2061 ntop_buf, sizeof(ntop_buf)));
2062 break;
2063 }
2064 }
2065 fflush(stdout(&__sF[1]));
2066}
2067
2068/* States*/
2069#define VIRGIN0 0
2070#define GOTONE1 1
2071#define GOTTWO2 2
2072/* Inputs */
2073#define DIGIT(4*0) (4*0)
2074#define END(4*1) (4*1)
2075#define DELIM(4*2) (4*2)
2076
2077void
2078sockaddr(char *addr, struct sockaddr *sa)
2079{
2080 char *cp = (char *)sa;
2081 int size = sa->sa_len;
2082 char *cplim = cp + size;
2083 int byte = 0, state = VIRGIN0, new = 0;
2084
2085 memset(cp, 0, size);
2086 cp++;
2087 do {
2088 if ((*addr >= '0') && (*addr <= '9')) {
2089 new = *addr - '0';
2090 } else if ((*addr >= 'a') && (*addr <= 'f')) {
2091 new = *addr - 'a' + 10;
2092 } else if ((*addr >= 'A') && (*addr <= 'F')) {
2093 new = *addr - 'A' + 10;
2094 } else if (*addr == '\0')
2095 state |= END(4*1);
2096 else
2097 state |= DELIM(4*2);
2098 addr++;
2099 switch (state /* | INPUT */) {
2100 case GOTTWO2 | DIGIT(4*0):
2101 *cp++ = byte; /*FALLTHROUGH*/
2102 case VIRGIN0 | DIGIT(4*0):
2103 state = GOTONE1; byte = new; continue;
2104 case GOTONE1 | DIGIT(4*0):
2105 state = GOTTWO2; byte = new + (byte << 4); continue;
2106 default: /* | DELIM */
2107 state = VIRGIN0; *cp++ = byte; byte = 0; continue;
2108 case GOTONE1 | END(4*1):
2109 case GOTTWO2 | END(4*1):
2110 *cp++ = byte; /* FALLTHROUGH */
2111 case VIRGIN0 | END(4*1):
2112 break;
2113 }
2114 break;
2115 } while (cp < cplim);
2116 sa->sa_len = cp - (char *)sa;
2117}
2118
2119void
2120getlabel(char *name)
2121{
2122 so_label.rtlabel.sr_len = sizeof(so_label.rtlabel);
2123 so_label.rtlabel.sr_family = AF_UNSPEC0;
2124 if (strlcpy(so_label.rtlabel.sr_label, name,
2125 sizeof(so_label.rtlabel.sr_label)) >=
2126 sizeof(so_label.rtlabel.sr_label))
2127 errx(1, "label too long");
2128 rtm_addrs |= RTA_LABEL0x400;
2129}
2130
2131#ifndef SMALL
2132int
2133gettable(const char *s)
2134{
2135 const char *errstr;
2136 struct rt_tableinfo info;
2137 int mib[6];
2138 size_t len;
2139
2140 tableid = strtonum(s, 0, RT_TABLEID_MAX255, &errstr);
2141 if (errstr)
2142 errx(1, "invalid table id: %s", errstr);
2143
2144 mib[0] = CTL_NET4;
2145 mib[1] = PF_ROUTE17;
2146 mib[2] = 0;
2147 mib[3] = 0;
2148 mib[4] = NET_RT_TABLE5;
2149 mib[5] = tableid;
2150
2151 len = sizeof(info);
2152 if (sysctl(mib, 6, &info, &len, NULL((void *)0), 0) == -1)
2153 return (errno(*__errno()));
2154 else
2155 return (0);
2156}
2157
2158int
2159rdomain(int argc, char **argv)
2160{
2161 if (!argc)
2162 usage(NULL((void *)0));
2163 if (setrtable(tableid) == -1)
2164 err(1, "setrtable");
2165 execvp(*argv, argv);
2166 warn("%s", argv[0]);
2167 return (errno(*__errno()) == ENOENT2 ? 127 : 126);
2168}
2169#endif /* SMALL */
2170
2171/*
2172 * Print RTM_PROPOSAL DNS server addresses.
2173 */
2174void
2175print_rtdns(struct sockaddr_rtdns *rtdns)
2176{
2177 struct in_addr server;
2178 struct in6_addr in6;
2179 size_t srclen, offset;
2180 unsigned int servercnt;
2181 int i;
2182 char *src = rtdns->sr_dns;
2183 char ntopbuf[INET6_ADDRSTRLEN46];
2184
2185 offset = offsetof(struct sockaddr_rtdns, sr_dns)__builtin_offsetof(struct sockaddr_rtdns, sr_dns);
2186 if (rtdns->sr_len < offset) {
2187 printf("<invalid sr_len (%u <= %zu)>\n", rtdns->sr_len,
2188 offset);
2189 return;
2190 }
2191 srclen = rtdns->sr_len - offset;
2192 if (srclen > sizeof(rtdns->sr_dns)) {
2193 printf("<invalid sr_len (%zu > %zu)>\n", srclen,
2194 sizeof(rtdns->sr_dns));
2195 return;
2196 }
2197 switch (rtdns->sr_family) {
2198 case AF_INET2:
2199 printf(" INET [");
2200 /* An array of IPv4 addresses. */
2201 servercnt = srclen / sizeof(struct in_addr);
2202 if (servercnt * sizeof(struct in_addr) != srclen) {
2203 printf("<invalid server count>\n");
2204 return;
2205 }
2206 for (i = 0; i < servercnt; i++) {
2207 memcpy(&server.s_addr, src, sizeof(server.s_addr));
2208 printf("%s%s", inet_ntoa(server), i == servercnt - 1 ?
2209 "": ", ");
2210 src += sizeof(struct in_addr);
2211 }
2212 break;
2213 case AF_INET624:
2214 printf(" INET6 [");
2215 servercnt = srclen / sizeof(struct in6_addr);
2216 if (servercnt * sizeof(struct in6_addr) != srclen) {
2217 printf("<invalid server count>\n");
2218 return;
2219 }
2220 for (i = 0; i < servercnt; i++) {
2221 memcpy(&in6, src, sizeof(in6));
2222 src += sizeof(in6);
2223 printf("%s%s", inet_ntop(AF_INET624, &in6, ntopbuf,
2224 INET6_ADDRSTRLEN46), i == servercnt - 1 ? "": ", ");
2225 }
2226 break;
2227 default:
2228 printf(" UNKNOWN [");
2229 break;
2230 }
2231 printf("]");
2232}
2233
2234/*
2235 * Print RTM_PROPOSAL static routes.
2236 */
2237void
2238print_rtstatic(struct sockaddr_rtstatic *rtstatic)
2239{
2240 struct sockaddr_in6 gateway6;
2241 struct in6_addr prefix;
2242 struct in_addr dest, gateway;
2243 size_t srclen, offset;
2244 int bits, bytes, error, first = 1;
2245 uint8_t prefixlen;
2246 unsigned char *src = rtstatic->sr_static;
2247 char ntoabuf[INET_ADDRSTRLEN16];
2248 char hbuf[NI_MAXHOST256];
2249 char ntopbuf[INET6_ADDRSTRLEN46];
2250
2251 offset = offsetof(struct sockaddr_rtstatic, sr_static)__builtin_offsetof(struct sockaddr_rtstatic, sr_static);
2252 if (rtstatic->sr_len <= offset) {
2253 printf("<invalid sr_len (%u <= %zu)>\n", rtstatic->sr_len,
2254 offset);
2255 return;
2256 }
2257 srclen = rtstatic->sr_len - offset;
2258 if (srclen > sizeof(rtstatic->sr_static)) {
2259 printf("<invalid sr_len (%zu > %zu)>\n", srclen,
2260 sizeof(rtstatic->sr_static));
2261 return;
2262 }
2263 printf(" [");
2264 switch (rtstatic->sr_family) {
2265 case AF_INET2:
2266 /* AF_INET -> RFC 3442 encoded static routes. */
2267 while (srclen) {
2268 bits = *src;
2269 src++;
2270 srclen--;
2271 bytes = (bits + 7) / 8;
2272 if (srclen < bytes || bytes > sizeof(dest.s_addr))
2273 break;
2274 memset(&dest, 0, sizeof(dest));
2275 memcpy(&dest.s_addr, src, bytes);
2276 src += bytes;
2277 srclen -= bytes;
2278 strlcpy(ntoabuf, inet_ntoa(dest), sizeof(ntoabuf));
2279 if (srclen < sizeof(gateway.s_addr))
2280 break;
2281 memcpy(&gateway.s_addr, src, sizeof(gateway.s_addr));
2282 src += sizeof(gateway.s_addr);
2283 srclen -= sizeof(gateway.s_addr);
2284 printf("%s%s/%u %s ", first ? "" : ", ", ntoabuf, bits,
2285 inet_ntoa(gateway));
2286 first = 0;
2287 }
2288 break;
2289 case AF_INET624:
2290 while (srclen >= sizeof(prefixlen) + sizeof(prefix) +
2291 sizeof(gateway6)) {
2292 memcpy(&prefixlen, src, sizeof(prefixlen));
2293 srclen -= sizeof(prefixlen);
2294 src += sizeof(prefixlen);
2295
2296 memcpy(&prefix, src, sizeof(prefix));
2297 srclen -= sizeof(prefix);
2298 src += sizeof(prefix);
2299
2300 memcpy(&gateway6, src, sizeof(gateway6));
2301 srclen -= sizeof(gateway6);
2302 src += sizeof(gateway6);
2303
2304 if ((error = getnameinfo((struct sockaddr *)&gateway6,
2305 gateway6.sin6_len, hbuf, sizeof(hbuf), NULL((void *)0), 0,
2306 NI_NUMERICHOST1 | NI_NUMERICSERV2))) {
2307 warnx("cannot get gateway address: %s",
2308 gai_strerror(error));
2309 return;
2310 }
2311 printf("%s%s/%u %s ", first ? "" : ", ",
2312 inet_ntop(AF_INET624, &prefix, ntopbuf,
2313 INET6_ADDRSTRLEN46), prefixlen, hbuf);
2314 first = 0;
2315 }
2316 break;
2317 default:
2318 printf("<unknown address family %u>", rtstatic->sr_family);
2319 break;
2320 }
2321 printf("]");
2322}
2323
2324/*
2325 * Print RTM_PROPOSAL domain search list.
2326 */
2327void
2328print_rtsearch(struct sockaddr_rtsearch *rtsearch)
2329{
2330 char *src = rtsearch->sr_search;
2331 size_t srclen, offset;
2332
2333 offset = offsetof(struct sockaddr_rtsearch, sr_search)__builtin_offsetof(struct sockaddr_rtsearch, sr_search);
2334 if (rtsearch->sr_len <= offset) {
2335 printf("<invalid sr_len (%u <= %zu)>\n", rtsearch->sr_len,
2336 offset);
2337 return;
2338 }
2339 srclen = rtsearch->sr_len - offset;
2340 if (srclen > sizeof(rtsearch->sr_search)) {
2341 printf("<invalid sr_len (%zu > %zu)>\n", srclen,
2342 sizeof(rtsearch->sr_search));
2343 return;
2344 }
2345
2346 printf(" [%.*s]", (int)srclen, src);
2347}
2348
2349/*
2350 * Print RTM_80211INFO info.
2351 */
2352void
2353print_80211info(struct if_ieee80211_msghdr *ifim)
2354{
2355 unsigned int ascii, nwidlen, i;
2356 u_int8_t *nwid, *bssid;
2357
2358 ascii = 1;
2359 nwid = ifim->ifim_ifie.ifie_nwid;
2360 nwidlen = ifim->ifim_ifie.ifie_nwid_len;
2361 for (i = 0; i < nwidlen; i++) {
2362 if (i == 0)
2363 printf("nwid ");
2364 else
2365 printf(":");
2366 printf("%02x", nwid[i]);
2367 if (!isprint((unsigned int)nwid[i]))
2368 ascii = 0;
2369 }
2370 if (i > 0) {
2371 if (ascii == 1)
2372 printf(" (%.*s)", nwidlen, nwid);
2373 printf(", ");
2374 }
2375 printf("channel %u, ", ifim->ifim_ifie.ifie_channel);
2376 bssid = ifim->ifim_ifie.ifie_addr;
2377 printf("bssid %02x:%02x:%02x:%02x:%02x:%02x\n",
2378 bssid[0], bssid[1], bssid[2],
2379 bssid[3], bssid[4], bssid[5]);
2380 printf("flags:");
2381 bprintf(stdout(&__sF[1]), ifim->ifim_ifie.ifie_flags, ieee80211flags);
2382 printf("\nxflags:");
2383 bprintf(stdout(&__sF[1]), ifim->ifim_ifie.ifie_xflags, ieee80211xflags);
2384 printf("\n");
2385}