}
# Prepare protocol options (like ICMP types, ports, etc...).
- my @protocol_options = &get_protocol_options($hash, $key, $protocol);
+ my @protocol_options = &get_protocol_options($hash, $key, $protocol, 0);
# Check if this protocol knows ports.
my $protocol_has_ports = ($protocol ~~ @PROTOCOLS_WITH_PORTS);
# Append protocol.
if ($protocol ne "all") {
- push(@options, ("-p", $protocol));
push(@options, @protocol_options);
}
my $firewall_is_in_source_subnet = 0;
if ($source) {
- $firewall_is_in_source_subnet = &firewall_is_in_subnet($source, 0);
+ $firewall_is_in_source_subnet = &firewall_is_in_subnet($source);
}
# Process NAT rules.
# Destination NAT
if ($NAT_MODE eq "DNAT") {
# Make port-forwardings useable from the internal networks.
- my @internal_addresses = &get_internal_firewall_ip_addresses();
+ my @internal_addresses = &get_internal_firewall_ip_addresses(1);
unless ($nat_address ~~ @internal_addresses) {
&add_dnat_mangle_rules($nat_address, @options);
}
- my @nat_options = @options;
+ my @nat_options = ();
+ if ($protocol ne "all") {
+ my @nat_protocol_options = &get_protocol_options($hash, $key, $protocol, 1);
+ push(@nat_options, @nat_protocol_options);
+ }
push(@nat_options, @source_options);
push(@nat_options, ("-d", $nat_address));
my $source = shift;
# Any static address of any zone.
- if ($zone eq "RED" || $zone eq "GREEN" || $zone eq "ORANGE" || $zone eq "BLUE") {
- return $defaultNetworks{$zone . "_ADDRESS"};
-
- } elsif ($zone eq "Default IP") {
+ if ($zone eq "AUTO") {
if ($source) {
- my $firewall_ip = &firewall_is_in_subnet($source, 1);
+ my $firewall_ip = &get_internal_firewall_ip_address($source, 1);
+ if ($firewall_ip) {
+ return $firewall_ip;
+ }
+ $firewall_ip = &get_matching_firewall_address($source, 1);
if ($firewall_ip) {
return $firewall_ip;
}
return &get_external_address();
+ } elsif ($zone eq "RED" || $zone eq "GREEN" || $zone eq "ORANGE" || $zone eq "BLUE") {
+ return $defaultNetworks{$zone . "_ADDRESS"};
+
+ } elsif ($zone eq "Default IP") {
+ return &get_external_address();
+
} else {
return &get_alias($zone);
}
my $hash = shift;
my $key = shift;
my $protocol = shift;
+ my $nat_options_wanted = shift;
my @options = ();
+ # Nothing to do if no protocol is specified.
+ if ($protocol eq "all") {
+ return @options;
+ } else {
+ push(@options, ("-p", $protocol));
+ }
+
# Process source ports.
my $use_src_ports = ($$hash{$key}[7] eq "ON");
my $src_ports = $$hash{$key}[10];
my $dst_ports = $$hash{$key}[15];
if (($dst_ports_mode eq "TGT_PORT") && $dst_ports) {
- if ($use_dnat && $$hash{$key}[30]) {
+ if ($nat_options_wanted && $use_dnat && $$hash{$key}[30]) {
$dst_ports = $$hash{$key}[30];
}
push(@options, &format_ports($dst_ports, "dst"));
}
sub get_internal_firewall_ip_addresses {
- my @addresses = ();
+ my $use_orange = shift;
- for my $zone ("GREEN", "BLUE", "ORANGE") {
+ my @zones = ("GREEN", "BLUE");
+ if ($use_orange) {
+ push(@zones, "ORANGE");
+ }
+
+ my @addresses = ();
+ for my $zone (@zones) {
next unless (exists $defaultNetworks{$zone . "_ADDRESS"});
my $zone_address = $defaultNetworks{$zone . "_ADDRESS"};
return @addresses;
}
-sub firewall_is_in_subnet {
+sub get_internal_firewall_ip_address {
my $subnet = shift;
my $use_orange = shift;
my ($net_address, $net_mask) = split("/", $subnet);
- if (!$net_mask) {
+ if ((!$net_mask) || ($net_mask ~~ ["32", "255.255.255.255"])) {
return 0;
}
+ my @addresses = &get_internal_firewall_ip_addresses($use_orange);
+ foreach my $zone_address (@addresses) {
+ if (&General::IpInSubnet($zone_address, $net_address, $net_mask)) {
+ return $zone_address;
+ }
+ }
+
+ return 0;
+}
+
+sub firewall_is_in_subnet {
+ my $subnet = shift;
+
+ # ORANGE is missing here, because nothing may ever access
+ # the firewall from this network.
+ my $address = &get_internal_firewall_ip_address($subnet, 0);
+
+ if ($address) {
+ return 1;
+ }
+
+ return 0;
+}
+
+sub get_matching_firewall_address {
+ my $addr = shift;
+ my $use_orange = shift;
+
+ my ($address, $netmask) = split("/", $addr);
+
my @zones = ("GREEN", "BLUE");
if ($use_orange) {
push(@zones, "ORANGE");
}
- # ORANGE is missing here, because nothing may ever access
- # the firewall from this network.
foreach my $zone (@zones) {
next unless (exists $defaultNetworks{$zone . "_ADDRESS"});
- my $zone_address = $defaultNetworks{$zone . "_ADDRESS"};
+ my $zone_subnet = $defaultNetworks{$zone . "_NETADDRESS"};
+ my $zone_mask = $defaultNetworks{$zone . "_NETMASK"};
- if (&General::IpInSubnet($zone_address, $net_address, $net_mask)) {
- return $zone_address;
+ if (&General::IpInSubnet($address, $zone_subnet, $zone_mask)) {
+ return $defaultNetworks{$zone . "_ADDRESS"};
}
}
+
+ return 0;
}