From 345e62e2aba53d139fb752e73d897c23758407f4 Mon Sep 17 00:00:00 2001 From: Stefan Schantl Date: Wed, 3 Feb 2016 14:53:13 +0100 Subject: [PATCH] Add IPv6 support to IPtables module. 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 --- modules/Base.pm | 18 +++++++- modules/IPtables.pm | 100 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 100 insertions(+), 18 deletions(-) diff --git a/modules/Base.pm b/modules/Base.pm index 1aa1d2f..f29f543 100644 --- a/modules/Base.pm +++ b/modules/Base.pm @@ -4,7 +4,7 @@ use warnings; use Exporter qw(import); -our @EXPORT_OK = qw(GenerateMonitoredFiles FilePositions); +our @EXPORT_OK = qw(GenerateMonitoredFiles DetectIPProtocolVersion FilePositions); 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. # diff --git a/modules/IPtables.pm b/modules/IPtables.pm index 7395d3e..7dafeba 100644 --- a/modules/IPtables.pm +++ b/modules/IPtables.pm @@ -9,8 +9,16 @@ our @EXPORT = qw(DoBlock DoUnblock DoFlush); # 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"; @@ -34,14 +42,20 @@ sub DoBlock (@) { } # 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"); } @@ -63,8 +77,16 @@ sub DoBlock (@) { 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. - 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) { @@ -76,11 +98,21 @@ sub DoUnblock ($) { # ## 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 () { - # 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. # -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; @@ -132,19 +164,53 @@ sub _get_rules_positions_by_address ($) { ## 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) { - return; + # Return "1" (True). + return 1; } } # 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; -- 2.39.2