]> git.ipfire.org Git - people/jschlag/ipfire-2.x.git/commitdiff
Merge branch 'seventeen-geoip' into next-geoip
authorStefan Schantl <stefan.schantl@ipfire.org>
Sun, 15 Mar 2015 10:38:45 +0000 (11:38 +0100)
committerStefan Schantl <stefan.schantl@ipfire.org>
Sun, 15 Mar 2015 10:38:45 +0000 (11:38 +0100)
1  2 
config/firewall/rules.pl
config/rootfiles/common/stage2
html/cgi-bin/firewall.cgi
html/cgi-bin/fwhosts.cgi
langs/en/cgi-bin/en.pl
make.sh

diff --combined config/firewall/rules.pl
index 8abc675f7f6f8d5693598ade0523748a5b20f20d,a12ab56670f92342527cc4748349fc0301cbde2e..fa7edee1bec2fb36645c144dc1bc77fd054ed937
mode 100755,100644..100644
@@@ -60,6 -60,7 +60,7 @@@ my $configfwdfw               = "${General::swroot}/
  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";
  
@@@ -88,27 -89,17 +89,30 @@@ sub main 
        # Flush all chains.
        &flush();
  
 -      # Reload firewall rules.
 -      &preparerules();
 +      # Prepare firewall rules.
 +      if (! -z  "${General::swroot}/firewall/input"){
 +              &buildrules(\%configinputfw);
 +      }
 +      if (! -z  "${General::swroot}/firewall/outgoing"){
 +              &buildrules(\%configoutgoingfw);
 +      }
 +      if (! -z  "${General::swroot}/firewall/config"){
 +              &buildrules(\%configfwdfw);
 +      }
  
        # Load P2P block rules.
        &p2pblock();
  
+       # Load GeoIP block rules.
+       &geoipblock();
        # Reload firewall policy.
        run("/usr/sbin/firewall-policy");
 +
 +      #Reload firewall.local if present
 +      if ( -f '/etc/sysconfig/firewall.local'){
 +              run("/etc/sysconfig/firewall.local reload");
 +      }
  }
  
  sub run {
@@@ -159,6 -150,18 +163,6 @@@ sub flush 
        run("$IPTABLES -t mangle -F $CHAIN_MANGLE_NAT_DESTINATION_FIX");
  }
  
 -sub preparerules {
 -      if (! -z  "${General::swroot}/firewall/input"){
 -              &buildrules(\%configinputfw);
 -      }
 -      if (! -z  "${General::swroot}/firewall/outgoing"){
 -              &buildrules(\%configoutgoingfw);
 -      }
 -      if (! -z  "${General::swroot}/firewall/config"){
 -              &buildrules(\%configfwdfw);
 -      }
 -}
 -
  sub buildrules {
        my $hash = shift;
  
                                        my @source_options = ();
                                        if ($source =~ /mac/) {
                                                push(@source_options, $source);
-                                       } elsif ($source) {
+                                       } elsif ($source =~ /-m geoip/) {
+                                               push(@source_options, $source);
+                                       } elsif($source) {
                                                push(@source_options, ("-s", $source));
                                        }
  
                                        # Prepare destination options.
                                        my @destination_options = ();
-                                       if ($destination) {
+                                       if ($destination =~ /-m geoip/) {
+                                               push(@destination_options,  $destination);
+                                       } elsif ($destination) {
                                                push(@destination_options, ("-d", $destination));
                                        }
  
                        }
                }
        }
 -      #Reload firewall.local if present
 -      if ( -f '/etc/sysconfig/firewall.local'){
 -              run("/etc/sysconfig/firewall.local reload");
 -      }
  }
  
  # Formats the given timestamp into the iptables format which is "hh:mm" UTC.
@@@ -570,6 -581,40 +578,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 44f24b4369504ec1bf84267b689b7244eb75f6c0,6c9325fd17337a5be41bec6d39e0811961ffb975..8ac30735a3d955b4b9cf87c8d5695dfd2c5a61ab
@@@ -48,6 -48,8 +48,6 @@@ home/nobod
  #lib
  #lib/firmware
  #lib/firmware/brcm
 -lib/firmware/brcm/brcmfmac4329-sdio.txt
 -lib/firmware/brcm/brcmfmac4330-sdio.txt
  lib/firmware/brcm/brcmfmac43362-sdio.txt
  #media
  media/cdrom
@@@ -101,6 -103,8 +101,8 @@@ usr/local/bin/timechec
  usr/local/bin/timezone-transition
  usr/local/bin/update-bootloader
  usr/local/bin/update-lang-cache
+ usr/local/bin/xt_geoip_build
+ usr/local/bin/xt_geoip_update
  #usr/local/include
  #usr/local/lib
  #usr/local/lib/sse2
  #usr/local/share/man/man8
  #usr/local/share/misc
  #usr/local/share/terminfo
+ #usr/local/share/xt_geoip
  #usr/local/share/zoneinfo
  #usr/local/src
  #usr/sbin
@@@ -141,6 -146,7 +144,7 @@@ usr/share/doc/licenses/GPLv
  #usr/share/man/man8
  #usr/share/misc
  #usr/share/terminfo
+ #usr/share/xt_geoip
  #usr/share/zoneinfo
  #var
  #var/cache
index 39b732ce36b77d073d064758cbefbc9d77e314b3,12152700fb15c0a71487a1761554d9402c5bf63a..3e1b33618c98fa01aecb30543e20d1628e73ba4d
@@@ -33,6 -33,7 +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 +48,7 @@@ my %defaultNetworks=()
  my %netsettings=();
  my %customhost=();
  my %customgrp=();
+ my %customgeoipgrp=();
  my %customnetworks=();
  my %customservice=();
  my %customservicegrp=();
@@@ -66,7 -68,6 +68,7 @@@ my %ipsecsettings=()
  my %aliases=();
  my %optionsfw=();
  my %ifaces=();
 +my %rulehash=();
  
  my @PROTOCOLS = ("TCP", "UDP", "ICMP", "IGMP", "AH", "ESP", "GRE","IPv6","IPIP");
  
@@@ -74,6 -75,7 +76,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";
@@@ -195,7 -197,6 +198,7 @@@ if ($fwdfwsettings{'ACTION'} eq 'saveru
        &General::readhasharray("$configfwdfw", \%configfwdfw);
        &General::readhasharray("$configinput", \%configinputfw);
        &General::readhasharray("$configoutgoing", \%configoutgoingfw);
 +      my $maxkey;
        #Set Variables according to the JQuery code in protocol section
        if ($fwdfwsettings{'PROT'} eq 'TCP' || $fwdfwsettings{'PROT'} eq 'UDP')
        {
        if(     $fwdfwsettings{'grp1'} eq 'ipfire_src' && $fwdfwsettings{'grp2'} eq 'ipfire'){
                $errormessage=$Lang::tr{'fwdfw err same'};
        }
 -      #INPUT part
 -      if($fwdfwsettings{'grp2'} eq 'ipfire' && $fwdfwsettings{$fwdfwsettings{'grp1'}} ne 'ORANGE'){
 +      # INPUT part
 +      if ($fwdfwsettings{'grp2'} eq 'ipfire' && $fwdfwsettings{$fwdfwsettings{'grp1'}} ne 'ORANGE'){
                $fwdfwsettings{'config'}=$configinput;
                $fwdfwsettings{'chain'} = 'INPUTFW';
 -              my $maxkey=&General::findhasharraykey(\%configinputfw);
 -              #check if we have an identical rule already
 -              if($fwdfwsettings{'oldrulenumber'} eq $fwdfwsettings{'rulepos'}){
 -                      foreach my $key (sort keys %configinputfw){
 -                              if (   "$fwdfwsettings{'RULE_ACTION'},$fwdfwsettings{'ACTIVE'},$fwdfwsettings{'grp1'},$fwdfwsettings{$fwdfwsettings{'grp1'}},$fwdfwsettings{'grp2'},$fwdfwsettings{$fwdfwsettings{'grp2'}},$fwdfwsettings{'USE_SRC_PORT'},$fwdfwsettings{'PROT'},$fwdfwsettings{'ICMP_TYPES'},$fwdfwsettings{'SRC_PORT'},$fwdfwsettings{'USESRV'},$fwdfwsettings{'TGT_PROT'},$fwdfwsettings{'ICMP_TGT'},$fwdfwsettings{'grp3'},$fwdfwsettings{$fwdfwsettings{'grp3'}},$fwdfwsettings{'LOG'},$fwdfwsettings{'TIME'},$fwdfwsettings{'TIME_MON'},$fwdfwsettings{'TIME_TUE'},$fwdfwsettings{'TIME_WED'},$fwdfwsettings{'TIME_THU'},$fwdfwsettings{'TIME_FRI'},$fwdfwsettings{'TIME_SAT'},$fwdfwsettings{'TIME_SUN'},$fwdfwsettings{'TIME_FROM'},$fwdfwsettings{'TIME_TO'},$fwdfwsettings{'USE_NAT'},$fwdfwsettings{$fwdfwsettings{'nat'}},$fwdfwsettings{'dnatport'},$fwdfwsettings{'nat'},$fwdfwsettings{'LIMIT_CON_CON'},$fwdfwsettings{'concon'},$fwdfwsettings{'RATE_LIMIT'},$fwdfwsettings{'ratecon'},$fwdfwsettings{'RATETIME'}"
 -                                      eq "$configinputfw{$key}[0],$configinputfw{$key}[2],$configinputfw{$key}[3],$configinputfw{$key}[4],$configinputfw{$key}[5],$configinputfw{$key}[6],$configinputfw{$key}[7],$configinputfw{$key}[8],$configinputfw{$key}[9],$configinputfw{$key}[10],$configinputfw{$key}[11],$configinputfw{$key}[12],$configinputfw{$key}[13],$configinputfw{$key}[14],$configinputfw{$key}[15],$configinputfw{$key}[17],$configinputfw{$key}[18],$configinputfw{$key}[19],$configinputfw{$key}[20],$configinputfw{$key}[21],$configinputfw{$key}[22],$configinputfw{$key}[23],$configinputfw{$key}[24],$configinputfw{$key}[25],$configinputfw{$key}[26],$configinputfw{$key}[27],$configinputfw{$key}[28],$configinputfw{$key}[29],$configinputfw{$key}[30],$configinputfw{$key}[31],$configinputfw{$key}[32],$configinputfw{$key}[33],$configinputfw{$key}[34],$configinputfw{$key}[35],$configinputfw{$key}[36]"){
 -                                              $errormessage.=$Lang::tr{'fwdfw err ruleexists'};
 -                                              if($fwdfwsettings{'oldruleremark'} ne $fwdfwsettings{'ruleremark'} && $fwdfwsettings{'updatefwrule'} eq 'on' && $fwdfwsettings{'ruleremark'} ne '' && !&validremark($fwdfwsettings{'ruleremark'})){
 -                                                      $errormessage=$Lang::tr{'fwdfw err remark'}."<br>";
 -                                              }
 -                                              if($fwdfwsettings{'oldruleremark'} ne $fwdfwsettings{'ruleremark'} && $fwdfwsettings{'updatefwrule'} eq 'on' && $fwdfwsettings{'ruleremark'} ne '' && &validremark($fwdfwsettings{'ruleremark'})){
 -                                                      $errormessage='';
 -                                              }
 -                                              if ($fwdfwsettings{'oldruleremark'} eq $fwdfwsettings{'ruleremark'}){
 -                                                      $fwdfwsettings{'nosave'} = 'on';
 -                                              }
 -                              }
 -                      }
 -              }
 -              #check Rulepos on new Rule
 -              if($fwdfwsettings{'rulepos'} > 0 && !$fwdfwsettings{'oldrulenumber'}){
 -                      $fwdfwsettings{'oldrulenumber'}=$maxkey;
 -                      foreach my $key (sort keys %configinputfw){
 -                              if (   "$fwdfwsettings{'RULE_ACTION'},$fwdfwsettings{'ACTIVE'},$fwdfwsettings{'grp1'},$fwdfwsettings{$fwdfwsettings{'grp1'}},$fwdfwsettings{'grp2'},$fwdfwsettings{$fwdfwsettings{'grp2'}},$fwdfwsettings{'USE_SRC_PORT'},$fwdfwsettings{'PROT'},$fwdfwsettings{'ICMP_TYPES'},$fwdfwsettings{'SRC_PORT'},$fwdfwsettings{'USESRV'},$fwdfwsettings{'TGT_PROT'},$fwdfwsettings{'ICMP_TGT'},$fwdfwsettings{'grp3'},$fwdfwsettings{$fwdfwsettings{'grp3'}},$fwdfwsettings{'LOG'},$fwdfwsettings{'TIME'},$fwdfwsettings{'TIME_MON'},$fwdfwsettings{'TIME_TUE'},$fwdfwsettings{'TIME_WED'},$fwdfwsettings{'TIME_THU'},$fwdfwsettings{'TIME_FRI'},$fwdfwsettings{'TIME_SAT'},$fwdfwsettings{'TIME_SUN'},$fwdfwsettings{'TIME_FROM'},$fwdfwsettings{'TIME_TO'},$fwdfwsettings{'USE_NAT'},$fwdfwsettings{$fwdfwsettings{'nat'}},$fwdfwsettings{'dnatport'},$fwdfwsettings{'nat'},$fwdfwsettings{'LIMIT_CON_CON'},$fwdfwsettings{'concon'},$fwdfwsettings{'RATE_LIMIT'},$fwdfwsettings{'ratecon'},$fwdfwsettings{'RATETIME'}"
 -                                      eq "$configinputfw{$key}[0],$configinputfw{$key}[2],$configinputfw{$key}[3],$configinputfw{$key}[4],$configinputfw{$key}[5],$configinputfw{$key}[6],$configinputfw{$key}[7],$configinputfw{$key}[8],$configinputfw{$key}[9],$configinputfw{$key}[10],$configinputfw{$key}[11],$configinputfw{$key}[12],$configinputfw{$key}[13],$configinputfw{$key}[14],$configinputfw{$key}[15],$configinputfw{$key}[17],$configinputfw{$key}[18],$configinputfw{$key}[19],$configinputfw{$key}[20],$configinputfw{$key}[21],$configinputfw{$key}[22],$configinputfw{$key}[23],$configinputfw{$key}[24],$configinputfw{$key}[25],$configinputfw{$key}[26],$configinputfw{$key}[27],$configinputfw{$key}[28],$configinputfw{$key}[29],$configinputfw{$key}[30],$configinputfw{$key}[31],$configinputfw{$key}[32],$configinputfw{$key}[33],$configinputfw{$key}[34],$configinputfw{$key}[35],$configinputfw{$key}[36]"){
 -                                              $errormessage.=$Lang::tr{'fwdfw err ruleexists'};
 -                              }
 -                      }
 -              }
 -              #check if we just close a rule
 -              if( $fwdfwsettings{'oldgrp1a'} eq  $fwdfwsettings{'grp1'} && $fwdfwsettings{'oldgrp1b'} eq $fwdfwsettings{$fwdfwsettings{'grp1'}} && $fwdfwsettings{'oldgrp2a'} eq  $fwdfwsettings{'grp2'} && $fwdfwsettings{'oldgrp2b'} eq $fwdfwsettings{$fwdfwsettings{'grp2'}} &&  $fwdfwsettings{'oldgrp3a'} eq $fwdfwsettings{'grp3'} && $fwdfwsettings{'oldgrp3b'} eq  $fwdfwsettings{$fwdfwsettings{'grp3'}} && $fwdfwsettings{'oldusesrv'} eq $fwdfwsettings{'USESRV'} && $fwdfwsettings{'oldruleremark'} eq $fwdfwsettings{'ruleremark'} && $fwdfwsettings{'oldruletype'} eq $fwdfwsettings{'chain'} ) {
 -                      if($fwdfwsettings{'nosave'} eq 'on' && $fwdfwsettings{'updatefwrule'} eq 'on'){
 -                              $errormessage='';
 -                              $fwdfwsettings{'nosave2'} = 'on';
 -                      }
 -              }
 -              if (!$errormessage){
 -                      if($fwdfwsettings{'nosave2'} ne 'on'){
 -                              &saverule(\%configinputfw,$configinput);
 -                      }
 -              }
 -      }elsif($fwdfwsettings{'grp1'} eq 'ipfire_src' ){
 +              $maxkey=&General::findhasharraykey(\%configinputfw);
 +              %rulehash=%configinputfw;
 +      }elsif ($fwdfwsettings{'grp1'} eq 'ipfire_src' ){
        # OUTGOING PART
                $fwdfwsettings{'config'}=$configoutgoing;
                $fwdfwsettings{'chain'} = 'OUTGOINGFW';
 -              my $maxkey=&General::findhasharraykey(\%configoutgoingfw);
 -              if($fwdfwsettings{'oldrulenumber'} eq $fwdfwsettings{'rulepos'}){
 -                      foreach my $key (sort keys %configoutgoingfw){
 -                              if (   "$fwdfwsettings{'RULE_ACTION'},$fwdfwsettings{'ACTIVE'},$fwdfwsettings{'grp1'},$fwdfwsettings{$fwdfwsettings{'grp1'}},$fwdfwsettings{'grp2'},$fwdfwsettings{$fwdfwsettings{'grp2'}},$fwdfwsettings{'USE_SRC_PORT'},$fwdfwsettings{'PROT'},$fwdfwsettings{'ICMP_TYPES'},$fwdfwsettings{'SRC_PORT'},$fwdfwsettings{'USESRV'},$fwdfwsettings{'TGT_PROT'},$fwdfwsettings{'ICMP_TGT'},$fwdfwsettings{'grp3'},$fwdfwsettings{$fwdfwsettings{'grp3'}},$fwdfwsettings{'LOG'},$fwdfwsettings{'TIME'},$fwdfwsettings{'TIME_MON'},$fwdfwsettings{'TIME_TUE'},$fwdfwsettings{'TIME_WED'},$fwdfwsettings{'TIME_THU'},$fwdfwsettings{'TIME_FRI'},$fwdfwsettings{'TIME_SAT'},$fwdfwsettings{'TIME_SUN'},$fwdfwsettings{'TIME_FROM'},$fwdfwsettings{'TIME_TO'},$fwdfwsettings{'USE_NAT'},$fwdfwsettings{$fwdfwsettings{'nat'}},$fwdfwsettings{'dnatport'},$fwdfwsettings{'nat'},$fwdfwsettings{'LIMIT_CON_CON'},$fwdfwsettings{'concon'},$fwdfwsettings{'RATE_LIMIT'},$fwdfwsettings{'ratecon'},$fwdfwsettings{'RATETIME'}"
 -                                      eq "$configoutgoingfw{$key}[0],$configoutgoingfw{$key}[2],$configoutgoingfw{$key}[3],$configoutgoingfw{$key}[4],$configoutgoingfw{$key}[5],$configoutgoingfw{$key}[6],$configoutgoingfw{$key}[7],$configoutgoingfw{$key}[8],$configoutgoingfw{$key}[9],$configoutgoingfw{$key}[10],$configoutgoingfw{$key}[11],$configoutgoingfw{$key}[12],$configoutgoingfw{$key}[13],$configoutgoingfw{$key}[14],$configoutgoingfw{$key}[15],$configoutgoingfw{$key}[17],$configoutgoingfw{$key}[18],$configoutgoingfw{$key}[19],$configoutgoingfw{$key}[20],$configoutgoingfw{$key}[21],$configoutgoingfw{$key}[22],$configoutgoingfw{$key}[23],$configoutgoingfw{$key}[24],$configoutgoingfw{$key}[25],$configoutgoingfw{$key}[26],$configoutgoingfw{$key}[27],$configoutgoingfw{$key}[28],$configoutgoingfw{$key}[29],$configoutgoingfw{$key}[30],$configoutgoingfw{$key}[31],$configoutgoingfw{$key}[32],$configoutgoingfw{$key}[33],$configoutgoingfw{$key}[34],$configoutgoingfw{$key}[35],$configoutgoingfw{$key}[36]"){
 -                                              $errormessage.=$Lang::tr{'fwdfw err ruleexists'};
 -                                              if($fwdfwsettings{'oldruleremark'} ne $fwdfwsettings{'ruleremark'} && $fwdfwsettings{'updatefwrule'} eq 'on' && $fwdfwsettings{'ruleremark'} ne '' && !&validremark($fwdfwsettings{'ruleremark'})){
 -                                                      $errormessage=$Lang::tr{'fwdfw err remark'}."<br>";
 -                                              }
 -                                              if($fwdfwsettings{'oldruleremark'} ne $fwdfwsettings{'ruleremark'} && $fwdfwsettings{'updatefwrule'} eq 'on' && $fwdfwsettings{'ruleremark'} ne '' && &validremark($fwdfwsettings{'ruleremark'})){
 -                                                      $errormessage='';
 -                                              }
 -                                              if ($fwdfwsettings{'oldruleremark'} eq $fwdfwsettings{'ruleremark'}){
 -                                                      $fwdfwsettings{'nosave'} = 'on';
 -                                              }
 -                              }
 -                      }
 -              }
 -              #check Rulepos on new Rule
 -              if($fwdfwsettings{'rulepos'} > 0 && !$fwdfwsettings{'oldrulenumber'}){
 -                      $fwdfwsettings{'oldrulenumber'}=$maxkey;
 -                      foreach my $key (sort keys %configoutgoingfw){
 -                              if (   "$fwdfwsettings{'RULE_ACTION'},$fwdfwsettings{'ACTIVE'},$fwdfwsettings{'grp1'},$fwdfwsettings{$fwdfwsettings{'grp1'}},$fwdfwsettings{'grp2'},$fwdfwsettings{$fwdfwsettings{'grp2'}},$fwdfwsettings{'USE_SRC_PORT'},$fwdfwsettings{'PROT'},$fwdfwsettings{'ICMP_TYPES'},$fwdfwsettings{'SRC_PORT'},$fwdfwsettings{'USESRV'},$fwdfwsettings{'TGT_PROT'},$fwdfwsettings{'ICMP_TGT'},$fwdfwsettings{'grp3'},$fwdfwsettings{$fwdfwsettings{'grp3'}},$fwdfwsettings{'LOG'},$fwdfwsettings{'TIME'},$fwdfwsettings{'TIME_MON'},$fwdfwsettings{'TIME_TUE'},$fwdfwsettings{'TIME_WED'},$fwdfwsettings{'TIME_THU'},$fwdfwsettings{'TIME_FRI'},$fwdfwsettings{'TIME_SAT'},$fwdfwsettings{'TIME_SUN'},$fwdfwsettings{'TIME_FROM'},$fwdfwsettings{'TIME_TO'},$fwdfwsettings{'USE_NAT'},$fwdfwsettings{$fwdfwsettings{'nat'}},$fwdfwsettings{'dnatport'},$fwdfwsettings{'nat'},$fwdfwsettings{'LIMIT_CON_CON'},$fwdfwsettings{'concon'},$fwdfwsettings{'RATE_LIMIT'},$fwdfwsettings{'ratecon'},$fwdfwsettings{'RATETIME'}"
 -                                      eq "$configoutgoingfw{$key}[0],$configoutgoingfw{$key}[2],$configoutgoingfw{$key}[3],$configoutgoingfw{$key}[4],$configoutgoingfw{$key}[5],$configoutgoingfw{$key}[6],$configoutgoingfw{$key}[7],$configoutgoingfw{$key}[8],$configoutgoingfw{$key}[9],$configoutgoingfw{$key}[10],$configoutgoingfw{$key}[11],$configoutgoingfw{$key}[12],$configoutgoingfw{$key}[13],$configoutgoingfw{$key}[14],$configoutgoingfw{$key}[15],$configoutgoingfw{$key}[17],$configoutgoingfw{$key}[18],$configoutgoingfw{$key}[19],$configoutgoingfw{$key}[20],$configoutgoingfw{$key}[21],$configoutgoingfw{$key}[22],$configoutgoingfw{$key}[23],$configoutgoingfw{$key}[24],$configoutgoingfw{$key}[25],$configoutgoingfw{$key}[26],$configoutgoingfw{$key}[27],$configoutgoingfw{$key}[28],$configoutgoingfw{$key}[29],$configoutgoingfw{$key}[30],$configoutgoingfw{$key}[31],$configoutgoingfw{$key}[32],$configoutgoingfw{$key}[33],$configoutgoingfw{$key}[34],$configoutgoingfw{$key}[35],$configoutgoingfw{$key}[36]"){
 -                                              $errormessage.=$Lang::tr{'fwdfw err ruleexists'};
 -                              }
 -                      }
 -              }
 -              #check if we just close a rule
 -              if( $fwdfwsettings{'oldgrp1a'} eq  $fwdfwsettings{'grp1'} && $fwdfwsettings{'oldgrp1b'} eq $fwdfwsettings{$fwdfwsettings{'grp1'}} && $fwdfwsettings{'oldgrp2a'} eq  $fwdfwsettings{'grp2'} && $fwdfwsettings{'oldgrp2b'} eq $fwdfwsettings{$fwdfwsettings{'grp2'}} &&  $fwdfwsettings{'oldgrp3a'} eq $fwdfwsettings{'grp3'} && $fwdfwsettings{'oldgrp3b'} eq  $fwdfwsettings{$fwdfwsettings{'grp3'}} && $fwdfwsettings{'oldusesrv'} eq $fwdfwsettings{'USESRV'} && $fwdfwsettings{'oldruleremark'} eq $fwdfwsettings{'ruleremark'} && $fwdfwsettings{'oldruletype'} eq $fwdfwsettings{'chain'} ) {
 -                      if($fwdfwsettings{'nosave'} eq 'on' && $fwdfwsettings{'updatefwrule'} eq 'on'){
 -                              $fwdfwsettings{'nosave2'} = 'on';
 -                              $errormessage='';
 -                      }
 -              }
 -              #increase counters
 -              if (!$errormessage){
 -                      if ($fwdfwsettings{'nosave2'} ne 'on'){
 -                              &saverule(\%configoutgoingfw,$configoutgoing);
 -                      }
 -              }
 -      }else{
 -              #FORWARD PART
 +              $maxkey=&General::findhasharraykey(\%configoutgoingfw);
 +              %rulehash=%configoutgoingfw;
 +      }else {
 +      # FORWARD PART
                $fwdfwsettings{'config'}=$configfwdfw;
                $fwdfwsettings{'chain'} = 'FORWARDFW';
 -              my $maxkey=&General::findhasharraykey(\%configfwdfw);
 -              if($fwdfwsettings{'oldrulenumber'} eq $fwdfwsettings{'rulepos'}){
 -                      #check if we have an identical rule already
 -                      foreach my $key (sort keys %configfwdfw){
 -                              if (   "$fwdfwsettings{'RULE_ACTION'},$fwdfwsettings{'ACTIVE'},$fwdfwsettings{'grp1'},$fwdfwsettings{$fwdfwsettings{'grp1'}},$fwdfwsettings{'grp2'},$fwdfwsettings{$fwdfwsettings{'grp2'}},$fwdfwsettings{'USE_SRC_PORT'},$fwdfwsettings{'PROT'},$fwdfwsettings{'ICMP_TYPES'},$fwdfwsettings{'SRC_PORT'},$fwdfwsettings{'USESRV'},$fwdfwsettings{'TGT_PROT'},$fwdfwsettings{'ICMP_TGT'},$fwdfwsettings{'grp3'},$fwdfwsettings{$fwdfwsettings{'grp3'}},$fwdfwsettings{'TIME'},$fwdfwsettings{'TIME_MON'},$fwdfwsettings{'TIME_TUE'},$fwdfwsettings{'TIME_WED'},$fwdfwsettings{'TIME_THU'},$fwdfwsettings{'TIME_FRI'},$fwdfwsettings{'TIME_SAT'},$fwdfwsettings{'TIME_SUN'},$fwdfwsettings{'TIME_FROM'},$fwdfwsettings{'TIME_TO'},$fwdfwsettings{'USE_NAT'},$fwdfwsettings{$fwdfwsettings{'nat'}},$fwdfwsettings{'dnatport'},$fwdfwsettings{'nat'},$fwdfwsettings{'LIMIT_CON_CON'},$fwdfwsettings{'concon'},$fwdfwsettings{'RATE_LIMIT'},$fwdfwsettings{'ratecon'},$fwdfwsettings{'RATETIME'}"
 -                                      eq "$configfwdfw{$key}[0],$configfwdfw{$key}[2],$configfwdfw{$key}[3],$configfwdfw{$key}[4],$configfwdfw{$key}[5],$configfwdfw{$key}[6],$configfwdfw{$key}[7],$configfwdfw{$key}[8],$configfwdfw{$key}[9],$configfwdfw{$key}[10],$configfwdfw{$key}[11],$configfwdfw{$key}[12],$configfwdfw{$key}[13],$configfwdfw{$key}[14],$configfwdfw{$key}[15],$configfwdfw{$key}[18],$configfwdfw{$key}[19],$configfwdfw{$key}[20],$configfwdfw{$key}[21],$configfwdfw{$key}[22],$configfwdfw{$key}[23],$configfwdfw{$key}[24],$configfwdfw{$key}[25],$configfwdfw{$key}[26],$configfwdfw{$key}[27],$configfwdfw{$key}[28],$configfwdfw{$key}[29],$configfwdfw{$key}[30],$configfwdfw{$key}[31],$configfwdfw{$key}[32],$configfwdfw{$key}[33],$configfwdfw{$key}[34],$configfwdfw{$key}[35],$configfwdfw{$key}[36]"){
 -                                              $errormessage.=$Lang::tr{'fwdfw err ruleexists'};
 -                                              if($fwdfwsettings{'oldruleremark'} ne $fwdfwsettings{'ruleremark'} && $fwdfwsettings{'updatefwrule'} eq 'on' && $fwdfwsettings{'ruleremark'} ne '' && !&validremark($fwdfwsettings{'ruleremark'})){
 -                                                      $errormessage=$Lang::tr{'fwdfw err remark'}."<br>";
 -                                              }
 -                                              if($fwdfwsettings{'oldruleremark'} ne $fwdfwsettings{'ruleremark'} && $fwdfwsettings{'updatefwrule'} eq 'on' && $fwdfwsettings{'ruleremark'} ne '' && &validremark($fwdfwsettings{'ruleremark'})){
 -                                                      $errormessage='';
 -                                              }
 -                                              if ($fwdfwsettings{'oldruleremark'} eq $fwdfwsettings{'ruleremark'}){
 -                                                      $fwdfwsettings{'nosave'} = 'on';
 -                                              }
 -                              }
 +              $maxkey=&General::findhasharraykey(\%configfwdfw);
 +              %rulehash=%configfwdfw;
 +      }
 +      #check if we have an identical rule already
 +      if($fwdfwsettings{'oldrulenumber'} eq $fwdfwsettings{'rulepos'}){
 +              foreach my $key (sort keys %rulehash){
 +                      if (   "$fwdfwsettings{'RULE_ACTION'},$fwdfwsettings{'ACTIVE'},$fwdfwsettings{'grp1'},$fwdfwsettings{$fwdfwsettings{'grp1'}},$fwdfwsettings{'grp2'},$fwdfwsettings{$fwdfwsettings{'grp2'}},$fwdfwsettings{'USE_SRC_PORT'},$fwdfwsettings{'PROT'},$fwdfwsettings{'ICMP_TYPES'},$fwdfwsettings{'SRC_PORT'},$fwdfwsettings{'USESRV'},$fwdfwsettings{'TGT_PROT'},$fwdfwsettings{'ICMP_TGT'},$fwdfwsettings{'grp3'},$fwdfwsettings{$fwdfwsettings{'grp3'}},$fwdfwsettings{'ruleremark'},$fwdfwsettings{'LOG'},$fwdfwsettings{'TIME'},$fwdfwsettings{'TIME_MON'},$fwdfwsettings{'TIME_TUE'},$fwdfwsettings{'TIME_WED'},$fwdfwsettings{'TIME_THU'},$fwdfwsettings{'TIME_FRI'},$fwdfwsettings{'TIME_SAT'},$fwdfwsettings{'TIME_SUN'},$fwdfwsettings{'TIME_FROM'},$fwdfwsettings{'TIME_TO'},$fwdfwsettings{'USE_NAT'},$fwdfwsettings{$fwdfwsettings{'nat'}},$fwdfwsettings{'dnatport'},$fwdfwsettings{'nat'},$fwdfwsettings{'LIMIT_CON_CON'},$fwdfwsettings{'concon'},$fwdfwsettings{'RATE_LIMIT'},$fwdfwsettings{'ratecon'},$fwdfwsettings{'RATETIME'}"
 +                              eq "$rulehash{$key}[0],$rulehash{$key}[2],$rulehash{$key}[3],$rulehash{$key}[4],$rulehash{$key}[5],$rulehash{$key}[6],$rulehash{$key}[7],$rulehash{$key}[8],$rulehash{$key}[9],$rulehash{$key}[10],$rulehash{$key}[11],$rulehash{$key}[12],$rulehash{$key}[13],$rulehash{$key}[14],$rulehash{$key}[15],$rulehash{$key}[16],$rulehash{$key}[17],$rulehash{$key}[18],$rulehash{$key}[19],$rulehash{$key}[20],$rulehash{$key}[21],$rulehash{$key}[22],$rulehash{$key}[23],$rulehash{$key}[24],$rulehash{$key}[25],$rulehash{$key}[26],$rulehash{$key}[27],$rulehash{$key}[28],$rulehash{$key}[29],$rulehash{$key}[30],$rulehash{$key}[31],$rulehash{$key}[32],$rulehash{$key}[33],$rulehash{$key}[34],$rulehash{$key}[35],$rulehash{$key}[36]"){
 +                                      $errormessage.=$Lang::tr{'fwdfw err ruleexists'};
 +                                      if($fwdfwsettings{'oldruleremark'} ne $fwdfwsettings{'ruleremark'} && $fwdfwsettings{'updatefwrule'} eq 'on' && $fwdfwsettings{'ruleremark'} ne '' && !&validremark($fwdfwsettings{'ruleremark'})){
 +                                              $errormessage=$Lang::tr{'fwdfw err remark'}."<br>";
 +                                      }
 +                                      if($fwdfwsettings{'oldruleremark'} ne $fwdfwsettings{'ruleremark'} && $fwdfwsettings{'updatefwrule'} eq 'on' && $fwdfwsettings{'ruleremark'} ne '' && &validremark($fwdfwsettings{'ruleremark'})){
 +                                              $errormessage='';
 +                                      }
 +                                      if ($fwdfwsettings{'oldruleremark'} eq $fwdfwsettings{'ruleremark'}){
 +                                              $fwdfwsettings{'nosave'} = 'on';
 +                                      }
                        }
                }
 -              #check Rulepos on new Rule
 -              if($fwdfwsettings{'rulepos'} > 0 && !$fwdfwsettings{'oldrulenumber'}){
 -                      $fwdfwsettings{'oldrulenumber'}=$maxkey;
 -                      foreach my $key (sort keys %configfwdfw){
 -                              if (   "$fwdfwsettings{'RULE_ACTION'},$fwdfwsettings{'ACTIVE'},$fwdfwsettings{'grp1'},$fwdfwsettings{$fwdfwsettings{'grp1'}},$fwdfwsettings{'grp2'},$fwdfwsettings{$fwdfwsettings{'grp2'}},$fwdfwsettings{'USE_SRC_PORT'},$fwdfwsettings{'PROT'},$fwdfwsettings{'ICMP_TYPES'},$fwdfwsettings{'SRC_PORT'},$fwdfwsettings{'USESRV'},$fwdfwsettings{'TGT_PROT'},$fwdfwsettings{'ICMP_TGT'},$fwdfwsettings{'grp3'},$fwdfwsettings{$fwdfwsettings{'grp3'}},$fwdfwsettings{'TIME'},$fwdfwsettings{'TIME_MON'},$fwdfwsettings{'TIME_TUE'},$fwdfwsettings{'TIME_WED'},$fwdfwsettings{'TIME_THU'},$fwdfwsettings{'TIME_FRI'},$fwdfwsettings{'TIME_SAT'},$fwdfwsettings{'TIME_SUN'},$fwdfwsettings{'TIME_FROM'},$fwdfwsettings{'TIME_TO'},$fwdfwsettings{'USE_NAT'},$fwdfwsettings{$fwdfwsettings{'nat'}},$fwdfwsettings{'dnatport'},$fwdfwsettings{'nat'},$fwdfwsettings{'LIMIT_CON_CON'},$fwdfwsettings{'concon'},$fwdfwsettings{'RATE_LIMIT'},$fwdfwsettings{'ratecon'},$fwdfwsettings{'RATETIME'}"
 -                                      eq "$configfwdfw{$key}[0],$configfwdfw{$key}[2],$configfwdfw{$key}[3],$configfwdfw{$key}[4],$configfwdfw{$key}[5],$configfwdfw{$key}[6],$configfwdfw{$key}[7],$configfwdfw{$key}[8],$configfwdfw{$key}[9],$configfwdfw{$key}[10],$configfwdfw{$key}[11],$configfwdfw{$key}[12],$configfwdfw{$key}[13],$configfwdfw{$key}[14],$configfwdfw{$key}[15],$configfwdfw{$key}[18],$configfwdfw{$key}[19],$configfwdfw{$key}[20],$configfwdfw{$key}[21],$configfwdfw{$key}[22],$configfwdfw{$key}[23],$configfwdfw{$key}[24],$configfwdfw{$key}[25],$configfwdfw{$key}[26],$configfwdfw{$key}[27],$configfwdfw{$key}[28],$configfwdfw{$key}[29],$configfwdfw{$key}[30],$configfwdfw{$key}[31],$configfwdfw{$key}[32],$configfwdfw{$key}[33],$configfwdfw{$key}[34],$configfwdfw{$key}[35],$configfwdfw{$key}[36]"){
 -                                              $errormessage.=$Lang::tr{'fwdfw err ruleexists'};
 -                              }
 +      }
 +      #check Rulepos on new Rule
 +      if($fwdfwsettings{'rulepos'} > 0 && !$fwdfwsettings{'oldrulenumber'}){
 +              $fwdfwsettings{'oldrulenumber'}=$maxkey;
 +              foreach my $key (sort keys %rulehash){
 +                      if (   "$fwdfwsettings{'RULE_ACTION'},$fwdfwsettings{'ACTIVE'},$fwdfwsettings{'grp1'},$fwdfwsettings{$fwdfwsettings{'grp1'}},$fwdfwsettings{'grp2'},$fwdfwsettings{$fwdfwsettings{'grp2'}},$fwdfwsettings{'USE_SRC_PORT'},$fwdfwsettings{'PROT'},$fwdfwsettings{'ICMP_TYPES'},$fwdfwsettings{'SRC_PORT'},$fwdfwsettings{'USESRV'},$fwdfwsettings{'TGT_PROT'},$fwdfwsettings{'ICMP_TGT'},$fwdfwsettings{'grp3'},$fwdfwsettings{$fwdfwsettings{'grp3'}},$fwdfwsettings{'TIME'},$fwdfwsettings{'TIME_MON'},$fwdfwsettings{'TIME_TUE'},$fwdfwsettings{'TIME_WED'},$fwdfwsettings{'TIME_THU'},$fwdfwsettings{'TIME_FRI'},$fwdfwsettings{'TIME_SAT'},$fwdfwsettings{'TIME_SUN'},$fwdfwsettings{'TIME_FROM'},$fwdfwsettings{'TIME_TO'},$fwdfwsettings{'USE_NAT'},$fwdfwsettings{$fwdfwsettings{'nat'}},$fwdfwsettings{'dnatport'},$fwdfwsettings{'nat'},$fwdfwsettings{'LIMIT_CON_CON'},$fwdfwsettings{'concon'},$fwdfwsettings{'RATE_LIMIT'},$fwdfwsettings{'ratecon'},$fwdfwsettings{'RATETIME'}"
 +                              eq "$rulehash{$key}[0],$rulehash{$key}[2],$rulehash{$key}[3],$rulehash{$key}[4],$rulehash{$key}[5],$rulehash{$key}[6],$rulehash{$key}[7],$rulehash{$key}[8],$rulehash{$key}[9],$rulehash{$key}[10],$rulehash{$key}[11],$rulehash{$key}[12],$rulehash{$key}[13],$rulehash{$key}[14],$rulehash{$key}[15],$rulehash{$key}[18],$rulehash{$key}[19],$rulehash{$key}[20],$rulehash{$key}[21],$rulehash{$key}[22],$rulehash{$key}[23],$rulehash{$key}[24],$rulehash{$key}[25],$rulehash{$key}[26],$rulehash{$key}[27],$rulehash{$key}[28],$rulehash{$key}[29],$rulehash{$key}[30],$rulehash{$key}[31],$rulehash{$key}[32],$rulehash{$key}[33],$rulehash{$key}[34],$rulehash{$key}[35],$rulehash{$key}[36]"){
 +                                      $errormessage.=$Lang::tr{'fwdfw err ruleexists'};
                        }
                }
 -              #check if we just close a rule
 -              if( $fwdfwsettings{'oldgrp1a'} eq  $fwdfwsettings{'grp1'} && $fwdfwsettings{'oldgrp1b'} eq $fwdfwsettings{$fwdfwsettings{'grp1'}} && $fwdfwsettings{'oldgrp2a'} eq  $fwdfwsettings{'grp2'} && $fwdfwsettings{'oldgrp2b'} eq $fwdfwsettings{$fwdfwsettings{'grp2'}} &&  $fwdfwsettings{'oldgrp3a'} eq $fwdfwsettings{'grp3'} && $fwdfwsettings{'oldgrp3b'} eq  $fwdfwsettings{$fwdfwsettings{'grp3'}} && $fwdfwsettings{'oldusesrv'} eq $fwdfwsettings{'USESRV'} && $fwdfwsettings{'oldruleremark'} eq $fwdfwsettings{'ruleremark'} && $fwdfwsettings{'oldruletype'} eq $fwdfwsettings{'chain'}){
 -                      if($fwdfwsettings{'nosave'} eq 'on' && $fwdfwsettings{'updatefwrule'} eq 'on'){
 -                              $fwdfwsettings{'nosave2'} = 'on';
 -                              $errormessage='';
 -                      }
 +      }
 +      #check if we just close a rule
 +      if( $fwdfwsettings{'oldgrp1a'} eq  $fwdfwsettings{'grp1'} && $fwdfwsettings{'oldgrp1b'} eq $fwdfwsettings{$fwdfwsettings{'grp1'}} && $fwdfwsettings{'oldgrp2a'} eq  $fwdfwsettings{'grp2'} && $fwdfwsettings{'oldgrp2b'} eq $fwdfwsettings{$fwdfwsettings{'grp2'}} &&  $fwdfwsettings{'oldgrp3a'} eq $fwdfwsettings{'grp3'} && $fwdfwsettings{'oldgrp3b'} eq  $fwdfwsettings{$fwdfwsettings{'grp3'}} && $fwdfwsettings{'oldusesrv'} eq $fwdfwsettings{'USESRV'} && $fwdfwsettings{'oldruleremark'} eq $fwdfwsettings{'ruleremark'} && $fwdfwsettings{'oldruletype'} eq $fwdfwsettings{'chain'}){
 +              if($fwdfwsettings{'nosave'} eq 'on' && $fwdfwsettings{'updatefwrule'} eq 'on'){
 +                      $fwdfwsettings{'nosave2'} = 'on';
 +                      $errormessage='';
                }
 -              #check max concurrent connections per ip address
 -              if ($fwdfwsettings{'LIMIT_CON_CON'} eq 'ON'){
 -                      if (!($fwdfwsettings{'concon'} =~ /^(\d+)$/)) {
 -                              $errormessage.=$Lang::tr{'fwdfw err concon'};
 -                      }
 -              }else{
 -                      $fwdfwsettings{'concon'}='';
 +      }
 +      #check max concurrent connections per ip address
 +      if ($fwdfwsettings{'LIMIT_CON_CON'} eq 'ON'){
 +              if (!($fwdfwsettings{'concon'} =~ /^(\d+)$/)) {
 +                      $errormessage.=$Lang::tr{'fwdfw err concon'};
                }
 -              #check ratelimit value
 -              if ($fwdfwsettings{'RATE_LIMIT'} eq 'ON'){
 -                      if (!($fwdfwsettings{'ratecon'} =~ /^(\d+)$/)) {
 -                              $errormessage.=$Lang::tr{'fwdfw err ratecon'};
 -                      }
 -              }else{
 -                      $fwdfwsettings{'ratecon'}='';
 +      }else{
 +              $fwdfwsettings{'concon'}='';
 +      }
 +      #check ratelimit value
 +      if ($fwdfwsettings{'RATE_LIMIT'} eq 'ON'){
 +              if (!($fwdfwsettings{'ratecon'} =~ /^(\d+)$/)) {
 +                      $errormessage.=$Lang::tr{'fwdfw err ratecon'};
                }
 -              #increase counters
 -              if (!$errormessage){
 -                      if ($fwdfwsettings{'nosave2'} ne 'on'){
 -                              &saverule(\%configfwdfw,$configfwdfw);
 -                      }
 +      }else{
 +              $fwdfwsettings{'ratecon'}='';
 +      }
 +      #increase counters
 +      if (!$errormessage){
 +              if ($fwdfwsettings{'nosave2'} ne 'on'){
 +                      &saverule(\%rulehash,$fwdfwsettings{'config'});
                }
        }
        if ($errormessage){
@@@ -790,7 -868,7 +793,7 @@@ sub checkrul
                $errormessage.=$Lang::tr{'fwdfw err remark'}."<br>";
        }
        #check if source and target identical
 -      if ($fwdfwsettings{$fwdfwsettings{'grp1'}} eq $fwdfwsettings{$fwdfwsettings{'grp2'}} && $fwdfwsettings{$fwdfwsettings{'grp1'}} ne 'ALL'){
 +      if ($fwdfwsettings{$fwdfwsettings{'grp1'}} eq $fwdfwsettings{$fwdfwsettings{'grp2'}} && $fwdfwsettings{$fwdfwsettings{'grp1'}} ne 'ALL' && $fwdfwsettings{'grp2'} ne 'ipfire'){
                $errormessage=$Lang::tr{'fwdfw err same'};
                return $errormessage;
        }
                }
                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
@@@ -1397,6 -1523,7 +1448,7 @@@ sub newrul
        &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=();
                                }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'){
                                }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'){
                        #RULE ACTIVE
                        if($$hash{$key}[2] eq 'ON'){
                                $gif="/images/on.gif"
-                               
                        }else{
                                $gif="/images/off.gif"
                        }
diff --combined html/cgi-bin/fwhosts.cgi
index f42947e8c7e99d056375fbd8165801ea9c68db44,395dca83c62fcac72058f72db07b5b0168dfc410..8aedd8a22c49236d7a0faead5cef00ea9e65f1e5
@@@ -27,6 -27,8 +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 +38,7 @@@ my %customhost=()
  my %customgrp=();
  my %customservice=();
  my %customservicegrp=();
+ my %customgeoipgrp=();
  my %ccdnet=();
  my %ccdhost=();
  my %ipsecconf=();
@@@ -62,6 -65,7 +65,7 @@@ my $configccdhost     = "${General::swroot}
  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 +77,7 @@@ unless (-e $confighost)   { system("tou
  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 +676,84 @@@ if ($fwhostsettings{'ACTION'} eq 'saveg
                &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;
@@@ -728,10 -811,10 +811,10 @@@ if ($fwhostsettings{'ACTION'} eq 'saves
                        }
                }
        }
 -      if ($tcpcounter > 15){
 +      if ($tcpcounter > 14){
                $errormessage=$Lang::tr{'fwhost err maxservicetcp'};
        }
 -      if ($udpcounter > 15){
 +      if ($udpcounter > 14){
                $errormessage=$Lang::tr{'fwhost err maxserviceudp'};
        }
        $tcpcounter=0;
@@@ -798,6 -881,12 +881,12 @@@ if ($fwhostsettings{'ACTION'} eq 'editg
        &addgrp;
        &viewtablegrp;
  }
+ if ($fwhostsettings{'ACTION'} eq 'editgeoipgrp')
+ {
+       $fwhostsettings{'update'}='on';
+       &addgeoipgrp;
+       &viewtablegeoipgrp;
+ }
  if ($fwhostsettings{'ACTION'} eq 'editservice')
  {
        $fwhostsettings{'updatesrv'}='on';
@@@ -830,6 -919,12 +919,12 @@@ if ($fwhostsettings{'ACTION'} eq 'reset
        $fwhostsettings{'remark'}       ="";
        &showmenu;
  }
+ if ($fwhostsettings{'ACTION'} eq 'resetgeoipgrp')
+ {
+       $fwhostsettings{'grp_name'} ="";
+       $fwhostsettings{'remark'}       ="";
+       &showmenu;
+ }
  # delete
  if ($fwhostsettings{'ACTION'} eq 'delnet')
  {
@@@ -887,6 -982,37 +982,37 @@@ if ($fwhostsettings{'ACTION'} eq 'delet
        &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);
        &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 +1119,11 @@@ if ($fwhostsettings{'ACTION'} eq $Lang:
        &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 +1158,31 @@@ if ($fwhostsettings{'ACTION'} eq 'chang
        &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 +1257,29 @@@ if ($fwhostsettings{'ACTION'} eq 'chang
        &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 +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
                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 +2140,195 @@@ sub viewtablegr
        &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 +2687,44 @@@ sub gethostcoun
        }
        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 --combined langs/en/cgi-bin/en.pl
index 8c049fffa987fa0af6dcceefe0498caf418cc7a8,fa014a92f9d3ca23e4c7fe82e3dd6cfaf5c44825..d8cb5aa67a9eb7d4798ae9aee84db7630f222f8c
  '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',
  'ike grouptype' => 'IKE Grouptype:',
  'ike integrity' => 'IKE Integrity:',
  'ike lifetime' => 'IKE Lifetime:',
 -'ike lifetime should be between 1 and 8 hours' => 'IKE lifetime should be between 1 and 8 hours.',
 +'ike lifetime should be between 1 and 24 hours' => 'IKE lifetime should be between 1 and 24 hours.',
  'imei' => 'IMEI',
  'import' => 'Import',
  'importkey' => 'Import PSK',
  'inactive' => 'inactive',
  'include logfiles' => 'Include logfiles',
  'incoming' => 'incoming',
 +'incoming compression in bytes per second' => 'Incoming Compression',
  'incoming firewall access' => 'Incoming Firewall Access',
 +'incoming overhead in bytes per second' => 'Incoming Overhead',
  'incoming traffic in bytes per second' => 'Incoming Traffic',
  'incorrect password' => 'Incorrect password',
  'info' => 'Info',
  'invalid input for organization' => 'Invalid input for organization',
  'invalid input for remote host/ip' => 'Invalid input for remote host/ip.',
  'invalid input for state or province' => 'Invalid input for state or province.',
 +'invalid input for valid till days' => 'Invalid input for Valid till (days).',
  'invalid ip' => 'Invalid IP Address',
  'invalid keep time' => 'Keep time must be a valid number',
  'invalid key' => 'Invalid key.',
  'our donors' => 'Our donors',
  'out' => 'Out',
  'outgoing' => 'outgoing',
 +'outgoing compression in bytes per second' => 'Outgoing compression',
  'outgoing firewall' => 'Outgoing Firewall',
  'outgoing firewall access' => 'Outgoing Firewall Access',
  'outgoing firewall add ip group' => 'Add IP Address Group',
  'outgoing firewall reset' => 'Reset all',
  'outgoing firewall view group' => 'View group',
  'outgoing firewall warning' => 'Not selecting source ip or mac ignores them',
 +'outgoing overhead in bytes per second' => 'Outgoing Overhead',
  'outgoing traffic in bytes per second' => 'Outgoing Traffic',
  'override mtu' => 'Override default MTU',
  'ovpn' => 'OpenVPN',
 +'ovpn add conf' => 'Additional configuration',
  'ovpn con stat' => 'OpenVPN Connection Statistics',
  'ovpn config' => 'OVPN-Config',
  'ovpn crypt options' => 'Cryptographic options',
  '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',
diff --combined make.sh
index 7d41b591c27ed551fbbd9ccd5dcea31345014005,9f77df59bebf7fe9846fbe56bfdfb2473e2b6006..395c21f2d7a524e76c43640b4ca6cb10657b51ac
+++ b/make.sh
@@@ -25,8 -25,8 +25,8 @@@
  NAME="IPFire"                                                 # Software name
  SNAME="ipfire"                                                        # Short name
  VERSION="2.17"                                                        # Version number
 -CORE="87-rc1"                                                 # Core Level (Filename)
 -PAKFIRE_CORE="86"                                             # Core Level (PAKFIRE)
 +CORE="87"                                                     # Core Level (Filename)
 +PAKFIRE_CORE="87"                                             # Core Level (PAKFIRE)
  GIT_BRANCH=`git rev-parse --abbrev-ref HEAD`                  # Git Branch
  SLOGAN="www.ipfire.org"                                               # Software slogan
  CONFIG_ROOT=/var/ipfire                                               # Configuration rootdir
@@@ -383,6 -383,7 +383,7 @@@ buildipfire() 
    export LOGFILE
    ipfiremake configroot
    ipfiremake backup
+   ipfiremake pkg-config
    ipfiremake libusb
    ipfiremake libusbx
    ipfiremake libpcap
    ipfiremake multipath-tools
    ipfiremake freetype
    ipfiremake grub
+   ipfiremake libmnl
+   ipfiremake iptables
  
    case "${TARGET_ARCH}" in
        i586)
                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
                ipfiremake e1000e                       KCFG=""
                ipfiremake igb                          KCFG=""
                ipfiremake ixgbe                        KCFG=""
+               ipfiremake xtables-addons               KCFG=""
                ipfiremake linux-initrd                 KCFG=""
                ;;
  
                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
                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
                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
    ipfiremake mtools
    ipfiremake initscripts
    ipfiremake whatmask
-   ipfiremake libmnl
-   ipfiremake iptables
    ipfiremake conntrack-tools
    ipfiremake libupnp
    ipfiremake ipaddr
    ipfiremake lm_sensors
    ipfiremake liboping
    ipfiremake collectd
 -  ipfiremake teamspeak
    ipfiremake elinks
    ipfiremake igmpproxy
    ipfiremake fbset
    ipfiremake iftop
    ipfiremake motion
    ipfiremake joe
 +  ipfiremake monit
    ipfiremake nut
    ipfiremake watchdog
    ipfiremake libpri
 +  ipfiremake libsrtp
    ipfiremake asterisk
    ipfiremake lcr
    ipfiremake usb_modeswitch
    ipfiremake squid-accounting
    ipfiremake pigz
    ipfiremake tmux
+   ipfiremake perl-Text-CSV_XS
    ipfiremake swconfig
 +  ipfiremake haproxy
  }
  
  buildinstaller() {