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