/* * cidr just takes an ip and a netmask and converts to CIDR notation. * * For example, address=192.168.4.4 and netmask=255.255.255.0 would * give you a network in CIDR notation of 192.168.4.0/24. * * (CIDR ==> Classless InterDomain Routing) * */ #include #include #include #include #include typedef unsigned int uint32; static const char* progname; static uint32 address; static uint32 netmask; static char version[] = "1.0"; static struct option optv[] = { {"help", 0, NULL, 'h'}, {"version", 0, NULL, 'v'}, {0, 0, NULL, 0} }; static const char* basename(const char* fullpath) { const char* rv = strrchr(fullpath, '/'); if( rv == NULL ) { rv = fullpath; } else { ++rv; } return rv; } static void usage(int rv) { FILE* f = 0; if( rv == 0 ) { f = stdout; } else { f = stderr; } fprintf(f, "\n"); fprintf(f, "Usage: %s [options]
\n", basename(progname)); fprintf(f, "\n"); fprintf(f, " Valid options are as follows:\n"); fprintf(f, " -h : Show help message.\n"); fprintf(f, " --help : Show help message.\n"); fprintf(f, "\n"); fprintf(f, " This program converts
and into valid " "CIDR notation.\n"); fprintf(f, " (CIDR ==> Classless InterDomain Routing notation).\n"); fprintf(f, "\n"); exit(rv); } /* Returns string that you need to free() on success; return NULL on * failure. */ static char* ip_uint32_to_string(uint32 ip) { /* Store each part of the dotted quad in ipv in network-byte order. */ uint32 ipv[4]; int i = 0; char* rv = NULL; if( (rv = malloc((size_t)16)) == NULL ) { fprintf(stderr, "malloc: %s\n", strerror(errno)); exit(1); } for( i = 3 ; i >= 0 ; --i ) { ipv[i] = ip & 0xff; ip >>= 8; } sprintf(rv, "%u.%u.%u.%u", ipv[0], ipv[1], ipv[2], ipv[3]); return rv; } /* Returns 1 on success; 0 on failure. */ static int ip_string_to_uint32(const char* s, uint32* ip) { int rv = 1; int dot_count = 0; const char* tmp = NULL; uint32 ipv[4]; /* This hold the IP -- but with the big end in ipv[0], * i.e., in network-byte order. */ /* Set elements of ipv array to illegal value. */ memset((void*)ipv, -1, sizeof(ipv)); /* Break the dotted-quad into four separate strings each with only * digits in it. */ for( tmp = s ; *tmp != '\0' ; ++tmp ) { /* Dots break the integers. */ if( *tmp == '.' ) { ++dot_count; if( dot_count > 3 ) { rv = 0; goto clean_up; } /* Accumulate. */ } else if( (*tmp >= '0') && (*tmp <= '9') ) { /* You need to clear the invalid value before starting to accumulate. */ if(ipv[dot_count] == (uint32)-1) { ipv[dot_count] = 0; } ipv[dot_count] = 10 * ipv[dot_count] + (*tmp - '0'); /* Invalid character. */ } else { rv = 0; goto clean_up; } } /* Need to verify the integers. As you go along, prepare the return * value as well. */ { int i = 0; int tmp = 0; for( i = 0 ; i < 4 ; ++i ) { if( ipv[i] > 255 ) { rv = 0; goto clean_up; } tmp |= ipv[i]; if( i < 3 ) { tmp <<= 8; } } *ip = tmp; } clean_up: return rv; } static int netmask_bit_count(uint32 netmask) { int rv = 0; uint32 bitmask = 0x80000000; for( ; (netmask & bitmask) != 0 ; bitmask >>= 1 ) { ++rv; } return rv; } static void adjust_args(int* argc, char** argv, int optind) { int dst = 1; int src = optind; for( ; src < *argc ; ++dst, ++src ) { argv[dst] = argv[src]; } *argc -= optind - 1; argv[dst] = NULL; } static void parse_command_line(int* argc, char** argv) { int opt = -1; progname = argv[0]; while( (opt = getopt_long(*argc, argv, ":hv", optv, NULL)) != -1 ) { switch(opt) { case (int)'h': usage(0); break; case (int)'v': printf("%s: v%s\n", basename(progname), version); exit(0); break; default: fprintf(stderr, "\n"); fprintf(stderr, "Error: Invalid parameter \"%s\" at index %d.\n", argv[optind - 1], optind - 1); usage(1); break; } } adjust_args(argc, argv, optind); if( *argc != 3 ) { usage(1); } if( !ip_string_to_uint32(argv[1], &address) ) { fprintf(stderr, "\n"); fprintf(stderr, "Error: Invalid IP format for address \"%s\".\n", argv[1]); usage(1); } if( !ip_string_to_uint32(argv[2], &netmask) ) { fprintf(stderr, "\n"); fprintf(stderr, "Error: Invalid IP format for netmask \"%s\".\n", argv[2]); usage(1); } } int main(int argc, char* argv[]) { char* network_ip_string = NULL; parse_command_line(&argc, argv); network_ip_string = ip_uint32_to_string(address & netmask); printf("%s/%d\n", network_ip_string, netmask_bit_count(netmask)); free(network_ip_string); return 0; }