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";
# Load P2P block rules.
&p2pblock();
+ # Load GeoIP block rules.
+ &geoipblock();
+
# Reload firewall policy.
run("/usr/sbin/firewall-policy");
}
print "\n";
}
+sub count_elements {
+ my $hash = shift;
+
+ return scalar @$hash;
+}
+
sub flush {
run("$IPTABLES -F $CHAIN_INPUT");
run("$IPTABLES -F $CHAIN_FORWARD");
# Skip disabled rules.
next unless ($$hash{$key}[2] eq 'ON');
+ # Count number of elements in this line
+ my $elements = &count_elements($$hash{$key});
+
if ($DEBUG) {
print_rule($$hash{$key});
}
}
}
+ # Concurrent connection limit
+ my @ratelimit_options = ();
+
+ if (($elements ge 34) && ($$hash{$key}[32] eq 'ON')) {
+ my $conn_limit = $$hash{$key}[33];
+
+ if ($conn_limit ge 1) {
+ push(@ratelimit_options, ("-m", "connlimit"));
+
+ # Use the the entire source IP address
+ push(@ratelimit_options, "--connlimit-saddr");
+ push(@ratelimit_options, ("--connlimit-mask", "32"));
+
+ # Apply the limit
+ push(@ratelimit_options, ("--connlimit-upto", $conn_limit));
+ }
+ }
+
+ # Ratelimit
+ if (($elements ge 37) && ($$hash{$key}[34] eq 'ON')) {
+ my $rate_limit = "$$hash{$key}[35]/$$hash{$key}[36]";
+
+ if ($rate_limit) {
+ push(@ratelimit_options, ("-m", "limit"));
+ push(@ratelimit_options, ("--limit", $rate_limit));
+ }
+ }
+
# Check which protocols are used in this rule and so that we can
# later group rules by protocols.
my @protocols = &get_protocols($hash, $key);
foreach my $src (@sources) {
# Skip invalid source.
+ next unless (defined $src);
next unless ($src);
# Sanitize source.
- my $source = $src;
+ my $source = @$src[0];
if ($source ~~ @ANY_ADDRESSES) {
$source = "";
}
+ my $source_intf = @$src[1];
+
foreach my $dst (@destinations) {
# Skip invalid rules.
+ next unless (defined $dst);
next if (!$dst || ($dst eq "none"));
# Sanitize destination.
- my $destination = $dst;
+ my $destination = @$dst[0];
if ($destination ~~ @ANY_ADDRESSES) {
$destination = "";
}
+ my $destination_intf = @$dst[1];
+
# Array with iptables arguments.
my @options = ();
# Add time constraint options.
push(@options, @time_options);
+ # Add ratelimiting option
+ push(@options, @ratelimit_options);
+
my $firewall_is_in_source_subnet = 1;
if ($source) {
$firewall_is_in_source_subnet = &firewall_is_in_subnet($source);
# Make port-forwardings useable from the internal networks.
my @internal_addresses = &fwlib::get_internal_firewall_ip_addresses(1);
unless ($nat_address ~~ @internal_addresses) {
- &add_dnat_mangle_rules($nat_address, @nat_options);
+ &add_dnat_mangle_rules($nat_address, $source_intf, @nat_options);
}
push(@nat_options, @source_options);
}
}
+ # Add source and destination interface to the filter rules.
+ # These are supposed to help filtering forged packets that originate
+ # from BLUE with an IP address from GREEN for instance.
+ if ($source_intf) {
+ push(@source_options, ("-i", $source_intf));
+ }
+
+ if ($destination_intf) {
+ push(@destination_options, ("-o", $destination_intf));
+ }
+
push(@options, @source_options);
push(@options, @destination_options);
}
}
}
+ #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.
}
sub p2pblock {
- my $search_action;
- my $target;
-
- if ($fwdfwsettings{"POLICY"} eq "MODE1") {
- $search_action = "on";
- $target = "ACCEPT";
- } else {
- $search_action = "off";
- $target = "DROP";
- }
-
open(FILE, "<$p2pfile") or die "Unable to read $p2pfile";
my @protocols = ();
foreach my $p2pentry (<FILE>) {
my @p2pline = split(/\;/, $p2pentry);
- next unless ($p2pline[2] eq $search_action);
+ next unless ($p2pline[2] eq "off");
push(@protocols, "--$p2pline[1]");
}
close(FILE);
+ run("$IPTABLES -F P2PBLOCK");
if (@protocols) {
- run("$IPTABLES -A FORWARDFW -m ipp2p @protocols -j $target");
+ run("$IPTABLES -A P2PBLOCK -m ipp2p @protocols -j DROP");
+ }
+}
+
+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 add_dnat_mangle_rules {
my $nat_address = shift;
+ my $interface = shift;
my @options = @_;
my $mark = 0;
next unless (exists $defaultNetworks{$zone . "_NETADDRESS"});
next unless (exists $defaultNetworks{$zone . "_NETMASK"});
+ next if ($interface && $interface ne $defaultNetworks{$zone . "_DEV"});
+
my @mangle_options = @options;
my $netaddress = $defaultNetworks{$zone . "_NETADDRESS"};