X-Git-Url: https://git.proxmox.com/?p=pve-firewall.git;a=blobdiff_plain;f=src%2FPVE%2FAPI2%2FFirewall%2FVM.pm;h=48b8c5fe2a974a02a0bb37d54fd4317b3d9f8cf6;hp=3d39978fc3b91ff6b563f1aeccd35e61f0666a72;hb=HEAD;hpb=464f933e74591889a8c9569eee3da71a812c905e diff --git a/src/PVE/API2/Firewall/VM.pm b/src/PVE/API2/Firewall/VM.pm index 3d39978..4222103 100644 --- a/src/PVE/API2/Firewall/VM.pm +++ b/src/PVE/API2/Firewall/VM.pm @@ -1,89 +1,339 @@ -package PVE::API2::Firewall::VM; +package PVE::API2::Firewall::VMBase; use strict; use warnings; + +use PVE::Exception qw(raise_param_exc); use PVE::JSONSchema qw(get_standard_option); use PVE::Cluster; use PVE::Firewall; use PVE::API2::Firewall::Rules; +use PVE::API2::Firewall::Aliases; -use Data::Dumper; # fixme: remove use base qw(PVE::RESTHandler); -__PACKAGE__->register_method ({ - subclass => "PVE::API2::Firewall::VMRules", - path => 'rules', -}); +my $option_properties = $PVE::Firewall::vm_option_properties; + +my $add_option_properties = sub { + my ($properties) = @_; + + foreach my $k (keys %$option_properties) { + $properties->{$k} = $option_properties->{$k}; + } + + return $properties; +}; + +sub register_handlers { + my ($class, $rule_env) = @_; -__PACKAGE__->register_method({ - name => 'index', - path => '', - method => 'GET', - permissions => { user => 'all' }, - description => "Directory index.", - parameters => { - additionalProperties => 0, - properties => { - node => get_standard_option('pve-node'), - vmid => get_standard_option('pve-vmid'), + $class->register_method({ + name => 'index', + path => '', + method => 'GET', + permissions => { user => 'all' }, + description => "Directory index.", + parameters => { + additionalProperties => 0, + properties => { + node => get_standard_option('pve-node'), + vmid => get_standard_option('pve-vmid'), + }, }, - }, - returns => { - type => 'array', - items => { + returns => { + type => 'array', + items => { + type => "object", + properties => {}, + }, + links => [ { rel => 'child', href => "{name}" } ], + }, + code => sub { + my ($param) = @_; + + my $result = [ + { name => 'rules' }, + { name => 'aliases' }, + { name => 'ipset' }, + { name => 'refs' }, + { name => 'options' }, + ]; + + return $result; + }}); + + + $class->register_method({ + name => 'get_options', + path => 'options', + method => 'GET', + description => "Get VM firewall options.", + proxyto => 'node', + permissions => { + check => ['perm', '/vms/{vmid}', [ 'VM.Audit' ]], + }, + parameters => { + additionalProperties => 0, + properties => { + node => get_standard_option('pve-node'), + vmid => get_standard_option('pve-vmid'), + }, + }, + returns => { type => "object", - properties => {}, + #additionalProperties => 1, + properties => $option_properties, }, - links => [ { rel => 'child', href => "{name}" } ], - }, - code => sub { - my ($param) = @_; - - my $result = [ - { name => 'rules' }, - { name => 'options' }, - ]; - - return $result; - }}); - -__PACKAGE__->register_method({ - name => 'get_options', - path => 'options', - method => 'GET', - description => "Get host firewall options.", - proxyto => 'node', - parameters => { - additionalProperties => 0, - properties => { - node => get_standard_option('pve-node'), - vmid => get_standard_option('pve-vmid'), + code => sub { + my ($param) = @_; + + my $cluster_conf = PVE::Firewall::load_clusterfw_conf(); + my $vmfw_conf = PVE::Firewall::load_vmfw_conf($cluster_conf, $rule_env, $param->{vmid}); + + return PVE::Firewall::copy_opject_with_digest($vmfw_conf->{options}); + }}); + + $class->register_method({ + name => 'set_options', + path => 'options', + method => 'PUT', + description => "Set Firewall options.", + protected => 1, + proxyto => 'node', + permissions => { + check => ['perm', '/vms/{vmid}', [ 'VM.Config.Network' ]], + }, + parameters => { + additionalProperties => 0, + properties => &$add_option_properties({ + node => get_standard_option('pve-node'), + vmid => get_standard_option('pve-vmid'), + delete => { + type => 'string', format => 'pve-configid-list', + description => "A list of settings you want to delete.", + optional => 1, + }, + digest => get_standard_option('pve-config-digest'), + }), }, - }, - returns => { - type => "object", - properties => {}, - }, - code => sub { - my ($param) = @_; + returns => { type => "null" }, + code => sub { + my ($param) = @_; + + PVE::Firewall::lock_vmfw_conf($param->{vmid}, 10, sub { + my $cluster_conf = PVE::Firewall::load_clusterfw_conf(); + my $vmfw_conf = PVE::Firewall::load_vmfw_conf($cluster_conf, $rule_env, $param->{vmid}); + + my (undef, $digest) = PVE::Firewall::copy_opject_with_digest($vmfw_conf->{options}); + PVE::Tools::assert_if_modified($digest, $param->{digest}); + + if ($param->{delete}) { + foreach my $opt (PVE::Tools::split_list($param->{delete})) { + raise_param_exc({ delete => "no such option '$opt'" }) + if !$option_properties->{$opt}; + delete $vmfw_conf->{options}->{$opt}; + } + } - my $vmid = $param->{vmid}; + if (defined($param->{enable})) { + $param->{enable} = $param->{enable} ? 1 : 0; + } - my $vmlist = PVE::Cluster::get_vmlist(); + foreach my $k (keys %$option_properties) { + next if !defined($param->{$k}); + $vmfw_conf->{options}->{$k} = $param->{$k}; + } - die "no such VM ('$vmid')\n" - if !($vmlist && $vmlist->{ids} && defined($vmlist->{ids}->{$vmid})); + PVE::Firewall::save_vmfw_conf($param->{vmid}, $vmfw_conf); + }); - my $vmfw_conf = PVE::Firewall::load_vmfw_conf($vmid); + return undef; + }}); + + $class->register_method({ + name => 'log', + path => 'log', + method => 'GET', + description => "Read firewall log", + proxyto => 'node', + permissions => { + check => ['perm', '/vms/{vmid}', [ 'VM.Console' ]], + }, + protected => 1, + parameters => { + additionalProperties => 0, + properties => { + node => get_standard_option('pve-node'), + vmid => get_standard_option('pve-vmid'), + start => { + type => 'integer', + minimum => 0, + optional => 1, + }, + limit => { + type => 'integer', + minimum => 0, + optional => 1, + }, + since => { + type => 'integer', + minimum => 0, + description => "Display log since this UNIX epoch.", + optional => 1, + }, + until => { + type => 'integer', + minimum => 0, + description => "Display log until this UNIX epoch.", + optional => 1, + }, + }, + }, + returns => { + type => 'array', + items => { + type => "object", + properties => { + n => { + description=> "Line number", + type=> 'integer', + }, + t => { + description=> "Line text", + type => 'string', + } + } + } + }, + code => sub { + my ($param) = @_; - my $options = $vmfw_conf->{options} || {}; + my $rpcenv = PVE::RPCEnvironment::get(); + my $user = $rpcenv->get_user(); + my $filename = "/var/log/pve-firewall.log"; + my $vmid = $param->{'vmid'}; - my $digest = $vmfw_conf->{digest}; + my $callback = sub { + my ($line) = @_; + my $reg = "^$vmid "; + return $line =~ m/$reg/; + }; + + my ($count, $lines) = PVE::Firewall::Helpers::dump_fw_logfile( + $filename, $param, $callback); + + $rpcenv->set_result_attrib('total', $count); + + return $lines; + }}); + + + $class->register_method({ + name => 'refs', + path => 'refs', + method => 'GET', + description => "Lists possible IPSet/Alias reference which are allowed in source/dest properties.", + permissions => { + check => ['perm', '/vms/{vmid}', [ 'VM.Audit' ]], + }, + parameters => { + additionalProperties => 0, + properties => { + node => get_standard_option('pve-node'), + vmid => get_standard_option('pve-vmid'), + type => { + description => "Only list references of specified type.", + type => 'string', + enum => ['alias', 'ipset'], + optional => 1, + }, + }, + }, + returns => { + type => 'array', + items => { + type => "object", + properties => { + type => { + type => 'string', + enum => ['alias', 'ipset'], + }, + name => { + type => 'string', + }, + ref => { + type => 'string', + }, + scope => { + type => 'string', + }, + comment => { + type => 'string', + optional => 1, + }, + }, + }, + }, + code => sub { + my ($param) = @_; - $options->{digest} = $digest; + my $cluster_conf = PVE::Firewall::load_clusterfw_conf(); + my $fw_conf = PVE::Firewall::load_vmfw_conf($cluster_conf, $rule_env, $param->{vmid}); + + my $dc_refs = PVE::Firewall::Helpers::collect_refs($cluster_conf, $param->{type}, 'dc'); + my $vm_refs = PVE::Firewall::Helpers::collect_refs($fw_conf, $param->{type}, 'guest'); + + return [@$dc_refs, @$vm_refs]; + }}); +} + +package PVE::API2::Firewall::VM; + +use strict; +use warnings; + +use base qw(PVE::API2::Firewall::VMBase); + +__PACKAGE__->register_method ({ + subclass => "PVE::API2::Firewall::VMRules", + path => 'rules', +}); + +__PACKAGE__->register_method ({ + subclass => "PVE::API2::Firewall::VMAliases", + path => 'aliases', +}); + +__PACKAGE__->register_method ({ + subclass => "PVE::API2::Firewall::VMIPSetList", + path => 'ipset', +}); + +__PACKAGE__->register_handlers('vm'); + +package PVE::API2::Firewall::CT; + +use strict; +use warnings; + +use base qw(PVE::API2::Firewall::VMBase); + +__PACKAGE__->register_method ({ + subclass => "PVE::API2::Firewall::CTRules", + path => 'rules', +}); + +__PACKAGE__->register_method ({ + subclass => "PVE::API2::Firewall::CTAliases", + path => 'aliases', +}); + +__PACKAGE__->register_method ({ + subclass => "PVE::API2::Firewall::CTIPSetList", + path => 'ipset', +}); - return $options; - }}); +__PACKAGE__->register_handlers('vm'); 1;