iptogeo/src/ip_to_geo.c
2016-01-31 11:42:28 +01:00

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, &params);
if (ret) return ret;
//self_test();
if (params.ip_given)
return interactive(&params);
else if (params.daemon_flag)
return daemonize(&params);
else
cmdline_parser_print_help();
return 0;
}