From e2da87230aa69348a1ed5147302ffaa8fcf4e20f Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Fri, 17 Dec 2010 22:08:15 +0100 Subject: [PATCH 01/11] geoip: prefix tools with xt_ This is preferable to have when manpages go into system locations. --- geoip/Makefile.am | 2 +- geoip/{geoip_build_db.pl => xt_geoip_build} | 0 geoip/{geoip_download.sh => xt_geoip_dl} | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename geoip/{geoip_build_db.pl => xt_geoip_build} (100%) rename geoip/{geoip_download.sh => xt_geoip_dl} (100%) diff --git a/geoip/Makefile.am b/geoip/Makefile.am index be30fe5..2862ddf 100644 --- a/geoip/Makefile.am +++ b/geoip/Makefile.am @@ -1,3 +1,3 @@ # -*- Makefile -*- -pkglibexec_SCRIPTS = geoip_build_db.pl geoip_download.sh +pkglibexec_SCRIPTS = xt_geoip_build xt_geoip_dl diff --git a/geoip/geoip_build_db.pl b/geoip/xt_geoip_build similarity index 100% rename from geoip/geoip_build_db.pl rename to geoip/xt_geoip_build diff --git a/geoip/geoip_download.sh b/geoip/xt_geoip_dl similarity index 100% rename from geoip/geoip_download.sh rename to geoip/xt_geoip_dl From 0f42828fd686b6ca1d7e2ac8e0daa0d1b8575a57 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Fri, 17 Dec 2010 22:28:50 +0100 Subject: [PATCH 02/11] geoip: add manpages to utility programs --- geoip/Makefile.am | 2 ++ geoip/xt_geoip_build.1 | 42 ++++++++++++++++++++++++++++++++++++++++++ geoip/xt_geoip_dl.1 | 21 +++++++++++++++++++++ 3 files changed, 65 insertions(+) create mode 100644 geoip/xt_geoip_build.1 create mode 100644 geoip/xt_geoip_dl.1 diff --git a/geoip/Makefile.am b/geoip/Makefile.am index 2862ddf..aa28c3d 100644 --- a/geoip/Makefile.am +++ b/geoip/Makefile.am @@ -1,3 +1,5 @@ # -*- Makefile -*- pkglibexec_SCRIPTS = xt_geoip_build xt_geoip_dl + +man1_MANS = xt_geoip_build.1 xt_geoip_dl.1 diff --git a/geoip/xt_geoip_build.1 b/geoip/xt_geoip_build.1 new file mode 100644 index 0000000..a61f92b --- /dev/null +++ b/geoip/xt_geoip_build.1 @@ -0,0 +1,42 @@ +.TH xt_geoip_build 1 "2010-12-17" "xtables-addons" "xtables-addons" +.SH Name +.PP +xt_geoip_build \(em convert GeoIP.csv to packed format for xt_geoip +.SH Syntax +.PP +\fI/usr/libexec/xt_geoip/\fP\fBxt_geoip_build\fP [\fB\-b\fP] [\fB\-D\fP +\fItarget_dir\fP] [\fIfile\fP...] +.SH Description +.PP +xt_geoip_build is used to build packed raw representations of the range +database that the xt_geoip module relies on. Since kernel memory is precious, +much of the preprocessing is done in userspace by this very building tool. One +file is produced for each country, so that no more addresses than needed are +required to be loaded into memory. The ranges in the packed database files are +also ordered, as xt_geoip relies on this property for its bisection approach to +work. +.PP +Input is processed from the listed files, or if none is given, from stdin. +.PP +Since the script is usually installed to the libexec directory of the +xtables-addons package and this is outside $PATH (on purpose), invoking the +script requires it to be called with a path. +.PP Options +.TP +\fB\-b\fP +The packed database files (file extension .iv0) are normally produced in +little-endian format. Use \fB\-b\fP to produce big-endian instead, as is needed +on some CPU families such as MIPS, PPC and SPARC. +.TP +\fB\-D\fP \fItarget_dir\fP +Specify a target directory into which the files are to be put. +.SH Application +.PP +Shell commands to build the databases and put them to where they are expected: +.PP +xt_geoip_build -D /usr/share/xt_geoip/LE +.PP +xt_geoip_build -bD /usr/share/xt_geoip/BE +.SH See also +.PP +xt_geoip_dl(1) diff --git a/geoip/xt_geoip_dl.1 b/geoip/xt_geoip_dl.1 new file mode 100644 index 0000000..3934335 --- /dev/null +++ b/geoip/xt_geoip_dl.1 @@ -0,0 +1,21 @@ +.TH xt_geoip_dl 1 "2010-12-17" "xtables-addons" "xtables-addons" +.SH Name +.PP +xt_geoip_dl \(em download GeoIP database files +.SH Syntax +.PP +\fI/usr/libexec/xt_geoip/\fP\fBxt_geoip_dl\fP +.SH Description +.PP +Downloads and unpacks the MaxMind GeoIP Country Lite databases for IPv4 and +IPv6 and unpacks them to the current directory. +.PP +Since the script is usually installed to the libexec directory of the +xtables-addons package and this is outside $PATH (on purpose), invoking the +script requires it to be called with a path. +.SH Options +.PP +None. +.SH See also +.PP +xt_geoip_build(1) From f7c7264a65dd459bf0bdb91600c57a9ba4f9b97b Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Fri, 17 Dec 2010 22:41:08 +0100 Subject: [PATCH 03/11] geoip: remove %names map --- geoip/xt_geoip_build | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/geoip/xt_geoip_build b/geoip/xt_geoip_build index 511f48e..7699219 100755 --- a/geoip/xt_geoip_build +++ b/geoip/xt_geoip_build @@ -11,7 +11,6 @@ use Text::CSV_XS; # or trade for Text::CSV use strict; my %country; -my %names; my $csv = Text::CSV_XS->new({binary => 0, eol => $/}); # or Text::CSV my $mode = "VV"; my $target_dir = "."; @@ -29,10 +28,9 @@ if (!-d $target_dir) { while (my $row = $csv->getline(*ARGV)) { if (!defined($country{$row->[4]})) { - $country{$row->[4]} = []; - $names{$row->[4]} = $row->[5]; + $country{$row->[4]} = {name => $row->[5], pool => []}; } - my $c = $country{$row->[4]}; + my $c = $country{$row->[4]}{pool}; push(@$c, [$row->[2], $row->[3]]); if ($. % 4096 == 0) { print STDERR "\r\e[2K$. entries"; @@ -43,11 +41,11 @@ print STDERR "\r\e[2K$. entries total\n"; foreach my $iso_code (sort keys %country) { printf "%5u ranges for %s %s\n", - scalar(@{$country{$iso_code}}), - $iso_code, $names{$iso_code}; + scalar(@{$country{$iso_code}{pool}}), + $iso_code, $country{$iso_code}{name}; open(my $fh, "> $target_dir/".uc($iso_code).".iv0"); - foreach my $range (@{$country{$iso_code}}) { + foreach my $range (@{$country{$iso_code}{pool}}) { print $fh pack($mode, $range->[0], $range->[1]); } close $fh; From 4d547c2bfc9895d61467d011904e3c1b2f2446bc Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Fri, 17 Dec 2010 22:47:01 +0100 Subject: [PATCH 04/11] geoip: remove -b option, always build both endianesses --- geoip/xt_geoip_build | 30 ++++++++++++++++++++++++------ geoip/xt_geoip_build.1 | 11 ++--------- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/geoip/xt_geoip_build b/geoip/xt_geoip_build index 7699219..4ba5404 100755 --- a/geoip/xt_geoip_build +++ b/geoip/xt_geoip_build @@ -12,19 +12,24 @@ use strict; my %country; my $csv = Text::CSV_XS->new({binary => 0, eol => $/}); # or Text::CSV -my $mode = "VV"; my $target_dir = "."; &Getopt::Long::Configure(qw(bundling)); &GetOptions( "D=s" => \$target_dir, - "b" => sub { $mode = "NN"; }, ); if (!-d $target_dir) { print STDERR "Target directory $target_dir does not exist.\n"; exit 1; } +foreach (qw(LE BE)) { + my $dir = "$target_dir/$_"; + if (!-e $dir && !mkdir($dir)) { + print STDERR "Could not mkdir $dir: $!\n"; + exit 1; + } +} while (my $row = $csv->getline(*ARGV)) { if (!defined($country{$row->[4]})) { @@ -40,13 +45,26 @@ while (my $row = $csv->getline(*ARGV)) { print STDERR "\r\e[2K$. entries total\n"; foreach my $iso_code (sort keys %country) { + my($file, $fh_le, $fh_be); + printf "%5u ranges for %s %s\n", scalar(@{$country{$iso_code}{pool}}), $iso_code, $country{$iso_code}{name}; - open(my $fh, "> $target_dir/".uc($iso_code).".iv0"); - foreach my $range (@{$country{$iso_code}{pool}}) { - print $fh pack($mode, $range->[0], $range->[1]); + $file = "$target_dir/LE/".uc($iso_code).".iv0"; + if (!open($fh_le, "> $file")) { + print STDERR "Error opening $file: $!\n"; + exit 1; } - close $fh; + $file = "$target_dir/BE/".uc($iso_code).".iv0"; + if (!open($fh_be, "> $file")) { + print STDERR "Error opening $file: $!\n"; + exit 1; + } + foreach my $range (@{$country{$iso_code}{pool}}) { + print $fh_le pack("VV", $range->[0], $range->[1]); + print $fh_be pack("NN", $range->[0], $range->[1]); + } + close $fh_le; + close $fh_be; } diff --git a/geoip/xt_geoip_build.1 b/geoip/xt_geoip_build.1 index a61f92b..3118787 100644 --- a/geoip/xt_geoip_build.1 +++ b/geoip/xt_geoip_build.1 @@ -4,7 +4,7 @@ xt_geoip_build \(em convert GeoIP.csv to packed format for xt_geoip .SH Syntax .PP -\fI/usr/libexec/xt_geoip/\fP\fBxt_geoip_build\fP [\fB\-b\fP] [\fB\-D\fP +\fI/usr/libexec/xt_geoip/\fP\fBxt_geoip_build\fP [\fB\-D\fP \fItarget_dir\fP] [\fIfile\fP...] .SH Description .PP @@ -23,20 +23,13 @@ xtables-addons package and this is outside $PATH (on purpose), invoking the script requires it to be called with a path. .PP Options .TP -\fB\-b\fP -The packed database files (file extension .iv0) are normally produced in -little-endian format. Use \fB\-b\fP to produce big-endian instead, as is needed -on some CPU families such as MIPS, PPC and SPARC. -.TP \fB\-D\fP \fItarget_dir\fP Specify a target directory into which the files are to be put. .SH Application .PP Shell commands to build the databases and put them to where they are expected: .PP -xt_geoip_build -D /usr/share/xt_geoip/LE -.PP -xt_geoip_build -bD /usr/share/xt_geoip/BE +xt_geoip_build -D /usr/share/xt_geoip .SH See also .PP xt_geoip_dl(1) From 25bf680ead80e505d5073308f151b4007cb5683f Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Sun, 19 Dec 2010 00:30:10 +0100 Subject: [PATCH 05/11] geoip: put IPv4 geoip data into its own map --- extensions/libxt_geoip.c | 4 ++-- geoip/xt_geoip_build | 17 ++++++++++------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/extensions/libxt_geoip.c b/extensions/libxt_geoip.c index c99d7ea..df28185 100644 --- a/extensions/libxt_geoip.c +++ b/extensions/libxt_geoip.c @@ -58,9 +58,9 @@ static struct geoip_subnet *geoip_get_subnets(const char *code, uint32_t *count) /* Use simple integer vector files */ #if __BYTE_ORDER == _BIG_ENDIAN - snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/BE/%s.iv0", code); + snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/BE/%s.iv4", code); #else - snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/LE/%s.iv0", code); + snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/LE/%s.iv4", code); #endif if ((fd = open(buf, O_RDONLY)) < 0) { diff --git a/geoip/xt_geoip_build b/geoip/xt_geoip_build index 4ba5404..5016ff3 100755 --- a/geoip/xt_geoip_build +++ b/geoip/xt_geoip_build @@ -33,9 +33,12 @@ foreach (qw(LE BE)) { while (my $row = $csv->getline(*ARGV)) { if (!defined($country{$row->[4]})) { - $country{$row->[4]} = {name => $row->[5], pool => []}; + $country{$row->[4]} = { + name => $row->[5], + pool_v4 => [], + }; } - my $c = $country{$row->[4]}{pool}; + my $c = $country{$row->[4]}{pool_v4}; push(@$c, [$row->[2], $row->[3]]); if ($. % 4096 == 0) { print STDERR "\r\e[2K$. entries"; @@ -47,21 +50,21 @@ print STDERR "\r\e[2K$. entries total\n"; foreach my $iso_code (sort keys %country) { my($file, $fh_le, $fh_be); - printf "%5u ranges for %s %s\n", - scalar(@{$country{$iso_code}{pool}}), + printf "%5u IPv4 ranges for %s %s\n", + scalar(@{$country{$iso_code}{pool_v4}}), $iso_code, $country{$iso_code}{name}; - $file = "$target_dir/LE/".uc($iso_code).".iv0"; + $file = "$target_dir/LE/".uc($iso_code).".iv4"; if (!open($fh_le, "> $file")) { print STDERR "Error opening $file: $!\n"; exit 1; } - $file = "$target_dir/BE/".uc($iso_code).".iv0"; + $file = "$target_dir/BE/".uc($iso_code).".iv4"; if (!open($fh_be, "> $file")) { print STDERR "Error opening $file: $!\n"; exit 1; } - foreach my $range (@{$country{$iso_code}{pool}}) { + foreach my $range (@{$country{$iso_code}{pool_v4}}) { print $fh_le pack("VV", $range->[0], $range->[1]); print $fh_be pack("NN", $range->[0], $range->[1]); } From f180c0e5c6026c44481607fcbe9f9bd3f4ed702e Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Tue, 4 Jan 2011 03:49:44 +0100 Subject: [PATCH 06/11] geoipdb tools: IPv6 support --- geoip/xt_geoip_build | 60 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 4 deletions(-) diff --git a/geoip/xt_geoip_build b/geoip/xt_geoip_build index 5016ff3..933bc17 100755 --- a/geoip/xt_geoip_build +++ b/geoip/xt_geoip_build @@ -1,7 +1,7 @@ #!/usr/bin/perl # # Converter for MaxMind CSV database to binary, for xt_geoip -# Copyright © Jan Engelhardt , 2008 +# Copyright © Jan Engelhardt , 2008-2011 # # Use -b argument to create big-endian tables. # @@ -11,7 +11,11 @@ use Text::CSV_XS; # or trade for Text::CSV use strict; my %country; -my $csv = Text::CSV_XS->new({binary => 0, eol => $/}); # or Text::CSV +my $csv = Text::CSV_XS->new({ + allow_whitespace => 1, + binary => 1, + eol => $/, +}); # or Text::CSV my $target_dir = "."; &Getopt::Long::Configure(qw(bundling)); @@ -36,10 +40,16 @@ while (my $row = $csv->getline(*ARGV)) { $country{$row->[4]} = { name => $row->[5], pool_v4 => [], + pool_v6 => [], }; } - my $c = $country{$row->[4]}{pool_v4}; - push(@$c, [$row->[2], $row->[3]]); + my $c = $country{$row->[4]}; + if ($row->[0] =~ /:/) { + push(@{$c->{pool_v6}}, + [&ip6_pack($row->[0]), &ip6_pack($row->[1])]); + } else { + push(@{$c->{pool_v4}}, [$row->[2], $row->[3]]); + } if ($. % 4096 == 0) { print STDERR "\r\e[2K$. entries"; } @@ -50,6 +60,27 @@ print STDERR "\r\e[2K$. entries total\n"; foreach my $iso_code (sort keys %country) { my($file, $fh_le, $fh_be); + printf "%5u IPv6 ranges for %s %s\n", + scalar(@{$country{$iso_code}{pool_v6}}), + $iso_code, $country{$iso_code}{name}; + + $file = "$target_dir/LE/".uc($iso_code).".iv6"; + if (!open($fh_le, "> $file")) { + print STDERR "Error opening $file: $!\n"; + exit 1; + } + $file = "$target_dir/BE/".uc($iso_code).".iv6"; + if (!open($fh_be, "> $file")) { + print STDERR "Error opening $file: $!\n"; + exit 1; + } + foreach my $range (@{$country{$iso_code}{pool_v6}}) { + print $fh_be $range->[0], $range->[1]; + print $fh_le &ip6_swap($range->[0]), &ip6_swap($range->[1]); + } + close $fh_le; + close $fh_be; + printf "%5u IPv4 ranges for %s %s\n", scalar(@{$country{$iso_code}{pool_v4}}), $iso_code, $country{$iso_code}{name}; @@ -71,3 +102,24 @@ foreach my $iso_code (sort keys %country) { close $fh_le; close $fh_be; } + +sub ip6_pack +{ + my $addr = shift @_; + $addr =~ s{::}{:!:}; + my @addr = split(/:/, $addr); + my @e = (0) x 8; + foreach (@addr) { + if ($_ eq "!") { + $_ = join(':', @e[0..(8-scalar(@addr))]); + } + } + @addr = split(/:/, join(':', @addr)); + $_ = hex($_) foreach @addr; + return pack("n*", @addr); +} + +sub ip6_swap +{ + return pack("V*", unpack("N*", shift @_)); +} From 80444b0d31d3fc4bdfccc306b86c9cd4f3f6518e Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Thu, 27 Jan 2011 02:55:10 +0100 Subject: [PATCH 07/11] geoipdb builder: separate into functions --- geoip/xt_geoip_build | 53 ++++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/geoip/xt_geoip_build b/geoip/xt_geoip_build index 933bc17..bcbf662 100755 --- a/geoip/xt_geoip_build +++ b/geoip/xt_geoip_build @@ -35,29 +35,44 @@ foreach (qw(LE BE)) { } } -while (my $row = $csv->getline(*ARGV)) { - if (!defined($country{$row->[4]})) { - $country{$row->[4]} = { - name => $row->[5], - pool_v4 => [], - pool_v6 => [], - }; +&collect(); +&dump(); + +sub collect +{ + while (my $row = $csv->getline(*ARGV)) { + if (!defined($country{$row->[4]})) { + $country{$row->[4]} = { + name => $row->[5], + pool_v4 => [], + pool_v6 => [], + }; + } + my $c = $country{$row->[4]}; + if ($row->[0] =~ /:/) { + push(@{$c->{pool_v6}}, + [&ip6_pack($row->[0]), &ip6_pack($row->[1])]); + } else { + push(@{$c->{pool_v4}}, [$row->[2], $row->[3]]); + } + if ($. % 4096 == 0) { + print STDERR "\r\e[2K$. entries"; + } } - my $c = $country{$row->[4]}; - if ($row->[0] =~ /:/) { - push(@{$c->{pool_v6}}, - [&ip6_pack($row->[0]), &ip6_pack($row->[1])]); - } else { - push(@{$c->{pool_v4}}, [$row->[2], $row->[3]]); - } - if ($. % 4096 == 0) { - print STDERR "\r\e[2K$. entries"; + + print STDERR "\r\e[2K$. entries total\n"; +} + +sub dump +{ + foreach my $iso_code (sort keys %country) { + &dump_one($iso_code); } } -print STDERR "\r\e[2K$. entries total\n"; - -foreach my $iso_code (sort keys %country) { +sub dump_one +{ + my $iso_code = shift @_; my($file, $fh_le, $fh_be); printf "%5u IPv6 ranges for %s %s\n", From 93a17fdde0ee9e77c705ce473deab5065e0e6e74 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Thu, 27 Jan 2011 03:05:30 +0100 Subject: [PATCH 08/11] geoipdb builder: get rid of some global variables --- geoip/xt_geoip_build | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/geoip/xt_geoip_build b/geoip/xt_geoip_build index bcbf662..8f54575 100755 --- a/geoip/xt_geoip_build +++ b/geoip/xt_geoip_build @@ -10,7 +10,6 @@ use IO::Handle; use Text::CSV_XS; # or trade for Text::CSV use strict; -my %country; my $csv = Text::CSV_XS->new({ allow_whitespace => 1, binary => 1, @@ -35,11 +34,12 @@ foreach (qw(LE BE)) { } } -&collect(); -&dump(); +&dump(&collect()); sub collect { + my %country; + while (my $row = $csv->getline(*ARGV)) { if (!defined($country{$row->[4]})) { $country{$row->[4]} = { @@ -61,23 +61,26 @@ sub collect } print STDERR "\r\e[2K$. entries total\n"; + return \%country; } sub dump { - foreach my $iso_code (sort keys %country) { - &dump_one($iso_code); + my $country = shift @_; + + foreach my $iso_code (sort keys %$country) { + &dump_one($iso_code, $country->{$iso_code}); } } sub dump_one { - my $iso_code = shift @_; + my($iso_code, $country) = @_; my($file, $fh_le, $fh_be); printf "%5u IPv6 ranges for %s %s\n", - scalar(@{$country{$iso_code}{pool_v6}}), - $iso_code, $country{$iso_code}{name}; + scalar(@{$country->{pool_v6}}), + $iso_code, $country->{name}; $file = "$target_dir/LE/".uc($iso_code).".iv6"; if (!open($fh_le, "> $file")) { @@ -89,7 +92,7 @@ sub dump_one print STDERR "Error opening $file: $!\n"; exit 1; } - foreach my $range (@{$country{$iso_code}{pool_v6}}) { + foreach my $range (@{$country->{pool_v6}}) { print $fh_be $range->[0], $range->[1]; print $fh_le &ip6_swap($range->[0]), &ip6_swap($range->[1]); } @@ -97,8 +100,8 @@ sub dump_one close $fh_be; printf "%5u IPv4 ranges for %s %s\n", - scalar(@{$country{$iso_code}{pool_v4}}), - $iso_code, $country{$iso_code}{name}; + scalar(@{$country->{pool_v4}}), + $iso_code, $country->{name}; $file = "$target_dir/LE/".uc($iso_code).".iv4"; if (!open($fh_le, "> $file")) { @@ -110,7 +113,7 @@ sub dump_one print STDERR "Error opening $file: $!\n"; exit 1; } - foreach my $range (@{$country{$iso_code}{pool_v4}}) { + foreach my $range (@{$country->{pool_v4}}) { print $fh_le pack("VV", $range->[0], $range->[1]); print $fh_be pack("NN", $range->[0], $range->[1]); } From 19f241a09cc76d9d565dc8a91a98b9634bc5894b Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 2 Feb 2011 01:52:26 +0100 Subject: [PATCH 09/11] xt_geoip: cleanups, preparations for IPv6 geoip --- extensions/xt_geoip.c | 27 ++++++++++++++------------- extensions/xt_geoip.h | 4 ++-- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/extensions/xt_geoip.c b/extensions/xt_geoip.c index 44e489d..acd1343 100644 --- a/extensions/xt_geoip.c +++ b/extensions/xt_geoip.c @@ -29,6 +29,12 @@ MODULE_AUTHOR("Samuel Jean"); MODULE_DESCRIPTION("xtables module for geoip match"); MODULE_ALIAS("ipt_geoip"); +/** + * @list: anchor point for geoip_head + * @subnets: packed ordered list of ranges + * @count: number of ranges + * @cc: country code + */ struct geoip_country_kernel { struct list_head list; struct geoip_subnet *subnets; @@ -45,7 +51,7 @@ geoip_add_node(const struct geoip_country_user __user *umem_ptr) { struct geoip_country_user umem; struct geoip_country_kernel *p; - struct geoip_subnet *s; + struct geoip_subnet *subnet; int ret; if (copy_from_user(&umem, umem_ptr, sizeof(umem)) != 0) @@ -58,18 +64,19 @@ geoip_add_node(const struct geoip_country_user __user *umem_ptr) p->count = umem.count; p->cc = umem.cc; - s = vmalloc(p->count * sizeof(struct geoip_subnet)); - if (s == NULL) { + subnet = vmalloc(p->count * sizeof(struct geoip_subnet)); + if (subnet == NULL) { ret = -ENOMEM; goto free_p; } - if (copy_from_user(s, (const void __user *)(unsigned long)umem.subnets, + if (copy_from_user(subnet, + (const void __user *)(unsigned long)umem.subnets, p->count * sizeof(struct geoip_subnet)) != 0) { ret = -EFAULT; goto free_s; } - p->subnets = s; + p->subnets = subnet; atomic_set(&p->ref, 1); INIT_LIST_HEAD(&p->list); @@ -80,7 +87,7 @@ geoip_add_node(const struct geoip_country_user __user *umem_ptr) return p; free_s: - vfree(s); + vfree(subnet); free_p: kfree(p); return ERR_PTR(ret); @@ -149,20 +156,14 @@ xt_geoip_mt(const struct sk_buff *skb, struct xt_action_param *par) unsigned int i; uint32_t ip; - if (info->flags & XT_GEOIP_SRC) - ip = ntohl(iph->saddr); - else - ip = ntohl(iph->daddr); - + ip = ntohl((info->flags & XT_GEOIP_SRC) ? iph->saddr : iph->daddr); rcu_read_lock(); for (i = 0; i < info->count; i++) { if ((node = info->mem[i].kernel) == NULL) { printk(KERN_ERR "xt_geoip: what the hell ?? '%c%c' isn't loaded into memory... skip it!\n", COUNTRY(info->cc[i])); - continue; } - if (geoip_bsearch(node->subnets, ip, 0, node->count)) { rcu_read_unlock(); return !(info->flags & XT_GEOIP_INV); diff --git a/extensions/xt_geoip.h b/extensions/xt_geoip.h index 291c108..eed4571 100644 --- a/extensions/xt_geoip.h +++ b/extensions/xt_geoip.h @@ -36,7 +36,7 @@ struct geoip_country_user { struct geoip_country_kernel; union geoip_country_group { - aligned_u64 user; + aligned_u64 user; /* struct geoip_country_user * */ struct geoip_country_kernel *kernel; }; @@ -49,6 +49,6 @@ struct xt_geoip_match_info { union geoip_country_group mem[XT_GEOIP_MAX]; }; -#define COUNTRY(cc) (cc >> 8), (cc & 0x00FF) +#define COUNTRY(cc) ((cc) >> 8), ((cc) & 0x00FF) #endif /* _LINUX_NETFILTER_XT_GEOIP_H */ From eb9634aee671129033f01821a5790a5e30e252a7 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 2 Feb 2011 01:56:38 +0100 Subject: [PATCH 10/11] xt_geoip: v4/v6 name preparations --- extensions/libxt_geoip.c | 9 +++++---- extensions/xt_geoip.c | 20 ++++++++++---------- extensions/xt_geoip.h | 2 +- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/extensions/libxt_geoip.c b/extensions/libxt_geoip.c index df28185..e6fbdd3 100644 --- a/extensions/libxt_geoip.c +++ b/extensions/libxt_geoip.c @@ -49,9 +49,10 @@ static struct option geoip_opts[] = { {NULL}, }; -static struct geoip_subnet *geoip_get_subnets(const char *code, uint32_t *count) +static struct geoip_subnet4 * +geoip_get_subnets(const char *code, uint32_t *count) { - struct geoip_subnet *subnets; + struct geoip_subnet4 *subnets; struct stat sb; char buf[256]; int fd; @@ -69,7 +70,7 @@ static struct geoip_subnet *geoip_get_subnets(const char *code, uint32_t *count) } fstat(fd, &sb); - if (sb.st_size % sizeof(struct geoip_subnet) != 0) + if (sb.st_size % sizeof(struct geoip_subnet4) != 0) xtables_error(OTHER_PROBLEM, "Database file %s seems to be " "corrupted", buf); subnets = malloc(sb.st_size); @@ -77,7 +78,7 @@ static struct geoip_subnet *geoip_get_subnets(const char *code, uint32_t *count) xtables_error(OTHER_PROBLEM, "geoip: insufficient memory"); read(fd, subnets, sb.st_size); close(fd); - *count = sb.st_size / sizeof(struct geoip_subnet); + *count = sb.st_size / sizeof(struct geoip_subnet4); return subnets; } diff --git a/extensions/xt_geoip.c b/extensions/xt_geoip.c index acd1343..2f3caae 100644 --- a/extensions/xt_geoip.c +++ b/extensions/xt_geoip.c @@ -37,7 +37,7 @@ MODULE_ALIAS("ipt_geoip"); */ struct geoip_country_kernel { struct list_head list; - struct geoip_subnet *subnets; + struct geoip_subnet4 *subnets; atomic_t ref; unsigned int count; unsigned short cc; @@ -51,7 +51,7 @@ geoip_add_node(const struct geoip_country_user __user *umem_ptr) { struct geoip_country_user umem; struct geoip_country_kernel *p; - struct geoip_subnet *subnet; + struct geoip_subnet4 *subnet; int ret; if (copy_from_user(&umem, umem_ptr, sizeof(umem)) != 0) @@ -64,14 +64,14 @@ geoip_add_node(const struct geoip_country_user __user *umem_ptr) p->count = umem.count; p->cc = umem.cc; - subnet = vmalloc(p->count * sizeof(struct geoip_subnet)); + subnet = vmalloc(p->count * sizeof(struct geoip_subnet4)); if (subnet == NULL) { ret = -ENOMEM; goto free_p; } if (copy_from_user(subnet, (const void __user *)(unsigned long)umem.subnets, - p->count * sizeof(struct geoip_subnet)) != 0) { + p->count * sizeof(struct geoip_subnet4)) != 0) { ret = -EFAULT; goto free_s; } @@ -128,7 +128,7 @@ static struct geoip_country_kernel *find_node(unsigned short cc) return NULL; } -static bool geoip_bsearch(const struct geoip_subnet *range, +static bool geoip_bsearch4(const struct geoip_subnet4 *range, uint32_t addr, int lo, int hi) { int mid; @@ -139,16 +139,16 @@ static bool geoip_bsearch(const struct geoip_subnet *range, if (range[mid].begin <= addr && addr <= range[mid].end) return true; if (range[mid].begin > addr) - return geoip_bsearch(range, addr, lo, mid); + return geoip_bsearch4(range, addr, lo, mid); else if (range[mid].end < addr) - return geoip_bsearch(range, addr, mid + 1, hi); + return geoip_bsearch4(range, addr, mid + 1, hi); WARN_ON(true); return false; } static bool -xt_geoip_mt(const struct sk_buff *skb, struct xt_action_param *par) +xt_geoip_mt4(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_geoip_match_info *info = par->matchinfo; const struct geoip_country_kernel *node; @@ -164,7 +164,7 @@ xt_geoip_mt(const struct sk_buff *skb, struct xt_action_param *par) COUNTRY(info->cc[i])); continue; } - if (geoip_bsearch(node->subnets, ip, 0, node->count)) { + if (geoip_bsearch4(node->subnets, ip, 0, node->count)) { rcu_read_unlock(); return !(info->flags & XT_GEOIP_INV); } @@ -232,7 +232,7 @@ static struct xt_match xt_geoip_match __read_mostly = { .name = "geoip", .revision = 1, .family = NFPROTO_IPV4, - .match = xt_geoip_mt, + .match = xt_geoip_mt4, .checkentry = xt_geoip_mt_checkentry, .destroy = xt_geoip_mt_destroy, .matchsize = sizeof(struct xt_geoip_match_info), diff --git a/extensions/xt_geoip.h b/extensions/xt_geoip.h index eed4571..c447e61 100644 --- a/extensions/xt_geoip.h +++ b/extensions/xt_geoip.h @@ -22,7 +22,7 @@ enum { }; /* Yup, an address range will be passed in with host-order */ -struct geoip_subnet { +struct geoip_subnet4 { __u32 begin; __u32 end; }; From 07cd29d9ce6ddf5e87088f8f58d72becb510717f Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 2 Feb 2011 02:01:28 +0100 Subject: [PATCH 11/11] xt_geoip: IPv6 support --- doc/changelog.txt | 2 + extensions/libxt_geoip.c | 120 ++++++++++++++++++++++--------- extensions/xt_geoip.c | 152 ++++++++++++++++++++++++++++++++------- extensions/xt_geoip.h | 4 ++ 4 files changed, 219 insertions(+), 59 deletions(-) diff --git a/doc/changelog.txt b/doc/changelog.txt index 6b28002..5d31f9c 100644 --- a/doc/changelog.txt +++ b/doc/changelog.txt @@ -4,6 +4,8 @@ HEAD Fixes: - Update to ipset 4.5 * the iptreemap type used wrong gfp flags when deleting entries +Enhancements: +- IPv6 support for xt_geoip v1.31 (2010-11-05) diff --git a/extensions/libxt_geoip.c b/extensions/libxt_geoip.c index e6fbdd3..dcaa434 100644 --- a/extensions/libxt_geoip.c +++ b/extensions/libxt_geoip.c @@ -2,7 +2,7 @@ * "geoip" match extension for iptables * Copyright © Samuel Jean , 2004 - 2008 * Copyright © Nicolas Bouliane , 2004 - 2008 - * Jan Engelhardt , 2008 + * Jan Engelhardt , 2008-2011 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License; either @@ -49,20 +49,28 @@ static struct option geoip_opts[] = { {NULL}, }; -static struct geoip_subnet4 * -geoip_get_subnets(const char *code, uint32_t *count) +static void * +geoip_get_subnets(const char *code, uint32_t *count, uint8_t nfproto) { - struct geoip_subnet4 *subnets; + void *subnets; struct stat sb; char buf[256]; int fd; /* Use simple integer vector files */ + if (nfproto == NFPROTO_IPV6) { #if __BYTE_ORDER == _BIG_ENDIAN - snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/BE/%s.iv4", code); + snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/BE/%s.iv6", code); #else - snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/LE/%s.iv4", code); + snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/LE/%s.iv6", code); #endif + } else { +#if __BYTE_ORDER == _BIG_ENDIAN + snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/BE/%s.iv4", code); +#else + snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/LE/%s.iv4", code); +#endif + } if ((fd = open(buf, O_RDONLY)) < 0) { fprintf(stderr, "Could not open %s: %s\n", buf, strerror(errno)); @@ -70,20 +78,31 @@ geoip_get_subnets(const char *code, uint32_t *count) } fstat(fd, &sb); - if (sb.st_size % sizeof(struct geoip_subnet4) != 0) - xtables_error(OTHER_PROBLEM, "Database file %s seems to be " - "corrupted", buf); + *count = sb.st_size; + switch (nfproto) { + case NFPROTO_IPV6: + if (sb.st_size % sizeof(struct geoip_subnet6) != 0) + xtables_error(OTHER_PROBLEM, + "Database file %s seems to be corrupted", buf); + *count /= sizeof(struct geoip_subnet6); + break; + case NFPROTO_IPV4: + if (sb.st_size % sizeof(struct geoip_subnet4) != 0) + xtables_error(OTHER_PROBLEM, + "Database file %s seems to be corrupted", buf); + *count /= sizeof(struct geoip_subnet4); + break; + } subnets = malloc(sb.st_size); if (subnets == NULL) xtables_error(OTHER_PROBLEM, "geoip: insufficient memory"); read(fd, subnets, sb.st_size); close(fd); - *count = sb.st_size / sizeof(struct geoip_subnet4); return subnets; } static struct geoip_country_user *geoip_load_cc(const char *code, - unsigned short cc) + unsigned short cc, uint8_t nfproto) { struct geoip_country_user *ginfo; ginfo = malloc(sizeof(struct geoip_country_user)); @@ -91,7 +110,8 @@ static struct geoip_country_user *geoip_load_cc(const char *code, if (!ginfo) return NULL; - ginfo->subnets = (unsigned long)geoip_get_subnets(code, &ginfo->count); + ginfo->subnets = (unsigned long)geoip_get_subnets(code, + &ginfo->count, nfproto); ginfo->cc = cc; return ginfo; @@ -134,7 +154,7 @@ check_geoip_cc(char *cc, u_int16_t cc_used[], u_int8_t count) } static unsigned int parse_geoip_cc(const char *ccstr, uint16_t *cc, - union geoip_country_group *mem) + union geoip_country_group *mem, uint8_t nfproto) { char *buffer, *cp, *next; u_int8_t i, count = 0; @@ -151,7 +171,8 @@ 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(cp, cctmp)) == 0) + if ((mem[count++].user = + (unsigned long)geoip_load_cc(cp, cctmp, nfproto)) == 0) xtables_error(OTHER_PROBLEM, "geoip: insufficient memory available"); cc[count-1] = cctmp; @@ -170,11 +191,9 @@ static unsigned int parse_geoip_cc(const char *ccstr, uint16_t *cc, return count; } -static int geoip_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static int geoip_parse(int c, bool invert, unsigned int *flags, + const char *arg, struct xt_geoip_match_info *info, uint8_t nfproto) { - struct xt_geoip_match_info *info = (void *)(*match)->data; - switch (c) { case '1': if (*flags & (XT_GEOIP_SRC | XT_GEOIP_DST)) @@ -186,7 +205,8 @@ static int geoip_parse(int c, char **argv, int invert, unsigned int *flags, if (invert) *flags |= XT_GEOIP_INV; - info->count = parse_geoip_cc(argv[optind-1], info->cc, info->mem); + info->count = parse_geoip_cc(arg, info->cc, info->mem, + nfproto); info->flags = *flags; return true; @@ -200,7 +220,8 @@ static int geoip_parse(int c, char **argv, int invert, unsigned int *flags, if (invert) *flags |= XT_GEOIP_INV; - info->count = parse_geoip_cc(argv[optind-1], info->cc, info->mem); + info->count = parse_geoip_cc(arg, info->cc, info->mem, + nfproto); info->flags = *flags; return true; } @@ -208,6 +229,20 @@ static int geoip_parse(int c, char **argv, int invert, unsigned int *flags, return false; } +static int geoip_parse6(int c, char **argv, int invert, unsigned int *flags, + const void *entry, struct xt_entry_match **match) +{ + return geoip_parse(c, invert, flags, optarg, + (void *)(*match)->data, NFPROTO_IPV6); +} + +static int geoip_parse4(int c, char **argv, int invert, unsigned int *flags, + const void *entry, struct xt_entry_match **match) +{ + return geoip_parse(c, invert, flags, optarg, + (void *)(*match)->data, NFPROTO_IPV4); +} + static void geoip_final_check(unsigned int flags) { @@ -260,22 +295,39 @@ geoip_save(const void *ip, const struct xt_entry_match *match) printf(" "); } -static struct xtables_match geoip_match = { - .family = NFPROTO_IPV4, - .name = "geoip", - .revision = 1, - .version = XTABLES_VERSION, - .size = XT_ALIGN(sizeof(struct xt_geoip_match_info)), - .userspacesize = offsetof(struct xt_geoip_match_info, mem), - .help = geoip_help, - .parse = geoip_parse, - .final_check = geoip_final_check, - .print = geoip_print, - .save = geoip_save, - .extra_opts = geoip_opts, +static struct xtables_match geoip_match[] = { + { + .family = NFPROTO_IPV6, + .name = "geoip", + .revision = 1, + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_geoip_match_info)), + .userspacesize = offsetof(struct xt_geoip_match_info, mem), + .help = geoip_help, + .parse = geoip_parse6, + .final_check = geoip_final_check, + .print = geoip_print, + .save = geoip_save, + .extra_opts = geoip_opts, + }, + { + .family = NFPROTO_IPV4, + .name = "geoip", + .revision = 1, + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_geoip_match_info)), + .userspacesize = offsetof(struct xt_geoip_match_info, mem), + .help = geoip_help, + .parse = geoip_parse4, + .final_check = geoip_final_check, + .print = geoip_print, + .save = geoip_save, + .extra_opts = geoip_opts, + }, }; static __attribute__((constructor)) void geoip_mt_ldr(void) { - xtables_register_match(&geoip_match); + xtables_register_matches(geoip_match, + sizeof(geoip_match) / sizeof(*geoip_match)); } diff --git a/extensions/xt_geoip.c b/extensions/xt_geoip.c index 2f3caae..c84b764 100644 --- a/extensions/xt_geoip.c +++ b/extensions/xt_geoip.c @@ -9,6 +9,7 @@ * Samuel Jean & Nicolas Bouliane */ #include +#include #include #include #include @@ -27,31 +28,49 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Nicolas Bouliane"); MODULE_AUTHOR("Samuel Jean"); MODULE_DESCRIPTION("xtables module for geoip match"); +MODULE_ALIAS("ip6t_geoip"); MODULE_ALIAS("ipt_geoip"); +enum geoip_proto { + GEOIPROTO_IPV6, + GEOIPROTO_IPV4, + __GEOIPROTO_MAX, +}; + /** * @list: anchor point for geoip_head - * @subnets: packed ordered list of ranges + * @subnets: packed ordered list of ranges (either v6 or v4) * @count: number of ranges * @cc: country code */ struct geoip_country_kernel { struct list_head list; - struct geoip_subnet4 *subnets; + void *subnets; atomic_t ref; unsigned int count; unsigned short cc; }; -static LIST_HEAD(geoip_head); +static struct list_head geoip_head[__GEOIPROTO_MAX]; static DEFINE_SPINLOCK(geoip_lock); +static const enum geoip_proto nfp2geo[] = { + [NFPROTO_IPV6] = GEOIPROTO_IPV6, + [NFPROTO_IPV4] = GEOIPROTO_IPV4, +}; +static const size_t geoproto_size[] = { + [GEOIPROTO_IPV6] = sizeof(struct geoip_subnet6), + [GEOIPROTO_IPV4] = sizeof(struct geoip_subnet4), +}; + static struct geoip_country_kernel * -geoip_add_node(const struct geoip_country_user __user *umem_ptr) +geoip_add_node(const struct geoip_country_user __user *umem_ptr, + enum geoip_proto proto) { struct geoip_country_user umem; struct geoip_country_kernel *p; - struct geoip_subnet4 *subnet; + size_t size; + void *subnet; int ret; if (copy_from_user(&umem, umem_ptr, sizeof(umem)) != 0) @@ -63,15 +82,14 @@ geoip_add_node(const struct geoip_country_user __user *umem_ptr) p->count = umem.count; p->cc = umem.cc; - - subnet = vmalloc(p->count * sizeof(struct geoip_subnet4)); + size = p->count * geoproto_size[proto]; + subnet = vmalloc(size); if (subnet == NULL) { ret = -ENOMEM; goto free_p; } if (copy_from_user(subnet, - (const void __user *)(unsigned long)umem.subnets, - p->count * sizeof(struct geoip_subnet4)) != 0) { + (const void __user *)(unsigned long)umem.subnets, size) != 0) { ret = -EFAULT; goto free_s; } @@ -81,7 +99,7 @@ geoip_add_node(const struct geoip_country_user __user *umem_ptr) INIT_LIST_HEAD(&p->list); spin_lock(&geoip_lock); - list_add_tail_rcu(&p->list, &geoip_head); + list_add_tail_rcu(&p->list, &geoip_head[proto]); spin_unlock(&geoip_lock); return p; @@ -112,12 +130,13 @@ static void geoip_try_remove_node(struct geoip_country_kernel *p) kfree(p); } -static struct geoip_country_kernel *find_node(unsigned short cc) +static struct geoip_country_kernel *find_node(unsigned short cc, + enum geoip_proto proto) { struct geoip_country_kernel *p; spin_lock(&geoip_lock); - list_for_each_entry_rcu(p, &geoip_head, list) + list_for_each_entry_rcu(p, &geoip_head[proto], list) if (p->cc == cc) { atomic_inc(&p->ref); spin_unlock(&geoip_lock); @@ -128,6 +147,72 @@ static struct geoip_country_kernel *find_node(unsigned short cc) return NULL; } +static inline int +ipv6_cmp(const struct in6_addr *p, const struct in6_addr *q) +{ + unsigned int i; + + for (i = 0; i < 4; ++i) { + if (p->s6_addr32[i] < q->s6_addr32[i]) + return -1; + else if (p->s6_addr32[i] > q->s6_addr32[i]) + return 1; + } + + return 0; +} + +static bool geoip_bsearch6(const struct geoip_subnet6 *range, + const struct in6_addr *addr, int lo, int hi) +{ + int mid; + + if (hi <= lo) + return false; + mid = (lo + hi) / 2; + if (ipv6_cmp(&range[mid].begin, addr) <= 0 && + ipv6_cmp(addr, &range[mid].end) <= 0) + return true; + if (ipv6_cmp(&range[mid].begin, addr) > 0) + return geoip_bsearch6(range, addr, lo, mid); + else if (ipv6_cmp(&range[mid].end, addr) < 0) + return geoip_bsearch6(range, addr, mid + 1, hi); + + WARN_ON(true); + return false; +} + +static bool +xt_geoip_mt6(const struct sk_buff *skb, struct xt_action_param *par) +{ + const struct xt_geoip_match_info *info = par->matchinfo; + const struct geoip_country_kernel *node; + const struct ipv6hdr *iph = ipv6_hdr(skb); + unsigned int i; + struct in6_addr ip; + + memcpy(&ip, (info->flags & XT_GEOIP_SRC) ? &iph->saddr : &iph->daddr, + sizeof(ip)); + for (i = 0; i < 4; ++i) + ip.s6_addr32[i] = ntohl(ip.s6_addr32[i]); + + rcu_read_lock(); + for (i = 0; i < info->count; i++) { + if ((node = info->mem[i].kernel) == NULL) { + pr_err("'%c%c' is not loaded into memory... skip it!\n", + COUNTRY(info->cc[i])); + continue; + } + if (geoip_bsearch6(node->subnets, &ip, 0, node->count)) { + rcu_read_unlock(); + return !(info->flags & XT_GEOIP_INV); + } + } + + rcu_read_unlock(); + return info->flags & XT_GEOIP_INV; +} + static bool geoip_bsearch4(const struct geoip_subnet4 *range, uint32_t addr, int lo, int hi) { @@ -181,9 +266,10 @@ static int xt_geoip_mt_checkentry(const struct xt_mtchk_param *par) unsigned int i; for (i = 0; i < info->count; i++) { - node = find_node(info->cc[i]); + node = find_node(info->cc[i], nfp2geo[par->family]); if (node == NULL) { - node = geoip_add_node((const void __user *)(unsigned long)info->mem[i].user); + node = geoip_add_node((const void __user *)(unsigned long)info->mem[i].user, + nfp2geo[par->family]); if (IS_ERR(node)) { printk(KERN_ERR "xt_geoip: unable to load '%c%c' into memory: %ld\n", @@ -228,25 +314,41 @@ static void xt_geoip_mt_destroy(const struct xt_mtdtor_param *par) "xt_geoip: please report this bug to the maintainers\n"); } -static struct xt_match xt_geoip_match __read_mostly = { - .name = "geoip", - .revision = 1, - .family = NFPROTO_IPV4, - .match = xt_geoip_mt4, - .checkentry = xt_geoip_mt_checkentry, - .destroy = xt_geoip_mt_destroy, - .matchsize = sizeof(struct xt_geoip_match_info), - .me = THIS_MODULE, +static struct xt_match xt_geoip_match[] __read_mostly = { + { + .name = "geoip", + .revision = 1, + .family = NFPROTO_IPV6, + .match = xt_geoip_mt6, + .checkentry = xt_geoip_mt_checkentry, + .destroy = xt_geoip_mt_destroy, + .matchsize = sizeof(struct xt_geoip_match_info), + .me = THIS_MODULE, + }, + { + .name = "geoip", + .revision = 1, + .family = NFPROTO_IPV4, + .match = xt_geoip_mt4, + .checkentry = xt_geoip_mt_checkentry, + .destroy = xt_geoip_mt_destroy, + .matchsize = sizeof(struct xt_geoip_match_info), + .me = THIS_MODULE, + }, }; static int __init xt_geoip_mt_init(void) { - return xt_register_match(&xt_geoip_match); + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(geoip_head); ++i) + INIT_LIST_HEAD(&geoip_head[i]); + return xt_register_matches(xt_geoip_match, ARRAY_SIZE(xt_geoip_match)); } static void __exit xt_geoip_mt_fini(void) { - xt_unregister_match(&xt_geoip_match); + xt_unregister_matches(xt_geoip_match, ARRAY_SIZE(xt_geoip_match)); } module_init(xt_geoip_mt_init); diff --git a/extensions/xt_geoip.h b/extensions/xt_geoip.h index c447e61..ee6e662 100644 --- a/extensions/xt_geoip.h +++ b/extensions/xt_geoip.h @@ -27,6 +27,10 @@ struct geoip_subnet4 { __u32 end; }; +struct geoip_subnet6 { + struct in6_addr begin, end; +}; + struct geoip_country_user { aligned_u64 subnets; __u32 count;