X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=config%2Ffirewall%2Frules.pl;h=a47c260a152647ab9c740578d4e3c0f27beb0d0a;hb=HEAD;hp=50feafa3bee11d5d3f3f0b217851ca7724ed6dca;hpb=39eba7abab657959a3057a8cc0140f53db328f95;p=ipfire-2.x.git diff --git a/config/firewall/rules.pl b/config/firewall/rules.pl index 50feafa3be..e38f772428 100644 --- a/config/firewall/rules.pl +++ b/config/firewall/rules.pl @@ -2,7 +2,7 @@ ############################################################################### # # # IPFire.org - A linux based firewall # -# Copyright (C) 2007-2020 IPFire Team # +# Copyright (C) 2007-2024 IPFire Team # # # # 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 # @@ -55,6 +55,7 @@ my @PRIVATE_NETWORKS = ( "172.16.0.0/12", "192.168.0.0/16", "100.64.0.0/10", + "224.0.0.0/4", ); # MARK masks @@ -296,6 +297,9 @@ sub buildrules { $NAT_MODE = uc($$hash{$key}[31]); } + # Enable SYN flood protection? + my $SYN_FLOOD_PROTECTION = 0; + # Set up time constraints. my @time_options = (); if ($$hash{$key}[18] eq 'ON') { @@ -369,6 +373,11 @@ sub buildrules { } } + # DoS Protection + if (($elements ge 38) && ($$hash{$key}[37] eq "ON")) { + $SYN_FLOOD_PROTECTION = 1; + } + # Check which protocols are used in this rule and so that we can # later group rules by protocols. my @protocols = &get_protocols($hash, $key); @@ -401,6 +410,9 @@ sub buildrules { $source = ""; } + # Make sure that $source is properly defined + next unless (defined $source); + my $source_intf = @$src[1]; foreach my $dst (@destinations) { @@ -604,6 +616,10 @@ sub buildrules { } run("$IPTABLES -A $chain @options @source_intf_options @destination_intf_options -j $target"); + if ($SYN_FLOOD_PROTECTION && ($protocol eq "tcp")) { + run("$IPTABLES -t raw -A SYN_FLOOD_PROTECT @options -j CT --notrack"); + } + # Handle forwarding rules and add corresponding rules for firewall access. if ($chain eq $CHAIN_FORWARD) { # If the firewall is part of the destination subnet and access to the destination network @@ -722,8 +738,8 @@ sub drop_hostile_networks () { &ipset_restore($HOSTILE_CCODE); # Check traffic in incoming/outgoing direction and drop if it matches - run("$IPTABLES -A HOSTILE -i $RED_DEV -m set --match-set $HOSTILE_CCODE src -j HOSTILE_DROP"); - run("$IPTABLES -A HOSTILE -o $RED_DEV -m set --match-set $HOSTILE_CCODE dst -j HOSTILE_DROP"); + run("$IPTABLES -A HOSTILE -i $RED_DEV -m set --match-set $HOSTILE_CCODE src -j HOSTILE_DROP_IN"); + run("$IPTABLES -A HOSTILE -o $RED_DEV -m set --match-set $HOSTILE_CCODE dst -j HOSTILE_DROP_OUT"); } sub ipblocklist () { @@ -731,35 +747,56 @@ sub ipblocklist () { run("$IPTABLES -F BLOCKLISTIN"); run("$IPTABLES -F BLOCKLISTOUT"); - # If the blocklist feature is disabled we are finished here. - if($blocklistsettings{'ENABLE'} ne "on") { - # Bye. - return; + # Check if the blocklist feature is enabled. + if($blocklistsettings{'ENABLE'} eq "on") { + # Loop through the array of private networks. + foreach my $private_network (@PRIVATE_NETWORKS) { + # Create firewall rules to never block private networks. + run("$IPTABLES -A BLOCKLISTIN -p ALL -i $RED_DEV -s $private_network -j RETURN"); + run("$IPTABLES -A BLOCKLISTOUT -p ALL -o $RED_DEV -d $private_network -j RETURN"); + } } # Loop through the array of blocklists. foreach my $blocklist (@blocklists) { - # Skip disabled blocklists. - next unless($blocklistsettings{$blocklist}) && ($blocklistsettings{$blocklist} eq "on")); + # Check if the blocklist feature and the current processed blocklist is enabled. + if(($blocklistsettings{'ENABLE'} eq "on") && ($blocklistsettings{$blocklist}) && ($blocklistsettings{$blocklist} eq "on")) { + # Call function to load the blocklist. + &ipset_restore($blocklist); + + # Call function to check if the corresponding iptables drop chain already has been created. + if(&firewall_chain_exists("${blocklist}_DROP")) { + # Create iptables chain. + run("$IPTABLES -N ${blocklist}_DROP"); + } else { + # Flush the chain. + run("$IPTABLES -F ${blocklist}_DROP"); + } - # Call function to load the blocklist. - &ipset_restore($blocklist); + # Check if logging is enabled. + if(($blocklistsettings{'LOGGING'}) && ($blocklistsettings{'LOGGING'} eq "on")) { + # Create logging rule. + run("$IPTABLES -A ${blocklist}_DROP -j LOG -m limit --limit 10/second --log-prefix \"BLKLST_$blocklist \""); + } - # Create iptables chain. - run("$IPTABLES -N ${blocklist}_DROP"); + # Create Drop rule. + run("$IPTABLES -A ${blocklist}_DROP -j DROP"); - # Check if logging is enables. - if($blocklistsettings{'LOGGING'} eq "on") { - # Create logging rule. - run("$IPTABLES -A ${blocklist}_DROP -j LOG -m limit --limit 10/second --log-prefix \"BLKLST_$blocklist\" "); - } + # Add the rules to check against the set + run("$IPTABLES -A BLOCKLISTIN -p ALL -i $RED_DEV -m set --match-set $blocklist src -j ${blocklist}_DROP"); + run("$IPTABLES -A BLOCKLISTOUT -p ALL -o $RED_DEV -m set --match-set $blocklist dst -j ${blocklist}_DROP"); - # Create Drop rule. - run("$IPTABLES A ${blocklist}_DROP -j DROP"); + # IP blocklist or the blocklist is disabled. + } else { + # Check if the blocklist related iptables drop chain exits. + unless(&firewall_chain_exists("${blocklist}_DROP")) { + # Flush the chain. + run("$IPTABLES -F ${blocklist}_DROP"); - # Add the rules to check against the set - run("$IPTABLES -A BLOCKLISTIN -p ALL -i $RED_DEV -m set --match-set $blocklist src -j ${blocklist}_DROP"); - run("$IPTABLES -A BLOCKLISTOUT -p ALL -o $RED_DEV -m set --match-set $blocklist dst -j ${blocklist}_DROP"); + # Drop the chain. + run("$IPTABLES -X ${blocklist}_DROP"); + } + } } } @@ -976,6 +1013,14 @@ sub firewall_is_in_subnet { return 0; } +sub firewall_chain_exists ($) { + my ($chain) = @_; + + my $ret = &General::system("iptables", "--wait", "-n", "-L", "$chain"); + + return $ret; +} + sub ipset_get_sets () { my @sets; @@ -1044,11 +1089,23 @@ sub ipset_restore ($) { # Check if the given set name is a blocklist. } elsif ($set ~~ @blocklists) { + # IPblocklist sets contains v4 as setname extension. + my $set_name = "$set" . "v4"; + # Get the database file for the given blocklist. my $db_file = &IPblocklist::get_ipset_db_file($set); # Call function to restore/load the set. &ipset_call_restore($db_file); + + # Check if the set is already loaded (has been used before). + if ($set ~~ @ipset_used_sets) { + # Swap the sets. + run("$IPSET swap $set_name $set"); + } else { + # Rename the set to proper use it. + run("$IPSET rename $set_name $set"); + } } # Store the restored set to the hash to prevent from loading it again.