From: Carsten Haerle <carsten.haerle@straightec.de>
To: pmg-devel@lists.proxmox.com
Cc: Carsten Haerle <carsten.haerle@straightec.de>
Subject: [PATCH pmg-api 4/6] fix #8231: config: resolve relay and transport host names for mynetworks
Date: Mon, 26 Oct 2026 10:58:49 +0100 [thread overview]
Message-ID: <20261026095852.3243241-5-carsten.haerle@straightec.de> (raw)
In-Reply-To: <20261026095852.3243241-1-carsten.haerle@straightec.de>
The default relay and the transport hosts are added to mynetworks, as
they are the mail servers that send outgoing mail through the internal
port. This only happened if they were configured as IP address. For a
host name nothing was added, so the same mail server was trusted or not
depending on whether it was entered by address or by name.
Resolve host names when the configuration is generated and add all their
addresses. If the address of such a host changes, this takes effect with
the next regeneration (configuration change, sync, boot). If a name
cannot be resolved, it is skipped with a warning, which is the same as
before. As the template variables are computed for every rendered
template, resolved names are cached for 60 seconds, so that a config
sync looks up (and warns) once instead of once per template.
Note that this extends the trusted networks on installations that use
host names for the default relay or transports: these mail servers can
now relay through the internal port, as they could if configured by
address.
The Networks list shows the host name the entry was resolved from.
Signed-off-by: Carsten Haerle <carsten.haerle@straightec.de>
---
src/PMG/API2/MyNetworks.pm | 3 ++
src/PMG/Config.pm | 65 +++++++++++++++++++++++++++++++-------
2 files changed, 56 insertions(+), 12 deletions(-)
diff --git a/src/PMG/API2/MyNetworks.pm b/src/PMG/API2/MyNetworks.pm
index 30bf448..bfb6183 100644
--- a/src/PMG/API2/MyNetworks.pm
+++ b/src/PMG/API2/MyNetworks.pm
@@ -81,6 +81,9 @@ __PACKAGE__->register_method({
if (my $domains = $origin->{transport}) {
push @why, "transport for " . join(', ', $domains->@*) . " (Transports)";
}
+ if (my $names = $origin->{names}) {
+ push @why, "resolved from '" . join("', '", sort keys $names->%*) . "'";
+ }
my $entry = {
cidr => $cidr,
diff --git a/src/PMG/Config.pm b/src/PMG/Config.pm
index e01d4d7..e579334 100644
--- a/src/PMG/Config.pm
+++ b/src/PMG/Config.pm
@@ -913,6 +913,7 @@ use Template;
use PVE::SafeSyslog;
use PVE::Tools qw($IPV4RE $IPV6RE);
+use Socket qw(AF_INET6 SOCK_STREAM);
use PVE::INotify;
use PVE::JSONSchema;
@@ -1555,8 +1556,51 @@ sub get_host_dns_info {
return $dnsinfo;
}
+# The template variables are computed for every rendered template, so cache
+# resolved host names for a short time to look up (and warn) once per run.
+my $resolved_hosts = {};
+
+# Returns the networks to trust for a relay or transport host: the address itself
+# or all addresses of a host name. Host names are resolved now, so a changed address
+# only takes effect with the next regeneration of the configuration.
+sub mynetworks_for_host {
+ my ($host) = @_;
+
+ return ("$host/32") if $host =~ m/^$IPV4RE$/;
+ return ("[$1]/128") if $host =~ m/^(?:ipv6:)?($IPV6RE)$/i;
+
+ my $cached = $resolved_hosts->{$host};
+ return $cached->{cidrs}->@* if $cached && time() - $cached->{time} < 60;
+
+ my $cidrs = {};
+ $resolved_hosts->{$host} = { time => time(), cidrs => [] };
+
+ my @addrinfo = eval { PVE::Tools::getaddrinfo_all($host, socktype => SOCK_STREAM) };
+ if (my $err = $@) {
+ warn "not adding '$host' to trusted networks - $err";
+ return ();
+ }
+
+ for my $ai (@addrinfo) {
+ my ($family, undef, $addr) = PVE::Tools::unpack_sockaddr_in46($ai->{addr});
+ my $ip = Socket::inet_ntop($family, $addr);
+ if ($family != AF_INET6) {
+ $cidrs->{"$ip/32"} = 1;
+ } elsif ($ip =~ m/^::ffff:($IPV4RE)$/i) {
+ $cidrs->{"$1/32"} = 1;
+ } else {
+ $cidrs->{"[$ip]/128"} = 1;
+ }
+ }
+
+ $resolved_hosts->{$host}->{cidrs} = [sort keys %$cidrs];
+
+ return $resolved_hosts->{$host}->{cidrs}->@*;
+}
+
# Networks trusted automatically, in addition to loopback and the configured
-# networks. Returns a hash: cidr => { local => 1, relay => 1, transport => [domains] }
+# networks. Returns a hash: cidr => { local => 1, relay => 1, transport => [domains],
+# names => { host name => 1 } }, 'names' only for hosts configured by host name.
sub get_automatic_mynetworks {
my ($self, $int_ip) = @_;
@@ -1565,13 +1609,11 @@ sub get_automatic_mynetworks {
if (my $tmap = PVE::INotify::read_file('transport')) {
foreach my $domain (sort keys %$tmap) {
my $host = $tmap->{$domain}->{host};
- my $cidr;
- if ($host =~ m/^$IPV4RE$/) {
- $cidr = "$host/32";
- } elsif ($host =~ m/^(?:ipv6:)?($IPV6RE)$/i) {
- $cidr = "[$1]/128";
+ my $is_name = $host !~ m/^(?:$IPV4RE|(?:ipv6:)?$IPV6RE)$/i;
+ for my $cidr (mynetworks_for_host($host)) {
+ push $res->{$cidr}->{transport}->@*, $domain;
+ $res->{$cidr}->{names}->{$host} = 1 if $is_name;
}
- push $res->{$cidr}->{transport}->@*, $domain if defined($cidr);
}
}
@@ -1592,12 +1634,11 @@ sub get_automatic_mynetworks {
$res->{$cidr}->{local} = 1;
}
- # host names are not resolved, they are not trusted automatically
if (my $relay = $self->get('mail', 'relay')) {
- if ($relay =~ m/^$IPV4RE$/) {
- $res->{"$relay/32"}->{relay} = 1;
- } elsif ($relay =~ m/^$IPV6RE$/) {
- $res->{"[$relay]/128"}->{relay} = 1;
+ my $is_name = $relay !~ m/^(?:$IPV4RE|$IPV6RE)$/;
+ for my $cidr (mynetworks_for_host($relay)) {
+ $res->{$cidr}->{relay} = 1;
+ $res->{$cidr}->{names}->{$relay} = 1 if $is_name;
}
}
--
2.53.0
next prev parent reply other threads:[~2026-10-27 9:31 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-26 9:58 [PATCH pmg-api/pmg-gui/pmg-docs 0/6] fix #8231: mail proxy: make automatically trusted networks visible and the local network optional Carsten Haerle
2026-10-26 9:58 ` [PATCH pmg-api 1/6] fix #8231: config: add option to not trust the local network automatically Carsten Haerle
2026-10-26 9:58 ` [PATCH pmg-api 2/6] config: factor out automatically trusted networks Carsten Haerle
2026-10-26 9:58 ` [PATCH pmg-api 3/6] fix #8231: api: mynetworks: optionally list " Carsten Haerle
2026-10-26 9:58 ` Carsten Haerle [this message]
2026-10-26 9:58 ` [PATCH pmg-gui 5/6] fix #8231: mail proxy: add trust local network option, show automatic networks Carsten Haerle
2026-10-26 9:58 ` [PATCH pmg-docs 6/6] mail proxy: networks: document automatically trusted networks Carsten Haerle
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261026095852.3243241-5-carsten.haerle@straightec.de \
--to=carsten.haerle@straightec.de \
--cc=pmg-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox