fix: dnsmasq answers the remote access clients' DNS queries, so they no longer get the router's own host name with all its addresses from systemd-resolved.
Release / release (push) Successful in 13s
Release / release (push) Successful in 13s
This commit is contained in:
1 parent
dabe4e8365
commit
e14bbe2ba1
13 files changed
+111
-24
No files matched your search
@@ -1144,9 +1144,9 @@ Status: Accepted
|
||||
Context: Sites get subdomains of a selected domain, delegated to the router, without a registrar
|
||||
change per site. Ubuntu has BIND, Knot and PowerDNS; only PowerDNS's gpgsql backend reads records
|
||||
from PostgreSQL, so changes are rows, without zone files or reloads. systemd-resolved's stub holds
|
||||
127.0.0.53 and 127.0.0.54, and its extra stub answered the remote access clients on the external
|
||||
addresses, the addresses an authoritative server needs. The extra stub answers on the internal
|
||||
address just as well, since the clients reach it through the tunnel when it is in `local.cidrs`.
|
||||
127.0.0.53 and 127.0.0.54, and the remote access clients' resolver answered on the external
|
||||
addresses, the addresses an authoritative server needs. The clients reach the internal address
|
||||
just as well, through the tunnel when it is in `local.cidrs` (ADR-43).
|
||||
|
||||
Decision: While `dns.enabled` is true, setup runs `pdns.service` with
|
||||
`/etc/powerdns/pdns.d/vpn-router.conf`, written before the packages are installed, on the
|
||||
@@ -1160,3 +1160,24 @@ shares an interface with it is refused while P2S or OpenVPN is enabled.
|
||||
|
||||
Consequences: The zone follows the sites at each setup run. One zone only, without DNSSEC or
|
||||
transfers; the delegation is made at the parent zone by hand.
|
||||
|
||||
## ADR-43: The remote access clients' resolver is dnsmasq, not systemd-resolved
|
||||
|
||||
Status: Accepted
|
||||
|
||||
Context: IKEv2 and OpenVPN clients were given the router as their DNS server, answered by
|
||||
systemd-resolved through a `DNSStubListenerExtra` drop-in. resolved synthesizes records for the
|
||||
machine's own host name, all its addresses, the Docker bridge and the tunnel addresses included,
|
||||
and for `_gateway` and `localhost`, on every stub, and systemd 255 has no setting that turns this
|
||||
off. Its extra stub also took port 53 of the addresses PowerDNS needs. dnsmasq-base is in main,
|
||||
a single binary without a service of its own, and forwards to one upstream server.
|
||||
|
||||
Decision: `vpn-router-resolver.service` runs dnsmasq, bound to the addresses of `p2s.dns_listen`
|
||||
only (`bind-interfaces`), forwarding to resolved's stub on 127.0.0.53, without `/etc/hosts` and
|
||||
without forwarding names that have no dot (`domain-needed`). resolved keeps its loopback stubs
|
||||
only and stays the router's own resolver, with the upstream servers of the platform. Setup writes
|
||||
`/etc/vpn-router/dnsmasq.conf` while IKEv2 or OpenVPN runs and removes the earlier drop-in.
|
||||
|
||||
Consequences: Clients resolve the names resolved resolves, Azure's internal names included, but
|
||||
not the router's synthesized ones. The package depends on dnsmasq-base. PowerDNS and the clients'
|
||||
resolver share no address.
|
||||
@@ -402,7 +402,7 @@ firewall rules. It provisions the user directory in `slapd` while OpenVPN or roa
|
||||
access is configured. It then starts `strongswan`, `wg-quick@wg0` and
|
||||
`openvpn-server@vpn-router` if the corresponding feature is configured, reloading or
|
||||
restarting them only when their inputs changed, and
|
||||
restarts `systemd-resolved` only when the road-warrior DNS drop-in changed. Turning a
|
||||
restarts the remote access clients' resolver only when its configuration changed. Turning a
|
||||
feature off in the configuration stops its service and removes its files. Every step is
|
||||
idempotent, so restarting with no changes does nothing.
|
||||
|
||||
@@ -874,9 +874,11 @@ router should be configured but the platform adds nothing.
|
||||
|
||||
The shipped modules currently add nothing. Road-warrior and OpenVPN clients are given the
|
||||
router's addresses of `p2s.dns_listen` as their DNS servers, by default the internal address,
|
||||
where the drop-in `/etc/systemd/resolved.conf.d/p2s-forwarder.conf` makes the router's own
|
||||
`systemd-resolved` answer and the firewall opens port 53 for the client pools, so no provider
|
||||
resolver has to be advertised or routed through the tunnel on any platform. The clients reach
|
||||
where `vpn-router-resolver.service`, dnsmasq with `/etc/vpn-router/dnsmasq.conf`, answers and
|
||||
the firewall opens port 53 for the client pools, so no provider resolver has to be advertised or
|
||||
routed through the tunnel on any platform. dnsmasq forwards to `systemd-resolved` on
|
||||
127.0.0.53, which keeps only its loopback stubs, and forwards no name without a dot, so the
|
||||
router's own host name, `_gateway` and `localhost` are not answered to the clients. The clients reach
|
||||
the internal address when it is inside `local.cidrs`, which they route through the tunnel. Port 53
|
||||
of the other addresses stays free for the name server (see Name server).
|
||||
The modules exist as the documented place for platform specifics if that changes.
|
||||
@@ -1111,8 +1113,8 @@ read at each request:
|
||||
| `GET /logs/file?path=<path>&lines=<n>` | `{"lines": [...]}`: the last lines of a file `web.log_files` lists |
|
||||
|
||||
The units are the package's own (`vpn-router-setup`, `-web`, `-metrics`, `-pki`, `-backup`,
|
||||
`-caddy`), `vpn-router-manager`, `caddy`, `slapd`, `nslcd`, `postgresql`, `strongswan`,
|
||||
`wg-quick@wg0`, `openvpn-server@vpn-router` and `ssh`. `lines` is 1 to 1000, 200 without it. A
|
||||
`-caddy`, `-resolver`, `-webdav`), `vpn-router-manager`, `caddy`, `slapd`, `nslcd`, `postgresql`,
|
||||
`strongswan`, `wg-quick@wg0`, `openvpn-server@vpn-router`, `ssh` and `pdns`. `lines` is 1 to 1000, 200 without it. A
|
||||
file is read from at most its last MiB, so very long lines give fewer lines. A unit or a file not
|
||||
in the lists is 404, as is a listed file that does not exist.
|
||||
|
||||
@@ -1574,8 +1576,8 @@ missing, without the recommended bind backend.
|
||||
Records added with `/dns` or the Router Manager (A, AAAA, CNAME, TXT, MX, SRV, CAA) are served
|
||||
too, but not those of a name and type the zone's own records have. Setup writes the zone at each
|
||||
run; the SOA's serial grows only when the records change. While P2S or OpenVPN is enabled,
|
||||
systemd-resolved answers their clients on port 53 of the addresses of `p2s.dns_listen`, by default
|
||||
the internal address, so `dns.listen` must not share an interface with it. The parent zone must delegate `dns.zone` to `dns.nameserver`, with glue records for
|
||||
dnsmasq answers their clients on port 53 of the addresses of `p2s.dns_listen`, by default the
|
||||
internal address, so `dns.listen` must not share an interface with it. The parent zone must delegate `dns.zone` to `dns.nameserver`, with glue records for
|
||||
a name server inside the zone.
|
||||
|
||||
```sh
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
vpn-router (0.31.2-1) unstable; urgency=medium
|
||||
|
||||
fix: dnsmasq answers the remote access clients' DNS queries, so they no longer get the router's own host name with all its addresses from systemd-resolved.
|
||||
|
||||
* vpn-router-resolver.service runs dnsmasq on the addresses of
|
||||
p2s.dns_listen, forwarding to systemd-resolved's stub on 127.0.0.53;
|
||||
names without a dot are not forwarded. The package depends on
|
||||
dnsmasq-base.
|
||||
* systemd-resolved keeps its loopback stubs only; setup removes the
|
||||
drop-in that made it listen for the clients.
|
||||
* /logs shows the journal of vpn-router-resolver, vpn-router-webdav and
|
||||
pdns.
|
||||
|
||||
-- Slawomir Koszewski <slawek@koszewscy.waw.pl> Tue, 27 Oct 2026 11:00:00 +0100
|
||||
|
||||
vpn-router (0.31.1-1) unstable; urgency=medium
|
||||
|
||||
fix: the remote access clients' resolver answers on the internal address by default, chosen by p2s.dns_listen, so the name server can take port 53 of the external addresses.
|
||||
|
||||
@@ -38,6 +38,7 @@ Depends: ${misc:Depends},
|
||||
openvpn-auth-ldap,
|
||||
iproute2,
|
||||
systemd-resolved,
|
||||
dnsmasq-base,
|
||||
zstd
|
||||
Recommends: bash-completion
|
||||
Suggests: caddy,
|
||||
|
||||
@@ -46,6 +46,7 @@ case "$1" in
|
||||
rm -f /etc/swanctl/conf.d/site-to-site.conf \
|
||||
/etc/swanctl/conf.d/road-warrior.conf \
|
||||
/etc/systemd/resolved.conf.d/p2s-forwarder.conf \
|
||||
/etc/vpn-router/dnsmasq.conf \
|
||||
/etc/wireguard/wg0.conf \
|
||||
/etc/openvpn/server/vpn-router.conf \
|
||||
/etc/openvpn/server/vpn-router-ldap.conf \
|
||||
|
||||
@@ -12,4 +12,5 @@ override_dh_installsystemd:
|
||||
dh_installsystemd --name=vpn-router-pki --no-enable --no-start
|
||||
dh_installsystemd --name=vpn-router-caddy --no-enable --no-start
|
||||
dh_installsystemd --name=vpn-router-webdav --no-enable --no-start
|
||||
dh_installsystemd --name=vpn-router-resolver --no-enable --no-start
|
||||
dh_installsystemd --name=vpn-router-install@ --no-enable --no-start
|
||||
@@ -0,0 +1,15 @@
|
||||
[Unit]
|
||||
Description=VPN Router DNS resolver of the remote access clients
|
||||
Documentation=file:/usr/share/doc/vpn-router/README.md
|
||||
After=network-online.target systemd-resolved.service
|
||||
Wants=network-online.target
|
||||
ConditionPathExists=/etc/vpn-router/dnsmasq.conf
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/sbin/dnsmasq --keep-in-foreground --pid-file= --log-facility=- --conf-file=/etc/vpn-router/dnsmasq.conf
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -81,6 +81,9 @@ CADDY_PKI_DIR = pathlib.Path('/etc/caddy/vpn-router-pki')
|
||||
#: The certificates and keys of the sites of tls file, <site>/cert.pem and key.pem.
|
||||
CADDY_SITES_DIR = pathlib.Path('/etc/caddy/vpn-router-sites')
|
||||
|
||||
#: The unit of dnsmasq, the resolver of the remote access clients.
|
||||
RESOLVER_UNIT = 'vpn-router-resolver.service'
|
||||
|
||||
#: The unit of rclone's WebDAV server of the sites' folders.
|
||||
WEBDAV_UNIT = 'vpn-router-webdav.service'
|
||||
|
||||
@@ -676,6 +679,19 @@ def caddy_address(host, port, tls):
|
||||
return f'{"http://" if tls == "none" else ""}{host}:{port}'
|
||||
|
||||
|
||||
def manage_resolver(changed):
|
||||
"""Run dnsmasq, the resolver of the remote access clients, while configure wrote its configuration, restarting it when
|
||||
that changed, and stop it when not. It starts after systemd-resolved has left the addresses it takes."""
|
||||
if not vpnrouter.RESOLVER_CONF.exists():
|
||||
if unit_is_active(RESOLVER_UNIT):
|
||||
run(['systemctl', 'disable', '--now', RESOLVER_UNIT], check=False)
|
||||
return
|
||||
if not unit_is_active(RESOLVER_UNIT):
|
||||
run(['systemctl', 'enable', '--now', RESOLVER_UNIT], check=False)
|
||||
elif 'resolver' in changed:
|
||||
run(['systemctl', 'restart', RESOLVER_UNIT], check=False)
|
||||
|
||||
|
||||
def manage_caddy(cfg, ctx):
|
||||
"""Run Caddy, the HTTPS proxy of the router's services and the server of the web sites, while either is wanted, and
|
||||
stop it when not.
|
||||
@@ -1062,6 +1078,8 @@ def main():
|
||||
if 'resolved' in changed:
|
||||
progress('running', 'resolver')
|
||||
run(['systemctl', 'restart', 'systemd-resolved'], check=False)
|
||||
progress('running', 'resolver of the remote access clients')
|
||||
manage_resolver(changed)
|
||||
|
||||
progress('running', 'platform module')
|
||||
run_platform_setup(cfg, ctx)
|
||||
|
||||
@@ -36,7 +36,10 @@ TEMPLATE_DIR = pathlib.Path('/usr/share/vpn-router/templates')
|
||||
SWANCTL_CONF_D = pathlib.Path('/etc/swanctl/conf.d')
|
||||
SITE_TO_SITE = SWANCTL_CONF_D / 'site-to-site.conf'
|
||||
ROAD_WARRIOR = SWANCTL_CONF_D / 'road-warrior.conf'
|
||||
#: The drop-in of systemd-resolved that earlier versions wrote for the remote access clients; removed when found.
|
||||
P2S_FORWARDER = pathlib.Path('/etc/systemd/resolved.conf.d/p2s-forwarder.conf')
|
||||
#: The configuration of dnsmasq, the resolver of the remote access clients (vpn-router-resolver.service).
|
||||
RESOLVER_CONF = pathlib.Path('/etc/vpn-router/dnsmasq.conf')
|
||||
WG_CONF = pathlib.Path('/etc/wireguard/wg0.conf')
|
||||
#: The router's WireGuard public key, which setup writes with its private key.
|
||||
WG_PUBLIC_KEY = pathlib.Path('/etc/wireguard/wg0.pub')
|
||||
@@ -1172,7 +1175,7 @@ def configure(cfg=None, public_ip=None):
|
||||
"""Render configuration files and provision PKI.
|
||||
|
||||
Returns (ctx, changed) where changed is a set naming what needs reloading:
|
||||
'swanctl', 'resolved', 'wireguard', 'openvpn'.
|
||||
'swanctl', 'resolved', 'resolver', 'wireguard', 'openvpn'.
|
||||
"""
|
||||
if cfg is None:
|
||||
cfg = load_config()
|
||||
@@ -1229,12 +1232,15 @@ def configure(cfg=None, public_ip=None):
|
||||
elif remove(ROAD_WARRIOR):
|
||||
changed.add('swanctl')
|
||||
|
||||
# The resolver of the remote access clients answers on the addresses of p2s.dns_listen only.
|
||||
if (p2s_ready(ctx) or openvpn_ready(ctx)) and ctx['p2s_resolver_addrs']:
|
||||
if render(env, ctx, 'p2s-forwarder.conf.j2', P2S_FORWARDER, 0o644):
|
||||
changed.add('resolved')
|
||||
elif remove(P2S_FORWARDER):
|
||||
# The resolver of the remote access clients is dnsmasq on the addresses of p2s.dns_listen; systemd-resolved keeps
|
||||
# its loopback stub only, so its records of the router's own name stay on the router.
|
||||
if remove(P2S_FORWARDER):
|
||||
changed.add('resolved')
|
||||
if (p2s_ready(ctx) or openvpn_ready(ctx)) and ctx['p2s_resolver_addrs']:
|
||||
if render(env, ctx, 'dnsmasq.conf.j2', RESOLVER_CONF, 0o644):
|
||||
changed.add('resolver')
|
||||
elif remove(RESOLVER_CONF):
|
||||
changed.add('resolver')
|
||||
|
||||
if wg_ready(ctx):
|
||||
if render_wg_conf(env, ctx):
|
||||
|
||||
@@ -4,8 +4,8 @@ No platform-specific configuration is currently required.
|
||||
|
||||
The Azure platform resolver 168.63.129.16 is deliberately *not* advertised to
|
||||
road-warrior clients and *not* added to the traffic selectors. Clients are
|
||||
given the router's addresses of p2s.dns_listen as their DNS servers, and the router
|
||||
forwards through its own systemd-resolved via the p2s-forwarder drop-in. That resolves
|
||||
given the router's addresses of p2s.dns_listen as their DNS servers, where dnsmasq
|
||||
forwards to the router's own systemd-resolved. That resolves
|
||||
Azure-internal names without routing the wireserver address through the tunnel
|
||||
and without a second resolver in the pool.
|
||||
"""
|
||||
@@ -171,7 +171,7 @@ POSTGRESQL_SETTINGS = ('server_version', 'listen_addresses', 'port', 'max_connec
|
||||
#: The units whose journal /logs/journal shows, besides the whole journal: the package's own and the services it runs.
|
||||
JOURNAL_UNITS = ('vpn-router-setup', 'vpn-router-web', 'vpn-router-metrics', 'vpn-router-pki', 'vpn-router-backup',
|
||||
'vpn-router-caddy', 'vpn-router-manager', 'caddy', 'slapd', 'nslcd', 'postgresql', 'strongswan',
|
||||
'wg-quick@wg0', 'openvpn-server@vpn-router', 'ssh')
|
||||
'wg-quick@wg0', 'openvpn-server@vpn-router', 'ssh', 'vpn-router-resolver', 'vpn-router-webdav', 'pdns')
|
||||
|
||||
#: The most lines /logs answers, the number it answers without lines, and the most bytes it reads from the end of a file.
|
||||
LOG_LINES_MAX = 1000
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# Written by vpn-router-setup from /etc/vpn-router/vpn-router.json; edits are overwritten.
|
||||
# The resolver of the remote access clients, on the addresses of p2s.dns_listen, forwarding to systemd-resolved's stub.
|
||||
{% for address in p2s_resolver_addrs -%}
|
||||
listen-address={{ address }}
|
||||
{% endfor -%}
|
||||
bind-interfaces
|
||||
no-resolv
|
||||
server=127.0.0.53
|
||||
domain-needed
|
||||
no-hosts
|
||||
cache-size=1000
|
||||
@@ -1,4 +0,0 @@
|
||||
[Resolve]
|
||||
{% for address in p2s_resolver_addrs -%}
|
||||
DNSStubListenerExtra={{ address }}
|
||||
{% endfor -%}
|
||||
Reference in new issue
Block a user