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