#include #include #include #include #include #include #include #include "ip_to_geo.h" #include "ip_data.c" static const uint8_t* ip_to_geo_rec(uint8_t* ip, unsigned level, const ip_level* root) { unsigned cur_average; const ip_level* cur_ip; unsigned cur_addr; while (1) { cur_ip = root; cur_addr = ip[level]; // Optimistic search if (cur_addr && level != 1) { cur_average = cur_addr >> root->average; while (cur_average-- && cur_ip->next) cur_ip = cur_ip->next; } #define IP_TEST \ { \ if (cur_addr >= cur_ip->start && cur_addr <= cur_ip->end) \ { \ if (cur_ip->childs) \ { \ level++; \ root = cur_ip->childs; \ continue; \ } \ else \ return &cur_ip->code; \ } \ } if (cur_addr < cur_ip->start) { for (cur_ip = cur_ip->prev; cur_ip; cur_ip = cur_ip->prev) IP_TEST; } else if (cur_addr > cur_ip->end) { for (cur_ip = cur_ip->next; cur_ip; cur_ip = cur_ip->next) IP_TEST; } else IP_TEST; break; } return NULL; } const uint8_t* ip_to_geo(uint8_t* ip, unsigned ip_size) { const ip_level* first_level; if (ip_size == 4) first_level = s_root_ip[ip[0]]; else return NULL; if (!first_level) return NULL; return ip_to_geo_rec(ip, 1, first_level); } const uint8_t* get_country_code(const uint8_t* idx) { if (!idx || *idx >= sizeof(country_codes)/sizeof(country_codes[0])) return NULL; return country_codes[*idx]; } int interactive(struct gengetopt_args_info* params) { uint8_t ip[16]; const uint8_t* cc; int ret, ip_size=4; ret = inet_pton(AF_INET, params->ip_arg, ip); if (ret != 1) { ip_size = 16; ret = inet_pton(AF_INET6, params->ip_arg, ip); if (ret != 1) { if (!params->quiet_flag) fprintf(stderr, "Invalid IP %s\n", params->ip_arg); return -1; } } cc = ip_to_geo((uint8_t*)&ret, ip_size); if (params->quiet_flag) printf("%s\n", (cc)?(char*)get_country_code(cc):""); else printf("IP %s : %s\n", params->ip_arg, (cc)?(char*)get_country_code(cc):""); return 0; } int main(int argc, char** argv) { int ret; struct gengetopt_args_info params; ret = cmdline_parser (argc, argv, ¶ms); if (ret) return ret; /* self_test(); */ if (params.ip_given) return interactive(¶ms); else if (params.daemon_flag) return daemonize(¶ms); else cmdline_parser_print_help(); return 0; }