Not getting packets in PacketTunnel on iOS

Hi,

I've created a packet tunnel but my packetFlow object isn't get called with any packets. Do I need to do something else to configure the packetFlow? Maybe I have to link it to a NWUDPSession?

Thanks,

Dave

class PacketTunnelProvider: NEPacketTunnelProvider {
    override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) {
        let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: tunnelRemoteAddress)
        settings.ipv4Settings = NEIPv4Settings(addresses: [tunnelRemoteAddress], subnetMasks: ["255.255.255.255"])
        settings.ipv4Settings?.includedRoutes = [NEIPv4Route.default()]

        setTunnelNetworkSettings(settings) { error in
            completionHandler(error)
                              
            self.readPacketObjects()
        }
    }
    
    private func readPacketObjects() {
        self.packetFlow.readPacketObjects() { packets in
            // It never gets here.
            self.logMessage("Got '\(packets.count)' packet(s)")

            self.packetFlow.writePacketObjects(packets)

            self.readPacketObjects()
        }
    }
}
Answered by DTS Engineer in 820897022
Written by docfp in 772219021
Maybe I have to link it to a NWUDPSession?

No. The routing of packets to your provider is independent of what the provider actually does with those packets. In a real VPN setup you’d want to set up your tunnel before you call the completion handler — indeed, you typically want to do this before calling setTunnelNetworkSettings(…), because important settings are coming from the VPN server — but if you’re just bringing things up then there’s no requirement to have the tunnel in place in order to get packets.

Rather, packets are routed to you based on your tunnel settings. And assuming you’re in destination IP mode — that is, the routingMethod property is .destinationIP, so not per-app VPN — then packets are routed to you based on their destination IP address.

Currently you’re claiming the default route. That sounds like it’ll simplify things, but it doesn’t. If you claim the default route then you need to provide a working DNS configuration. So, just to get things started:

  • Claim a route to a specific network.

  • Write a small test project that sends UDP datagrams to an IP address on that network.

Can you receive those packets?


Also, I’m not sure what you’re hoping to achieve via that writePacketObjects(…) call, but it’s almost most definitely not correct. The writePacketObjects(…) method is the mechanism you use to pass packets coming it from your VPN tunnel up to the networking stack. Echoing back packets in this way is not going to do anything useful.

Finally, I wanna make sure you’re using a packet tunnel provider to implement… well… a packet tunnel. I see lots of folks attempt to use it for ‘off-label’ purposes and that generally ends badly. See TN3120 Expected use cases for Network Extension packet tunnel providers.

Share and Enjoy

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

Written by docfp in 772219021
Maybe I have to link it to a NWUDPSession?

No. The routing of packets to your provider is independent of what the provider actually does with those packets. In a real VPN setup you’d want to set up your tunnel before you call the completion handler — indeed, you typically want to do this before calling setTunnelNetworkSettings(…), because important settings are coming from the VPN server — but if you’re just bringing things up then there’s no requirement to have the tunnel in place in order to get packets.

Rather, packets are routed to you based on your tunnel settings. And assuming you’re in destination IP mode — that is, the routingMethod property is .destinationIP, so not per-app VPN — then packets are routed to you based on their destination IP address.

Currently you’re claiming the default route. That sounds like it’ll simplify things, but it doesn’t. If you claim the default route then you need to provide a working DNS configuration. So, just to get things started:

  • Claim a route to a specific network.

  • Write a small test project that sends UDP datagrams to an IP address on that network.

Can you receive those packets?


Also, I’m not sure what you’re hoping to achieve via that writePacketObjects(…) call, but it’s almost most definitely not correct. The writePacketObjects(…) method is the mechanism you use to pass packets coming it from your VPN tunnel up to the networking stack. Echoing back packets in this way is not going to do anything useful.

Finally, I wanna make sure you’re using a packet tunnel provider to implement… well… a packet tunnel. I see lots of folks attempt to use it for ‘off-label’ purposes and that generally ends badly. See TN3120 Expected use cases for Network Extension packet tunnel providers.

Share and Enjoy

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

Yes the tunnel is in .destinationMode.

I'm not sure what you mean say if I claim all traffic I need to provide a working DNS configuration. Does this mean the tunnel's DNS overrides the devices resolver? Will the traffic still pass through the tunnel but be routed to the tunnels DNS server? I tried adding this and it doesn't seem to make any difference. I still can't resolve anything.

   let dnsSettings = NEDNSSettings(servers: ["8.8.8.8"])
   settings.dnsSettings = dnsSettings

Apart from the API docs is there any other information available on configuring the tunnel?

Sorry, I wasn't using writePacketObjects(...) for anything. I was just trying to get at packets coming in.

Written by docfp in 822481022
Does this mean the tunnel's DNS overrides the devices resolver?

Yes. See this post.

When bringing up a tunnel I recommend that you work progressively:

  1. First claim a route to a single dummy network. That should leave your system working overall.

  2. Write a small BSD Sockets tool (or app on iOS) then sends traffic to an IP address on that network. Confirm that traffic arrives in your tunnel. Ignore DNS for the moment.

  3. Implement the code to tunnel this traffic.

  4. Then tweak your configuration to claim a route that has a working server. For example, you might claim a route leading to one of the IP addresses for example.com.

  5. Expand your BSD Sockets code to open a TCP connection to that server. Again, use an IP address, not a DNS name. If that fails, you have a single problem to debug. If it works, it gives you confidence to move on to the next step.

  6. Claim the default route.

  7. Repeat step 5, to make sure things are still working.

  8. Then start dealing with DNS.

Share and Enjoy

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

Hi Quinn,

I worked through it progressively like you suggested and I was able to route UDP traffic and receive a response.

The problem I see now is that I can't use the systems DNS resolver. It seems if I capture all the traffic:

settings.ipv4Settings?.includedRoutes = [NEIPv4Route.default()]

then I MUST set the DNS settings:

let dnsSettings = NEDNSSettings(servers: [DNS_SERVER])
settings.dnsSettings = dnsSettings

I thought if I set:

dnsSettings.matchDomains = [""]

then DNS_SERVER will only be used for the domains in the matchDomains list and the system resolver used for everything else but this doesn't seem to be the case.

Is this a bug?

Thanks,

Dave

Written by docfp in 825613022
I was able to route UDP traffic and receive a response.

Yay!

Written by docfp in 825613022
and the system resolver used for everything else but this doesn't seem to be the case.

You’ve misunderstood the nature of match domains:

  • If match domains contains a list of domains, the system only uses your resolver for those domains.

  • If match domains contains the empty string, the system uses your resolver for all domains.

The latter is useful when you don’t claim the default route (thus creating a split tunnel) but you want your resolver to be used for all DNS resolution. I talk about this more in this post.

However, you’re claiming the default route (a full tunnel) and thus you must provide a working DNS.

Share and Enjoy

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

Not getting packets in PacketTunnel on iOS
 
 
Q