Annotation of embedaddon/libpdel/net/uroute.c, revision 1.1
1.1 ! misho 1:
! 2: /*
! 3: * Copyright (c) 2001-2002 Packet Design, LLC.
! 4: * All rights reserved.
! 5: *
! 6: * Subject to the following obligations and disclaimer of warranty,
! 7: * use and redistribution of this software, in source or object code
! 8: * forms, with or without modifications are expressly permitted by
! 9: * Packet Design; provided, however, that:
! 10: *
! 11: * (i) Any and all reproductions of the source or object code
! 12: * must include the copyright notice above and the following
! 13: * disclaimer of warranties; and
! 14: * (ii) No rights are granted, in any manner or form, to use
! 15: * Packet Design trademarks, including the mark "PACKET DESIGN"
! 16: * on advertising, endorsements, or otherwise except as such
! 17: * appears in the above copyright notice or in the software.
! 18: *
! 19: * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
! 20: * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
! 21: * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
! 22: * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
! 23: * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
! 24: * OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
! 25: * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
! 26: * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
! 27: * RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE
! 28: * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
! 29: * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
! 30: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
! 31: * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
! 32: * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
! 33: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 34: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
! 35: * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
! 36: * THE POSSIBILITY OF SUCH DAMAGE.
! 37: *
! 38: * Author: Archie Cobbs <archie@freebsd.org>
! 39: */
! 40:
! 41: #include <sys/types.h>
! 42: #include <sys/param.h>
! 43: #include <sys/socket.h>
! 44: #include <sys/sysctl.h>
! 45: #include <sys/sockio.h>
! 46: #include <sys/ioctl.h>
! 47:
! 48: #include <net/if.h>
! 49: #include <net/if_dl.h>
! 50: #include <net/if_types.h>
! 51: #include <net/route.h>
! 52:
! 53: #include <netinet/in.h>
! 54: #include <netinet/if_ether.h>
! 55: #include <arpa/inet.h>
! 56:
! 57: #include <stdio.h>
! 58: #include <stdlib.h>
! 59: #include <stdarg.h>
! 60: #include <unistd.h>
! 61: #include <assert.h>
! 62: #include <string.h>
! 63: #include <errno.h>
! 64: #include <err.h>
! 65:
! 66: #include "structs/structs.h"
! 67: #include "structs/type/array.h"
! 68:
! 69: #include "net/route_msg.h"
! 70: #include "net/uroute.h"
! 71: #include "util/typed_mem.h"
! 72:
! 73: #define ROUNDUP(a) \
! 74: ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
! 75: #define ADVANCE(x, n) ((x) += ROUNDUP((n)->sa_len))
! 76:
! 77: #ifdef RTF_CLONING
! 78: #define WRITABLE_FLAGS (RTF_STATIC | RTF_LLINFO | RTF_REJECT | RTF_BLACKHOLE \
! 79: | RTF_PROTO1 | RTF_PROTO2 | RTF_CLONING \
! 80: | RTF_XRESOLVE | RTF_UP | RTF_GATEWAY)
! 81: #else
! 82: #define WRITABLE_FLAGS (RTF_STATIC | RTF_REJECT | RTF_BLACKHOLE \
! 83: | RTF_PROTO1 | RTF_PROTO2 \
! 84: | RTF_XRESOLVE | RTF_UP | RTF_GATEWAY)
! 85: #endif
! 86:
! 87: struct route_flag {
! 88: const char *name;
! 89: int bit;
! 90: };
! 91:
! 92: static const struct route_flag route_flags[] = {
! 93: #define FLAG(x) { #x, RTF_ ## x }
! 94: FLAG(UP),
! 95: FLAG(GATEWAY),
! 96: FLAG(HOST),
! 97: FLAG(REJECT),
! 98: FLAG(DYNAMIC),
! 99: FLAG(MODIFIED),
! 100: FLAG(DONE),
! 101: #ifdef RTF_CLONING
! 102: FLAG(CLONING),
! 103: #endif
! 104: FLAG(XRESOLVE),
! 105: #ifdef RTF_LLINFO
! 106: FLAG(LLINFO),
! 107: #endif
! 108: FLAG(STATIC),
! 109: FLAG(BLACKHOLE),
! 110: FLAG(PROTO2),
! 111: FLAG(PROTO1),
! 112: FLAG(PRCLONING),
! 113: #ifdef RTF_WASCLONED
! 114: FLAG(WASCLONED),
! 115: #endif
! 116: FLAG(PROTO3),
! 117: FLAG(PINNED),
! 118: FLAG(LOCAL),
! 119: FLAG(BROADCAST),
! 120: FLAG(MULTICAST),
! 121: #undef FLAG
! 122: { NULL, 0 }
! 123: };
! 124:
! 125: /* Route structure */
! 126: struct uroute {
! 127: int flags;
! 128: struct sockaddr *dest;
! 129: struct sockaddr *gateway;
! 130: struct sockaddr *netmask;
! 131: };
! 132:
! 133: /*
! 134: * Internal functions
! 135: */
! 136: static int uroute_do_route(struct uroute *route, int sock, int type);
! 137: static const char *uroute_sockaddr_string(const struct sockaddr *sa);
! 138:
! 139: /*
! 140: * Create a new route.
! 141: */
! 142: struct uroute *
! 143: uroute_create(const struct sockaddr *dest, const struct sockaddr *gateway,
! 144: const struct sockaddr *netmask)
! 145: {
! 146: struct uroute *route;
! 147:
! 148: if (dest == NULL || gateway == NULL) {
! 149: errno = EINVAL;
! 150: return (NULL);
! 151: }
! 152: if ((route = MALLOC("uroute", sizeof(*route))) == NULL)
! 153: return (NULL);
! 154: memset(route, 0, sizeof(*route));
! 155: if ((route->dest = MALLOC("uroute.dest", dest->sa_len)) == NULL)
! 156: goto fail;
! 157: memcpy(route->dest, dest, dest->sa_len);
! 158: if ((route->gateway = MALLOC("uroute.gateway",
! 159: gateway->sa_len)) == NULL)
! 160: goto fail;
! 161: memcpy(route->gateway, gateway, gateway->sa_len);
! 162: if (netmask != NULL) {
! 163: if ((route->netmask = MALLOC("uroute.netmask",
! 164: netmask->sa_len)) == NULL)
! 165: goto fail;
! 166: memcpy(route->netmask, netmask, netmask->sa_len);
! 167: }
! 168: route->flags = RTF_STATIC;
! 169: return (route);
! 170:
! 171: fail:
! 172: /* Clean up */
! 173: uroute_destroy(&route);
! 174: return (NULL);
! 175: }
! 176:
! 177: /*
! 178: * Free a route.
! 179: */
! 180: void
! 181: uroute_destroy(struct uroute **routep)
! 182: {
! 183: struct uroute *const route = *routep;
! 184:
! 185: if (route == NULL)
! 186: return;
! 187: FREE("uroute.dest", route->dest);
! 188: FREE("uroute.gateway", route->gateway);
! 189: FREE("uroute.netmask", route->netmask);
! 190: FREE("uroute", route);
! 191: *routep = NULL;
! 192: }
! 193:
! 194: /*
! 195: * Get the destination address.
! 196: */
! 197: const struct sockaddr *
! 198: uroute_get_dest(struct uroute *route)
! 199: {
! 200: return (route->dest);
! 201: }
! 202:
! 203: /*
! 204: * Get the gateway address.
! 205: */
! 206: const struct sockaddr *
! 207: uroute_get_gateway(struct uroute *route)
! 208: {
! 209: return (route->gateway);
! 210: }
! 211:
! 212: /*
! 213: * Get the netmask.
! 214: *
! 215: * Returns NULL for a host route.
! 216: */
! 217: const struct sockaddr *
! 218: uroute_get_netmask(struct uroute *route)
! 219: {
! 220: return (route->netmask);
! 221: }
! 222:
! 223: /*
! 224: * Get the flags.
! 225: */
! 226: int
! 227: uroute_get_flags(struct uroute *route)
! 228: {
! 229: return (route->flags);
! 230: }
! 231:
! 232: /*
! 233: * Set the flags.
! 234: */
! 235: void
! 236: uroute_set_flags(struct uroute *route, int flags)
! 237: {
! 238: route->flags = flags;
! 239: }
! 240:
! 241: /*
! 242: * Add route to the kernel routing table.
! 243: */
! 244: int
! 245: uroute_add(struct uroute *route)
! 246: {
! 247: return (uroute_do_route(route, -1, RTM_ADD));
! 248: }
! 249:
! 250: /*
! 251: * Delete a route.
! 252: */
! 253: int
! 254: uroute_delete(struct uroute *route)
! 255: {
! 256: return (uroute_do_route(route, -1, RTM_DELETE));
! 257: }
! 258:
! 259: /*
! 260: * Get the installed kernel route that matches the destination "dest".
! 261: */
! 262: struct uroute *
! 263: uroute_get(const struct sockaddr *dest)
! 264: {
! 265: struct uroute *route = NULL;
! 266: struct route_msg *msg = NULL;
! 267: struct route_msg **list = NULL;
! 268: struct sockaddr_dl sdl;
! 269: int errno_save;
! 270: int sock = -1;
! 271: int num = 0;
! 272: int seq;
! 273: int i;
! 274:
! 275: /* Build new route message */
! 276: if ((msg = route_msg_create()) == NULL)
! 277: goto fail;
! 278: seq = route_msg_get_seq(msg);
! 279: route_msg_set_type(msg, RTM_GET);
! 280: if (route_msg_set_dest(msg, dest) == -1)
! 281: goto fail;
! 282: memset(&sdl, 0, sizeof(sdl));
! 283: sdl.sdl_type = IFT_OTHER;
! 284: sdl.sdl_len = 8;
! 285: sdl.sdl_family = AF_LINK;
! 286: if (route_msg_set_ifp(msg, (struct sockaddr *)&sdl) == -1)
! 287: goto fail;
! 288: route_msg_set_flags(msg, RTF_UP|RTF_GATEWAY|RTF_HOST|RTF_STATIC);
! 289:
! 290: /* Send request */
! 291: if ((sock = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
! 292: goto fail;
! 293: if (route_msg_send(msg, sock) == -1)
! 294: goto fail;
! 295: route_msg_destroy(&msg);
! 296: msg = NULL;
! 297:
! 298: /* Get response */
! 299: while (1) {
! 300:
! 301: /* Decode it */
! 302: if ((num = route_msg_recv(&list, sock, TYPED_MEM_TEMP)) == -1)
! 303: goto fail;
! 304:
! 305: /* Check returned messages for a match */
! 306: for (i = 0; i < num; i++) {
! 307: struct route_msg *const msg = list[i];
! 308:
! 309: if (route_msg_get_pid(msg) == getpid()
! 310: && route_msg_get_seq(msg) == seq) {
! 311: if ((route = uroute_create(route_msg_get_dest(
! 312: msg), route_msg_get_gateway(msg),
! 313: route_msg_get_netmask(msg))) == NULL)
! 314: goto fail;
! 315: break;
! 316: }
! 317: }
! 318: if (route != NULL)
! 319: break;
! 320:
! 321: /* Free list and try again */
! 322: for (i = 0; i < num; i++)
! 323: route_msg_destroy(&list[i]);
! 324: FREE(TYPED_MEM_TEMP, list);
! 325: list = NULL;
! 326: }
! 327:
! 328: fail:
! 329: /* Clean up and exit */
! 330: errno_save = errno;
! 331: if (sock != -1)
! 332: (void)close(sock);
! 333: if (msg != NULL)
! 334: route_msg_destroy(&msg);
! 335: if (list != NULL) {
! 336: for (i = 0; i < num; i++)
! 337: route_msg_destroy(&list[i]);
! 338: FREE(TYPED_MEM_TEMP, list);
! 339: }
! 340: errno = errno_save;
! 341: return (route);
! 342: }
! 343:
! 344: /*
! 345: * Build and send a route message by type.
! 346: */
! 347: static int
! 348: uroute_do_route(struct uroute *route, int sock, int type)
! 349: {
! 350: struct route_msg *msg;
! 351: int close_sock = 0;
! 352: int r = -1;
! 353: int flags;
! 354:
! 355: /* Create new route message */
! 356: if ((msg = route_msg_create()) == NULL)
! 357: return (-1);
! 358:
! 359: /* Open socket if requested */
! 360: if (sock == -1) {
! 361: if ((sock = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
! 362: goto fail;
! 363: close_sock = 1;
! 364: }
! 365:
! 366: /* Build message */
! 367: route_msg_set_type(msg, type);
! 368: flags = route->flags & WRITABLE_FLAGS;
! 369: flags |= RTF_UP;
! 370: if (route->gateway->sa_family != AF_LINK)
! 371: flags |= RTF_GATEWAY;
! 372: if (route->netmask == NULL)
! 373: flags |= RTF_HOST;
! 374: else
! 375: flags &= ~RTF_HOST;
! 376: route_msg_set_flags(msg, flags);
! 377: if (route_msg_set_dest(msg, route->dest) == -1)
! 378: goto fail;
! 379: if (route_msg_set_gateway(msg, route->gateway) == -1)
! 380: goto fail;
! 381: if (route_msg_set_netmask(msg, route->netmask) == -1)
! 382: goto fail;
! 383:
! 384: /* Send messsage */
! 385: r = route_msg_send(msg, sock);
! 386:
! 387: fail:
! 388: /* Clean up */
! 389: route_msg_destroy(&msg);
! 390: if (close_sock)
! 391: (void)close(sock);
! 392:
! 393: /* Done */
! 394: return (r);
! 395: }
! 396:
! 397: /*
! 398: * Get the entire routing table.
! 399: */
! 400: int
! 401: uroute_get_all(struct uroute ***listp, const char *mtype)
! 402: {
! 403: static int oid[6] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_DUMP, 0 };
! 404: static const int noid = sizeof(oid) / sizeof(*oid);
! 405: struct route_msg **list = NULL;
! 406: struct uroute **routes = NULL;
! 407: u_char *buf = NULL;
! 408: size_t actual;
! 409: size_t needed;
! 410: int num = 0;
! 411: int i;
! 412:
! 413: /* Get size estimate */
! 414: if (sysctl(oid, noid, NULL, &needed, NULL, 0) < 0)
! 415: goto fail;
! 416:
! 417: /* Allocate buffer for returned value */
! 418: if ((buf = MALLOC(TYPED_MEM_TEMP, needed)) == NULL)
! 419: goto fail;
! 420:
! 421: /* Get actual data */
! 422: actual = needed;
! 423: if (sysctl(oid, noid, buf, &actual, NULL, 0) < 0)
! 424: goto fail;
! 425:
! 426: /* Decode route messages */
! 427: if ((num = route_msg_decode(buf, actual, &list, TYPED_MEM_TEMP)) == -1)
! 428: goto fail;
! 429:
! 430: /* Create routes array from route message array */
! 431: if ((routes = MALLOC(mtype, num * sizeof(*routes))) == NULL)
! 432: goto fail;
! 433: memset(routes, 0, num * sizeof(*routes));
! 434: for (i = 0; i < num; i++) {
! 435: struct route_msg *const msg = list[i];
! 436:
! 437: if ((routes[i] = uroute_create(route_msg_get_dest(msg),
! 438: route_msg_get_gateway(msg),
! 439: route_msg_get_netmask(msg))) == NULL) {
! 440: while (i > 0)
! 441: uroute_destroy(&routes[--i]);
! 442: FREE(mtype, routes);
! 443: routes = NULL;
! 444: goto fail;
! 445: }
! 446: routes[i]->flags = route_msg_get_flags(msg);
! 447: }
! 448:
! 449: fail:
! 450: /* Clean up and exit */
! 451: if (buf != NULL)
! 452: FREE(TYPED_MEM_TEMP, buf);
! 453: if (list != NULL) {
! 454: for (i = 0; i < num; i++)
! 455: route_msg_destroy(&list[i]);
! 456: FREE(TYPED_MEM_TEMP, list);
! 457: }
! 458: if (routes != NULL) {
! 459: *listp = routes;
! 460: return (num);
! 461: }
! 462: return (-1);
! 463: }
! 464:
! 465: /*
! 466: * Print a route.
! 467: */
! 468: void
! 469: uroute_print(struct uroute *route, FILE *fp)
! 470: {
! 471: int didflag;
! 472: int i;
! 473:
! 474: fprintf(fp, "dest %s gateway %s",
! 475: uroute_sockaddr_string(route->dest),
! 476: uroute_sockaddr_string(route->gateway));
! 477: if (route->netmask != NULL) {
! 478: fprintf(fp, " netmask %s",
! 479: uroute_sockaddr_string(route->netmask));
! 480: }
! 481: fprintf(fp, " flags=<");
! 482: for (i = didflag = 0; route_flags[i].name != NULL; i++) {
! 483: if ((route->flags & route_flags[i].bit) != 0) {
! 484: if (didflag)
! 485: fprintf(fp, ",");
! 486: didflag = 1;
! 487: fprintf(fp, "%s", route_flags[i].name);
! 488: }
! 489: }
! 490: fprintf(fp, ">");
! 491: }
! 492:
! 493: static const char *
! 494: uroute_sockaddr_string(const struct sockaddr *sa)
! 495: {
! 496: static char buf[2][256];
! 497: static int n;
! 498: int i;
! 499:
! 500: n ^= 1;
! 501: switch (sa->sa_family) {
! 502: case AF_INET:
! 503: strlcpy(buf[n], inet_ntoa(((struct sockaddr_in *)(void *)
! 504: sa)->sin_addr), sizeof(buf[n]));
! 505: break;
! 506: case AF_LINK:
! 507: /* XXX implement me */
! 508: default:
! 509: snprintf(buf[n], sizeof(buf[n]), "{ len=%d af=%d data=[",
! 510: sa->sa_len, sa->sa_family);
! 511: for (i = 2; i < sa->sa_len; i++) {
! 512: snprintf(buf[n] + strlen(buf[n]),
! 513: sizeof(buf[n]) - strlen(buf[n]),
! 514: " %02X", ((u_char *)sa)[i]);
! 515: }
! 516: strlcat(buf[n], " ] }", sizeof(buf[n]));
! 517: }
! 518: return (buf[n]);
! 519: }
! 520:
! 521:
! 522: #ifdef UROUTE_TEST
! 523:
! 524: int
! 525: main(int ac, char **av)
! 526: {
! 527: struct sockaddr_in dest;
! 528: struct sockaddr_in gateway;
! 529: struct sockaddr_in netmask;
! 530: struct uroute *route = NULL;
! 531: int do_netmask = 0;
! 532: int fail = 0;
! 533: int cmd = 0;
! 534:
! 535: memset(&dest, 0, sizeof(dest));
! 536: dest.sin_family = AF_INET;
! 537: dest.sin_len = sizeof(dest);
! 538: memset(&gateway, 0, sizeof(gateway));
! 539: gateway.sin_family = AF_INET;
! 540: gateway.sin_len = sizeof(gateway);
! 541: memset(&netmask, 0, sizeof(netmask));
! 542: netmask.sin_family = AF_INET;
! 543: netmask.sin_len = sizeof(netmask);
! 544:
! 545: av++;
! 546: ac--;
! 547: switch (ac) {
! 548: case 4:
! 549: if (inet_aton(av[3], &netmask.sin_addr))
! 550: ;
! 551: else {
! 552: u_long haddr;
! 553:
! 554: if (sscanf(av[3], "%lu", &haddr) != 1)
! 555: err(1, "invalid netmask \"%s\"", av[3]);
! 556: netmask.sin_addr.s_addr = htonl(haddr);
! 557: }
! 558: do_netmask = 1;
! 559: // fall through
! 560: case 3:
! 561: if (!inet_aton(av[2], &gateway.sin_addr))
! 562: err(1, "invalid IP address \"%s\"", av[2]);
! 563: if (!strcmp(av[0], "add"))
! 564: cmd = 1;
! 565: else if (!strcmp(av[0], "delete"))
! 566: cmd = 2;
! 567: else {
! 568: fail = 1;
! 569: break;
! 570: }
! 571: if (!inet_aton(av[1], &dest.sin_addr))
! 572: err(1, "invalid IP address \"%s\"", av[1]);
! 573: if ((route = uroute_create((struct sockaddr *)&dest,
! 574: (struct sockaddr *)&gateway,
! 575: do_netmask ? (struct sockaddr *)&netmask : NULL)) == NULL)
! 576: err(1, "uroute_create");
! 577: break;
! 578: case 2:
! 579: if (strcmp(av[0], "get") != 0) {
! 580: fail = 1;
! 581: break;
! 582: }
! 583: if (!inet_aton(av[1], &dest.sin_addr))
! 584: err(1, "invalid IP address \"%s\"", av[1]);
! 585: break;
! 586: case 1:
! 587: if (strcmp(av[0], "list") != 0) {
! 588: fail = 1;
! 589: break;
! 590: }
! 591: // fall through
! 592: case 0:
! 593: cmd = 3;
! 594: break;
! 595: default:
! 596: fail = 1;
! 597: break;
! 598: }
! 599: if (fail) {
! 600: fprintf(stderr, "Usage: uroute <add | delete | get | list>"
! 601: " [dest [ gateway [netmask] ]]\n");
! 602: exit(1);
! 603: }
! 604:
! 605: switch (cmd) {
! 606: case 0: // get
! 607: if ((route = uroute_get((struct sockaddr *)&dest)) == NULL)
! 608: err(1, "uroute_get");
! 609: uroute_print(route, stdout);
! 610: printf("\n");
! 611: uroute_destroy(&route);
! 612: break;
! 613: case 1: // add
! 614: if (uroute_add(route) == -1)
! 615: err(1, "uroute_add");
! 616: uroute_destroy(&route);
! 617: break;
! 618: case 2: // delete
! 619: if (uroute_delete(route) == -1)
! 620: err(1, "uroute_delete");
! 621: uroute_destroy(&route);
! 622: break;
! 623: case 3: // list
! 624: {
! 625: struct uroute **list;
! 626: int num;
! 627: int i;
! 628:
! 629: if ((num = uroute_get_all(&list, "main")) == -1)
! 630: err(1, "uroute_get_all");
! 631: for (i = 0; i < num; i++) {
! 632: uroute_print(list[i], stdout);
! 633: printf("\n");
! 634: }
! 635: for (i = 0; i < num; i++)
! 636: uroute_destroy(&list[i]);
! 637: FREE("main", list);
! 638: break;
! 639: }
! 640: default:
! 641: assert(0);
! 642: }
! 643:
! 644: /* Done */
! 645: typed_mem_dump(stdout);
! 646: return (0);
! 647: }
! 648: #endif
! 649:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>