IP to Geo

IP to Geo Git Source Tree

Root/src/ip_to_geo.c

1/*
2 Copyright 2016 Grégory Soutadé
3
4 This file is part of iptogeo.
5
6 iptogeo is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 iptogeo is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with iptogeo. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20#include <sys/socket.h>
21#include <netinet/in.h>
22#include <arpa/inet.h>
23#include <stdint.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27
28#include "ip_to_geo.h"
29
30#include "ip_data.c"
31
32static const uint8_t* ip_to_geo_rec(uint8_t* ip, unsigned level, const ip_level* root)
33{
34 uint8_t cur_average;
35 const ip_level* cur_ip;
36 uint8_t cur_addr;
37
38 while (1)
39 {
40 start_loop:
41 cur_ip = root;
42 cur_addr = ip[level];
43
44 // Optimistic search
45 if (cur_addr && level != 1)
46 {
47 cur_average = cur_addr >> root->average;
48
49 while (cur_average-- && cur_ip->next)
50 cur_ip = cur_ip->next;
51 }
52
53#define IP_TEST \
54 { \
55 if (cur_addr >= cur_ip->start && cur_addr <= cur_ip->end) \
56 { \
57 if (cur_ip->childs) \
58 { \
59 level++; \
60 root = cur_ip->childs; \
61 goto start_loop; \
62 } \
63 else \
64 return &cur_ip->code; \
65 } \
66 }
67
68 if (cur_addr < cur_ip->start)
69 {
70 for (cur_ip = cur_ip->prev; cur_ip; cur_ip = cur_ip->prev)
71 IP_TEST;
72 }
73 else if (cur_addr > cur_ip->end)
74 {
75 for (cur_ip = cur_ip->next; cur_ip; cur_ip = cur_ip->next)
76 IP_TEST;
77 }
78 else
79 IP_TEST;
80
81 break;
82 }
83 return NULL;
84}
85
86
87const uint8_t* ip_to_geo(uint8_t* ip, unsigned ip_size)
88{
89 const ip_level* first_level;
90
91 if (ip_size == 4)
92 first_level = s_root_ipv4[ip[0]];
93 else if (ip_size == 16)
94 first_level = s_root_ipv6[ip[0]];
95 else
96 return NULL;
97
98 if (!first_level) return NULL;
99
100 return ip_to_geo_rec(ip, 1, first_level);
101}
102
103const uint8_t* get_country_code(const uint8_t* idx)
104{
105 if (!idx || *idx >= sizeof(country_codes)/sizeof(country_codes[0]))
106 return NULL;
107
108 return country_codes[*idx];
109}
110
111int interactive(struct gengetopt_args_info* params)
112{
113 uint8_t ip[16];
114 const uint8_t* cc;
115 int ret, ip_size=4;
116
117 ret = inet_pton(AF_INET, params->ip_arg, ip);
118 if (ret != 1)
119 {
120 ip_size = 16;
121 ret = inet_pton(AF_INET6, params->ip_arg, ip);
122 if (ret != 1)
123 {
124 if (!params->quiet_flag)
125 fprintf(stderr, "Invalid IP %s\n", params->ip_arg);
126 return -1;
127 }
128 }
129
130 cc = ip_to_geo(ip, ip_size);
131
132 if (params->quiet_flag)
133 printf("%s\n", (cc)?(char*)get_country_code(cc):"<none>");
134 else
135 printf("IP %s : %s\n", params->ip_arg, (cc)?(char*)get_country_code(cc):"<none>");
136
137 return 0;
138}
139
140int main(int argc, char** argv)
141{
142 int ret;
143 struct gengetopt_args_info params;
144
145 ret = cmdline_parser (argc, argv, &params);
146
147 if (ret) return ret;
148
149 /* self_test(); */
150
151 if (params.ip_given)
152 return interactive(&params);
153 else if (params.daemon_flag)
154 return daemonize(&params);
155 else
156 cmdline_parser_print_help();
157
158 return 0;
159}

Archive Download this file

Branches

Tags