From: Dietmar Maurer Date: Tue, 25 Mar 2014 06:20:44 +0000 (+0100) Subject: improve API X-Git-Url: https://git.proxmox.com/?p=pve-firewall.git;a=commitdiff_plain;h=9c7e08582e838e283333e9d49d59737d5e877628 improve API --- diff --git a/src/PVE/API2/Firewall/Groups.pm b/src/PVE/API2/Firewall/Groups.pm index d7f33b8..9ce6ce7 100644 --- a/src/PVE/API2/Firewall/Groups.pm +++ b/src/PVE/API2/Firewall/Groups.pm @@ -69,8 +69,13 @@ __PACKAGE__->register_method({ type => 'array', items => { type => "object", - properties => {}, + properties => { + pos => { + type => 'integer', + } + }, }, + links => [ { rel => 'child', href => "{pos}" } ], }, code => sub { my ($param) = @_; @@ -92,4 +97,195 @@ __PACKAGE__->register_method({ return $res; }}); +__PACKAGE__->register_method({ + name => 'get_rule', + path => '{group}/{pos}', + method => 'GET', + description => "Get single rule data.", + proxyto => 'node', + parameters => { + additionalProperties => 0, + properties => { + node => get_standard_option('pve-node'), + group => { + description => "Security group name.", + type => 'string', + }, + pos => { + description => "Return rule from position .", + type => 'integer', + minimum => 0, + }, + }, + }, + returns => { + type => "object", + properties => { + pos => { + type => 'integer', + } + }, + }, + code => sub { + my ($param) = @_; + + my $groups_conf = PVE::Firewall::load_security_groups(); + + my $rules = $groups_conf->{rules}->{$param->{group}}; + die "no such security group\n" if !defined($rules); + + my $digest = $groups_conf->{digest}; + # fixme: check digest + + die "no rule at position $param->{pos}\n" if $param->{pos} >= scalar(@$rules); + + my $rule = $rules->[$param->{pos}]; + + return PVE::Firewall::cleanup_fw_rule($rule, $digest, $param->{pos}); + }}); + + +__PACKAGE__->register_method({ + name => 'create_rule', + path => '{group}', + method => 'POST', + description => "Create new rule.", + proxyto => 'node', + protected => 1, + parameters => { + additionalProperties => 0, + properties => PVE::Firewall::add_rule_properties({ + node => get_standard_option('pve-node'), + group => { + description => "Security group name.", + type => 'string', + }, + }), + }, + returns => { type => "null" }, + code => sub { + my ($param) = @_; + + my $groups_conf = PVE::Firewall::load_security_groups(); + + my $rules = $groups_conf->{rules}->{$param->{group}}; + die "no such security group\n" if !defined($rules); + + my $digest = $groups_conf->{digest}; + + my $rule = { type => 'out', action => 'ACCEPT', enable => 0}; + + PVE::Firewall::copy_rule_data($rule, $param); + + unshift @$rules, $rule; + + PVE::Firewall::save_security_groups($groups_conf); + + return undef; + }}); + +__PACKAGE__->register_method({ + name => 'update_rule', + path => '{group}/{pos}', + method => 'PUT', + description => "Modify rule data.", + proxyto => 'node', + protected => 1, + parameters => { + additionalProperties => 0, + properties => PVE::Firewall::add_rule_properties({ + node => get_standard_option('pve-node'), + group => { + description => "Security group name.", + type => 'string', + }, + moveto => { + description => "Move rule to new position .", + type => 'integer', + minimum => 0, + optional => 1, + }, + }), + }, + returns => { type => "null" }, + code => sub { + my ($param) = @_; + + my $groups_conf = PVE::Firewall::load_security_groups(); + + my $rules = $groups_conf->{rules}->{$param->{group}}; + die "no such security group\n" if !defined($rules); + + my $digest = $groups_conf->{digest}; + # fixme: check digest + + die "no rule at position $param->{pos}\n" if $param->{pos} >= scalar(@$rules); + + my $rule = $rules->[$param->{pos}]; + + PVE::Firewall::copy_rule_data($rule, $param); + + 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, $rule if $moveto >= scalar(@$rules); + + $groups_conf->{rules}->{$param->{group}} = $newrules; + } + + PVE::Firewall::save_security_groups($groups_conf); + + return undef; + }}); + +__PACKAGE__->register_method({ + name => 'delete_rule', + path => '{group}/{pos}', + method => 'DELETE', + description => "Delete rule.", + proxyto => 'node', + protected => 1, + parameters => { + additionalProperties => 0, + properties => { + node => get_standard_option('pve-node'), + group => { + description => "Security group name.", + type => 'string', + }, + pos => { + description => "Delete rule at position .", + type => 'integer', + minimum => 0, + }, + }, + }, + returns => { type => "null" }, + code => sub { + my ($param) = @_; + + my $groups_conf = PVE::Firewall::load_security_groups(); + + my $rules = $groups_conf->{rules}->{$param->{group}}; + die "no such security group\n" if !defined($rules); + + my $digest = $groups_conf->{digest}; + # fixme: check digest + + die "no rule at position $param->{pos}\n" if $param->{pos} >= scalar(@$rules); + + splice(@$rules, $param->{pos}, 1); + + PVE::Firewall::save_security_groups($groups_conf); + + return undef; + }}); + 1; diff --git a/src/PVE/Firewall.pm b/src/PVE/Firewall.pm index 2f8fc51..2eb8a0e 100644 --- a/src/PVE/Firewall.pm +++ b/src/PVE/Firewall.pm @@ -655,6 +655,84 @@ sub cleanup_fw_rule { return $r; } +my $rule_properties = { + pos => { + description => "Update rule at position .", + type => 'integer', + minimum => 0, + optional => 1, + }, + digest => { + type => 'string', + optional => 1, + }, + type => { + type => 'string', + optional => 1, + enum => ['in', 'out', 'group'], + }, + action => { + type => 'string', + optional => 1, + }, + source => { + type => 'string', + optional => 1, + }, + dest => { + type => 'string', + optional => 1, + }, + proto => { + type => 'string', + optional => 1, + }, + enable => { + type => 'boolean', + optional => 1, + }, + sport => { + type => 'string', + optional => 1, + }, + dport => { + type => 'string', + optional => 1, + }, + comment => { + type => 'string', + optional => 1, + }, +}; + +sub add_rule_properties { + my ($properties) = @_; + + foreach my $k (keys %$rule_properties) { + $properties->{$k} = $rule_properties->{$k}; + } + + return $properties; +} + +sub copy_rule_data { + my ($rule, $param) = @_; + + foreach my $k (keys %$rule_properties) { + if (defined(my $v = $param->{$k})) { + if ($v eq '' || $v eq '-') { + delete $rule->{$k}; + } else { + $rule->{$k} = $v; + } + } else { + delete $rule->{$k}; + } + } + return $rule; +} + +# core functions my $bridge_firewall_enabled = 0; sub enable_bridge_firewall { @@ -1807,6 +1885,40 @@ sub load_security_groups { return $groups_conf; } +sub save_security_groups { + my ($groups_conf) = @_; + + my $raw = ''; + my $filename = "/etc/pve/firewall/groups.fw"; + + foreach my $group (sort keys %{$groups_conf->{rules}}) { + my $rules = $groups_conf->{rules}->{$group}; + $raw .= "[group $group]\n\n"; + + foreach my $rule (@$rules) { + if ($rule->{type} eq 'in' || $rule->{type} eq 'out') { + $raw .= '|' if defined($rule->{enable}) && !$rule->{enable}; + $raw .= uc($rule->{type}); + $raw .= " " . $rule->{action}; + $raw .= " " . ($rule->{source} || '-'); + $raw .= " " . ($rule->{dest} || '-'); + $raw .= " " . ($rule->{proto} || '-'); + $raw .= " " . ($rule->{dport} || '-'); + $raw .= " " . ($rule->{sport} || '-'); + $raw .= " # " . encode('utf8', $rule->{comment}) + if $rule->{comment} && $rule->{comment} !~ m/^\s*$/; + $raw .= "\n"; + } else { + die "implement me '$rule->{type}'"; + } + } + + $raw .= "\n"; + } + + PVE::Tools::file_set_contents($filename, $raw); +} + sub load_hostfw_conf { my $hostfw_conf = {};