fix port parser
authorDietmar Maurer <dietmar@proxmox.com>
Fri, 4 Apr 2014 11:22:12 +0000 (13:22 +0200)
committerDietmar Maurer <dietmar@proxmox.com>
Fri, 4 Apr 2014 11:22:12 +0000 (13:22 +0200)
And correctly verify rules on updates on API.

src/PVE/API2/Firewall/Rules.pm
src/PVE/Firewall.pm

index 032631d..d9ba2f4 100644 (file)
@@ -32,6 +32,10 @@ sub save_rules {
 
 my $additional_param_hash = {};
 
+sub allow_groups {
+    return 1;
+}
+
 sub additional_parameters {
     my ($class, $new_value) = @_;
 
@@ -160,6 +164,7 @@ sub register_create_rule {
            my $rule = {};
 
            PVE::Firewall::copy_rule_data($rule, $param);
+           PVE::Firewall::verify_rule($rule, $class->allow_groups());
 
            $rule->{enable} = 0 if !defined($param->{enable});
 
@@ -237,6 +242,8 @@ sub register_update_rule {
                PVE::Firewall::copy_rule_data($rule, $param);
                
                PVE::Firewall::delete_rule_properties($rule, $param->{'delete'}) if $param->{'delete'};
+
+               PVE::Firewall::verify_rule($rule, $class->allow_groups());
            }
 
            $class->save_rules($param, $fw_conf, $rules);
@@ -304,6 +311,10 @@ __PACKAGE__->additional_parameters({ group => {
     maxLength => 20, # fixme: what length?
 }});
 
+sub allow_groups {
+    return 0;
+}
+
 sub load_config {
     my ($class, $param) = @_;
 
index ea8853e..9a8561e 100644 (file)
@@ -6,6 +6,7 @@ use POSIX;
 use Data::Dumper;
 use Digest::SHA;
 use PVE::INotify;
+use PVE::Exception qw(raise raise_param_exc);
 use PVE::JSONSchema qw(get_standard_option);
 use PVE::Cluster;
 use PVE::ProcFSTools;
@@ -692,31 +693,29 @@ sub parse_port_name_number_or_range {
     my ($str) = @_;
 
     my $services = PVE::Firewall::get_etc_services();
-    my $nbports = 0;
+    my $count = 0;
     foreach my $item (split(/,/, $str)) {
-       my $portlist = "";
-       my $oldpon = undef;
-       $nbports++;
-       foreach my $pon (split(':', $item, 2)) {
-           $pon = $services->{byname}->{$pon}->{port} if $services->{byname}->{$pon}->{port};
-           if ($pon =~ m/^\d+$/){
-               die "invalid port '$pon'\n" if $pon < 0 && $pon > 65535;
-               die "port '$pon' must be bigger than port '$oldpon' \n" if $oldpon && ($pon < $oldpon);
-               $oldpon = $pon;
-           }else{
-               die "invalid port $services->{byname}->{$pon}\n" if !$services->{byname}->{$pon};
-           }
+       $count++;
+       if ($item =~ m/^(\d+):(\d+)$/) {
+           my ($port1, $port2) = ($1, $2);
+           die "invalid port '$port1'\n" if $port1 > 65535;
+           die "invalid port '$port2'\n" if $port2 > 65535;
+       } elsif ($item =~ m/^(\d+)$/) {
+           my $port = $1;
+           die "invalid port '$port'\n" if $port > 65535;
+       } else {
+           die "invalid port '$item'\n" if !$services->{byname}->{$item}; 
        }
     }
 
-    return ($nbports);
+    return $count;
 }
 
 PVE::JSONSchema::register_format('pve-fw-port-spec', \&pve_fw_verify_port_spec);
 sub pve_fw_verify_port_spec {
    my ($portstr) = @_;
 
-    parse_port_name_number_or_range($portstr);
+   parse_port_name_number_or_range($portstr);
 
    return $portstr;
 }
@@ -848,6 +847,57 @@ sub delete_rule_properties {
     return $rule;
 }
 
+sub verify_rule {
+    my ($rule, $allow_groups) = @_;
+
+    my $type = $rule->{type};
+
+    raise_param_exc({ type => "missing property"}) if !$type;
+    raise_param_exc({ action => "missing property"}) if !$rule->{action};
+    if ($type eq  'in' || $type eq 'out') {
+       raise_param_exc({ action => "unknown action '$rule->{action}'"})
+           if $rule->{action} !~ m/^(ACCEPT|DROP|REJECT)$/;
+    } elsif ($type eq 'group') {
+       raise_param_exc({ type => "security groups not allowed"}) 
+           if !$allow_groups;
+       raise_param_exc({ action => "invalid characters in security group name"}) 
+           if $rule->{action} !~ m/^[A-Za-z0-9_\-]+$/;
+    } else {
+       raise_param_exc({ type => "unknown rule type '$type'"});
+    }
+   
+    # fixme: verify $rule->{iface}?
+
+    if ($rule->{macro}) {
+       my $preferred_name = $pve_fw_preferred_macro_names->{lc($rule->{macro})};
+       raise_param_exc({ macro => "unknown macro '$rule->{macro}'"}) if !$preferred_name;
+       $rule->{macro} = $preferred_name;
+    }
+
+    if ($rule->{dport}) {
+       eval { parse_port_name_number_or_range($rule->{dport}); };
+       raise_param_exc({ dport => $@ }) if $@;
+    }
+
+    if ($rule->{sport}) {
+       eval { parse_port_name_number_or_range($rule->{sport}); };
+       raise_param_exc({ sport => $@ }) if $@;
+    }
+
+    if ($rule->{source}) {
+       eval { parse_address_list($rule->{source}); };
+       raise_param_exc({ source => $@ }) if $@;
+    }
+
+    if ($rule->{dest}) {
+       eval { parse_address_list($rule->{dest}); };
+       raise_param_exc({ dest => $@ }) if $@;
+    }
+
+    return $rule;
+}
+
 sub copy_rule_data {
     my ($rule, $param) = @_;
 
@@ -862,6 +912,9 @@ sub copy_rule_data {
            delete $rule->{$k};
        }
     }
+
+    # verify rule now
+
     return $rule;
 }
 
@@ -2033,7 +2086,11 @@ my $format_rules = sub {
        if ($rule->{type} eq  'in' || $rule->{type} eq 'out') {
            $raw .= '|' if defined($rule->{enable}) && !$rule->{enable};
            $raw .= uc($rule->{type});
-           $raw .= " " . $rule->{action};
+           if ($rule->{macro}) {
+               $raw .= " $rule->{macro}($rule->{action})";
+           } else {
+               $raw .= " " . $rule->{action};
+           }
            $raw .= " " . ($rule->{iface} || '-') if $need_iface;
            $raw .= " " . ($rule->{source} || '-');
            $raw .= " " . ($rule->{dest} || '-');