Get DNS servers from the system

Hello!

I'd like to ask about the best way of getting a list of DNS servers from the system (iOS & macOS).

Why?
I am using NEPacketTunnelProvider to implement a VPN app. When a device joins a network with a Captive Portal and the VPN is on, the VPN should redirect DNS queries to the DNS servers that were received from the network's DHCP server. So that my VPN is able to correctly reroute the traffic which is not blocked by the network's gateway and the Captive Portal landing page is served.

When I don't do anything, the traffic goes to the tunnel and the tunnel's encrypted traffic is then dropped by the gateway serving the Captive Portal.

When I temporarily turn off the VPN, opt out of all the traffic or pass the traffic to the system resolver, the traffic gets affected by other network settings (like DNSSettings) which leads to the same situation - the user not being able to authenticate with the Captive Portal.

So far, I have tried multiple ways, including res_9_getservers but unsuccessfully. As a part of my investigation, I have found out that the /etc/resolv.conf file is not populated with DNS servers until the Captive Portal is acknowledged by the user which makes getaddrinfo unusable to achieve my goal. But I am not sure if that's a bug or intended behavior.

Thank you for your help!

I'd like to ask about the best way of getting a list of DNS servers from the system (iOS & macOS).

There isn’t a good way to do this on either platform. That’s because the concept of “a list of DNS servers” doesn’t make sense on our Apple systems. DNS servers can be scoped, based on a variety of criteria, and so there’s no one single list.

On macOS you can get a lot more insight into this via System Configuration framework, but in the SC preferences and the SC dynamic store. Those APIs aren’t available on iOS.

Regarding your big picture issue, if the device is on a captive network and you’re unable to communicate with your VPN server, shouldn’t you just take your tunnel down?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Hello Eskimo!
Thank you for your answer! Basically, what I am looking for is "if Captive Network gateway provides DNS servers to use, use them for clearing Captive Portal". So maybe even more close to what ipconfig getpacket en0 returns, but using some API that's available on both platforms.

Regarding the bigger picture - you're right and that's what we do when our VPN app is running as the only VPN in the system. But we'd like to support compatibility with other network settings that can be pushed via configuration profile (like DNSSettings with DNS over HTTPS payload).

I have found this question about the system behaviour when the device is connected to the Captive Network and DoH settings are in place which is tightly connected to what we're trying to resolve. If OS would be able to clear the captive portal with DoH payload, we can just continue to take down the tunnel and leave it on the system.

Thanks for the background.

I don’t think I’m gonna have any great answers for you here. You can probably cobble something together on macOS, but your options on iOS are much more limited.

But still, I’d like to further clarify your use case:

Regarding the bigger picture - you're right and that's what we do when our VPN app is running as the only VPN in the system.

Cool.

But we'd like to support compatibility with other network settings that can be pushed via configuration profile …

Can you elaborate on that?

I suspect that I’m gonna end up recommending that you file an ER about this, but if I can understand your use case better I might be able to suggest a good way to pitch that.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Can you elaborate on that?

Sure! I'll describe the general problem that we're facing and how we wanted to overcome it.

In our scenario, we have two variables in play:

  • Configuration profile with DNS over HTTPS settings
  • our VPN app

Here are the scenarios that we have investigated so far. In all of them, the device is connected to the captive network.

  • Device with DoH settings, no VPN app - struggles with Captive Portal, as the DNS gets encrypted and dropped by the gateway
  • Device with VPN app, no DoH settings - works with Captive Portal, as we're able to detect the Captive Portal and opt out of the traffic until the Captive Portal is cleared.
  • Device with VPN and DoH settings - this is the pain point. By opting out of the traffic, we're getting to the first scenario where the user struggles with Captive Portal - DNS traffic leaks from the VPN to the DoH payload, gets encrypted and then blocked.

We wanted to prevent this situation by not opting out of the DNS traffic from the VPN and sending it to the DNS server provided by the gateway instead (root of my original question) so it won't fall back to the DoH.

Note to the configuration profiles with DoH: They are provided to our users either by us, or they can be freely downloaded from the internet (like Quad9 configuration profiles). And we want our VPN app to be compatible with both.

Thank you for looking into this!

Get DNS servers from the system
 
 
Q