dns: force default-route for VPNs without routing domains

When a VPN connection is configured with "never-default=true" (e.g.,
the "Use this connection only for resources on its network" option is
checked), NetworkManager currently does not mark the link as having a
default route for DNS purposes.

If the VPN also does not provide any specific search or routing domains,
its DNS servers are effectively dropped and not passed to systemd-resolved.
This results in a "split-tunneling trap": the user has routes to the
internal network, but cannot resolve internal hostnames.

This commit introduces a fallback: if a VPN has no specific routing domains,
we force the has_default_route property to TRUE. This ensures that:
1 The VPN's DNS servers are registered with systemd-resolved.
2 systemd-resolved can perform parallel lookups (routing queries to both
the physical link and the VPN link).
3 The VPN's higher DNS priority is respected for these queries without
hijacking the actual IP routing for internet traffic.

This fixes the issue where internal DNS becomes unreachable when split-tunneling
is enabled on VPNs that don't explicitly push search domains.
This commit is contained in:
xinpeng.wang 2026-04-08 17:58:19 +08:00 committed by wang xinpeng
parent 5e02f13611
commit 0b562b8873

View file

@ -1751,6 +1751,20 @@ _mgr_configs_data_construct(NMDnsManager *self)
has_default_route_explicit || (priority < 0 && has_default_route_auto);
ip_data->domains.has_default_route =
ip_data->domains.has_default_route_exclusive || has_default_route_auto;
/* * Heuristic: If this is a VPN and it has no specific search or routing
* domains, it would normally be ignored by systemd-resolved unless it
* has a default route.
*
* When 'never-default' is TRUE (split-tunnel), we force 'has_default_route'
* here to ensure NM pushes these DNS servers to resolved. This allows
* resolved to perform parallel queries across both the physical and VPN
* links, ensuring internal hostnames can still be resolved without
* breaking global internet connectivity.
*/
if (ip_data->ip_config_type == NM_DNS_IP_CONFIG_TYPE_VPN
&& !nm_l3_config_data_get_searches(ip_data->l3cd, ip_data->addr_family, &num)
&& !nm_l3_config_data_get_domains(ip_data->l3cd, ip_data->addr_family, &num))
ip_data->domains.has_default_route = TRUE;
{
gs_free char *str1 = NULL;