]> git.proxmox.com Git - pve-firewall.git/blobdiff - src/PVE/Firewall.pm
parse_protocol_file: support lines without end comments
[pve-firewall.git] / src / PVE / Firewall.pm
index bc3d9fe083b4d2c28ba7871dabddb4db1a810ef8..ac4850744a83571a5aec1340ace98997e0dfb48d 100644 (file)
@@ -876,12 +876,8 @@ sub get_etc_services {
     return $etc_services;
 }
 
-my $etc_protocols;
-
-sub get_etc_protocols {
-    return $etc_protocols if $etc_protocols;
-
-    my $filename = "/etc/protocols";
+sub parse_protocol_file {
+    my ($filename) = @_;
 
     my $fh = IO::File->new($filename, O_RDONLY);
     if (!$fh) {
@@ -896,7 +892,7 @@ sub get_etc_protocols {
        next if $line =~m/^#/;
        next if ($line =~m/^\s*$/);
 
-       if ($line =~ m!^(\S+)\s+(\d+)\s+.*$!) {
+       if ($line =~ m!^(\S+)\s+(\d+)(?:\s+.*)?$!) {
            $protocols->{byid}->{$2}->{name} = $1;
            $protocols->{byname}->{$1} = $protocols->{byid}->{$2};
        }
@@ -904,6 +900,16 @@ sub get_etc_protocols {
 
     close($fh);
 
+    return $protocols;
+}
+
+my $etc_protocols;
+
+sub get_etc_protocols {
+    return $etc_protocols if $etc_protocols;
+
+    my $protocols = parse_protocol_file('/etc/protocols');
+
     # add special case for ICMP v6
     $protocols->{byid}->{icmpv6}->{name} = "icmpv6";
     $protocols->{byname}->{icmpv6} = $protocols->{byid}->{icmpv6};
@@ -1063,7 +1069,7 @@ sub parse_port_name_number_or_range {
     die "too many entries in port list (> 15 numbers)\n"
        if $count > 15;
 
-    return $count;
+    return (scalar(@elements) > 1);
 }
 
 PVE::JSONSchema::register_format('pve-fw-sport-spec', \&pve_fw_verify_sport_spec);
@@ -1885,19 +1891,12 @@ sub ipt_rule_to_cmds {
        if (my $proto = $rule->{proto}) {
            push @match, "-p $proto";
 
-           my $nbdport = defined($rule->{dport}) ? parse_port_name_number_or_range($rule->{dport}, 1) : 0;
-           my $nbsport = defined($rule->{sport}) ? parse_port_name_number_or_range($rule->{sport}, 0) : 0;
-
-           my $multiport = 0;
-           $multiport++ if $nbdport > 1;
-           $multiport++ if $nbsport > 1;
-
-           push @match, "--match multiport" if $multiport;
+           my $multidport = defined($rule->{dport}) && parse_port_name_number_or_range($rule->{dport}, 1);
+           my $multisport = defined($rule->{sport}) && parse_port_name_number_or_range($rule->{sport}, 0);
 
-           die "multiport: option '--sports' cannot be used together with '--dports'\n"
-               if ($multiport == 2) && ($rule->{dport} ne $rule->{sport});
+           my $add_dport = sub {
+               return if !$rule->{dport};
 
-           if ($rule->{dport}) {
                if ($proto eq 'icmp') {
                    # Note: we use dport to store --icmp-type
                    die "unknown icmp-type '$rule->{dport}'\n"
@@ -1910,28 +1909,29 @@ sub ipt_rule_to_cmds {
                    push @match, "-m icmpv6 --icmpv6-type $rule->{dport}";
                } elsif (!$PROTOCOLS_WITH_PORTS->{$proto}) {
                    die "protocol $proto does not have ports\n";
+               } elsif ($multidport) {
+                   push @match, "--match multiport", "--dports $rule->{dport}";
                } else {
-                   if ($nbdport > 1) {
-                       if ($multiport == 2) {
-                           push @match,  "--ports $rule->{dport}";
-                       } else {
-                           push @match, "--dports $rule->{dport}";
-                       }
-                   } else {
-                       push @match, "--dport $rule->{dport}";
-                   }
+                   push @match, "--dport $rule->{dport}";
                }
-           }
+           };
+
+           my $add_sport = sub {
+               return if !$rule->{sport};
 
-           if ($rule->{sport}) {
                die "protocol $proto does not have ports\n"
                    if !$PROTOCOLS_WITH_PORTS->{$proto};
-               if ($nbsport > 1) {
-                   push @match, "--sports $rule->{sport}" if $multiport != 2;
+               if ($multisport) {
+                   push @match, "--match multiport", "--sports $rule->{sport}";
                } else {
                    push @match, "--sport $rule->{sport}";
                }
-           }
+           };
+
+           # order matters - single port before multiport!
+           $add_dport->() if $multisport;
+           $add_sport->();
+           $add_dport->() if !$multisport;
        } elsif ($rule->{dport} || $rule->{sport}) {
            die "destination port '$rule->{dport}', but no protocol specified\n" if $rule->{dport};
            die "source port '$rule->{sport}', but no protocol specified\n" if $rule->{sport};