]> git.ipfire.org Git - people/teissler/ipfire-2.x.git/blobdiff - config/firewall/rules.pl
firewall: Fix rule generation for protocols without ports.
[people/teissler/ipfire-2.x.git] / config / firewall / rules.pl
index 12c0c2b232a0e868ea2ac9d1c9a1a7edee835e28..92f1c0a3083d56a64f5cd8c6e9330a5508cd43a6 100755 (executable)
@@ -53,7 +53,6 @@ my %customgrp=();
 my %configinputfw=();
 my %configoutgoingfw=();
 my %confignatfw=();
-my %aliases=();
 my @p2ps=();
 
 my $configfwdfw                = "${General::swroot}/firewall/config";
@@ -69,7 +68,6 @@ my $netsettings               = "${General::swroot}/ethernet/settings";
 &General::readhasharray($configinput, \%configinputfw);
 &General::readhasharray($configoutgoing, \%configoutgoingfw);
 &General::readhasharray($configgrp, \%customgrp);
-&General::get_aliases(\%aliases);
 
 my @log_limit_options = &make_log_limit_options();
 
@@ -175,6 +173,9 @@ sub buildrules {
                # Collect all destinations.
                my @destinations = &fwlib::get_addresses($hash, $key, "tgt");
 
+               # True if the destination is the firewall itself.
+               my $destination_is_firewall = ($$hash{$key}[5] eq "ipfire");
+
                # Check if logging should be enabled.
                my $LOG = ($$hash{$key}[17] eq 'ON');
 
@@ -251,17 +252,22 @@ sub buildrules {
                        # Check if this protocol knows ports.
                        my $protocol_has_ports = ($protocol ~~ @PROTOCOLS_WITH_PORTS);
 
-                       foreach my $source (@sources) {
-                               foreach my $destination (@destinations) {
-                                       # Skip invalid rules.
-                                       next if (!$source || !$destination || ($destination eq "none"));
+                       foreach my $src (@sources) {
+                               # Skip invalid source.
+                               next unless ($src);
 
-                                       # Sanitize source.
-                                       if ($source ~~ @ANY_ADDRESSES) {
-                                               $source = "";
-                                       }
+                               # Sanitize source.
+                               my $source = $src;
+                               if ($source ~~ @ANY_ADDRESSES) {
+                                       $source = "";
+                               }
+
+                               foreach my $dst (@destinations) {
+                                       # Skip invalid rules.
+                                       next if (!$dst || ($dst eq "none"));
 
                                        # Sanitize destination.
+                                       my $destination = $dst;
                                        if ($destination ~~ @ANY_ADDRESSES) {
                                                $destination = "";
                                        }
@@ -319,22 +325,45 @@ sub buildrules {
                                                        }
                                                        push(@nat_options, @source_options);
                                                        push(@nat_options, ("-d", $nat_address));
+                                                       push(@nat_options, @time_options);
 
-                                                       my ($dnat_address, $dnat_mask) = split("/", $destination);
-                                                       @destination_options = ("-d", $dnat_address);
-
+                                                       my $dnat_port;
                                                        if ($protocol_has_ports) {
-                                                               my $dnat_port = &get_dnat_target_port($hash, $key);
+                                                               $dnat_port = &get_dnat_target_port($hash, $key);
+                                                       }
+
+                                                       my @nat_action_options = ();
+
+                                                       # Use iptables REDIRECT
+                                                       my $use_redirect = ($destination_is_firewall && !$destination && $protocol_has_ports && $dnat_port);
+                                                       if ($use_redirect) {
+                                                               push(@nat_action_options, ("-j", "REDIRECT", "--to-ports", $dnat_port));
+
+                                                       # Use iptables DNAT
+                                                       } else {
+                                                               if ($destination_is_firewall && !$destination) {
+                                                                       $destination = &fwlib::get_external_address();
+                                                               }
+                                                               next unless ($destination);
 
-                                                               if ($dnat_port) {
-                                                                       $dnat_address .= ":$dnat_port";
+                                                               my ($dnat_address, $dnat_mask) = split("/", $destination);
+                                                               @destination_options = ("-d", $dnat_address);
+
+                                                               if ($protocol_has_ports) {
+                                                                       my $dnat_port = &get_dnat_target_port($hash, $key);
+
+                                                                       if ($dnat_port) {
+                                                                               $dnat_address .= ":$dnat_port";
+                                                                       }
                                                                }
+
+                                                               push(@nat_action_options, ("-j", "DNAT", "--to-destination", $dnat_address));
                                                        }
 
                                                        if ($LOG) {
                                                                run("$IPTABLES -t nat -A $CHAIN_NAT_DESTINATION @nat_options @log_limit_options -j LOG --log-prefix 'DNAT '");
                                                        }
-                                                       run("$IPTABLES -t nat -A $CHAIN_NAT_DESTINATION @nat_options -j DNAT --to-destination $dnat_address");
+                                                       run("$IPTABLES -t nat -A $CHAIN_NAT_DESTINATION @nat_options @nat_action_options");
 
                                                # Source NAT
                                                } elsif ($NAT_MODE eq "SNAT") {
@@ -506,43 +535,45 @@ sub get_protocol_options {
                push(@options, ("-p", $protocol));
        }
 
-       # Process source ports.
-       my $use_src_ports = ($$hash{$key}[7] eq "ON");
-       my $src_ports     = $$hash{$key}[10];
+       if ($protocol ~~ @PROTOCOLS_WITH_PORTS) {
+               # Process source ports.
+               my $use_src_ports = ($$hash{$key}[7] eq "ON");
+               my $src_ports     = $$hash{$key}[10];
 
-       if ($use_src_ports && $src_ports) {
-               push(@options, &format_ports($src_ports, "src"));
-       }
-
-       # Process destination ports.
-       my $use_dst_ports  = ($$hash{$key}[11] eq "ON");
-       my $use_dnat       = (($$hash{$key}[28] eq "ON") && ($$hash{$key}[31] eq "dnat"));
+               if ($use_src_ports && $src_ports) {
+                       push(@options, &format_ports($src_ports, "src"));
+               }
 
-       if ($use_dst_ports) {
-               my $dst_ports_mode = $$hash{$key}[14];
-               my $dst_ports      = $$hash{$key}[15];
+               # Process destination ports.
+               my $use_dst_ports  = ($$hash{$key}[11] eq "ON");
+               my $use_dnat       = (($$hash{$key}[28] eq "ON") && ($$hash{$key}[31] eq "dnat"));
 
-               if (($dst_ports_mode eq "TGT_PORT") && $dst_ports) {
-                       if ($nat_options_wanted && $use_dnat && $$hash{$key}[30]) {
-                               $dst_ports = $$hash{$key}[30];
-                       }
-                       push(@options, &format_ports($dst_ports, "dst"));
+               if ($use_dst_ports) {
+                       my $dst_ports_mode = $$hash{$key}[14];
+                       my $dst_ports      = $$hash{$key}[15];
 
-               } elsif ($dst_ports_mode eq "cust_srv") {
-                       if ($protocol eq "ICMP") {
-                               push(@options, ("--icmp-type", &fwlib::get_srv_port($dst_ports, 3, "ICMP")));
-                       } else {
-                               $dst_ports = &fwlib::get_srv_port($dst_ports, 1, uc($protocol));
+                       if (($dst_ports_mode eq "TGT_PORT") && $dst_ports) {
+                               if ($nat_options_wanted && $use_dnat && $$hash{$key}[30]) {
+                                       $dst_ports = $$hash{$key}[30];
+                               }
                                push(@options, &format_ports($dst_ports, "dst"));
-                       }
 
-               } elsif ($dst_ports_mode eq "cust_srvgrp") {
-                       push(@options, &fwlib::get_srvgrp_port($dst_ports, uc($protocol)));
+                       } elsif ($dst_ports_mode eq "cust_srv") {
+                               if ($protocol eq "ICMP") {
+                                       push(@options, ("--icmp-type", &fwlib::get_srv_port($dst_ports, 3, "ICMP")));
+                               } else {
+                                       $dst_ports = &fwlib::get_srv_port($dst_ports, 1, uc($protocol));
+                                       push(@options, &format_ports($dst_ports, "dst"));
+                               }
+
+                       } elsif ($dst_ports_mode eq "cust_srvgrp") {
+                               push(@options, &fwlib::get_srvgrp_port($dst_ports, uc($protocol)));
+                       }
                }
        }
 
        # Check if a single ICMP type is selected.
-       if (!$use_src_ports && !$use_dst_ports && $protocol eq "icmp") {
+       if ($protocol eq "icmp") {
                my $icmp_type = $$hash{$key}[9];
 
                if (($icmp_type ne "All ICMP-Types") && $icmp_type) {