X-Git-Url: https://git.proxmox.com/?p=pve-firewall.git;a=blobdiff_plain;f=src%2FPVE%2FAPI2%2FFirewall%2FRules.pm;h=44756637117b1e7b2ad762d92c57a0dd8833843b;hp=400cd7cdd15d30b6af3c6b03cc82a361fb18f636;hb=HEAD;hpb=9f6845cfa97dbe5e264c9d4e188a245ba3d7edf5 diff --git a/src/PVE/API2/Firewall/Rules.pm b/src/PVE/API2/Firewall/Rules.pm index 400cd7c..9fcfb20 100644 --- a/src/PVE/API2/Firewall/Rules.pm +++ b/src/PVE/API2/Firewall/Rules.pm @@ -2,6 +2,7 @@ package PVE::API2::Firewall::RulesBase; use strict; use warnings; + use PVE::JSONSchema qw(get_standard_option); use PVE::Exception qw(raise raise_param_exc); @@ -9,7 +10,7 @@ use PVE::Firewall; use base qw(PVE::RESTHandler); -my $api_properties = { +my $api_properties = { pos => { description => "Rule position.", type => 'integer', @@ -17,6 +18,12 @@ my $api_properties = { }, }; +sub lock_config { + my ($class, $param, $code) = @_; + + die "implement this in subclass"; +} + sub load_config { my ($class, $param) = @_; @@ -35,7 +42,7 @@ my $additional_param_hash = {}; sub rule_env { my ($class, $param) = @_; - + die "implement this in subclass"; } @@ -105,7 +112,7 @@ sub register_get_rule { my $properties = $class->additional_parameters(); $properties->{pos} = $api_properties->{pos}; - + my $rule_env = $class->rule_env(); $class->register_method({ @@ -122,9 +129,62 @@ sub register_get_rule { returns => { type => "object", properties => { + action => { + type => 'string', + }, + comment => { + type => 'string', + optional => 1, + }, + dest => { + type => 'string', + optional => 1, + }, + dport => { + type => 'string', + optional => 1, + }, + enable => { + type => 'integer', + optional => 1, + }, + log => PVE::Firewall::get_standard_option('pve-fw-loglevel', { + description => 'Log level for firewall rule', + }), + 'icmp-type' => { + type => 'string', + optional => 1, + }, + iface => { + type => 'string', + optional => 1, + }, + ipversion => { + type => 'integer', + optional => 1, + }, + macro => { + type => 'string', + optional => 1, + }, pos => { type => 'integer', - } + }, + proto => { + type => 'string', + optional => 1, + }, + source => { + type => 'string', + optional => 1, + }, + sport => { + type => 'string', + optional => 1, + }, + type => { + type => 'string', + }, }, }, code => sub { @@ -133,9 +193,9 @@ sub register_get_rule { my ($cluster_conf, $fw_conf, $rules) = $class->load_config($param); my ($list, $digest) = PVE::Firewall::copy_list_with_digest($rules); - + die "no rule at position $param->{pos}\n" if $param->{pos} >= scalar(@$list); - + my $rule = $list->[$param->{pos}]; $rule->{pos} = $param->{pos}; @@ -151,7 +211,7 @@ sub register_create_rule { my $create_rule_properties = PVE::Firewall::add_rule_properties($properties); $create_rule_properties->{action}->{optional} = 0; $create_rule_properties->{type}->{optional} = 0; - + my $rule_env = $class->rule_env(); $class->register_method({ @@ -170,18 +230,22 @@ sub register_create_rule { code => sub { my ($param) = @_; - my ($cluster_conf, $fw_conf, $rules) = $class->load_config($param); + $class->lock_config($param, sub { + my ($param) = @_; - my $rule = {}; + my ($cluster_conf, $fw_conf, $rules) = $class->load_config($param); - PVE::Firewall::copy_rule_data($rule, $param); - PVE::Firewall::verify_rule($rule, $cluster_conf, $fw_conf, $class->rule_env()); + my $rule = {}; - $rule->{enable} = 0 if !defined($param->{enable}); + PVE::Firewall::copy_rule_data($rule, $param); + PVE::Firewall::verify_rule($rule, $cluster_conf, $fw_conf, $class->rule_env()); - unshift @$rules, $rule; + $rule->{enable} = 0 if !defined($param->{enable}); - $class->save_rules($param, $fw_conf, $rules); + unshift @$rules, $rule; + + $class->save_rules($param, $fw_conf, $rules); + }); return undef; }}); @@ -193,7 +257,7 @@ sub register_update_rule { my $properties = $class->additional_parameters(); $properties->{pos} = $api_properties->{pos}; - + my $rule_env = $class->rule_env(); $properties->{moveto} = { @@ -227,36 +291,40 @@ sub register_update_rule { code => sub { my ($param) = @_; - my ($cluster_conf, $fw_conf, $rules) = $class->load_config($param); + $class->lock_config($param, sub { + my ($param) = @_; + + my ($cluster_conf, $fw_conf, $rules) = $class->load_config($param); - my (undef, $digest) = PVE::Firewall::copy_list_with_digest($rules); - PVE::Tools::assert_if_modified($digest, $param->{digest}); + my (undef, $digest) = PVE::Firewall::copy_list_with_digest($rules); + PVE::Tools::assert_if_modified($digest, $param->{digest}); - die "no rule at position $param->{pos}\n" if $param->{pos} >= scalar(@$rules); - - my $rule = $rules->[$param->{pos}]; + die "no rule at position $param->{pos}\n" if $param->{pos} >= scalar(@$rules); - my $moveto = $param->{moveto}; - if (defined($moveto) && $moveto != $param->{pos}) { - my $newrules = []; - for (my $i = 0; $i < scalar(@$rules); $i++) { - next if $i == $param->{pos}; - if ($i == $moveto) { - push @$newrules, $rule; + my $rule = $rules->[$param->{pos}]; + + my $moveto = $param->{moveto}; + if (defined($moveto) && $moveto != $param->{pos}) { + my $newrules = []; + for (my $i = 0; $i < scalar(@$rules); $i++) { + next if $i == $param->{pos}; + if ($i == $moveto) { + push @$newrules, $rule; + } + push @$newrules, $rules->[$i]; } - push @$newrules, $rules->[$i]; - } - push @$newrules, $rule if $moveto >= scalar(@$rules); - $rules = $newrules; - } else { - PVE::Firewall::copy_rule_data($rule, $param); - - PVE::Firewall::delete_rule_properties($rule, $param->{'delete'}) if $param->{'delete'}; + push @$newrules, $rule if $moveto >= scalar(@$rules); + $rules = $newrules; + } else { + PVE::Firewall::copy_rule_data($rule, $param); - PVE::Firewall::verify_rule($rule, $cluster_conf, $fw_conf, $class->rule_env()); - } + PVE::Firewall::delete_rule_properties($rule, $param->{'delete'}) if $param->{'delete'}; + + PVE::Firewall::verify_rule($rule, $cluster_conf, $fw_conf, $class->rule_env()); + } - $class->save_rules($param, $fw_conf, $rules); + $class->save_rules($param, $fw_conf, $rules); + }); return undef; }}); @@ -270,7 +338,7 @@ sub register_delete_rule { $properties->{pos} = $api_properties->{pos}; $properties->{digest} = get_standard_option('pve-config-digest'); - + my $rule_env = $class->rule_env(); $class->register_method({ @@ -289,16 +357,20 @@ sub register_delete_rule { code => sub { my ($param) = @_; - my ($cluster_conf, $fw_conf, $rules) = $class->load_config($param); + $class->lock_config($param, sub { + my ($param) = @_; + + my ($cluster_conf, $fw_conf, $rules) = $class->load_config($param); + + my (undef, $digest) = PVE::Firewall::copy_list_with_digest($rules); + PVE::Tools::assert_if_modified($digest, $param->{digest}); - my (undef, $digest) = PVE::Firewall::copy_list_with_digest($rules); - PVE::Tools::assert_if_modified($digest, $param->{digest}); - - die "no rule at position $param->{pos}\n" if $param->{pos} >= scalar(@$rules); - - splice(@$rules, $param->{pos}, 1); - - $class->save_rules($param, $fw_conf, $rules); + die "no rule at position $param->{pos}\n" if $param->{pos} >= scalar(@$rules); + + splice(@$rules, $param->{pos}, 1); + + $class->save_rules($param, $fw_conf, $rules); + }); return undef; }}); @@ -327,10 +399,16 @@ __PACKAGE__->additional_parameters({ group => get_standard_option('pve-security- sub rule_env { my ($class, $param) = @_; - + return 'group'; } +sub lock_config { + my ($class, $param, $code) = @_; + + PVE::Firewall::lock_clusterfw_conf(10, $code, $param); +} + sub load_config { my ($class, $param) = @_; @@ -359,22 +437,29 @@ __PACKAGE__->register_method({ method => 'DELETE', description => "Delete security group.", protected => 1, + permissions => { + check => ['perm', '/', [ 'Sys.Modify' ]], + }, parameters => { additionalProperties => 0, - properties => { + properties => { group => get_standard_option('pve-security-group-name'), }, }, returns => { type => 'null' }, code => sub { my ($param) = @_; - - my (undef, $cluster_conf, $rules) = __PACKAGE__->load_config($param); - die "Security group '$param->{group}' is not empty\n" - if scalar(@$rules); + __PACKAGE__->lock_config($param, sub { + my ($param) = @_; + + my (undef, $cluster_conf, $rules) = __PACKAGE__->load_config($param); - __PACKAGE__->save_rules($param, $cluster_conf, undef); + die "Security group '$param->{group}' is not empty\n" + if scalar(@$rules); + + __PACKAGE__->save_rules($param, $cluster_conf, undef); + }); return undef; }}); @@ -390,10 +475,16 @@ use base qw(PVE::API2::Firewall::RulesBase); sub rule_env { my ($class, $param) = @_; - + return 'cluster'; } +sub lock_config { + my ($class, $param, $code) = @_; + + PVE::Firewall::lock_clusterfw_conf(10, $code, $param); +} + sub load_config { my ($class, $param) = @_; @@ -424,10 +515,16 @@ __PACKAGE__->additional_parameters({ node => get_standard_option('pve-node')}); sub rule_env { my ($class, $param) = @_; - + return 'host'; } +sub lock_config { + my ($class, $param, $code) = @_; + + PVE::Firewall::lock_hostfw_conf(undef, 10, $code, $param); +} + sub load_config { my ($class, $param) = @_; @@ -455,17 +552,23 @@ use PVE::JSONSchema qw(get_standard_option); use base qw(PVE::API2::Firewall::RulesBase); -__PACKAGE__->additional_parameters({ +__PACKAGE__->additional_parameters({ node => get_standard_option('pve-node'), - vmid => get_standard_option('pve-vmid'), + vmid => get_standard_option('pve-vmid'), }); sub rule_env { my ($class, $param) = @_; - + return 'vm'; } +sub lock_config { + my ($class, $param, $code) = @_; + + PVE::Firewall::lock_vmfw_conf($param->{vmid}, 10, $code, $param); +} + sub load_config { my ($class, $param) = @_; @@ -493,17 +596,23 @@ use PVE::JSONSchema qw(get_standard_option); use base qw(PVE::API2::Firewall::RulesBase); -__PACKAGE__->additional_parameters({ +__PACKAGE__->additional_parameters({ node => get_standard_option('pve-node'), - vmid => get_standard_option('pve-vmid'), + vmid => get_standard_option('pve-vmid'), }); sub rule_env { my ($class, $param) = @_; - + return 'ct'; } +sub lock_config { + my ($class, $param, $code) = @_; + + PVE::Firewall::lock_vmfw_conf($param->{vmid}, 10, $code, $param); +} + sub load_config { my ($class, $param) = @_;