139 lines
3.3 KiB
C
139 lines
3.3 KiB
C
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "ip_to_geo.h"
|
|
|
|
#include "ip_data.c"
|
|
|
|
static const uint8_t* ip_to_geo_rec(uint32_t ipv4, unsigned level, const ip_level* root)
|
|
{
|
|
unsigned cur_average;
|
|
const ip_level* cur_ip = root;
|
|
unsigned cur_addr = (ipv4 >> (level*8)) & 0xFF;
|
|
|
|
// Optimistic search
|
|
if (cur_addr && level != 2)
|
|
{
|
|
cur_average = cur_addr >> root->average;
|
|
|
|
while (cur_average-- && cur_ip->next)
|
|
cur_ip = cur_ip->next;
|
|
}
|
|
|
|
#define IP_TEST \
|
|
do { \
|
|
if (cur_addr >= cur_ip->start && cur_addr <= cur_ip->end) \
|
|
{ \
|
|
if (cur_ip->childs) \
|
|
return ip_to_geo_rec(ipv4, level-1, cur_ip->childs); \
|
|
else \
|
|
return &cur_ip->code; \
|
|
} \
|
|
} while (0)
|
|
|
|
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;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
const uint8_t* ip_to_geo(uint32_t ipv4)
|
|
{
|
|
const ip_level* first_level = s_root_ip[ipv4 >> 24];
|
|
|
|
if (!first_level) return NULL;
|
|
|
|
return ip_to_geo_rec(ipv4, 2, 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 strip_to_int(char* strip_, uint32_t* ip) */
|
|
/* { */
|
|
/* char* saveptr = NULL; */
|
|
/* char* cur; */
|
|
/* int i; */
|
|
/* char* strip = strdup(strip_); */
|
|
|
|
/* *ip = 0; */
|
|
|
|
/* for(i=3; i>=0; i--) */
|
|
/* { */
|
|
/* cur = strtok_r(strip, ".", &saveptr); */
|
|
/* if (!cur) goto end; */
|
|
/* *ip += atoi(cur) << (8*i); */
|
|
/* strip = NULL; */
|
|
/* } */
|
|
|
|
/* cur = strtok_r(strip, ".", &saveptr); */
|
|
/* end: */
|
|
/* free(strip); */
|
|
/* return (cur)?-1:0; */
|
|
/* } */
|
|
|
|
int interactive(struct gengetopt_args_info* params)
|
|
{
|
|
const uint8_t* cc;
|
|
int ret;
|
|
|
|
ret = inet_addr(params->ip_arg);
|
|
if (ret == INADDR_NONE)
|
|
{
|
|
if (!params->quiet_flag)
|
|
fprintf(stderr, "Invalid IP %s\n", params->ip_arg);
|
|
return -1;
|
|
}
|
|
|
|
cc = ip_to_geo((uint32_t)ret);
|
|
|
|
if (params->quiet_flag)
|
|
printf("%s\n", (cc)?(char*)get_country_code(cc):"<none>");
|
|
else
|
|
printf("IP %s : %s\n", params->ip_arg, (cc)?(char*)get_country_code(cc):"<none>");
|
|
|
|
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;
|
|
}
|