Resolve DNS queries using PacketTunnelProvide for a custom VPN app

Hello,

We are working on developing an iOS client that implements a custom VPN protocol using the PacketTunnelProvider from the NetworkExtension APIs. This client application is responsible for tunneling the traffic based on IP and host names. Hostname based applications are behind a private network and are not accessible from public internet. So, in order for us to tunnel the traffic based on host names, we are in a position to resolve the IP addresses locally on the client side, before tunneling the traffic. Please note that there are no custom / private DNS servers that can help us to resolve the IPs.

So essentially, we might have to resolve the DNS queries locally on the client for these specific set hostnames and then establish a connection to the remote endpoint in order to tunnel the traffic. We are kind of lost in weeds trying to identify a better solution to attain this functionality. Below is the approach that we are looking to give a try and would appreciate your inputs on what would be the best way to go about this.

Given that, we are establishing a tun interface on the PacketTunnelProvider to tunnel the traffic to the remote endpoint, one option is to make use of the existing tun interface to filter out the DNS packets and resolve the host names programmatically. This seems to be a viable solution but we are not sure about any potential implications in terms of performance bottlenecks related to DNS responses, caching etc. Also, concerned about App store limitations in using the tun interface to handle DNS packets.

Based on our research, AdBlock for iOS (https://adblockforios.com) also uses a VPN extension to resolve and blackhole the domain name based on the hosts list. So this is more in line with what we trying to achieve except for the fact that we would need to resolve the hostname rather than black holing it. This approach seems promising but would like to get feedback on this before we go down this road. Any thoughts or directions on this would be very helpful. Thanks in advance!

one option is to make use of the existing tun interface to filter out the DNS packets and resolve the host names programmatically. This seems to be a viable solution but we are not sure about any potential implications in terms of performance bottlenecks related to DNS responses

Right. This seems reasonable if your DNS servers are not available via the public internet. And yes, this does have a performance implication but if the time to live on the DNS queries is longer and the application servers do not rotate IPs often then this should workout fine.

Regarding:

to resolve and blackhole the domain name based on the hosts list. So this is more in line with what we trying to achieve except for the fact that we would need to resolve the hostname rather than black holing it. 

You need to use the DNS responses to access private resources for business purposes, correct? If so, this seems like it fits with TN3120 Expected use cases for Network Extension packet tunnel providers.

Thanks @meaton for the direction on this. I had a couple of concerns around this

Right. This seems reasonable if your DNS servers are not available via the public internet. And yes, this does have a performance implication but if the time to live on the DNS queries is longer and the application servers do not rotate IPs often then this should workout fine.

To be more precise its not that DNS servers are not available via the public internet, instead there is no DNS server at all. So basically, we have to resolve the IP address locally through a mapping table (something like hosts file). Given this behavior, does it make sense to intercept the DNS queries through TUN interface and respond to the queries from the NetworkExtension itself and then on-ramp the traffic once the actual packets flow in.

Regarding:

You need to use the DNS responses to access private resources for business purposes, correct? If so, this seems like it fits with TN3120 Expected use cases for Network Extension packet tunnel providers.

Also in the expected use cases of PacketTunnelProvider, it is mentioned that it is not advisable to intercept all the DNS traffic but intercept only DNS queries for the isolated network. I am a bit lost here, because if we had to intercept DNS queries for a subset, is there any way to effectively do that? Split tunneling is one way that I could foresee, but again we might have to add in DNS server routes to the includedRoutes, but on the iOS device if we end up adding a DNS server route, this would eventually lead to intercepting all DNS queries if am not wrong. Can you please let me know is there something that am missing here?

Given this behavior, does it make sense to intercept the DNS queries through TUN interface and respond to the queries from the NetworkExtension itself and then on-ramp the traffic once the actual packets flow in.

I always try and steer folks away from this approach and always recommend that if your packets are read from the virtual interface that they hit the network. For example, even if's it's a DNS server sitting in the private network that you can point this traffic to that's just responding with the mapped file contents. This seems like a more scalable approach anyways if you want to move application servers around.

Regarding:

because if we had to intercept DNS queries for a subset, is there any way to effectively do that?

One way to do this is to only filter DNS traffic based on the hostnames matched in NEDNSSettings, for example:

let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "x.x.x.x")

...

let dnsSettings = NEDNSSettings.init(servers: ["x.x.x.x"])
dnsSettings.matchDomains = ["apple.com"]
dnsSettings.matchDomainsNoSearch = true
settings.dnsSettings = dnsSettings

Hey @meaton, appreciate all your support on this. I still have something, that I would like to run it through you if you don't mind.

I always try and steer folks away from this approach and always recommend that if your packets are read from the virtual interface that they hit the network. For example, even if's it's a DNS server sitting in the private network that you can point this traffic to that's just responding with the mapped file contents. This seems like a more scalable approach anyways if you want to move application servers around.

I completely understand it's a scalable approach and the ideal way. But, being an enterprise network and existing clients of different devices work in the legacy way, we are in a situation to adapt them and not really have an option to have a DNS server in place. That's kind of restriction and that leads to a scenario where we have to do the resolution locally. That's the part am concerned whether the approach that we discussed above makes sense and is adhering to the Apple Store guidelines. I also don't want to end-up implementing something that gets rejected. Would appreciate your insights on this.

Regarding:

let dnsSettings = NEDNSSettings.init(servers: ["x.x.x.x"])

Again, we don't really have a server here and that leads to my question of whether using the DNS settings without servers is something possible? The matchDomains is the exact API that I was looking for to filter out DNS queries based on host name, but this questions keeps lingering for me.

Thanks so much again!

That's the part am concerned whether the approach that we discussed above makes sense and is adhering to the Apple Store guidelines. I also don't want to end-up implementing something that gets rejected. Would appreciate your insights on this.

I cannot give you any insights here, only to make sure your app complies with the stated App Store Review Guidelines..

Resolve DNS queries using PacketTunnelProvide for a custom VPN app
 
 
Q