From 48f07c195761d0c7129b6beb314c339ba7164eaf Mon Sep 17 00:00:00 2001 From: Alexander Marx Date: Fri, 18 Jul 2014 08:44:45 +0200 Subject: [PATCH] Firewall: make DNAT only accessible from selected source network We added RED to the standard networks and now portforwardings are only useable from the selected source. If selected "all" the portforwarding can be used from any internal network. Else the access is only grnated from the selected source network. --- config/firewall/firewall-lib.pl | 53 ++++++++++++++++++++++----------- config/firewall/rules.pl | 25 ++++++++++++---- html/cgi-bin/firewall.cgi | 1 - html/cgi-bin/fwhosts.cgi | 8 ++++- 4 files changed, 63 insertions(+), 24 deletions(-) diff --git a/config/firewall/firewall-lib.pl b/config/firewall/firewall-lib.pl index c4a19e5d80..9b3f2bff43 100755 --- a/config/firewall/firewall-lib.pl +++ b/config/firewall/firewall-lib.pl @@ -217,7 +217,7 @@ sub get_std_net_ip }elsif($val eq 'BLUE'){ return "$netsettings{'BLUE_NETADDRESS'}/$netsettings{'BLUE_NETMASK'}"; }elsif($val eq 'RED'){ - return "0.0.0.0/0 -o $con"; + return "0.0.0.0/0"; }elsif($val =~ /OpenVPN/i){ return "$ovpnsettings{'DOVPN_SUBNET'}"; }elsif($val =~ /IPsec/i){ @@ -226,6 +226,23 @@ sub get_std_net_ip return ; } } +sub get_interface +{ + my $net=shift; + if($net eq "$netsettings{'GREEN_NETADDRESS'}/$netsettings{'GREEN_NETMASK'}"){ + return "$netsettings{'GREEN_DEV'}"; + } + if($net eq "$netsettings{'ORANGE_NETADDRESS'}/$netsettings{'ORANGE_NETMASK'}"){ + return "$netsettings{'ORANGE_DEV'}"; + } + if($net eq "$netsettings{'BLUE_NETADDRESS'}/$netsettings{'BLUE_NETMASK'}"){ + return "$netsettings{'BLUE_DEV'}"; + } + if($net eq "0.0.0.0/0"){ + return "$netsettings{'RED_DEV'}"; + } + return ""; +} sub get_net_ip { my $val=shift; @@ -305,9 +322,9 @@ sub get_address # address. Otherwise, we assume that it is an IP address. if ($key ~~ ["src_addr", "tgt_addr"]) { if (&General::validmac($value)) { - push(@ret, "-m mac --mac-source $value"); + push(@ret, ["-m mac --mac-source $value", ""]); } else { - push(@ret, $value); + push(@ret, [$value, ""]); } # If a default network interface (GREEN, BLUE, etc.) is selected, we @@ -316,88 +333,90 @@ sub get_address my $external_interface = &get_external_interface(); my $network_address = &get_std_net_ip($value, $external_interface); + if ($network_address) { - push(@ret, $network_address); + my $interface = &get_interface($network_address); + push(@ret, [$network_address, $interface]); } # Custom networks. } elsif ($key ~~ ["cust_net_src", "cust_net_tgt", "Custom Network"]) { my $network_address = &get_net_ip($value); if ($network_address) { - push(@ret, $network_address); + push(@ret, [$network_address, ""]); } # Custom hosts. } elsif ($key ~~ ["cust_host_src", "cust_host_tgt", "Custom Host"]) { my $host_address = &get_host_ip($value, $type); if ($host_address) { - push(@ret, $host_address); + push(@ret, [$host_address, ""]); } # OpenVPN networks. } elsif ($key ~~ ["ovpn_net_src", "ovpn_net_tgt", "OpenVPN static network"]) { my $network_address = &get_ovpn_net_ip($value, 1); if ($network_address) { - push(@ret, $network_address); + push(@ret, [$network_address, ""]); } # OpenVPN hosts. } elsif ($key ~~ ["ovpn_host_src", "ovpn_host_tgt", "OpenVPN static host"]) { my $host_address = &get_ovpn_host_ip($value, 33); if ($host_address) { - push(@ret, $host_address); + push(@ret, [$host_address, ""]); } # OpenVPN N2N. } elsif ($key ~~ ["ovpn_n2n_src", "ovpn_n2n_tgt", "OpenVPN N-2-N"]) { my $network_address = &get_ovpn_n2n_ip($value, 11); if ($network_address) { - push(@ret, $network_address); + push(@ret, [$network_address, ""]); } # IPsec networks. } elsif ($key ~~ ["ipsec_net_src", "ipsec_net_tgt", "IpSec Network"]) { my $network_address = &get_ipsec_net_ip($value, 11); if ($network_address) { - push(@ret, $network_address); + push(@ret, [$network_address, ""]); } # The firewall's own IP addresses. } elsif ($key ~~ ["ipfire", "ipfire_src"]) { # ALL if ($value eq "ALL") { - push(@ret, "0/0"); + push(@ret, ["0/0", ""]); # GREEN } elsif ($value eq "GREEN") { - push(@ret, $netsettings{"GREEN_ADDRESS"}); + push(@ret, [$netsettings{"GREEN_ADDRESS"}, ""]); # BLUE } elsif ($value eq "BLUE") { - push(@ret, $netsettings{"BLUE_ADDRESS"}); + push(@ret, [$netsettings{"BLUE_ADDRESS"}, ""]); # ORANGE } elsif ($value eq "ORANGE") { - push(@ret, $netsettings{"ORANGE_ADDRESS"}); + push(@ret, [$netsettings{"ORANGE_ADDRESS"}, ""]); # RED } elsif ($value ~~ ["RED", "RED1"]) { my $address = &get_external_address(); if ($address) { - push(@ret, $address); + push(@ret, [$address, ""]); } # Aliases } else { my $alias = &get_alias($value); if ($alias) { - push(@ret, $alias); + push(@ret, [$alias, ""]); } } # If nothing was selected, we assume "any". } else { - push(@ret, "0/0"); + push(@ret, ["0/0", ""]); } return @ret; diff --git a/config/firewall/rules.pl b/config/firewall/rules.pl index c0ddcb2d69..887c052657 100755 --- a/config/firewall/rules.pl +++ b/config/firewall/rules.pl @@ -291,24 +291,28 @@ sub buildrules { foreach my $src (@sources) { # Skip invalid source. - next unless ($src); + next unless (@$src[0]); # 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 if (!$dst || ($dst eq "none")); + next if (!@$dst[0] || (@$dst[0] 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 = (); @@ -325,12 +329,20 @@ sub buildrules { push(@source_options, ("-s", $source)); } + if ($source_intf) { + push(@source_options, ("-i", $source_intf)); + } + # Prepare destination options. my @destination_options = (); if ($destination) { push(@destination_options, ("-d", $destination)); } + if ($destination_intf) { + push(@destination_options, ("-o", $destination_intf)); + } + # Add time constraint options. push(@options, @time_options); @@ -364,7 +376,7 @@ sub buildrules { # 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); @@ -681,6 +693,7 @@ sub get_dnat_target_port { sub add_dnat_mangle_rules { my $nat_address = shift; + my $interface = shift; my @options = @_; my $mark = 0; @@ -691,6 +704,8 @@ sub add_dnat_mangle_rules { 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"}; diff --git a/html/cgi-bin/firewall.cgi b/html/cgi-bin/firewall.cgi index e6ae5272a2..2539d102c3 100644 --- a/html/cgi-bin/firewall.cgi +++ b/html/cgi-bin/firewall.cgi @@ -1064,7 +1064,6 @@ print<