DNS server on Proxmox Mail Gateway
Introduction
One of the most effective means to detecting spam currently is the use of DnsBlocklists. These lists are used to query the IP of the connecting SMTP server, or IPs and hostnames occurring in the mail body.
Some of the DNS Blocklists used by SpamAssassin (and thus also Proxmox Mail Gateway) allow only a certain number of requests per DNS server and don't respond once your DNS server has reached it's quota. This is reflected in the mail logs and SpamAssassin hits of a mail. If you see 'URIBL_BLOCKED', 'RCVD_IN_DNSWL_BLOCKED' or 'SURBL_BLOCKED' in your mail logs or the mail headers, this is an indication that your system has reached the quota.
If you're using a shared DNS server (e.g. your ISPs, or a publicly available one like 9.9.9.9, 1.1.1.1, 8.8.8.8) it is quite likely that the Mail Gateway's requests will be blocked.
Installing a dedicated DNS server on the Proxmox Mail Gateway can help in such situations.
Keep in mind that the DNS Blocklists can only count the requests per public IP, i.e. if you have both your internal DNS and Proxmox Mail Gateway natted to the same public IP setting up a recursive DNS server will not help.
If you keep reaching the limit despite having a dedicated recursive server for your Proxmox Mail Gateway you should consider getting a dedicated feed, which is provided by most DNS Blocklist providers for a fee. This also helps keeping this important infrastructure up and running.
We will use the Unbound recursive DNS server.
Installing and using unbound
Simply run
apt install unbound dnsutils
to install the unbound
server - the dnsutils
package contains dig
, which can be used for testing.
Check that unbound is indeed listening on port 53:
# ss -tulnp | grep :53 udp UNCONN 0 0 127.0.0.1:53 0.0.0.0:* users:(("unbound",pid=137,fd=5)) udp UNCONN 0 0 [::1]:53 [::]:* users:(("unbound",pid=137,fd=3)) tcp LISTEN 0 128 127.0.0.1:53 0.0.0.0:* users:(("unbound",pid=137,fd=6)) tcp LISTEN 0 128 [::1]:53 [::]:* users:(("unbound",pid=137,fd=4))
You can verify that DNS resolution works by using the dig
utility
# dig a proxmox.com @127.0.0.1 +short 79.133.36.244
Afterwards you need to configure your Proxmox Mail Gateway installation to use the local dns-server listening on 127.0.0.1
(or optionally ::1
) as resolver.
In the following article we assume that your domain is yourdomain.example
- you need to adapt the posted configuration.
On a standard installation this is done by simply placing:
nameserver 127.0.0.1 search yourdomain.example
in /etc/resolv.conf
. You can use the GUI for setting the dns-resolver as well under Configuration -> Network/Time -> DNS - Just add 127.0.0.1
as DNS Server 1
.
When Proxmox Mail Gateway is running as a Container on Proxmox VE, then you need to edit the container's DNS Settings to use 127.0.0.1
as DNS Server (and adapt your search domain to yourdomain.example
)
If you have installed the resolvconf package you should not need to change everything, since the unbound package in Debian brings integration with resolvconf
Should your system use systemd-resolved
make sure that
resolvectl status
indicates that 127.0.0.1
is listed as Current DNS Server
Alternatively you can simply disable and stop the service
systemctl disable systemd-resolved systemctl stop systemd-resolved
After installing you can either reboot you Proxmox Mail Gateway, or restart the services relevant for mail-processing:
systemctl restart pmg-smtp-filter pmgpolicy postfix
Forwarding requests for your internal zone to your internal DNS
In some environments the internally used DNS has all knowledge about your domain, and should be consulted for it, instead of unbound getting the publicly available data via DNS delegation from the root-servers.
You can configure unbound to ask your internal DNS-server (for this example the internal DNS-server has the IP 192.0.2.53) for your internal domains (yourdomain.example and yourseconddomain.example).
Create a dedicated config-snippet /etc/unbound/unbound.conf.d/local-stub.conf
:
stub-zone: name: "yourdomain.example" stub-addr: 192.0.2.53
stub-zone: name: "yourseconddomain.example" stub-addr: 192.0.2.53
Afterwards restart unbound and verify that DNS-requests for yourdomain.example are delegated to 192.0.2.53 (by checking the DNS logs there):
systemctl restart unbound dig test.yourdomain.example @127.0.0.1
Optional: Using the local unbound only for DNS Blocklist requests
Should your environment require you to use an internal DNS server for all requests, because you have a very modified setup or are employing some other blocking for regulatory reasons you can also try to forward all other requests to your internal DNS Server and only ask the DNS Blocklist zones recursively.
This setup is not recommended for general use, since it increases the complexity which makes debugging harder.
In the example we will use recursive queries for the following domains and forward all other requests to 192.0.2.53:
- mailspike.net
- dnsbl.sorbs.net
- rhsbl.sorbs.net
- bl.spamcop.net
- spamhaus.org
- surbl.org
- uribl.com
- dnswl.org
The list is taken from the Spam Assassin Entry on DNS Blocklists.
You should enhance the list by all domains you are using in your setup (especially the one's configured for postscreen
)
Since unbound cannot do recursive lookups for specific zones if it is forwarding all other requests we will configure 2 unbound instances:
- one listening on port
5003
for recursive lookups - the DNSBL instance - one forwarding requests for the DNSBL domains to port 5003, and all other requests to your internal DNS Server.
For the DNSBL instance - create a config-file which does only include the necessary config-options /etc/unbound/unbound-dnsbl.conf
:
#unbound instance listening on port 5003 for DNSBL lookups include: "/etc/unbound/unbound.conf.d/qname-minimisation.conf" include: "/etc/unbound/unbound.conf.d/root-auto-trust-anchor-file.conf" port: 5003 remote-control: control-port: 8954
Additionally you need to create a systemd-unit (/etc/systemd/system/unbound-rbl.service
[Unit] Description=Unbound DNS server for DNSBL lookups Documentation=man:unbound(8) After=network.target Before=nss-lookup.target Wants=nss-lookup.target
[Service] Type=simple Restart=on-failure EnvironmentFile=-/etc/default/unbound EnvironmentFile=-/etc/default/unbound-rbl ExecStartPre=-/usr/lib/unbound/package-helper chroot_setup ExecStartPre=-/usr/lib/unbound/package-helper root_trust_anchor_update ExecStart=/usr/sbin/unbound -c /etc/unbound/unbound-rbl.conf -d $DAEMON_OPTS ExecReload=/usr/sbin/unbound-control -c /etc/unbound/unbound-rbl.conf reload
[Install] WantedBy=multi-user.target
and enable it with
systemctl enable unbound-rbl systemctl start unbound-rbl
For the instance listening on port 53 you need to create a config-snippet in /etc/unbound/unbound.conf.d/pmg-dnsbl.conf
:
server: do-not-query-localhost: no # depending on your internal DNS-servers capabilities these options might be necessary # harden-dnssec-stripped: no # module-config: "iterator" forward-zone: name: "uceprotect.net" forward-addr: 127.0.0.1@5003 forward-zone: name: "mailspike.net" forward-addr: 127.0.0.1@5003 forward-zone: name: "sorbs.net" forward-addr: 127.0.0.1@5003 forward-zone: name: "bl.spamcop.net" forward-addr: 127.0.0.1@5003 forward-zone: name: "spamhaus.org" forward-addr: 127.0.0.1@5003 forward-zone: name: "surbl.org" forward-addr: 127.0.0.1@5003 forward-zone: name: "uribl.com" forward-addr: 127.0.0.1@5003 forward-zone: name: "dnswl.org" forward-addr: 127.0.0.1@5003 forward-zone: name: "." forward-addr: 192.0.2.53
Test the setup by doing lookups to:
- a testpoint of a DNSBL and verify that the query does not arrive at your internal server
- a testpoint of an arbitrary address (which should arrive at your internal server):
# dig any test.uribl.com.multi.uribl.com @127.0.0.1 +short # should not show up as query on 192.0.2.53 127.0.0.14 "permanent testpoint" # dig a proxmox.com @127.0.0.1 +short #should show up as query on 192.0.2.53 79.133.36.244