fix: WireGuard clients may use the router's DNS resolver, which runs while WireGuard does, and /remote-access names its addresses for their configuration.
Release / release (push) Successful in 14s

This commit is contained in:
slawek committed 2026-10-26 18:33:03 +01:00
1 parent e14bbe2ba1
commit 770332728e
6 files changed
+38 -15

No files matched your search

+14
View File
@@ -1,3 +1,17 @@
vpn-router (0.31.3-1) unstable; urgency=medium
fix: WireGuard clients may use the router's DNS resolver, which runs while WireGuard does, and /remote-access names its addresses for their configuration.
* The firewall opens port 53 of the remote access clients' resolver for
the WireGuard network, as it does for the IKEv2 and OpenVPN pools.
* The resolver runs while WireGuard is the only remote access enabled.
* GET /remote-access answers the resolver's addresses as
wireguard_server.dns.
* dns.listen may not share an interface with p2s.dns_listen while
WireGuard is enabled either.
-- Slawomir Koszewski <slawek@koszewscy.waw.pl> Tue, 27 Oct 2026 12:00:00 +0100
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.
+3 -1
View File
@@ -243,7 +243,8 @@ def filter_block(ctx):
lines += ['# OPENVPN RULES END']
pools = [pool for ready, pool in ((vpnrouter.p2s_ready(ctx), ctx['p2s_address_pool']),
(vpnrouter.openvpn_ready(ctx), ctx['openvpn_pool'])) if ready]
(vpnrouter.openvpn_ready(ctx), ctx['openvpn_pool']),
(vpnrouter.wg_ready(ctx), ctx['wg_network'])) if ready]
# The remote access clients' resolver answers on the addresses of p2s.dns_listen.
if pools and ctx['p2s_resolver_addrs']:
lines += ['', '# P2S DNS RULES START']
@@ -953,6 +954,7 @@ def refresh_web(cfg, ctx):
'internal_address': ctx['int_addr'],
'internal_gateway': ctx['int_gateway_ip'],
'local_cidrs': ctx['local_cidr_list'],
'client_dns': ctx['p2s_resolver_addrs'] if vpnrouter.RESOLVER_CONF.exists() else [],
'site_to_site': [{
'name': connection['name'],
'local_identity': connection['local_id'],
@@ -588,11 +588,11 @@ def validate(cfg):
if resolver_listen not in LISTEN_CHOICES:
raise ConfigError(f'p2s.dns_listen: {resolver_listen!r} is not one of {", ".join(LISTEN_CHOICES)}')
sides = {'internal': {'internal'}, 'external': {'external'}, 'both': {'internal', 'external'}}
if dns['enabled'] and (_get(cfg, 'p2s', 'enabled') or _get(cfg, 'openvpn', 'enabled')) and \
sides[dns['listen']] & sides[resolver_listen]:
remote_access = any(_get(cfg, system, 'enabled') for system in ('p2s', 'openvpn', 'wireguard'))
if dns['enabled'] and remote_access and sides[dns['listen']] & sides[resolver_listen]:
raise ConfigError(f'dns.listen: port 53 of the {" and ".join(sorted(sides[dns["listen"]] & sides[resolver_listen]))} '
f'addresses is the resolver of the remote access clients (p2s.dns_listen {resolver_listen}) '
'while p2s.enabled or openvpn.enabled is true')
'while p2s.enabled, openvpn.enabled or wireguard.enabled is true')
for option in ('root_name', 'p2s_name', 's2s_name'):
value = _get(cfg, 'pki', option)
@@ -993,6 +993,8 @@ def build_context(cfg, public_ip=None):
'p2s_dns': _join(resolver_addrs, _split_list(extras['EXTRA_P2S_DNS'])),
'wg_enabled': _get(cfg, 'wireguard', 'enabled'),
'wg_address': _get(cfg, 'wireguard', 'address'),
'wg_network': str(ipaddress.ip_interface(_get(cfg, 'wireguard', 'address')).network)
if _get(cfg, 'wireguard', 'address') else '',
'wg_listen_port': _get(cfg, 'wireguard', 'listen_port'),
'wg_peers_begin': WG_PEERS_BEGIN,
'wg_peers_end': WG_PEERS_END,
@@ -1236,7 +1238,7 @@ def configure(cfg=None, public_ip=None):
# 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 (p2s_ready(ctx) or openvpn_ready(ctx) or wg_ready(ctx)) and ctx['p2s_resolver_addrs']:
if render(env, ctx, 'dnsmasq.conf.j2', RESOLVER_CONF, 0o644):
changed.add('resolver')
elif remove(RESOLVER_CONF):
+7 -4
View File
@@ -888,9 +888,10 @@ def backup(method, path, body):
def wireguard_server(cfg, state):
"""What a WireGuard peer's configuration needs of the router: {public_key, endpoint, allowed_ips}; public_key is
null before setup made the key pair, endpoint, <wan.local_fqdn>:<wireguard.listen_port>, null without a name, and
allowed_ips the networks reached through the tunnel, the router's local CIDRs and the WireGuard network."""
"""What a WireGuard peer's configuration needs of the router: {public_key, endpoint, allowed_ips, dns}; public_key is
null before setup made the key pair, endpoint, <wan.local_fqdn>:<wireguard.listen_port>, null without a name,
allowed_ips the networks reached through the tunnel, the router's local CIDRs and the WireGuard network, and dns the
addresses of the remote access clients' resolver, [] while it does not run."""
try:
public_key = vpnrouter.WG_PUBLIC_KEY.read_text(encoding='utf-8').strip() or None
except OSError:
@@ -901,8 +902,10 @@ def wireguard_server(cfg, state):
allowed = [cidr for cidr in networks if isinstance(cidr, str)] if isinstance(networks, list) else []
if address:
allowed.append(str(ipaddress.ip_interface(address).network))
dns = section(state, 'network').get('client_dns')
return {'public_key': public_key, 'endpoint': f'{fqdn}:{cfg["wireguard"]["listen_port"]}' if fqdn else None,
'allowed_ips': list(dict.fromkeys(allowed))}
'allowed_ips': list(dict.fromkeys(allowed)),
'dns': [address for address in dns if isinstance(address, str)] if isinstance(dns, list) else []}
def remote_access(state, method, path, body):