int main( int argc, char **argv ) { uint8 anAddress[4]; uint8 anMask[4]; uint8 anGateway[4] = { 0, 0, 0, 0 }; const char *pzGateway = NULL, *pzProgram; const char *pzCommand, *pzNetAddr, *pzNetMask; struct rtentry sRoute; bool bLong = false; bool bNetSet = false, bMaskSet = false, bGwSet = false; int c; if ( (pzProgram = strrchr( *argv, '/' )) != NULL ) ++pzProgram; else pzProgram = *argv; memset( &sRoute, 0, sizeof( sRoute ) ); sRoute.rt_metric = 0; sRoute.rt_flags = RTF_UP | RTF_STATIC; /* Not necessary */ while ( ( c = getopt_long( argc, argv, "hlqvi:g:", long_opts, ( int * )0 ) ) != EOF ) { switch ( c ) { case 0: break; case 'l': bLong = true; break; case 'v': g_nShowVersion = true; break; case 'h': g_nShowHelp = true; break; default: usage( pzProgram, 0 ); return ( EXIT_FAILURE ); } } argc -= optind; argv += optind; if ( (pzCommand = *argv++) == NULL ) { usage( pzProgram, 0 ); return ( EXIT_FAILURE ); } /* Check command is valid */ if ( strcmp( pzCommand, "list" ) == 0 ) { list_routes( bLong ); return ( EXIT_SUCCESS ); } else if ( strcmp( pzCommand, "add" ) != 0 && strcmp( pzCommand, "del" ) != 0 ) { usage( pzProgram, 0 ); return ( EXIT_FAILURE ); } /* Add or delete a route */ /* Look for address parameter */ while ( *argv ) { const char *pzInstruction = *argv++; char *pzArg = *argv++; if ( pzArg == NULL ) { /* No argument */ usage( pzProgram, 0 ); return ( EXIT_FAILURE ); } if ( strcmp( pzInstruction, "net" ) == 0 ) { char *pzStr; if( bNetSet == true ) { usage( pzProgram, 0 ); return ( EXIT_FAILURE ); } if( strcmp( pzArg, "default" ) == 0 ) { bNetSet = true; bMaskSet = true; } else { if( (pzStr = strchr( pzArg, '/' )) != NULL ) { /* CIDR notation in address parameter */ int nBits; uint32 nIpAddr = 0xFFFFFFFF; *pzStr++ = 0; if( (nBits = atoi( pzStr )) < 32 ) nIpAddr <<= (32 - nBits); *((uint32 *)&((struct sockaddr_in *)&sRoute.rt_genmask)->sin_addr) = htonl( nIpAddr ); bMaskSet = true; } /* Interpret as IP address */ parse_ipaddress( (uint8*)&((struct sockaddr_in *)&sRoute.rt_dst)->sin_addr, pzArg ); bNetSet = true; } } else if ( strcmp( pzInstruction, "mask" ) == 0 ) { if( bMaskSet == true ) { usage( pzProgram, 0 ); return ( EXIT_FAILURE ); } parse_ipaddress( (uint8*)&((struct sockaddr_in *)&sRoute.rt_genmask)->sin_addr, pzArg ); bMaskSet = true; } else if ( strcmp( pzInstruction, "gw" ) == 0 ) { if( bGwSet == true ) { usage( pzProgram, 0 ); return ( EXIT_FAILURE ); } parse_ipaddress( (uint8*)&((struct sockaddr_in *)&sRoute.rt_gateway)->sin_addr, pzArg ); sRoute.rt_flags |= RTF_GATEWAY; bGwSet = true; } else { usage( pzProgram, 0 ); return ( EXIT_FAILURE ); } } /* Check for required arguments */ if( !bNetSet || !bMaskSet ) { usage( pzProgram, 0 ); return ( EXIT_FAILURE ); } /* Perform action */ if ( strcmp( pzCommand, "add" ) == 0 ) { add_route( &sRoute ); } else if ( strcmp( pzCommand, "del" ) == 0 ) { del_route( &sRoute ); } return ( EXIT_SUCCESS ); }
int main(int argc, char** argv) { if (argc > 1 && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h"))) usage(0); int32 mode = RTM_LIST; if (argc > 1) { if (!strcmp(argv[1], "delete") || !strcmp(argv[1], "del") || !strcmp(argv[1], "-d")) { // delete route if (argc < 3) usage(1); mode = RTM_DELETE; } else if (!strcmp(argv[1], "add") || !strcmp(argv[1], "-a")) { // add route if (argc < 3) usage(1); mode = RTM_ADD; } else if (!strcmp(argv[1], "get")) { // get route for destination if (argc < 3) usage(1); mode = RTM_GET; } } int32 i = 2; int32 interfaceIndex = i; bool familySpecified = false; int32 familyIndex = 0; const char *interface = NULL; sockaddr_storage destination; sockaddr_storage mask; sockaddr_storage gateway; bool hasDestination = false, hasGateway = false, hasMask = false; bool defaultRoute = false; route_entry route; memset(&route, 0, sizeof(route_entry)); while (i < argc && i < 5) { // try to parse address family if (i <= 3 && familyIndex == -1 && get_address_family(argv[i], familyIndex)) { familySpecified = true; if (i == 2) interfaceIndex = -1; } if (!strcmp(argv[i], "default")) { defaultRoute = true; route.flags = RTF_DEFAULT; i++; break; } else if (parse_address(familyIndex, argv[i], destination)) { hasDestination = true; i++; break; } i++; } if (!defaultRoute && !hasDestination && mode != RTM_LIST) usage(1); if (i == 3) interfaceIndex = -1; if (interfaceIndex != -1 && interfaceIndex < argc) interface = argv[interfaceIndex]; if (i < argc && parse_address(familyIndex, argv[i], mask)) { hasMask = true; i++; } // parse options and flags while (i < argc) { if (!strcmp(argv[i], "gw") || !strcmp(argv[i], "gateway")) { if (!parse_address(familyIndex, argv[i + 1], gateway)) { fprintf(stderr, "%s: Option 'gw' needs valid address parameter\n", kProgramName); exit(1); } hasGateway = true; i++; } else if (!strcmp(argv[i], "nm") || !strcmp(argv[i], "netmask")) { if (hasMask) { fprintf(stderr, "%s: Netmask is specified twice\n", kProgramName); exit(1); } if (!parse_address(familyIndex, argv[i + 1], mask)) { fprintf(stderr, "%s: Option 'netmask' needs valid address parameter\n", kProgramName); exit(1); } hasMask = true; i++; } else if (!strcmp(argv[i], "mtu")) { route.mtu = argv[i + 1] ? strtol(argv[i + 1], NULL, 0) : 0; if (route.mtu <= 500) { fprintf(stderr, "%s: Option 'mtu' exptected valid max transfer unit size\n", kProgramName); exit(1); } i++; } else if (!strcmp(argv[i], "host")) { route.flags |= RTF_HOST; } else if (!strcmp(argv[i], "local")) { route.flags |= RTF_LOCAL; } else if (!strcmp(argv[i], "reject")) { route.flags |= RTF_REJECT; } else usage(1); i++; } if (hasDestination) route.destination = (sockaddr *)&destination; if (hasMask) route.mask = (sockaddr *)&mask; if (hasGateway) { route.gateway = (sockaddr *)&gateway; route.flags |= RTF_GATEWAY; } // we need a socket to talk to the networking stack int socket = ::socket(kFamilies[familyIndex].family, SOCK_DGRAM, 0); if (socket < 0) { fprintf(stderr, "%s: The requested address family is not available.\n", kProgramName); return 1; } switch (mode) { case RTM_ADD: if (interface == NULL) { fprintf(stderr, "%s: You need to specify an interface when adding a route.\n", kProgramName); usage(1); } add_route(socket, interface, route); break; case RTM_DELETE: if (interface == NULL) { fprintf(stderr, "%s: You need to specify an interface when removing a route.\n", kProgramName); usage(1); } delete_route(socket, interface, route); break; case RTM_LIST: if (familySpecified) list_routes(socket, interface, route); else { for (int32 i = 0; kFamilies[i].family >= 0; i++) { int socket = ::socket(kFamilies[familyIndex].family, SOCK_DGRAM, 0); if (socket < 0) continue; list_routes(socket, interface, route); close(socket); } } break; case RTM_GET: get_route(socket, route); break; } close(socket); return 0; }