NEPacketTunnelFlow.readPackets not always returning UDP packets

I am using the NEPacketTunnelFlow.readPackets completion handler to intercept packets as they are outgoing.

A problem I am currently facing is that packets of type UDP are not always received and sometimes, not at all, and I am not really sure why. Is this an operating system caching mechanism maybe?

I am not by any means a networking expert nor do I have more than basic knowledge in the field, so maybe I can get a logical explanation here.

My current setup: iPhone 11 with iOS 16.2, Xcode 14.2, Minimum OS: iOS 13.0

This is my code:

func readOutgoingPackets() {
    tunnelProvider?.packetFlow.readPackets { [weak self] packets, protocols in
        guard let self else { return }

        for (i, packet) in packets.enumerated() {
            self?.parsePacket(packet)
        }

        self?.readOutgoingPackets()
    }
}

func parsePacket(_ packet: Data) {
    do {
        let data = BinaryData(data: packet)
        let header = IPHeader(version: try data.get(0),
                            headerLength: try data.get(1),
                            typeOfService: try data.get(2),
                            length: try data.get(3),
                            id: try data.get(5),
                            offset: try data.get(7),
                            timeToLive: try data.get(8),
                            proto: try data.get(9),
                            checksum: try data.get(10),
                            source: in_addr(s_addr: try data.get(12)),
                            destination: in_addr(s_addr: try data.get(16)))

        switch header.proto {
        case 17:
            os_log("🌐 📦 UDP packet read")
        case 6:
            os_log("🌐 📦 TCP packet read")
        default: break
        }
    } catch {
       os_log("🌐 ❗️ Error parsing packet")
    }
}

I am using an external library called BinarySwift to read the binary IP packet headers.

Any help would be appreciated. Thanks!

A problem I am currently facing is that packets of type UDP are not always received and sometimes, not at all, and I am not really sure why.

Try using a NEDNSSettings to match a domain that you need for the business purposes of your tunnel. This should give you some more UDP traffic to work with.

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

If you are still not able to claim UDP traffic then try to extracting the bytes/bits from the start of the packet, or Data, without the 3rd party library and see what you are working with. This should tell you what the traffic is that you are working with at least.

NEPacketTunnelFlow.readPackets not always returning UDP packets
 
 
Q