/* ipcalc - IP address bitwise calculator * example: * * # ipcalc 210.154.33.106 and /28 * 210.154.33.96 * # ipcalc not /28 * 0.0.0.15 * # ipcalc 210.154.33.106 or not /28 * 210.154.33.111 */ #include #include #include #define IP_STRMAXSIZ sizeof("000.000.000.000") typedef unsigned int IP; enum token_types { TOK_IP, /* 192.168.1.3, /24 */ TOK_OR, /* or */ TOK_XOR, /* xor */ TOK_AND, /* and */ TOK_NOT, /* not */ TOK_LP, /* [ */ TOK_RP, /* ] */ TOK_END }; enum output_type { OUTPUT_DOT, OUTPUT_HEX, OUTPUT_BIN }; static struct { const char *name; int type; } token_table[] = { {"or", TOK_OR}, {"|", TOK_OR}, {"xor", TOK_XOR}, {"^", TOK_XOR}, {"and", TOK_AND}, {"&", TOK_AND}, {"not", TOK_NOT}, {"~", TOK_NOT}, {"(", TOK_LP}, {"[", TOK_LP}, {"{", TOK_LP}, {")", TOK_RP}, {"]", TOK_RP}, {"}", TOK_RP}, {NULL, -1} }; static int token_type; static IP token_value; static int token_count; static int main_argc; static char **main_argv; static void usage(void) { fprintf(stderr, "ipcalc [-hDHB] expr ...\n"); exit(1); } static int parse_bin_ip(const char *str, IP *addr) { int i, b; *addr = 0; for(i = 0; i < 32; i++) { if(str[i] == '0') b = 0; else if(str[i] == '1') b = 1; else return 0; *addr = (*addr << 1) | b; } return 1; } static int parse_ip(const char *str, IP *addr) { int shift, octet, len; char buff[IP_STRMAXSIZ]; char *s, *t; len = strlen(str); if(len == 32) return parse_bin_ip(str, addr); if(len > sizeof(buff)) return 0; strcpy(buff, str); s = buff; shift = 24; *addr = 0; while(*s) { t = s; if(!isdigit(*t)) return 0; while(isdigit(*t)) t++; if(*t == '.') *t++ = '\0'; else if(*t) return 0; if(shift < 0) return 0; octet = atoi(s); if(octet < 0 || octet > 255) return 0; *addr |= octet << shift; s = t; shift -= 8; } return 1; } static int parse_hex_ip(const char *str, IP *addr) { int i, h; if(strlen(str) != 8) return 0; *addr = 0; for(i = 7; i >= 0; i--) { h = str[i]; if('0' <= h && h <= '9') h -= '0'; else if('A' <= h && h <= 'F') h -= 'A' - 10; else if('a' <= h && h <= 'f') h -= 'a' - 10; else return 0; *addr = *addr << 4 | h; } return 1; } static void nexttoken(void) { char *tok; int i; if(token_count == main_argc) { token_type = TOK_END; return; } tok = main_argv[token_count++]; if(tok[0] == '0' && tok[1] == 'x') { if(!parse_hex_ip(tok + 2, &token_value)) goto error; token_type = TOK_IP; return; } if('0' <= *tok && *tok <= '9') { if(!parse_ip(tok, &token_value)) goto error; token_type = TOK_IP; return; } if(*tok == '/') { int bits; if(!isdigit(tok[1])) goto error; bits = atoi(tok + 1); if(bits < 0 || bits > 32) goto error; bits = 32 - bits; /* convert host bits */ token_type = TOK_IP; token_value = (~0u >> bits) << bits; return; } for(i = 0; token_table[i].name; i++) { if(strcmp(tok, token_table[i].name) == 0) { token_type = token_table[i].type; token_value = 0; return; } } error: fprintf(stderr, "Unexpected token: %s\n", tok); exit(1); return; /* dummy */ } static void start_parser(int argc, char **argv) { main_argc = argc; main_argv = argv; token_count = 0; } static char *ip2str(IP addr, int type) { static char buff[33]; char *s; int shift; s = buff; switch(type) { case OUTPUT_HEX: sprintf(buff, "0x%08x", addr); break; case OUTPUT_BIN: for(shift = 31; shift >= 0; shift--) { if((addr >> shift) & 1) *s++ = '1'; else *s++ = '0'; } *s = '\0'; break; case OUTPUT_DOT: default: for(shift = 24; shift >= 0; shift -= 8) { sprintf(s, "%d", (addr >> shift) & 0xff); s += strlen(s); if(shift != 0) *s++ = '.'; } *s = '\0'; } return buff; } static IP expr(void); static IP expr_or(void); static IP expr_xor(void); static IP expr_and(void); static IP expr_not(void); static IP expr_p(void); static IP expr_atom(void); static IP expr(void) { IP value; nexttoken(); value = expr_or(); if(token_type != TOK_END) { fprintf(stderr, "Syntax error\n"); exit(1); } return value; } static IP expr_or(void) { IP value; value = expr_xor(); if(token_type == TOK_OR) { nexttoken(); value |= expr_or(); } return value; } static IP expr_xor(void) { IP value; value = expr_and(); if(token_type == TOK_XOR) { nexttoken(); value ^= expr_xor(); } return value; } static IP expr_and(void) { IP value; value = expr_not(); if(token_type == TOK_AND) { nexttoken(); value &= expr_and(); } return value; } static IP expr_not(void) { IP value; if(token_type == TOK_NOT) { nexttoken(); value = ~expr_not(); } else value = expr_p(); return value; } static IP expr_p(void) { IP value; if(token_type == TOK_LP) { nexttoken(); value = expr_or(); if(token_type != TOK_RP) { fprintf(stderr, "Parenthesis miss match\n"); exit(1); } nexttoken(); } else value = expr_atom(); return value; } static IP expr_atom(void) { IP value; switch(token_type) { case TOK_IP: value = token_value; nexttoken(); return value; } fprintf(stderr, "Syntax error\n"); exit(1); return 0; /* dummy */ } int main(int argc, char **argv) { IP addr; int output_type = OUTPUT_DOT; int i; #ifdef sun extern char *optarg; extern int optind; #endif /* sun */ if(argc < 2) usage(); while((i = getopt(argc, argv, "hHDB")) > 0) { switch(i) { case 'D': output_type = OUTPUT_DOT; break; case 'H': output_type = OUTPUT_HEX; break; case 'B': output_type = OUTPUT_BIN; break; case '?': case 'h': usage(); } } if(optind >= argc) usage(); start_parser(argc - optind, argv + optind); addr = expr(); printf("%s\n", ip2str(addr, output_type)); return 0; }