From bef31f06892cc7d9dc87780286a4c4ae6806c691 Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Mon, 27 Feb 2017 07:28:38 +0100 Subject: [PATCH] implement parser/writer and API for /etc/pmg/mynetworks --- Makefile | 1 + NEWS | 1 + PMG/API2/Config.pm | 10 ++ PMG/API2/MyNetworks.pm | 213 +++++++++++++++++++++++++++++++++++++++++ PMG/Config.pm | 52 ++++++++++ 5 files changed, 277 insertions(+) create mode 100644 PMG/API2/MyNetworks.pm diff --git a/Makefile b/Makefile index f334066..97dba63 100644 --- a/Makefile +++ b/Makefile @@ -103,6 +103,7 @@ LIBSOURCES = \ PMG/API2/LDAP.pm \ PMG/API2/Domains.pm \ PMG/API2/Transport.pm \ + PMG/API2/MyNetworks.pm \ PMG/API2/Config.pm \ PMG/API2/ClusterConfig.pm \ PMG/API2/Nodes.pm \ diff --git a/NEWS b/NEWS index 155b5fe..38b4f16 100644 --- a/NEWS +++ b/NEWS @@ -13,6 +13,7 @@ Proxmox Mail Gateway 5.0 News - templates moved to /var/lib/pmg/templates/ +- use extra file to store mail/networks /etc/pmg/mynetworks Incompatible changes: --------------------- diff --git a/PMG/API2/Config.pm b/PMG/API2/Config.pm index 2be8d34..b6eeda8 100644 --- a/PMG/API2/Config.pm +++ b/PMG/API2/Config.pm @@ -17,6 +17,7 @@ use PMG::API2::LDAP; use PMG::API2::Domains; use PMG::API2::Transport; use PMG::API2::ClusterConfig; +use PMG::API2::MyNetworks; use base qw(PVE::RESTHandler); @@ -42,6 +43,14 @@ __PACKAGE__->register_method ({ path => 'transport', }); +__PACKAGE__->register_method ({ + subclass => "PMG::API2::MyNetworks", + # set fragment delimiter (no subdirs) - we need that, because CIDRs + # contain a slash '/' + fragmentDelimiter => '', + path => 'mynetworks', +}); + __PACKAGE__->register_method ({ subclass => "PMG::API2::ClusterConfig", path => 'cluster', @@ -73,6 +82,7 @@ __PACKAGE__->register_method ({ } push @$res, { section => 'ldap' }; + push @$res, { section => 'mynetworks' }; push @$res, { section => 'domains' }; push @$res, { section => 'cluster' }; push @$res, { section => 'ruledb' }; diff --git a/PMG/API2/MyNetworks.pm b/PMG/API2/MyNetworks.pm new file mode 100644 index 0000000..8c87e41 --- /dev/null +++ b/PMG/API2/MyNetworks.pm @@ -0,0 +1,213 @@ +package PMG::API2::MyNetworks; + +use strict; +use warnings; +use Data::Dumper; + +use PVE::SafeSyslog; +use PVE::Tools qw(extract_param); +use HTTP::Status qw(:constants); +use PVE::JSONSchema qw(get_standard_option); +use PVE::RESTHandler; +use PVE::INotify; + +use PMG::Config; + +use base qw(PVE::RESTHandler); + +__PACKAGE__->register_method ({ + name => 'index', + path => '', + method => 'GET', + description => "List of trusted networks from where SMTP clients are allowed to relay mail through Proxmox Mail Gateway.", + proxyto => 'master', + parameters => { + additionalProperties => 0, + properties => {}, + }, + returns => { + type => 'array', + items => { + type => "object", + properties => { + cidr => { type => 'string'}, + }, + }, + links => [ { rel => 'child', href => "{cide}" } ], + }, + code => sub { + my ($param) = @_; + + my $mynetworks = PVE::INotify::read_file('mynetworks'); + + my $res = []; + + foreach my $cidr (sort keys %$mynetworks) { + push @$res, $mynetworks->{$cidr}; + } + + return $res; + }}); + +__PACKAGE__->register_method ({ + name => 'create', + path => '', + method => 'POST', + proxyto => 'master', + protected => 1, + description => "Add a trusted network.", + parameters => { + additionalProperties => 0, + properties => { + cidr => { + description => "IPv4 or IPv6 network in CIDR notation.", + type => 'string', format => 'CIDR', + }, + comment => { + description => "Comment.", + type => 'string', + optional => 1, + }, + }, + }, + returns => { type => 'null' }, + code => sub { + my ($param) = @_; + + my $code = sub { + + my $mynetworks = PVE::INotify::read_file('mynetworks'); + + die "trusted network '$param->{cidr}' already exists\n" + if $mynetworks->{$param->{cidr}}; + + $mynetworks->{$param->{cidr}} = { + comment => $param->{comment} // '', + }; + + PVE::INotify::write_file('mynetworks', $mynetworks); + + PMG::Config::postmap_pmg_mynetworks(); + }; + + PMG::Config::lock_config($code, "add trusted network failed"); + + return undef; + }}); + +__PACKAGE__->register_method ({ + name => 'read', + path => '{cidr}', + method => 'GET', + description => "Read trusted network data (comment).", + proxyto => 'master', + parameters => { + additionalProperties => 0, + properties => { + cidr => { + description => "IPv4 or IPv6 network in CIDR notation.", + type => 'string', format => 'CIDR', + }, + }, + }, + returns => { + type => "object", + properties => { + cidr => { type => 'string'}, + comment => { type => 'string'}, + }, + }, + code => sub { + my ($param) = @_; + + my $mynetworks = PVE::INotify::read_file('mynetworks'); + + die "trusted network '$param->{cidr}' does not exist\n" + if !$mynetworks->{$param->{cidr}}; + + return $mynetworks->{$param->{cidr}} + }}); + +__PACKAGE__->register_method ({ + name => 'write', + path => '{cidr}', + method => 'PUT', + description => "Update trusted data (comment).", + protected => 1, + proxyto => 'master', + parameters => { + additionalProperties => 0, + properties => { + cidr => { + description => "IPv4 or IPv6 network in CIDR notation.", + type => 'string', #format => 'CIDR', + }, + comment => { + description => "Comment.", + type => 'string', + }, + }, + }, + returns => { type => 'null' }, + code => sub { + my ($param) = @_; + + my $code = sub { + + my $mynetworks = PVE::INotify::read_file('mynetworks'); + + die "trusted network '$param->{cidr}' does not exist\n" + if !$mynetworks->{$param->{cidr}}; + + $mynetworks->{$param->{cidr}}->{comment} = $param->{comment}; + + PVE::INotify::write_file('mynetworks', $mynetworks); + + PMG::Config::postmap_pmg_mynetworks(); + }; + + PMG::Config::lock_config($code, "update trusted network failed"); + + return undef; + }}); + +__PACKAGE__->register_method ({ + name => 'delete', + path => '{cidr}', + method => 'DELETE', + description => "Delete a truster network", + protected => 1, + proxyto => 'master', + parameters => { + additionalProperties => 0, + properties => { + cidr => { + description => "IPv4 or IPv6 network in CIDR notation.", + type => 'string', format => 'CIDR', + }, + } + }, + returns => { type => 'null' }, + code => sub { + my ($param) = @_; + + my $code = sub { + + my $mynetworks = PVE::INotify::read_file('mynetworks'); + + die "trusted network '$param->{cidr}' does not exist\n" + if !$mynetworks->{$param->{cidr}}; + + delete $mynetworks->{$param->{cidr}}; + + PVE::INotify::write_file('mynetworks', $mynetworks); + + PMG::Config::postmap_pmg_mynetworks(); + }; + + PMG::Config::lock_config($code, "delete trusted network failed"); + + return undef; + }}); + +1; diff --git a/PMG/Config.pm b/PMG/Config.pm index d6d6570..9c6d59b 100755 --- a/PMG/Config.pm +++ b/PMG/Config.pm @@ -713,6 +713,55 @@ PVE::INotify::register_file('domains', $domainsfilename, \&write_pmg_domains, undef, always_call_parser => 1); +my $mynetworks_filename = "/etc/pmg/mynetworks"; + +sub postmap_pmg_mynetworks { + PMG::Utils::run_postmap($mynetworks_filename); +} + +sub read_pmg_mynetworks { + my ($filename, $fh) = @_; + + my $mynetworks = {}; + + my $comment = ''; + if (defined($fh)) { + while (defined(my $line = <$fh>)) { + chomp $line; + next if $line =~ m/^\s*$/; + if ($line =~ m!^((?:$IPV4RE|$IPV6RE))/(\d+)\s*(?:#(.*)\s*)?$!) { + my ($network, $prefix_size, $comment) = ($1, $2, $3); + my $cidr = "$network/${prefix_size}"; + $mynetworks->{$cidr} = { + cidr => $cidr, + network_address => $network, + prefix_size => $prefix_size, + comment => $comment // '', + }; + } else { + warn "parse error in '$filename': $line\n"; + } + } + } + + return $mynetworks; +} + +sub write_pmg_mynetworks { + my ($filename, $fh, $mynetworks) = @_; + + foreach my $cidr (sort keys %$mynetworks) { + my $data = $mynetworks->{$cidr}; + my $comment = $data->{comment} // '*'; + PVE::Tools::safe_print($filename, $fh, "$cidr #$comment\n"); + } +} + +PVE::INotify::register_file('mynetworks', $mynetworks_filename, + \&read_pmg_mynetworks, + \&write_pmg_mynetworks, + undef, always_call_parser => 1); + my $transport_map_filename = "/etc/pmg/transport"; sub postmap_pmg_transport { @@ -840,7 +889,9 @@ sub get_template_vars { my $mynetworks = [ '127.0.0.0/8', '[::1]/128' ]; push @$mynetworks, @$transportnets; push @$mynetworks, $int_net_cidr; + push @$mynetworks, 'hash:/etc/pmg/mynetworks'; + my $netlist = PVE::INotify::read_file('mynetworks'); # add default relay to mynetworks if (my $relay = $self->get('mail', 'relay')) { if ($relay =~ m/^$IPV4RE$/) { @@ -1039,6 +1090,7 @@ sub rewrite_config_postfix { # make sure we have required files (else postfix start fails) postmap_pmg_domains(); postmap_pmg_transport(); + postmap_pmg_mynetworks(); IO::File->new($transport_map_filename, 'a', 0644); -- 2.39.5