2 * netsniff-ng - the packet sniffing beast
3 * Copyright 2013 Daniel Borkmann.
4 * Subject to the GPL, version 2.
11 #include <GeoIPCity.h>
12 #include <netinet/in.h>
14 #include <sys/types.h>
29 const char *desc
, *local
;
30 const char *remote
, *possible_prefix
;
33 #define PRE "/download/geoip/database"
34 static const struct file files
[] = {
35 [GEOIP_CITY_EDITION_REV1
] = {
37 .local
= PREFIX_STRING
"/etc/netsniff-ng/city4.dat",
38 .remote
= "/GeoLiteCity.dat.gz",
39 .possible_prefix
= PRE
,
41 [GEOIP_CITY_EDITION_REV1_V6
] = {
43 .local
= PREFIX_STRING
"/etc/netsniff-ng/city6.dat",
44 .remote
= "/GeoLiteCityv6.dat.gz",
45 .possible_prefix
= PRE
"/GeoLiteCityv6-beta",
47 [GEOIP_COUNTRY_EDITION
] = {
48 .desc
= "Country IPv4",
49 .local
= PREFIX_STRING
"/etc/netsniff-ng/country4.dat",
50 .remote
= "/GeoIP.dat.gz",
51 .possible_prefix
= PRE
"/GeoLiteCountry",
53 [GEOIP_COUNTRY_EDITION_V6
] = {
54 .desc
= "Country IPv6",
55 .local
= PREFIX_STRING
"/etc/netsniff-ng/country6.dat",
56 .remote
= "/GeoIPv6.dat.gz",
57 .possible_prefix
= PRE
,
59 [GEOIP_ASNUM_EDITION
] = {
60 .desc
= "AS Numbers IPv4",
61 .local
= PREFIX_STRING
"/etc/netsniff-ng/asname4.dat",
62 .remote
= "/GeoIPASNum.dat.gz",
63 .possible_prefix
= PRE
"/asnum",
65 [GEOIP_ASNUM_EDITION_V6
] = {
66 .desc
= "AS Numbers IPv6",
67 .local
= PREFIX_STRING
"/etc/netsniff-ng/asname6.dat",
68 .remote
= "/GeoIPASNumv6.dat.gz",
69 .possible_prefix
= PRE
"/asnum",
73 static GeoIP
*gi4_asname
= NULL
, *gi6_asname
= NULL
;
74 static GeoIP
*gi4_country
= NULL
, *gi6_country
= NULL
;
75 static GeoIP
*gi4_city
= NULL
, *gi6_city
= NULL
;
77 static GeoIPRecord empty
= { 0 };
79 static char *servers
[16] = { 0 };
81 #define CITYV4 (1 << 0)
82 #define CITYV6 (1 << 1)
83 #define COUNTRYV4 (1 << 2)
84 #define COUNTRYV6 (1 << 3)
85 #define ASNAMV4 (1 << 4)
86 #define ASNAMV6 (1 << 5)
88 #define HAVEALL (CITYV4 | CITYV6 | COUNTRYV4 | COUNTRYV6 | ASNAMV4 | ASNAMV6)
90 static int geoip_db_present
= 0;
92 int geoip_working(void)
94 return geoip_db_present
== HAVEALL
;
97 static int geoip_get_remote_fd(const char *server
, const char *port
)
100 struct addrinfo hints
, *ahead
, *ai
;
102 bug_on(!server
|| !port
);
104 memset(&hints
, 0, sizeof(hints
));
106 hints
.ai_family
= PF_UNSPEC
;
107 hints
.ai_socktype
= SOCK_STREAM
;
108 hints
.ai_protocol
= IPPROTO_TCP
;
109 hints
.ai_flags
= AI_NUMERICSERV
;
111 ret
= getaddrinfo(server
, port
, &hints
, &ahead
);
115 for (ai
= ahead
; ai
!= NULL
&& fd
< 0; ai
= ai
->ai_next
) {
116 fd
= socket(ai
->ai_family
, ai
->ai_socktype
, ai
->ai_protocol
);
120 ret
= connect(fd
, ai
->ai_addr
, ai
->ai_addrlen
);
135 static void geoip_inflate(int which
)
140 char zfile
[128], raw
[4096];
142 slprintf(zfile
, sizeof(zfile
), "%s.gz", files
[which
].local
);
143 fpi
= gzopen(zfile
, "rb");
145 panic("No %s file!\n", zfile
);
147 fpo
= fopen(files
[which
].local
, "wb");
149 panic("Cannot create %s!\n", files
[which
].local
);
151 while ((ret
= gzread(fpi
, raw
, sizeof(raw
))) && ret2
)
152 ret2
= fwrite(raw
, ret
, 1, fpo
);
158 static int geoip_get_database(const char *host
, int which
)
160 int found
, sock
, fd
, i
, good
, retry
= 0;
161 ssize_t ret
, len
, rtotlen
= 0, totlen
= 0;
162 char raw
[4096], *ptr
, zfile
[128];
163 size_t lenl
= strlen("Content-Length: ");
164 size_t lent
= strlen("HTTP/1.1 200 OK");
165 size_t lenc
= strlen("\r\n\r\n");
172 sock
= geoip_get_remote_fd(host
, "80");
176 slprintf(raw
, sizeof(raw
), "GET %s%s HTTP/1.1\nHost: %s\r\n\r\n",
177 retry
? files
[which
].possible_prefix
: "",
178 files
[which
].remote
, host
);
180 ret
= write(sock
, raw
, strlen(raw
));
186 shutdown(sock
, SHUT_WR
);
188 slprintf(zfile
, sizeof(zfile
), "%s.gz", files
[which
].local
);
189 fd
= open_or_die_m(zfile
, O_WRONLY
| O_CREAT
| O_TRUNC
, DEFFILEMODE
);
191 memset(raw
, 0, sizeof(raw
));
192 ret
= read(sock
, raw
, sizeof(raw
));
199 raw
[sizeof(raw
) - 1] = 0;
201 for (i
= 0; i
< ret
; i
++) {
202 if (!strncmp(raw
+ i
, "Content-Length: ", min(ret
- i
, lenl
))) {
203 ptr
= raw
+ i
+ lenl
;
204 rtotlen
= strtoul(ptr
, NULL
, 10);
207 if (!strncmp(raw
+ i
, "HTTP/1.1 200 OK", min(ret
- i
, lent
)))
210 if (!strncmp(raw
+ i
, "\r\n\r\n", min(ret
- i
, lenc
))) {
211 ptr
= raw
+ i
+ lenc
;
212 len
= ret
- i
- lenc
;
218 if (!found
|| ptr
>= raw
+ ret
|| len
< 0 || rtotlen
== 0 || good
== 0) {
231 write_or_die(fd
, ptr
, len
);
233 printf("\r%s [%.2f%%, %zd/%zd, %s]", files
[which
].desc
,
234 100.f
* totlen
/ rtotlen
, totlen
, rtotlen
, host
);
237 memset(raw
, 0, sizeof(raw
));
238 ret
= read(sock
, raw
, sizeof(raw
));
249 if (totlen
!= rtotlen
) {
250 unlink(files
[which
].local
);
254 geoip_inflate(which
);
260 static GeoIPRecord
*geoip4_get_record(struct sockaddr_in sa
)
262 bug_on(gi4_city
== NULL
);
264 return GeoIP_record_by_ipnum(gi4_city
, ntohl(sa
.sin_addr
.s_addr
)) ? : &empty
;
267 static GeoIPRecord
*geoip6_get_record(struct sockaddr_in6 sa
)
269 bug_on(gi6_city
== NULL
);
271 return GeoIP_record_by_ipnum_v6(gi6_city
, sa
.sin6_addr
) ? : &empty
;
274 const char *geoip4_as_name(struct sockaddr_in sa
)
276 bug_on(gi4_asname
== NULL
);
278 return GeoIP_name_by_ipnum(gi4_asname
, ntohl(sa
.sin_addr
.s_addr
));
281 const char *geoip6_as_name(struct sockaddr_in6 sa
)
283 bug_on(gi6_asname
== NULL
);
285 return GeoIP_name_by_ipnum_v6(gi6_asname
, sa
.sin6_addr
);
288 float geoip4_longitude(struct sockaddr_in sa
)
290 return geoip4_get_record(sa
)->longitude
;
293 float geoip4_latitude(struct sockaddr_in sa
)
295 return geoip4_get_record(sa
)->latitude
;
298 float geoip6_longitude(struct sockaddr_in6 sa
)
300 return geoip6_get_record(sa
)->longitude
;
303 float geoip6_latitude(struct sockaddr_in6 sa
)
305 return geoip6_get_record(sa
)->latitude
;
308 const char *geoip4_city_name(struct sockaddr_in sa
)
310 return geoip4_get_record(sa
)->city
;
313 const char *geoip6_city_name(struct sockaddr_in6 sa
)
315 return geoip6_get_record(sa
)->city
;
318 const char *geoip4_region_name(struct sockaddr_in sa
)
320 return geoip4_get_record(sa
)->region
;
323 const char *geoip6_region_name(struct sockaddr_in6 sa
)
325 return geoip6_get_record(sa
)->region
;
328 const char *geoip4_country_name(struct sockaddr_in sa
)
330 bug_on(gi4_country
== NULL
);
332 return GeoIP_country_name_by_ipnum(gi4_country
, ntohl(sa
.sin_addr
.s_addr
));
335 const char *geoip6_country_name(struct sockaddr_in6 sa
)
337 bug_on(gi6_country
== NULL
);
339 return GeoIP_country_name_by_ipnum_v6(gi6_country
, sa
.sin6_addr
);
342 static int fdout
, fderr
;
344 /* GeoIP people were too stupid to come to the idea that you could set
345 * errno appropriately and return NULL instead of printing stuff from
346 * the library directly that noone can turn off.
349 static void geoip_open_prepare(void)
361 static void geoip_open_restore(void)
370 static GeoIP
*geoip_open_type(int type
, int flags
)
374 geoip_open_prepare();
375 ret
= GeoIP_open_type(type
, flags
);
376 geoip_open_restore();
381 static GeoIP
*geoip_open(const char *filename
, int flags
)
385 geoip_open_prepare();
386 ret
= GeoIP_open(filename
, flags
);
387 geoip_open_restore();
392 static void init_geoip_city_open4(int enforce
)
394 gi4_city
= geoip_open(files
[GEOIP_CITY_EDITION_REV1
].local
, GEOIP_MMAP_CACHE
);
395 if (gi4_city
== NULL
) {
396 gi4_city
= geoip_open_type(GEOIP_CITY_EDITION_REV1
, GEOIP_MMAP_CACHE
);
397 if (gi4_city
== NULL
)
399 panic("Cannot open GeoIP4 city database, try --update!\n");
403 GeoIP_set_charset(gi4_city
, GEOIP_CHARSET_UTF8
);
404 geoip_db_present
|= CITYV4
;
408 static void init_geoip_city_open6(int enforce
)
410 gi6_city
= geoip_open(files
[GEOIP_CITY_EDITION_REV1_V6
].local
, GEOIP_MMAP_CACHE
);
411 if (gi6_city
== NULL
) {
412 gi6_city
= geoip_open_type(GEOIP_CITY_EDITION_REV1_V6
, GEOIP_MMAP_CACHE
);
413 if (gi6_city
== NULL
)
415 panic("Cannot open GeoIP6 city database, try --update!\n");
419 GeoIP_set_charset(gi6_city
, GEOIP_CHARSET_UTF8
);
420 geoip_db_present
|= CITYV6
;
424 static void init_geoip_city(int enforce
)
426 init_geoip_city_open4(enforce
);
427 init_geoip_city_open6(enforce
);
430 static void destroy_geoip_city(void)
432 GeoIP_delete(gi4_city
);
433 GeoIP_delete(gi6_city
);
436 static void init_geoip_country_open4(int enforce
)
438 gi4_country
= geoip_open(files
[GEOIP_COUNTRY_EDITION
].local
, GEOIP_MMAP_CACHE
);
439 if (gi4_country
== NULL
) {
440 gi4_country
= geoip_open_type(GEOIP_COUNTRY_EDITION
, GEOIP_MMAP_CACHE
);
441 if (gi4_country
== NULL
)
443 panic("Cannot open GeoIP4 country database, try --update!\n");
447 GeoIP_set_charset(gi4_country
, GEOIP_CHARSET_UTF8
);
448 geoip_db_present
|= COUNTRYV4
;
452 static void init_geoip_country_open6(int enforce
)
454 gi6_country
= geoip_open(files
[GEOIP_COUNTRY_EDITION_V6
].local
, GEOIP_MMAP_CACHE
);
455 if (gi6_country
== NULL
) {
456 gi6_country
= geoip_open_type(GEOIP_COUNTRY_EDITION_V6
, GEOIP_MMAP_CACHE
);
457 if (gi6_country
== NULL
)
459 panic("Cannot open GeoIP6 country database, try --update!\n");
463 GeoIP_set_charset(gi6_country
, GEOIP_CHARSET_UTF8
);
464 geoip_db_present
|= COUNTRYV6
;
468 static void init_geoip_country(int enforce
)
470 init_geoip_country_open4(enforce
);
471 init_geoip_country_open6(enforce
);
474 static void destroy_geoip_country(void)
476 GeoIP_delete(gi4_country
);
477 GeoIP_delete(gi6_country
);
480 static void init_geoip_asname_open4(int enforce
)
482 gi4_asname
= geoip_open(files
[GEOIP_ASNUM_EDITION
].local
, GEOIP_MMAP_CACHE
);
483 if (gi4_asname
== NULL
) {
484 gi4_asname
= geoip_open_type(GEOIP_ASNUM_EDITION
, GEOIP_MMAP_CACHE
);
485 if (gi4_asname
== NULL
)
487 panic("Cannot open GeoIP4 AS database, try --update!\n");
491 GeoIP_set_charset(gi4_asname
, GEOIP_CHARSET_UTF8
);
492 geoip_db_present
|= ASNAMV4
;
496 static void init_geoip_asname_open6(int enforce
)
498 gi6_asname
= geoip_open(files
[GEOIP_ASNUM_EDITION_V6
].local
, GEOIP_MMAP_CACHE
);
499 if (gi6_asname
== NULL
) {
500 gi6_asname
= geoip_open_type(GEOIP_ASNUM_EDITION_V6
, GEOIP_MMAP_CACHE
);
501 if (gi6_asname
== NULL
)
503 panic("Cannot open GeoIP6 AS database, try --update!\n");
507 GeoIP_set_charset(gi6_asname
, GEOIP_CHARSET_UTF8
);
508 geoip_db_present
|= ASNAMV6
;
512 static void init_geoip_asname(int enforce
)
514 init_geoip_asname_open4(enforce
);
515 init_geoip_asname_open6(enforce
);
518 static void destroy_geoip_asname(void)
520 GeoIP_delete(gi4_asname
);
521 GeoIP_delete(gi6_asname
);
524 static void init_mirrors(void)
530 fp
= fopen(PREFIX_STRING
"/etc/netsniff-ng/geoip.conf", "r");
532 panic("Cannot open geoip.conf!\n");
534 fmemset(buff
, 0, sizeof(buff
));
535 while (fgets(buff
, sizeof(buff
), fp
) != NULL
&&
536 i
< array_size(servers
)) {
537 buff
[sizeof(buff
) - 1] = 0;
538 buff
[strlen(buff
) - 1] = 0;
540 if (buff
[0] == '#') {
541 fmemset(buff
, 0, sizeof(buff
));
545 servers
[i
++] = xstrdup(buff
);
546 fmemset(buff
, 0, sizeof(buff
));
552 static void destroy_mirrors(void)
556 for (i
= 0; i
< array_size(servers
); ++i
)
560 void init_geoip(int enforce
)
562 init_geoip_city(enforce
);
563 init_geoip_country(enforce
);
564 init_geoip_asname(enforce
);
567 void update_geoip(void)
569 int i
, j
, ret
, good
= 0;
573 for (i
= 0; i
< array_size(files
); ++i
) {
574 if (files
[i
].local
&& files
[i
].remote
) {
577 for (j
= 0; j
< array_size(servers
); ++j
) {
578 if (servers
[j
] == NULL
)
580 ret
= geoip_get_database(servers
[j
], i
);
588 panic("Cannot get %s from mirrors!\n",
596 void destroy_geoip(void)
598 destroy_geoip_city();
599 destroy_geoip_country();
600 destroy_geoip_asname();
602 geoip_db_present
= 0;