Merge pull request #58 from electronjoe/a1cf780cccc4819eb360cda1e0e94e17935cb8c7
[netsniff-ng-old.git] / geoip.c
blobfc61184c1af0b7cc0d45a9bf7189d262d75430a6
1 /*
2 * netsniff-ng - the packet sniffing beast
3 * Copyright 2013 Daniel Borkmann.
4 * Subject to the GPL, version 2.
5 */
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <GeoIP.h>
11 #include <GeoIPCity.h>
12 #include <netinet/in.h>
13 #include <netdb.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <fcntl.h>
17 #include <unistd.h>
19 #include "built_in.h"
20 #include "die.h"
21 #include "xutils.h"
22 #include "xio.h"
23 #include "xmalloc.h"
24 #include "zlib.h"
25 #include "geoip.h"
27 struct file {
28 const char *desc, *local;
29 const char *remote, *possible_prefix;
32 #define PRE "/download/geoip/database"
33 static const struct file files[] = {
34 [GEOIP_CITY_EDITION_REV1] = {
35 .desc = "City IPv4",
36 .local = "/etc/netsniff-ng/city4.dat",
37 .remote = "/GeoLiteCity.dat.gz",
38 .possible_prefix = PRE,
40 [GEOIP_CITY_EDITION_REV1_V6] = {
41 .desc = "City IPv6",
42 .local = "/etc/netsniff-ng/city6.dat",
43 .remote = "/GeoLiteCityv6.dat.gz",
44 .possible_prefix = PRE "/GeoLiteCityv6-beta",
46 [GEOIP_COUNTRY_EDITION] = {
47 .desc = "Country IPv4",
48 .local = "/etc/netsniff-ng/country4.dat",
49 .remote = "/GeoIP.dat.gz",
50 .possible_prefix = PRE "/GeoLiteCountry",
52 [GEOIP_COUNTRY_EDITION_V6] = {
53 .desc = "Country IPv6",
54 .local = "/etc/netsniff-ng/country6.dat",
55 .remote = "/GeoIPv6.dat.gz",
56 .possible_prefix = PRE,
58 [GEOIP_ASNUM_EDITION] = {
59 .desc = "AS Numbers IPv4",
60 .local = "/etc/netsniff-ng/asname4.dat",
61 .remote = "/GeoIPASNum.dat.gz",
62 .possible_prefix = PRE "/asnum",
64 [GEOIP_ASNUM_EDITION_V6] = {
65 .desc = "AS Numbers IPv6",
66 .local = "/etc/netsniff-ng/asname6.dat",
67 .remote = "/GeoIPASNumv6.dat.gz",
68 .possible_prefix = PRE "/asnum",
72 static GeoIP *gi4_asname = NULL, *gi6_asname = NULL;
73 static GeoIP *gi4_country = NULL, *gi6_country = NULL;
74 static GeoIP *gi4_city = NULL, *gi6_city = NULL;
76 static GeoIPRecord empty = { 0 };
78 static char *servers[16] = { 0 };
80 #define CITYV4 (1 << 0)
81 #define CITYV6 (1 << 1)
82 #define COUNTRYV4 (1 << 2)
83 #define COUNTRYV6 (1 << 3)
84 #define ASNAMV4 (1 << 4)
85 #define ASNAMV6 (1 << 5)
87 #define HAVEALL (CITYV4 | CITYV6 | COUNTRYV4 | COUNTRYV6 | ASNAMV4 | ASNAMV6)
89 static int geoip_db_present = 0;
91 int geoip_working(void)
93 return geoip_db_present == HAVEALL;
96 static int geoip_get_remote_fd(const char *server, const char *port)
98 int ret, fd = -1;
99 struct addrinfo hints, *ahead, *ai;
101 bug_on(!server || !port);
103 memset(&hints, 0, sizeof(hints));
105 hints.ai_family = PF_UNSPEC;
106 hints.ai_socktype = SOCK_STREAM;
107 hints.ai_protocol = IPPROTO_TCP;
108 hints.ai_flags = AI_NUMERICSERV;
110 ret = getaddrinfo(server, port, &hints, &ahead);
111 if (ret != 0)
112 return -EIO;
114 for (ai = ahead; ai != NULL && fd < 0; ai = ai->ai_next) {
115 fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
116 if (fd < 0)
117 continue;
119 ret = connect(fd, ai->ai_addr, ai->ai_addrlen);
120 if (ret < 0) {
121 close(fd);
122 fd = -1;
123 continue;
126 break;
129 freeaddrinfo(ahead);
131 return fd;
134 static void geoip_inflate(int which)
136 int ret, ret2 = 1;
137 gzFile fpi;
138 FILE *fpo;
139 char zfile[128], raw[4096];
141 slprintf(zfile, sizeof(zfile), "%s.gz", files[which].local);
142 fpi = gzopen(zfile, "rb");
143 if (fpi == NULL)
144 panic("No %s file!\n", zfile);
146 fpo = fopen(files[which].local, "wb");
147 if (fpo == NULL)
148 panic("Cannot create %s!\n", files[which].local);
150 while ((ret = gzread(fpi, raw, sizeof(raw))) && ret2)
151 ret2 = fwrite(raw, ret, 1, fpo);
153 gzclose(fpi);
154 fclose(fpo);
157 static int geoip_get_database(const char *host, int which)
159 int found, sock, fd, i, good, retry = 0;
160 ssize_t ret, len, rtotlen = 0, totlen = 0;
161 char raw[4096], *ptr, zfile[128];
162 size_t lenl = strlen("Content-Length: ");
163 size_t lent = strlen("HTTP/1.1 200 OK");
164 size_t lenc = strlen("\r\n\r\n");
166 again:
167 found = good = 0;
168 ptr = NULL;
169 len = 0;
171 sock = geoip_get_remote_fd(host, "80");
172 if (sock < 0)
173 return -EIO;
175 slprintf(raw, sizeof(raw), "GET %s%s HTTP/1.1\nHost: %s\r\n\r\n",
176 retry ? files[which].possible_prefix : "",
177 files[which].remote, host);
179 ret = write(sock, raw, strlen(raw));
180 if (ret <= 0)
181 return -EIO;
183 shutdown(sock, SHUT_WR);
185 slprintf(zfile, sizeof(zfile), "%s.gz", files[which].local);
186 fd = open_or_die_m(zfile, O_WRONLY | O_CREAT | O_TRUNC, DEFFILEMODE);
188 memset(raw, 0, sizeof(raw));
189 ret = read(sock, raw, sizeof(raw));
190 if (ret <= 0)
191 return -EIO;
193 for (i = 0; i < ret; i++) {
194 if (!strncmp(raw + i, "Content-Length: ", min(ret - i, lenl))) {
195 ptr = raw + i + lenl;
196 rtotlen = strtoul(ptr, NULL, 10);
199 if (!strncmp(raw + i, "HTTP/1.1 200 OK", min(ret - i, lent)))
200 good = 1;
202 if (!strncmp(raw + i, "\r\n\r\n", min(ret - i, lenc))) {
203 ptr = raw + i + lenc;
204 len = ret - i - lenc;
205 found = 1;
206 break;
210 if (!found || ptr >= raw + ret || len < 0 || rtotlen == 0 || good == 0) {
211 if (retry == 0) {
212 retry = 1;
213 close(fd);
214 close(sock);
215 goto again;
218 return -ENOENT;
221 do {
222 write_or_die(fd, ptr, len);
223 totlen += len;
224 printf("\r%s [%.2f%%, %zd/%zd, %s]", files[which].desc,
225 100.f * totlen / rtotlen, totlen, rtotlen, host);
226 fflush(stdout);
228 memset(raw, 0, sizeof(raw));
229 ret = read(sock, raw, sizeof(raw));
231 ptr = raw;
232 len = ret;
233 } while(ret > 0);
235 printf("\n");
237 if (totlen != rtotlen) {
238 unlink(files[which].local);
239 return -EIO;
242 close(fd);
243 close(sock);
245 geoip_inflate(which);
247 unlink(zfile);
249 return 0;
252 static GeoIPRecord *geoip4_get_record(struct sockaddr_in sa)
254 bug_on(gi4_city == NULL);
256 return GeoIP_record_by_ipnum(gi4_city, ntohl(sa.sin_addr.s_addr)) ? : &empty;
259 static GeoIPRecord *geoip6_get_record(struct sockaddr_in6 sa)
261 bug_on(gi6_city == NULL);
263 return GeoIP_record_by_ipnum_v6(gi6_city, sa.sin6_addr) ? : &empty;
266 const char *geoip4_as_name(struct sockaddr_in sa)
268 bug_on(gi4_asname == NULL);
270 return GeoIP_name_by_ipnum(gi4_asname, ntohl(sa.sin_addr.s_addr));
273 const char *geoip6_as_name(struct sockaddr_in6 sa)
275 bug_on(gi6_asname == NULL);
277 return GeoIP_name_by_ipnum_v6(gi6_asname, sa.sin6_addr);
280 float geoip4_longitude(struct sockaddr_in sa)
282 return geoip4_get_record(sa)->longitude;
285 float geoip4_latitude(struct sockaddr_in sa)
287 return geoip4_get_record(sa)->latitude;
290 float geoip6_longitude(struct sockaddr_in6 sa)
292 return geoip6_get_record(sa)->longitude;
295 float geoip6_latitude(struct sockaddr_in6 sa)
297 return geoip6_get_record(sa)->latitude;
300 const char *geoip4_city_name(struct sockaddr_in sa)
302 return geoip4_get_record(sa)->city;
305 const char *geoip6_city_name(struct sockaddr_in6 sa)
307 return geoip6_get_record(sa)->city;
310 const char *geoip4_region_name(struct sockaddr_in sa)
312 return geoip4_get_record(sa)->region;
315 const char *geoip6_region_name(struct sockaddr_in6 sa)
317 return geoip6_get_record(sa)->region;
320 const char *geoip4_country_name(struct sockaddr_in sa)
322 bug_on(gi4_country == NULL);
324 return GeoIP_country_name_by_ipnum(gi4_country, ntohl(sa.sin_addr.s_addr));
327 const char *geoip6_country_name(struct sockaddr_in6 sa)
329 bug_on(gi6_country == NULL);
331 return GeoIP_country_name_by_ipnum_v6(gi6_country, sa.sin6_addr);
334 static int fdout, fderr;
336 /* GeoIP people were too stupid to come to the idea that you could set
337 * errno appropriately and return NULL instead of printing stuff from
338 * the library directly that noone can turn off.
341 static void geoip_open_prepare(void)
343 fflush(stdout);
344 fdout = dup(1);
346 fflush(stderr);
347 fderr = dup(2);
349 close(1);
350 close(2);
353 static void geoip_open_restore(void)
355 dup2(fdout, 1);
356 dup2(fderr, 2);
358 close(fdout);
359 close(fderr);
362 static GeoIP *geoip_open_type(int type, int flags)
364 GeoIP *ret;
366 geoip_open_prepare();
367 ret = GeoIP_open_type(type, flags);
368 geoip_open_restore();
370 return ret;
373 static GeoIP *geoip_open(const char *filename, int flags)
375 GeoIP *ret;
377 geoip_open_prepare();
378 ret = GeoIP_open(filename, flags);
379 geoip_open_restore();
381 return ret;
384 static void init_geoip_city_open4(int enforce)
386 gi4_city = geoip_open(files[GEOIP_CITY_EDITION_REV1].local, GEOIP_MMAP_CACHE);
387 if (gi4_city == NULL) {
388 gi4_city = geoip_open_type(GEOIP_CITY_EDITION_REV1, GEOIP_MMAP_CACHE);
389 if (gi4_city == NULL)
390 if (enforce)
391 panic("Cannot open GeoIP4 city database, try --update!\n");
394 if (gi4_city) {
395 GeoIP_set_charset(gi4_city, GEOIP_CHARSET_UTF8);
396 geoip_db_present |= CITYV4;
400 static void init_geoip_city_open6(int enforce)
402 gi6_city = geoip_open(files[GEOIP_CITY_EDITION_REV1_V6].local, GEOIP_MMAP_CACHE);
403 if (gi6_city == NULL) {
404 gi6_city = geoip_open_type(GEOIP_CITY_EDITION_REV1_V6, GEOIP_MMAP_CACHE);
405 if (gi6_city == NULL)
406 if (enforce)
407 panic("Cannot open GeoIP6 city database, try --update!\n");
410 if (gi6_city) {
411 GeoIP_set_charset(gi6_city, GEOIP_CHARSET_UTF8);
412 geoip_db_present |= CITYV6;
416 static void init_geoip_city(int enforce)
418 init_geoip_city_open4(enforce);
419 init_geoip_city_open6(enforce);
422 static void destroy_geoip_city(void)
424 GeoIP_delete(gi4_city);
425 GeoIP_delete(gi6_city);
428 static void init_geoip_country_open4(int enforce)
430 gi4_country = geoip_open(files[GEOIP_COUNTRY_EDITION].local, GEOIP_MMAP_CACHE);
431 if (gi4_country == NULL) {
432 gi4_country = geoip_open_type(GEOIP_COUNTRY_EDITION, GEOIP_MMAP_CACHE);
433 if (gi4_country == NULL)
434 if (enforce)
435 panic("Cannot open GeoIP4 country database, try --update!\n");
438 if (gi4_country) {
439 GeoIP_set_charset(gi4_country, GEOIP_CHARSET_UTF8);
440 geoip_db_present |= COUNTRYV4;
444 static void init_geoip_country_open6(int enforce)
446 gi6_country = geoip_open(files[GEOIP_COUNTRY_EDITION_V6].local, GEOIP_MMAP_CACHE);
447 if (gi6_country == NULL) {
448 gi6_country = geoip_open_type(GEOIP_COUNTRY_EDITION_V6, GEOIP_MMAP_CACHE);
449 if (gi6_country == NULL)
450 if (enforce)
451 panic("Cannot open GeoIP6 country database, try --update!\n");
454 if (gi6_country) {
455 GeoIP_set_charset(gi6_country, GEOIP_CHARSET_UTF8);
456 geoip_db_present |= COUNTRYV6;
460 static void init_geoip_country(int enforce)
462 init_geoip_country_open4(enforce);
463 init_geoip_country_open6(enforce);
466 static void destroy_geoip_country(void)
468 GeoIP_delete(gi4_country);
469 GeoIP_delete(gi6_country);
472 static void init_geoip_asname_open4(int enforce)
474 gi4_asname = geoip_open(files[GEOIP_ASNUM_EDITION].local, GEOIP_MMAP_CACHE);
475 if (gi4_asname == NULL) {
476 gi4_asname = geoip_open_type(GEOIP_ASNUM_EDITION, GEOIP_MMAP_CACHE);
477 if (gi4_asname == NULL)
478 if (enforce)
479 panic("Cannot open GeoIP4 AS database, try --update!\n");
482 if (gi4_asname) {
483 GeoIP_set_charset(gi4_asname, GEOIP_CHARSET_UTF8);
484 geoip_db_present |= ASNAMV4;
488 static void init_geoip_asname_open6(int enforce)
490 gi6_asname = geoip_open(files[GEOIP_ASNUM_EDITION_V6].local, GEOIP_MMAP_CACHE);
491 if (gi6_asname == NULL) {
492 gi6_asname = geoip_open_type(GEOIP_ASNUM_EDITION_V6, GEOIP_MMAP_CACHE);
493 if (gi6_asname == NULL)
494 if (enforce)
495 panic("Cannot open GeoIP6 AS database, try --update!\n");
498 if (gi6_asname) {
499 GeoIP_set_charset(gi6_asname, GEOIP_CHARSET_UTF8);
500 geoip_db_present |= ASNAMV6;
504 static void init_geoip_asname(int enforce)
506 init_geoip_asname_open4(enforce);
507 init_geoip_asname_open6(enforce);
510 static void destroy_geoip_asname(void)
512 GeoIP_delete(gi4_asname);
513 GeoIP_delete(gi6_asname);
516 static void init_mirrors(void)
518 int i = 0;
519 FILE *fp;
520 char buff[256];
522 fp = fopen("/etc/netsniff-ng/geoip.conf", "r");
523 if (!fp)
524 panic("Cannot open geoip.conf!\n");
526 fmemset(buff, 0, sizeof(buff));
527 while (fgets(buff, sizeof(buff), fp) != NULL &&
528 i < array_size(servers)) {
529 buff[sizeof(buff) - 1] = 0;
530 buff[strlen(buff) - 1] = 0;
532 if (buff[0] == '#') {
533 fmemset(buff, 0, sizeof(buff));
534 continue;
537 servers[i++] = xstrdup(buff);
538 fmemset(buff, 0, sizeof(buff));
541 fclose(fp);
544 static void destroy_mirrors(void)
546 int i;
548 for (i = 0; i < array_size(servers); ++i)
549 free(servers[i]);
552 void init_geoip(int enforce)
554 init_geoip_city(enforce);
555 init_geoip_country(enforce);
556 init_geoip_asname(enforce);
559 void update_geoip(void)
561 int i, j, ret, good = 0;
563 init_mirrors();
565 for (i = 0; i < array_size(files); ++i) {
566 if (files[i].local && files[i].remote) {
567 good = 0;
569 for (j = 0; j < array_size(servers); ++j) {
570 if (servers[j] == NULL)
571 continue;
572 ret = geoip_get_database(servers[j], i);
573 if (!ret) {
574 good = 1;
575 break;
579 if (good == 0)
580 panic("Cannot get %s from mirrors!\n",
581 files[i].remote);
585 destroy_mirrors();
588 void destroy_geoip(void)
590 destroy_geoip_city();
591 destroy_geoip_country();
592 destroy_geoip_asname();
594 geoip_db_present = 0;