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