1 /* 2 * Copyright 2006-2010, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 */ 8 9 10 #include <SupportDefs.h> 11 12 #include <arpa/inet.h> 13 #include <net/if.h> 14 #include <net/if_dl.h> 15 #include <net/if_types.h> 16 #include <netinet/in.h> 17 #include <sys/socket.h> 18 #include <sys/sockio.h> 19 20 #include <errno.h> 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <unistd.h> 25 26 27 extern const char* __progname; 28 const char* kProgramName = __progname; 29 30 31 enum modes { 32 RTM_LIST = 0, 33 RTM_DELETE, 34 RTM_ADD, 35 RTM_GET, 36 37 // TODO: 38 RTM_CHANGE, 39 RTM_FLUSH, 40 }; 41 42 enum preferred_output_format { 43 PREFER_OUTPUT_MASK, 44 PREFER_OUTPUT_PREFIX_LENGTH, 45 }; 46 47 struct address_family { 48 int family; 49 const char* name; 50 const char* identifiers[4]; 51 preferred_output_format preferred_format; 52 bool (*parse_address)(const char* string, sockaddr* _address); 53 bool (*prefix_length_to_mask)(uint8 prefixLength, sockaddr* mask); 54 uint8 (*mask_to_prefix_length)(sockaddr* mask); 55 const char* (*address_to_string)(sockaddr* address); 56 }; 57 58 // AF_INET family 59 static bool inet_parse_address(const char* string, sockaddr* address); 60 static bool inet_prefix_length_to_mask(uint8 prefixLength, sockaddr* mask); 61 static uint8 inet_mask_to_prefix_length(sockaddr* mask); 62 static const char* inet_address_to_string(sockaddr* address); 63 64 // AF_INET6 family 65 static bool inet6_parse_address(const char* string, sockaddr* address); 66 static bool inet6_prefix_length_to_mask(uint8 prefixLength, sockaddr* mask); 67 static uint8 inet6_mask_to_prefix_length(sockaddr* mask); 68 static const char* inet6_address_to_string(sockaddr* address); 69 70 static const address_family kFamilies[] = { 71 { 72 AF_INET, 73 "inet", 74 {"AF_INET", "inet", "ipv4", NULL}, 75 PREFER_OUTPUT_MASK, 76 inet_parse_address, 77 inet_prefix_length_to_mask, 78 inet_mask_to_prefix_length, 79 inet_address_to_string, 80 }, 81 { 82 AF_INET6, 83 "inet6", 84 {"AF_INET6", "inet6", "ipv6", NULL}, 85 PREFER_OUTPUT_PREFIX_LENGTH, 86 inet6_parse_address, 87 inet6_prefix_length_to_mask, 88 inet6_mask_to_prefix_length, 89 inet6_address_to_string, 90 }, 91 { -1, NULL, {NULL}, PREFER_OUTPUT_MASK, NULL, NULL, NULL, NULL } 92 }; 93 94 95 static bool 96 inet_parse_address(const char* string, sockaddr* _address) 97 { 98 in_addr inetAddress; 99 100 if (inet_aton(string, &inetAddress) != 1) 101 return false; 102 103 sockaddr_in& address = *(sockaddr_in*)_address; 104 address.sin_family = AF_INET; 105 address.sin_len = sizeof(struct sockaddr_in); 106 address.sin_port = 0; 107 address.sin_addr = inetAddress; 108 memset(&address.sin_zero[0], 0, sizeof(address.sin_zero)); 109 110 return true; 111 } 112 113 114 static bool 115 inet_prefix_length_to_mask(uint8 prefixLength, sockaddr* _mask) 116 { 117 if (prefixLength > 32) 118 return false; 119 120 sockaddr_in& mask = *(sockaddr_in*)_mask; 121 mask.sin_family = AF_INET; 122 mask.sin_len = sizeof(sockaddr_in); 123 mask.sin_port = 0; 124 memset(&mask.sin_zero[0], 0, sizeof(mask.sin_zero)); 125 126 uint32 hostMask = 0; 127 for (uint8 i = 32; i > 32 - prefixLength; i--) 128 hostMask |= 1 << (i - 1); 129 mask.sin_addr.s_addr = htonl(hostMask); 130 131 return true; 132 } 133 134 135 static uint8 136 inet_mask_to_prefix_length(sockaddr* _mask) 137 { 138 if (_mask == NULL) 139 return 32; 140 141 sockaddr_in& mask = *(sockaddr_in*)_mask; 142 if (mask.sin_family != AF_INET) 143 return (uint8)-1; 144 145 uint8 result = 0; 146 uint32 hostMask = ntohl(mask.sin_addr.s_addr); 147 for (uint8 i = 32; i > 0; i--) { 148 if (hostMask & (1 << (i - 1)) == 0) 149 break; 150 result++; 151 } 152 153 return result; 154 } 155 156 157 static const char* 158 inet_address_to_string(sockaddr* address) 159 { 160 if (address == NULL || address->sa_family != AF_INET) 161 return "-"; 162 163 return inet_ntoa(((sockaddr_in*)address)->sin_addr); 164 } 165 166 167 static bool 168 inet6_parse_address(const char* string, sockaddr* _address) 169 { 170 sockaddr_in6& address = *(sockaddr_in6*)_address; 171 172 if (inet_pton(AF_INET6, string, &address.sin6_addr) != 1) 173 return false; 174 175 address.sin6_family = AF_INET6; 176 address.sin6_len = sizeof(sockaddr_in6); 177 address.sin6_port = 0; 178 address.sin6_flowinfo = 0; 179 address.sin6_scope_id = 0; 180 181 return true; 182 } 183 184 185 static bool 186 inet6_prefix_length_to_mask(uint8 prefixLength, sockaddr* _mask) 187 { 188 if (prefixLength > 128) 189 return false; 190 191 sockaddr_in6& mask = *(sockaddr_in6*)_mask; 192 mask.sin6_family = AF_INET6; 193 mask.sin6_len = sizeof(sockaddr_in6); 194 mask.sin6_port = 0; 195 mask.sin6_flowinfo = 0; 196 mask.sin6_scope_id = 0; 197 memset(mask.sin6_addr.s6_addr, 0, sizeof(in6_addr)); 198 199 for (uint8 i = 0; i < sizeof(in6_addr); i++, prefixLength -= 8) { 200 if (prefixLength < 8) { 201 const uint8 masks[] = { 202 0x00, 0x80, 0xc0, 0xe0, 203 0xf0, 0xf8, 0xfc, 0xfe 204 }; 205 mask.sin6_addr.s6_addr[i] = masks[prefixLength]; 206 break; 207 } 208 209 mask.sin6_addr.s6_addr[i] = 0xff; 210 } 211 212 return true; 213 } 214 215 216 static uint8 217 inet6_mask_to_prefix_length(sockaddr* _mask) 218 { 219 if (_mask == NULL) 220 return 128; 221 222 sockaddr_in6& mask = *(sockaddr_in6*)_mask; 223 if (mask.sin6_family != AF_INET6) 224 return (uint8)-1; 225 226 uint8 result = 0; 227 for (uint8 i = 0; i < sizeof(in6_addr); i++) { 228 for (uint8 j = 0; j < 8; j++) { 229 if (!(mask.sin6_addr.s6_addr[i] & (1 << j))) 230 return result; 231 result++; 232 } 233 } 234 235 return 128; 236 } 237 238 239 static const char* 240 inet6_address_to_string(sockaddr* address) 241 { 242 if (address == NULL || address->sa_family != AF_INET6) 243 return "-"; 244 245 static char buffer[INET6_ADDRSTRLEN]; 246 247 inet_ntop(AF_INET6, &((sockaddr_in6*)address)->sin6_addr, 248 buffer, sizeof(buffer)); 249 250 return buffer; 251 } 252 253 254 // #pragma mark - 255 256 257 void 258 usage(int status) 259 { 260 printf("usage: %s [command] [<interface>] [<address family>] " 261 "<address|default> [<option/flags>...]\n" 262 "Where <command> can be the one of:\n" 263 " add - add a route for the specified interface\n" 264 " delete - deletes the specified route\n" 265 " list - list with filters [default]\n" 266 "<option> can be the following:\n" 267 " netmask <addr> - networking subnet mask\n" 268 " prefixlen <number> - subnet mask length in bits\n" 269 " gw <addr> - gateway address\n" 270 " mtu <bytes> - maximal transfer unit\n" 271 "And <flags> can be: reject, local, host\n\n" 272 "Example:\n" 273 "\t%s add /dev/net/ipro1000/0 default gw 192.168.0.254\n", 274 kProgramName, kProgramName); 275 276 exit(status); 277 } 278 279 280 bool 281 prepare_request(struct ifreq& request, const char* name) 282 { 283 if (strlen(name) >= IF_NAMESIZE) { 284 fprintf(stderr, "%s: interface name \"%s\" is too long.\n", 285 kProgramName, name); 286 return false; 287 } 288 289 strcpy(request.ifr_name, name); 290 return true; 291 } 292 293 294 bool 295 get_address_family(const char* argument, int32& familyIndex) 296 { 297 for (int32 i = 0; kFamilies[i].family >= 0; i++) { 298 for (int32 j = 0; kFamilies[i].identifiers[j]; j++) { 299 if (!strcmp(argument, kFamilies[i].identifiers[j])) { 300 // found a match 301 familyIndex = i; 302 return true; 303 } 304 } 305 } 306 307 // defaults to AF_INET 308 familyIndex = 0; 309 return false; 310 } 311 312 313 bool 314 parse_address(int32 familyIndex, const char* argument, 315 struct sockaddr_storage& address) 316 { 317 if (argument == NULL) 318 return false; 319 320 return kFamilies[familyIndex].parse_address(argument, (sockaddr*)&address); 321 } 322 323 324 bool 325 prefix_length_to_mask(int32 familyIndex, const char* argument, 326 struct sockaddr_storage& mask) 327 { 328 if (argument == NULL) 329 return false; 330 331 char *end; 332 uint32 prefixLength = strtoul(argument, &end, 10); 333 if (end == argument) 334 return false; 335 336 return kFamilies[familyIndex].prefix_length_to_mask( 337 (uint8)prefixLength, (sockaddr*)&mask); 338 } 339 340 341 // #pragma mark - 342 343 344 void 345 list_routes(int socket, const char *interfaceName, route_entry &route) 346 { 347 // get a list of all routes 348 349 ifconf config; 350 config.ifc_len = sizeof(config.ifc_value); 351 if (ioctl(socket, SIOCGRTSIZE, &config, sizeof(struct ifconf)) < 0) 352 return; 353 354 uint32 size = (uint32)config.ifc_value; 355 if (size == 0) 356 return; 357 358 void *buffer = malloc(size); 359 if (buffer == NULL) { 360 fprintf(stderr, "%s: Out of memory.\n", kProgramName); 361 return; 362 } 363 364 config.ifc_len = size; 365 config.ifc_buf = buffer; 366 if (ioctl(socket, SIOCGRTTABLE, &config, sizeof(struct ifconf)) < 0) 367 return; 368 369 ifreq *interface = (ifreq*)buffer; 370 ifreq *end = (ifreq*)((uint8*)buffer + size); 371 372 while (interface < end) { 373 route_entry& route = interface->ifr_route; 374 375 // apply filters 376 if (interfaceName == NULL 377 || !strcmp(interfaceName, interface->ifr_name)) { 378 // find family 379 const address_family *family = NULL; 380 for (int32 i = 0; kFamilies[i].family >= 0; i++) { 381 if (route.destination->sa_family == kFamilies[i].family) { 382 family = &kFamilies[i]; 383 break; 384 } 385 } 386 387 if (family != NULL) { 388 // TODO: is the %15s format OK for IPv6? 389 printf("%15s", family->address_to_string(route.destination)); 390 switch (family->preferred_format) { 391 case PREFER_OUTPUT_MASK: 392 printf(" mask %-15s ", 393 family->address_to_string(route.mask)); 394 break; 395 case PREFER_OUTPUT_PREFIX_LENGTH: 396 printf("/%u ", 397 family->mask_to_prefix_length(route.mask)); 398 break; 399 } 400 if ((route.flags & RTF_GATEWAY) != 0) { 401 printf("gateway %-15s ", 402 family->address_to_string(route.gateway)); 403 } 404 } else { 405 printf("unknown family "); 406 } 407 408 printf("%s", interface->ifr_name); 409 410 if (route.flags != 0) { 411 const struct { 412 int value; 413 const char *name; 414 } kFlags[] = { 415 {RTF_DEFAULT, "default"}, 416 {RTF_REJECT, "reject"}, 417 {RTF_HOST, "host"}, 418 {RTF_LOCAL, "local"}, 419 {RTF_DYNAMIC, "dynamic"}, 420 {RTF_MODIFIED, "modified"}, 421 }; 422 bool first = true; 423 424 for (uint32 i = 0; i < sizeof(kFlags) / sizeof(kFlags[0]); i++) { 425 if ((route.flags & kFlags[i].value) != 0) { 426 if (first) { 427 printf(", "); 428 first = false; 429 } else 430 putchar(' '); 431 printf(kFlags[i].name); 432 } 433 } 434 } 435 436 putchar('\n'); 437 } 438 439 int32 addressSize = 0; 440 if (route.destination != NULL) 441 addressSize += route.destination->sa_len; 442 if (route.mask != NULL) 443 addressSize += route.mask->sa_len; 444 if (route.gateway != NULL) 445 addressSize += route.gateway->sa_len; 446 447 interface = (ifreq*)((addr_t)interface + IF_NAMESIZE + sizeof(route_entry) 448 + addressSize); 449 } 450 451 free(buffer); 452 } 453 454 455 void 456 delete_route(int socket, const char *interface, route_entry &route) 457 { 458 ifreq request; 459 if (!prepare_request(request, interface)) 460 return; 461 462 request.ifr_route = route; 463 464 if (ioctl(socket, SIOCDELRT, &request, sizeof(request)) < 0) { 465 fprintf(stderr, "%s: Could not delete route for %s: %s\n", 466 kProgramName, interface, strerror(errno)); 467 } 468 } 469 470 471 void 472 add_route(int socket, const char *interface, route_entry &route) 473 { 474 ifreq request; 475 if (!prepare_request(request, interface)) 476 return; 477 478 route.flags |= RTF_STATIC; 479 request.ifr_route = route; 480 481 if (ioctl(socket, SIOCADDRT, &request, sizeof(request)) < 0) { 482 fprintf(stderr, "%s: Could not add route for %s: %s\n", 483 kProgramName, interface, strerror(errno)); 484 } 485 } 486 487 488 void 489 get_route(int socket, route_entry &route) 490 { 491 union { 492 route_entry request; 493 uint8 buffer[512]; 494 }; 495 496 request = route; 497 498 if (ioctl(socket, SIOCGETRT, buffer, sizeof(buffer)) < 0) { 499 fprintf(stderr, "%s: Could not get route: %s\n", 500 kProgramName, strerror(errno)); 501 return; 502 } 503 504 // find family 505 const address_family *family = NULL; 506 for (int32 i = 0; kFamilies[i].family >= 0; i++) { 507 if (route.destination->sa_family == kFamilies[i].family) { 508 family = &kFamilies[i]; 509 break; 510 } 511 } 512 513 if (family != NULL) { 514 printf("%s", family->address_to_string(request.destination)); 515 switch (family->preferred_format) { 516 case PREFER_OUTPUT_MASK: 517 printf(" mask %s ", 518 family->address_to_string(request.mask)); 519 break; 520 case PREFER_OUTPUT_PREFIX_LENGTH: 521 printf("/%u ", 522 family->mask_to_prefix_length(request.mask)); 523 break; 524 } 525 526 if (request.flags & RTF_GATEWAY) 527 printf("gateway %s ", family->address_to_string(request.gateway)); 528 529 printf("source %s\n", family->address_to_string(request.source)); 530 } else { 531 printf("unknown family "); 532 } 533 } 534 535 536 // #pragma mark - 537 538 539 int 540 main(int argc, char** argv) 541 { 542 if (argc > 1 && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h"))) 543 usage(0); 544 545 int32 mode = RTM_LIST; 546 547 if (argc > 1) { 548 if (!strcmp(argv[1], "delete") 549 || !strcmp(argv[1], "del") 550 || !strcmp(argv[1], "-d")) { 551 // delete route 552 if (argc < 3) 553 usage(1); 554 555 mode = RTM_DELETE; 556 } else if (!strcmp(argv[1], "add") 557 || !strcmp(argv[1], "-a")) { 558 // add route 559 if (argc < 3) 560 usage(1); 561 562 mode = RTM_ADD; 563 } else if (!strcmp(argv[1], "get")) { 564 // get route for destination 565 if (argc < 3) 566 usage(1); 567 568 mode = RTM_GET; 569 } 570 } 571 572 int32 i = 2; 573 int32 interfaceIndex = i; 574 bool familySpecified = false; 575 int32 familyIndex = 0; 576 const char *interface = NULL; 577 sockaddr_storage destination; 578 sockaddr_storage mask; 579 sockaddr_storage gateway; 580 bool hasDestination = false, hasGateway = false, hasMask = false; 581 bool defaultRoute = false; 582 583 route_entry route; 584 memset(&route, 0, sizeof(route_entry)); 585 586 while (i < argc && i < 5) { 587 // try to parse address family 588 if (i <= 3 && familySpecified == false 589 && get_address_family(argv[i], familyIndex)) { 590 familySpecified = true; 591 if (i == 2) 592 interfaceIndex = -1; 593 } 594 595 if (!strcmp(argv[i], "default")) { 596 defaultRoute = true; 597 route.flags = RTF_DEFAULT; 598 i++; 599 break; 600 } else if (parse_address(familyIndex, argv[i], destination)) { 601 hasDestination = true; 602 i++; 603 break; 604 } 605 606 i++; 607 } 608 609 if (!defaultRoute && !hasDestination && mode != RTM_LIST) 610 usage(1); 611 612 if (i == 3) 613 interfaceIndex = -1; 614 if (interfaceIndex != -1 && interfaceIndex < argc) 615 interface = argv[interfaceIndex]; 616 617 if (i < argc && parse_address(familyIndex, argv[i], mask)) { 618 hasMask = true; 619 i++; 620 } 621 622 // parse options and flags 623 624 while (i < argc) { 625 if (!strcmp(argv[i], "gw") || !strcmp(argv[i], "gateway")) { 626 if (!parse_address(familyIndex, argv[i + 1], gateway)) { 627 fprintf(stderr, "%s: Option 'gw' needs valid address parameter\n", 628 kProgramName); 629 exit(1); 630 } 631 hasGateway = true; 632 i++; 633 } else if (!strcmp(argv[i], "nm") || !strcmp(argv[i], "netmask")) { 634 if (hasMask) { 635 fprintf(stderr, "%s: Netmask or prefix length is specified twice\n", 636 kProgramName); 637 exit(1); 638 } 639 if (!parse_address(familyIndex, argv[i + 1], mask)) { 640 fprintf(stderr, "%s: Option 'netmask' needs valid address parameter\n", 641 kProgramName); 642 exit(1); 643 } 644 hasMask = true; 645 i++; 646 } else if (!strcmp(argv[i], "plen") || !strcmp(argv[i], "prefixlen")) { 647 if (hasMask) { 648 fprintf(stderr, "%s: Netmask or prefix length is specified twice\n", 649 kProgramName); 650 exit(1); 651 } 652 if (!prefix_length_to_mask(familyIndex, argv[i + 1], mask)) { 653 fprintf(stderr, "%s: Option 'prefixlen' is invalid for this " 654 "address family\n", kProgramName); 655 exit(1); 656 } 657 hasMask = true; 658 i++; 659 } else if (!strcmp(argv[i], "mtu")) { 660 route.mtu = argv[i + 1] ? strtol(argv[i + 1], NULL, 0) : 0; 661 if (route.mtu <= 500) { 662 fprintf(stderr, "%s: Option 'mtu' exptected valid max transfer unit size\n", 663 kProgramName); 664 exit(1); 665 } 666 i++; 667 } else if (!strcmp(argv[i], "host")) { 668 route.flags |= RTF_HOST; 669 } else if (!strcmp(argv[i], "local")) { 670 route.flags |= RTF_LOCAL; 671 } else if (!strcmp(argv[i], "reject")) { 672 route.flags |= RTF_REJECT; 673 } else 674 usage(1); 675 676 i++; 677 } 678 679 if (hasDestination) 680 route.destination = (sockaddr*)&destination; 681 if (hasMask) 682 route.mask = (sockaddr*)&mask; 683 if (hasGateway) { 684 route.gateway = (sockaddr*)&gateway; 685 route.flags |= RTF_GATEWAY; 686 } 687 688 // we need a socket to talk to the networking stack 689 int socket = ::socket(kFamilies[familyIndex].family, SOCK_DGRAM, 0); 690 if (socket < 0) { 691 fprintf(stderr, "%s: The requested address family is not available.\n", 692 kProgramName); 693 return 1; 694 } 695 696 switch (mode) { 697 case RTM_ADD: 698 if (interface == NULL) { 699 fprintf(stderr, "%s: You need to specify an interface when adding a route.\n", 700 kProgramName); 701 usage(1); 702 } 703 704 add_route(socket, interface, route); 705 break; 706 case RTM_DELETE: 707 if (interface == NULL) { 708 fprintf(stderr, "%s: You need to specify an interface when removing a route.\n", 709 kProgramName); 710 usage(1); 711 } 712 713 delete_route(socket, interface, route); 714 break; 715 716 case RTM_LIST: 717 if (familySpecified) 718 list_routes(socket, interface, route); 719 else { 720 for (int32 i = 0; kFamilies[i].family >= 0; i++) { 721 int socket = ::socket(kFamilies[i].family, SOCK_DGRAM, 0); 722 if (socket < 0) 723 continue; 724 725 list_routes(socket, interface, route); 726 close(socket); 727 } 728 } 729 break; 730 731 case RTM_GET: 732 get_route(socket, route); 733 break; 734 } 735 736 close(socket); 737 return 0; 738 } 739 740