mirror of
git://git.code.sf.net/p/xtables-addons/xtables-addons
synced 2025-09-07 13:15:12 +02:00
geoip: use simpler, preprocessed integer vector lists and fix endian issue
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.
This commit is contained in:
@@ -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;
|
||||
struct stat sb;
|
||||
char buf[256];
|
||||
int fd;
|
||||
|
||||
size_t idxsz;
|
||||
u_int16_t i;
|
||||
/* 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
|
||||
|
||||
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");
|
||||
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");
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
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;
|
||||
|
@@ -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).
|
||||
|
Reference in New Issue
Block a user