safing / portmaster

🏔 Love Freedom - ❌ Block Mass Surveillance
https://safing.io
GNU General Public License v3.0
9.16k stars 288 forks source link

Support systemd-resolved as a fallback when using systemd-networkd #655

Closed kakra closed 1 year ago

kakra commented 2 years ago

What would you like to add or change?:

I'm using systemd-networkd instead of NetworkManager to configure my network, VPN connections and associated DNS zones. While running portmaster, I cannot resolve my VPN-connected DNS zones, it simply fails. This is probably because it tries to query the NetworkManager dbus interface to read the system resolvers - but that doesn't exist here. Instead, it should simply query 127.0.0.53 instead which is where systemd-resolved lives, and which knows about my DNS zone routes to query the respective DNS servers behind those VPNs.

I tried setting dns://127.0.0.53 instead but that seems to loop and eventually time out as a result.

Clearing the DNS servers as suggested in the FAQ falls back to using CloudFlare because it cannot query the NetworkManager interface.

Why do you and others need this?:

My system is setup to maintain various VPN connections to different sites to work from home or manage sites privately owned among the my family. The VPN connections are setup in systemd-networkd to add DNS zone routing to systemd-resolved so systemd-resolved properly resolves zones using the correct DNS servers behind the VPN tunnels.

For the home office case, this is also used in a split-brain DNS scenario where a public host name would resolve to a local IP which is quite important for correct scoping of VoIP protocols and even Active Directory in some scenarios (e.g., AD DNS-SD). Those public host names and zones are also added via the DNS zone routing feature of systemd-resolved.

portmaster should allow to support such scenarios, probably by integrating better with systemd-resolved and systemd-networkd. But as start, it would be fine if I could manually add configuration to resolve some zones via specific DNS resolvers. Also, it should not loopback to itself when manually adding a 127.0.0.0/8 IP to the DNS resolver configuration.

Currently, I cannot properly work from home via VPN while portmaster is running. Using IPs directly breaks SSL domain name verification for https, also, some internal destinations and used applications depend on proper SSL SNI.

Information:

Here's an anonymized example configuration of my systemd-networkd configuration which respects proper DNS zone routing:

# /etc/systemd/network/10-vpn-office.network
[Match]
Name=vpn-office

[Link]
RequiredForOnline=no

[Network]
DNS=10.1.2.254
Domains=~example.de ~example.local

which results in this resolver configuration:

# resolvectl status
Global
           Protocols: +LLMNR +mDNS -DNSOverTLS DNSSEC=no/unsupported
    resolv.conf mode: stub
Fallback DNS Servers: 1.1.1.1#cloudflare-dns.com 8.8.8.8#dns.google 1.0.0.1#cloudflare-dns.com 8.8.4.4#dns.google 2606:4700:4700::1111#cloudflare-dns.com 2001:4860:4860::8888#dns.google 2606:4700:4700::1001#cloudflare-dns.com
                      2001:4860:4860::8844#dns.google

[...]

Link 3 (vpn-office)
    Current Scopes: DNS LLMNR/IPv4 LLMNR/IPv6
         Protocols: -DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
Current DNS Server: 10.1.2.254
       DNS Servers: 10.1.2.254
        DNS Domain: ~example.de ~example.local

[...]

Link 5 (vmbridge)
    Current Scopes: DNS LLMNR/IPv4 LLMNR/IPv6 mDNS/IPv4 mDNS/IPv6
         Protocols: +DefaultRoute +LLMNR +mDNS -DNSOverTLS DNSSEC=no/unsupported
Current DNS Server: 192.168.x.1
       DNS Servers: 192.168.x.1 2a02:x:y:z::1
        DNS Domain: local.domain.de ~. ~external.example.de

DNS queries for voip.example.de correctly resolve to the local IP of our VoIP services, queries for srv-dc.example.local correctly resolve for the local IP of our domain controller - unless portmaster is running.

ghost commented 2 years ago

Thanks for your suggestion, I will pass it to the team.

dhaavi commented 2 years ago

Hey @kakra, thanks for the great suggestions and taking the time to lay out your use case in such detail.

I think the Portmaster should be able to do this, but I would also want to explore how a better integration would look like. Let's start:

1. Manual Configuration

You can configure search domains for resolvers in the Portmaster, who will then prioritize these resolvers for queries matching the search domains. I just realized that our DNS Configuration Guide does not draw the latest definition from the correct data source, so these options are missing on the docs page. You can however view the help from within the Portmaster by going to the "DNS Servers" setting, clicking the "(i)" and then "Show More". The relevant options are:

2. Automatic Configuration through rseolv.conf

In addition to getting resolves from the NetworkManager, the Portmaster also reads the resolv.conf file. It should also correctly detect the search domains from there and configure them correctly. I see that you are using the ~ prefix for the domains, which as far as I understand, results in these entries not being added to the resolv.conf file, as they are not search domains, but for routing only. (See https://systemd.network/systemd.network.html#Domains=) If acceptable, removing the ~ might make it work.

You can then check if the Portmaster parsed everything correctly by querying the current resolvers at http://127.0.0.1:817/api/v1/dns/resolvers (docs) on the machine where the Portmaster is installed.

If that does not work, please share your resolv.conf file, so I can see if I can improve on this.

3. Improving Integration

My guess is that systemd-networkd will be taking over in the mid-term future, so we are very interested in increasing integration. Do you have any specific recommendations on what integrations you feel would make sense? Also, I was not able to find an API to access the state or any config of systemd-networkd programmatically. Do you know of any interface for this?

Thanks!

dhaavi commented 2 years ago

Regarding the automatic redirection:

Also, it should not loopback to itself when manually adding a 127.0.0.0/8 IP to the DNS resolver configuration.

This would be extremely hard to get right, as we are not sure where the inital query goes to, as it may not go over the network as with systemd-resolved. If you are sure you can manage a leak-proof setup of chaining DNS servers, we have an experimental setting that you can turn off to disable redirection: Seamless DNS Integration

The Portmaster also does self-check and will scream at you if you get it wrong. ;)

kakra commented 2 years ago

@dhaavi

You can configure search domains for resolvers in the Portmaster, who will then prioritize these resolvers for queries matching the search domains. [...] The relevant options are:

  • search: specify prioritized domains/TLDs for this resolver (delimited by ,)
  • search-only: use this resolver for domains in the search parameter only (no value)

Combining both would actually mean "routing" to me as systemd-resolved supports it. I do not want to use those resolvers for searching at all (this is different from routing: searching would append the zone name for querying, routing only passes fqdn queries to the matching zone resolvers).

Only my locally configured domain should be used to searches.

I've tested it now and it did not work: (update: it works, see https://github.com/safing/portmaster/issues/655#issuecomment-1133773187)

image

It neither resolves the ?search=internal.example.de&search-only domain, nor it is able to handle those .local domain names that you often find in Active Directory environments (because MS decided it would be a good idea to add .local to non-fqdn AD domains for DNS although this is clearly reserved for MDNS):

Mai 21 16:46:49 jupiter portmaster-start[1122]: 220521 16:46:49.847 nameserver:280 ▶ WARN 058 nameserver: failed to resolve device.example.local.AAAA: all 2 query-compliant resolvers failed, last error: write udp6 [::]:44854->[ff02::fb]:5353: sendto: cannot assign requested address

Two ideas:

  1. Either it's not resolving my .site.local domain names because the ?search=example.local&search-only configuration does not seem to work (as mentioned above, it doesn't resolve internal.example.de via that DNS server.
  2. Or it's forcing .local via the MDNS resolver no matter if that FQDN has two or three components. For compatibility with MS AD, only component1.local should probably resolved via MDNS while fqdn.site.local (or more components) should be resolved via the local site resolver (or rather if the query matches the interface-specific search domain).

In addition to getting resolves from the NetworkManager, the Portmaster also reads the resolv.conf file. It should also correctly detect the search domains from there and configure them correctly. I see that you are using the ~ prefix for the domains, which as far as I understand, results in these entries not being added to the resolv.conf file, as they are not search domains, but for routing only. (See https://systemd.network/systemd.network.html#Domains=) If acceptable, removing the ~ might make it work.

See above: I don't want those zones being searched for unqualified hostnames which I would use locally. Only FQDN hostnames should be resolved via those resolvers. That's a difference, and hence the ~ prefixed zones won't be added to resolv.conf but systemd-resolved handles that internally. Otherwise it may leak local hostnames to remote resolvers which may actually even resolve to an IP although the name isn't in my local zone.

If that does not work, please share your resolv.conf file, so I can see if I can improve on this.

Well, method 1 didn't work, method 2 won't work because it would only use that resolver as a fallback - in addition to it being run on the local node which will proxy DNS requests to the final resolver.

This is my resolv.conf:

nameserver 127.0.0.53
options edns0 trust-ad
search internal.example.de

But I think there's still some problem with method 1 because it won't use the specified resolvers as configured in the screenshot. But I'm not sure if I set everything up correctly.

My guess is that systemd-networkd will be taking over in the mid-term future, so we are very interested in increasing integration. Do you have any specific recommendations on what integrations you feel would make sense?

I think the zone routing is one of the most important features, otherwise it's mostly a stub resolver with secure DNS support and fallback to public DNS if all other resolvers timed out.

Also, systemd-resolved seems to have a concept of interface-specific zones and queries those zones first via the interface-specific DNS servers. It's probably exact that feature which should be implemented in the Portmaster. You should be able to get that information via dbus:

Also, I was not able to find an API to access the state or any config of systemd-networkd programmatically. Do you know of any interface for this?

I'm not sure if there are any dbus APIs yet but there's resolvectl which probably uses some sort of API. At a quick glance, it also seems to support direct querying of the service without going through an IP socket - but it would still create a new DNS query which would loop back to the Portmaster.

It looks like this is implemented via dbus API: https://github.com/systemd/systemd/blob/main/src/resolve/resolvectl.c

Example for query interface: https://github.com/systemd/systemd/blob/7d3f2499b8c9320cd518d0282481698ee41a1a43/src/resolve/resolvectl.c#L302

Example for querying each network link: https://github.com/systemd/systemd/blob/7d3f2499b8c9320cd518d0282481698ee41a1a43/src/resolve/resolvectl.c#L1536

kakra commented 2 years ago

BTW: I found that NetworkManager seems to support interface-specific DNS zone resolvers meanwhile. Originally, I went with systemd-resolved because it was the only software supporting this. I didn't look into NetworkManager ever again because it also slowed down the boot process. But having researched this topic a little, it seems to support resolver priorities based on interface-specific zones. I'm not sure if and how this feature is handled by the Portmaster but it's more or less the same thing that systemd-resolved supports. So a general abstract integration in the Portmaster which would then use the proper dbus APIs of each implementation under the hood (systemd-networkd, NetworkManager) would be nice.

I'm planning on using the Windows version of the Portmaster, too - in a similar scenario where I need interface-specific DNS zones. I think Windows supports this (at least, I can configure DNS zones and servers per interface). Will the Portmaster automatically work correctly here?

kakra commented 2 years ago

If you are sure you can manage a leak-proof setup of chaining DNS servers, we have an experimental setting that you can turn off to disable redirection: Seamless DNS Integration

I cannot seem to find it with developer interface enabled. Maybe it's not part of the stable release yet?

kakra commented 2 years ago

But I think there's still some problem with method 1 because it won't use the specified resolvers as configured in the screenshot. But I'm not sure if I set everything up correctly.

@dhaavi Coincidentally, it turns out there was a faulty switch in the office just in front of the name server. Name resolution using the setup from the screenshot works.

dhaavi commented 2 years ago

Hey @kakra, great to hear it works now!

Combining both would actually mean "routing" to me as systemd-resolved supports it. I do not want to use those resolvers for searching at all (this is different from routing: searching would append the zone name for querying, routing only passes fqdn queries to the matching zone resolvers).

The Portmaster does not do searches itself, just routing.

I'm planning on using the Windows version of the Portmaster, too - in a similar scenario where I need interface-specific DNS zones. I think Windows supports this (at least, I can configure DNS zones and servers per interface). Will the Portmaster automatically work correctly here?

It also parses the search domains on Windows, so if you configure it like that it should pick it up automatically. Not sure if Windows has "routing-only" domain options.

I cannot seem to find it with developer interface enabled. Maybe it's not part of the stable release yet?

It's also marked as experimental, so you will need to raise/lower the Feature Stability.

Also, systemd-resolved seems to have a concept of interface-specific zones and queries those zones first via the interface-specific DNS servers. It's probably exact that feature which should be implemented in the Portmaster.

IIRC, this is exactly the information we are getting. Just checked: Yup. And we get both the search domains as well as the routing-only domains.

Example for query interface

I don't think building on a reverse-engineered interface will lead to a stable experience. I guess we have to wait for the official docs for this one.

kakra commented 2 years ago

I don't think building on a reverse-engineered interface will lead to a stable experience. I guess we have to wait for the official docs for this one.

Like these?

dhaavi commented 2 years ago

Yes! Perfect!

This one looks juicy: Describe(out s json)

Do you perhaps know which distros already use networkd by default? I need a VM, as my host does not use it and I don't want fiddle around with my work device. ;)

kakra commented 2 years ago

Most desktop-oriented distros will probably use NetworkManager by default.

Usually it's as easy as disabling the old network setup services and enabling systemd-networkd instead. Here's an example for Debian: https://wiki.debian.org/SystemdNetworkd

I'm using Gentoo but that may be too much of a hassle to even install in the first place.

You should be able to test that in a VM, and if you feel brave enough, change your host. But I probably won't recommend that for distributions with tightly integrated NetworkManager.

Raphty commented 1 year ago

I am cleaning out old issues. If you feel this issue should not have been closed let me know.

Please keep in mind, the free version of Portmaster only has limited support. For free users our active Discord community as well as the chat bot are the fastest and best way to get their help. https://discord.gg/safing If you find our work brings value to you, please consider supporting it by purchasing Plus or Pro Packages https://safing.io/pricing/. If you are already a subscriber, first Thank You! and also if you want priority support pleas send in an email and let me know your username so I can prioritize your request accordingly.