Annotation of src/sbin/route/route.c, Revision 1.62
1.62 ! jrf 1: /* $NetBSD: route.c,v 1.61 2002/10/18 00:21:23 itojun 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.
15: * 3. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
17: * This product includes software developed by the University of
18: * California, Berkeley and its contributors.
19: * 4. Neither the name of the University nor the names of its contributors
20: * may be used to endorse or promote products derived from this software
21: * without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33: * SUCH DAMAGE.
34: */
35:
1.23 lukem 36: #include <sys/cdefs.h>
1.1 cgd 37: #ifndef lint
1.23 lukem 38: __COPYRIGHT("@(#) Copyright (c) 1983, 1989, 1991, 1993\n\
39: The Regents of the University of California. All rights reserved.\n");
1.1 cgd 40: #endif /* not lint */
41:
42: #ifndef lint
1.11 cgd 43: #if 0
1.24 lukem 44: static char sccsid[] = "@(#)route.c 8.6 (Berkeley) 4/28/95";
1.11 cgd 45: #else
1.62 ! jrf 46: __RCSID("$NetBSD: route.c,v 1.61 2002/10/18 00:21:23 itojun Exp $");
1.11 cgd 47: #endif
1.1 cgd 48: #endif /* not lint */
49:
50: #include <sys/param.h>
51: #include <sys/file.h>
52: #include <sys/socket.h>
53: #include <sys/ioctl.h>
54: #include <sys/mbuf.h>
1.7 mycroft 55: #include <sys/sysctl.h>
1.1 cgd 56:
1.7 mycroft 57: #include <net/if.h>
1.1 cgd 58: #include <net/route.h>
59: #include <net/if_dl.h>
60: #include <netinet/in.h>
1.19 christos 61: #include <netatalk/at.h>
1.1 cgd 62: #include <netns/ns.h>
63: #include <netiso/iso.h>
64: #include <netccitt/x25.h>
65: #include <arpa/inet.h>
66: #include <netdb.h>
67:
68: #include <errno.h>
69: #include <unistd.h>
70: #include <stdio.h>
71: #include <ctype.h>
72: #include <stdlib.h>
73: #include <string.h>
1.28 kleink 74: #include <time.h>
1.1 cgd 75: #include <paths.h>
1.26 christos 76: #include <err.h>
1.1 cgd 77:
78: #include "keywords.h"
1.19 christos 79: #include "extern.h"
80:
81: typedef union sockunion *sup;
82:
83: int main __P((int, char **));
1.52 christos 84: static void usage __P((char *)) __attribute__((__noreturn__));
1.19 christos 85: static char *any_ntoa __P((const struct sockaddr *));
86: static void set_metric __P((char *, int));
1.52 christos 87: static int newroute __P((int, char **));
1.27 ross 88: static void inet_makenetandmask __P((u_int32_t, struct sockaddr_in *));
1.36 itojun 89: #ifdef INET6
1.54 itojun 90: static int inet6_makenetandmask __P((struct sockaddr_in6 *));
1.36 itojun 91: #endif
1.19 christos 92: static int getaddr __P((int, char *, struct hostent **));
1.52 christos 93: static int flushroutes __P((int, char *[]));
1.19 christos 94: #ifndef SMALL
1.31 itojun 95: static int prefixlen __P((char *));
1.19 christos 96: static int x25_makemask __P((void));
97: static void interfaces __P((void));
98: static void monitor __P((void));
99: static void print_getmsg __P((struct rt_msghdr *, int));
1.53 christos 100: static const char *linkstate __P((struct if_msghdr *));
101: #endif /* SMALL */
1.19 christos 102: static int rtmsg __P((int, int ));
103: static void mask_addr __P((void));
104: static void print_rtmsg __P((struct rt_msghdr *, int));
105: static void pmsg_common __P((struct rt_msghdr *));
106: static void pmsg_addrs __P((char *, int));
107: static void bprintf __P((FILE *, int, u_char *));
108: static int keyword __P((char *));
109: static void sodump __P((sup, char *));
110: static void sockaddr __P((char *, struct sockaddr *));
1.1 cgd 111:
112: union sockunion {
113: struct sockaddr sa;
114: struct sockaddr_in sin;
1.31 itojun 115: #ifdef INET6
116: struct sockaddr_in6 sin6;
117: #endif
1.19 christos 118: struct sockaddr_at sat;
1.30 lukem 119: struct sockaddr_dl sdl;
120: #ifndef SMALL
1.1 cgd 121: struct sockaddr_ns sns;
122: struct sockaddr_iso siso;
123: struct sockaddr_x25 sx25;
1.30 lukem 124: #endif /* SMALL */
1.1 cgd 125: } so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp;
126:
1.18 carrel 127: int pid, rtm_addrs;
1.51 lukem 128: int sock;
1.19 christos 129: int forcehost, forcenet, doflush, nflag, af, qflag, tflag;
1.1 cgd 130: int iflag, verbose, aflen = sizeof (struct sockaddr_in);
1.50 atatat 131: int locking, lockrest, debugonly, shortoutput, rv;
1.1 cgd 132: struct rt_metrics rt_metrics;
1.27 ross 133: u_int32_t 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.23 lukem 138: static void
1.1 cgd 139: usage(cp)
140: char *cp;
141: {
1.45 cgd 142:
1.1 cgd 143: if (cp)
1.26 christos 144: warnx("botched keyword: %s", cp);
1.1 cgd 145: (void) fprintf(stderr,
1.50 atatat 146: "Usage: %s [ -fnqvs ] cmd [[ -<qualifers> ] args ]\n",
1.45 cgd 147: getprogname());
1.1 cgd 148: exit(1);
149: /* NOTREACHED */
150: }
151:
152: #define ROUNDUP(a) \
1.33 itojun 153: ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
1.1 cgd 154: #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
155:
1.7 mycroft 156: int
1.1 cgd 157: main(argc, argv)
158: int argc;
159: char **argv;
160: {
161: int ch;
162:
163: if (argc < 2)
1.26 christos 164: usage(NULL);
1.1 cgd 165:
1.62 ! jrf 166: /* The -d (debugonly) and -t (tflag) are for program debugging
! 167: * and are deliberately not documented.
! 168: *
! 169: * debugonly fakes the operation. If it is manipulating a route
! 170: * it will flush all routes not associated with a network interface.
! 171: * tflag uses /dev/null instead of a real socket.
! 172: */
1.50 atatat 173: while ((ch = getopt(argc, argv, "fnqvdts")) != -1)
1.1 cgd 174: switch(ch) {
1.30 lukem 175: case 'f':
176: doflush = 1;
177: break;
1.1 cgd 178: case 'n':
179: nflag = 1;
180: break;
181: case 'q':
182: qflag = 1;
183: break;
184: case 'v':
185: verbose = 1;
186: break;
187: case 't':
188: tflag = 1;
189: break;
1.7 mycroft 190: case 'd':
191: debugonly = 1;
192: break;
1.50 atatat 193: case 's':
194: shortoutput = 1;
195: break;
1.1 cgd 196: case '?':
197: default:
1.26 christos 198: usage(NULL);
1.52 christos 199: /*NOTREACHED*/
1.1 cgd 200: }
201: argc -= optind;
202: argv += optind;
203:
204: pid = getpid();
205: if (tflag)
1.51 lukem 206: sock = open("/dev/null", O_WRONLY, 0);
1.1 cgd 207: else
1.51 lukem 208: sock = socket(PF_ROUTE, SOCK_RAW, 0);
209: if (sock < 0)
1.26 christos 210: err(1, "socket");
1.17 gwr 211:
1.30 lukem 212: if (*argv == NULL) {
213: if (doflush)
214: ch = K_FLUSH;
215: else
216: goto no_cmd;
217: } else
218: ch = keyword(*argv);
219:
220: switch (ch) {
1.17 gwr 221: #ifndef SMALL
222: case K_GET:
223: #endif /* SMALL */
224: case K_CHANGE:
225: case K_ADD:
226: case K_DELETE:
1.30 lukem 227: if (doflush)
1.52 christos 228: (void)flushroutes(1, argv);
229: return newroute(argc, argv);
1.17 gwr 230:
231: case K_SHOW:
232: show(argc, argv);
1.52 christos 233: return 0;
1.17 gwr 234:
235: #ifndef SMALL
236: case K_MONITOR:
237: monitor();
1.52 christos 238: return 0;
1.17 gwr 239:
1.30 lukem 240: #endif /* SMALL */
1.17 gwr 241: case K_FLUSH:
1.52 christos 242: return flushroutes(argc, argv);
1.17 gwr 243:
244: no_cmd:
245: default:
246: usage(*argv);
1.52 christos 247: /*NOTREACHED*/
1.17 gwr 248: }
1.1 cgd 249: }
250:
251: /*
252: * Purge all entries in the routing tables not
253: * associated with network interfaces.
254: */
1.52 christos 255: static int
1.1 cgd 256: flushroutes(argc, argv)
257: int argc;
258: char *argv[];
259: {
1.7 mycroft 260: size_t needed;
261: int mib[6], rlen, seqno;
1.1 cgd 262: char *buf, *next, *lim;
1.23 lukem 263: struct rt_msghdr *rtm;
1.1 cgd 264:
1.30 lukem 265: af = 0;
1.51 lukem 266: shutdown(sock, SHUT_RD); /* Don't want to read back our messages */
1.1 cgd 267: if (argc > 1) {
268: argv++;
269: if (argc == 2 && **argv == '-')
270: switch (keyword(*argv + 1)) {
271: case K_INET:
272: af = AF_INET;
273: break;
1.31 itojun 274: #ifdef INET6
275: case K_INET6:
276: af = AF_INET6;
277: break;
278: #endif
1.19 christos 279: case K_ATALK:
280: af = AF_APPLETALK;
281: break;
1.30 lukem 282: #ifndef SMALL
1.1 cgd 283: case K_XNS:
284: af = AF_NS;
285: break;
1.30 lukem 286: #endif /* SMALL */
1.1 cgd 287: case K_LINK:
288: af = AF_LINK;
289: break;
1.30 lukem 290: #ifndef SMALL
1.1 cgd 291: case K_ISO:
292: case K_OSI:
293: af = AF_ISO;
294: break;
295: case K_X25:
296: af = AF_CCITT;
1.30 lukem 297: #endif /* SMALL */
1.1 cgd 298: default:
299: goto bad;
300: } else
301: bad: usage(*argv);
302: }
1.7 mycroft 303: mib[0] = CTL_NET;
304: mib[1] = PF_ROUTE;
305: mib[2] = 0; /* protocol */
306: mib[3] = 0; /* wildcard address family */
307: mib[4] = NET_RT_DUMP;
308: mib[5] = 0; /* no flags */
309: if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
1.26 christos 310: err(1, "route-sysctl-estimate");
1.22 thorpej 311: if (needed == 0)
1.52 christos 312: return 0;
1.1 cgd 313: if ((buf = malloc(needed)) == NULL)
1.26 christos 314: err(1, "malloc");
1.7 mycroft 315: if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
1.26 christos 316: err(1, "actual retrieval of routing table");
1.7 mycroft 317: lim = buf + needed;
1.17 gwr 318: if (verbose) {
1.7 mycroft 319: (void) printf("Examining routing table from sysctl\n");
1.17 gwr 320: if (af) printf("(address family %s)\n", (*argv + 1));
321: }
1.1 cgd 322: seqno = 0; /* ??? */
323: for (next = buf; next < lim; next += rtm->rtm_msglen) {
324: rtm = (struct rt_msghdr *)next;
1.7 mycroft 325: if (verbose)
326: print_rtmsg(rtm, rtm->rtm_msglen);
1.1 cgd 327: if ((rtm->rtm_flags & RTF_GATEWAY) == 0)
328: continue;
329: if (af) {
330: struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
331:
332: if (sa->sa_family != af)
333: continue;
334: }
1.7 mycroft 335: if (debugonly)
336: continue;
1.1 cgd 337: rtm->rtm_type = RTM_DELETE;
338: rtm->rtm_seq = seqno;
1.51 lukem 339: rlen = write(sock, next, rtm->rtm_msglen);
1.1 cgd 340: if (rlen < (int)rtm->rtm_msglen) {
1.26 christos 341: warn("write to routing socket, got %d for rlen", rlen);
1.1 cgd 342: break;
343: }
344: seqno++;
345: if (qflag)
346: continue;
347: if (verbose)
348: print_rtmsg(rtm, rlen);
349: else {
350: struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
1.49 atatat 351: (void) printf("%-20.20s ",
352: routename(sa, NULL, rtm->rtm_flags));
1.33 itojun 353: sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa);
1.49 atatat 354: (void) printf("%-20.20s ",
355: routename(sa, NULL, RTF_HOST));
1.1 cgd 356: (void) printf("done\n");
357: }
358: }
1.52 christos 359: return 0;
1.1 cgd 360: }
1.17 gwr 361:
362:
363: static char hexlist[] = "0123456789abcdef";
364:
1.19 christos 365: static char *
1.17 gwr 366: any_ntoa(sa)
367: const struct sockaddr *sa;
368: {
369: static char obuf[64];
370: const char *in;
371: char *out;
372: int len;
373:
374: len = sa->sa_len;
375: in = sa->sa_data;
376: out = obuf;
377:
378: do {
379: *out++ = hexlist[(*in >> 4) & 15];
380: *out++ = hexlist[(*in++) & 15];
381: *out++ = '.';
382: } while (--len > 0);
383: out[-1] = '\0';
384: return obuf;
385: }
386:
1.7 mycroft 387:
1.49 atatat 388: int
1.51 lukem 389: netmask_length(nm, family)
1.49 atatat 390: struct sockaddr *nm;
1.51 lukem 391: int family;
1.49 atatat 392: {
393: static int
394: /* number of bits in a nibble */
395: _t[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 },
396: /* good nibbles are 1111, 1110, 1100, 1000, 0000 */
397: _g[] = { 1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,1 };
398: int mask, good, zeroes, maskbytes, bit, i;
399: unsigned char *maskdata;
400:
401: if (nm == NULL)
402: return 0;
403:
404: mask = 0;
405: good = 1;
406: zeroes = 0;
407:
1.51 lukem 408: switch (family) {
1.49 atatat 409: case AF_INET: {
1.51 lukem 410: struct sockaddr_in *nsin = (struct sockaddr_in *)nm;
411: maskdata = (unsigned char *) &nsin->sin_addr;
412: maskbytes = nsin->sin_len -
413: ((caddr_t)&nsin->sin_addr - (caddr_t)nsin);
1.49 atatat 414: break;
415: }
416: case AF_INET6: {
417: struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nm;
418: maskdata = (unsigned char *) &sin6->sin6_addr;
419: maskbytes = sin6->sin6_len -
420: ((caddr_t)&sin6->sin6_addr - (caddr_t)sin6);
421: break;
422: }
423: default:
424: return 0;
425: }
426:
427: /*
428: * Count the bits in the nibbles of the mask, and marking the
429: * netmask as not good (or at best, non-standard and very
430: * discouraged, in the case of AF_INET) if we find either of
431: * a nibble with non-contiguous bits, or a non-zero nibble
432: * after we've found a zero nibble.
433: */
434: for (i = 0; i < maskbytes; i++) {
435: /* high nibble */
436: mask += bit = _t[maskdata[i] >> 4];
437: good &= _g[maskdata[i] >> 4];
438: if (zeroes && bit)
439: good = 0;
440: if (bit == 0)
441: zeroes = 1;
442: /* low nibble */
443: mask += bit = _t[maskdata[i] & 0xf];
444: good &= _g[maskdata[i] & 0xf];
445: if (zeroes && bit)
446: good = 0;
447: if (bit == 0)
448: zeroes = 1;
449: }
450:
451: /*
452: * Always return the number of bits found, but as a negative
453: * if the mask wasn't one we like.
454: */
455: return good ? mask : -mask;
456: }
457:
458: char *
459: netmask_string(mask, len)
460: struct sockaddr *mask;
461: int len;
462: {
463: static char smask[16];
464:
465: if (len >= 0)
466: snprintf(smask, sizeof(smask), "%d", len);
467: else {
468: /* XXX AF_INET only?! */
1.51 lukem 469: struct sockaddr_in nsin;
1.49 atatat 470:
1.51 lukem 471: memset(&nsin, 0, sizeof(nsin));
472: memcpy(&nsin, mask, mask->sa_len);
473: snprintf(smask, sizeof(smask), "%s", inet_ntoa(nsin.sin_addr));
1.49 atatat 474: }
475:
476: return smask;
477: }
478:
479:
1.1 cgd 480: char *
1.49 atatat 481: routename(sa, nm, flags)
482: struct sockaddr *sa, *nm;
483: int flags;
1.1 cgd 484: {
1.23 lukem 485: char *cp;
1.1 cgd 486: static char line[50];
487: struct hostent *hp;
488: static char domain[MAXHOSTNAMELEN + 1];
489: static int first = 1;
1.17 gwr 490: struct in_addr in;
1.49 atatat 491: int nml;
492:
493: if ((flags & RTF_HOST) == 0)
494: return netname(sa, nm);
1.1 cgd 495:
496: if (first) {
497: first = 0;
498: if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
1.20 mrg 499: (cp = strchr(domain, '.'))) {
500: (void)strncpy(domain, cp + 1, sizeof(domain) - 1);
501: domain[sizeof(domain) - 1] = '\0';
502: } else
1.1 cgd 503: domain[0] = 0;
504: }
1.7 mycroft 505:
1.20 mrg 506: if (sa->sa_len == 0) {
507: strncpy(line, "default", sizeof(line) - 1);
508: line[sizeof(line) - 1] = '\0';
509: } else switch (sa->sa_family) {
1.1 cgd 510:
511: case AF_INET:
512: in = ((struct sockaddr_in *)sa)->sin_addr;
1.49 atatat 513: nml = netmask_length(nm, AF_INET);
1.1 cgd 514:
515: cp = 0;
1.49 atatat 516: if (in.s_addr == INADDR_ANY || sa->sa_len < 4) {
517: if (nml == 0)
518: cp = "default";
519: else {
520: static char notdefault[sizeof(NOTDEFSTRING)];
521:
522: snprintf(notdefault, sizeof(notdefault),
523: "0.0.0.0/%s", netmask_string(nm, nml));
524: cp = notdefault;
525: }
526: }
1.1 cgd 527: if (cp == 0 && !nflag) {
528: hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
529: AF_INET);
530: if (hp) {
1.8 mycroft 531: if ((cp = strchr(hp->h_name, '.')) &&
1.1 cgd 532: !strcmp(cp + 1, domain))
533: *cp = 0;
534: cp = hp->h_name;
535: }
536: }
537: if (cp)
1.20 mrg 538: (void)strncpy(line, cp, sizeof(line) - 1);
1.17 gwr 539: else
1.20 mrg 540: (void)strncpy(line, inet_ntoa(in), sizeof(line) - 1);
541: line[sizeof(line) - 1] = '\0';
1.1 cgd 542: break;
543:
1.17 gwr 544: case AF_LINK:
545: return (link_ntoa((struct sockaddr_dl *)sa));
546:
547: #ifndef SMALL
1.31 itojun 548: #ifdef INET6
549: case AF_INET6:
1.36 itojun 550: {
551: struct sockaddr_in6 sin6;
552: int niflags;
1.31 itojun 553:
1.36 itojun 554: #ifdef NI_WITHSCOPEID
555: niflags = NI_WITHSCOPEID;
556: #else
557: niflags = 0;
558: #endif
559: if (nflag)
560: niflags |= NI_NUMERICHOST;
561: memset(&sin6, 0, sizeof(sin6));
562: memcpy(&sin6, sa, sa->sa_len);
563: sin6.sin6_len = sizeof(struct sockaddr_in6);
564: sin6.sin6_family = AF_INET6;
565: #ifdef __KAME__
566: if (sa->sa_len == sizeof(struct sockaddr_in6) &&
1.37 itojun 567: (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
568: IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
1.36 itojun 569: sin6.sin6_scope_id == 0) {
570: sin6.sin6_scope_id =
571: ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
572: sin6.sin6_addr.s6_addr[2] = 0;
573: sin6.sin6_addr.s6_addr[3] = 0;
574: }
575: #endif
1.49 atatat 576: nml = netmask_length(nm, AF_INET6);
577: if (IN6_IS_ADDR_UNSPECIFIED(&sin6.sin6_addr)) {
578: if (nml == 0) {
579: strncpy(line, "::", sizeof(line) - 1);
580: line[sizeof(line) - 1] = '\0';
581: }
582: else
583: /* noncontiguous never happens in ipv6 */
584: snprintf(line, sizeof(line), "::/%d", nml);
585: }
586:
587: else if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
1.36 itojun 588: line, sizeof(line), NULL, 0, niflags) != 0)
589: strncpy(line, "invalid", sizeof(line));
590: break;
1.31 itojun 591: }
592: #endif
593:
1.1 cgd 594: case AF_NS:
595: return (ns_print((struct sockaddr_ns *)sa));
596:
597: case AF_ISO:
1.20 mrg 598: (void)snprintf(line, sizeof line, "iso %s",
1.1 cgd 599: iso_ntoa(&((struct sockaddr_iso *)sa)->siso_addr));
600: break;
1.30 lukem 601: #endif /* SMALL */
1.19 christos 602:
603: case AF_APPLETALK:
604: (void) snprintf(line, sizeof(line), "atalk %d.%d",
605: ((struct sockaddr_at *)sa)->sat_addr.s_net,
606: ((struct sockaddr_at *)sa)->sat_addr.s_node);
607: break;
1.1 cgd 608:
609: default:
1.20 mrg 610: (void)snprintf(line, sizeof line, "(%d) %s",
1.17 gwr 611: sa->sa_family, any_ntoa(sa));
612: break;
1.1 cgd 613:
614: }
615: return (line);
616: }
617:
618: /*
619: * Return the name of the network whose address is given.
620: * The address is assumed to be that of a net or subnet, not a host.
621: */
622: char *
1.49 atatat 623: netname(sa, nm)
624: struct sockaddr *sa, *nm;
1.1 cgd 625: {
626: char *cp = 0;
627: static char line[50];
628: struct netent *np = 0;
1.27 ross 629: u_int32_t net, mask;
630: u_int32_t i;
1.49 atatat 631: int subnetshift, nml;
1.17 gwr 632: struct in_addr in;
1.1 cgd 633:
634: switch (sa->sa_family) {
635:
636: case AF_INET:
637: in = ((struct sockaddr_in *)sa)->sin_addr;
1.17 gwr 638: i = ntohl(in.s_addr);
1.49 atatat 639: nml = netmask_length(nm, AF_INET);
640: if (i == 0) {
641: if (nml == 0)
642: cp = "default";
643: else {
644: static char notdefault[sizeof(NOTDEFSTRING)];
645:
646: snprintf(notdefault, sizeof(notdefault),
647: "0.0.0.0/%s", netmask_string(nm, nml));
648: cp = notdefault;
649: }
650: }
1.1 cgd 651: else if (!nflag) {
652: if (IN_CLASSA(i)) {
653: mask = IN_CLASSA_NET;
654: subnetshift = 8;
655: } else if (IN_CLASSB(i)) {
656: mask = IN_CLASSB_NET;
657: subnetshift = 8;
658: } else {
659: mask = IN_CLASSC_NET;
660: subnetshift = 4;
661: }
662: /*
663: * If there are more bits than the standard mask
664: * would suggest, subnets must be in use.
665: * Guess at the subnet mask, assuming reasonable
666: * width subnet fields.
667: */
1.17 gwr 668: while (i &~ mask)
1.27 ross 669: mask = (int32_t)mask >> subnetshift;
1.17 gwr 670: net = i & mask;
1.1 cgd 671: while ((mask & 1) == 0)
672: mask >>= 1, net >>= 1;
673: np = getnetbyaddr(net, AF_INET);
674: if (np)
675: cp = np->n_name;
676: }
1.20 mrg 677: if (cp) {
678: (void)strncpy(line, cp, sizeof(line) - 1);
679: line[sizeof(line) - 1] = '\0';
680: } else {
1.17 gwr 681: #if 0 /* XXX - This is silly... */
682: #define C(x) ((x) & 0xff)
683: if ((i & 0xffffff) == 0)
1.20 mrg 684: (void)snprintf(line, sizeof line, "%u",
685: C(i >> 24));
1.17 gwr 686: else if ((i & 0xffff) == 0)
1.20 mrg 687: (void)snprintf(line, sizeof line, "%u.%u",
688: C(i >> 24), C(i >> 16));
1.17 gwr 689: else if ((i & 0xff) == 0)
1.20 mrg 690: (void)snprintf(line, sizeof line, "%u.%u.%u",
691: C(i >> 24), C(i >> 16), C(i >> 8));
1.17 gwr 692: else
1.20 mrg 693: (void)snprintf(line, sizeof line, "%u.%u.%u.%u",
694: C(i >> 24), C(i >> 16), C(i >> 8), C(i));
1.17 gwr 695: #undef C
696: #else /* XXX */
1.20 mrg 697: (void)strncpy(line, inet_ntoa(in), sizeof(line) - 1);
1.17 gwr 698: #endif /* XXX */
1.20 mrg 699: }
1.1 cgd 700: break;
701:
1.17 gwr 702: case AF_LINK:
703: return (link_ntoa((struct sockaddr_dl *)sa));
704:
705: #ifndef SMALL
1.31 itojun 706: #ifdef INET6
707: case AF_INET6:
1.36 itojun 708: {
709: struct sockaddr_in6 sin6;
710: int niflags;
1.31 itojun 711:
1.36 itojun 712: #ifdef NI_WITHSCOPEID
713: niflags = NI_WITHSCOPEID;
714: #else
715: niflags = 0;
716: #endif
717: if (nflag)
718: niflags |= NI_NUMERICHOST;
719: memset(&sin6, 0, sizeof(sin6));
720: memcpy(&sin6, sa, sa->sa_len);
721: sin6.sin6_len = sizeof(struct sockaddr_in6);
722: sin6.sin6_family = AF_INET6;
723: #ifdef __KAME__
724: if (sa->sa_len == sizeof(struct sockaddr_in6) &&
1.37 itojun 725: (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
726: IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
1.36 itojun 727: sin6.sin6_scope_id == 0) {
728: sin6.sin6_scope_id =
729: ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
730: sin6.sin6_addr.s6_addr[2] = 0;
731: sin6.sin6_addr.s6_addr[3] = 0;
732: }
733: #endif
1.49 atatat 734: nml = netmask_length(nm, AF_INET6);
735: if (IN6_IS_ADDR_UNSPECIFIED(&sin6.sin6_addr)) {
736: if (nml == 0) {
737: strncpy(line, "::", sizeof(line) - 1);
738: line[sizeof(line) - 1] = '\0';
739: }
740: else
741: /* noncontiguous never happens in ipv6 */
742: snprintf(line, sizeof(line), "::/%d", nml);
743: }
744:
745: else if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
1.36 itojun 746: line, sizeof(line), NULL, 0, niflags) != 0)
747: strncpy(line, "invalid", sizeof(line));
748: break;
1.31 itojun 749: }
750: #endif
751:
1.1 cgd 752: case AF_NS:
753: return (ns_print((struct sockaddr_ns *)sa));
754:
755: case AF_ISO:
1.20 mrg 756: (void)snprintf(line, sizeof line, "iso %s",
1.1 cgd 757: iso_ntoa(&((struct sockaddr_iso *)sa)->siso_addr));
758: break;
1.30 lukem 759: #endif /* SMALL */
1.19 christos 760:
761: case AF_APPLETALK:
762: (void) snprintf(line, sizeof(line), "atalk %d.%d",
763: ((struct sockaddr_at *)sa)->sat_addr.s_net,
764: ((struct sockaddr_at *)sa)->sat_addr.s_node);
765: break;
1.1 cgd 766:
767: default:
1.20 mrg 768: (void)snprintf(line, sizeof line, "af %d: %s",
1.17 gwr 769: sa->sa_family, any_ntoa(sa));
1.1 cgd 770: break;
771: }
772: return (line);
773: }
774:
1.19 christos 775: static void
1.1 cgd 776: set_metric(value, key)
777: char *value;
778: int key;
779: {
1.7 mycroft 780: int flag = 0;
1.1 cgd 781: u_long noval, *valp = &noval;
782:
783: switch (key) {
784: #define caseof(x, y, z) case x: valp = &rt_metrics.z; flag = y; break
785: caseof(K_MTU, RTV_MTU, rmx_mtu);
786: caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount);
787: caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire);
788: caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe);
789: caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe);
790: caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh);
791: caseof(K_RTT, RTV_RTT, rmx_rtt);
792: caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar);
793: }
794: rtm_inits |= flag;
795: if (lockrest || locking)
796: rt_metrics.rmx_locks |= flag;
797: if (locking)
798: locking = 0;
799: *valp = atoi(value);
800: }
801:
1.52 christos 802: static int
1.1 cgd 803: newroute(argc, argv)
804: int argc;
1.23 lukem 805: char **argv;
1.1 cgd 806: {
1.29 mycroft 807: char *cmd, *dest = "", *gateway = "";
1.51 lukem 808: const char *error;
1.7 mycroft 809: int ishost = 0, ret, attempts, oerrno, flags = RTF_STATIC;
1.1 cgd 810: int key;
811: struct hostent *hp = 0;
812:
813: cmd = argv[0];
1.30 lukem 814: af = 0;
1.1 cgd 815: if (*cmd != 'g')
1.51 lukem 816: shutdown(sock, SHUT_RD); /* Don't want to read back our messages */
1.1 cgd 817: while (--argc > 0) {
818: if (**(++argv)== '-') {
819: switch (key = keyword(1 + *argv)) {
1.17 gwr 820:
821: case K_SA:
822: af = PF_ROUTE;
823: aflen = sizeof(union sockunion);
824: break;
825:
1.19 christos 826: case K_ATALK:
827: af = AF_APPLETALK;
828: aflen = sizeof(struct sockaddr_at);
829: break;
830:
1.17 gwr 831: case K_INET:
832: af = AF_INET;
833: aflen = sizeof(struct sockaddr_in);
834: break;
835:
1.31 itojun 836: #ifdef INET6
837: case K_INET6:
838: af = AF_INET6;
839: aflen = sizeof(struct sockaddr_in6);
840: break;
841: #endif
842:
1.1 cgd 843: case K_LINK:
844: af = AF_LINK;
845: aflen = sizeof(struct sockaddr_dl);
846: break;
1.17 gwr 847:
1.30 lukem 848: #ifndef SMALL
1.1 cgd 849: case K_OSI:
850: case K_ISO:
851: af = AF_ISO;
852: aflen = sizeof(struct sockaddr_iso);
853: break;
1.17 gwr 854:
1.1 cgd 855: case K_X25:
856: af = AF_CCITT;
857: aflen = sizeof(struct sockaddr_x25);
858: break;
1.17 gwr 859:
1.1 cgd 860: case K_XNS:
861: af = AF_NS;
862: aflen = sizeof(struct sockaddr_ns);
863: break;
1.30 lukem 864: #endif /* SMALL */
1.17 gwr 865:
1.1 cgd 866: case K_IFACE:
867: case K_INTERFACE:
868: iflag++;
1.14 mycroft 869: break;
1.7 mycroft 870: case K_NOSTATIC:
871: flags &= ~RTF_STATIC;
1.13 mycroft 872: break;
873: case K_LLINFO:
874: flags |= RTF_LLINFO;
1.1 cgd 875: break;
876: case K_LOCK:
877: locking = 1;
878: break;
879: case K_LOCKREST:
880: lockrest = 1;
881: break;
882: case K_HOST:
883: forcehost++;
884: break;
885: case K_REJECT:
886: flags |= RTF_REJECT;
887: break;
1.7 mycroft 888: case K_BLACKHOLE:
889: flags |= RTF_BLACKHOLE;
1.43 itojun 890: break;
891: case K_CLONED:
892: flags |= RTF_CLONED;
1.7 mycroft 893: break;
1.1 cgd 894: case K_PROTO1:
895: flags |= RTF_PROTO1;
896: break;
897: case K_PROTO2:
898: flags |= RTF_PROTO2;
899: break;
900: case K_CLONING:
901: flags |= RTF_CLONING;
902: break;
903: case K_XRESOLVE:
904: flags |= RTF_XRESOLVE;
905: break;
1.7 mycroft 906: case K_STATIC:
907: flags |= RTF_STATIC;
908: break;
1.1 cgd 909: case K_IFA:
1.21 thorpej 910: if (!--argc)
911: usage(1+*argv);
1.1 cgd 912: (void) getaddr(RTA_IFA, *++argv, 0);
913: break;
914: case K_IFP:
1.21 thorpej 915: if (!--argc)
916: usage(1+*argv);
1.1 cgd 917: (void) getaddr(RTA_IFP, *++argv, 0);
918: break;
919: case K_GENMASK:
1.21 thorpej 920: if (!--argc)
921: usage(1+*argv);
1.1 cgd 922: (void) getaddr(RTA_GENMASK, *++argv, 0);
923: break;
924: case K_GATEWAY:
1.21 thorpej 925: if (!--argc)
926: usage(1+*argv);
1.1 cgd 927: (void) getaddr(RTA_GATEWAY, *++argv, 0);
928: break;
929: case K_DST:
1.21 thorpej 930: if (!--argc)
931: usage(1+*argv);
1.1 cgd 932: ishost = getaddr(RTA_DST, *++argv, &hp);
933: dest = *argv;
934: break;
935: case K_NETMASK:
1.21 thorpej 936: if (!--argc)
937: usage(1+*argv);
1.1 cgd 938: (void) getaddr(RTA_NETMASK, *++argv, 0);
939: /* FALLTHROUGH */
940: case K_NET:
941: forcenet++;
942: break;
1.31 itojun 943: case K_PREFIXLEN:
1.60 itojun 944: if (!--argc)
945: usage(1+*argv);
1.61 itojun 946: ishost = prefixlen(*++argv);
1.31 itojun 947: break;
1.1 cgd 948: case K_MTU:
949: case K_HOPCOUNT:
950: case K_EXPIRE:
951: case K_RECVPIPE:
952: case K_SENDPIPE:
953: case K_SSTHRESH:
954: case K_RTT:
955: case K_RTTVAR:
1.21 thorpej 956: if (!--argc)
957: usage(1+*argv);
1.1 cgd 958: set_metric(*++argv, key);
959: break;
960: default:
961: usage(1+*argv);
962: }
963: } else {
964: if ((rtm_addrs & RTA_DST) == 0) {
965: dest = *argv;
966: ishost = getaddr(RTA_DST, *argv, &hp);
967: } else if ((rtm_addrs & RTA_GATEWAY) == 0) {
968: gateway = *argv;
969: (void) getaddr(RTA_GATEWAY, *argv, &hp);
970: } else {
1.51 lukem 971: ret = atoi(*argv);
1.7 mycroft 972:
1.1 cgd 973: if (ret == 0) {
1.15 pk 974: if (!qflag && strcmp(*argv, "0") == 0)
1.26 christos 975: warnx("%s, %s",
1.7 mycroft 976: "old usage of trailing 0",
1.26 christos 977: "assuming route to if");
1.7 mycroft 978: else
979: usage((char *)NULL);
1.1 cgd 980: iflag = 1;
981: continue;
982: } else if (ret > 0 && ret < 10) {
1.15 pk 983: if (!qflag) {
1.26 christos 984: warnx("%s, %s",
985: "old usage of trailing digit",
986: "assuming route via gateway");
1.15 pk 987: }
1.1 cgd 988: iflag = 0;
989: continue;
990: }
991: (void) getaddr(RTA_NETMASK, *argv, 0);
992: }
993: }
994: }
995: if (forcehost)
996: ishost = 1;
997: if (forcenet)
998: ishost = 0;
999: flags |= RTF_UP;
1000: if (ishost)
1001: flags |= RTF_HOST;
1002: if (iflag == 0)
1003: flags |= RTF_GATEWAY;
1004: for (attempts = 1; ; attempts++) {
1005: errno = 0;
1.7 mycroft 1006: if ((ret = rtmsg(*cmd, flags)) == 0)
1007: break;
1.1 cgd 1008: if (errno != ENETUNREACH && errno != ESRCH)
1009: break;
1.7 mycroft 1010: if (af == AF_INET && *gateway && hp && hp->h_addr_list[1]) {
1.1 cgd 1011: hp->h_addr_list++;
1.24 lukem 1012: memmove(&so_gate.sin.sin_addr, hp->h_addr_list[0],
1.1 cgd 1013: hp->h_length);
1014: } else
1015: break;
1016: }
1017: if (*cmd == 'g')
1.52 christos 1018: return rv;
1.1 cgd 1019: oerrno = errno;
1.15 pk 1020: if (!qflag) {
1021: (void) printf("%s %s %s", cmd, ishost? "host" : "net", dest);
1022: if (*gateway) {
1023: (void) printf(": gateway %s", gateway);
1024: if (attempts > 1 && ret == 0 && af == AF_INET)
1025: (void) printf(" (%s)",
1.40 itojun 1026: inet_ntoa(so_gate.sin.sin_addr));
1.15 pk 1027: }
1028: if (ret == 0)
1029: (void) printf("\n");
1030: }
1031: if (ret != 0) {
1.1 cgd 1032: switch (oerrno) {
1033: case ESRCH:
1.51 lukem 1034: error = "not in table";
1.1 cgd 1035: break;
1036: case EBUSY:
1.51 lukem 1037: error = "entry in use";
1.1 cgd 1038: break;
1039: case ENOBUFS:
1.51 lukem 1040: error = "routing table overflow";
1.1 cgd 1041: break;
1042: default:
1.51 lukem 1043: error = strerror(oerrno);
1.1 cgd 1044: break;
1045: }
1.51 lukem 1046: (void) printf(": %s\n", error);
1.52 christos 1047: return 1;
1.1 cgd 1048: }
1.52 christos 1049: return 0;
1.1 cgd 1050: }
1051:
1.19 christos 1052: static void
1.51 lukem 1053: inet_makenetandmask(net, isin)
1.27 ross 1054: u_int32_t net;
1.51 lukem 1055: struct sockaddr_in *isin;
1.1 cgd 1056: {
1.27 ross 1057: u_int32_t addr, mask = 0;
1.23 lukem 1058: char *cp;
1.1 cgd 1059:
1060: rtm_addrs |= RTA_NETMASK;
1061: if (net == 0)
1062: mask = addr = 0;
1063: else if (net < 128) {
1064: addr = net << IN_CLASSA_NSHIFT;
1065: mask = IN_CLASSA_NET;
1066: } else if (net < 65536) {
1067: addr = net << IN_CLASSB_NSHIFT;
1068: mask = IN_CLASSB_NET;
1069: } else if (net < 16777216L) {
1070: addr = net << IN_CLASSC_NSHIFT;
1071: mask = IN_CLASSC_NET;
1072: } else {
1073: addr = net;
1074: if ((addr & IN_CLASSA_HOST) == 0)
1075: mask = IN_CLASSA_NET;
1076: else if ((addr & IN_CLASSB_HOST) == 0)
1077: mask = IN_CLASSB_NET;
1078: else if ((addr & IN_CLASSC_HOST) == 0)
1079: mask = IN_CLASSC_NET;
1080: else
1081: mask = -1;
1082: }
1.51 lukem 1083: isin->sin_addr.s_addr = htonl(addr);
1084: isin = &so_mask.sin;
1085: isin->sin_addr.s_addr = htonl(mask);
1086: isin->sin_len = 0;
1087: isin->sin_family = 0;
1088: cp = (char *)(&isin->sin_addr + 1);
1089: while (*--cp == 0 && cp > (char *)isin)
1.1 cgd 1090: ;
1.51 lukem 1091: isin->sin_len = 1 + cp - (char *)isin;
1.1 cgd 1092: }
1093:
1.36 itojun 1094: #ifdef INET6
1095: /*
1096: * XXX the function may need more improvement...
1097: */
1.54 itojun 1098: static int
1.36 itojun 1099: inet6_makenetandmask(sin6)
1100: struct sockaddr_in6 *sin6;
1101: {
1102: char *plen;
1103: struct in6_addr in6;
1104:
1105: plen = NULL;
1106: if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
1107: sin6->sin6_scope_id == 0) {
1108: plen = "0";
1109: } else if ((sin6->sin6_addr.s6_addr[0] & 0xe0) == 0x20) {
1110: /* aggregatable global unicast - RFC2374 */
1111: memset(&in6, 0, sizeof(in6));
1112: if (!memcmp(&sin6->sin6_addr.s6_addr[8], &in6.s6_addr[8], 8))
1113: plen = "64";
1114: }
1115:
1.56 itojun 1116: if (!plen || strcmp(plen, "128") == 0)
1117: return 1;
1118: else {
1.36 itojun 1119: rtm_addrs |= RTA_NETMASK;
1.56 itojun 1120: (void)prefixlen(plen);
1121: return 0;
1.36 itojun 1122: }
1123: }
1124: #endif
1125:
1.1 cgd 1126: /*
1127: * Interpret an argument as a network address of some kind,
1128: * returning 1 if a host address, 0 if a network address.
1129: */
1.19 christos 1130: static int
1.1 cgd 1131: getaddr(which, s, hpp)
1132: int which;
1133: char *s;
1134: struct hostent **hpp;
1135: {
1.23 lukem 1136: sup su;
1.1 cgd 1137: struct hostent *hp;
1138: struct netent *np;
1.27 ross 1139: u_int32_t val;
1.19 christos 1140: char *t;
1.31 itojun 1141: int afamily; /* local copy of af so we can change it */
1.1 cgd 1142:
1143: if (af == 0) {
1144: af = AF_INET;
1145: aflen = sizeof(struct sockaddr_in);
1146: }
1.31 itojun 1147: afamily = af;
1.1 cgd 1148: rtm_addrs |= which;
1149: switch (which) {
1.7 mycroft 1150: case RTA_DST:
1151: su = &so_dst;
1152: break;
1153: case RTA_GATEWAY:
1154: su = &so_gate;
1155: break;
1156: case RTA_NETMASK:
1157: su = &so_mask;
1158: break;
1159: case RTA_GENMASK:
1160: su = &so_genmask;
1161: break;
1162: case RTA_IFP:
1163: su = &so_ifp;
1.31 itojun 1164: afamily = AF_LINK;
1.7 mycroft 1165: break;
1166: case RTA_IFA:
1167: su = &so_ifa;
1168: su->sa.sa_family = af;
1169: break;
1170: default:
1.19 christos 1171: su = NULL;
1.7 mycroft 1172: usage("Internal Error");
1173: /*NOTREACHED*/
1.1 cgd 1174: }
1175: su->sa.sa_len = aflen;
1.31 itojun 1176: su->sa.sa_family = afamily; /* cases that don't want it have left already */
1.1 cgd 1177: if (strcmp(s, "default") == 0) {
1178: switch (which) {
1179: case RTA_DST:
1180: forcenet++;
1181: (void) getaddr(RTA_NETMASK, s, 0);
1182: break;
1183: case RTA_NETMASK:
1184: case RTA_GENMASK:
1185: su->sa.sa_len = 0;
1186: }
1.7 mycroft 1187: return (0);
1.1 cgd 1188: }
1.31 itojun 1189: switch (afamily) {
1.17 gwr 1190: #ifndef SMALL
1.31 itojun 1191: #ifdef INET6
1192: case AF_INET6:
1.36 itojun 1193: {
1194: struct addrinfo hints, *res;
1195:
1196: memset(&hints, 0, sizeof(hints));
1197: hints.ai_family = afamily; /*AF_INET6*/
1198: hints.ai_flags = AI_NUMERICHOST;
1199: hints.ai_socktype = SOCK_DGRAM; /*dummy*/
1.58 itojun 1200: if (getaddrinfo(s, "0", &hints, &res) != 0) {
1201: hints.ai_flags = 0;
1202: if (getaddrinfo(s, "0", &hints, &res) != 0) {
1203: (void) fprintf(stderr, "%s: bad value\n", s);
1204: exit(1);
1205: }
1206: }
1207: if (sizeof(su->sin6) != res->ai_addrlen) {
1.31 itojun 1208: (void) fprintf(stderr, "%s: bad value\n", s);
1209: exit(1);
1210: }
1.58 itojun 1211: if (res->ai_next) {
1212: (void) fprintf(stderr,
1213: "%s: resolved to multiple values\n", s);
1214: exit(1);
1215: }
1.36 itojun 1216: memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6));
1.58 itojun 1217: freeaddrinfo(res);
1.36 itojun 1218: #ifdef __KAME__
1.37 itojun 1219: if ((IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr) ||
1220: IN6_IS_ADDR_MC_LINKLOCAL(&su->sin6.sin6_addr)) &&
1.36 itojun 1221: su->sin6.sin6_scope_id) {
1222: *(u_int16_t *)&su->sin6.sin6_addr.s6_addr[2] =
1223: htons(su->sin6.sin6_scope_id);
1224: su->sin6.sin6_scope_id = 0;
1225: }
1226: #endif
1.58 itojun 1227: if (hints.ai_flags == AI_NUMERICHOST) {
1228: if (which == RTA_DST)
1229: return (inet6_makenetandmask(&su->sin6));
1230: return (0);
1231: } else
1232: return (1);
1.36 itojun 1233: }
1.31 itojun 1234: #endif
1235:
1.7 mycroft 1236: case AF_NS:
1237: if (which == RTA_DST) {
1238: struct sockaddr_ns *sms = &(so_mask.sns);
1.8 mycroft 1239: memset(sms, 0, sizeof(*sms));
1.7 mycroft 1240: sms->sns_family = 0;
1241: sms->sns_len = 6;
1242: sms->sns_addr.x_net = *(union ns_net *)ns_bh;
1243: rtm_addrs |= RTA_NETMASK;
1244: }
1245: su->sns.sns_addr = ns_addr(s);
1246: return (!ns_nullhost(su->sns.sns_addr));
1247:
1248: case AF_OSI:
1249: su->siso.siso_addr = *iso_addr(s);
1250: if (which == RTA_NETMASK || which == RTA_GENMASK) {
1.23 lukem 1251: char *cp = (char *)TSEL(&su->siso);
1.7 mycroft 1252: su->siso.siso_nlen = 0;
1253: do {--cp ;} while ((cp > (char *)su) && (*cp == 0));
1254: su->siso.siso_len = 1 + cp - (char *)su;
1255: }
1256: return (1);
1257:
1258: case AF_CCITT:
1259: ccitt_addr(s, &su->sx25);
1260: return (which == RTA_DST ? x25_makemask() : 1);
1.17 gwr 1261: #endif /* SMALL */
1.7 mycroft 1262:
1263: case PF_ROUTE:
1264: su->sa.sa_len = sizeof(*su);
1265: sockaddr(s, &su->sa);
1266: return (1);
1267:
1.19 christos 1268: case AF_APPLETALK:
1269: t = strchr (s, '.');
1270: if (!t) {
1271: badataddr:
1.26 christos 1272: errx(1, "bad address: %s", s);
1.19 christos 1273: }
1274: val = atoi (s);
1275: if (val > 65535)
1276: goto badataddr;
1277: su->sat.sat_addr.s_net = val;
1278: val = atoi (t);
1279: if (val > 256)
1280: goto badataddr;
1281: su->sat.sat_addr.s_node = val;
1282: rtm_addrs |= RTA_NETMASK;
1283: return(forcehost || su->sat.sat_addr.s_node != 0);
1284:
1.17 gwr 1285: case AF_LINK:
1286: link_addr(s, &su->sdl);
1287: return (1);
1288:
1.7 mycroft 1289: case AF_INET:
1290: default:
1291: break;
1292: }
1293:
1.1 cgd 1294: if (hpp == NULL)
1295: hpp = &hp;
1296: *hpp = NULL;
1.16 cgd 1297: if (((val = inet_addr(s)) != INADDR_NONE) &&
1.1 cgd 1298: (which != RTA_DST || forcenet == 0)) {
1299: su->sin.sin_addr.s_addr = val;
1300: if (inet_lnaof(su->sin.sin_addr) != INADDR_ANY)
1301: return (1);
1302: else {
1303: val = ntohl(val);
1.7 mycroft 1304: goto netdone;
1.1 cgd 1305: }
1306: }
1.16 cgd 1307: if ((val = inet_network(s)) != INADDR_NONE ||
1.7 mycroft 1308: ((np = getnetbyname(s)) != NULL && (val = np->n_net) != 0)) {
1309: netdone:
1310: if (which == RTA_DST)
1311: inet_makenetandmask(val, &su->sin);
1312: return (0);
1.1 cgd 1313: }
1314: hp = gethostbyname(s);
1315: if (hp) {
1316: *hpp = hp;
1317: su->sin.sin_family = hp->h_addrtype;
1.24 lukem 1318: memmove(&su->sin.sin_addr, hp->h_addr, hp->h_length);
1.1 cgd 1319: return (1);
1320: }
1.26 christos 1321: errx(1, "bad value: %s", s);
1.7 mycroft 1322: }
1323:
1.31 itojun 1324: int
1325: prefixlen(s)
1326: char *s;
1327: {
1328: int len = atoi(s), q, r;
1.47 itojun 1329: int max;
1330:
1331: switch (af) {
1332: case AF_INET:
1333: max = sizeof(struct in_addr) * 8;
1334: break;
1335: #ifdef INET6
1336: case AF_INET6:
1337: max = sizeof(struct in6_addr) * 8;
1338: break;
1339: #endif
1340: default:
1341: (void) fprintf(stderr,
1342: "prefixlen is not supported with af %d\n", af);
1343: exit(1);
1344: }
1.31 itojun 1345:
1346: rtm_addrs |= RTA_NETMASK;
1.48 itojun 1347: if (len < -1 || len > max) {
1.31 itojun 1348: (void) fprintf(stderr, "%s: bad value\n", s);
1349: exit(1);
1350: }
1351:
1352: q = len >> 3;
1353: r = len & 7;
1.47 itojun 1354: switch (af) {
1355: case AF_INET:
1356: memset(&so_mask, 0, sizeof(so_mask));
1357: so_mask.sin.sin_family = AF_INET;
1358: so_mask.sin.sin_len = sizeof(struct sockaddr_in);
1359: so_mask.sin.sin_addr.s_addr = htonl(0xffffffff << (32 - len));
1360: break;
1361: #ifdef INET6
1362: case AF_INET6:
1363: so_mask.sin6.sin6_family = AF_INET6;
1364: so_mask.sin6.sin6_len = sizeof(struct sockaddr_in6);
1365: memset((void *)&so_mask.sin6.sin6_addr, 0,
1366: sizeof(so_mask.sin6.sin6_addr));
1367: if (q > 0)
1368: memset((void *)&so_mask.sin6.sin6_addr, 0xff, q);
1369: if (r > 0)
1370: *((u_char *)&so_mask.sin6.sin6_addr + q) =
1371: (0xff00 >> r) & 0xff;
1372: break;
1373: #endif
1374: }
1.61 itojun 1375: return (len == max);
1.31 itojun 1376: }
1377:
1.38 sommerfe 1378: #ifndef SMALL
1.7 mycroft 1379: int
1380: x25_makemask()
1381: {
1.23 lukem 1382: char *cp;
1.7 mycroft 1383:
1384: if ((rtm_addrs & RTA_NETMASK) == 0) {
1.1 cgd 1385: rtm_addrs |= RTA_NETMASK;
1.7 mycroft 1386: for (cp = (char *)&so_mask.sx25.x25_net;
1387: cp < &so_mask.sx25.x25_opts.op_flags; cp++)
1388: *cp = -1;
1389: so_mask.sx25.x25_len = (u_char)&(((sup)0)->sx25.x25_opts);
1.1 cgd 1390: }
1.7 mycroft 1391: return 0;
1.1 cgd 1392: }
1393:
1394:
1395: char *
1396: ns_print(sns)
1397: struct sockaddr_ns *sns;
1398: {
1399: struct ns_addr work;
1.27 ross 1400: union { union ns_net net_e; u_int32_t int32_t_e; } net;
1.1 cgd 1401: u_short port;
1402: static char mybuf[50], cport[10], chost[25];
1403: char *host = "";
1.23 lukem 1404: char *p;
1405: u_char *q;
1.1 cgd 1406:
1407: work = sns->sns_addr;
1408: port = ntohs(work.x_port);
1409: work.x_port = 0;
1410: net.net_e = work.x_net;
1.27 ross 1411: if (ns_nullhost(work) && net.int32_t_e == 0) {
1.1 cgd 1412: if (!port)
1413: return ("*.*");
1.20 mrg 1414: (void)snprintf(mybuf, sizeof mybuf, "*.%XH", port);
1.1 cgd 1415: return (mybuf);
1416: }
1417:
1.9 mycroft 1418: if (memcmp(ns_bh, work.x_host.c_host, 6) == 0)
1.1 cgd 1419: host = "any";
1.9 mycroft 1420: else if (memcmp(ns_nullh, work.x_host.c_host, 6) == 0)
1.1 cgd 1421: host = "*";
1422: else {
1423: q = work.x_host.c_host;
1.20 mrg 1424: (void)snprintf(chost, sizeof chost, "%02X%02X%02X%02X%02X%02XH",
1.1 cgd 1425: q[0], q[1], q[2], q[3], q[4], q[5]);
1426: for (p = chost; *p == '0' && p < chost + 12; p++)
1427: /* void */;
1428: host = p;
1429: }
1430: if (port)
1.20 mrg 1431: (void)snprintf(cport, sizeof cport, ".%XH", htons(port));
1.1 cgd 1432: else
1433: *cport = 0;
1434:
1.20 mrg 1435: (void)snprintf(mybuf, sizeof mybuf, "%XH.%s%s",
1.27 ross 1436: (u_int32_t)ntohl(net.int32_t_e), host, cport);
1.1 cgd 1437: return (mybuf);
1438: }
1439:
1.19 christos 1440: static void
1.7 mycroft 1441: interfaces()
1442: {
1443: size_t needed;
1444: int mib[6];
1445: char *buf, *lim, *next;
1.23 lukem 1446: struct rt_msghdr *rtm;
1.7 mycroft 1447:
1448: mib[0] = CTL_NET;
1449: mib[1] = PF_ROUTE;
1450: mib[2] = 0; /* protocol */
1451: mib[3] = 0; /* wildcard address family */
1452: mib[4] = NET_RT_IFLIST;
1453: mib[5] = 0; /* no flags */
1454: if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
1.26 christos 1455: err(1, "route-sysctl-estimate");
1.7 mycroft 1456: if ((buf = malloc(needed)) == NULL)
1.26 christos 1457: err(1, "malloc");
1.7 mycroft 1458: if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
1.26 christos 1459: err(1, "actual retrieval of interface table");
1.7 mycroft 1460: lim = buf + needed;
1461: for (next = buf; next < lim; next += rtm->rtm_msglen) {
1462: rtm = (struct rt_msghdr *)next;
1463: print_rtmsg(rtm, rtm->rtm_msglen);
1464: }
1465: }
1466:
1.19 christos 1467: static void
1.1 cgd 1468: monitor()
1469: {
1470: int n;
1471: char msg[2048];
1472:
1473: verbose = 1;
1.7 mycroft 1474: if (debugonly) {
1475: interfaces();
1476: exit(0);
1477: }
1.1 cgd 1478: for(;;) {
1.32 mjacob 1479: time_t now;
1.51 lukem 1480: n = read(sock, msg, 2048);
1.31 itojun 1481: now = time(NULL);
1482: (void) printf("got message of size %d on %s", n, ctime(&now));
1.7 mycroft 1483: print_rtmsg((struct rt_msghdr *)msg, n);
1.1 cgd 1484: }
1485: }
1486:
1.17 gwr 1487: #endif /* SMALL */
1488:
1489:
1.1 cgd 1490: struct {
1491: struct rt_msghdr m_rtm;
1492: char m_space[512];
1493: } m_rtmsg;
1494:
1.19 christos 1495: static int
1.1 cgd 1496: rtmsg(cmd, flags)
1497: int cmd, flags;
1498: {
1499: static int seq;
1500: int rlen;
1.23 lukem 1501: char *cp = m_rtmsg.m_space;
1502: int l;
1.1 cgd 1503:
1504: #define NEXTADDR(w, u) \
1505: if (rtm_addrs & (w)) {\
1.24 lukem 1506: l = ROUNDUP(u.sa.sa_len); memmove(cp, &(u), l); cp += l;\
1.50 atatat 1507: if (verbose && ! shortoutput) sodump(&(u),"u");\
1.1 cgd 1508: }
1509:
1510: errno = 0;
1.8 mycroft 1511: memset(&m_rtmsg, 0, sizeof(m_rtmsg));
1.1 cgd 1512: if (cmd == 'a')
1513: cmd = RTM_ADD;
1514: else if (cmd == 'c')
1515: cmd = RTM_CHANGE;
1.7 mycroft 1516: else if (cmd == 'g') {
1.17 gwr 1517: #ifdef SMALL
1518: return (-1);
1519: #else /* SMALL */
1.1 cgd 1520: cmd = RTM_GET;
1.7 mycroft 1521: if (so_ifp.sa.sa_family == 0) {
1.10 cgd 1522: so_ifp.sa.sa_family = AF_LINK;
1523: so_ifp.sa.sa_len = sizeof(struct sockaddr_dl);
1.7 mycroft 1524: rtm_addrs |= RTA_IFP;
1525: }
1.17 gwr 1526: #endif /* SMALL */
1.7 mycroft 1527: } else
1.1 cgd 1528: cmd = RTM_DELETE;
1529: #define rtm m_rtmsg.m_rtm
1530: rtm.rtm_type = cmd;
1531: rtm.rtm_flags = flags;
1532: rtm.rtm_version = RTM_VERSION;
1533: rtm.rtm_seq = ++seq;
1534: rtm.rtm_addrs = rtm_addrs;
1535: rtm.rtm_rmx = rt_metrics;
1536: rtm.rtm_inits = rtm_inits;
1537:
1538: if (rtm_addrs & RTA_NETMASK)
1539: mask_addr();
1540: NEXTADDR(RTA_DST, so_dst);
1541: NEXTADDR(RTA_GATEWAY, so_gate);
1542: NEXTADDR(RTA_NETMASK, so_mask);
1543: NEXTADDR(RTA_GENMASK, so_genmask);
1544: NEXTADDR(RTA_IFP, so_ifp);
1545: NEXTADDR(RTA_IFA, so_ifa);
1546: rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
1.50 atatat 1547: if (verbose && ! shortoutput)
1.1 cgd 1548: print_rtmsg(&rtm, l);
1549: if (debugonly)
1.7 mycroft 1550: return (0);
1.51 lukem 1551: if ((rlen = write(sock, (char *)&m_rtmsg, l)) < 0) {
1.1 cgd 1552: perror("writing to routing socket");
1553: return (-1);
1554: }
1.17 gwr 1555: #ifndef SMALL
1.1 cgd 1556: if (cmd == RTM_GET) {
1557: do {
1.51 lukem 1558: l = read(sock, (char *)&m_rtmsg, sizeof(m_rtmsg));
1.1 cgd 1559: } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
1560: if (l < 0)
1.26 christos 1561: err(1, "read from routing socket");
1.1 cgd 1562: else
1563: print_getmsg(&rtm, l);
1564: }
1.17 gwr 1565: #endif /* SMALL */
1.1 cgd 1566: #undef rtm
1567: return (0);
1568: }
1569:
1.19 christos 1570: static void
1.7 mycroft 1571: mask_addr()
1572: {
1573: int olen = so_mask.sa.sa_len;
1.23 lukem 1574: char *cp1 = olen + (char *)&so_mask, *cp2;
1.1 cgd 1575:
1.7 mycroft 1576: for (so_mask.sa.sa_len = 0; cp1 > (char *)&so_mask; )
1577: if (*--cp1 != 0) {
1578: so_mask.sa.sa_len = 1 + cp1 - (char *)&so_mask;
1579: break;
1580: }
1.1 cgd 1581: if ((rtm_addrs & RTA_DST) == 0)
1582: return;
1.7 mycroft 1583: switch (so_dst.sa.sa_family) {
1.30 lukem 1584: case AF_INET:
1.31 itojun 1585: #ifdef INET6
1586: case AF_INET6:
1587: #endif
1.30 lukem 1588: case AF_APPLETALK:
1589: #ifndef SMALL
1.1 cgd 1590: case AF_NS:
1.7 mycroft 1591: case AF_CCITT:
1.30 lukem 1592: #endif /* SMALL */
1.7 mycroft 1593: case 0:
1.1 cgd 1594: return;
1.30 lukem 1595: #ifndef SMALL
1.1 cgd 1596: case AF_ISO:
1.7 mycroft 1597: olen = MIN(so_dst.siso.siso_nlen,
1598: MAX(so_mask.sa.sa_len - 6, 0));
1599: break;
1.30 lukem 1600: #endif /* SMALL */
1.1 cgd 1601: }
1602: cp1 = so_mask.sa.sa_len + 1 + (char *)&so_dst;
1603: cp2 = so_dst.sa.sa_len + 1 + (char *)&so_dst;
1604: while (cp2 > cp1)
1605: *--cp2 = 0;
1606: cp2 = so_mask.sa.sa_len + 1 + (char *)&so_mask;
1607: while (cp1 > so_dst.sa.sa_data)
1608: *--cp1 &= *--cp2;
1.30 lukem 1609: #ifndef SMALL
1.7 mycroft 1610: switch (so_dst.sa.sa_family) {
1.1 cgd 1611: case AF_ISO:
1612: so_dst.siso.siso_nlen = olen;
1.7 mycroft 1613: break;
1.1 cgd 1614: }
1.30 lukem 1615: #endif /* SMALL */
1.1 cgd 1616: }
1617:
1618: char *msgtypes[] = {
1619: "",
1620: "RTM_ADD: Add Route",
1621: "RTM_DELETE: Delete Route",
1622: "RTM_CHANGE: Change Metrics or flags",
1623: "RTM_GET: Report Metrics",
1624: "RTM_LOSING: Kernel Suspects Partitioning",
1625: "RTM_REDIRECT: Told to use different route",
1626: "RTM_MISS: Lookup failed on this address",
1627: "RTM_LOCK: fix specified metrics",
1628: "RTM_OLDADD: caused by SIOCADDRT",
1629: "RTM_OLDDEL: caused by SIOCDELRT",
1.7 mycroft 1630: "RTM_RESOLVE: Route created by cloning",
1631: "RTM_NEWADDR: address being added to iface",
1632: "RTM_DELADDR: address being removed from iface",
1.39 itojun 1633: "RTM_OIFINFO: iface status change (pre-1.5)",
1.7 mycroft 1634: "RTM_IFINFO: iface status change",
1.39 itojun 1635: "RTM_IFANNOUNCE: iface arrival/departure",
1.1 cgd 1636: 0,
1637: };
1638:
1639: char metricnames[] =
1.7 mycroft 1640: "\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount\1mtu";
1641: char routeflags[] =
1.42 itojun 1642: "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE\016CLONED\017PROTO2\020PROTO1";
1.7 mycroft 1643: char ifnetflags[] =
1644: "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6NOTRAILERS\7RUNNING\010NOARP\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1\017LINK2\020MULTICAST";
1645: char addrnames[] =
1646: "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
1.1 cgd 1647:
1.53 christos 1648:
1649: #ifndef SMALL
1650: static const char *
1651: linkstate(ifm)
1652: struct if_msghdr *ifm;
1653: {
1654: static char buf[64];
1655:
1656: switch (ifm->ifm_data.ifi_link_state) {
1657: case LINK_STATE_UNKNOWN:
1658: return "carrier: unknown";
1659: case LINK_STATE_DOWN:
1660: return "carrier: no carrier";
1661: case LINK_STATE_UP:
1662: return "carrier: active";
1663: default:
1664: (void)snprintf(buf, sizeof(buf), "carrier: 0x%x",
1665: ifm->ifm_data.ifi_link_state);
1666: return buf;
1667: }
1668: }
1669: #endif /* SMALL */
1670:
1.19 christos 1671: static void
1.1 cgd 1672: print_rtmsg(rtm, msglen)
1.23 lukem 1673: struct rt_msghdr *rtm;
1.1 cgd 1674: int msglen;
1675: {
1.7 mycroft 1676: struct if_msghdr *ifm;
1677: struct ifa_msghdr *ifam;
1.39 itojun 1678: struct if_announcemsghdr *ifan;
1.7 mycroft 1679:
1.1 cgd 1680: if (verbose == 0)
1681: return;
1682: if (rtm->rtm_version != RTM_VERSION) {
1683: (void) printf("routing message version %d not understood\n",
1684: rtm->rtm_version);
1685: return;
1686: }
1.39 itojun 1687: if (msgtypes[rtm->rtm_type])
1688: (void)printf("%s: ", msgtypes[rtm->rtm_type]);
1689: else
1690: (void)printf("#%d: ", rtm->rtm_type);
1691: (void)printf("len %d, ", rtm->rtm_msglen);
1.7 mycroft 1692: switch (rtm->rtm_type) {
1693: case RTM_IFINFO:
1694: ifm = (struct if_msghdr *)rtm;
1.53 christos 1695: (void) printf("if# %d, %s, flags:", ifm->ifm_index,
1696: #ifdef SMALL
1697: ""
1698: #else
1699: linkstate(ifm)
1700: #endif /* SMALL */
1701: );
1.7 mycroft 1702: bprintf(stdout, ifm->ifm_flags, ifnetflags);
1703: pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs);
1704: break;
1705: case RTM_NEWADDR:
1706: case RTM_DELADDR:
1707: ifam = (struct ifa_msghdr *)rtm;
1708: (void) printf("metric %d, flags:", ifam->ifam_metric);
1709: bprintf(stdout, ifam->ifam_flags, routeflags);
1710: pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs);
1.39 itojun 1711: break;
1712: case RTM_IFANNOUNCE:
1713: ifan = (struct if_announcemsghdr *)rtm;
1714: (void) printf("if# %d, what: ", ifan->ifan_index);
1715: switch (ifan->ifan_what) {
1716: case IFAN_ARRIVAL:
1717: printf("arrival");
1718: break;
1719: case IFAN_DEPARTURE:
1720: printf("departure");
1721: break;
1722: default:
1723: printf("#%d", ifan->ifan_what);
1724: break;
1725: }
1726: printf("\n");
1.7 mycroft 1727: break;
1728: default:
1729: (void) printf("pid: %d, seq %d, errno %d, flags:",
1730: rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno);
1731: bprintf(stdout, rtm->rtm_flags, routeflags);
1732: pmsg_common(rtm);
1733: }
1.1 cgd 1734: }
1735:
1.17 gwr 1736: #ifndef SMALL
1.19 christos 1737: static void
1.1 cgd 1738: print_getmsg(rtm, msglen)
1.23 lukem 1739: struct rt_msghdr *rtm;
1.1 cgd 1740: int msglen;
1741: {
1.34 sommerfe 1742: struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL, *ifa = NULL;
1.7 mycroft 1743: struct sockaddr_dl *ifp = NULL;
1.23 lukem 1744: struct sockaddr *sa;
1745: char *cp;
1746: int i;
1.7 mycroft 1747:
1.50 atatat 1748: if (! shortoutput)
1749: (void) printf(" route to: %s\n",
1750: routename((struct sockaddr *) &so_dst, NULL, RTF_HOST));
1.1 cgd 1751: if (rtm->rtm_version != RTM_VERSION) {
1.26 christos 1752: warnx("routing message version %d not understood",
1.1 cgd 1753: rtm->rtm_version);
1754: return;
1755: }
1756: if (rtm->rtm_msglen > msglen) {
1.59 grant 1757: warnx("message length mismatch, in packet %d, returned %d",
1.1 cgd 1758: rtm->rtm_msglen, msglen);
1759: }
1.7 mycroft 1760: if (rtm->rtm_errno) {
1.26 christos 1761: warn("RTM_GET");
1.7 mycroft 1762: return;
1763: }
1764: cp = ((char *)(rtm + 1));
1765: if (rtm->rtm_addrs)
1766: for (i = 1; i; i <<= 1)
1767: if (i & rtm->rtm_addrs) {
1768: sa = (struct sockaddr *)cp;
1769: switch (i) {
1770: case RTA_DST:
1771: dst = sa;
1772: break;
1773: case RTA_GATEWAY:
1774: gate = sa;
1775: break;
1776: case RTA_NETMASK:
1777: mask = sa;
1778: break;
1779: case RTA_IFP:
1780: if (sa->sa_family == AF_LINK &&
1781: ((struct sockaddr_dl *)sa)->sdl_nlen)
1782: ifp = (struct sockaddr_dl *)sa;
1783: break;
1.34 sommerfe 1784: case RTA_IFA:
1785: ifa = sa;
1786: break;
1.7 mycroft 1787: }
1788: ADVANCE(cp, sa);
1789: }
1790: if (dst && mask)
1791: mask->sa_family = dst->sa_family; /* XXX */
1.50 atatat 1792: if (dst && ! shortoutput)
1.49 atatat 1793: (void)printf("destination: %s\n",
1794: routename(dst, mask, RTF_HOST));
1.50 atatat 1795: if (mask && ! shortoutput) {
1.7 mycroft 1796: int savenflag = nflag;
1797:
1798: nflag = 1;
1.49 atatat 1799: (void)printf(" mask: %s\n",
1800: routename(mask, NULL, RTF_HOST));
1.7 mycroft 1801: nflag = savenflag;
1802: }
1.50 atatat 1803: if (gate && rtm->rtm_flags & RTF_GATEWAY && ! shortoutput)
1.49 atatat 1804: (void)printf(" gateway: %s\n",
1805: routename(gate, NULL, RTF_HOST));
1.50 atatat 1806: if (ifa && ! shortoutput)
1.49 atatat 1807: (void)printf(" local addr: %s\n",
1808: routename(ifa, NULL, RTF_HOST));
1.50 atatat 1809: if (ifp && ! shortoutput)
1.7 mycroft 1810: (void)printf(" interface: %.*s\n",
1811: ifp->sdl_nlen, ifp->sdl_data);
1.50 atatat 1812: if (! shortoutput) {
1813: (void)printf(" flags: ");
1814: bprintf(stdout, rtm->rtm_flags, routeflags);
1815: }
1.7 mycroft 1816:
1817: #define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ')
1818: #define msec(u) (((u) + 500) / 1000) /* usec to msec */
1819:
1.50 atatat 1820: if (! shortoutput) {
1821: (void) printf("\n%s\n", "\
1.7 mycroft 1822: recvpipe sendpipe ssthresh rtt,msec rttvar hopcount mtu expire");
1.50 atatat 1823: printf("%8ld%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE));
1824: printf("%8ld%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE));
1825: printf("%8ld%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH));
1826: printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT));
1827: printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR));
1828: printf("%8ld%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT));
1829: printf("%8ld%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU));
1830: if (rtm->rtm_rmx.rmx_expire)
1831: rtm->rtm_rmx.rmx_expire -= time(0);
1832: printf("%8ld%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE));
1833: }
1.7 mycroft 1834: #undef lock
1835: #undef msec
1836: #define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD)
1.50 atatat 1837:
1838: if ((rtm->rtm_addrs & RTF_GATEWAY) == 0)
1839: rv = 1;
1840: else {
1.51 lukem 1841: char *name;
1842: int addrs;
1.50 atatat 1843:
1844: cp = (char *)(rtm + 1);
1845: addrs = rtm->rtm_addrs;
1846:
1847: for (i = 1; i; i <<= 1) {
1848: sa = (struct sockaddr *)cp;
1849: if (i == RTF_GATEWAY) {
1850: name = routename(sa, NULL, RTF_HOST);
1851: if (name[0] == '\0')
1852: rv = 1;
1853: else if (shortoutput)
1854: printf("%s\n", name);
1855: }
1856: if (i & addrs)
1857: ADVANCE(cp, sa);
1858: }
1859: }
1860:
1861: if (shortoutput)
1862: return;
1863: else if (verbose)
1.7 mycroft 1864: pmsg_common(rtm);
1865: else if (rtm->rtm_addrs &~ RTA_IGN) {
1866: (void) printf("sockaddrs: ");
1867: bprintf(stdout, rtm->rtm_addrs, addrnames);
1868: putchar('\n');
1869: }
1870: #undef RTA_IGN
1.1 cgd 1871: }
1.17 gwr 1872: #endif /* SMALL */
1.1 cgd 1873:
1874: void
1875: pmsg_common(rtm)
1.23 lukem 1876: struct rt_msghdr *rtm;
1.1 cgd 1877: {
1878: (void) printf("\nlocks: ");
1879: bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames);
1880: (void) printf(" inits: ");
1881: bprintf(stdout, rtm->rtm_inits, metricnames);
1.7 mycroft 1882: pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs);
1883: }
1884:
1.19 christos 1885: static void
1.7 mycroft 1886: pmsg_addrs(cp, addrs)
1887: char *cp;
1888: int addrs;
1889: {
1.23 lukem 1890: struct sockaddr *sa;
1.7 mycroft 1891: int i;
1892:
1.46 bad 1893: if (addrs != 0) {
1894: (void) printf("\nsockaddrs: ");
1895: bprintf(stdout, addrs, addrnames);
1896: (void) putchar('\n');
1897: for (i = 1; i; i <<= 1)
1898: if (i & addrs) {
1899: sa = (struct sockaddr *)cp;
1.49 atatat 1900: (void) printf(" %s",
1901: routename(sa, NULL, RTF_HOST));
1.46 bad 1902: ADVANCE(cp, sa);
1903: }
1904: }
1.1 cgd 1905: (void) putchar('\n');
1906: (void) fflush(stdout);
1907: }
1908:
1.19 christos 1909: static void
1.1 cgd 1910: bprintf(fp, b, s)
1.23 lukem 1911: FILE *fp;
1912: int b;
1913: u_char *s;
1.1 cgd 1914: {
1.23 lukem 1915: int i;
1.1 cgd 1916: int gotsome = 0;
1917:
1918: if (b == 0)
1919: return;
1.19 christos 1920: while ((i = *s++) != 0) {
1.1 cgd 1921: if (b & (1 << (i-1))) {
1922: if (gotsome == 0)
1923: i = '<';
1924: else
1925: i = ',';
1926: (void) putc(i, fp);
1927: gotsome = 1;
1928: for (; (i = *s) > 32; s++)
1929: (void) putc(i, fp);
1930: } else
1931: while (*s > 32)
1932: s++;
1933: }
1934: if (gotsome)
1935: (void) putc('>', fp);
1936: }
1937:
1.19 christos 1938: static int
1.1 cgd 1939: keyword(cp)
1940: char *cp;
1941: {
1.23 lukem 1942: struct keytab *kt = keywords;
1.1 cgd 1943:
1944: while (kt->kt_cp && strcmp(kt->kt_cp, cp))
1945: kt++;
1946: return kt->kt_i;
1947: }
1948:
1.19 christos 1949: static void
1.1 cgd 1950: sodump(su, which)
1.23 lukem 1951: sup su;
1.1 cgd 1952: char *which;
1953: {
1.35 itojun 1954: #ifdef INET6
1955: char ntop_buf[NI_MAXHOST];
1956: #endif
1957:
1.1 cgd 1958: switch (su->sa.sa_family) {
1.17 gwr 1959: case AF_INET:
1960: (void) printf("%s: inet %s; ",
1961: which, inet_ntoa(su->sin.sin_addr));
1962: break;
1.19 christos 1963: case AF_APPLETALK:
1964: (void) printf("%s: atalk %d.%d; ",
1965: which, su->sat.sat_addr.s_net, su->sat.sat_addr.s_node);
1966: break;
1.1 cgd 1967: case AF_LINK:
1968: (void) printf("%s: link %s; ",
1969: which, link_ntoa(&su->sdl));
1970: break;
1.17 gwr 1971: #ifndef SMALL
1.31 itojun 1972: #ifdef INET6
1973: case AF_INET6:
1974: (void) printf("%s: inet6 %s; ",
1975: which, inet_ntop(AF_INET6, &su->sin6.sin6_addr,
1976: ntop_buf, sizeof(ntop_buf)));
1977: break;
1978: #endif
1.1 cgd 1979: case AF_ISO:
1980: (void) printf("%s: iso %s; ",
1981: which, iso_ntoa(&su->siso.siso_addr));
1982: break;
1983: case AF_NS:
1984: (void) printf("%s: xns %s; ",
1985: which, ns_ntoa(su->sns.sns_addr));
1986: break;
1.17 gwr 1987: #endif /* SMALL */
1988: default:
1.19 christos 1989: (void) printf("af %p: %s; ",
1.17 gwr 1990: which, any_ntoa(&su->sa));
1.1 cgd 1991: }
1992: (void) fflush(stdout);
1993: }
1.7 mycroft 1994:
1.1 cgd 1995: /* States*/
1996: #define VIRGIN 0
1997: #define GOTONE 1
1998: #define GOTTWO 2
1999: /* Inputs */
2000: #define DIGIT (4*0)
2001: #define END (4*1)
2002: #define DELIM (4*2)
2003:
1.19 christos 2004: static void
1.1 cgd 2005: sockaddr(addr, sa)
1.23 lukem 2006: char *addr;
2007: struct sockaddr *sa;
1.1 cgd 2008: {
1.23 lukem 2009: char *cp = (char *)sa;
1.1 cgd 2010: int size = sa->sa_len;
2011: char *cplim = cp + size;
1.23 lukem 2012: int byte = 0, state = VIRGIN, new = 0;
1.1 cgd 2013:
1.19 christos 2014: (void) memset(cp, 0, size);
1.7 mycroft 2015: cp++;
1.1 cgd 2016: do {
2017: if ((*addr >= '0') && (*addr <= '9')) {
2018: new = *addr - '0';
2019: } else if ((*addr >= 'a') && (*addr <= 'f')) {
2020: new = *addr - 'a' + 10;
2021: } else if ((*addr >= 'A') && (*addr <= 'F')) {
2022: new = *addr - 'A' + 10;
1.7 mycroft 2023: } else if (*addr == 0)
1.1 cgd 2024: state |= END;
2025: else
2026: state |= DELIM;
2027: addr++;
2028: switch (state /* | INPUT */) {
2029: case GOTTWO | DIGIT:
2030: *cp++ = byte; /*FALLTHROUGH*/
2031: case VIRGIN | DIGIT:
2032: state = GOTONE; byte = new; continue;
2033: case GOTONE | DIGIT:
2034: state = GOTTWO; byte = new + (byte << 4); continue;
2035: default: /* | DELIM */
2036: state = VIRGIN; *cp++ = byte; byte = 0; continue;
2037: case GOTONE | END:
2038: case GOTTWO | END:
2039: *cp++ = byte; /* FALLTHROUGH */
2040: case VIRGIN | END:
2041: break;
2042: }
2043: break;
1.7 mycroft 2044: } while (cp < cplim);
1.1 cgd 2045: sa->sa_len = cp - (char *)sa;
2046: }
CVSweb <webmaster@jp.NetBSD.org>