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>
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
] = {
36 .local
= DATDIR_STRING
"/city4.dat",
37 .remote
= "/GeoLiteCity.dat.gz",
38 .possible_prefix
= PRE
,
40 [GEOIP_CITY_EDITION_REV1_V6
] = {
42 .local
= DATDIR_STRING
"/city6.dat",
43 .remote
= "/GeoLiteCityv6.dat.gz",
44 .possible_prefix
= PRE
"/GeoLiteCityv6-beta",
46 [GEOIP_COUNTRY_EDITION
] = {
47 .desc
= "Country IPv4",
48 .local
= DATDIR_STRING
"/country4.dat",
49 .remote
= "/GeoIP.dat.gz",
50 .possible_prefix
= PRE
"/GeoLiteCountry",
52 [GEOIP_COUNTRY_EDITION_V6
] = {
53 .desc
= "Country IPv6",
54 .local
= DATDIR_STRING
"/country6.dat",
55 .remote
= "/GeoIPv6.dat.gz",
56 .possible_prefix
= PRE
,
58 [GEOIP_ASNUM_EDITION
] = {
59 .desc
= "AS Numbers IPv4",
60 .local
= DATDIR_STRING
"/asname4.dat",
61 .remote
= "/GeoIPASNum.dat.gz",
62 .possible_prefix
= PRE
"/asnum",
64 [GEOIP_ASNUM_EDITION_V6
] = {
65 .desc
= "AS Numbers IPv6",
66 .local
= DATDIR_STRING
"/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 char *servers
[16] = { NULL
};
78 #define CITYV4 (1 << 0)
79 #define CITYV6 (1 << 1)
80 #define COUNTRYV4 (1 << 2)
81 #define COUNTRYV6 (1 << 3)
82 #define ASNAMV4 (1 << 4)
83 #define ASNAMV6 (1 << 5)
85 #define HAVEALL (CITYV4 | CITYV6 | COUNTRYV4 | COUNTRYV6 | ASNAMV4 | ASNAMV6)
87 static int geoip_db_present
= 0;
89 int geoip_working(void)
91 return geoip_db_present
== HAVEALL
;
94 static int geoip_get_remote_fd(const char *server
, const char *port
)
97 struct addrinfo hints
, *ahead
, *ai
;
99 bug_on(!server
|| !port
);
101 memset(&hints
, 0, sizeof(hints
));
103 hints
.ai_family
= PF_UNSPEC
;
104 hints
.ai_socktype
= SOCK_STREAM
;
105 hints
.ai_protocol
= IPPROTO_TCP
;
106 hints
.ai_flags
= AI_NUMERICSERV
;
108 ret
= getaddrinfo(server
, port
, &hints
, &ahead
);
112 for (ai
= ahead
; ai
!= NULL
&& fd
< 0; ai
= ai
->ai_next
) {
113 fd
= socket(ai
->ai_family
, ai
->ai_socktype
, ai
->ai_protocol
);
117 ret
= connect(fd
, ai
->ai_addr
, ai
->ai_addrlen
);
132 static void geoip_inflate(int which
)
137 char zfile
[128], raw
[4096];
139 slprintf(zfile
, sizeof(zfile
), "%s.gz", files
[which
].local
);
140 fpi
= gzopen(zfile
, "rb");
142 panic("No %s file!\n", zfile
);
144 fpo
= fopen(files
[which
].local
, "wb");
146 panic("Cannot create %s!\n", files
[which
].local
);
148 while ((ret
= gzread(fpi
, raw
, sizeof(raw
))) && ret2
)
149 ret2
= fwrite(raw
, ret
, 1, fpo
);
152 panic("Error in gzread: %s\n", gzerror(fpi
, &ret
));
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");
166 const char *http_req_fmt
= "GET %s%s HTTP/1.1\r\n"
167 "Connection: close\r\n"
174 sock
= geoip_get_remote_fd(host
, "80");
178 slprintf(raw
, sizeof(raw
), http_req_fmt
,
179 retry
? files
[which
].possible_prefix
: "",
180 files
[which
].remote
, host
);
182 ret
= write(sock
, raw
, strlen(raw
));
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 for (i
= 0; i
< ret
; i
++) {
200 if (!strncmp(raw
+ i
, "Content-Length: ", min_t(size_t, ret
- i
, lenl
))) {
201 ptr
= raw
+ i
+ lenl
;
202 rtotlen
= strtoul(ptr
, NULL
, 10);
205 if (!strncmp(raw
+ i
, "HTTP/1.1 200 OK", min_t(size_t, ret
- i
, lent
)))
208 if (!strncmp(raw
+ i
, "\r\n\r\n", min_t(size_t, ret
- i
, lenc
))) {
209 ptr
= raw
+ i
+ lenc
;
210 len
= ret
- i
- lenc
;
216 if (!found
|| ptr
>= raw
+ ret
|| len
< 0 || rtotlen
== 0 || good
== 0) {
229 write_or_die(fd
, ptr
, len
);
231 printf("\r%s [%.2f%%, %zd/%zd, %s]", files
[which
].desc
,
232 100.f
* totlen
/ rtotlen
, totlen
, rtotlen
, host
);
235 memset(raw
, 0, sizeof(raw
));
236 ret
= read(sock
, raw
, sizeof(raw
));
247 if (totlen
!= rtotlen
) {
248 unlink(files
[which
].local
);
252 geoip_inflate(which
);
258 static GeoIPRecord
*geoip4_get_record(struct sockaddr_in
*sa
)
260 bug_on(gi4_city
== NULL
);
262 return GeoIP_record_by_ipnum(gi4_city
, ntohl(sa
->sin_addr
.s_addr
));
265 static GeoIPRecord
*geoip6_get_record(struct sockaddr_in6
*sa
)
267 bug_on(gi6_city
== NULL
);
269 return GeoIP_record_by_ipnum_v6(gi6_city
, sa
->sin6_addr
);
272 const char *geoip4_as_name(struct sockaddr_in
*sa
)
274 bug_on(gi4_asname
== NULL
);
276 return GeoIP_name_by_ipnum(gi4_asname
, ntohl(sa
->sin_addr
.s_addr
));
279 const char *geoip6_as_name(struct sockaddr_in6
*sa
)
281 bug_on(gi6_asname
== NULL
);
283 return GeoIP_name_by_ipnum_v6(gi6_asname
, sa
->sin6_addr
);
286 float geoip4_longitude(struct sockaddr_in
*sa
)
291 record
= geoip4_get_record(sa
);
295 longitude
= record
->longitude
;
297 GeoIPRecord_delete(record
);
301 float geoip4_latitude(struct sockaddr_in
*sa
)
306 record
= geoip4_get_record(sa
);
310 latitude
= record
->latitude
;
312 GeoIPRecord_delete(record
);
316 float geoip6_longitude(struct sockaddr_in6
*sa
)
321 record
= geoip6_get_record(sa
);
325 longitude
= record
->longitude
;
327 GeoIPRecord_delete(record
);
331 float geoip6_latitude(struct sockaddr_in6
*sa
)
336 record
= geoip6_get_record(sa
);
340 latitude
= record
->latitude
;
342 GeoIPRecord_delete(record
);
346 char *geoip4_city_name(struct sockaddr_in
*sa
)
351 record
= geoip4_get_record(sa
);
356 city
= xstrdup(record
->city
);
358 GeoIPRecord_delete(record
);
362 char *geoip6_city_name(struct sockaddr_in6
*sa
)
367 record
= geoip6_get_record(sa
);
372 city
= xstrdup(record
->city
);
374 GeoIPRecord_delete(record
);
378 char *geoip4_region_name(struct sockaddr_in
*sa
)
383 record
= geoip4_get_record(sa
);
388 region
= xstrdup(record
->region
);
390 GeoIPRecord_delete(record
);
394 char *geoip6_region_name(struct sockaddr_in6
*sa
)
399 record
= geoip6_get_record(sa
);
404 region
= xstrdup(record
->region
);
406 GeoIPRecord_delete(record
);
410 const char *geoip4_country_name(struct sockaddr_in
*sa
)
412 bug_on(gi4_country
== NULL
);
414 return GeoIP_country_name_by_ipnum(gi4_country
, ntohl(sa
->sin_addr
.s_addr
));
417 const char *geoip6_country_name(struct sockaddr_in6
*sa
)
419 bug_on(gi6_country
== NULL
);
421 return GeoIP_country_name_by_ipnum_v6(gi6_country
, sa
->sin6_addr
);
424 const char *geoip4_country_code3_name(struct sockaddr_in
*sa
)
426 bug_on(gi4_country
== NULL
);
428 return GeoIP_country_code3_by_ipnum(gi4_country
, ntohl(sa
->sin_addr
.s_addr
));
431 const char *geoip6_country_code3_name(struct sockaddr_in6
*sa
)
433 bug_on(gi6_country
== NULL
);
435 return GeoIP_country_code3_by_ipnum_v6(gi6_country
, sa
->sin6_addr
);
438 static int fdout
, fderr
;
440 /* GeoIP people were too stupid to come to the idea that you could set
441 * errno appropriately and return NULL instead of printing stuff from
442 * the library directly that no one can turn off.
445 static void geoip_open_prepare(void)
448 fdout
= dup_or_die(1);
451 fderr
= dup_or_die(2);
457 static void geoip_open_restore(void)
459 dup2_or_die(fdout
, 1);
460 dup2_or_die(fderr
, 2);
466 static GeoIP
*geoip_open_type(int type
, int flags
)
470 geoip_open_prepare();
471 ret
= GeoIP_open_type(type
, flags
);
472 geoip_open_restore();
477 static GeoIP
*geoip_open(const char *filename
, int flags
)
481 geoip_open_prepare();
482 ret
= GeoIP_open(filename
, flags
);
483 geoip_open_restore();
488 static void init_geoip_city_open4(int enforce
)
490 gi4_city
= geoip_open(files
[GEOIP_CITY_EDITION_REV1
].local
, GEOIP_MMAP_CACHE
);
491 if (gi4_city
== NULL
) {
492 gi4_city
= geoip_open_type(GEOIP_CITY_EDITION_REV1
, GEOIP_MMAP_CACHE
);
493 if (gi4_city
== NULL
)
495 panic("Cannot open GeoIP4 city database, try --update!\n");
499 GeoIP_set_charset(gi4_city
, GEOIP_CHARSET_UTF8
);
500 geoip_db_present
|= CITYV4
;
504 static void init_geoip_city_open6(int enforce
)
506 gi6_city
= geoip_open(files
[GEOIP_CITY_EDITION_REV1_V6
].local
, GEOIP_MMAP_CACHE
);
507 if (gi6_city
== NULL
) {
508 gi6_city
= geoip_open_type(GEOIP_CITY_EDITION_REV1_V6
, GEOIP_MMAP_CACHE
);
509 if (gi6_city
== NULL
)
511 panic("Cannot open GeoIP6 city database, try --update!\n");
515 GeoIP_set_charset(gi6_city
, GEOIP_CHARSET_UTF8
);
516 geoip_db_present
|= CITYV6
;
520 static void init_geoip_city(int enforce
)
522 init_geoip_city_open4(enforce
);
523 init_geoip_city_open6(enforce
);
526 static void destroy_geoip_city(void)
528 GeoIP_delete(gi4_city
);
529 GeoIP_delete(gi6_city
);
532 static void init_geoip_country_open4(int enforce
)
534 gi4_country
= geoip_open(files
[GEOIP_COUNTRY_EDITION
].local
, GEOIP_MMAP_CACHE
);
535 if (gi4_country
== NULL
) {
536 gi4_country
= geoip_open_type(GEOIP_COUNTRY_EDITION
, GEOIP_MMAP_CACHE
);
537 if (gi4_country
== NULL
)
539 panic("Cannot open GeoIP4 country database, try --update!\n");
543 GeoIP_set_charset(gi4_country
, GEOIP_CHARSET_UTF8
);
544 geoip_db_present
|= COUNTRYV4
;
548 static void init_geoip_country_open6(int enforce
)
550 gi6_country
= geoip_open(files
[GEOIP_COUNTRY_EDITION_V6
].local
, GEOIP_MMAP_CACHE
);
551 if (gi6_country
== NULL
) {
552 gi6_country
= geoip_open_type(GEOIP_COUNTRY_EDITION_V6
, GEOIP_MMAP_CACHE
);
553 if (gi6_country
== NULL
)
555 panic("Cannot open GeoIP6 country database, try --update!\n");
559 GeoIP_set_charset(gi6_country
, GEOIP_CHARSET_UTF8
);
560 geoip_db_present
|= COUNTRYV6
;
564 static void init_geoip_country(int enforce
)
566 init_geoip_country_open4(enforce
);
567 init_geoip_country_open6(enforce
);
570 static void destroy_geoip_country(void)
572 GeoIP_delete(gi4_country
);
573 GeoIP_delete(gi6_country
);
576 static void init_geoip_asname_open4(int enforce
)
578 gi4_asname
= geoip_open(files
[GEOIP_ASNUM_EDITION
].local
, GEOIP_MMAP_CACHE
);
579 if (gi4_asname
== NULL
) {
580 gi4_asname
= geoip_open_type(GEOIP_ASNUM_EDITION
, GEOIP_MMAP_CACHE
);
581 if (gi4_asname
== NULL
)
583 panic("Cannot open GeoIP4 AS database, try --update!\n");
587 GeoIP_set_charset(gi4_asname
, GEOIP_CHARSET_UTF8
);
588 geoip_db_present
|= ASNAMV4
;
592 static void init_geoip_asname_open6(int enforce
)
594 gi6_asname
= geoip_open(files
[GEOIP_ASNUM_EDITION_V6
].local
, GEOIP_MMAP_CACHE
);
595 if (gi6_asname
== NULL
) {
596 gi6_asname
= geoip_open_type(GEOIP_ASNUM_EDITION_V6
, GEOIP_MMAP_CACHE
);
597 if (gi6_asname
== NULL
)
599 panic("Cannot open GeoIP6 AS database, try --update!\n");
603 GeoIP_set_charset(gi6_asname
, GEOIP_CHARSET_UTF8
);
604 geoip_db_present
|= ASNAMV6
;
608 static void init_geoip_asname(int enforce
)
610 init_geoip_asname_open4(enforce
);
611 init_geoip_asname_open6(enforce
);
614 static void destroy_geoip_asname(void)
616 GeoIP_delete(gi4_asname
);
617 GeoIP_delete(gi6_asname
);
620 static void init_mirrors(void)
626 fp
= fopen(ETCDIRE_STRING
"/geoip.conf", "r");
628 panic("Cannot open geoip.conf!\n");
630 memset(buff
, 0, sizeof(buff
));
631 while (fgets(buff
, sizeof(buff
), fp
) != NULL
&&
632 i
< array_size(servers
)) {
633 buff
[strcspn(buff
, "\r\n")] = 0;
634 buff
[strcspn(buff
, "\r\n")] = 0;
636 if (buff
[0] == '#') {
637 memset(buff
, 0, sizeof(buff
));
641 servers
[i
++] = xstrdup(buff
);
642 memset(buff
, 0, sizeof(buff
));
648 static void destroy_mirrors(void)
652 for (i
= 0; i
< array_size(servers
); ++i
)
656 void init_geoip(int enforce
)
658 init_geoip_city(enforce
);
659 init_geoip_country(enforce
);
660 init_geoip_asname(enforce
);
663 void update_geoip(void)
670 for (i
= 0; i
< array_size(files
); ++i
) {
671 if (files
[i
].local
&& files
[i
].remote
) {
674 for (j
= 0; j
< array_size(servers
); ++j
) {
675 if (servers
[j
] == NULL
)
677 ret
= geoip_get_database(servers
[j
], i
);
685 panic("Cannot get %s from mirrors!\n",
693 void destroy_geoip(void)
695 destroy_geoip_city();
696 destroy_geoip_country();
697 destroy_geoip_asname();
699 geoip_db_present
= 0;