]> git.ipfire.org Git - thirdparty/xtables-addons.git/commitdiff
geoip: add database query tool for use with ipsets
authorPhilip Prindeville <philipp@redfish-solutions.com>
Mon, 30 Apr 2018 00:06:04 +0000 (02:06 +0200)
committerJan Engelhardt <jengelh@inai.de>
Mon, 30 Apr 2018 07:41:21 +0000 (09:41 +0200)
Add a tool for retrieiving the IPv4 or IPv6 (or both!) CIDR ranges
for a given country, which can then be injected into an ipset if
one doesn't want to use (or have available) the xt_geoip extension.

Signed-off-by: Philip Prindeville <philipp@redfish-solutions.com>
geoip/xt_geoip_fetch [new file with mode: 0755]

diff --git a/geoip/xt_geoip_fetch b/geoip/xt_geoip_fetch
new file mode 100755 (executable)
index 0000000..4a35760
--- /dev/null
@@ -0,0 +1,93 @@
+#!/usr/bin/perl
+#
+#      Utility to query GeoIP database
+#      Copyright Philip Prindeville, 2018
+#
+use Getopt::Long;
+use Socket qw(AF_INET AF_INET6 inet_ntop);
+use warnings;
+use strict;
+
+sub AF_INET_SIZE() { 4 }
+sub AF_INET6_SIZE() { 16 }
+
+my $target_dir = ".";
+my $ipv4 = 0;
+my $ipv6 = 0;
+
+&Getopt::Long::Configure(qw(bundling));
+&GetOptions(
+       "D=s" => \$target_dir,
+       "4"   => \$ipv4,
+       "6"   => \$ipv6,
+);
+
+if (!-d $target_dir) {
+       print STDERR "Target directory $target_dir does not exit.\n";
+       exit 1;
+}
+
+# if neither specified, assume both
+if (! $ipv4 && ! $ipv6) {
+       $ipv4 = $ipv6 = 1;
+}
+
+foreach my $cc (@ARGV) {
+       if ($cc !~ m/^([a-z]{2}|a[12]|o1)$/i) {
+               print STDERR "Invalid country code '$cc'\n";
+               exit 1;
+       }
+
+       my $file = $target_dir . '/' . uc($cc) . '.iv4';
+
+       if (! -f $file) {
+               printf STDERR "Can't find data for country '$cc'\n";
+               exit 1;
+       }
+
+       my ($contents, $buffer, $bytes, $fh);
+
+       if ($ipv4) {
+               open($fh, '<', $file) || die "Couldn't open file for '$cc'\n";
+
+               binmode($fh);
+
+               while (($bytes = read($fh, $buffer, AF_INET_SIZE * 2)) == AF_INET_SIZE * 2) {
+                       my $start = inet_ntop(AF_INET, substr($buffer, 0, AF_INET_SIZE));
+                       my $end = inet_ntop(AF_INET, substr($buffer, AF_INET_SIZE));
+                       print $start, '-', $end, "\n";
+               }
+               close($fh);
+               if (! defined $bytes) {
+                       printf STDERR "Error reading file for '$cc'\n";
+                       exit 1;
+               } elsif ($bytes != 0) {
+                       printf STDERR "Short read on file for '$cc'\n";
+                       exit 1;
+               }
+       }
+
+       substr($file, -1) = '6';
+
+       if ($ipv6) {
+               open($fh, '<', $file) || die "Couldn't open file for '$cc'\n";
+
+               binmode($fh);
+
+               while (($bytes = read($fh, $buffer, AF_INET6_SIZE * 2)) == AF_INET6_SIZE * 2) {
+                       my $start = inet_ntop(AF_INET6, substr($buffer, 0, AF_INET6_SIZE));
+                       my $end = inet_ntop(AF_INET6, substr($buffer, AF_INET6_SIZE));
+                       print $start, '-', $end, "\n";
+               }
+               close($fh);
+               if (! defined $bytes) {
+                       printf STDERR "Error reading file for '$cc'\n";
+                       exit 1;
+               } elsif ($bytes != 0) {
+                       printf STDERR "Short read on file for '$cc'\n";
+                       exit 1;
+               }
+       }
+}
+
+exit 0;