]> git.ipfire.org Git - thirdparty/xtables-addons.git/commitdiff
geoip: use simpler, preprocessed integer vector lists and fix endian issue
authorJan Engelhardt <jengelh@computergmbh.de>
Tue, 18 Mar 2008 14:47:10 +0000 (15:47 +0100)
committerJan Engelhardt <jengelh@computergmbh.de>
Sat, 22 Mar 2008 02:59:57 +0000 (03:59 +0100)
The old database format was in unknown byteorder -- if you run the
converter program yourself, you got a host order file, but if you
downloaded the preprocessed DB file (geoipdb.bin), you got a
little-endian file.

Use a new database format. Instead of having an index and a DB file,
do away with the index and let the filesystem do the indexing, using
one file per country. Also access the database files with a known
endianess type. The converter script now produces two distinct
variants (especially needed for IA-64).

All of this reduces the touched code by half.

extensions/libxt_geoip.c
extensions/libxt_geoip.man

index 5a99f4e318d7ceda07b255dea2cfa4f298893b88..c1aeb0c95ae1e8d643a9778f07c8bbc5a3c8a98f 100644 (file)
@@ -15,7 +15,9 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <ctype.h>
+#include <endian.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <getopt.h>
 #include <stddef.h>
 #include <stdio.h>
@@ -24,6 +26,7 @@
 #include <unistd.h>
 #include <xtables.h>
 #include "xt_geoip.h"
+#define GEOIP_DB_DIR "/var/geoip"
 
 static void geoip_help(void)
 {
@@ -51,78 +54,40 @@ static struct option geoip_opts[] = {
        {  0  },
 };
 
-struct geoip_index {
-       u_int16_t cc;
-       u_int32_t offset;
-} __attribute__ ((packed));
-
-static struct geoip_subnet *
-get_country_subnets(u_int16_t cc, u_int32_t *count)
+static struct geoip_subnet *geoip_get_subnets(const char *code, uint32_t *count)
 {
-       FILE *ixfd, *dbfd;
        struct geoip_subnet *subnets;
-       struct geoip_index *index;
-       struct stat buf;
-
-       size_t idxsz;
-       u_int16_t i;
-
-       u_int16_t db_cc = 0;
-       u_int16_t db_nsubnets = 0;
-
-       if ((ixfd = fopen("/var/geoip/geoipdb.idx", "r")) == NULL) {
-               perror("/var/geoip/geoipdb.idx");
-               exit_error(OTHER_PROBLEM,
-                       "geoip: cannot open geoip's database index file");
-       }
-
-       stat("/var/geoip/geoipdb.idx", &buf);
-       idxsz = buf.st_size/sizeof(struct geoip_index);
-       index = malloc(buf.st_size);
-
-       fread(index, buf.st_size, 1, ixfd);
-
-       for (i = 0; i < idxsz; i++)
-               if (cc == index[i].cc)
-                       break;
-
-       if (cc != index[i].cc)
-               exit_error(OTHER_PROBLEM,
-                       "geoip match: sorry, '%c%c' isn't in the database\n", COUNTRY(cc));
-
-       fclose(ixfd);
-
-       if ((dbfd = fopen("/var/geoip/geoipdb.bin", "r")) == NULL) {
-               perror("/var/geoip/geoipdb.bin");
-               exit_error(OTHER_PROBLEM,
-                       "geoip: cannot open geoip's database file");
+       struct stat sb;
+       char buf[256];
+       int fd;
+
+       /* Use simple integer vector files */
+#if __BYTE_ORDER == _BIG_ENDIAN
+       snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/BE/%s.iv0", code);
+#else
+       snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/LE/%s.iv0", code);
+#endif
+
+       if ((fd = open(buf, O_RDONLY)) < 0) {
+               fprintf(stderr, "Could not open %s: %s\n", buf, strerror(errno));
+               exit_error(OTHER_PROBLEM, "Could not read geoip database");
        }
 
-       fseek(dbfd, index[i].offset, SEEK_SET);
-       fread(&db_cc, sizeof(u_int16_t), 1, dbfd);
-
-       if (db_cc != cc)
-               exit_error(OTHER_PROBLEM,
-                       "geoip: this shouldn't happened, the database might be corrupted, or there's a bug.\n"
-                       "you should contact maintainers");
-
-       fread(&db_nsubnets, sizeof(u_int16_t), 1, dbfd);
-
-       subnets = malloc(db_nsubnets * sizeof(struct geoip_subnet));
-
-       if (!subnets)
-               exit_error(OTHER_PROBLEM,
-                       "geoip: insufficient memory available");
-
-       fread(subnets, db_nsubnets * sizeof(struct geoip_subnet), 1, dbfd);
-
-       fclose(dbfd);
-       free(index);
-       *count = db_nsubnets;
+       fstat(fd, &sb);
+       if (sb.st_size % sizeof(struct geoip_subnet) != 0)
+               exit_error(OTHER_PROBLEM, "Database file %s seems to be "
+                          "corrupted", buf);
+       subnets = malloc(sb.st_size);
+       if (subnets == NULL)
+               exit_error(OTHER_PROBLEM, "geoip: insufficient memory");
+       read(fd, subnets, sb.st_size);
+       close(fd);
+       *count = sb.st_size / sizeof(struct geoip_subnet);
        return subnets;
 }
-
-static struct geoip_country_user *geoip_load_cc(unsigned short cc)
+static struct geoip_country_user *geoip_load_cc(const char *code,
+    unsigned short cc)
 {
        struct geoip_country_user *ginfo;
        ginfo = malloc(sizeof(struct geoip_country_user));
@@ -130,7 +95,7 @@ static struct geoip_country_user *geoip_load_cc(unsigned short cc)
        if (!ginfo)
                return NULL;
 
-       ginfo->subnets = (unsigned long)get_country_subnets(cc, &ginfo->count);
+       ginfo->subnets = (unsigned long)geoip_get_subnets(code, &ginfo->count);
        ginfo->cc = cc;
 
        return ginfo;
@@ -190,7 +155,7 @@ static unsigned int parse_geoip_cc(const char *ccstr, uint16_t *cc,
                if (next) *next++ = '\0';
 
                if ((cctmp = check_geoip_cc(cp, cc, count)) != 0) {
-                       if ((mem[count++].user = (unsigned long)geoip_load_cc(cctmp)) == 0)
+                       if ((mem[count++].user = (unsigned long)geoip_load_cc(cp, cctmp)) == 0)
                                exit_error(OTHER_PROBLEM,
                                        "geoip: insufficient memory available");
                        cc[count-1] = cctmp;
index bc3b5172a51fa7d7fed0dd85bffb5082a52252bf..5f7ca040a02b481efe73dee57a9e13d0af864b9f 100644 (file)
@@ -1,15 +1,16 @@
 Match a packet by its source or destination country.
 .TP
-[\fB!\fR] \fB--src-cc\fR, \fB--source-country \fIcountry\fR[\fB,\fIcountry\fB,\fIcountry\fB,\fI...\fR]
+[\fB!\fP] \fB--src-cc\fP, \fB--source-country\fP \fIcountry\fP[\fB,\fP\fIcountry\fP\fB...\fP]
 Match packet coming from (one of) the specified country(ies)
 .TP
-[\fB!\fR] \fB--dst-cc\fR, \fB--destination-country \fIcountry\fR[\fB,\fIcountry\fB,\fIcountry\fB,\fI...\fR]
+[\fB!\fP] \fB--dst-cc\fP, \fB--destination-country\fP \fIcountry\fP[\fB,\fP\fIcountry\fP\fB...\fP]
 Match packet going to (one of) the specified country(ies)
 .TP
 NOTE:
 The country is inputed by its ISO3166 code.
 .P
-The only extra files you need is a binary db (geoipdb.bin) & its index file (geoipdb.idx).
-Both files are generated from a countries & subnets database with the csv2bin tool,
-available at http://people.netfilter.org/peejix/geoip/. Both files MUST also be moved in /var/geoip/
-as the shared library is statically looking for that pathname (ex.: /var/geoip/geoipdb.bin).
+The extra files you will need is the binary database files. They are generated
+from a country-subnet database with the geoip_csv_iv0.pl tool, available at
+http://jengelh.hopto.org/files/geoip/ . The files MUST be moved to /var/geoip/
+as the shared library is statically looking for this pathname (e.g.
+/var/geoip/LE/de.iv0).