From 1210ae94fb22cd0d52f5a0f3453a2fb9409b4298 Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Tue, 27 May 2014 11:38:54 +0200 Subject: [PATCH] implement ipsets for VM/CT --- src/PVE/API2/Firewall/Groups.pm | 34 ---- src/PVE/API2/Firewall/IPSet.pm | 310 +++++++++++++++++++++++++------- src/PVE/API2/Firewall/Rules.pm | 34 +++- src/PVE/API2/Firewall/VM.pm | 10 ++ src/PVE/Firewall.pm | 246 ++++++++++--------------- 5 files changed, 380 insertions(+), 254 deletions(-) diff --git a/src/PVE/API2/Firewall/Groups.pm b/src/PVE/API2/Firewall/Groups.pm index 9e4d08a..6d9117b 100644 --- a/src/PVE/API2/Firewall/Groups.pm +++ b/src/PVE/API2/Firewall/Groups.pm @@ -118,40 +118,6 @@ __PACKAGE__->register_method({ return undef; }}); -__PACKAGE__->register_method({ - name => 'delete_security_group', - path => '{group}', - method => 'DELETE', - description => "Delete security group.", - protected => 1, - parameters => { - additionalProperties => 0, - properties => { - group => get_standard_option('pve-security-group-name'), - digest => get_standard_option('pve-config-digest'), - }, - }, - returns => { type => 'null' }, - code => sub { - my ($param) = @_; - - my $cluster_conf = PVE::Firewall::load_clusterfw_conf(); - - return undef if !$cluster_conf->{groups}->{$param->{group}}; - - my (undef, $digest) = &$get_security_group_list($cluster_conf); - PVE::Tools::assert_if_modified($digest, $param->{digest}); - - die "Security group '$param->{group}' is not empty\n" - if scalar(@{$cluster_conf->{groups}->{$param->{group}}}); - - delete $cluster_conf->{groups}->{$param->{group}}; - - PVE::Firewall::save_clusterfw_conf($cluster_conf); - - return undef; - }}); - __PACKAGE__->register_method ({ subclass => "PVE::API2::Firewall::GroupRules", path => '{group}', diff --git a/src/PVE/API2/Firewall/IPSet.pm b/src/PVE/API2/Firewall/IPSet.pm index 4dac1c4..56dd4f2 100644 --- a/src/PVE/API2/Firewall/IPSet.pm +++ b/src/PVE/API2/Firewall/IPSet.pm @@ -29,14 +29,28 @@ sub load_config { my ($class, $param) = @_; die "implement this in subclass"; + + #return ($cluster_conf, $fw_conf, $ipset); } -sub save_ipset { - my ($class, $param, $fw_conf, $rules) = @_; +sub save_config { + my ($class, $param, $fw_conf) = @_; die "implement this in subclass"; } +sub save_ipset { + my ($class, $param, $fw_conf, $ipset) = @_; + + if (!defined($ipset)) { + delete $fw_conf->{ipset}->{$param->{name}}; + } else { + $fw_conf->{ipset}->{$param->{name}} = $ipset; + } + + $class->save_config($param, $fw_conf); +} + my $additional_param_hash = {}; sub additional_parameters { @@ -93,12 +107,44 @@ sub register_get_ipset { code => sub { my ($param) = @_; - my ($fw_conf, $ipset) = $class->load_config($param); + my ($cluster_conf, $fw_conf, $ipset) = $class->load_config($param); return PVE::Firewall::copy_list_with_digest($ipset); }}); } +sub register_delete_ipset { + my ($class) = @_; + + my $properties = $class->additional_parameters(); + + $properties->{name} = get_standard_option('ipset-name'); + + $class->register_method({ + name => 'delete_ipset', + path => '', + method => 'DELETE', + description => "Delete IPSet", + protected => 1, + parameters => { + additionalProperties => 0, + properties => $properties, + }, + returns => { type => 'null' }, + code => sub { + my ($param) = @_; + + my ($cluster_conf, $fw_conf, $ipset) = $class->load_config($param); + + die "IPSet '$param->{name}' is not empty\n" + if scalar(@$ipset); + + $class->save_ipset($param, $fw_conf, undef); + + return undef; + }}); +} + sub register_create_ip { my ($class) = @_; @@ -123,7 +169,7 @@ sub register_create_ip { code => sub { my ($param) = @_; - my ($fw_conf, $ipset) = $class->load_config($param); + my ($cluster_conf, $fw_conf, $ipset) = $class->load_config($param); my $cidr = $param->{cidr}; @@ -166,7 +212,7 @@ sub register_read_ip { code => sub { my ($param) = @_; - my ($fw_conf, $ipset) = $class->load_config($param); + my ($cluster_conf, $fw_conf, $ipset) = $class->load_config($param); my $list = PVE::Firewall::copy_list_with_digest($ipset); @@ -205,7 +251,7 @@ sub register_update_ip { code => sub { my ($param) = @_; - my ($fw_conf, $ipset) = $class->load_config($param); + my ($cluster_conf, $fw_conf, $ipset) = $class->load_config($param); my (undef, $digest) = PVE::Firewall::copy_list_with_digest($ipset); PVE::Tools::assert_if_modified($digest, $param->{digest}); @@ -246,7 +292,7 @@ sub register_delete_ip { code => sub { my ($param) = @_; - my ($fw_conf, $ipset) = $class->load_config($param); + my ($cluster_conf, $fw_conf, $ipset) = $class->load_config($param); my (undef, $digest) = PVE::Firewall::copy_list_with_digest($ipset); PVE::Tools::assert_if_modified($digest, $param->{digest}); @@ -266,6 +312,7 @@ sub register_delete_ip { sub register_handlers { my ($class) = @_; + $class->register_delete_ipset(); $class->register_get_ipset(); $class->register_create_ip(); $class->register_read_ip(); @@ -287,18 +334,81 @@ sub load_config { my $ipset = $fw_conf->{ipset}->{$param->{name}}; die "no such IPSet '$param->{name}'\n" if !defined($ipset); - return ($fw_conf, $ipset); + return (undef, $fw_conf, $ipset); } -sub save_ipset { - my ($class, $param, $fw_conf, $ipset) = @_; +sub save_config { + my ($class, $param, $fw_conf) = @_; - $fw_conf->{ipset}->{$param->{name}} = $ipset; PVE::Firewall::save_clusterfw_conf($fw_conf); } __PACKAGE__->register_handlers(); +package PVE::API2::Firewall::VMIPset; + +use strict; +use warnings; +use PVE::JSONSchema qw(get_standard_option); + +use base qw(PVE::API2::Firewall::IPSetBase); + +__PACKAGE__->additional_parameters({ + node => get_standard_option('pve-node'), + vmid => get_standard_option('pve-vmid'), +}); + +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}); + my $ipset = $fw_conf->{ipset}->{$param->{name}}; + die "no such IPSet '$param->{name}'\n" if !defined($ipset); + + return ($cluster_conf, $fw_conf, $ipset); +} + +sub save_config { + my ($class, $param, $fw_conf) = @_; + + PVE::Firewall::save_vmfw_conf($param->{vmid}, $fw_conf); +} + +__PACKAGE__->register_handlers(); + +package PVE::API2::Firewall::CTIPset; + +use strict; +use warnings; +use PVE::JSONSchema qw(get_standard_option); + +use base qw(PVE::API2::Firewall::IPSetBase); + +__PACKAGE__->additional_parameters({ + node => get_standard_option('pve-node'), + vmid => get_standard_option('pve-vmid'), +}); + +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}); + my $ipset = $fw_conf->{ipset}->{$param->{name}}; + die "no such IPSet '$param->{name}'\n" if !defined($ipset); + + return ($cluster_conf, $fw_conf, $ipset); +} + +sub save_config { + my ($class, $param, $fw_conf) = @_; + + PVE::Firewall::save_vmfw_conf($param->{vmid}, $fw_conf); +} + +__PACKAGE__->register_handlers(); + package PVE::API2::Firewall::BaseIPSetList; use strict; @@ -309,6 +419,36 @@ use PVE::Firewall; use base qw(PVE::RESTHandler); +sub load_config { + my ($class, $param) = @_; + + die "implement this in subclass"; + + #return ($cluster_conf, $fw_conf); +} + +sub save_config { + my ($class, $param, $fw_conf) = @_; + + die "implement this in subclass"; +} + +my $additional_param_hash_list = {}; + +sub additional_parameters { + my ($class, $new_value) = @_; + + if (defined($new_value)) { + $additional_param_hash_list->{$class} = $new_value; + } + + # return a copy + my $copy = {}; + my $org = $additional_param_hash_list->{$class} || {}; + foreach my $p (keys %$org) { $copy->{$p} = $org->{$p}; } + return $copy; +} + my $get_ipset_list = sub { my ($fw_conf) = @_; @@ -331,6 +471,8 @@ my $get_ipset_list = sub { sub register_index { my ($class) = @_; + my $properties = $class->additional_parameters(); + $class->register_method({ name => 'ipset_index', path => '', @@ -338,6 +480,7 @@ sub register_index { description => "List IPSets", parameters => { additionalProperties => 0, + properties => $properties, }, returns => { type => 'array', @@ -357,7 +500,7 @@ sub register_index { code => sub { my ($param) = @_; - my $fw_conf = $class->load_config(); + my ($cluster_conf, $fw_conf) = $class->load_config($param); return &$get_ipset_list($fw_conf); }}); @@ -366,6 +509,18 @@ sub register_index { sub register_create { my ($class) = @_; + my $properties = $class->additional_parameters(); + + $properties->{name} = get_standard_option('ipset-name'); + + $properties->{comment} = { type => 'string', optional => 1 }; + + $properties->{digest} = get_standard_option('pve-config-digest'); + + $properties->{rename} = get_standard_option('ipset-name', { + description => "Rename an existing IPSet. You can set 'rename' to the same value as 'name' to update the 'comment' of an existing IPSet.", + optional => 1 }); + $class->register_method({ name => 'create_ipset', path => '', @@ -374,24 +529,13 @@ sub register_create { protected => 1, parameters => { additionalProperties => 0, - properties => { - name => get_standard_option('ipset-name'), - comment => { - type => 'string', - optional => 1, - }, - rename => get_standard_option('ipset-name', { - description => "Rename an existing IPSet. You can set 'rename' to the same value as 'name' to update the 'comment' of an existing IPSet.", - optional => 1, - }), - digest => get_standard_option('pve-config-digest'), - } + properties => $properties, }, returns => { type => 'null' }, code => sub { my ($param) = @_; - my $fw_conf = $class->load_config(); + my ($cluster_conf, $fw_conf) = $class->load_config($param); if ($param->{rename}) { my (undef, $digest) = &$get_ipset_list($fw_conf); @@ -416,82 +560,118 @@ sub register_create { $fw_conf->{ipset_comments}->{$param->{name}} = $param->{comment} if defined($param->{comment}); } - $class->save_config($fw_conf); + $class->save_config($param, $fw_conf); return undef; }}); } -sub register_delete { +sub register_handlers { my ($class) = @_; - $class->register_method({ - name => 'delete_ipset', - path => '{name}', - method => 'DELETE', - description => "Delete IPSet", - protected => 1, - parameters => { - additionalProperties => 0, - properties => { - name => get_standard_option('ipset-name'), - digest => get_standard_option('pve-config-digest'), - }, - }, - returns => { type => 'null' }, - code => sub { - my ($param) = @_; - - my $fw_conf = $class->load_config(); + $class->register_index(); + $class->register_create(); +} - return undef if !$fw_conf->{ipset}->{$param->{name}}; +package PVE::API2::Firewall::ClusterIPSetList; - my (undef, $digest) = &$get_ipset_list($fw_conf); - PVE::Tools::assert_if_modified($digest, $param->{digest}); +use strict; +use warnings; +use PVE::Firewall; - die "IPSet '$param->{name}' is not empty\n" - if scalar(@{$fw_conf->{ipset}->{$param->{name}}}); +use base qw(PVE::API2::Firewall::BaseIPSetList); + +sub load_config { + my ($class, $param) = @_; + + my $cluster_conf = PVE::Firewall::load_clusterfw_conf(); + return (undef, $cluster_conf); +} - delete $fw_conf->{ipset}->{$param->{name}}; +sub save_config { + my ($class, $param, $fw_conf) = @_; - $class->save_config($fw_conf); + PVE::Firewall::save_clusterfw_conf($fw_conf); +} - return undef; - }}); +__PACKAGE__->register_handlers(); + +__PACKAGE__->register_method ({ + subclass => "PVE::API2::Firewall::ClusterIPset", + path => '{name}', + # set fragment delimiter (no subdirs) - we need that, because CIDR address contain a slash '/' + fragmentDelimiter => '', +}); + +package PVE::API2::Firewall::VMIPSetList; + +use strict; +use warnings; +use PVE::JSONSchema qw(get_standard_option); +use PVE::Firewall; + +use base qw(PVE::API2::Firewall::BaseIPSetList); + +__PACKAGE__->additional_parameters({ + node => get_standard_option('pve-node'), + vmid => get_standard_option('pve-vmid'), +}); + +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); } -sub register_handlers { - my ($class) = @_; +sub save_config { + my ($class, $param, $fw_conf) = @_; - $class->register_index(); - $class->register_create(); - $class->register_delete(); + PVE::Firewall::save_vmfw_conf($param->{vmid}, $fw_conf); } -package PVE::API2::Firewall::ClusterIPSetList; +__PACKAGE__->register_handlers(); + +__PACKAGE__->register_method ({ + subclass => "PVE::API2::Firewall::VMIPset", + path => '{name}', + # set fragment delimiter (no subdirs) - we need that, because CIDR address contain a slash '/' + fragmentDelimiter => '', +}); + +package PVE::API2::Firewall::CTIPSetList; use strict; use warnings; +use PVE::JSONSchema qw(get_standard_option); use PVE::Firewall; use base qw(PVE::API2::Firewall::BaseIPSetList); +__PACKAGE__->additional_parameters({ + node => get_standard_option('pve-node'), + vmid => get_standard_option('pve-vmid'), +}); + sub load_config { - my ($class) = @_; + my ($class, $param) = @_; - return PVE::Firewall::load_clusterfw_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); } sub save_config { - my ($class, $fw_conf) = @_; + my ($class, $param, $fw_conf) = @_; - PVE::Firewall::save_clusterfw_conf($fw_conf); + PVE::Firewall::save_vmfw_conf($param->{vmid}, $fw_conf); } __PACKAGE__->register_handlers(); __PACKAGE__->register_method ({ - subclass => "PVE::API2::Firewall::ClusterIPset", + subclass => "PVE::API2::Firewall::CTIPset", path => '{name}', # set fragment delimiter (no subdirs) - we need that, because CIDR address contain a slash '/' fragmentDelimiter => '', diff --git a/src/PVE/API2/Firewall/Rules.pm b/src/PVE/API2/Firewall/Rules.pm index fba5c10..df9f562 100644 --- a/src/PVE/API2/Firewall/Rules.pm +++ b/src/PVE/API2/Firewall/Rules.pm @@ -304,6 +304,7 @@ use base qw(PVE::API2::Firewall::RulesBase); __PACKAGE__->additional_parameters({ group => get_standard_option('pve-security-group-name') }); + sub rule_env { my ($class, $param) = @_; @@ -323,10 +324,41 @@ sub load_config { sub save_rules { my ($class, $param, $fw_conf, $rules) = @_; - $fw_conf->{groups}->{$param->{group}} = $rules; + if (!defined($rules)) { + delete $fw_conf->{groups}->{$param->{group}}; + } else { + $fw_conf->{groups}->{$param->{group}} = $rules; + } + PVE::Firewall::save_clusterfw_conf($fw_conf); } +__PACKAGE__->register_method({ + name => 'delete_security_group', + path => '', + method => 'DELETE', + description => "Delete security group.", + protected => 1, + parameters => { + additionalProperties => 0, + 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__->save_rules($param, $cluster_conf, undef); + + return undef; + }}); + __PACKAGE__->register_handlers(); package PVE::API2::Firewall::ClusterRules; diff --git a/src/PVE/API2/Firewall/VM.pm b/src/PVE/API2/Firewall/VM.pm index e0c7832..040f23e 100644 --- a/src/PVE/API2/Firewall/VM.pm +++ b/src/PVE/API2/Firewall/VM.pm @@ -248,6 +248,11 @@ __PACKAGE__->register_method ({ path => 'aliases', }); +__PACKAGE__->register_method ({ + subclass => "PVE::API2::Firewall::VMIPSetList", + path => 'ipset', +}); + __PACKAGE__->register_handlers('vm'); package PVE::API2::Firewall::CT; @@ -267,6 +272,11 @@ __PACKAGE__->register_method ({ path => 'aliases', }); +__PACKAGE__->register_method ({ + subclass => "PVE::API2::Firewall::CTIPSetList", + path => 'ipset', +}); + __PACKAGE__->register_handlers('vm'); 1; diff --git a/src/PVE/Firewall.pm b/src/PVE/Firewall.pm index 8e2a26c..0d21480 100644 --- a/src/PVE/Firewall.pm +++ b/src/PVE/Firewall.pm @@ -2087,130 +2087,13 @@ sub parse_alias { return undef; } -sub parse_vm_fw_rules { - my ($filename, $fh, $cluster_conf, $rule_env, $verbose) = @_; - - my $res = { - rules => [], - options => {}, - aliases => {}, - }; - - my $section; - - while (defined(my $line = <$fh>)) { - next if $line =~ m/^#/; - next if $line =~ m/^\s*$/; - - my $linenr = $fh->input_line_number(); - my $prefix = "$filename (line $linenr)"; - - if ($line =~ m/^\[(\S+)\]\s*$/i) { - $section = lc($1); - warn "$prefix: ignore unknown section '$section'\n" if !$res->{$section}; - next; - } - if (!$section) { - warn "$prefix: skip line - no section"; - next; - } - - next if !$res->{$section}; # skip undefined section - - if ($section eq 'options') { - eval { - my ($opt, $value) = parse_vmfw_option($line); - $res->{options}->{$opt} = $value; - }; - warn "$prefix: $@" if $@; - next; - } - - if ($section eq 'aliases') { - eval { - my $data = parse_alias($line); - $res->{aliases}->{lc($data->{name})} = $data; - }; - warn "$prefix: $@" if $@; - next; - } - - my $rule; - eval { $rule = parse_fw_rule($prefix, $line, $cluster_conf, $res, $rule_env, $verbose); }; - if (my $err = $@) { - warn "$prefix: $err"; - next; - } - - push @{$res->{$section}}, $rule; - } - - return $res; -} - -sub parse_host_fw_rules { - my ($filename, $fh, $cluster_conf, $verbose) = @_; - - my $res = { rules => [], options => {}}; - - my $section; - - while (defined(my $line = <$fh>)) { - next if $line =~ m/^#/; - next if $line =~ m/^\s*$/; - - my $linenr = $fh->input_line_number(); - my $prefix = "$filename (line $linenr)"; - - if ($line =~ m/^\[(\S+)\]\s*$/i) { - $section = lc($1); - warn "$prefix: ignore unknown section '$section'\n" if !$res->{$section}; - next; - } - if (!$section) { - warn "$prefix: skip line - no section"; - next; - } - - next if !$res->{$section}; # skip undefined section - - if ($section eq 'options') { - eval { - my ($opt, $value) = parse_hostfw_option($line); - $res->{options}->{$opt} = $value; - }; - warn "$prefix: $@" if $@; - next; - } - - my $rule; - eval { $rule = parse_fw_rule($prefix, $line, $cluster_conf, $res, 'host', $verbose); }; - if (my $err = $@) { - warn "$prefix: $err"; - next; - } - - push @{$res->{$section}}, $rule; - } - - return $res; -} - -sub parse_cluster_fw_rules { - my ($filename, $fh, $verbose) = @_; +sub generic_fw_rules_parser { + my ($filename, $fh, $verbose, $cluster_conf, $empty_conf, $rule_env) = @_; my $section; my $group; - my $res = { - rules => [], - options => {}, - aliases => {}, - groups => {}, - group_comments => {}, - ipset => {} , - ipset_comments => {}, - }; + my $res = $empty_conf; while (defined(my $line = <$fh>)) { next if $line =~ m/^#/; @@ -2219,17 +2102,17 @@ sub parse_cluster_fw_rules { my $linenr = $fh->input_line_number(); my $prefix = "$filename (line $linenr)"; - if ($line =~ m/^\[options\]$/i) { + if ($empty_conf->{options} && ($line =~ m/^\[options\]$/i)) { $section = 'options'; next; } - if ($line =~ m/^\[aliases\]$/i) { + if ($empty_conf->{aliases} && ($line =~ m/^\[aliases\]$/i)) { $section = 'aliases'; next; } - if ($line =~ m/^\[group\s+(\S+)\]\s*(?:#\s*(.*?)\s*)?$/i) { + if ($empty_conf->{groups} && ($line =~ m/^\[group\s+(\S+)\]\s*(?:#\s*(.*?)\s*)?$/i)) { $section = 'groups'; $group = lc($1); my $comment = $2; @@ -2239,12 +2122,12 @@ sub parse_cluster_fw_rules { next; } - if ($line =~ m/^\[rules\]$/i) { + if ($empty_conf->{rules} && ($line =~ m/^\[rules\]$/i)) { $section = 'rules'; next; } - if ($line =~ m/^\[ipset\s+(\S+)\]\s*(?:#\s*(.*?)\s*)?$/i) { + if ($empty_conf->{ipset} && ($line =~ m/^\[ipset\s+(\S+)\]\s*(?:#\s*(.*?)\s*)?$/i)) { $section = 'ipset'; $group = lc($1); my $comment = $2; @@ -2261,7 +2144,14 @@ sub parse_cluster_fw_rules { if ($section eq 'options') { eval { - my ($opt, $value) = parse_clusterfw_option($line); + my ($opt, $value); + if ($rule_env eq 'cluster') { + ($opt, $value) = parse_clusterfw_option($line); + } elsif ($rule_env eq 'host') { + ($opt, $value) = parse_hostfw_option($line); + } else { + ($opt, $value) = parse_vmfw_option($line); + } $res->{options}->{$opt} = $value; }; warn "$prefix: $@" if $@; @@ -2273,7 +2163,7 @@ sub parse_cluster_fw_rules { warn "$prefix: $@" if $@; } elsif ($section eq 'rules') { my $rule; - eval { $rule = parse_fw_rule($prefix, $line, $res, undef, 'cluster', $verbose); }; + eval { $rule = parse_fw_rule($prefix, $line, $cluster_conf, $res, $rule_env, $verbose); }; if (my $err = $@) { warn "$prefix: $err"; next; @@ -2281,7 +2171,7 @@ sub parse_cluster_fw_rules { push @{$res->{$section}}, $rule; } elsif ($section eq 'groups') { my $rule; - eval { $rule = parse_fw_rule($prefix, $line, $res, undef, 'group', $verbose); }; + eval { $rule = parse_fw_rule($prefix, $line, $cluster_conf, undef, 'group', $verbose); }; if (my $err = $@) { warn "$prefix: $err"; next; @@ -2310,12 +2200,56 @@ sub parse_cluster_fw_rules { $entry->{comment} = $comment if $comment; push @{$res->{$section}->{$group}}, $entry; + } else { + warn "$prefix: skip line - unknown section\n"; + next; } } return $res; } +sub parse_host_fw_rules { + my ($filename, $fh, $cluster_conf, $verbose) = @_; + + my $empty_conf = { rules => [], options => {}}; + + return generic_fw_rules_parser($filename, $fh, $verbose, $cluster_conf, $empty_conf, 'host'); +} + +sub parse_vm_fw_rules { + my ($filename, $fh, $cluster_conf, $rule_env, $verbose) = @_; + + my $empty_conf = { + rules => [], + options => {}, + aliases => {}, + ipset => {} , + ipset_comments => {}, + }; + + return generic_fw_rules_parser($filename, $fh, $verbose, $cluster_conf, $empty_conf, $rule_env); +} + +sub parse_cluster_fw_rules { + my ($filename, $fh, $verbose) = @_; + + my $section; + my $group; + + my $empty_conf = { + rules => [], + options => {}, + aliases => {}, + groups => {}, + group_comments => {}, + ipset => {} , + ipset_comments => {}, + }; + + return generic_fw_rules_parser($filename, $fh, $verbose, $empty_conf, $empty_conf, 'cluster'); +} + sub run_locked { my ($code, @param) = @_; @@ -2448,23 +2382,35 @@ my $format_aliases = sub { return $raw; }; -my $format_ipset = sub { - my ($options) = @_; - +my $format_ipsets = sub { + my ($fw_conf) = @_; + my $raw = ''; - my $nethash = {}; - foreach my $entry (@$options) { - $nethash->{$entry->{cidr}} = $entry; - } + foreach my $ipset (sort keys %{$fw_conf->{ipset}}) { + if (my $comment = $fw_conf->{ipset_comments}->{$ipset}) { + my $utf8comment = encode('utf8', $comment); + $raw .= "[IPSET $ipset] # $utf8comment\n\n"; + } else { + $raw .= "[IPSET $ipset]\n\n"; + } + my $options = $fw_conf->{ipset}->{$ipset}; - foreach my $cidr (sort keys %$nethash) { - my $entry = $nethash->{$cidr}; - my $line = $entry->{nomatch} ? '!' : ''; - $line .= $entry->{cidr}; - $line .= " # " . encode('utf8', $entry->{comment}) - if $entry->{comment} && $entry->{comment} !~ m/^\s*$/; - $raw .= "$line\n"; + my $nethash = {}; + foreach my $entry (@$options) { + $nethash->{$entry->{cidr}} = $entry; + } + + foreach my $cidr (sort keys %$nethash) { + my $entry = $nethash->{$cidr}; + my $line = $entry->{nomatch} ? '!' : ''; + $line .= $entry->{cidr}; + $line .= " # " . encode('utf8', $entry->{comment}) + if $entry->{comment} && $entry->{comment} !~ m/^\s*$/; + $raw .= "$line\n"; + } + + $raw .= "\n"; } return $raw; @@ -2481,6 +2427,8 @@ sub save_vmfw_conf { my $aliases = $vmfw_conf->{aliases}; $raw .= &$format_aliases($aliases) if scalar(keys %$aliases); + $raw .= &$format_ipsets($vmfw_conf); + my $rules = $vmfw_conf->{rules} || []; if (scalar(@$rules)) { $raw .= "[RULES]\n\n"; @@ -2646,18 +2594,8 @@ sub save_clusterfw_conf { my $aliases = $cluster_conf->{aliases}; $raw .= &$format_aliases($aliases) if scalar(keys %$aliases); - foreach my $ipset (sort keys %{$cluster_conf->{ipset}}) { - if (my $comment = $cluster_conf->{ipset_comments}->{$ipset}) { - my $utf8comment = encode('utf8', $comment); - $raw .= "[IPSET $ipset] # $utf8comment\n\n"; - } else { - $raw .= "[IPSET $ipset]\n\n"; - } - my $options = $cluster_conf->{ipset}->{$ipset}; - $raw .= &$format_ipset($options); - $raw .= "\n"; - } - + $raw .= &$format_ipsets($cluster_conf); + my $rules = $cluster_conf->{rules}; if (scalar(@$rules)) { $raw .= "[RULES]\n\n"; -- 2.39.2