My application implements and IPv6 over IPv4 tunnel using NEPacketTunnelProvider. The tunnelling system works perfect but iOS is only requesting IPv4 resolution so it makes the system quite unusefulness.
If I understood correctly how iOS works, the system don't use IPv6 resolution because it doesn't detect a primary interface with IPv6 address (despite the tun interface has an IPv6 address assigned). I think that in order to have an IPv6 address I have to have a default IPv6 route pointing to the tun interface. If I use tunSettings.ipv6Settings?.includedRoutes = [NEIPv6Route.default()], full network doesn't work (wireless notification icon disappear) but if I add the two routes ::/1 and 8000::/1 I have IP connectivity but not DNS resolution.
What I should do to have IPv6 resolution?
On the other hand and just for curiosity. If what I have explained is correct and we need to have an IPv6 default route to the interface to have IPv6 resolution, how it would work If I only want to tunnel part of the traffic?
Logs when using NEIPv6Route.default() can be found here http://openoverlayrouter.org/downloads/logs.txt
The code I am using is:
class PacketTunnelProvider: NEPacketTunnelProvider{
....
var completionHandler: ((Error?) -> Void)?
//Fake VPN server IP address
var tunSettings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "0.0.0.0")
override func startTunnel(options: [String : NSObject]? = nil, completionHandler: @escaping (Error?) -> Void) {
self.completionHandler = completionHandler
//TUN IP address
let eid = defaults?.string(forKey: "eid")
if validateIPv4(ip: eid!) {
tunSettings.ipv4Settings = NEIPv4Settings(addresses: [eid!], subnetMasks: ["255.255.255.255"])
// Networks to be routed through TUN
tunSettings.ipv4Settings?.includedRoutes = [NEIPv4Route.default()]
} else if validateIPv6(ip: eid!) {
tunSettings.ipv6Settings = NEIPv6Settings(addresses: [eid!], networkPrefixLengths: [128 as NSNumber])
// Networks to be routed through TUN, it appears that there is some bug with defualt IPv6 route ::/0, so we define 2 routes with 2 big networks.
let route1 = NEIPv6Route(destinationAddress: "::", networkPrefixLength: 1)
let route2 = NEIPv6Route(destinationAddress: "8000::", networkPrefixLength: 1)
tunSettings.ipv6Settings?.includedRoutes = [route1, route2]
}
tunSettings.mtu = 1440
// When using IPv6 configuration, the system doesn't send the DNS request to this server. For IPv4 it works
tunSettings.dnsSettings = NEDNSSettings(servers: [(defaults?.string(forKey: "dnsServer"))!])
// Apply settings and create TUN
setTunnelNetworkSettings(tunSettings) { error in
if error != nil {
NSLog("PacketTunnelProvider.startTunnel.setTunnelNetworkSettingsError \(String(describing: error))")
completionHandler(error)
}
// Tell to the system that the fake VPN is "up"
completionHandler(nil)
}
....
}