From 42ce2cced8ffe2d30f6aba78d879f66bd4db6845 Mon Sep 17 00:00:00 2001 From: John Crisp Date: Thu, 13 Feb 2025 19:14:51 +0100 Subject: [PATCH] * Thu Feb 13 2025 John Crisp 1.3.1-24.sme - move scriptoig back to /usr/share/geoip - Lose the LE/BE (Little/Big Endian) parts as iptables can't seme to read the file in subdirs - Update ULOG to NFLOG in rules but restricts the number of countries --- .../etc/rc.d/init.d/masq/90adjustXt_Geoip | 6 +- .../lib/SrvMngr/Controller/Xt_geoip.pm | 8 +- root/usr/share/xt_geoip/update_base | 7 +- .../usr/share/xt_geoip/xt_geoip_build_maxmind | 257 ++++++++++++++++++ root/usr/share/xt_geoip/xt_geoip_dl | 9 +- smeserver-xt_geoip.spec | 8 +- 6 files changed, 285 insertions(+), 10 deletions(-) create mode 100644 root/usr/share/xt_geoip/xt_geoip_build_maxmind diff --git a/root/etc/e-smith/templates/etc/rc.d/init.d/masq/90adjustXt_Geoip b/root/etc/e-smith/templates/etc/rc.d/init.d/masq/90adjustXt_Geoip index aceea0e..d5b0484 100644 --- a/root/etc/e-smith/templates/etc/rc.d/init.d/masq/90adjustXt_Geoip +++ b/root/etc/e-smith/templates/etc/rc.d/init.d/masq/90adjustXt_Geoip @@ -73,7 +73,7 @@ EOF if ($port ne '' and $servStatus eq 'enabled' and $servAccess eq 'public' and $locBC ne '') { push @locPorts, $port; my $multi = ( $port =~ /[,:]/ )? "-m multiport --dports" : "--dport"; - $OUT .= " /sbin/iptables -A \$NEW_XTGeoIP -m geoip $reverse --src-cc $locBC -p tcp $multi $port -j ULOG --ulog-prefix \"GeoIP BAN: $servName\"\n"; + $OUT .= " /sbin/iptables -A \$NEW_XTGeoIP -m geoip $reverse --src-cc $locBC -p tcp $multi $port -j NFLOG --nflog-prefix \"GeoIP BAN: $servName\"\n"; $OUT .= " /sbin/iptables -A \$NEW_XTGeoIP -m geoip $reverse --src-cc $locBC -p tcp $multi $port -j DROP\n"; } } @@ -85,10 +85,10 @@ EOF @locPorts = () unless $others; if (@locPorts != 0) { my $LocPorts = join ',', @locPorts; - $OUT .= " /sbin/iptables -A \$NEW_XTGeoIP -p tcp -m geoip -m multiport ! --dports $LocPorts $reverse --src-cc $BC -j ULOG --ulog-prefix \"GeoIP BAN: OTHER\"\n"; + $OUT .= " /sbin/iptables -A \$NEW_XTGeoIP -p tcp -m geoip -m multiport ! --dports $LocPorts $reverse --src-cc $BC -j NFLOG --nflog-prefix \"GeoIP BAN: OTHER\"\n"; $OUT .= " /sbin/iptables -A \$NEW_XTGeoIP -p tcp -m geoip -m multiport ! --dports $LocPorts $reverse --src-cc $BC -j DROP\n"; } else { - $OUT .= " /sbin/iptables -A \$NEW_XTGeoIP -p tcp -m geoip $reverse --src-cc $BC -j ULOG --ulog-prefix \"GeoIP BAN: ALL\"\n"; + $OUT .= " /sbin/iptables -A \$NEW_XTGeoIP -p tcp -m geoip $reverse --src-cc $BC -j NFLOG --nflog-prefix \"GeoIP BAN: ALL\"\n"; $OUT .= " /sbin/iptables -A \$NEW_XTGeoIP -p tcp -m geoip $reverse --src-cc $BC -j DROP\n"; } } diff --git a/root/usr/share/smanager/lib/SrvMngr/Controller/Xt_geoip.pm b/root/usr/share/smanager/lib/SrvMngr/Controller/Xt_geoip.pm index 1237745..63f8b51 100644 --- a/root/usr/share/smanager/lib/SrvMngr/Controller/Xt_geoip.pm +++ b/root/usr/share/smanager/lib/SrvMngr/Controller/Xt_geoip.pm @@ -244,7 +244,8 @@ sub get_stat_license_key { } ## end sub get_stat_license_key sub get_date_update { - my $file = "/usr/share/xt_geoip/LE/A1.iv4"; + #my $file = "/usr/share/xt_geoip/LE/A1.iv4"; + my $file = "/usr/share/xt_geoip/A1.iv4"; my $filetime = (-e $file) ? (stat($file))[9] : 0; return strftime("%Y/%m/%d %H:%M", localtime($filetime)) || ''; } ## end sub get_date_update @@ -318,7 +319,7 @@ sub generateStats { return $out; } ## end sub generateStats -#Subroutine to list counries codes +#Subroutine to list countries codes sub generateCodes { my $c = shift; my $out = ''; @@ -426,7 +427,8 @@ sub must_exist { return $c->l('xtg_ERROR_COUNTRY_MAX', $ctr) if ($ctr > 50); foreach my $bcs (@mq_bcs) { - my $file = "/usr/share/xt_geoip/LE/" . $bcs . ".iv4"; + #my $file = "/usr/share/xt_geoip/LE/" . $bcs . ".iv4"; + my $file = "/usr/share/xt_geoip/" . $bcs . ".iv4"; if (!-f $file) { $listerr .= $bcs . ","; } } return $c->l('xtg_ERROR_COUNTRY_NOT_EXIST', $listerr) if $listerr; diff --git a/root/usr/share/xt_geoip/update_base b/root/usr/share/xt_geoip/update_base index 0042e8b..d70f38d 100644 --- a/root/usr/share/xt_geoip/update_base +++ b/root/usr/share/xt_geoip/update_base @@ -1,5 +1,8 @@ +# Run the builder - this leaves all the file in /usr.share/xt_geoip +# It's messy but I don't know how to get iptables to read a sub dir + cd /usr/share/xt_geoip if ( ./xt_geoip_dl ) then - /usr/libexec/xtables-addons/xt_geoip_build GeoIPCountryWhois.csv -fi \ No newline at end of file + /usr/share/xt_geoip/xt_geoip_build_maxmind +fi diff --git a/root/usr/share/xt_geoip/xt_geoip_build_maxmind b/root/usr/share/xt_geoip/xt_geoip_build_maxmind new file mode 100644 index 0000000..0dad652 --- /dev/null +++ b/root/usr/share/xt_geoip/xt_geoip_build_maxmind @@ -0,0 +1,257 @@ +#!/usr/bin/perl +# +# Converter for MaxMind (GeoLite2) CSV database to binary, for xt_geoip +# Copyright Jan Engelhardt, 2008-2011 +# Copyright Philip Prindeville, 2018 +# copied from /usr/libexec/xtables-addons to work on Koozali SME v11 +# cannot work out to get iptables to read from a sub directory from a here +# +use Getopt::Long; +use Net::CIDR::Lite; +use Socket qw(AF_INET AF_INET6 inet_pton); +use warnings; +use Text::CSV_XS; # or trade for Text::CSV +use strict; +$| = 1; +my $csv = Text::CSV_XS->new( + { allow_whitespace => 1, + binary => 1, + eol => $/, + } +); # or Text::CSV + +#my $source_dir = "."; +my $source_dir = "./GeoLite2-Country-CSV"; +my $quiet = 0; +my $target_dir = "."; +&Getopt::Long::Configure(qw(bundling)); +&GetOptions( + "D=s" => \$target_dir, + "S=s" => \$source_dir, + "q" => \$quiet, + "s" => sub { $target_dir = "/usr/share/xt_geoip"; }, +); + +if (!-d $source_dir) { + print STDERR "Source directory \"$source_dir\" does not exist.\n"; + exit 1; +} + +if (!-d $target_dir) { + print STDERR "Target directory \"$target_dir\" does not exist.\n"; + exit 1; +} +my %countryId; +my %countryName; +&loadCountries(); +&dump(&collect()); + +sub loadCountries { + sub id; + sub cc; + sub long; + sub ct; + sub cn; + %countryId = (); + %countryName = (); + my $file = "$source_dir/GeoLite2-Country-Locations-en.csv"; + open(my $fh, '<', $file) || die "Couldn't open list country names\n"; + + # first line is headers + my $row = $csv->getline($fh); + my %header = map { ($row->[$_], $_); } (0 .. $#{$row}); + my %pairs = ( + country_iso_code => 'ISO Country Code', + geoname_id => 'ID', + country_name => 'Country Name', + continent_code => 'Continent Code', + continent_name => 'Continent Name', + ); + + # verify that the columns we need are present + map { die "Table has no $pairs{$_} column\n" unless (exists $header{$_}); } keys %pairs; + my %remapping = ( + id => 'geoname_id', + cc => 'country_iso_code', + long => 'country_name', + ct => 'continent_code', + cn => 'continent_name', + ); + + # now create a function which returns the value of that column # + map { eval "sub $_ () { \$header{\$remapping{$_}}; }"; } keys %remapping; + + while (my $row = $csv->getline($fh)) { + if ($row->[cc] eq '' && $row->[long] eq '') { + $countryId{ $row->[id] } = $row->[ct]; + $countryName{ $row->[ct] } = $row->[cn]; + } else { + $countryId{ $row->[id] } = $row->[cc]; + $countryName{ $row->[cc] } = $row->[long]; + } + } ## end while (my $row = $csv->getline...) + $countryName{A1} = 'Anonymous Proxy'; + $countryName{A2} = 'Satellite Provider'; + $countryName{O1} = 'Other Country'; + close($fh); + + # clean up the namespace + undef &id; + undef &cc; + undef &long; + undef &ct; + undef &cn; +} ## end sub loadCountries + +sub lookupCountry { + my ($id, $rid, $proxy, $sat) = @_; + + if ($proxy) { + return 'A1'; + } elsif ($sat) { + return 'A2'; + } + $id ||= $rid; + + if ($id eq '') { + return 'O1'; + } + die "Unknown id: $id line $.\n" unless (exists $countryId{$id}); + return $countryId{$id}; +} ## end sub lookupCountry + +sub collect { + my ($file, $fh, $row); + my (%country, %header); + sub net; + sub id; + sub rid; + sub proxy; + sub sat; + my %pairs = ( + network => 'Network', + registered_country_geoname_id => 'Registered Country ID', + geoname_id => 'Country ID', + is_anonymous_proxy => 'Anonymous Proxy', + is_satellite_provider => 'Satellite', + ); + + foreach (sort keys %countryName) { + $country{$_} = { + name => $countryName{$_}, + pool_v4 => Net::CIDR::Lite->new(), + pool_v6 => Net::CIDR::Lite->new(), + }; + } ## end foreach (sort keys %countryName) + $file = "$source_dir/GeoLite2-Country-Blocks-IPv4.csv"; + open($fh, '<', $file) || die "Can't open IPv4 database\n"; + + # first line is headers + $row = $csv->getline($fh); + %header = map { ($row->[$_], $_); } (0 .. $#{$row}); + + # verify that the columns we need are present + map { die "Table has no %pairs{$_} column\n" unless (exists $header{$_}); } keys %pairs; + my %remapping = ( + net => 'network', + id => 'geoname_id', + rid => 'registered_country_geoname_id', + proxy => 'is_anonymous_proxy', + sat => 'is_satellite_provider', + ); + + # now create a function which returns the value of that column # + map { eval "sub $_ () { \$header{\$remapping{$_}}; }"; } keys %remapping; + + while ($row = $csv->getline($fh)) { + my ($cc, $cidr); + $cc = lookupCountry($row->[id], $row->[rid], $row->[proxy], $row->[sat]); + $cidr = $row->[net]; + $country{$cc}->{pool_v4}->add($cidr); + + if (!$quiet && $. % 4096 == 0) { + print STDOUT "\r\e[2K$. entries"; + } + } ## end while ($row = $csv->getline...) + print STDOUT "\r\e[2K$. entries total\n" unless ($quiet); + close($fh); + + # clean up the namespace + undef &net; + undef &id; + undef &rid; + undef &proxy; + undef &sat; + $file = "$source_dir/GeoLite2-Country-Blocks-IPv6.csv"; + open($fh, '<', $file) || die "Can't open IPv6 database\n"; + + # first line is headers + $row = $csv->getline($fh); + %header = map { ($row->[$_], $_); } (0 .. $#{$row}); + + # verify that the columns we need are present + map { die "Table has no %pairs{$_} column\n" unless (exists $header{$_}); } keys %pairs; + + # unlikely the IPv6 table has different columns, but just to be sure + # create a function which returns the value of that column # + map { eval "sub $_ () { \$header{\$remapping{$_}}; }"; } keys %remapping; + + while ($row = $csv->getline($fh)) { + my ($cc, $cidr); + $cc = lookupCountry($row->[id], $row->[rid], $row->[proxy], $row->[sat]); + $cidr = $row->[net]; + $country{$cc}->{pool_v6}->add($cidr); + + if (!$quiet && $. % 4096 == 0) { + print STDOUT "\r\e[2K$. entries"; + } + } ## end while ($row = $csv->getline...) + print STDOUT "\r\e[2K$. entries total\n" unless ($quiet); + close($fh); + + # clean up the namespace + undef &net; + undef &id; + undef &rid; + undef &proxy; + undef &sat; + return \%country; +} ## end sub collect + +sub dump { + my $country = shift @_; + + foreach my $iso_code (sort keys %{$country}) { + &dump_one($iso_code, $country->{$iso_code}); + } +} ## end sub dump + +sub dump_one { + my ($iso_code, $country) = @_; + my @ranges; + @ranges = $country->{pool_v4}->list_range(); + writeCountry($iso_code, $country->{name}, AF_INET, @ranges); + @ranges = $country->{pool_v6}->list_range(); + writeCountry($iso_code, $country->{name}, AF_INET6, @ranges); +} ## end sub dump_one + +sub writeCountry { + my ($iso_code, $name, $family, @ranges) = @_; + my $fh; + printf "%5u IPv%s ranges for %s %s\n", scalar(@ranges), ($family == AF_INET ? '4' : '6'), $iso_code, $name unless ($quiet); + my $file = "$target_dir/" . uc($iso_code) . ".iv" . ($family == AF_INET ? '4' : '6'); + + if (!open($fh, '>', $file)) { + print STDERR "Error opening $file: $!\n"; + exit 1; + } + binmode($fh); + + foreach my $range (@ranges) { + my ($start, $end) = split('-', $range); + $start = inet_pton($family, $start); + $end = inet_pton($family, $end); + print $fh $start, $end; + } ## end foreach my $range (@ranges) + close $fh; +} ## end sub writeCountry diff --git a/root/usr/share/xt_geoip/xt_geoip_dl b/root/usr/share/xt_geoip/xt_geoip_dl index a54b3b9..84eac93 100644 --- a/root/usr/share/xt_geoip/xt_geoip_dl +++ b/root/usr/share/xt_geoip/xt_geoip_dl @@ -3,6 +3,9 @@ # Original script from xtables-addons # SME specific use of ConfigDB # replace /usr/libexec/xtables-addons/xt_geoip_dl in /usr/share/xt_geoip/update_base +# Koozali SME v11 +# Now migrated to using files in /usr/share/xt_geoip + status=$(/sbin/e-smith/config getprop geoip status) if [[ "$status" != "enabled" ]] @@ -26,5 +29,9 @@ then exit 2 fi -unzip -q GeoLite2-Country-CSV.zip +# unzip -q GeoLite2-Country-CSV.zip +if [ ! -d "/usr/share/xt_geoip/GeoLite2-Country-CSV" ]; then + mkdir -p "/usr/share/xt_geoip/GeoLite2-Country-CSV"; +fi +unzip -o -q -j GeoLite2-Country-CSV.zip -d /usr/share/xt_geoip/GeoLite2-Country-CSV rm -f GeoLite2-Country-CSV.zip diff --git a/smeserver-xt_geoip.spec b/smeserver-xt_geoip.spec index c60d042..863fe22 100644 --- a/smeserver-xt_geoip.spec +++ b/smeserver-xt_geoip.spec @@ -1,6 +1,6 @@ %define name smeserver-xt_geoip %define version 1.3.1 -%define release 23 +%define release 24 Summary: smserver rpm to setup database, update and configuration for xt_geoip module with a panel. Name: %{name} @@ -56,6 +56,7 @@ rm -f %{name}-%{version}-filelist --file /usr/share/xt_geoip/geoip_stats 'attr(0755, root, root)'\ --file /usr/share/xt_geoip/xt_geoip_dl 'attr(0750, root, root)'\ --file /usr/share/xt_geoip/update_base 'attr(0750, root, root)'\ + --file /usr/share/xt_geoip/xt_geoip_build_maxmind 'attr(0750, root, root)'\ > %{name}-%{version}-filelist echo "%doc COPYING" >> %{name}-%{version}-filelist @@ -81,6 +82,11 @@ fi %changelog +* Thu Feb 13 2025 John Crisp 1.3.1-24.sme +- move scriptoig back to /usr/share/geoip +- Lose the LE/BE (Little/Big Endian) parts as iptables can't seme to read the file in subdirs +- Update ULOG to NFLOG in rules but restricts the number of countries + * Wed Feb 12 2025 John Crisp 1.3.1-23.sme - Update dependencies for xtables addons - Remove $ from config in templates