Add IPv6 support to IPtables module.
authorStefan Schantl <stefan.schantl@ipfire.org>
Wed, 3 Feb 2016 13:53:13 +0000 (14:53 +0100)
committerStefan Schantl <stefan.schantl@ipfire.org>
Wed, 3 Feb 2016 13:53:13 +0000 (14:53 +0100)
When using IPtables as firewall engine, now IPv6
addresses also can be handled in a proper way.

To do this, the correct iptables helper binary will be choosen,
based on the IP address which should be (un)blocked and executed.

Signed-off-by: Stefan Schantl <stefan.schantl@ipfire.org>
modules/Base.pm
modules/IPtables.pm

index 1aa1d2f..f29f543 100644 (file)
@@ -4,7 +4,7 @@ use warnings;
 
 use Exporter qw(import);
 
 
 use Exporter qw(import);
 
-our @EXPORT_OK = qw(GenerateMonitoredFiles FilePositions);
+our @EXPORT_OK = qw(GenerateMonitoredFiles DetectIPProtocolVersion FilePositions);
 
 use Net::IP;
 
 
 use Net::IP;
 
@@ -172,6 +172,22 @@ sub IPOrNet2Int($) {
        }
 }
 
        }
 }
 
+#
+## DetectIPProtocolVersion function.
+#
+## Wrapper function for determining the used protocol version (4/6)
+## for a given IP address.
+#
+sub DetectIPProtocolVersion ($) {
+       my $address = shift;
+
+       # Call external perl module to detect the used IP protocol version.
+       my $version = &Net::IP::ip_get_version($address);
+
+       # Return the detected version.
+       return $version;
+}
+
 #
 ## Function for fileposition initialization.
 #
 #
 ## Function for fileposition initialization.
 #
index 7395d3e..7dafeba 100644 (file)
@@ -9,8 +9,16 @@ our @EXPORT = qw(DoBlock DoUnblock DoFlush);
 # Array of supported block actions.
 my @supported_actions = ("DROP", "REJECT");
 
 # Array of supported block actions.
 my @supported_actions = ("DROP", "REJECT");
 
-# The path to the iptables executeable.
-my $iptables = "/usr/sbin/iptables";
+# Path where the IPtables related binaries are stored.
+my $bindir = "/usr/sbin/";
+
+# Hash which contains the path to the IPtables binaries,
+# based on the used IP protocol version. IPtables is
+# designed to use different binaries for IPv4 and IPv6.
+my %binaries = (
+       "4" => "iptables",
+       "6" => "ip6tables",
+);
 
 # The used firewall chain.
 my $chain = "INPUT";
 
 # The used firewall chain.
 my $chain = "INPUT";
@@ -34,14 +42,20 @@ sub DoBlock (@) {
        }
 
        # Check if the given action is supported.
        }
 
        # Check if the given action is supported.
-       my $error = &_check_action($action);
+       unless(&_check_action($action)) {
+               # Abort and return an error message.
+               return "Unsupported action: $action";
+       }
+
+       # Obtain which binary should be executed.
+       my $iptables = &_omit_binary($address);
 
 
-       # Abort and return the recieved error.
-       if ($error) {
-               return $error;
+       # Abort if no suitable binary could be obtained.
+       unless ($iptables) {
+               return "No suitable binary found.";
        }
 
        }
 
-       # Call iptables to block the given address.
+       # Call IPtables binary to block the given address.
        system("$iptables --wait -A $chain -s $address -j $action");
 }
 
        system("$iptables --wait -A $chain -s $address -j $action");
 }
 
@@ -63,8 +77,16 @@ sub DoBlock (@) {
 sub DoUnblock ($) {
        my ($address) = @_;
 
 sub DoUnblock ($) {
        my ($address) = @_;
 
+       # Obtain which binary should be executed.
+       my $iptables = &_omit_binary($address);
+
+       # Abort if no suitable binary could be obtained.
+       unless($iptables) {
+               return "No suitable binary found.";
+       }
+
        # Get rulepositions for the specified address.
        # Get rulepositions for the specified address.
-       my @rules = &_get_rules_positions_by_address($address);
+       my @rules = &_get_rules_positions_by_address($address, $iptables);
 
        # Loop through the rules array and drop the firewall rules.
        foreach my $rule (@rules) {
 
        # Loop through the rules array and drop the firewall rules.
        foreach my $rule (@rules) {
@@ -76,11 +98,21 @@ sub DoUnblock ($) {
 #
 ## The DoFlush subroutine.
 #
 #
 ## The DoFlush subroutine.
 #
-## Call this subroutine to entirely flush the IPtables chain.
+## Call this subroutine to entirely flush the IPtables chains for each
+## supported protocol version.
 #
 sub DoFlush () {
 #
 sub DoFlush () {
-       # Call iptalbes and flush the chain.
-       system("$iptables --wait -F $chain");
+       # Loop through the binaries hash to flush 
+       foreach my $key (keys %binaries) {
+               # Grab binary from hash and generate the absolute path
+               # to the binary.
+               my $iptables = join ("/", $bindir,$binaries{$key});
+
+               # Execute the binary if avail- and executeable.
+               if (-x $iptables) {
+                       system("$iptables --wait -F $chain");
+               }
+       }
 }
 
 #
 }
 
 #
@@ -90,8 +122,8 @@ sub DoFlush () {
 ## firewall rules for a given address. Those position will be collected
 ## and returned in reversed order. 
 #
 ## firewall rules for a given address. Those position will be collected
 ## and returned in reversed order. 
 #
-sub _get_rules_positions_by_address ($) {
-       my ($address) = @_;
+sub _get_rules_positions_by_address ($$) {
+       my ($address, $iptables) = @_;
 
        # Array to store the rule positions.
        my @rules;
 
        # Array to store the rule positions.
        my @rules;
@@ -132,19 +164,53 @@ sub _get_rules_positions_by_address ($) {
 ## the firewall engine.
 #
 sub _check_action ($) {
 ## the firewall engine.
 #
 sub _check_action ($) {
-       my $action = $_[0];
+       my $action = shift;
 
        # Check if the recieved action is part of the supported_actions array.
        foreach my $item (@supported_actions) {
                # Exit the loop and return "nothing" if we found a match.
                if($item eq $action) {
 
        # Check if the recieved action is part of the supported_actions array.
        foreach my $item (@supported_actions) {
                # Exit the loop and return "nothing" if we found a match.
                if($item eq $action) {
-                       return;
+                       # Return "1" (True).
+                       return 1;
                }
        }
 
        # If we got here, the given action is not part of the array of supported
                }
        }
 
        # If we got here, the given action is not part of the array of supported
-       # actions. Return an error message.
-       return "Unsupported action: $action";
+       # actions. Return nothing (False).
+       return;
+}
+
+#
+## The _omit_binary function.
+#
+## This private function is responsible for selecting and returning the correct
+## IPtables binary, based on which kind of IP address has been given.
+#
+sub _omit_binary ($) {
+       my $address = shift;
+
+       # Obtain used protocol version, based on the
+       # given IP address.
+       my $proto_version = &Guardian::Base::DetectIPProtocolVersion($address);
+
+       # Abort if the protocol version could not proper be detected.
+       unless ($proto_version) {
+               # Return nothing (False).
+               return;
+       }
+
+       # Obtain which binary is responsible, based on the detected protocol version and
+       # generate the full path to it.
+       my $binary = join("/",$bindir,$binaries{$proto_version});
+
+       # Abort if the obtained binary is not avail- or executeable.
+       unless (-x $binary) {
+               # Return nothing (False).
+               return;
+       }
+
+       # Return the detected and validated binary.
+       return $binary;
 }
 
 1;
 }
 
 1;