NEPacketTunnelProvider - Tunnel Works but Internet Connection Fails

Hi,

I'm working on a VPN app using NEPacketTunnelProvider. The primary goal is to capture outgoing network packets while keeping the internet connection functional. However, with the current implementation, the internet connection stops working after the VPN is enabled. Specifically, browsers like Safari and Chrome fail to load any website (e.g., google.com or apple.com). Below is the relevant code snippet from my startTunnel method:

override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) {
    os_log("Starting tunnel...", log: self.log, type: .info)
    
    // Configure network settings
    let networkSettings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "10.0.0.1")
    networkSettings.ipv4Settings = NEIPv4Settings(addresses: ["10.0.0.2"], subnetMasks: ["255.255.255.0"])
    networkSettings.ipv4Settings?.includedRoutes = [NEIPv4Route.default()] // Route all traffic through tunnel
    networkSettings.ipv4Settings?.excludedRoutes = [] // No exceptions
    
    // DNS configuration
    networkSettings.dnsSettings = NEDNSSettings(servers: ["8.8.8.8"])
    //networkSettings.dnsSettings?.matchDomains = [""] // Uncommented to process all domains
    
    // MTU configuration
    networkSettings.mtu = 1400
    
    // Apply tunnel network settings
    setTunnelNetworkSettings(networkSettings) { [weak self] error in
        guard let self = self else { return }
        if let error = error {
            os_log("Failed to set tunnel settings: %{public}@", log: self.log, type: .error, error.localizedDescription)
            completionHandler(error)
            return
        }
        
        os_log("Tunnel settings applied successfully", log: self.log, type: .info)
        self.readPackets() // Start reading packets
        completionHandler(nil)
    }
}

private func readPackets() {
    let queue = DispatchQueue(label: "PacketProcessing", qos: .userInitiated)
    
    self.packetFlow.readPackets { packets, protocols in
        queue.async {
            for (i, packet) in packets.enumerated() {
                self.logPacketInfo(packet: packet, protocolCheck: Int32(protocols[i]))
                self.packetFlow.writePackets([packet], withProtocols: [protocols[i]]) // Re-send packet
            }
            self.readPackets() // Continue reading
        }
    }
}

Questions

  1. Are there additional configurations required to ensure that the VPN forwards packets correctly to maintain internet connectivity?

  2. Could there be a missing setting related to includedRoutes or dnsSettings that is causing the issue?

  3. How should packets be properly handled in the readPackets method to avoid breaking the internet connection?

  4. With this approach, is it possible to read network packets generated by browsers like Safari and Chrome?

Please understand that it's my first time leaving a question, so it's not readable.

Thank you!!

The primary goal is to capture outgoing network packets while keeping the internet connection functional.

I’d like to better understand your goal here. Most VPN products create a tunnel to a VPN server and then forward packets between the packet flow and that tunnel. It sounds like you’re trying to create something that’s not a VPN. That is, you want to monitor the packets destined for wider Internet but not actually forward them down a tunnel. Is that right?

If so, that’s not something we support. TN3120 Expected use cases for Network Extension packet tunnel providers explains this in more detail. The packet tunnel infrastructure is intended to be used to implement VPN products. If you try to use it to implement other products, like a packet monitoring app, you will encounter weird problems.

Share and Enjoy

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

NEPacketTunnelProvider - Tunnel Works but Internet Connection Fails
 
 
Q