Merge branch 'master' of ssh://git.ipfire.org/pub/git/ipfire-2.x into seventeen-geoip
authorStefan Schantl <stefan.schantl@ipfire.org>
Sat, 14 Feb 2015 11:34:31 +0000 (12:34 +0100)
committerStefan Schantl <stefan.schantl@ipfire.org>
Sat, 14 Feb 2015 11:34:31 +0000 (12:34 +0100)
Conflicts:
make.sh

26 files changed:
config/cfgroot/general-functions.pl
config/cfgroot/geoip-functions.pl [new file with mode: 0644]
config/cfgroot/header.pl
config/cron/crontab
config/firewall/firewall-lib.pl
config/firewall/geoipblock [new file with mode: 0644]
config/firewall/rules.pl [changed mode: 0755->0644]
config/menu/50-firewall.menu
config/rootfiles/common/Locale-Country
config/rootfiles/common/perl-Text-CSV_XS [new file with mode: 0644]
config/rootfiles/common/stage2
config/rootfiles/common/xtables-addons [new file with mode: 0644]
config/xtables-addons/mconfig [new file with mode: 0644]
html/cgi-bin/firewall.cgi
html/cgi-bin/fwhosts.cgi
html/cgi-bin/geoip-block.cgi [new file with mode: 0644]
langs/en/cgi-bin/en.pl
lfs/Locale-Country
lfs/perl-Text-CSV_XS [new file with mode: 0644]
lfs/stage2
lfs/xtables-addons [new file with mode: 0644]
make.sh
src/initscripts/init.d/firewall
src/initscripts/init.d/networking/red.up/99-geoip-database [new file with mode: 0644]
src/scripts/xt_geoip_build [new file with mode: 0644]
src/scripts/xt_geoip_update [new file with mode: 0644]

index 35ae7c0..29f7e8c 100644 (file)
@@ -17,6 +17,7 @@ package General;
 use strict;
 use Socket;
 use IO::Socket;
+use Locale::Country;
 use Net::SSLeay;
 use Net::IPv4Addr qw(:all);
 $|=1; # line buffering
diff --git a/config/cfgroot/geoip-functions.pl b/config/cfgroot/geoip-functions.pl
new file mode 100644 (file)
index 0000000..68b6f50
--- /dev/null
@@ -0,0 +1,90 @@
+#!/usr/bin/perl -w
+############################################################################
+#                                                                          #
+# This file is part of the IPFire Firewall.                                #
+#                                                                          #
+# IPFire is free software; you can redistribute it and/or modify           #
+# it under the terms of the GNU General Public License as published by     #
+# the Free Software Foundation; either version 2 of the License, or        #
+# (at your option) any later version.                                      #
+#                                                                          #
+# IPFire is distributed in the hope that it will be useful,                #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of           #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            #
+# GNU General Public License for more details.                             #
+#                                                                          #
+# You should have received a copy of the GNU General Public License        #
+# along with IPFire; if not, write to the Free Software                    #
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA #
+#                                                                          #
+# Copyright (C) 2015 IPFire Team <info@ipfire.org>.                        #
+#                                                                          #
+############################################################################
+
+package GeoIP;
+
+use Locale::Country;
+
+# Function to get the flag icon for a specified country code.
+sub get_flag_icon($) {
+       my ($input) = @_;
+
+       # Webserver's root dir. (Required for generating full path)
+       my $webroot = "/srv/web/ipfire/html";
+
+       # Directory which contains the flag icons.
+       my $flagdir = "/images/flags";
+
+       # File extension of the country flags.
+       my $ext = "png";
+
+       # Remove whitespaces.
+       chomp($input);
+
+       # Convert given country code to lower case.
+       my $ccode = lc($input);
+
+       # Generate filename, based on the contry code in lower case
+       # and the defined file extension.
+       my $file = join('.', $ccode,$ext);
+
+       # Generate path inside webroot to the previously generated file.
+       my $flag_icon = join('/', $flagdir,$file);
+
+       # Generate absolute path to the icon file.
+       my $absolute_path = join('', $webroot,$flag_icon);
+       # Check if the a icon file exists.
+       if (-e "$absolute_path") {
+               # Return content of flag_icon.
+               return $flag_icon;
+       }
+}
+
+# Function to get the county name by a given country code.
+sub get_full_country_name($) {
+       my ($input) = @_;
+       my $name;
+
+       # Remove whitespaces.
+       chomp($input);
+
+       # Convert input into lower case format.
+       my $code = lc($input);
+
+       # Handle country codes which are not in the list.
+       if ($code eq "a1") { $name = "Anonymous Proxy" }
+       elsif ($code eq "a2") { $name = "Satellite Provider" }
+       elsif ($code eq "o1") { $name = "Other Country" }
+       elsif ($code eq "ap") { $name = "Asia/Pacific Region" }
+       elsif ($code eq "eu") { $name = "Europe" }
+       elsif ($code eq "yu") { $name = "Yugoslavia" }
+       else {
+               # Use perl built-in module to get the country code.
+               $name = &Locale::Country::code2country($code);
+       }
+
+       return $name;
+}
+
+1;
index cf895bf..974c4d8 100644 (file)
@@ -263,7 +263,7 @@ sub getcgihash {
        return if ($ENV{'REQUEST_METHOD'} ne 'POST');
        if (!$params->{'wantfile'}) {
                $CGI::DISABLE_UPLOADS = 1;
-               $CGI::POST_MAX        = 512 * 1024;
+               $CGI::POST_MAX        = 1024 * 1024;
        } else {
                $CGI::POST_MAX = 10 * 1024 * 1024;
        }
index d78d08f..54e9b5f 100644 (file)
@@ -57,3 +57,6 @@ HOME=/
 # Re-read firewall rules every Sunday in March, October and November to take care of daylight saving time
 00 3 * 3 0          /usr/local/bin/timezone-transition /usr/local/bin/firewallctrl
 00 2 * 10-11 0      /usr/local/bin/timezone-transition /usr/local/bin/firewallctrl
+
+# Update GeoIP database once a month.
+3 2 1 * * *    [ -f "/var/ipfire/red/active" ] && /usr/local/bin/xt_geoip_update >/dev/null 2>&1
index f3cd67f..f73d84f 100755 (executable)
@@ -552,4 +552,37 @@ sub get_internal_firewall_ip_address
        return 0;
 }
 
+sub get_geoip_locations() {
+       # Path to the directory which contains the binary geoip
+       # databases.
+       my $directory="/usr/share/xt_geoip/LE";
+
+       # Array to store the final country list.
+       my @country_codes = ();
+
+       # Open location and do a directory listing.
+       opendir(DIR, "$directory");
+       my @locations = readdir(DIR);
+       closedir(DIR);
+
+       # Loop through the directory listing, and cut of the file extensions.
+       foreach my $location (sort @locations) {
+               # skip . and ..
+               next if($location =~ /^\.$/);
+               next if($location =~ /^\.\.$/);
+
+               # Remove whitespaces.
+               chomp($location);
+
+               # Cut-off file extension.
+               my ($country_code, $extension) = split(/\./, $location);
+
+               # Add country code to array.
+               push(@country_codes, $country_code);
+       }
+
+       # Return final array.
+       return @country_codes;
+}
+
 return 1;
diff --git a/config/firewall/geoipblock b/config/firewall/geoipblock
new file mode 100644 (file)
index 0000000..4d483d3
--- /dev/null
@@ -0,0 +1 @@
+GEOIPBLOCK_ENABLED=off
old mode 100755 (executable)
new mode 100644 (file)
index 97b8897..cd2f3a6
@@ -60,6 +60,7 @@ my $configfwdfw               = "${General::swroot}/firewall/config";
 my $configinput            = "${General::swroot}/firewall/input";
 my $configoutgoing  = "${General::swroot}/firewall/outgoing";
 my $p2pfile                    = "${General::swroot}/firewall/p2protocols";
+my $geoipfile          = "${General::swroot}/firewall/geoipblock";
 my $configgrp          = "${General::swroot}/fwhosts/customgroups";
 my $netsettings                = "${General::swroot}/ethernet/settings";
 
@@ -94,6 +95,9 @@ sub main {
        # Load P2P block rules.
        &p2pblock();
 
+       # Load GeoIP block rules.
+       &geoipblock();
+
        # Reload firewall policy.
        run("/usr/sbin/firewall-policy");
 }
@@ -573,6 +577,40 @@ sub p2pblock {
        }
 }
 
+sub geoipblock {
+       my %geoipsettings = ();
+
+       # Check if the geoip settings file exists
+       if (-e "$geoipfile") {
+               # Read settings file
+               &General::readhash("$geoipfile", \%geoipsettings);
+       } else {
+               # Exit submodule, go on processing the remaining script
+               return;
+       }
+
+       # If geoip blocking is not enabled, we are finished here.
+       if ($geoipsettings{'GEOIPBLOCK_ENABLED'} ne "on") {
+               # Exit submodule. Process remaining script.
+               return;
+       }
+
+       # Get supported locations.
+       my @locations = &fwlib::get_geoip_locations();
+
+       # Create iptables chain.
+       run("$IPTABLES -F GEOIPBLOCK");
+
+       # Loop through all supported geoip locations and
+       # create iptables rules, if blocking this country
+       # is enabled.
+       foreach my $location (@locations) {
+               if($geoipsettings{$location} eq "on") {
+                       run("$IPTABLES -A GEOIPBLOCK -m geoip --src-cc $location -j DROP");
+               }
+       }
+}
+
 sub get_protocols {
        my $hash = shift;
        my $key = shift;
index e872e64..7271b32 100644 (file)
                                'title' => "P2P-Block",
                                'enabled' => 1,
                                };
+    $subfirewall->{'50.geoipblock'} = {
+                               'caption' => $Lang::tr{'geoipblock'},
+                               'uri' => '/cgi-bin/geoip-block.cgi',
+                               'title' => $Lang::tr{'geoipblock'},
+                               'enabled' => 1,
+                               };
     $subfirewall->{'60.wireless'} = {
                                'caption' => $Lang::tr{'blue access'},
                                'uri' => '/cgi-bin/wireless.cgi',
index bbe51ee..0ed312f 100644 (file)
@@ -1,13 +1,50 @@
-#usr/lib/perl5/site_perl/5.12.3/Locale
-usr/lib/perl5/site_perl/5.12.3/Locale/Constants.pm
-usr/lib/perl5/site_perl/5.12.3/Locale/Constants.pod
-usr/lib/perl5/site_perl/5.12.3/Locale/Country.pm
-usr/lib/perl5/site_perl/5.12.3/Locale/Country.pod
-usr/lib/perl5/site_perl/5.12.3/Locale/Currency.pm
-usr/lib/perl5/site_perl/5.12.3/Locale/Currency.pod
-usr/lib/perl5/site_perl/5.12.3/Locale/Language.pm
-usr/lib/perl5/site_perl/5.12.3/Locale/Language.pod
-usr/lib/perl5/site_perl/5.12.3/Locale/Script.pm
-usr/lib/perl5/site_perl/5.12.3/Locale/Script.pod
-#usr/lib/perl5/site_perl/5.12.3/MACHINE-linux-thread-multi/auto/Locale-Codes
-#usr/lib/perl5/site_perl/5.12.3/MACHINE-linux-thread-multi/auto/Locale-Codes/.packlist
+#usr/lib/perl5/5.12.3/Locale/Codes
+usr/lib/perl5/5.12.3/Locale/Codes.pm
+usr/lib/perl5/5.12.3/Locale/Codes.pod
+usr/lib/perl5/5.12.3/Locale/Codes/API.pod
+usr/lib/perl5/5.12.3/Locale/Codes/Changes.pod
+usr/lib/perl5/5.12.3/Locale/Codes/Constants.pm
+usr/lib/perl5/5.12.3/Locale/Codes/Constants.pod
+usr/lib/perl5/5.12.3/Locale/Codes/Country.pm
+usr/lib/perl5/5.12.3/Locale/Codes/Country.pod
+usr/lib/perl5/5.12.3/Locale/Codes/Country_Codes.pm
+usr/lib/perl5/5.12.3/Locale/Codes/Country_Retired.pm
+usr/lib/perl5/5.12.3/Locale/Codes/Currency.pm
+usr/lib/perl5/5.12.3/Locale/Codes/Currency.pod
+usr/lib/perl5/5.12.3/Locale/Codes/Currency_Codes.pm
+usr/lib/perl5/5.12.3/Locale/Codes/Currency_Retired.pm
+usr/lib/perl5/5.12.3/Locale/Codes/LangExt.pm
+usr/lib/perl5/5.12.3/Locale/Codes/LangExt.pod
+usr/lib/perl5/5.12.3/Locale/Codes/LangExt_Codes.pm
+usr/lib/perl5/5.12.3/Locale/Codes/LangExt_Retired.pm
+usr/lib/perl5/5.12.3/Locale/Codes/LangFam.pm
+usr/lib/perl5/5.12.3/Locale/Codes/LangFam.pod
+usr/lib/perl5/5.12.3/Locale/Codes/LangFam_Codes.pm
+usr/lib/perl5/5.12.3/Locale/Codes/LangFam_Retired.pm
+usr/lib/perl5/5.12.3/Locale/Codes/LangVar.pm
+usr/lib/perl5/5.12.3/Locale/Codes/LangVar.pod
+usr/lib/perl5/5.12.3/Locale/Codes/LangVar_Codes.pm
+usr/lib/perl5/5.12.3/Locale/Codes/LangVar_Retired.pm
+usr/lib/perl5/5.12.3/Locale/Codes/Language.pm
+usr/lib/perl5/5.12.3/Locale/Codes/Language.pod
+usr/lib/perl5/5.12.3/Locale/Codes/Language_Codes.pm
+usr/lib/perl5/5.12.3/Locale/Codes/Language_Retired.pm
+usr/lib/perl5/5.12.3/Locale/Codes/Script.pm
+usr/lib/perl5/5.12.3/Locale/Codes/Script.pod
+usr/lib/perl5/5.12.3/Locale/Codes/Script_Codes.pm
+usr/lib/perl5/5.12.3/Locale/Codes/Script_Retired.pm
+#usr/lib/perl5/5.12.3/i586-linux-thread-multi/auto/Locale
+#usr/lib/perl5/5.12.3/i586-linux-thread-multi/auto/Locale/Codes
+#usr/lib/perl5/5.12.3/i586-linux-thread-multi/auto/Locale/Codes/.packlist
+#usr/share/man/man3/Locale::Codes.3
+#usr/share/man/man3/Locale::Codes::API.3
+#usr/share/man/man3/Locale::Codes::Changes.3
+#usr/share/man/man3/Locale::Codes::Constants.3
+#usr/share/man/man3/Locale::Codes::Country.3
+#usr/share/man/man3/Locale::Codes::Currency.3
+#usr/share/man/man3/Locale::Codes::LangExt.3
+#usr/share/man/man3/Locale::Codes::LangFam.3
+#usr/share/man/man3/Locale::Codes::LangFam_Retired.3
+#usr/share/man/man3/Locale::Codes::LangVar.3
+#usr/share/man/man3/Locale::Codes::Language.3
+#usr/share/man/man3/Locale::Codes::Script.3
diff --git a/config/rootfiles/common/perl-Text-CSV_XS b/config/rootfiles/common/perl-Text-CSV_XS
new file mode 100644 (file)
index 0000000..ca2f642
--- /dev/null
@@ -0,0 +1,8 @@
+#usr/lib/perl5/site_perl/5.12.3/i586-linux-thread-multi/Text
+usr/lib/perl5/site_perl/5.12.3/i586-linux-thread-multi/Text/CSV_XS.pm
+#usr/lib/perl5/site_perl/5.12.3/i586-linux-thread-multi/auto/Text
+#usr/lib/perl5/site_perl/5.12.3/i586-linux-thread-multi/auto/Text/CSV_XS
+#usr/lib/perl5/site_perl/5.12.3/i586-linux-thread-multi/auto/Text/CSV_XS/.packlist
+#usr/lib/perl5/site_perl/5.12.3/i586-linux-thread-multi/auto/Text/CSV_XS/CSV_XS.bs
+usr/lib/perl5/site_perl/5.12.3/i586-linux-thread-multi/auto/Text/CSV_XS/CSV_XS.so
+#usr/share/man/man3/Text::CSV_XS.3
index 663aef5..4e8b750 100644 (file)
@@ -143,6 +143,7 @@ usr/share/doc/licenses/GPLv3
 #usr/share/man/man8
 #usr/share/misc
 #usr/share/terminfo
+#usr/share/xt_geoip
 #usr/share/zoneinfo
 #var
 #var/cache
diff --git a/config/rootfiles/common/xtables-addons b/config/rootfiles/common/xtables-addons
new file mode 100644 (file)
index 0000000..9053c28
--- /dev/null
@@ -0,0 +1,7 @@
+lib/xtables/libxt_geoip.so
+#usr/libexec/xtables-addons
+usr/libexec/xtables-addons/xt_geoip_build
+usr/libexec/xtables-addons/xt_geoip_dl
+#usr/share/man/man1/xt_geoip_build.1
+#usr/share/man/man1/xt_geoip_dl.1
+#usr/share/man/man8/xtables-addons.8
diff --git a/config/xtables-addons/mconfig b/config/xtables-addons/mconfig
new file mode 100644 (file)
index 0000000..92e47f0
--- /dev/null
@@ -0,0 +1,24 @@
+# -*- Makefile -*-
+#
+build_ACCOUNT=n
+build_CHAOS=n
+build_DELUDE=n
+build_DHCPMAC=n
+build_DNETMAP=n
+build_ECHO=n
+build_IPMARK=n
+build_LOGMARK=n
+build_SYSRQ=n
+build_TARPIT=n
+build_condition=n
+build_fuzzy=n
+build_geoip=m
+build_gradm=n
+build_iface=n
+build_ipp2p=n
+build_ipv4options=n
+build_length2=n
+build_lscan=n
+build_pknock=n
+build_psd=n
+build_quota2=n
index badee6b..1215270 100644 (file)
@@ -33,6 +33,7 @@ no warnings 'uninitialized';
 require '/var/ipfire/general-functions.pl';
 require "${General::swroot}/lang.pl";
 require "${General::swroot}/header.pl";
+require "${General::swroot}/geoip-functions.pl";
 require "/usr/lib/firewall/firewall-lib.pl";
 
 unless (-d "${General::swroot}/firewall")                      { system("mkdir ${General::swroot}/firewall"); }
@@ -47,6 +48,7 @@ my %defaultNetworks=();
 my %netsettings=();
 my %customhost=();
 my %customgrp=();
+my %customgeoipgrp=();
 my %customnetworks=();
 my %customservice=();
 my %customservicegrp=();
@@ -73,6 +75,7 @@ my $color;
 my $confignet          = "${General::swroot}/fwhosts/customnetworks";
 my $confighost         = "${General::swroot}/fwhosts/customhosts";
 my $configgrp          = "${General::swroot}/fwhosts/customgroups";
+my $configgeoipgrp     = "${General::swroot}/fwhosts/customgeoipgrp";
 my $configsrv          = "${General::swroot}/fwhosts/customservices";
 my $configsrvgrp       = "${General::swroot}/fwhosts/customservicegrp";
 my $configccdnet       = "${General::swroot}/ovpn/ccd.conf";
@@ -1135,6 +1138,54 @@ END
                }
                print"</select></td>";
        }
+       # geoip locations / groups.
+       my @geoip_locations = &fwlib::get_geoip_locations();
+
+       print "<tr>\n";
+       print "<td valign='top'><input type='radio' name='$grp' id='cust_geoip_$srctgt' value='cust_geoip_$srctgt' $checked{$grp}{'cust_geoip_'.$srctgt}></td>\n";
+       print "<td>$Lang::tr{'geoip'}</td>\n";
+       print "<td align='right'><select name='cust_geoip_$srctgt' style='width:200px;'>\n";
+
+       # Add GeoIP groups to dropdown.
+       if (!-z $configgeoipgrp) {
+               print "<optgroup label='$Lang::tr{'fwhost cust geoipgroup'}'>\n";
+               foreach my $key (sort { ncmp($customgeoipgrp{$a}[0],$customgeoipgrp{$b}[0]) } keys %customgeoipgrp) {
+                       my $selected;
+
+                       # Generate stored value for select detection.
+                       my $stored = join(':', "group",$customgeoipgrp{$key}[0]);
+
+                       # Only show a group once and group with elements.
+                       if($helper ne $customgeoipgrp{$key}[0] && $customgeoipgrp{$key}[2] ne 'none') {
+                               # Mark current entry as selected.
+                               if ($fwdfwsettings{$fwdfwsettings{$grp}} eq $stored) {
+                                       $selected = "selected='selected'";
+                               }
+                                print"<option $selected value='group:$customgeoipgrp{$key}[0]'>$customgeoipgrp{$key}[0]</option>\n";
+                        }
+                        $helper=$customgeoipgrp{$key}[0];
+                }
+               print "</optgroup>\n";
+       }
+
+       # Add locations.
+       print "<optgroup label='$Lang::tr{'fwhost cust geoiplocation'}'>\n";
+       foreach my $location (@geoip_locations) {
+               # Get country name.
+               my $country_name = &GeoIP::get_full_country_name($location);
+
+               # Mark current entry as selected.
+               my $selected;
+               if ($fwdfwsettings{$fwdfwsettings{$grp}} eq $location) {
+                       $selected = "selected='selected'";
+               }
+               print "<option $selected value='$location'>$location - $country_name</option>\n";
+       }
+       print "</optgroup>\n";
+
+       # Close GeoIP dropdown.
+       print "</select></td>\n";
+
        #End left table. start right table (vpn)
        print"</tr></table></td><td valign='top'><table width='95%' border='0' align='right'><tr>";
        # CCD networks
@@ -1472,6 +1523,7 @@ sub newrule
        &General::readhasharray("$confighost", \%customhost);
        &General::readhasharray("$configccdhost", \%ccdhost);
        &General::readhasharray("$configgrp", \%customgrp);
+       &General::readhasharray("$configgeoipgrp", \%customgeoipgrp);
        &General::readhasharray("$configipsec", \%ipsecconf);
        &General::get_aliases(\%aliases);
        my %checked=();
@@ -2600,6 +2652,13 @@ END
                                }else{
                                        print $$hash{$key}[4];
                                }
+                       }elsif ($$hash{$key}[3] eq 'cust_geoip_src') {
+                               my ($split1,$split2) = split(":", $$hash{$key}[4]);
+                               if ($split2) {
+                                       print "$split2\n";
+                               }else{
+                                       print "$Lang::tr{'geoip'}: $$hash{$key}[4]\n";
+                               }
                        }elsif ($$hash{$key}[4] eq 'RED1'){
                                print "$ipfireiface $Lang::tr{'fwdfw red'}";
                        }elsif ($$hash{$key}[4] eq 'ALL'){
@@ -2676,6 +2735,13 @@ END
                                }else{
                                        print $$hash{$key}[6];
                                }
+                       }elsif ($$hash{$key}[5] eq 'cust_geoip_tgt') {
+                               my ($split1,$split2) = split(":", $$hash{$key}[6]);
+                               if ($split2) {
+                                       print "$split2\n";
+                               }else{
+                                       print "$Lang::tr{'geoip'}: $$hash{$key}[6]\n";
+                               }
                        }elsif ($$hash{$key}[5] eq 'tgt_addr'){
                                my ($split1,$split2) = split("/",$$hash{$key}[6]);
                                if ($split2 eq '32'){
@@ -2693,7 +2759,6 @@ END
                        #RULE ACTIVE
                        if($$hash{$key}[2] eq 'ON'){
                                $gif="/images/on.gif"
-                               
                        }else{
                                $gif="/images/off.gif"
                        }
index c3642f0..395dca8 100644 (file)
@@ -27,6 +27,8 @@ use Sort::Naturally;
 use CGI::Carp 'fatalsToBrowser';
 no warnings 'uninitialized';
 require '/var/ipfire/general-functions.pl';
+require "/var/ipfire/geoip-functions.pl";
+require "/usr/lib/firewall/firewall-lib.pl";
 require "${General::swroot}/lang.pl";
 require "${General::swroot}/header.pl";
 
@@ -36,6 +38,7 @@ my %customhost=();
 my %customgrp=();
 my %customservice=();
 my %customservicegrp=();
+my %customgeoipgrp=();
 my %ccdnet=();
 my %ccdhost=();
 my %ipsecconf=();
@@ -62,6 +65,7 @@ my $configccdhost     = "${General::swroot}/ovpn/ovpnconfig";
 my $configipsec                = "${General::swroot}/vpn/config";
 my $configsrv          = "${General::swroot}/fwhosts/customservices";
 my $configsrvgrp       = "${General::swroot}/fwhosts/customservicegrp";
+my $configgeoipgrp     = "${General::swroot}/fwhosts/customgeoipgrp";
 my $fwconfigfwd                = "${General::swroot}/firewall/config";
 my $fwconfiginp                = "${General::swroot}/firewall/input";
 my $fwconfigout                = "${General::swroot}/firewall/outgoing";
@@ -73,6 +77,7 @@ unless (-e $confighost)   { system("touch $confighost"); }
 unless (-e $configgrp)    { system("touch $configgrp"); }
 unless (-e $configsrv)    { system("touch $configsrv"); }
 unless (-e $configsrvgrp) { system("touch $configsrvgrp"); }
+unless (-e $configgeoipgrp) { system("touch $configgeoipgrp"); }
 
 &General::readhash("${General::swroot}/main/settings", \%mainsettings);
 &General::readhash("/srv/web/ipfire/html/themes/".$mainsettings{'THEME'}."/include/colors.txt", \%color);
@@ -671,6 +676,84 @@ if ($fwhostsettings{'ACTION'} eq 'savegrp')
                &addgrp;
                &viewtablegrp;
 }
+if ($fwhostsettings{'ACTION'} eq 'savegeoipgrp')
+{
+       my $grp=$fwhostsettings{'grp_name'};
+       my $rem=$fwhostsettings{'remark'};
+       my $count;
+       my $type;
+       my @target;
+       my @newgrp;
+       &General::readhasharray("$configgeoipgrp", \%customgeoipgrp);
+
+       # Check for existing group name.
+       if (!&checkgroup($grp) && $fwhostsettings{'update'} ne 'on'){
+               $errormessage = $Lang::tr{'fwhost err grpexist'};
+       }
+
+       # Check remark.
+       if ($rem ne '' && !&validremark($rem) && $fwhostsettings{'update'} ne 'on'){
+               $errormessage = $Lang::tr{'fwhost err remark'};
+       }
+
+       if ($fwhostsettings{'update'} eq 'on'){
+               @target=$fwhostsettings{'COUNTRY_CODE'};
+               $type='GeoIP Group';
+
+               #check if host/net exists in grp
+               my $test="$grp,$fwhostsettings{'oldremark'},@target";
+               foreach my $key (keys %customgeoipgrp) {
+                       my $test1="$customgeoipgrp{$key}[0],$customgeoipgrp{$key}[1],$customgeoipgrp{$key}[2]";
+                       if ($test1 eq $test){
+                               $errormessage=$Lang::tr{'fwhost err isingrp'};
+                               $fwhostsettings{'update'} = 'on';
+                       }
+               }
+       }
+
+       if (!$errormessage){
+               #on first save, we have an empty @target, so fill it with nothing
+               my $targetvalues=@target;
+               if ($targetvalues == '0'){
+                       @target="none";
+               }
+               #on update, we have to delete the dummy entry
+               foreach my $key (keys %customgeoipgrp){
+                       if ($customgeoipgrp{$key}[0] eq $grp && $customgeoipgrp{$key}[2] eq "none"){
+                               delete $customgeoipgrp{$key};
+                               last;
+                       }
+               }
+               &General::writehasharray("$configgeoipgrp", \%customgeoipgrp);
+               &General::readhasharray("$configgeoipgrp", \%customgeoipgrp);
+               #create array with new lines
+               foreach my $line (@target){
+                       push (@newgrp,"$grp,$rem,$line");
+               }
+               #append new entries
+               my $key = &General::findhasharraykey (\%customgeoipgrp);
+               foreach my $line (@newgrp){
+                       foreach my $i (0 .. 3) { $customgeoipgrp{$key}[$i] = "";}
+                       my ($a,$b,$c,$d) = split (",",$line);
+                       $customgeoipgrp{$key}[0] = $a;
+                       $customgeoipgrp{$key}[1] = $b;
+                       $customgeoipgrp{$key}[2] = $c;
+                       $customgeoipgrp{$key}[3] = $type;
+               }
+               &General::writehasharray("$configgeoipgrp", \%customgeoipgrp);
+               #update counter in Host/Net
+               $fwhostsettings{'update'}='on';
+       }
+               #check if ruleupdate is needed
+               my $geoipgrpcount=0;
+               $geoipgrpcount=&getgeoipcount($grp);
+               if($geoipgrpcount > 0 )
+               {
+                       &General::firewall_config_changed();
+               }
+               &addgeoipgrp;
+               &viewtablegeoipgrp;
+}
 if ($fwhostsettings{'ACTION'} eq 'saveservice')
 {
        my $ICMP;
@@ -798,6 +881,12 @@ if ($fwhostsettings{'ACTION'} eq 'editgrp')
        &addgrp;
        &viewtablegrp;
 }
+if ($fwhostsettings{'ACTION'} eq 'editgeoipgrp')
+{
+       $fwhostsettings{'update'}='on';
+       &addgeoipgrp;
+       &viewtablegeoipgrp;
+}
 if ($fwhostsettings{'ACTION'} eq 'editservice')
 {
        $fwhostsettings{'updatesrv'}='on';
@@ -830,6 +919,12 @@ if ($fwhostsettings{'ACTION'} eq 'resetgrp')
        $fwhostsettings{'remark'}       ="";
        &showmenu;
 }
+if ($fwhostsettings{'ACTION'} eq 'resetgeoipgrp')
+{
+       $fwhostsettings{'grp_name'} ="";
+       $fwhostsettings{'remark'}       ="";
+       &showmenu;
+}
 # delete
 if ($fwhostsettings{'ACTION'} eq 'delnet')
 {
@@ -887,6 +982,37 @@ if ($fwhostsettings{'ACTION'} eq 'deletegrphost')
        &addgrp;
        &viewtablegrp;
 }
+if ($fwhostsettings{'ACTION'} eq 'deletegeoipgrpentry')
+{
+        my $grpremark;
+        my $grpname;
+        &General::readhasharray("$configgeoipgrp", \%customgeoipgrp);
+        foreach my $key (keys %customgeoipgrp){
+                if($customgeoipgrp{$key}[0].",".$customgeoipgrp{$key}[1].",".$customgeoipgrp{$key}[2].",".$customgeoipgrp{$key}[3] eq $fwhostsettings{'delentry'}){
+                        $grpname=$customgeoipgrp{$key}[0];
+                        $grpremark=$customgeoipgrp{$key}[1];
+                        #check if we delete the last entry, then generate dummy
+                        if ($fwhostsettings{'last'} eq 'on'){
+                                $customgeoipgrp{$key}[1] = '';
+                                $customgeoipgrp{$key}[2] = 'none';
+                                $customgeoipgrp{$key}[3] = '';
+                                $fwhostsettings{'last'}='';
+                                last;
+                        }else{
+                                delete $customgeoipgrp{$key};
+                        }
+                }
+        }
+        &General::writehasharray("$configgeoipgrp", \%customgeoipgrp);
+        &General::firewall_config_changed();
+        if ($fwhostsettings{'update'} eq 'on'){
+                $fwhostsettings{'remark'}= $grpremark;
+                $fwhostsettings{'grp_name'}=$grpname;
+        }
+        &addgeoipgrp;
+        &viewtablegeoipgrp;
+}
+
 if ($fwhostsettings{'ACTION'} eq 'delgrp')
 {
        &General::readhasharray("$configgrp", \%customgrp);
@@ -903,6 +1029,22 @@ if ($fwhostsettings{'ACTION'} eq 'delgrp')
        &addgrp;
        &viewtablegrp;
 }
+if ($fwhostsettings{'ACTION'} eq 'delgeoipgrp')
+{
+       &General::readhasharray("$configgeoipgrp", \%customgeoipgrp);
+       &decrease($fwhostsettings{'grp_name'});
+       foreach my $key (sort keys %customgeoipgrp)
+       {
+               if($customgeoipgrp{$key}[0] eq $fwhostsettings{'grp_name'})
+               {
+                       delete $customgeoipgrp{$key};
+               }
+       }
+       &General::writehasharray("$configgeoipgrp", \%customgeoipgrp);
+       $fwhostsettings{'grp_name'}='';
+       &addgeoipgrp;
+       &viewtablegeoipgrp;
+}
 if ($fwhostsettings{'ACTION'} eq 'delservice')
 {
        &General::readhasharray("$configsrv", \%customservice);
@@ -977,6 +1119,11 @@ if ($fwhostsettings{'ACTION'} eq $Lang::tr{'fwhost newgrp'})
        &addgrp;
        &viewtablegrp;
 }
+if ($fwhostsettings{'ACTION'} eq $Lang::tr{'fwhost newgeoipgrp'})
+{
+       &addgeoipgrp;
+       &viewtablegeoipgrp;
+}
 if ($fwhostsettings{'ACTION'} eq $Lang::tr{'fwhost newservice'})
 {
        &addservice;
@@ -1011,6 +1158,31 @@ if ($fwhostsettings{'ACTION'} eq 'changegrpremark')
        &addgrp;
        &viewtablegrp;
 }
+if ($fwhostsettings{'ACTION'} eq 'changegeoipgrpremark')
+{
+       &General::readhasharray("$configgeoipgrp", \%customgeoipgrp);
+       if ($fwhostsettings{'oldrem'} ne $fwhostsettings{'newrem'} && (&validremark($fwhostsettings{'newrem'}) || $fwhostsettings{'newrem'} eq '')){
+               foreach my $key (sort keys %customgeoipgrp)
+                       {
+                               if($customgeoipgrp{$key}[0] eq $fwhostsettings{'grp'} && $customgeoipgrp{$key}[1] eq $fwhostsettings{'oldrem'})
+                               {
+                                       $customgeoipgrp{$key}[1]='';
+                                       $customgeoipgrp{$key}[1]=$fwhostsettings{'newrem'};
+                               }
+                       }
+                       &General::writehasharray("$configgeoipgrp", \%customgeoipgrp);
+                       $fwhostsettings{'update'}='on';
+                       $fwhostsettings{'remark'}=$fwhostsettings{'newrem'};
+       }else{
+               $errormessage=$Lang::tr{'fwhost err remark'};
+               $fwhostsettings{'remark'}=$fwhostsettings{'oldrem'};
+               $fwhostsettings{'grp_name'}=$fwhostsettings{'grp'};
+               $fwhostsettings{'update'} = 'on';
+       }
+       $fwhostsettings{'grp_name'}=$fwhostsettings{'grp'};
+       &addgeoipgrp;
+       &viewtablegeoipgrp;
+}
 if ($fwhostsettings{'ACTION'} eq 'changesrvgrpremark')
 {
        &General::readhasharray("$configsrvgrp", \%customservicegrp );
@@ -1085,6 +1257,29 @@ if ($fwhostsettings{'ACTION'} eq 'changegrpname')
        &addgrp;
        &viewtablegrp;
 }
+if ($fwhostsettings{'ACTION'} eq 'changegeoipgrpname')
+{
+       &General::readhasharray("$configgeoipgrp", \%customgeoipgrp );
+       if ($fwhostsettings{'oldgrpname'} ne $fwhostsettings{'grp'}){
+               #Check new groupname
+               if (!&validhostname($fwhostsettings{'grp'})){
+                       $errormessage.=$Lang::tr{'fwhost err name'}."<br>";
+               }
+               if (!$errormessage){
+                       # Rename group.
+                       foreach my $key (keys %customgeoipgrp) {
+                               if($customgeoipgrp{$key}[0] eq $fwhostsettings{'oldgrpname'}){
+                                       $customgeoipgrp{$key}[0]=$fwhostsettings{'grp'};
+                               }
+                       }
+                       &General::writehasharray("$configgeoipgrp", \%customgeoipgrp );
+                       #change name in FW Rules
+                       &changenameinfw($fwhostsettings{'oldgrpname'},$fwhostsettings{'grp'},6);
+               }
+       }
+       &addgeoipgrp;
+       &viewtablegeoipgrp;
+}
 ###  VIEW  ###
 if($fwhostsettings{'ACTION'} eq '')
 {
@@ -1096,7 +1291,7 @@ sub showmenu {
        print "$Lang::tr{'fwhost welcome'}";
        print<<END;
        <br><br><table border='0' width='100%'>
-       <tr><td><form method='post'><input type='submit' name='ACTION' value='$Lang::tr{'fwhost newnet'}' ><input type='submit' name='ACTION' value='$Lang::tr{'fwhost newhost'}' ><input type='submit' name='ACTION' value='$Lang::tr{'fwhost newgrp'}' ></form></td>
+       <tr><td><form method='post'><input type='submit' name='ACTION' value='$Lang::tr{'fwhost newnet'}' ><input type='submit' name='ACTION' value='$Lang::tr{'fwhost newhost'}' ><input type='submit' name='ACTION' value='$Lang::tr{'fwhost newgrp'}' ><input type='submit' name='ACTION' value='$Lang::tr{'fwhost newgeoipgrp'}' ></form></td>
        <td align='right'><form method='post'><input type='submit' name='ACTION' value='$Lang::tr{'fwhost newservice'}' ><input type='submit' name='ACTION' value='$Lang::tr{'fwhost newservicegrp'}' ></form></td></tr>
        <tr><td colspan='6'></td></tr></table>
 END
@@ -1381,6 +1576,113 @@ END
                print"<tr><td style='text-align:right;'><input type='submit' value='$Lang::tr{'add'}' style='min-width:100px;' /><input type='hidden' name='oldremark' value='$fwhostsettings{'oldremark'}'><input type='hidden' name='update' value=\"$fwhostsettings{'update'}\"><input type='hidden' name='ACTION' value='savegrp' ></form><form method='post' style='display:inline'><input type='submit' value='$Lang::tr{'fwhost back'}' style='min-width:100px;'><input type='hidden' name='ACTION' value='resetgrp'></form></td></table>";
        &Header::closebox();
 }
+sub addgeoipgrp
+{
+       &hint;
+       &error;
+       &showmenu;
+       &Header::openbox('100%', 'left', $Lang::tr{'fwhost addgeoipgrp'});
+
+       my %checked=();
+       my $show='';
+       $checked{'check1'}{'off'} = '';
+       $checked{'check1'}{'on'} = '';
+       $checked{'grp2'}{$fwhostsettings{'grp2'}} = 'CHECKED';
+       $fwhostsettings{'oldremark'}=$fwhostsettings{'remark'};
+       $fwhostsettings{'oldgrpname'}=$fwhostsettings{'grp_name'};
+       my $grp=$fwhostsettings{'grp_name'};
+       my $rem=$fwhostsettings{'remark'};
+               if ($fwhostsettings{'update'} eq ''){
+                       print<<END;
+               <table width='100%' border='0'>
+                       <tr>
+                               <td style='width:15%;'>$Lang::tr{'fwhost addgrpname'}</td>
+                               <td><form method='post'><input type='TEXT' name='grp_name' value='$fwhostsettings{'grp_name'}' size='30'></td>
+                       </tr>
+                       <tr>
+                               <td>$Lang::tr{'remark'}:</td>
+                               <td ><input type='TEXT' name='remark' value='$fwhostsettings{'remark'}' style='width: 99%;'></td>
+                       </tr>
+                       <tr>
+                               <td colspan='2'><br></td>
+                       </tr>
+               </table>
+END
+               } else {
+                       print<<END;
+                       <table width='100%' border='0'>
+                               <form method='post'><tr>
+                                       <td style='width:15%;'>$Lang::tr{'fwhost addgrpname'}</td>
+                                       <td style='width:30%;'><input type='TEXT' name='grp'  value='$fwhostsettings{'grp_name'}' size='30'></td>
+                                       <td>
+                                               <input type='submit' value='$Lang::tr{'fwhost change'}'>
+                                               <input type='hidden' name='oldgrpname' value='$fwhostsettings{'oldgrpname'}'>
+                                               <input type='hidden' name='ACTION' value='changegeoipgrpname'>
+                                       </td>
+                                       <td></td>
+                               </tr></form>
+                               <tr><form method='post' style='display:inline'>
+                                       <td>$Lang::tr{'remark'}:</td>
+                                       <td colspan='2' style='width:98%;'>
+                                               <input type='TEXT' name='newrem' value='$fwhostsettings{'remark'}' style='width:98%;'>
+                                       </td>
+                                       <td align='right'>
+                                               <input type='submit' value='$Lang::tr{'fwhost change'}'>
+                                               <input type='hidden' name='grp' value='$fwhostsettings{'grp_name'}'>
+                                               <input type='hidden' name='oldrem' value='$fwhostsettings{'oldremark'}'>
+                                               <input type='hidden' name='ACTION' value='changegeoipgrpremark'>
+                                       </td>
+                               </tr></form>
+                       </table>
+                       <br><br>
+END
+               }
+               if ($fwhostsettings{'update'} eq 'on') {
+                       my @geoip_locations = &fwlib::get_geoip_locations();
+
+                       print<<END;
+                       <form method='post'>
+                       <input type='hidden' name='remark' value='$rem'>
+                       <input type='hidden' name='grp_name' value='$grp'>
+
+                       <table width='100%' border='0'>
+                               <tr>
+                                       <td style='text-align:left;'>
+                                               <select name='COUNTRY_CODE' style='width:16em;'>";
+END
+                               foreach my $location (@geoip_locations) {
+                                       # Get full country name.
+                                       my $fullname = &GeoIP::get_full_country_name($location);
+
+                                       print"<option value='$location'>$location - $fullname</option>\n";
+                               }
+       print <<END;
+                                               </select>
+                                       </td>
+                               </tr>
+                       </table>
+                       <br><br>
+END
+               }
+       print <<END;
+               <table width='100%'>
+                       <tr><td style='text-align:right;'>
+                               <input type='submit' value='$Lang::tr{'add'}' style='min-width:100px;' />
+                               <input type='hidden' name='oldremark' value='$fwhostsettings{'oldremark'}'>
+                               <input type='hidden' name='update' value=\"$fwhostsettings{'update'}\">
+                               <input type='hidden' name='ACTION' value='savegeoipgrp' >
+                       </form>
+
+                       <form method='post' style='display:inline'>
+
+                       <input type='submit' value='$Lang::tr{'fwhost back'}' style='min-width:100px;'>
+                       <input type='hidden' name='ACTION' value='resetgeoipgrp'>
+
+                       </form>
+                       </td></tr></table>
+END
+       &Header::closebox();
+}
 sub addservice
 {
        &error;
@@ -1838,6 +2140,195 @@ sub viewtablegrp
        &Header::closebox();
 }
 
+}
+sub viewtablegeoipgrp
+{
+       # If our filesize is "zero" there is nothing to read-in.
+       if (-z "$configgeoipgrp") {
+               return;
+       }
+
+       &Header::openbox('100%', 'left', $Lang::tr{'fwhost cust geoipgrp'});
+       &General::readhasharray("$configgeoipgrp", \%customgeoipgrp);
+       &General::readhasharray("$fwconfigfwd", \%fwfwd);
+       &General::readhasharray("$fwconfiginp", \%fwinp);
+       &General::readhasharray("$fwconfigout", \%fwout);
+       my @grp=();
+       my $helper='';
+       my $count=1;
+       my $country_code;
+       my $grpname;
+       my $remark;
+       my $number;
+       my $delflag;
+       my @counter;
+       my %hash;
+
+       # If there are no groups we are finished here.
+       if (!keys %customgeoipgrp) {
+               print "<center><b>$Lang::tr{'fwhost err emptytable'}</b>";
+               return;
+       }
+
+       # Put all groups in a hash.
+       foreach my $key (sort { ncmp($customgeoipgrp{$a}[0],$customgeoipgrp{$b}[0]) }
+                        sort { ncmp($customgeoipgrp{$a}[2],$customgeoipgrp{$b}[2]) } keys %customgeoipgrp) {
+                               push (@counter,$customgeoipgrp{$key}[0]);
+       }
+
+       # Increase current used key.
+       foreach my $key1 (@counter) {
+               $hash{$key1}++ ;
+       }
+
+       # Sort hash.
+       foreach my $key (sort { ncmp($customgeoipgrp{$a}[0],$customgeoipgrp{$b}[0]) }
+                        sort { ncmp($customgeoipgrp{$a}[2],$customgeoipgrp{$b}[2]) } keys %customgeoipgrp) {
+               $count++;
+               if ($helper ne $customgeoipgrp{$key}[0]) {
+                       $delflag='0';
+
+                       foreach my $key1 (sort { ncmp($customgeoipgrp{$a}[0],$customgeoipgrp{$b}[0]) }
+                                         sort { ncmp($customgeoipgrp{$a}[2],$customgeoipgrp{$b}[2]) } keys %customgeoipgrp) {
+
+                               if ($customgeoipgrp{$key}[0] eq $customgeoipgrp{$key1}[0])
+                               {
+                                       $delflag++;
+                               }
+                               if($delflag > 1){
+                                       last;
+                               }
+                       }
+
+                       $number=1;
+
+                       # Groupname.
+                       $grpname=$customgeoipgrp{$key}[0];
+
+                       # Group remark.
+                       $remark="$customgeoipgrp{$key}[1]";
+
+                       # Country code.
+                       $country_code="$customgeoipgrp{$key}[2]";
+
+                       if ($count gt 1){
+                               print"</table>";
+                               $count=1;
+                       }
+
+                       # Display groups header.
+                       print "<br><b><u>$grpname</u></b>&nbsp; &nbsp;\n";
+                       print "<b>$Lang::tr{'remark'}:</b>&nbsp $remark &nbsp\n" if ($remark ne '');
+
+                       # Get group count.
+                       my $geoipgrpcount=&getgeoipcount($grpname);
+                       print "<b>$Lang::tr{'used'}:</b> $geoipgrpcount x";
+
+                       # Only display delete icon, if the group is not used by a firewall rule.
+                       if($geoipgrpcount == '0') {
+                               print"<form method='post' style='display:inline'>\n";
+                               print"<input type='image' src='/images/delete.gif' alt='$Lang::tr{'delete'}' title='$Lang::tr{'delete'}' align='right' />\n";
+                               print"<input type='hidden' name='grp_name' value='$grpname' >\n";
+                               print"<input type='hidden' name='ACTION' value='delgeoipgrp'>\n";
+                               print"</form>";
+                       }
+
+                       # Icon for group editing.
+print <<END;
+                       <form method='post' style='display:inline'>
+                               <input type='image' src='/images/edit.gif' alt='$Lang::tr{'edit'}' title='$Lang::tr{'edit'}' align='right'/>
+                               <input type='hidden' name='grp_name' value='$grpname' >
+                               <input type='hidden' name='remark' value='$remark' >
+                               <input type='hidden' name='ACTION' value='editgeoipgrp'>
+                       </form>
+
+                       <table width='100%' cellspacing='0' class='tbl'>
+END
+                       # Display headlines if the group contains any entries.
+                       if ($country_code ne "none") {
+print <<END;
+                               <tr>
+                                       <td width='10%' align='center'>
+                                               <b>$Lang::tr{'flag'}</b>
+                                       </td>
+
+                                       <td width='10%'align='center'>
+                                               <b>$Lang::tr{'countrycode'}</b>
+                                       </td>
+
+                                       <td width='70%'align='left'>
+                                               <b>$Lang::tr{'country'}</b>
+                                       </td>
+
+                                       <td width='10%' align='right'></td>
+                               </tr>
+END
+                       }
+               }
+
+               # Check if our group contains any entries.
+               if ($country_code eq "none") {
+                       print "<tr><td>$Lang::tr{'fwhost err emptytable'}</td></tr>\n";
+               } else {
+                       # Check if we are currently editing a group and assign column backgound colors.
+                       my $col='';
+                       if ( ($fwhostsettings{'ACTION'} eq 'editgeoipgrp' || $fwhostsettings{'update'} ne '')
+                               && $fwhostsettings{'grp_name'} eq $customgeoipgrp{$key}[0]) {
+                               $col="bgcolor='${Header::colouryellow}'";
+                       } elsif ($count %2 == 0){
+                               $col="bgcolor='$color{'color20'}'";
+                       } else {
+                               $col="bgcolor='$color{'color22'}'";
+                       }
+
+                       # Get country flag.
+                       my $icon = &GeoIP::get_flag_icon($customgeoipgrp{$key}[2]);
+
+                       # Print column with flag icon.
+                       my $col_content;
+                       if ($icon) {
+                               $col_content = "<img src='$icon' alt='$customgeoipgrp{$key}[2]' title='$customgeoipgrp{$key}[2]'>";
+                       } else {
+                               $col_content = "<b>N/A</b>";
+                       }
+
+                       print "<td align='center' $col>$col_content</td>\n";
+
+                       # Print column with country code.
+                       print "<td align='center' $col>$customgeoipgrp{$key}[2]</td>\n";
+
+                       # Print column with full country name.
+                       my $country_name = &GeoIP::get_full_country_name($customgeoipgrp{$key}[2]);
+                       print "<td align='left' $col>$country_name</td>\n";
+
+                       # Generate from for removing entries from a group.
+                       print "<td align='right' width='1%' $col><form method='post'>\n";
+
+                       if ($delflag > 0){
+                               print"<input type='image' src='/images/delete.gif' align='middle' alt='$Lang::tr{'delete'}' title='$Lang::tr{'delete'}'/>\n";
+
+                               # Check if this group only has a single entry.
+                               foreach my $key2 (keys %hash) {
+                                       if ($hash{$key2}<2 && $key2 eq $customgeoipgrp{$key}[0]){
+                                               print "<input type='hidden' name='last' value='on'>"  ;
+                                       }
+                               }
+                       }
+
+                       print "<input type='hidden' name='ACTION' value='deletegeoipgrpentry'>\n";
+                       print "<input type='hidden' name='update' value='$fwhostsettings{'update'}'>\n";
+                       print "<input type='hidden' name='delentry' value='$grpname,$remark,$customgeoipgrp{$key}[2],$customgeoipgrp{$key}[3]'>\n";
+                       print "</form>\n";
+                       print "</td>\n";
+                       print "</tr>\n";
+               }
+
+               $helper=$customgeoipgrp{$key}[0];
+               $number++;
+       }
+
+       print"</table>\n";
+       &Header::closebox();
 }
 sub viewtableservice
 {
@@ -2196,6 +2687,44 @@ sub gethostcount
        }
        return $srvcounter;
 }
+sub getgeoipcount
+{
+       my $groupname=shift;
+       my $counter=0;
+
+       # GeoIP groups are stored as "group:groupname" in the
+       # firewall settings files.
+       my $searchstring = join(':', "group",$groupname);
+
+       # Count services used in firewall - forward
+       foreach my $key1 (keys %fwfwd) {
+               if($fwfwd{$key1}[4] eq $searchstring){
+                       $counter++;
+               }
+               if($fwfwd{$key1}[6] eq $searchstring){
+                       $counter++;
+               }
+       }
+       #Count services used in firewall - input
+       foreach my $key2 (keys %fwinp) {
+               if($fwinp{$key2}[4] eq $searchstring){
+                       $counter++;
+               }
+               if($fwinp{$key2}[6] eq $searchstring){
+                       $counter++;
+               }
+       }
+       #Count services used in firewall - outgoing
+       foreach my $key3 (keys %fwout) {
+               if($fwout{$key3}[4] eq $searchstring){
+                       $counter++;
+               }
+               if($fwout{$key3}[6] eq $searchstring){
+                       $counter++;
+               }
+       }
+       return $counter;
+}
 sub getnetcount
 {
        my $searchstring=shift;
diff --git a/html/cgi-bin/geoip-block.cgi b/html/cgi-bin/geoip-block.cgi
new file mode 100644 (file)
index 0000000..ccbfa92
--- /dev/null
@@ -0,0 +1,263 @@
+#!/usr/bin/perl
+###############################################################################
+#                                                                             #
+# IPFire.org - A linux based firewall                                         #
+# Copyright (C) 2014 IPFire Developemnt Team <info@ipfire.org>                #
+#                                                                             #
+# This program is free software: you can redistribute it and/or modify        #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation, either version 3 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# This program is distributed in the hope that it will be useful,             #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+# GNU General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+###############################################################################
+
+use strict;
+# enable only the following on debugging purpose
+#use warnings;
+#use CGI::Carp 'fatalsToBrowser';
+
+require '/var/ipfire/general-functions.pl';
+require "${General::swroot}/geoip-functions.pl";
+require "${General::swroot}/lang.pl";
+require "${General::swroot}/header.pl";
+require "/usr/lib/firewall/firewall-lib.pl";
+
+my $notice;
+my $settingsfile = "${General::swroot}/firewall/geoipblock";
+
+my %color = ();
+my %mainsettings = ();
+my %settings = ();
+my %cgiparams = ();
+
+# Read configuration file.
+&General::readhash("$settingsfile", \%settings);
+
+&General::readhash("${General::swroot}/main/settings", \%mainsettings);
+&General::readhash("/srv/web/ipfire/html/themes/".$mainsettings{'THEME'}."/include/colors.txt", \%color);
+
+&Header::showhttpheaders();
+
+#Get GUI values
+&Header::getcgihash(\%cgiparams);
+
+# Call subfunction to get all available locations.
+my @locations = &fwlib::get_geoip_locations();
+
+if ($cgiparams{'ACTION'} eq $Lang::tr{'save'}) {
+       # Check if we want to disable geoipblock.
+       if (exists $cgiparams{'GEOIPBLOCK_ENABLED'}) {
+               $settings{'GEOIPBLOCK_ENABLED'} = "on";
+       } else {
+               $settings{'GEOIPBLOCK_ENABLED'} = "off";
+       }
+
+       # Loop through our locations array to prevent from
+       # non existing countries or code.
+       foreach my $cn (@locations) {
+               # Check if blocking for this country should be enabled/disabled.
+               if (exists $cgiparams{$cn}) {
+                       $settings{$cn} = "on";
+               } else {
+                       $settings{$cn} = "off";
+               }
+       }
+
+       &General::writehash("$settingsfile", \%settings);
+
+       # Mark the firewall config as changed.
+       &General::firewall_config_changed();
+
+       # Assign reload notice. We directly can use
+       # the notice from p2p block.
+       $notice = $Lang::tr{'p2p block save notice'};
+}
+
+&Header::openpage($Lang::tr{'geoipblock configuration'}, 1, '');
+
+# Print notice that a firewall reload is required.
+if ($notice) {
+       &Header::openbox('100%', 'left', $Lang::tr{'notice'});
+       print "<font class='base'>$notice</font>";
+       &Header::closebox();
+}
+
+# Checkbox pre-selection.
+my $checked;
+if ($settings{'GEOIPBLOCK_ENABLED'} eq "on") {
+       $checked = "checked='checked'";
+}
+
+# Print box to enable/disable geoipblock.
+print"<form method='POST' action='$ENV{'SCRIPT_NAME'}'>\n";
+
+&Header::openbox('100%', 'center', $Lang::tr{'geoipblock'});
+print <<END;
+       <table width='95%'>
+               <tr>
+                       <td width='25%' class='base'>$Lang::tr{'geoipblock enable feature'}
+                       <td><input type='checkbox' name='GEOIPBLOCK_ENABLED' $checked></td>
+               </tr>
+               <tr>
+                       <td colspan='2'><br></td>
+               </tr>
+       </table>
+
+       <hr>
+
+       <table width='95%'>
+               <tr>
+                       <td align='center'><input type='submit' name='ACTION' value='$Lang::tr{'save'}'></td>
+               </tr>
+       </table>
+END
+
+&Header::closebox();
+
+&Header::openbox('100%', 'center', $Lang::tr{'geoipblock block countries'});
+### JAVA SCRIPT ###
+print <<END;
+<script>
+       // Function to allow checking all checkboxes at once.
+       function check_all() {
+               \$("#countries").find(":checkbox").prop("checked", true);
+       }
+
+       function uncheck_all() {
+               \$("#countries").find(":checkbox").prop("checked", false);
+       }
+</script>
+
+<table width='95%' class='tbl' id="countries">
+       <tr>
+               <td width='5%' align='center' bgcolor='$color{'color20'}'></td>
+               <td width='5%' align='center' bgcolor='$color{'color20'}'>
+                       <b>$Lang::tr{'flag'}</b>
+               </td>
+               <td width='5%' align='center' bgcolor='$color{'color20'}'>
+                       <b>$Lang::tr{'countrycode'}</b>
+               </td>
+               <td with='35%' align='left' bgcolor='$color{'color20'}'>
+                       <b>$Lang::tr{'country'}</b>
+               </td>
+
+               <td width='5%' bgcolor='$color{'color20'}'>&nbsp;</td>
+
+               <td width='5%' align='center' bgcolor='$color{'color20'}'></td>
+               <td width='5%' align='center' bgcolor='$color{'color20'}'>
+                       <b>$Lang::tr{'flag'}</b>
+               </td>
+               <td width='5%' align='center' bgcolor='$color{'color20'}'>
+                       <b>$Lang::tr{'countrycode'}</b>
+               </td>
+               <td with='35%' align='left' bgcolor='$color{'color20'}'>
+                       <b>$Lang::tr{'country'}</b>
+               </td>
+       </tr>
+END
+
+my $lines;
+my $lines2;
+my $col;
+foreach my $location (@locations) {
+       # Country code in upper case. (DE)
+       my $ccode_uc = $location;
+
+       # County code in lower case. (de)
+       my $ccode_lc = lc($location);
+
+       # Full name of the country based on the country code.
+       my $cname = &GeoIP::get_full_country_name($ccode_lc);
+
+       # Get flag icon for of the country.
+       my $flag_icon = &GeoIP::get_flag_icon($ccode_uc);
+
+       my $flag;
+       # Check if a flag for the country is available.
+       if ($flag_icon) {
+               $flag="<img src='$flag_icon' alt='$ccode_uc' title='$ccode_uc'>";
+       } else {
+               $flag="<b>N/A</b>";
+       }
+
+       # Checkbox pre-selection.
+       my $checked;
+       if ($settings{$ccode_uc} eq "on") {
+               $checked = "checked='checked'";
+       }
+
+       # Colour lines.
+       if ($lines % 2) {
+               $col="bgcolor='$color{'color20'}'";
+       } else {
+               $col="bgcolor='$color{'color22'}'";
+       }
+
+       # Grouping elements.
+       my $line_start;
+       my $line_end;
+       if ($lines2 % 2) {
+               # Increase lines (background color by once.
+               $lines++;
+
+               # Add empty column in front.
+               $line_start="<td $col>&nbsp;</td>";
+
+               # When the line number can be diveded by "2",
+               # we are going to close the line.
+               $line_end="</tr>";
+       } else {
+               # When the line number is  not divideable by "2",
+               # we are starting a new line.
+               $line_start="<tr>";
+               $line_end;
+       }
+
+       print "$line_start<td align='center' $col><input type='checkbox' name='$ccode_uc' $checked></td>\n";
+       print "<td align='center' $col>$flag</td>\n";
+       print "<td align='center' $col>$ccode_uc</td>\n";
+       print "<td align='left' $col>$cname</td>$line_end\n";
+                       
+$lines2++;
+}
+
+print <<END;
+</table>
+
+<table width='95%'>
+       <tr>
+               <td align='right'>
+                       <a href="javascript:check_all()">$Lang::tr{'check all'}</a> /
+                       <a href="javascript:uncheck_all()">$Lang::tr{'uncheck all'}</a>
+               </td>
+       </tr>
+       <tr>
+               <td align='center'><input type='submit' name='ACTION' value='$Lang::tr{'save'}'></td>
+       </tr>
+</table>
+
+<hr>
+
+<table width='70%'>
+       <tr>
+               <td width='5%'><img src='/images/on.gif'></td>
+               <td>$Lang::tr{'geoipblock country is blocked'}</td>
+               <td width='5%'><img src='/images/off.gif'></td>
+               <td>$Lang::tr{'geoipblock country is allowed'}</td>
+       </tr>
+</table>
+END
+
+&Header::closebox();
+print"</form>\n";
+
+&Header::closebigbox();
+&Header::closepage();
index 1986409..fa014a9 100644 (file)
 'bit' => 'bit',
 'bitrate' => 'Bitrate',
 'bleeding rules' => 'Bleeding Edge Snort Rules',
+'block' => 'Block',
 'blue' => 'BLUE',
 'blue access' => 'Blue Access',
 'blue access use hint' => 'You have to enter the MAC or the IP Address for a device. To enter both is also possible',
 'chain' => 'Chain',
 'change passwords' => 'Change passwords',
 'change share' => 'edit share options',
+'check all' =>'Check all',
 'check for net traffic update' => 'Check for Net-Traffic updates',
 'check vpn lr' => 'Check',
 'choose config' => 'Choose config',
 'fwhost OpenVPN static host' => 'OpenVPN static host',
 'fwhost OpenVPN static network' => 'OpenVPN static network',
 'fwhost Standard Network' => 'Standard network',
+'fwhost addgeoipgrp' => 'Add new GeoIP group',
 'fwhost addgrp' => 'Add new network/host group',
 'fwhost addgrpname' => 'Group name:',
 'fwhost addhost' => 'Add new host',
 'fwhost change' => 'Modify',
 'fwhost changeremark' => 'You modified just the remark',
 'fwhost cust addr' => 'Hosts',
+'fwhost cust geoip' => 'GeoIP Groups',
+'fwhost cust geoipgroup' => 'GeoIP Groups',
+'fwhost cust geoiplocation' => 'GeoIP Locations',
 'fwhost cust grp' => 'Network/Host Groups',
 'fwhost cust net' => 'Networks',
 'fwhost cust service' => 'Services',
 'fwhost ipsec net' => 'IPsec networks:',
 'fwhost menu' => 'Firewall Groups',
 'fwhost netaddress' => 'Network address',
+'fwhost newgeoipgrp' => 'GeoIP Groups',
 'fwhost newgrp' => 'Network/Host Groups',
 'fwhost newhost' => 'Hosts',
 'fwhost newnet' => 'Networks',
 'generating the root and host certificates may take a long time. it can take up to several minutes on older hardware. please be patient' => 'Generating the root and host certificates may take a long time.  It can take up to several minutes on older hardware. Please be patient.',
 'genkey' => 'Generate PSK',
 'genre' => 'Genre',
+'geoip' => 'GeoIP',
+'geoipblock' => 'GeoIP Block',
+'geoipblock block countries' => 'Block countries',
+'geoipblock configuration' => 'GeoIP Configuration',
+'geoipblock country code' => 'Country Code',
+'geoipblock country is allowed' => 'Traffic from this country is allowed',
+'geoipblock country is blocked' => 'Traffic from this country will be blocked',
+'geoipblock country name' => 'Country Name',
+'geoipblock enable feature' => 'Enable GeoIP based blocking:',
+'geoipblock flag' => 'Flag',
 'global settings' => 'Global Settings',
 'gpl i accept these terms and conditions' => 'I accept these terms and conditions',
 'gpl license agreement' => 'License Agreement',
 'type' => 'Type',
 'umount' => 'Umount',
 'umount removable media before to unplug' => 'Umount removable media before unplugging the device',
+'uncheck all' => 'Uncheck all',
 'unable to alter profiles while red is active' => 'Unable to alter profiles while RED is active.',
 'unable to contact' => 'Unable to contact',
+'unblock' => 'Unblock',
+'unblock all' => 'Unblock all',
 'unencrypted' => 'Unencrypted',
 'uninstall' => 'Uninstall',
 'unix charset' => 'UNIX Charset',
index b2c1455..02bf7a0 100644 (file)
@@ -24,7 +24,7 @@
 
 include Config
 
-VER        = 2.07
+VER        = 3.33
 
 THISAPP    = Locale-Codes-$(VER)
 DL_FILE    = $(THISAPP).tar.gz
@@ -40,7 +40,7 @@ objects = $(DL_FILE)
 
 $(DL_FILE) = $(DL_FROM)/$(DL_FILE)
 
-$(DL_FILE)_MD5 = af0537cc4a882096d0320612c440df6d
+$(DL_FILE)_MD5 = bc7496f97889de8504e80addaa0ee40c
 
 install : $(TARGET)
 
diff --git a/lfs/perl-Text-CSV_XS b/lfs/perl-Text-CSV_XS
new file mode 100644 (file)
index 0000000..f94593f
--- /dev/null
@@ -0,0 +1,77 @@
+###############################################################################
+#                                                                             #
+# IPFire.org - A linux based firewall                                         #
+# Copyright (C) 2014  IPFire Team  <info@ipfire.org>                          #
+#                                                                             #
+# This program is free software: you can redistribute it and/or modify        #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation, either version 3 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# This program is distributed in the hope that it will be useful,             #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+# GNU General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+###############################################################################
+
+
+###############################################################################
+# Definitions
+###############################################################################
+
+include Config
+VER        = 1.12
+
+THISAPP    = Text-CSV_XS-$(VER)
+DL_FILE    = ${THISAPP}.tgz
+DL_FROM    = $(URL_IPFIRE)
+DIR_APP    = $(DIR_SRC)/$(THISAPP)
+TARGET     = $(DIR_INFO)/$(THISAPP)
+
+###############################################################################
+# Top-level Rules
+###############################################################################
+
+objects = $(DL_FILE)
+
+$(DL_FILE) = $(DL_FROM)/$(DL_FILE)
+
+$(DL_FILE)_MD5 = b91f2d806054b68c2a29d3da5821fe87
+
+install : $(TARGET)
+
+check : $(patsubst %,$(DIR_CHK)/%,$(objects))
+
+download :$(patsubst %,$(DIR_DL)/%,$(objects))
+
+md5 : $(subst %,%_MD5,$(objects))
+
+###############################################################################
+# Downloading, checking, md5sum
+###############################################################################
+
+$(patsubst %,$(DIR_CHK)/%,$(objects)) :
+       @$(CHECK)
+
+$(patsubst %,$(DIR_DL)/%,$(objects)) :
+       @$(LOAD)
+
+$(subst %,%_MD5,$(objects)) :
+       @$(MD5)
+
+###############################################################################
+# Installation Details
+###############################################################################
+
+$(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
+       @$(PREBUILD)
+       @rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar zxf $(DIR_DL)/$(DL_FILE)
+       cd $(DIR_APP) && perl Makefile.PL
+       cd $(DIR_APP) && make $(MAKETUNING) $(EXTRA_MAKE)
+       cd $(DIR_APP) && make install
+       @rm -rf $(DIR_APP)
+       @$(POSTBUILD)
index 895ee15..4388114 100644 (file)
@@ -55,7 +55,7 @@ $(TARGET) :
        -install -dv -m 1777 /tmp /var/tmp
        -mkdir -pv /usr/{,local/}{bin,include,lib{,/sse2},sbin,src}
        -mkdir -pv /usr/{,local/}share/{doc,info,locale,man}
-       -mkdir -v  /usr/{,local/}share/{misc,terminfo,zoneinfo}
+       -mkdir -v  /usr/{,local/}share/{misc,terminfo,xt_geoip,zoneinfo}
        -mkdir -pv /usr/{,local/}share/man/man{1..8}
        #-for dir in /usr /usr/local; do \
        #  ln -sv share/{man,doc,info} $$dir; \
diff --git a/lfs/xtables-addons b/lfs/xtables-addons
new file mode 100644 (file)
index 0000000..1848dc9
--- /dev/null
@@ -0,0 +1,110 @@
+###############################################################################
+#                                                                             #
+# IPFire.org - A linux based firewall                                         #
+# Copyright (C) 2007-2014  IPFire Team <info@ipfire.org>                      #
+#                                                                             #
+# This program is free software: you can redistribute it and/or modify        #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation, either version 3 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# This program is distributed in the hope that it will be useful,             #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+# GNU General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+###############################################################################
+
+###############################################################################
+# Definitions
+###############################################################################
+
+include Config
+
+VERSUFIX = ipfire$(KCFG)
+MODPATH = /lib/modules/$(KVER)-$(VERSUFIX)/extra/
+
+VER        = 2.6
+
+THISAPP    = xtables-addons-$(VER)
+DL_FILE    = $(THISAPP).tar.xz
+DL_FROM    = $(URL_IPFIRE)
+DIR_APP    = $(DIR_SRC)/$(THISAPP)
+
+ifeq "$(USPACE)" "1"
+  TARGET = $(DIR_INFO)/$(THISAPP)
+else
+  TARGET = $(DIR_INFO)/$(THISAPP)-kmod-$(KVER)-$(VERSUFIX)
+endif
+
+###############################################################################
+# Top-level Rules
+###############################################################################
+
+objects = $(DL_FILE)
+
+$(DL_FILE) = $(DL_FROM)/$(DL_FILE)
+
+$(DL_FILE)_MD5 = 087835ba7e564481b6fd398692268340
+
+install : $(TARGET)
+
+check : $(patsubst %,$(DIR_CHK)/%,$(objects))
+
+download :$(patsubst %,$(DIR_DL)/%,$(objects))
+
+md5 : $(subst %,%_MD5,$(objects))
+
+dist: 
+       $(PAK)
+
+###############################################################################
+# Downloading, checking, md5sum
+###############################################################################
+
+$(patsubst %,$(DIR_CHK)/%,$(objects)) :
+       @$(CHECK)
+
+$(patsubst %,$(DIR_DL)/%,$(objects)) :
+       @$(LOAD)
+
+$(subst %,%_MD5,$(objects)) :
+       @$(MD5)
+
+###############################################################################
+# Installation Details
+###############################################################################
+
+$(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
+       @$(PREBUILD)
+       @rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar axf $(DIR_DL)/$(DL_FILE)
+
+       # Only build the specified modules.
+       cp -avf $(DIR_SRC)/config/xtables-addons/mconfig \
+               $(DIR_APP)/mconfig
+
+# Check if we build the modules for a kernel or the userspace parts.
+ifeq "$(USPACE)" "1"
+       cd $(DIR_APP) && ./configure \
+               --prefix=/usr \
+               --without-kbuild
+
+       cd $(DIR_APP) && make $(MAKETUNING)
+       cd $(DIR_APP) && make install
+else
+       cd $(DIR_APP) && ./configure \
+               --with-kbuild=/usr/src/linux-$(KVER)/
+
+       cd $(DIR_APP) && make $(MAKETUNING)
+
+       # Install the built kernel modules.
+       cd $(DIR_APP) && for f in $$(ls extensions/*.ko); do \
+               install -m 644 $$f $(MODPATH); \
+       done
+endif
+
+       @rm -rf $(DIR_APP)
+       @$(POSTBUILD)
diff --git a/make.sh b/make.sh
index 92edf78..9f77df5 100755 (executable)
--- a/make.sh
+++ b/make.sh
@@ -383,6 +383,7 @@ buildipfire() {
   export LOGFILE
   ipfiremake configroot
   ipfiremake backup
+  ipfiremake pkg-config
   ipfiremake libusb
   ipfiremake libusbx
   ipfiremake libpcap
@@ -403,6 +404,8 @@ buildipfire() {
   ipfiremake multipath-tools
   ipfiremake freetype
   ipfiremake grub
+  ipfiremake libmnl
+  ipfiremake iptables
 
   case "${TARGET_ARCH}" in
        i586)
@@ -413,6 +416,7 @@ buildipfire() {
                ipfiremake e1000e                       KCFG="-pae"
                ipfiremake igb                          KCFG="-pae"
                ipfiremake ixgbe                        KCFG="-pae"
+               ipfiremake xtables-addons               KCFG="-pae"
                ipfiremake linux-initrd                 KCFG="-pae"
 
                # x86 kernel build
@@ -422,6 +426,7 @@ buildipfire() {
                ipfiremake e1000e                       KCFG=""
                ipfiremake igb                          KCFG=""
                ipfiremake ixgbe                        KCFG=""
+               ipfiremake xtables-addons               KCFG=""
                ipfiremake linux-initrd                 KCFG=""
                ;;
 
@@ -430,6 +435,7 @@ buildipfire() {
                ipfiremake linux                        KCFG="-rpi"
                ipfiremake backports                    KCFG="-rpi"
                ipfiremake cryptodev                    KCFG="-rpi"
+               ipfiremake xtables-addons               KCFG="-rpi"
                ipfiremake linux-initrd                 KCFG="-rpi"
 
                # arm multi platform (Panda, Wandboard ...) kernel build
@@ -439,6 +445,7 @@ buildipfire() {
                ipfiremake e1000e                       KCFG="-multi"
                ipfiremake igb                          KCFG="-multi"
                ipfiremake ixgbe                        KCFG="-multi"
+               ipfiremake xtables-addons               KCFG="-multi"
                ipfiremake linux-initrd                 KCFG="-multi"
 
                # arm-kirkwood (Dreamplug, ICY-Box ...) kernel build
@@ -448,10 +455,11 @@ buildipfire() {
                ipfiremake e1000e                       KCFG="-kirkwood"
                ipfiremake igb                          KCFG="-kirkwood"
                ipfiremake ixgbe                        KCFG="-kirkwood"
+               ipfiremake xtables-addons               KCFG="-kirkwood"
                ipfiremake linux-initrd                 KCFG="-kirkwood"
                ;;
   esac
-  ipfiremake pkg-config
+  ipfiremake xtables-addons                    USPACE="1"
   ipfiremake openssl
   ipfiremake openssl-compat
   ipfiremake libgpg-error
@@ -526,8 +534,6 @@ buildipfire() {
   ipfiremake mtools
   ipfiremake initscripts
   ipfiremake whatmask
-  ipfiremake libmnl
-  ipfiremake iptables
   ipfiremake conntrack-tools
   ipfiremake libupnp
   ipfiremake ipaddr
@@ -809,6 +815,7 @@ buildipfire() {
   ipfiremake squid-accounting
   ipfiremake pigz
   ipfiremake tmux
+  ipfiremake perl-Text-CSV_XS
   ipfiremake swconfig
 }
 
index c383652..8ca02bc 100644 (file)
@@ -179,6 +179,11 @@ iptables_init() {
                iptables -A OUTPUT -o "${BLUE_DEV}" -j DHCPBLUEOUTPUT
        fi
 
+       # GeoIP block
+       iptables -N GEOIPBLOCK
+       iptables -A INPUT -j GEOIPBLOCK
+       iptables -A FORWARD -j GEOIPBLOCK
+
        # trafic from ipsecX/TUN/TAP interfaces, before "-i GREEN_DEV" accept everything
        iptables -N IPSECINPUT
        iptables -N IPSECFORWARD
diff --git a/src/initscripts/init.d/networking/red.up/99-geoip-database b/src/initscripts/init.d/networking/red.up/99-geoip-database
new file mode 100644 (file)
index 0000000..020f2fa
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# Get the GeoIP database if no one exists yet.
+
+DIR=/usr/share/xt_geoip
+
+found=false
+
+# Check if the directory contains any data.
+for i in $DIR/*; do
+        found=true
+        break
+done
+
+# Download ruleset if none has been found.
+if ! ${found}; then
+       /us/local/bin/xt_geoip_update >/dev/null 2>&1
+fi
+
+exit 0
diff --git a/src/scripts/xt_geoip_build b/src/scripts/xt_geoip_build
new file mode 100644 (file)
index 0000000..202156f
--- /dev/null
@@ -0,0 +1,89 @@
+#!/usr/bin/perl
+#
+#      Converter for MaxMind CSV database to binary, for xt_geoip
+#      Copyright © Jan Engelhardt, 2008-2011
+#
+use Getopt::Long;
+use IO::Handle;
+use Text::CSV_XS; # or trade for Text::CSV
+use strict;
+
+my $csv = Text::CSV_XS->new({
+       allow_whitespace => 1,
+       binary => 1,
+       eol => $/,
+}); # or Text::CSV
+my $target_dir = ".";
+
+&Getopt::Long::Configure(qw(bundling));
+&GetOptions(
+       "D=s" => \$target_dir,
+);
+
+if (!-d $target_dir) {
+       print STDERR "Target directory $target_dir does not exist.\n";
+       exit 1;
+}
+
+my $dir = "$target_dir/LE";
+if (!-e $dir && !mkdir($dir)) {
+       print STDERR "Could not mkdir $dir: $!\n";
+       exit 1;
+}
+
+&dump(&collect());
+
+sub collect
+{
+       my %country;
+
+       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]};
+
+               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";
+       return \%country;
+}
+
+sub dump
+{
+       my $country = shift @_;
+
+       foreach my $iso_code (sort keys %$country) {
+               &dump_one($iso_code, $country->{$iso_code});
+       }
+}
+
+sub dump_one
+{
+       my($iso_code, $country) = @_;
+       my($file, $fh_le, $fh_be);
+
+       printf "%5u IPv4 ranges for %s %s\n",
+               scalar(@{$country->{pool_v4}}),
+               $iso_code, $country->{name};
+
+       $file = "$target_dir/LE/".uc($iso_code).".iv4";
+       if (!open($fh_le, "> $file")) {
+               print STDERR "Error opening $file: $!\n";
+               exit 1;
+       }
+       foreach my $range (@{$country->{pool_v4}}) {
+               print $fh_le pack("VV", $range->[0], $range->[1]);
+               #print $fh_be pack("NN", $range->[0], $range->[1]);
+       }
+       close $fh_le;
+}
diff --git a/src/scripts/xt_geoip_update b/src/scripts/xt_geoip_update
new file mode 100644 (file)
index 0000000..3ad34d0
--- /dev/null
@@ -0,0 +1,118 @@
+#!/bin/bash
+###############################################################################
+#                                                                             #
+# IPFire.org - A linux based firewall                                         #
+# Copyright (C) 2014 IPFire Development Team <info@ipfire.org>                #
+#                                                                             #
+# This program is free software: you can redistribute it and/or modify        #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation, either version 3 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# This program is distributed in the hope that it will be useful,             #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+# GNU General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+###############################################################################
+
+TMP_PATH=$(mktemp -d)
+TMP_FILE=$(mktemp)
+
+SCRIPT_PATH=/usr/libexec/xtables-addons
+DEST_PATH=/usr/share/xt_geoip
+
+DL_URL=http://geolite.maxmind.com/download/geoip/database
+DL_FILE=GeoIPCountryCSV.zip
+
+CSV_FILE=GeoIPCountryWhois.csv
+
+ARCH=LE
+
+function download() {
+       echo "Downloading latest GeoIP ruleset..."
+
+       # Get the latest GeoIP database from server.
+       wget $DL_URL/$DL_FILE -O $TMP_PATH/$TMP_FILE
+
+       # Extract files.
+       unzip $TMP_PATH/$TMP_FILE -d $TMP_PATH
+
+       return 0
+}
+
+function build() {
+       echo "Convert database..."
+
+       # Check if the csv file exists.
+       if [ ! -e $TMP_PATH/$CSV_FILE ]; then
+               echo "$TMP_PATH/$CSV_FILE not found. Exiting."
+               return 1
+       fi
+
+       # Run script to convert the CSV file into several xtables
+       # compatible binary files.
+       if ! $SCRIPT_PATH/xt_geoip_build $TMP_DIR/$CSV_FILE -D $TMP_DIR; then
+               echo "Could not convert ruleset. Aborting." >&2
+               return 1
+       fi
+
+       return 0
+}
+
+function install() {
+       echo "Install databases..."
+
+       # Check if our destination exist.
+       if [ ! -e "$DEST_PATH" ]; then
+               mkdir -p $DEST_PATH &>/dev/null
+       fi
+
+       # Install databases.
+       if ! cp -af $TMP_PATH/$ARCH $DEST_PATH &>/dev/null; then
+               echo "Could not copy files. Aborting." >&2
+               return 1
+       fi
+
+       return 0
+}
+
+function cleanup() {
+       echo "Cleaning up temporary files..."
+       if ! rm -rf $TMP_PATH &>/dev/null; then
+               echo "Could not remove files. Aborting." >&2
+               return 1
+       fi
+
+       return 0
+}
+
+function main() {
+       # Download ruleset.
+       download || exit $?
+
+       # Convert the ruleset.
+       if ! build; then
+               # Do cleanup.
+               cleanup || exit $?
+               exit 1
+       fi
+
+       # Install the converted ruleset.
+       if ! install; then
+               # Do cleanup.
+               cleanup || exit $?
+               exit 1
+       fi
+
+       # Finaly remove temporary files.
+       cleanup || exit $?
+
+       return 0
+}
+
+# Run the main function.
+main