Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
use base qw(PVE::RESTHandler);
use base qw(PVE::RESTHandler);
cidr => {
description => "Network/IP specification in CIDR format.",
type => 'string', format => 'IPorCIDR',
cidr => {
description => "Network/IP specification in CIDR format.",
type => 'string', format => 'IPorCIDR',
sub rule_env {
my ($class, $param) = @_;
sub rule_env {
my ($class, $param) = @_;
die "implement this in subclass";
}
die "implement this in subclass";
}
type => 'string',
optional => 1,
},
type => 'string',
optional => 1,
},
- digest => get_standard_option('pve-config-digest', { optional => 0} ),
+ digest => get_standard_option('pve-config-digest', { optional => 0} ),
},
},
links => [ { rel => 'child', href => "{name}" } ],
},
},
links => [ { rel => 'child', href => "{name}" } ],
my ($fw_conf, $aliases) = $class->load_config($param);
my $name = lc($param->{name});
my ($fw_conf, $aliases) = $class->load_config($param);
my $name = lc($param->{name});
-
- raise_param_exc({ name => "alias '$param->{name}' already exists" })
+
+ raise_param_exc({ name => "alias '$param->{name}' already exists" })
if defined($aliases->{$name});
if defined($aliases->{$name});
my $data = { name => $param->{name}, cidr => $param->{cidr} };
$data->{comment} = $param->{comment} if $param->{comment};
my $data = { name => $param->{name}, cidr => $param->{cidr} };
$data->{comment} = $param->{comment} if $param->{comment};
my $properties = $class->additional_parameters();
$properties->{name} = $api_properties->{name};
my $properties = $class->additional_parameters();
$properties->{name} = $api_properties->{name};
$class->register_method({
name => 'read_alias',
path => '{name}',
$class->register_method({
name => 'read_alias',
path => '{name}',
$rename = lc($rename) if $rename;
if ($rename && ($name ne $rename)) {
$rename = lc($rename) if $rename;
if ($rename && ($name ne $rename)) {
- raise_param_exc({ name => "alias '$param->{rename}' already exists" })
+ raise_param_exc({ name => "alias '$param->{rename}' already exists" })
if defined($aliases->{$rename});
$aliases->{$name}->{name} = $param->{rename};
$aliases->{$rename} = $aliases->{$name};
if defined($aliases->{$rename});
$aliases->{$name}->{name} = $param->{rename};
$aliases->{$rename} = $aliases->{$name};
delete $aliases->{$name};
$class->save_aliases($param, $fw_conf, $aliases);
delete $aliases->{$name};
$class->save_aliases($param, $fw_conf, $aliases);
sub rule_env {
my ($class, $param) = @_;
sub rule_env {
my ($class, $param) = @_;
sub rule_env {
my ($class, $param) = @_;
sub rule_env {
my ($class, $param) = @_;
-__PACKAGE__->additional_parameters({
+__PACKAGE__->additional_parameters({
node => get_standard_option('pve-node'),
node => get_standard_option('pve-node'),
- vmid => get_standard_option('pve-vmid'),
+ vmid => get_standard_option('pve-vmid'),
sub rule_env {
my ($class, $param) = @_;
sub rule_env {
my ($class, $param) = @_;
-__PACKAGE__->additional_parameters({
+__PACKAGE__->additional_parameters({
node => get_standard_option('pve-node'),
node => get_standard_option('pve-node'),
- vmid => get_standard_option('pve-vmid'),
+ vmid => get_standard_option('pve-vmid'),
my $res = [];
foreach my $group (sort keys %{$cluster_conf->{groups}}) {
my $res = [];
foreach my $group (sort keys %{$cluster_conf->{groups}}) {
group => $group,
};
if (my $comment = $cluster_conf->{group_comments}->{$group}) {
group => $group,
};
if (my $comment = $cluster_conf->{group_comments}->{$group}) {
type => 'array',
items => {
type => "object",
type => 'array',
items => {
type => "object",
group => get_standard_option('pve-security-group-name'),
digest => get_standard_option('pve-config-digest', { optional => 0} ),
group => get_standard_option('pve-security-group-name'),
digest => get_standard_option('pve-config-digest', { optional => 0} ),
type => 'string',
optional => 1,
}
type => 'string',
optional => 1,
}
},
parameters => {
additionalProperties => 0,
},
parameters => {
additionalProperties => 0,
group => get_standard_option('pve-security-group-name'),
comment => {
type => 'string',
group => get_standard_option('pve-security-group-name'),
comment => {
type => 'string',
my (undef, $digest) = &$get_security_group_list($cluster_conf);
PVE::Tools::assert_if_modified($digest, $param->{digest});
my (undef, $digest) = &$get_security_group_list($cluster_conf);
PVE::Tools::assert_if_modified($digest, $param->{digest});
- raise_param_exc({ group => "Security group '$param->{rename}' does not exists" })
+ raise_param_exc({ group => "Security group '$param->{rename}' does not exist" })
if !$cluster_conf->{groups}->{$param->{rename}};
# prevent overwriting an existing group
if !$cluster_conf->{groups}->{$param->{rename}};
# prevent overwriting an existing group
$cluster_conf->{group_comments}->{$param->{group}} = $param->{comment} if defined($param->{comment});
} else {
foreach my $name (keys %{$cluster_conf->{groups}}) {
$cluster_conf->{group_comments}->{$param->{group}} = $param->{comment} if defined($param->{comment});
} else {
foreach my $name (keys %{$cluster_conf->{groups}}) {
- raise_param_exc({ group => "Security group '$name' already exists" })
+ raise_param_exc({ group => "Security group '$name' already exists" })
if $name eq $param->{group};
}
if $name eq $param->{group};
}
}
PVE::Firewall::save_clusterfw_conf($cluster_conf);
}
PVE::Firewall::save_clusterfw_conf($cluster_conf);
return undef;
}});
__PACKAGE__->register_method ({
return undef;
}});
__PACKAGE__->register_method ({
- subclass => "PVE::API2::Firewall::GroupRules",
+ subclass => "PVE::API2::Firewall::GroupRules",
use base qw(PVE::RESTHandler);
__PACKAGE__->register_method ({
use base qw(PVE::RESTHandler);
__PACKAGE__->register_method ({
- subclass => "PVE::API2::Firewall::HostRules",
+ subclass => "PVE::API2::Firewall::HostRules",
foreach my $k (keys %$option_properties) {
$properties->{$k} = $option_properties->{$k};
}
foreach my $k (keys %$option_properties) {
$properties->{$k} = $option_properties->{$k};
}
if ($param->{delete}) {
foreach my $opt (PVE::Tools::split_list($param->{delete})) {
if ($param->{delete}) {
foreach my $opt (PVE::Tools::split_list($param->{delete})) {
- raise_param_exc({ delete => "no such option '$opt'" })
+ raise_param_exc({ delete => "no such option '$opt'" })
if !$option_properties->{$opt};
delete $hostfw_conf->{options}->{$opt};
}
if !$option_properties->{$opt};
delete $hostfw_conf->{options}->{$opt};
}
foreach my $k (keys %$option_properties) {
next if !defined($param->{$k});
foreach my $k (keys %$option_properties) {
next if !defined($param->{$k});
- $hostfw_conf->{options}->{$k} = $param->{$k};
+ $hostfw_conf->{options}->{$k} = $param->{$k};
}
PVE::Firewall::save_hostfw_conf($hostfw_conf);
}
PVE::Firewall::save_hostfw_conf($hostfw_conf);
}});
__PACKAGE__->register_method({
}});
__PACKAGE__->register_method({
- name => 'log',
- path => 'log',
+ name => 'log',
+ path => 'log',
method => 'GET',
description => "Read firewall log",
proxyto => 'node',
method => 'GET',
description => "Read firewall log",
proxyto => 'node',
},
returns => {
type => 'array',
},
returns => {
type => 'array',
type => "object",
properties => {
n => {
type => "object",
properties => {
n => {
my ($count, $lines) = PVE::Tools::dump_logfile("/var/log/pve-firewall.log", $param->{start}, $param->{limit});
$rpcenv->set_result_attrib('total', $count);
my ($count, $lines) = PVE::Tools::dump_logfile("/var/log/pve-firewall.log", $param->{start}, $param->{limit});
$rpcenv->set_result_attrib('total', $count);
use base qw(PVE::RESTHandler);
use base qw(PVE::RESTHandler);
cidr => {
description => "Network/IP specification in CIDR format.",
type => 'string', format => 'IPorCIDRorAlias',
cidr => {
description => "Network/IP specification in CIDR format.",
type => 'string', format => 'IPorCIDRorAlias',
sub rule_env {
my ($class, $param) = @_;
sub rule_env {
my ($class, $param) = @_;
die "implement this in subclass";
}
die "implement this in subclass";
}
type => 'boolean',
optional => 1,
},
type => 'boolean',
optional => 1,
},
- digest => get_standard_option('pve-config-digest', { optional => 0} ),
+ digest => get_standard_option('pve-config-digest', { optional => 0} ),
},
},
links => [ { rel => 'child', href => "{cidr}" } ],
},
},
links => [ { rel => 'child', href => "{cidr}" } ],
returns => { type => 'null' },
code => sub {
my ($param) = @_;
returns => { type => 'null' },
code => sub {
my ($param) = @_;
my ($cluster_conf, $fw_conf, $ipset) = $class->load_config($param);
my ($cluster_conf, $fw_conf, $ipset) = $class->load_config($param);
- die "IPSet '$param->{name}' is not empty\n"
+ die "IPSet '$param->{name}' is not empty\n"
if scalar(@$ipset);
$class->save_ipset($param, $fw_conf, undef);
if scalar(@$ipset);
$class->save_ipset($param, $fw_conf, undef);
my ($cluster_conf, $fw_conf, $ipset) = $class->load_config($param);
my $cidr = $param->{cidr};
my ($cluster_conf, $fw_conf, $ipset) = $class->load_config($param);
my $cidr = $param->{cidr};
foreach my $entry (@$ipset) {
foreach my $entry (@$ipset) {
- raise_param_exc({ cidr => "address '$cidr' already exists" })
+ raise_param_exc({ cidr => "address '$cidr' already exists" })
if $entry->{cidr} eq $cidr;
}
if $entry->{cidr} eq $cidr;
}
$properties->{name} = $api_properties->{name};
$properties->{cidr} = $api_properties->{cidr};
$properties->{name} = $api_properties->{name};
$properties->{cidr} = $api_properties->{cidr};
$class->register_method({
name => 'read_ip',
path => '{cidr}',
$class->register_method({
name => 'read_ip',
path => '{cidr}',
PVE::Tools::assert_if_modified($digest, $param->{digest});
my $new = [];
PVE::Tools::assert_if_modified($digest, $param->{digest});
my $new = [];
foreach my $entry (@$ipset) {
push @$new, $entry if $entry->{cidr} ne $param->{cidr};
}
$class->save_ipset($param, $fw_conf, $new);
foreach my $entry (@$ipset) {
push @$new, $entry if $entry->{cidr} ne $param->{cidr};
}
$class->save_ipset($param, $fw_conf, $new);
sub rule_env {
my ($class, $param) = @_;
sub rule_env {
my ($class, $param) = @_;
sub rule_env {
my ($class, $param) = @_;
sub rule_env {
my ($class, $param) = @_;
-__PACKAGE__->additional_parameters({
+__PACKAGE__->additional_parameters({
node => get_standard_option('pve-node'),
node => get_standard_option('pve-node'),
- vmid => get_standard_option('pve-vmid'),
+ vmid => get_standard_option('pve-vmid'),
sub rule_env {
my ($class, $param) = @_;
sub rule_env {
my ($class, $param) = @_;
-__PACKAGE__->additional_parameters({
+__PACKAGE__->additional_parameters({
node => get_standard_option('pve-node'),
node => get_standard_option('pve-node'),
- vmid => get_standard_option('pve-vmid'),
+ vmid => get_standard_option('pve-vmid'),
sub load_config {
my ($class, $param) = @_;
sub load_config {
my ($class, $param) = @_;
die "implement this in subclass";
#return ($cluster_conf, $fw_conf);
die "implement this in subclass";
#return ($cluster_conf, $fw_conf);
sub rule_env {
my ($class, $param) = @_;
sub rule_env {
my ($class, $param) = @_;
die "implement this in subclass";
}
die "implement this in subclass";
}
my $res = [];
foreach my $name (sort keys %{$fw_conf->{ipset}}) {
my $res = [];
foreach my $name (sort keys %{$fw_conf->{ipset}}) {
name => $name,
};
if (my $comment = $fw_conf->{ipset_comments}->{$name}) {
name => $name,
};
if (my $comment = $fw_conf->{ipset_comments}->{$name}) {
type => 'array',
items => {
type => "object",
type => 'array',
items => {
type => "object",
name => get_standard_option('ipset-name'),
digest => get_standard_option('pve-config-digest', { optional => 0} ),
name => get_standard_option('ipset-name'),
digest => get_standard_option('pve-config-digest', { optional => 0} ),
type => 'string',
optional => 1,
}
type => 'string',
optional => 1,
}
},
code => sub {
my ($param) = @_;
},
code => sub {
my ($param) = @_;
my ($cluster_conf, $fw_conf) = $class->load_config($param);
my ($cluster_conf, $fw_conf) = $class->load_config($param);
- return &$get_ipset_list($fw_conf);
+ return &$get_ipset_list($fw_conf);
returns => { type => 'null' },
code => sub {
my ($param) = @_;
returns => { type => 'null' },
code => sub {
my ($param) = @_;
my ($cluster_conf, $fw_conf) = $class->load_config($param);
if ($param->{rename}) {
my (undef, $digest) = &$get_ipset_list($fw_conf);
PVE::Tools::assert_if_modified($digest, $param->{digest});
my ($cluster_conf, $fw_conf) = $class->load_config($param);
if ($param->{rename}) {
my (undef, $digest) = &$get_ipset_list($fw_conf);
PVE::Tools::assert_if_modified($digest, $param->{digest});
- raise_param_exc({ name => "IPSet '$param->{rename}' does not exists" })
+ raise_param_exc({ name => "IPSet '$param->{rename}' does not exist" })
if !$fw_conf->{ipset}->{$param->{rename}};
# prevent overwriting existing ipset
if !$fw_conf->{ipset}->{$param->{rename}};
# prevent overwriting existing ipset
$fw_conf->{ipset_comments}->{$param->{name}} = $comment;
}
$fw_conf->{ipset_comments}->{$param->{name}} = $param->{comment} if defined($param->{comment});
$fw_conf->{ipset_comments}->{$param->{name}} = $comment;
}
$fw_conf->{ipset_comments}->{$param->{name}} = $param->{comment} if defined($param->{comment});
foreach my $name (keys %{$fw_conf->{ipset}}) {
foreach my $name (keys %{$fw_conf->{ipset}}) {
- raise_param_exc({ name => "IPSet '$name' already exists" })
+ raise_param_exc({ name => "IPSet '$name' already exists" })
if $name eq $param->{name};
}
if $name eq $param->{name};
}
sub rule_env {
my ($class, $param) = @_;
sub rule_env {
my ($class, $param) = @_;
return 'cluster';
}
sub load_config {
my ($class, $param) = @_;
return 'cluster';
}
sub load_config {
my ($class, $param) = @_;
my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
return (undef, $cluster_conf);
}
my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
return (undef, $cluster_conf);
}
__PACKAGE__->register_handlers();
__PACKAGE__->register_method ({
__PACKAGE__->register_handlers();
__PACKAGE__->register_method ({
- subclass => "PVE::API2::Firewall::ClusterIPset",
+ subclass => "PVE::API2::Firewall::ClusterIPset",
- # set fragment delimiter (no subdirs) - we need that, because CIDR address contain a slash '/'
- fragmentDelimiter => '',
+ # set fragment delimiter (no subdirs) - we need that, because CIDR address contain a slash '/'
+ fragmentDelimiter => '',
});
package PVE::API2::Firewall::VMIPSetList;
});
package PVE::API2::Firewall::VMIPSetList;
use base qw(PVE::API2::Firewall::BaseIPSetList);
use base qw(PVE::API2::Firewall::BaseIPSetList);
-__PACKAGE__->additional_parameters({
+__PACKAGE__->additional_parameters({
node => get_standard_option('pve-node'),
node => get_standard_option('pve-node'),
- vmid => get_standard_option('pve-vmid'),
+ vmid => get_standard_option('pve-vmid'),
});
sub rule_env {
my ($class, $param) = @_;
});
sub rule_env {
my ($class, $param) = @_;
return 'vm';
}
sub load_config {
my ($class, $param) = @_;
return 'vm';
}
sub load_config {
my ($class, $param) = @_;
my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
my $fw_conf = PVE::Firewall::load_vmfw_conf($cluster_conf, 'vm', $param->{vmid});
return ($cluster_conf, $fw_conf);
my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
my $fw_conf = PVE::Firewall::load_vmfw_conf($cluster_conf, 'vm', $param->{vmid});
return ($cluster_conf, $fw_conf);
__PACKAGE__->register_handlers();
__PACKAGE__->register_method ({
__PACKAGE__->register_handlers();
__PACKAGE__->register_method ({
- subclass => "PVE::API2::Firewall::VMIPset",
+ subclass => "PVE::API2::Firewall::VMIPset",
- # set fragment delimiter (no subdirs) - we need that, because CIDR address contain a slash '/'
- fragmentDelimiter => '',
+ # set fragment delimiter (no subdirs) - we need that, because CIDR address contain a slash '/'
+ fragmentDelimiter => '',
});
package PVE::API2::Firewall::CTIPSetList;
});
package PVE::API2::Firewall::CTIPSetList;
use base qw(PVE::API2::Firewall::BaseIPSetList);
use base qw(PVE::API2::Firewall::BaseIPSetList);
-__PACKAGE__->additional_parameters({
+__PACKAGE__->additional_parameters({
node => get_standard_option('pve-node'),
node => get_standard_option('pve-node'),
- vmid => get_standard_option('pve-vmid'),
+ vmid => get_standard_option('pve-vmid'),
});
sub rule_env {
my ($class, $param) = @_;
});
sub rule_env {
my ($class, $param) = @_;
return 'ct';
}
sub load_config {
my ($class, $param) = @_;
return 'ct';
}
sub load_config {
my ($class, $param) = @_;
my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
my $fw_conf = PVE::Firewall::load_vmfw_conf($cluster_conf, 'ct', $param->{vmid});
return ($cluster_conf, $fw_conf);
my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
my $fw_conf = PVE::Firewall::load_vmfw_conf($cluster_conf, 'ct', $param->{vmid});
return ($cluster_conf, $fw_conf);
__PACKAGE__->register_handlers();
__PACKAGE__->register_method ({
__PACKAGE__->register_handlers();
__PACKAGE__->register_method ({
- subclass => "PVE::API2::Firewall::CTIPset",
+ subclass => "PVE::API2::Firewall::CTIPset",
- # set fragment delimiter (no subdirs) - we need that, because CIDR address contain a slash '/'
- fragmentDelimiter => '',
+ # set fragment delimiter (no subdirs) - we need that, because CIDR address contain a slash '/'
+ fragmentDelimiter => '',
use base qw(PVE::RESTHandler);
use base qw(PVE::RESTHandler);
pos => {
description => "Rule position.",
type => 'integer',
pos => {
description => "Rule position.",
type => 'integer',
sub rule_env {
my ($class, $param) = @_;
sub rule_env {
my ($class, $param) = @_;
die "implement this in subclass";
}
die "implement this in subclass";
}
my $properties = $class->additional_parameters();
$properties->{pos} = $api_properties->{pos};
my $properties = $class->additional_parameters();
$properties->{pos} = $api_properties->{pos};
my $rule_env = $class->rule_env();
$class->register_method({
my $rule_env = $class->rule_env();
$class->register_method({
my ($cluster_conf, $fw_conf, $rules) = $class->load_config($param);
my ($list, $digest) = PVE::Firewall::copy_list_with_digest($rules);
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);
die "no rule at position $param->{pos}\n" if $param->{pos} >= scalar(@$list);
my $rule = $list->[$param->{pos}];
$rule->{pos} = $param->{pos};
my $rule = $list->[$param->{pos}];
$rule->{pos} = $param->{pos};
my $create_rule_properties = PVE::Firewall::add_rule_properties($properties);
$create_rule_properties->{action}->{optional} = 0;
$create_rule_properties->{type}->{optional} = 0;
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({
my $rule_env = $class->rule_env();
$class->register_method({
my $properties = $class->additional_parameters();
$properties->{pos} = $api_properties->{pos};
my $properties = $class->additional_parameters();
$properties->{pos} = $api_properties->{pos};
my $rule_env = $class->rule_env();
$properties->{moveto} = {
my $rule_env = $class->rule_env();
$properties->{moveto} = {
PVE::Tools::assert_if_modified($digest, $param->{digest});
die "no rule at position $param->{pos}\n" if $param->{pos} >= scalar(@$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}];
my $moveto = $param->{moveto};
my $rule = $rules->[$param->{pos}];
my $moveto = $param->{moveto};
$rules = $newrules;
} else {
PVE::Firewall::copy_rule_data($rule, $param);
$rules = $newrules;
} else {
PVE::Firewall::copy_rule_data($rule, $param);
PVE::Firewall::delete_rule_properties($rule, $param->{'delete'}) if $param->{'delete'};
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());
$properties->{pos} = $api_properties->{pos};
$properties->{digest} = get_standard_option('pve-config-digest');
$properties->{pos} = $api_properties->{pos};
$properties->{digest} = get_standard_option('pve-config-digest');
my $rule_env = $class->rule_env();
$class->register_method({
my $rule_env = $class->rule_env();
$class->register_method({
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);
die "no rule at position $param->{pos}\n" if $param->{pos} >= scalar(@$rules);
splice(@$rules, $param->{pos}, 1);
splice(@$rules, $param->{pos}, 1);
$class->save_rules($param, $fw_conf, $rules);
return undef;
$class->save_rules($param, $fw_conf, $rules);
return undef;
sub rule_env {
my ($class, $param) = @_;
sub rule_env {
my ($class, $param) = @_;
},
parameters => {
additionalProperties => 0,
},
parameters => {
additionalProperties => 0,
group => get_standard_option('pve-security-group-name'),
},
},
returns => { type => 'null' },
code => sub {
my ($param) = @_;
group => get_standard_option('pve-security-group-name'),
},
},
returns => { type => 'null' },
code => sub {
my ($param) = @_;
my (undef, $cluster_conf, $rules) = __PACKAGE__->load_config($param);
my (undef, $cluster_conf, $rules) = __PACKAGE__->load_config($param);
- die "Security group '$param->{group}' is not empty\n"
+ die "Security group '$param->{group}' is not empty\n"
if scalar(@$rules);
__PACKAGE__->save_rules($param, $cluster_conf, undef);
if scalar(@$rules);
__PACKAGE__->save_rules($param, $cluster_conf, undef);
sub rule_env {
my ($class, $param) = @_;
sub rule_env {
my ($class, $param) = @_;
sub rule_env {
my ($class, $param) = @_;
sub rule_env {
my ($class, $param) = @_;
use base qw(PVE::API2::Firewall::RulesBase);
use base qw(PVE::API2::Firewall::RulesBase);
-__PACKAGE__->additional_parameters({
+__PACKAGE__->additional_parameters({
node => get_standard_option('pve-node'),
node => get_standard_option('pve-node'),
- vmid => get_standard_option('pve-vmid'),
+ vmid => get_standard_option('pve-vmid'),
});
sub rule_env {
my ($class, $param) = @_;
});
sub rule_env {
my ($class, $param) = @_;
use base qw(PVE::API2::Firewall::RulesBase);
use base qw(PVE::API2::Firewall::RulesBase);
-__PACKAGE__->additional_parameters({
+__PACKAGE__->additional_parameters({
node => get_standard_option('pve-node'),
node => get_standard_option('pve-node'),
- vmid => get_standard_option('pve-vmid'),
+ vmid => get_standard_option('pve-vmid'),
});
sub rule_env {
my ($class, $param) = @_;
});
sub rule_env {
my ($class, $param) = @_;
foreach my $k (keys %$option_properties) {
$properties->{$k} = $option_properties->{$k};
}
foreach my $k (keys %$option_properties) {
$properties->{$k} = $option_properties->{$k};
}
if ($param->{delete}) {
foreach my $opt (PVE::Tools::split_list($param->{delete})) {
if ($param->{delete}) {
foreach my $opt (PVE::Tools::split_list($param->{delete})) {
- raise_param_exc({ delete => "no such option '$opt'" })
+ raise_param_exc({ delete => "no such option '$opt'" })
if !$option_properties->{$opt};
delete $vmfw_conf->{options}->{$opt};
}
if !$option_properties->{$opt};
delete $vmfw_conf->{options}->{$opt};
}
foreach my $k (keys %$option_properties) {
next if !defined($param->{$k});
foreach my $k (keys %$option_properties) {
next if !defined($param->{$k});
- $vmfw_conf->{options}->{$k} = $param->{$k};
+ $vmfw_conf->{options}->{$k} = $param->{$k};
}
PVE::Firewall::save_vmfw_conf($param->{vmid}, $vmfw_conf);
}
PVE::Firewall::save_vmfw_conf($param->{vmid}, $vmfw_conf);
return undef;
}});
$class->register_method({
return undef;
}});
$class->register_method({
- name => 'log',
- path => 'log',
+ name => 'log',
+ path => 'log',
method => 'GET',
description => "Read firewall log",
proxyto => 'node',
method => 'GET',
description => "Read firewall log",
proxyto => 'node',
},
returns => {
type => 'array',
},
returns => {
type => 'array',
type => "object",
properties => {
n => {
type => "object",
properties => {
n => {
my $user = $rpcenv->get_user();
my $vmid = $param->{vmid};
my $user = $rpcenv->get_user();
my $vmid = $param->{vmid};
- my ($count, $lines) = PVE::Tools::dump_logfile("/var/log/pve-firewall.log",
+ my ($count, $lines) = PVE::Tools::dump_logfile("/var/log/pve-firewall.log",
$param->{start}, $param->{limit},
"^$vmid ");
$param->{start}, $param->{limit},
"^$vmid ");
$rpcenv->set_result_attrib('total', $count);
$rpcenv->set_result_attrib('total', $count);
type => 'array',
items => {
type => "object",
type => 'array',
items => {
type => "object",
type => {
type => 'string',
enum => ['alias', 'ipset'],
type => {
type => 'string',
enum => ['alias', 'ipset'],
name => {
type => 'string',
},
name => {
type => 'string',
},
type => 'string',
optional => 1,
},
type => 'string',
optional => 1,
},
},
code => sub {
my ($param) = @_;
},
code => sub {
my ($param) = @_;
my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
my $fw_conf = PVE::Firewall::load_vmfw_conf($cluster_conf, $rule_env, $param->{vmid});
my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
my $fw_conf = PVE::Firewall::load_vmfw_conf($cluster_conf, $rule_env, $param->{vmid});
next if !$conf;
if (!$param->{type} || $param->{type} eq 'ipset') {
foreach my $name (keys %{$conf->{ipset}}) {
next if !$conf;
if (!$param->{type} || $param->{type} eq 'ipset') {
foreach my $name (keys %{$conf->{ipset}}) {
type => 'ipset',
name => $name,
ref => "+$name",
type => 'ipset',
name => $name,
ref => "+$name",
if (!$param->{type} || $param->{type} eq 'alias') {
foreach my $name (keys %{$conf->{aliases}}) {
my $e = $conf->{aliases}->{$name};
if (!$param->{type} || $param->{type} eq 'alias') {
foreach my $name (keys %{$conf->{aliases}}) {
my $e = $conf->{aliases}->{$name};
type => 'alias',
name => $name,
ref => $name,
type => 'alias',
name => $name,
ref => $name,
my $res = [];
foreach my $e (values %$ipsets) { push @$res, $e; };
foreach my $e (values %$aliases) { push @$res, $e; };
my $res = [];
foreach my $e (values %$ipsets) { push @$res, $e; };
foreach my $e (values %$aliases) { push @$res, $e; };
use base qw(PVE::API2::Firewall::VMBase);
__PACKAGE__->register_method ({
use base qw(PVE::API2::Firewall::VMBase);
__PACKAGE__->register_method ({
- subclass => "PVE::API2::Firewall::VMRules",
+ subclass => "PVE::API2::Firewall::VMRules",
path => 'rules',
});
__PACKAGE__->register_method ({
path => 'rules',
});
__PACKAGE__->register_method ({
- subclass => "PVE::API2::Firewall::VMAliases",
+ subclass => "PVE::API2::Firewall::VMAliases",
path => 'aliases',
});
__PACKAGE__->register_method ({
path => 'aliases',
});
__PACKAGE__->register_method ({
- subclass => "PVE::API2::Firewall::VMIPSetList",
+ subclass => "PVE::API2::Firewall::VMIPSetList",
use base qw(PVE::API2::Firewall::VMBase);
__PACKAGE__->register_method ({
use base qw(PVE::API2::Firewall::VMBase);
__PACKAGE__->register_method ({
- subclass => "PVE::API2::Firewall::CTRules",
+ subclass => "PVE::API2::Firewall::CTRules",
path => 'rules',
});
__PACKAGE__->register_method ({
path => 'rules',
});
__PACKAGE__->register_method ({
- subclass => "PVE::API2::Firewall::CTAliases",
+ subclass => "PVE::API2::Firewall::CTAliases",
path => 'aliases',
});
__PACKAGE__->register_method ({
path => 'aliases',
});
__PACKAGE__->register_method ({
- subclass => "PVE::API2::Firewall::CTIPSetList",
+ subclass => "PVE::API2::Firewall::CTIPSetList",
}
# ipset names are limited to 31 characters,
}
# ipset names are limited to 31 characters,
-# and we use '-v4' or '-v6' to indicate IP versions,
-# and we use '_swap' suffix for atomic update,
+# and we use '-v4' or '-v6' to indicate IP versions,
+# and we use '_swap' suffix for atomic update,
# for example PVEFW-${VMID}-${ipset_name}_swap
my $max_iptables_ipset_name_length = 31 - length("PVEFW-") - length("_swap");
# for example PVEFW-${VMID}-${ipset_name}_swap
my $max_iptables_ipset_name_length = 31 - length("PVEFW-") - length("_swap");
my $source_ipversion = parse_address_list($rule->{source});
&$set_ip_version($source_ipversion);
};
my $source_ipversion = parse_address_list($rule->{source});
&$set_ip_version($source_ipversion);
};
- eval {
- my $dest_ipversion = parse_address_list($rule->{dest});
+ eval {
+ my $dest_ipversion = parse_address_list($rule->{dest});
&$set_ip_version($dest_ipversion);
};
&$add_error('dest', $@) if $@;
&$set_ip_version($dest_ipversion);
};
&$add_error('dest', $@) if $@;
if (!(defined($options->{dhcp}) && $options->{dhcp} == 0)) {
if ($ipversion == 4) {
if ($direction eq 'OUT') {
if (!(defined($options->{dhcp}) && $options->{dhcp} == 0)) {
if ($ipversion == 4) {
if ($direction eq 'OUT') {
- ruleset_generate_rule($ruleset, $chain, $ipversion,
+ ruleset_generate_rule($ruleset, $chain, $ipversion,
{ action => 'PVEFW-SET-ACCEPT-MARK',
proto => 'udp', sport => 68, dport => 67 });
} else {
{ action => 'PVEFW-SET-ACCEPT-MARK',
proto => 'udp', sport => 68, dport => 67 });
} else {
my ($cidr) = @_;
my $ipversion;
my ($cidr) = @_;
my $ipversion;
if ($cidr =~ m!^(?:$IPV6RE)(/(\d+))?$!) {
$cidr =~ s|/128$||;
$ipversion = 6;
if ($cidr =~ m!^(?:$IPV6RE)(/(\d+))?$!) {
$cidr =~ s|/128$||;
$ipversion = 6;
warn "$prefix: $err";
next;
}
warn "$prefix: $err";
next;
}
$res->{$section}->{$group} = [];
$res->{group_comments}->{$group} = decode('utf8', $comment)
if $comment;
$res->{$section}->{$group} = [];
$res->{group_comments}->{$group} = decode('utf8', $comment)
if $comment;
$section = 'ipset';
$group = lc($1);
my $comment = $2;
$section = 'ipset';
$group = lc($1);
my $comment = $2;
die "ipset name too long\n" if length($group) > $max_ipset_name_length;
die "invalid ipset name '$group'\n" if $group !~ m/^${ipset_name_pattern}$/;
};
die "ipset name too long\n" if length($group) > $max_ipset_name_length;
die "invalid ipset name '$group'\n" if $group !~ m/^${ipset_name_pattern}$/;
};
$errors->{nomatch} = "nomatch not supported by kernel";
}
$errors->{nomatch} = "nomatch not supported by kernel";
}
if ($cidr =~ m/^${ip_alias_pattern}$/) {
resolve_alias($cluster_conf, $res, $cidr); # make sure alias exists
} else {
if ($cidr =~ m/^${ip_alias_pattern}$/) {
resolve_alias($cluster_conf, $res, $cidr); # make sure alias exists
} else {
my $format_ipsets = sub {
my ($fw_conf) = @_;
my $format_ipsets = sub {
my ($fw_conf) = @_;
my $raw = '';
foreach my $ipset (sort keys %{$fw_conf->{ipset}}) {
my $raw = '';
foreach my $ipset (sort keys %{$fw_conf->{ipset}}) {
foreach my $vmid (keys %{$vmdata->{qemu}}) {
my $vmfw_conf = load_vmfw_conf($cluster_conf, 'vm', $vmid, $dir);
foreach my $vmid (keys %{$vmdata->{qemu}}) {
my $vmfw_conf = load_vmfw_conf($cluster_conf, 'vm', $vmid, $dir);
- next if !$vmfw_conf->{options}; # skip if file does not exists
+ next if !$vmfw_conf->{options}; # skip if file does not exist
$vmfw_configs->{$vmid} = $vmfw_conf;
}
foreach my $vmid (keys %{$vmdata->{lxc}}) {
my $vmfw_conf = load_vmfw_conf($cluster_conf, 'ct', $vmid, $dir);
$vmfw_configs->{$vmid} = $vmfw_conf;
}
foreach my $vmid (keys %{$vmdata->{lxc}}) {
my $vmfw_conf = load_vmfw_conf($cluster_conf, 'ct', $vmid, $dir);
- next if !$vmfw_conf->{options}; # skip if file does not exists
+ next if !$vmfw_conf->{options}; # skip if file does not exist
$vmfw_configs->{$vmid} = $vmfw_conf;
}
$vmfw_configs->{$vmid} = $vmfw_conf;
}
$raw .= &$format_aliases($aliases) if $aliases && scalar(keys %$aliases);
$raw .= &$format_ipsets($cluster_conf) if $cluster_conf->{ipset};
$raw .= &$format_aliases($aliases) if $aliases && scalar(keys %$aliases);
$raw .= &$format_ipsets($cluster_conf) if $cluster_conf->{ipset};
my $rules = $cluster_conf->{rules};
if ($rules && scalar(@$rules)) {
$raw .= "[RULES]\n\n";
my $rules = $cluster_conf->{rules};
if ($rules && scalar(@$rules)) {
$raw .= "[RULES]\n\n";
my $localnet_ver;
($localnet, $localnet_ver) = parse_ip_or_cidr(local_network() || '127.0.0.0/8');
my $localnet_ver;
($localnet, $localnet_ver) = parse_ip_or_cidr(local_network() || '127.0.0.0/8');
- $cluster_conf->{aliases}->{local_network} = {
+ $cluster_conf->{aliases}->{local_network} = {
name => 'local_network', cidr => $localnet, ipversion => $localnet_ver };
}
name => 'local_network', cidr => $localnet, ipversion => $localnet_ver };
}
my $ipset_chains = ipset_get_chains();
my $cmdlist = "";
my $ipset_chains = ipset_get_chains();
my $cmdlist = "";
foreach my $chain (keys %$ipset_chains) {
$cmdlist .= "flush $chain\n";
$cmdlist .= "destroy $chain\n";
foreach my $chain (keys %$ipset_chains) {
$cmdlist .= "flush $chain\n";
$cmdlist .= "destroy $chain\n";
sub reset_trace {
$trace = '';
}
sub reset_trace {
$trace = '';
}
return undef if $cstate eq 'INVALID'; # no match
return undef if $cstate eq 'RELATED,ESTABLISHED'; # no match
return undef if $cstate eq 'INVALID'; # no match
return undef if $cstate eq 'RELATED,ESTABLISHED'; # no match
next if $cstate =~ m/NEW/;
next if $cstate =~ m/NEW/;
die "cstate test '$cstate' not implemented\n";
}
if ($rule =~ s/^-m addrtype --src-type (\S+)\s*//) {
my $atype = $1;
die "cstate test '$cstate' not implemented\n";
}
if ($rule =~ s/^-m addrtype --src-type (\S+)\s*//) {
my $atype = $1;
- die "missing source address type (srctype)\n"
+ die "missing source address type (srctype)\n"
if !$pkg->{srctype};
return undef if $atype ne $pkg->{srctype};
}
if ($rule =~ s/^-m addrtype --dst-type (\S+)\s*//) {
my $atype = $1;
if !$pkg->{srctype};
return undef if $atype ne $pkg->{srctype};
}
if ($rule =~ s/^-m addrtype --dst-type (\S+)\s*//) {
my $atype = $1;
- die "missing destination address type (dsttype)\n"
+ die "missing destination address type (dsttype)\n"
if !$pkg->{dsttype};
return undef if $atype ne $pkg->{dsttype};
}
if !$pkg->{dsttype};
return undef if $atype ne $pkg->{dsttype};
}
return undef if !$ip->overlaps(Net::IP->new($pkg->{source})); # no match
next;
}
return undef if !$ip->overlaps(Net::IP->new($pkg->{source})); # no match
next;
}
if ($rule =~ s/^-d (\S+)\s*//) {
die "missing destination" if !$pkg->{dest};
my $ip = Net::IP->new($1);
if ($rule =~ s/^-d (\S+)\s*//) {
die "missing destination" if !$pkg->{dest};
my $ip = Net::IP->new($1);
}
if ($rule =~ s/^-j NFLOG --nflog-prefix \"[^\"]+\"$//) {
}
if ($rule =~ s/^-j NFLOG --nflog-prefix \"[^\"]+\"$//) {
my ($ruleset, $ipset_ruleset, $chain, $pkg) = @_;
add_trace("ENTER chain $chain\n");
my ($ruleset, $ipset_ruleset, $chain, $pkg) = @_;
add_trace("ENTER chain $chain\n");
my $counter = 0;
if ($chain eq 'PVEFW-Drop') {
my $counter = 0;
if ($chain eq 'PVEFW-Drop') {
next;
}
add_trace("MATCH: $rule\n");
next;
}
add_trace("MATCH: $rule\n");
if ($action eq 'ACCEPT' || $action eq 'DROP' || $action eq 'REJECT') {
add_trace("TERMINATE chain $chain: $action\n");
return ($action, $counter);
if ($action eq 'ACCEPT' || $action eq 'DROP' || $action eq 'REJECT') {
add_trace("TERMINATE chain $chain: $action\n");
return ($action, $counter);
$pkg->{iface_out} = $from_info->{fwbr} || die 'internal error';
$pkg->{physdev_in} = $from_info->{tapdev} || die 'internal error';
$pkg->{physdev_out} = $from_info->{fwln} || die 'internal error';
$pkg->{iface_out} = $from_info->{fwbr} || die 'internal error';
$pkg->{physdev_in} = $from_info->{tapdev} || die 'internal error';
$pkg->{physdev_out} = $from_info->{fwln} || die 'internal error';
} elsif ($route_state eq 'fwbr-in') {
$chain = 'PVEFW-FORWARD';
} elsif ($route_state eq 'fwbr-in') {
$chain = 'PVEFW-FORWARD';
$pkg->{physdev_out} = $target->{tapdev} || die 'internal error';
} elsif ($route_state =~ m/^vmbr\d+$/) {
$pkg->{physdev_out} = $target->{tapdev} || die 'internal error';
} elsif ($route_state =~ m/^vmbr\d+$/) {
die "missing physdev_in - internal error?" if !$physdev_in;
$pkg->{physdev_in} = $physdev_in;
die "missing physdev_in - internal error?" if !$physdev_in;
$pkg->{physdev_in} = $physdev_in;
my ($res, $ctr) = ruleset_simulate_chain($ruleset, $ipset_ruleset, $chain, $pkg);
$rule_check_counter += $ctr;
return ($res, $ipt_invocation_counter, $rule_check_counter) if $res ne 'ACCEPT';
my ($res, $ctr) = ruleset_simulate_chain($ruleset, $ipset_ruleset, $chain, $pkg);
$rule_check_counter += $ctr;
return ($res, $ipt_invocation_counter, $rule_check_counter) if $res ne 'ACCEPT';
$route_state = $next_route_state;
$route_state = $next_route_state;
my $from = $test->{from} || die "missing 'from' field";
my $to = $test->{to} || die "missing 'to' field";
my $action = $test->{action} || die "missing 'action'";
my $from = $test->{from} || die "missing 'from' field";
my $to = $test->{to} || die "missing 'to' field";
my $action = $test->{action} || die "missing 'action'";
my $testid = $test->{id};
my $testid = $test->{id};
die "from/to needs to be different" if $from eq $to;
my $pkg = {
die "from/to needs to be different" if $from eq $to;
my $pkg = {
return 'SKIPPED' if !$have_lxc;
my $vmid = $1;
$from_info = extract_ct_info($vmdata, $vmid, 0);
return 'SKIPPED' if !$have_lxc;
my $vmid = $1;
$from_info = extract_ct_info($vmdata, $vmid, 0);
- $start_state = 'fwbr-out';
+ $start_state = 'fwbr-out';
$pkg->{mac_source} = $from_info->{macaddr};
} elsif ($from =~ m/^vm(\d+)(i(\d))?$/) {
return 'SKIPPED' if !$have_qemu_server;
my $vmid = $1;
my $netnum = $3 || 0;
$from_info = extract_vm_info($vmdata, $vmid, $netnum);
$pkg->{mac_source} = $from_info->{macaddr};
} elsif ($from =~ m/^vm(\d+)(i(\d))?$/) {
return 'SKIPPED' if !$have_qemu_server;
my $vmid = $1;
my $netnum = $3 || 0;
$from_info = extract_vm_info($vmdata, $vmid, $netnum);
- $start_state = 'fwbr-out';
+ $start_state = 'fwbr-out';
$pkg->{mac_source} = $from_info->{macaddr};
} else {
die "unable to parse \"from => '$from'\"\n";
$pkg->{mac_source} = $from_info->{macaddr};
} else {
die "unable to parse \"from => '$from'\"\n";
$pkg->{source} = '100.100.1.2' if !defined($pkg->{source});
$pkg->{dest} = '100.200.3.4' if !defined($pkg->{dest});
$pkg->{source} = '100.100.1.2' if !defined($pkg->{source});
$pkg->{dest} = '100.200.3.4' if !defined($pkg->{dest});
- my ($res, $ic, $rc) = route_packet($ruleset, $ipset_ruleset, $pkg,
+ my ($res, $ic, $rc) = route_packet($ruleset, $ipset_ruleset, $pkg,
$from_info, $target, $start_state);
add_trace("IPT statistics: invocation = $ic, checks = $rc\n");
$from_info, $target, $start_state);
add_trace("IPT statistics: invocation = $ic, checks = $rc\n");
return $res if $action eq 'QUERY';
die "test failed ($res != $action)\n" if $action ne $res;
return $res if $action eq 'QUERY';
die "test failed ($res != $action)\n" if $action ne $res;