]> git.saurik.com Git - apple/network_cmds.git/blob - route.tproj/route.c
23cba41d5b4557139c4e6c93c050f30616d996df
[apple/network_cmds.git] / route.tproj / route.c
1 /*
2 * Copyright (c) 2008-2011 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * Copyright (c) 1983, 1989, 1991, 1993
30 * The Regents of the University of California. All rights reserved.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 */
60
61 #include <sys/cdefs.h>
62 #ifndef lint
63 __unused static const char copyright[] =
64 "@(#) Copyright (c) 1983, 1989, 1991, 1993\n\
65 The Regents of the University of California. All rights reserved.\n";
66 #endif /* not lint */
67
68 #ifndef lint
69 #if 0
70 static char sccsid[] = "@(#)route.c 8.3 (Berkeley) 3/19/94";
71 #endif
72 __unused static const char rcsid[] =
73 "$Id: route.c,v 1.4 2006/02/07 06:22:29 lindak Exp $";
74 #endif /* not lint */
75
76 #include <sys/param.h>
77 #include <sys/file.h>
78 #include <sys/socket.h>
79 #include <sys/ioctl.h>
80 #include <sys/sysctl.h>
81 #include <sys/types.h>
82
83 #include <net/if.h>
84 #include <net/route.h>
85 #include <net/if_dl.h>
86 #include <netinet/in.h>
87 #include <arpa/inet.h>
88 #include <netdb.h>
89
90 #include <ctype.h>
91 #include <err.h>
92 #include <errno.h>
93 #include <paths.h>
94 #include <stdio.h>
95 #include <stdlib.h>
96 #include <string.h>
97 #include <sysexits.h>
98 #include <unistd.h>
99 #include <ifaddrs.h>
100
101 struct keytab {
102 char *kt_cp;
103 int kt_i;
104 } keywords[] = {
105 #include "keywords.h"
106 {0, 0}
107 };
108
109 union sockunion {
110 struct sockaddr sa;
111 struct sockaddr_in sin;
112 #ifdef INET6
113 struct sockaddr_in6 sin6;
114 #endif
115 struct sockaddr_dl sdl;
116 struct sockaddr_storage ss; /* added to avoid memory overrun */
117 } so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp;
118
119 typedef union sockunion *sup;
120 int pid, rtm_addrs, uid;
121 int s;
122 int forcehost, forcenet, doflush, nflag, af, qflag, tflag, keyword();
123 int iflag, verbose, aflen = sizeof (struct sockaddr_in);
124 int locking, lockrest, debugonly;
125 struct rt_metrics rt_metrics;
126 u_long rtm_inits;
127 unsigned int ifscope;
128
129 static const char *route_strerror(int);
130 const char *routename(), *netname();
131 void flushroutes(), newroute(), monitor(), sockaddr(), sodump(), bprintf();
132 void print_getmsg(), print_rtmsg(), pmsg_common(), pmsg_addrs(), mask_addr();
133 int getaddr(), rtmsg(), x25_makemask();
134 int prefixlen();
135 extern char *iso_ntoa();
136
137 void usage __P((const char *)) __dead2;
138
139 void
140 usage(cp)
141 const char *cp;
142 {
143 if (cp)
144 warnx("bad keyword: %s", cp);
145 (void) fprintf(stderr,
146 "usage: route [-dnqtv] command [[modifiers] args]\n");
147 exit(EX_USAGE);
148 /* NOTREACHED */
149 }
150
151 #define ROUNDUP(a) \
152 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t))
153 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
154
155 int
156 main(argc, argv)
157 int argc;
158 char **argv;
159 {
160 int ch;
161
162 if (argc < 2)
163 usage((char *)NULL);
164
165 while ((ch = getopt(argc, argv, "nqdtv")) != -1)
166 switch(ch) {
167 case 'n':
168 nflag = 1;
169 break;
170 case 'q':
171 qflag = 1;
172 break;
173 case 'v':
174 verbose = 1;
175 break;
176 case 't':
177 tflag = 1;
178 break;
179 case 'd':
180 debugonly = 1;
181 break;
182 case '?':
183 default:
184 usage((char *)NULL);
185 }
186 argc -= optind;
187 argv += optind;
188
189 pid = getpid();
190 uid = geteuid();
191 if (tflag)
192 s = open(_PATH_DEVNULL, O_WRONLY, 0);
193 else
194 s = socket(PF_ROUTE, SOCK_RAW, 0);
195 if (s < 0)
196 err(EX_OSERR, "socket");
197 setuid(uid);
198 if (*argv)
199 switch (keyword(*argv)) {
200 case K_GET:
201 uid = 0;
202 /* FALLTHROUGH */
203
204 case K_CHANGE:
205 case K_ADD:
206 case K_DELETE:
207 newroute(argc, argv);
208 exit(0);
209 /* NOTREACHED */
210
211 case K_MONITOR:
212 monitor();
213 /* NOTREACHED */
214
215 case K_FLUSH:
216 flushroutes(argc, argv);
217 exit(0);
218 /* NOTREACHED */
219 }
220 usage(*argv);
221 /* NOTREACHED */
222 }
223
224 /*
225 * Purge all entries in the routing tables not
226 * associated with network interfaces.
227 */
228 void
229 flushroutes(argc, argv)
230 int argc;
231 char *argv[];
232 {
233 size_t needed;
234 int mib[6], rlen, seqno;
235 char *buf, *next, *lim;
236 register struct rt_msghdr *rtm;
237
238 if (uid) {
239 errx(EX_NOPERM, "must be root to alter routing table");
240 }
241 shutdown(s, 0); /* Don't want to read back our messages */
242 if (argc > 1) {
243 argv++;
244 if (argc == 2 && **argv == '-')
245 switch (keyword(*argv + 1)) {
246 case K_INET:
247 af = AF_INET;
248 break;
249 #ifdef INET6
250 case K_INET6:
251 af = AF_INET6;
252 break;
253 #endif
254 case K_LINK:
255 af = AF_LINK;
256 break;
257 default:
258 goto bad;
259 } else
260 bad: usage(*argv);
261 }
262 mib[0] = CTL_NET;
263 mib[1] = PF_ROUTE;
264 mib[2] = 0; /* protocol */
265 mib[3] = 0; /* wildcard address family */
266 mib[4] = NET_RT_DUMP;
267 mib[5] = 0; /* no flags */
268 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
269 err(EX_OSERR, "route-sysctl-estimate");
270 if ((buf = malloc(needed)) == NULL)
271 errx(EX_OSERR, "malloc failed");
272 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
273 err(EX_OSERR, "route-sysctl-get");
274 lim = buf + needed;
275 if (verbose)
276 (void) printf("Examining routing table from sysctl\n");
277 seqno = 0; /* ??? */
278 for (next = buf; next < lim; next += rtm->rtm_msglen) {
279 rtm = (struct rt_msghdr *)next;
280 if (verbose)
281 print_rtmsg(rtm, rtm->rtm_msglen);
282 if ((rtm->rtm_flags & RTF_GATEWAY) == 0)
283 continue;
284 if (af) {
285 struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
286
287 if (sa->sa_family != af)
288 continue;
289 }
290 if (debugonly)
291 continue;
292 rtm->rtm_type = RTM_DELETE;
293 rtm->rtm_seq = seqno;
294 rlen = write(s, next, rtm->rtm_msglen);
295 if (rlen < (int)rtm->rtm_msglen) {
296 warn("write to routing socket");
297 (void) printf("got only %d for rlen\n", rlen);
298 break;
299 }
300 seqno++;
301 if (qflag)
302 continue;
303 if (verbose)
304 print_rtmsg(rtm, rlen);
305 else {
306 struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
307 (void) printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ?
308 routename(sa) : netname(sa));
309 sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa);
310 (void) printf("%-20.20s ", routename(sa));
311 (void) printf("done\n");
312 }
313 }
314 }
315
316 const char *
317 routename(sa)
318 struct sockaddr *sa;
319 {
320 register char *cp;
321 static char line[MAXHOSTNAMELEN + 1];
322 struct hostent *hp;
323 static char domain[MAXHOSTNAMELEN + 1];
324 static int first = 1;
325
326 if (first) {
327 first = 0;
328 if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
329 (cp = index(domain, '.'))) {
330 domain[MAXHOSTNAMELEN] = '\0';
331 (void) strlcpy(domain, cp + 1, sizeof(domain));
332 } else
333 domain[0] = 0;
334 }
335
336 if (sa->sa_len == 0)
337 strlcpy(line, "default", sizeof(line));
338 else switch (sa->sa_family) {
339
340 case AF_INET:
341 { struct in_addr in;
342 in = ((struct sockaddr_in *)sa)->sin_addr;
343
344 cp = 0;
345 if (in.s_addr == INADDR_ANY || sa->sa_len < 4)
346 cp = "default";
347 if (cp == 0 && !nflag) {
348 hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
349 AF_INET);
350 if (hp) {
351 if ((cp = index(hp->h_name, '.')) &&
352 !strcmp(cp + 1, domain))
353 *cp = 0;
354 cp = hp->h_name;
355 }
356 }
357 if (cp) {
358 strncpy(line, cp, sizeof(line) - 1);
359 line[sizeof(line) - 1] = '\0';
360 } else {
361 /* XXX - why not inet_ntoa()? */
362 #define C(x) (unsigned)((x) & 0xff)
363 in.s_addr = ntohl(in.s_addr);
364 (void) snprintf(line, sizeof(line), "%u.%u.%u.%u", C(in.s_addr >> 24),
365 C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
366 }
367 break;
368 }
369
370 #ifdef INET6
371 case AF_INET6:
372 {
373 struct sockaddr_in6 sin6; /* use static var for safety */
374 int niflags = 0;
375 #ifdef NI_WITHSCOPEID
376 niflags = NI_WITHSCOPEID;
377 #endif
378
379 memset(&sin6, 0, sizeof(sin6));
380 memcpy(&sin6, sa, sa->sa_len);
381 sin6.sin6_len = sizeof(struct sockaddr_in6);
382 sin6.sin6_family = AF_INET6;
383 #ifdef __KAME__
384 if (sa->sa_len == sizeof(struct sockaddr_in6) &&
385 (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
386 IN6_IS_ADDR_MC_NODELOCAL(&sin6.sin6_addr) ||
387 IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
388 sin6.sin6_scope_id == 0) {
389 sin6.sin6_scope_id =
390 ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
391 sin6.sin6_addr.s6_addr[2] = 0;
392 sin6.sin6_addr.s6_addr[3] = 0;
393 }
394 #endif
395 if (nflag)
396 niflags |= NI_NUMERICHOST;
397 if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
398 line, sizeof(line), NULL, 0, niflags) != 0)
399 strncpy(line, "invalid", sizeof(line));
400
401 return(line);
402 }
403 #endif
404
405 case AF_LINK:
406 return (link_ntoa((struct sockaddr_dl *)sa));
407
408 default:
409 { u_short *s = (u_short *)sa;
410 u_short *slim = s + ((sa->sa_len + 1) >> 1);
411 char *cp = line + snprintf(line, sizeof(line), "(%d)", sa->sa_family);
412 char *cpe = line + sizeof(line);
413
414 while (++s < slim && cp < cpe) /* start with sa->sa_data */
415 cp += snprintf(cp, cpe - cp, " %x", *s);
416 break;
417 }
418 }
419 return (line);
420 }
421
422 /*
423 * Return the name of the network whose address is given.
424 * The address is assumed to be that of a net or subnet, not a host.
425 */
426 const char *
427 netname(sa)
428 struct sockaddr *sa;
429 {
430 char *cp = 0;
431 static char line[MAXHOSTNAMELEN + 1];
432 struct netent *np = 0;
433 in_addr_t net, mask;
434 register in_addr_t i;
435 int subnetshift;
436
437 switch (sa->sa_family) {
438
439 case AF_INET:
440 { struct in_addr in;
441 in = ((struct sockaddr_in *)sa)->sin_addr;
442
443 i = in.s_addr = ntohl(in.s_addr);
444 if (in.s_addr == 0)
445 cp = "default";
446 else if (!nflag) {
447 if (IN_CLASSA(i)) {
448 mask = IN_CLASSA_NET;
449 subnetshift = 8;
450 } else if (IN_CLASSB(i)) {
451 mask = IN_CLASSB_NET;
452 subnetshift = 8;
453 } else {
454 mask = IN_CLASSC_NET;
455 subnetshift = 4;
456 }
457 /*
458 * If there are more bits than the standard mask
459 * would suggest, subnets must be in use.
460 * Guess at the subnet mask, assuming reasonable
461 * width subnet fields.
462 */
463 while (in.s_addr &~ mask)
464 mask = mask >> subnetshift;
465 net = in.s_addr & mask;
466 while ((mask & 1) == 0)
467 mask >>= 1, net >>= 1;
468 np = getnetbyaddr(net, AF_INET);
469 if (np)
470 cp = np->n_name;
471 }
472 if (cp)
473 strncpy(line, cp, sizeof(line));
474 else if ((in.s_addr & 0xffffff) == 0)
475 (void) snprintf(line, sizeof(line), "%u", C(in.s_addr >> 24));
476 else if ((in.s_addr & 0xffff) == 0)
477 (void) snprintf(line, sizeof(line), "%u.%u", C(in.s_addr >> 24),
478 C(in.s_addr >> 16));
479 else if ((in.s_addr & 0xff) == 0)
480 (void) snprintf(line, sizeof(line), "%u.%u.%u", C(in.s_addr >> 24),
481 C(in.s_addr >> 16), C(in.s_addr >> 8));
482 else
483 (void) snprintf(line, sizeof(line), "%u.%u.%u.%u", C(in.s_addr >> 24),
484 C(in.s_addr >> 16), C(in.s_addr >> 8),
485 C(in.s_addr));
486 break;
487 }
488
489 #ifdef INET6
490 case AF_INET6:
491 {
492 struct sockaddr_in6 sin6; /* use static var for safety */
493 int niflags = 0;
494 #ifdef NI_WITHSCOPEID
495 niflags = NI_WITHSCOPEID;
496 #endif
497
498 memset(&sin6, 0, sizeof(sin6));
499 memcpy(&sin6, sa, sa->sa_len);
500 sin6.sin6_len = sizeof(struct sockaddr_in6);
501 sin6.sin6_family = AF_INET6;
502 #ifdef __KAME__
503 if (sa->sa_len == sizeof(struct sockaddr_in6) &&
504 (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
505 IN6_IS_ADDR_MC_NODELOCAL(&sin6.sin6_addr) ||
506 IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
507 sin6.sin6_scope_id == 0) {
508 sin6.sin6_scope_id =
509 ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
510 sin6.sin6_addr.s6_addr[2] = 0;
511 sin6.sin6_addr.s6_addr[3] = 0;
512 }
513 #endif
514 if (nflag)
515 niflags |= NI_NUMERICHOST;
516 if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
517 line, sizeof(line), NULL, 0, niflags) != 0)
518 strncpy(line, "invalid", sizeof(line));
519
520 return(line);
521 }
522 #endif
523
524 case AF_LINK:
525 return (link_ntoa((struct sockaddr_dl *)sa));
526
527
528 default:
529 { u_short *s = (u_short *)sa->sa_data;
530 u_short *slim = s + ((sa->sa_len + 1)>>1);
531 char *cp = line + snprintf(line, sizeof(line), "af %d:", sa->sa_family);
532 char *cpe = line + sizeof(line);
533
534 while (s < slim && cp < cpe)
535 cp += snprintf(cp, cpe - cp, " %x", *s++);
536 break;
537 }
538 }
539 return (line);
540 }
541
542 static const char *
543 route_strerror(int error)
544 {
545
546 switch (error) {
547 case ESRCH:
548 return "not in table";
549 case EBUSY:
550 return "entry in use";
551 case ENOBUFS:
552 return "routing table overflow";
553 default:
554 return (strerror(error));
555 }
556 }
557
558 void
559 set_metric(value, key)
560 char *value;
561 int key;
562 {
563 int flag = 0;
564 u_int noval, *valp = &noval;
565
566 switch (key) {
567 #define caseof(x, y, z) case x: valp = (u_int *)&rt_metrics.z; flag = y; break
568 caseof(K_MTU, RTV_MTU, rmx_mtu);
569 caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount);
570 caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire);
571 caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe);
572 caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe);
573 caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh);
574 caseof(K_RTT, RTV_RTT, rmx_rtt);
575 caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar);
576 }
577 rtm_inits |= flag;
578 if (lockrest || locking)
579 rt_metrics.rmx_locks |= flag;
580 if (locking)
581 locking = 0;
582 *valp = atoi(value);
583 }
584
585 void
586 newroute(argc, argv)
587 int argc;
588 register char **argv;
589 {
590 char *cmd, *dest = "", *gateway = "";
591 int ishost = 0, ret, attempts, oerrno, flags = RTF_STATIC;
592 int key;
593 struct hostent *hp = 0;
594
595 if (uid) {
596 errx(EX_NOPERM, "must be root to alter routing table");
597 }
598 cmd = argv[0];
599 if (*cmd != 'g')
600 shutdown(s, 0); /* Don't want to read back our messages */
601 while (--argc > 0) {
602 if (**(++argv)== '-') {
603 switch (key = keyword(1 + *argv)) {
604 case K_LINK:
605 af = AF_LINK;
606 aflen = sizeof(struct sockaddr_dl);
607 break;
608 case K_INET:
609 af = AF_INET;
610 aflen = sizeof(struct sockaddr_in);
611 break;
612 #ifdef INET6
613 case K_INET6:
614 af = AF_INET6;
615 aflen = sizeof(struct sockaddr_in6);
616 break;
617 #endif
618 case K_SA:
619 af = PF_ROUTE;
620 aflen = sizeof(union sockunion);
621 break;
622 case K_IFACE:
623 case K_INTERFACE:
624 iflag++;
625 break;
626 case K_NOSTATIC:
627 flags &= ~RTF_STATIC;
628 break;
629 case K_LLINFO:
630 flags |= RTF_LLINFO;
631 break;
632 case K_LOCK:
633 locking = 1;
634 break;
635 case K_LOCKREST:
636 lockrest = 1;
637 break;
638 case K_HOST:
639 forcehost++;
640 break;
641 case K_REJECT:
642 flags |= RTF_REJECT;
643 break;
644 case K_BLACKHOLE:
645 flags |= RTF_BLACKHOLE;
646 break;
647 case K_PROTO1:
648 flags |= RTF_PROTO1;
649 break;
650 case K_PROTO2:
651 flags |= RTF_PROTO2;
652 break;
653 case K_CLONING:
654 flags |= RTF_CLONING;
655 break;
656 case K_XRESOLVE:
657 flags |= RTF_XRESOLVE;
658 break;
659 case K_STATIC:
660 flags |= RTF_STATIC;
661 break;
662 case K_IFA:
663 if (!--argc)
664 usage((char *)NULL);
665 (void) getaddr(RTA_IFA, *++argv, 0);
666 break;
667 case K_IFP:
668 if (!--argc)
669 usage((char *)NULL);
670 (void) getaddr(RTA_IFP, *++argv, 0);
671 break;
672 case K_GENMASK:
673 if (!--argc)
674 usage((char *)NULL);
675 (void) getaddr(RTA_GENMASK, *++argv, 0);
676 break;
677 case K_GATEWAY:
678 if (!--argc)
679 usage((char *)NULL);
680 (void) getaddr(RTA_GATEWAY, *++argv, 0);
681 break;
682 case K_DST:
683 if (!--argc)
684 usage((char *)NULL);
685 ishost = getaddr(RTA_DST, *++argv, &hp);
686 dest = *argv;
687 break;
688 case K_NETMASK:
689 if (!--argc)
690 usage((char *)NULL);
691 (void) getaddr(RTA_NETMASK, *++argv, 0);
692 /* FALLTHROUGH */
693 case K_NET:
694 forcenet++;
695 break;
696 case K_PREFIXLEN:
697 if (!--argc)
698 usage((char *)NULL);
699 if (prefixlen(*++argv) == -1) {
700 forcenet = 0;
701 ishost = 1;
702 } else {
703 forcenet = 1;
704 ishost = 0;
705 }
706 break;
707 case K_MTU:
708 case K_HOPCOUNT:
709 case K_EXPIRE:
710 case K_RECVPIPE:
711 case K_SENDPIPE:
712 case K_SSTHRESH:
713 case K_RTT:
714 case K_RTTVAR:
715 if (!--argc)
716 usage((char *)NULL);
717 set_metric(*++argv, key);
718 break;
719 case K_IFSCOPE:
720 if (!--argc)
721 usage((char *)NULL);
722 if ((ifscope = if_nametoindex(*++argv)) != 0)
723 flags |= RTF_IFSCOPE;
724 else
725 errx(1, "bad interface name");
726 break;
727 default:
728 usage(1+*argv);
729 }
730 } else {
731 if ((rtm_addrs & RTA_DST) == 0) {
732 dest = *argv;
733 ishost = getaddr(RTA_DST, *argv, &hp);
734 } else if ((rtm_addrs & RTA_GATEWAY) == 0) {
735 gateway = *argv;
736 (void) getaddr(RTA_GATEWAY, *argv, &hp);
737 } else {
738 (void) getaddr(RTA_NETMASK, *argv, 0);
739 }
740 }
741 }
742 if (forcehost) {
743 ishost = 1;
744 #ifdef INET6
745 if (af == AF_INET6) {
746 rtm_addrs &= ~RTA_NETMASK;
747 memset((void *)&so_mask, 0, sizeof(so_mask));
748 }
749 #endif
750 }
751 if (forcenet)
752 ishost = 0;
753 flags |= RTF_UP;
754 if (ishost)
755 flags |= RTF_HOST;
756 if (iflag == 0)
757 flags |= RTF_GATEWAY;
758 if (so_mask.sin.sin_family == AF_INET) {
759 // make sure the mask is contiguous
760 long i;
761 for (i = 0; i < 32; i++)
762 if (((so_mask.sin.sin_addr.s_addr) & ntohl((1 << i))) != 0)
763 break;
764 for (; i < 32; i++)
765 if (((so_mask.sin.sin_addr.s_addr) & ntohl((1 << i))) == 0)
766 errx(EX_NOHOST, "invalid mask: %s", inet_ntoa(so_mask.sin.sin_addr));
767 }
768 for (attempts = 1; ; attempts++) {
769 errno = 0;
770 if ((ret = rtmsg(*cmd, flags)) == 0)
771 break;
772 if (errno != ENETUNREACH && errno != ESRCH)
773 break;
774 if (af == AF_INET && *gateway && hp && hp->h_addr_list[1]) {
775 hp->h_addr_list++;
776 bcopy(hp->h_addr_list[0], &so_gate.sin.sin_addr,
777 MIN(hp->h_length, sizeof(so_gate.sin.sin_addr)));
778 } else
779 break;
780 }
781 if (*cmd == 'g')
782 exit(0);
783 oerrno = errno;
784 (void) printf("%s %s %s", cmd, ishost? "host" : "net", dest);
785 if (*gateway) {
786 (void) printf(": gateway %s", gateway);
787 if (attempts > 1 && ret == 0 && af == AF_INET)
788 (void) printf(" (%s)", inet_ntoa(so_gate.sin.sin_addr));
789 }
790 if (ret == 0)
791 (void) printf("\n");
792 else {
793 (void)printf(": %s\n", route_strerror(oerrno));
794 }
795 }
796
797 void
798 inet_makenetandmask(net, sin, bits)
799 in_addr_t net, bits;
800 register struct sockaddr_in *sin;
801 {
802 in_addr_t addr, mask = 0;
803 register char *cp;
804
805 rtm_addrs |= RTA_NETMASK;
806 if (bits) {
807 addr = net;
808 mask = 0xffffffff << (32 - bits);
809 } else if (net == 0)
810 mask = addr = 0;
811 else if (net < 128) {
812 addr = net << IN_CLASSA_NSHIFT;
813 mask = IN_CLASSA_NET;
814 } else if (net < 65536) {
815 addr = net << IN_CLASSB_NSHIFT;
816 mask = IN_CLASSB_NET;
817 } else if (net < 16777216L) {
818 addr = net << IN_CLASSC_NSHIFT;
819 mask = IN_CLASSC_NET;
820 } else {
821 addr = net;
822 if ((addr & IN_CLASSA_HOST) == 0)
823 mask = IN_CLASSA_NET;
824 else if ((addr & IN_CLASSB_HOST) == 0)
825 mask = IN_CLASSB_NET;
826 else if ((addr & IN_CLASSC_HOST) == 0)
827 mask = IN_CLASSC_NET;
828 else
829 mask = -1;
830 }
831 sin->sin_addr.s_addr = htonl(addr);
832 sin = &so_mask.sin;
833 sin->sin_addr.s_addr = htonl(mask);
834 sin->sin_len = 0;
835 sin->sin_family = 0;
836 cp = (char *)(&sin->sin_addr + 1);
837 while (*--cp == 0 && cp > (char *)sin)
838 ;
839 sin->sin_len = 1 + cp - (char *)sin;
840 }
841
842 #ifdef INET6
843 /*
844 * XXX the function may need more improvement...
845 */
846 static int
847 inet6_makenetandmask(struct sockaddr_in6 *sin6, const char *plen)
848 {
849 struct in6_addr in6;
850
851 if (plen == NULL) {
852 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
853 sin6->sin6_scope_id == 0) {
854 plen = "0";
855 } else if ((sin6->sin6_addr.s6_addr[0] & 0xe0) == 0x20) {
856 /* aggregatable global unicast - RFC2374 */
857 memset(&in6, 0, sizeof(in6));
858 if (!memcmp(&sin6->sin6_addr.s6_addr[8],
859 &in6.s6_addr[8], 8))
860 plen = "64";
861 }
862 }
863
864 if (plen == NULL || strcmp(plen, "128") == 0)
865 return (1);
866 rtm_addrs |= RTA_NETMASK;
867 prefixlen(plen);
868 return (0);
869 }
870 #endif
871
872 /*
873 * Interpret an argument as a network address of some kind,
874 * returning 1 if a host address, 0 if a network address.
875 */
876 int
877 getaddr(which, s, hpp)
878 int which;
879 char *s;
880 struct hostent **hpp;
881 {
882 register sup su = NULL;
883 struct hostent *hp;
884 struct netent *np;
885 in_addr_t val;
886 char *q;
887 int afamily; /* local copy of af so we can change it */
888
889 if (af == 0) {
890 af = AF_INET;
891 aflen = sizeof(struct sockaddr_in);
892 }
893 afamily = af;
894 rtm_addrs |= which;
895 switch (which) {
896 case RTA_DST:
897 su = &so_dst;
898 break;
899 case RTA_GATEWAY:
900 su = &so_gate;
901 if (iflag) {
902 struct ifaddrs *ifap, *ifa;
903 struct sockaddr_dl *sdl = NULL;
904
905 if (getifaddrs(&ifap))
906 err(1, "getifaddrs");
907
908 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
909 if (ifa->ifa_addr->sa_family != AF_LINK)
910 continue;
911
912 if (strcmp(s, ifa->ifa_name))
913 continue;
914
915 sdl = (struct sockaddr_dl *)ifa->ifa_addr;
916 }
917 /* If we found it, then use it */
918 if (sdl) {
919 /*
920 * Copy is safe since we have a
921 * sockaddr_storage member in sockunion{}.
922 * Note that we need to copy before calling
923 * freeifaddrs().
924 */
925 memcpy(&su->sdl, sdl, sdl->sdl_len);
926 }
927 freeifaddrs(ifap);
928 if (sdl)
929 return(1);
930 }
931 break;
932 case RTA_NETMASK:
933 su = &so_mask;
934 break;
935 case RTA_GENMASK:
936 su = &so_genmask;
937 break;
938 case RTA_IFP:
939 su = &so_ifp;
940 afamily = AF_LINK;
941 break;
942 case RTA_IFA:
943 su = &so_ifa;
944 break;
945 default:
946 usage("internal error");
947 /*NOTREACHED*/
948 }
949 su->sa.sa_len = aflen;
950 su->sa.sa_family = afamily; /* cases that don't want it have left already */
951 if (strcmp(s, "default") == 0) {
952 /*
953 * Default is net 0.0.0.0/0
954 */
955 switch (which) {
956 case RTA_DST:
957 forcenet++;
958 /* bzero(su, sizeof(*su)); *//* for readability */
959 (void) getaddr(RTA_NETMASK, s, 0);
960 break;
961 case RTA_NETMASK:
962 case RTA_GENMASK:
963 /* bzero(su, sizeof(*su)); *//* for readability */
964 su->sa.sa_len = 0;
965 break;
966 }
967 return (0);
968 }
969 switch (afamily) {
970 #ifdef INET6
971 case AF_INET6:
972 {
973 struct addrinfo hints, *res;
974 int ecode;
975
976 q = NULL;
977 if (which == RTA_DST && (q = strchr(s, '/')) != NULL)
978 *q = '\0';
979 memset(&hints, 0, sizeof(hints));
980 hints.ai_family = afamily; /*AF_INET6*/
981 hints.ai_flags = AI_NUMERICHOST;
982 hints.ai_socktype = SOCK_DGRAM; /*dummy*/
983 ecode = getaddrinfo(s, NULL, &hints, &res);
984 if (ecode != 0 || res->ai_family != AF_INET6 ||
985 res->ai_addrlen != sizeof(su->sin6)) {
986 (void) fprintf(stderr, "%s: %s\n", s,
987 gai_strerror(ecode));
988 exit(1);
989 }
990 memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6));
991 #ifdef __KAME__
992 if ((IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr) ||
993 IN6_IS_ADDR_MC_NODELOCAL(&su->sin6.sin6_addr) ||
994 IN6_IS_ADDR_MC_LINKLOCAL(&su->sin6.sin6_addr)) &&
995 su->sin6.sin6_scope_id) {
996 *(u_int16_t *)&su->sin6.sin6_addr.s6_addr[2] =
997 htons(su->sin6.sin6_scope_id);
998 su->sin6.sin6_scope_id = 0;
999 }
1000 #endif
1001 freeaddrinfo(res);
1002 if (hints.ai_flags == AI_NUMERICHOST) {
1003 if (q != NULL)
1004 *q++ = '/';
1005 if (which == RTA_DST)
1006 return (inet6_makenetandmask(&su->sin6, q));
1007 return (0);
1008 } else {
1009 return (1);
1010 }
1011 }
1012 #endif /* INET6 */
1013
1014 case AF_LINK:
1015 link_addr(s, &su->sdl);
1016 return (1);
1017
1018
1019 case PF_ROUTE:
1020 su->sa.sa_len = sizeof(*su);
1021 sockaddr(s, &su->sa);
1022 return (1);
1023
1024 case AF_INET:
1025 default:
1026 break;
1027 }
1028
1029 if (hpp == NULL)
1030 hpp = &hp;
1031 *hpp = NULL;
1032
1033 q = strchr(s,'/');
1034 if (q && which == RTA_DST) {
1035 *q = '\0';
1036 if ((val = inet_addr(s)) != INADDR_NONE) {
1037 inet_makenetandmask(
1038 ntohl(val), &su->sin, strtoul(q+1, 0, 0));
1039 return (0);
1040 }
1041 *q = '/';
1042 }
1043 if ((which != RTA_DST || forcenet == 0) &&
1044 (val = inet_addr(s)) != INADDR_NONE) {
1045 su->sin.sin_addr.s_addr = val;
1046 if (which != RTA_DST ||
1047 inet_lnaof(su->sin.sin_addr) != INADDR_ANY)
1048 return (1);
1049 else {
1050 val = ntohl(val);
1051 goto netdone;
1052 }
1053 }
1054 if (which == RTA_DST && forcehost == 0 &&
1055 ((val = inet_network(s)) != INADDR_NONE ||
1056 ((np = getnetbyname(s)) != NULL && (val = np->n_net) != 0))) {
1057 netdone:
1058 inet_makenetandmask(val, &su->sin, 0);
1059 return (0);
1060 }
1061 hp = gethostbyname(s);
1062 if (hp) {
1063 *hpp = hp;
1064 su->sin.sin_family = hp->h_addrtype;
1065 bcopy(hp->h_addr, (char *)&su->sin.sin_addr,
1066 MIN(hp->h_length, sizeof(su->sin.sin_addr)));
1067 return (1);
1068 }
1069 errx(EX_NOHOST, "bad address: %s", s);
1070 }
1071
1072 int
1073 prefixlen(s)
1074 char *s;
1075 {
1076 int len = atoi(s), q, r;
1077 int max;
1078 char *p;
1079
1080 rtm_addrs |= RTA_NETMASK;
1081 switch (af) {
1082 #ifdef INET6
1083 case AF_INET6:
1084 max = 128;
1085 p = (char *)&so_mask.sin6.sin6_addr;
1086 break;
1087 #endif
1088 case AF_INET:
1089 max = 32;
1090 p = (char *)&so_mask.sin.sin_addr;
1091 break;
1092 default:
1093 (void) fprintf(stderr, "prefixlen not supported in this af\n");
1094 exit(1);
1095 /*NOTREACHED*/
1096 }
1097
1098 if (len < 0 || max < len) {
1099 (void) fprintf(stderr, "%s: bad value\n", s);
1100 exit(1);
1101 }
1102
1103 q = len >> 3;
1104 r = len & 7;
1105 so_mask.sa.sa_family = af;
1106 so_mask.sa.sa_len = aflen;
1107 memset((void *)p, 0, max / 8);
1108 if (q > 0)
1109 memset((void *)p, 0xff, q);
1110 if (r > 0)
1111 *((u_char *)p + q) = (0xff00 >> r) & 0xff;
1112 if (len == max)
1113 return -1;
1114 else
1115 return len;
1116 }
1117
1118 void
1119 interfaces()
1120 {
1121 size_t needed;
1122 int mib[6];
1123 char *buf, *lim, *next;
1124 register struct rt_msghdr *rtm;
1125
1126 mib[0] = CTL_NET;
1127 mib[1] = PF_ROUTE;
1128 mib[2] = 0; /* protocol */
1129 mib[3] = 0; /* wildcard address family */
1130 mib[4] = NET_RT_IFLIST;
1131 mib[5] = 0; /* no flags */
1132 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
1133 err(EX_OSERR, "route-sysctl-estimate");
1134 if ((buf = malloc(needed)) == NULL)
1135 errx(EX_OSERR, "malloc failed");
1136 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
1137 err(EX_OSERR, "actual retrieval of interface table");
1138 lim = buf + needed;
1139 for (next = buf; next < lim; next += rtm->rtm_msglen) {
1140 rtm = (struct rt_msghdr *)next;
1141 print_rtmsg(rtm, rtm->rtm_msglen);
1142 }
1143 }
1144
1145 void
1146 monitor()
1147 {
1148 int n;
1149 char msg[2048];
1150
1151 verbose = 1;
1152 if (debugonly) {
1153 interfaces();
1154 exit(0);
1155 }
1156 for(;;) {
1157 time_t now;
1158 n = read(s, msg, 2048);
1159 now = time(NULL);
1160 (void) printf("\ngot message of size %d on %s", n, ctime(&now));
1161 print_rtmsg((struct rt_msghdr *)msg, n);
1162 }
1163 }
1164
1165 struct {
1166 struct rt_msghdr m_rtm;
1167 char m_space[512];
1168 } m_rtmsg;
1169
1170 int
1171 rtmsg(cmd, flags)
1172 int cmd, flags;
1173 {
1174 static int seq;
1175 int rlen;
1176 register char *cp = m_rtmsg.m_space;
1177 register int l;
1178
1179 #define NEXTADDR(w, u) \
1180 if (rtm_addrs & (w)) {\
1181 l = ROUNDUP(u.sa.sa_len); bcopy((char *)&(u), cp, l); cp += l;\
1182 if (verbose) sodump(&(u),"u");\
1183 }
1184
1185 errno = 0;
1186 bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
1187 if (cmd == 'a')
1188 cmd = RTM_ADD;
1189 else if (cmd == 'c')
1190 cmd = RTM_CHANGE;
1191 else if (cmd == 'g') {
1192 cmd = RTM_GET;
1193 if (so_ifp.sa.sa_family == 0) {
1194 so_ifp.sa.sa_family = AF_LINK;
1195 so_ifp.sa.sa_len = sizeof(struct sockaddr_dl);
1196 rtm_addrs |= RTA_IFP;
1197 }
1198 } else
1199 cmd = RTM_DELETE;
1200 #define rtm m_rtmsg.m_rtm
1201 rtm.rtm_type = cmd;
1202 rtm.rtm_flags = flags;
1203 rtm.rtm_version = RTM_VERSION;
1204 rtm.rtm_seq = ++seq;
1205 rtm.rtm_addrs = rtm_addrs;
1206 rtm.rtm_rmx = rt_metrics;
1207 rtm.rtm_inits = rtm_inits;
1208 rtm.rtm_index = ifscope;
1209
1210 if (rtm_addrs & RTA_NETMASK)
1211 mask_addr();
1212 NEXTADDR(RTA_DST, so_dst);
1213 NEXTADDR(RTA_GATEWAY, so_gate);
1214 NEXTADDR(RTA_NETMASK, so_mask);
1215 NEXTADDR(RTA_GENMASK, so_genmask);
1216 NEXTADDR(RTA_IFP, so_ifp);
1217 NEXTADDR(RTA_IFA, so_ifa);
1218 rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
1219 if (verbose)
1220 print_rtmsg(&rtm, l);
1221 if (debugonly)
1222 return (0);
1223 if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
1224 warnx("writing to routing socket: %s", route_strerror(errno));
1225 return (-1);
1226 }
1227 if (cmd == RTM_GET) {
1228 do {
1229 l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
1230 } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
1231 if (l < 0)
1232 warn("read from routing socket");
1233 else
1234 print_getmsg(&rtm, l);
1235 }
1236 #undef rtm
1237 return (0);
1238 }
1239
1240 void
1241 mask_addr()
1242 {
1243 int olen = so_mask.sa.sa_len;
1244 register char *cp1 = olen + (char *)&so_mask, *cp2;
1245
1246 for (so_mask.sa.sa_len = 0; cp1 > (char *)&so_mask; )
1247 if (*--cp1 != 0) {
1248 so_mask.sa.sa_len = 1 + cp1 - (char *)&so_mask;
1249 break;
1250 }
1251 if ((rtm_addrs & RTA_DST) == 0)
1252 return;
1253 switch (so_dst.sa.sa_family) {
1254 case AF_INET:
1255 #ifdef INET6
1256 case AF_INET6:
1257 #endif
1258 case AF_APPLETALK:
1259 case 0:
1260 return;
1261 }
1262 cp1 = so_mask.sa.sa_len + 1 + (char *)&so_dst;
1263 cp2 = so_dst.sa.sa_len + 1 + (char *)&so_dst;
1264 while (cp2 > cp1)
1265 *--cp2 = 0;
1266 cp2 = so_mask.sa.sa_len + 1 + (char *)&so_mask;
1267 while (cp1 > so_dst.sa.sa_data)
1268 *--cp1 &= *--cp2;
1269 }
1270
1271 char *msgtypes[] = {
1272 "",
1273 "RTM_ADD: Add Route",
1274 "RTM_DELETE: Delete Route",
1275 "RTM_CHANGE: Change Metrics or flags",
1276 "RTM_GET: Report Metrics",
1277 "RTM_LOSING: Kernel Suspects Partitioning",
1278 "RTM_REDIRECT: Told to use different route",
1279 "RTM_MISS: Lookup failed on this address",
1280 "RTM_LOCK: fix specified metrics",
1281 "RTM_OLDADD: caused by SIOCADDRT",
1282 "RTM_OLDDEL: caused by SIOCDELRT",
1283 "RTM_RESOLVE: Route created by cloning",
1284 "RTM_NEWADDR: address being added to iface",
1285 "RTM_DELADDR: address being removed from iface",
1286 "RTM_IFINFO: iface status change",
1287 "RTM_NEWMADDR: new multicast group membership on iface",
1288 "RTM_DELMADDR: multicast group membership removed from iface",
1289 0,
1290 };
1291
1292 char metricnames[] =
1293 "\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount"
1294 "\1mtu";
1295 char routeflags[] =
1296 "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010DELCLONE"
1297 "\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE\016b016"
1298 "\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3\024b024"
1299 "\025PINNED\026LOCAL\027BROADCAST\030MULTICAST\031IFSCOPE\032CONDEMNED"
1300 "\033IFREF\034PROXY\035ROUTER";
1301 char ifnetflags[] =
1302 "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP"
1303 "\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1"
1304 "\017LINK2\020MULTICAST";
1305 char addrnames[] =
1306 "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
1307
1308 void
1309 print_rtmsg(rtm, msglen)
1310 register struct rt_msghdr *rtm;
1311 int msglen;
1312 {
1313 struct if_msghdr *ifm;
1314 struct ifa_msghdr *ifam;
1315 #ifdef RTM_NEWMADDR
1316 struct ifma_msghdr *ifmam;
1317 #endif
1318
1319 if (verbose == 0)
1320 return;
1321 if (rtm->rtm_version != RTM_VERSION) {
1322 (void) printf("routing message version %d not understood\n",
1323 rtm->rtm_version);
1324 return;
1325 }
1326 (void)printf("%s: len %d, ", msgtypes[rtm->rtm_type], rtm->rtm_msglen);
1327 switch (rtm->rtm_type) {
1328 case RTM_IFINFO:
1329 ifm = (struct if_msghdr *)rtm;
1330 (void) printf("if# %d, flags:", ifm->ifm_index);
1331 bprintf(stdout, ifm->ifm_flags, ifnetflags);
1332 pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs);
1333 break;
1334 case RTM_NEWADDR:
1335 case RTM_DELADDR:
1336 ifam = (struct ifa_msghdr *)rtm;
1337 (void) printf("metric %d, flags:", ifam->ifam_metric);
1338 bprintf(stdout, ifam->ifam_flags, routeflags);
1339 pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs);
1340 break;
1341 #ifdef RTM_NEWMADDR
1342 case RTM_NEWMADDR:
1343 case RTM_DELMADDR:
1344 ifmam = (struct ifma_msghdr *)rtm;
1345 pmsg_addrs((char *)(ifmam + 1), ifmam->ifmam_addrs);
1346 break;
1347 #endif
1348 default:
1349 (void) printf("pid: %ld, seq %d, errno %d, ",
1350 (long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno);
1351 if (rtm->rtm_flags & RTF_IFSCOPE)
1352 (void) printf("ifscope %d, ", rtm->rtm_index);
1353 if (rtm->rtm_flags & RTF_IFREF)
1354 (void) printf("ifref, ");
1355 (void) printf("flags:");
1356 bprintf(stdout, rtm->rtm_flags, routeflags);
1357 pmsg_common(rtm);
1358 }
1359 }
1360
1361 void
1362 print_getmsg(rtm, msglen)
1363 register struct rt_msghdr *rtm;
1364 int msglen;
1365 {
1366 struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL;
1367 struct sockaddr_dl *ifp = NULL;
1368 register struct sockaddr *sa;
1369 register char *cp;
1370 register int i;
1371
1372 (void) printf(" route to: %s\n", routename(&so_dst.sa));
1373 if (rtm->rtm_version != RTM_VERSION) {
1374 warnx("routing message version %d not understood",
1375 rtm->rtm_version);
1376 return;
1377 }
1378 if (rtm->rtm_msglen > msglen) {
1379 warnx("message length mismatch, in packet %d, returned %d",
1380 rtm->rtm_msglen, msglen);
1381 }
1382 if (rtm->rtm_errno) {
1383 errno = rtm->rtm_errno;
1384 warn("message indicates error %d", errno);
1385 return;
1386 }
1387 cp = ((char *)(rtm + 1));
1388 if (rtm->rtm_addrs)
1389 for (i = 1; i; i <<= 1)
1390 if (i & rtm->rtm_addrs) {
1391 sa = (struct sockaddr *)cp;
1392 switch (i) {
1393 case RTA_DST:
1394 dst = sa;
1395 break;
1396 case RTA_GATEWAY:
1397 gate = sa;
1398 break;
1399 case RTA_NETMASK:
1400 mask = sa;
1401 break;
1402 case RTA_IFP:
1403 if (sa->sa_family == AF_LINK &&
1404 ((struct sockaddr_dl *)sa)->sdl_nlen)
1405 ifp = (struct sockaddr_dl *)sa;
1406 break;
1407 }
1408 ADVANCE(cp, sa);
1409 }
1410 if (dst && mask)
1411 mask->sa_family = dst->sa_family; /* XXX */
1412 if (dst)
1413 (void)printf("destination: %s\n", routename(dst));
1414 if (mask) {
1415 int savenflag = nflag;
1416
1417 nflag = 1;
1418 (void)printf(" mask: %s\n", routename(mask));
1419 nflag = savenflag;
1420 }
1421 if (gate && rtm->rtm_flags & RTF_GATEWAY)
1422 (void)printf(" gateway: %s\n", routename(gate));
1423 if (ifp)
1424 (void)printf(" interface: %.*s\n",
1425 ifp->sdl_nlen, ifp->sdl_data);
1426 (void)printf(" flags: ");
1427 bprintf(stdout, rtm->rtm_flags, routeflags);
1428
1429 #define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ')
1430 #define msec(u) (((u) + 500) / 1000) /* usec to msec */
1431
1432 (void) printf("\n%s\n", "\
1433 recvpipe sendpipe ssthresh rtt,msec rttvar hopcount mtu expire");
1434 printf("%8u%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE));
1435 printf("%8u%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE));
1436 printf("%8u%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH));
1437 printf("%8u%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT));
1438 printf("%8u%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR));
1439 printf("%8u%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT));
1440 printf("%8u%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU));
1441 if (rtm->rtm_rmx.rmx_expire)
1442 rtm->rtm_rmx.rmx_expire -= time(0);
1443 printf("%8d%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE));
1444 #undef lock
1445 #undef msec
1446 #define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD)
1447 if (verbose)
1448 pmsg_common(rtm);
1449 else if (rtm->rtm_addrs &~ RTA_IGN) {
1450 (void) printf("sockaddrs: ");
1451 bprintf(stdout, rtm->rtm_addrs, addrnames);
1452 putchar('\n');
1453 }
1454 #undef RTA_IGN
1455 }
1456
1457 void
1458 pmsg_common(rtm)
1459 register struct rt_msghdr *rtm;
1460 {
1461 (void) printf("\nlocks: ");
1462 bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames);
1463 (void) printf(" inits: ");
1464 bprintf(stdout, rtm->rtm_inits, metricnames);
1465 pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs);
1466 }
1467
1468 void
1469 pmsg_addrs(cp, addrs)
1470 char *cp;
1471 int addrs;
1472 {
1473 register struct sockaddr *sa;
1474 int i;
1475
1476 if (addrs == 0) {
1477 (void) putchar('\n');
1478 return;
1479 }
1480 (void) printf("\nsockaddrs: ");
1481 bprintf(stdout, addrs, addrnames);
1482 (void) putchar('\n');
1483 for (i = 1; i; i <<= 1)
1484 if (i & addrs) {
1485 sa = (struct sockaddr *)cp;
1486 (void) printf(" %s", routename(sa));
1487 ADVANCE(cp, sa);
1488 }
1489 (void) putchar('\n');
1490 (void) fflush(stdout);
1491 }
1492
1493 void
1494 bprintf(fp, b, s)
1495 register FILE *fp;
1496 register int b;
1497 register u_char *s;
1498 {
1499 register int i;
1500 int gotsome = 0;
1501
1502 if (b == 0)
1503 return;
1504 while ((i = *s++) != 0) {
1505 if (b & (1 << (i-1))) {
1506 if (gotsome == 0)
1507 i = '<';
1508 else
1509 i = ',';
1510 (void) putc(i, fp);
1511 gotsome = 1;
1512 for (; (i = *s) > 32; s++)
1513 (void) putc(i, fp);
1514 } else
1515 while (*s > 32)
1516 s++;
1517 }
1518 if (gotsome)
1519 (void) putc('>', fp);
1520 }
1521
1522 int
1523 keyword(cp)
1524 char *cp;
1525 {
1526 register struct keytab *kt = keywords;
1527
1528 while (kt->kt_cp && strcmp(kt->kt_cp, cp))
1529 kt++;
1530 return kt->kt_i;
1531 }
1532
1533 void
1534 sodump(su, which)
1535 register sup su;
1536 char *which;
1537 {
1538 switch (su->sa.sa_family) {
1539 case AF_LINK:
1540 (void) printf("%s: link %s; ",
1541 which, link_ntoa(&su->sdl));
1542 break;
1543 case AF_INET:
1544 (void) printf("%s: inet %s; ",
1545 which, inet_ntoa(su->sin.sin_addr));
1546 break;
1547 }
1548 (void) fflush(stdout);
1549 }
1550
1551 /* States*/
1552 #define VIRGIN 0
1553 #define GOTONE 1
1554 #define GOTTWO 2
1555 /* Inputs */
1556 #define DIGIT (4*0)
1557 #define END (4*1)
1558 #define DELIM (4*2)
1559
1560 void
1561 sockaddr(addr, sa)
1562 register char *addr;
1563 register struct sockaddr *sa;
1564 {
1565 register char *cp = (char *)sa;
1566 int size = sa->sa_len;
1567 char *cplim = cp + size;
1568 register int byte = 0, state = VIRGIN, new = 0 /* foil gcc */;
1569
1570 bzero(cp, size);
1571 cp++;
1572 do {
1573 if ((*addr >= '0') && (*addr <= '9')) {
1574 new = *addr - '0';
1575 } else if ((*addr >= 'a') && (*addr <= 'f')) {
1576 new = *addr - 'a' + 10;
1577 } else if ((*addr >= 'A') && (*addr <= 'F')) {
1578 new = *addr - 'A' + 10;
1579 } else if (*addr == 0)
1580 state |= END;
1581 else
1582 state |= DELIM;
1583 addr++;
1584 switch (state /* | INPUT */) {
1585 case GOTTWO | DIGIT:
1586 *cp++ = byte; /*FALLTHROUGH*/
1587 case VIRGIN | DIGIT:
1588 state = GOTONE; byte = new; continue;
1589 case GOTONE | DIGIT:
1590 state = GOTTWO; byte = new + (byte << 4); continue;
1591 default: /* | DELIM */
1592 state = VIRGIN; *cp++ = byte; byte = 0; continue;
1593 case GOTONE | END:
1594 case GOTTWO | END:
1595 *cp++ = byte; /* FALLTHROUGH */
1596 case VIRGIN | END:
1597 break;
1598 }
1599 break;
1600 } while (cp < cplim);
1601 sa->sa_len = cp - (char *)sa;
1602 }