NEPacketTunnelProvider::packetFlow.readPackets is not called and network extension crashes

Hi! I am trying to build a network system extension with NEPacketTunnelProvider. Actually, I want to see all outgoing packets. So, here is my config for NETunnelProviderManager:

        let protocolConfiguration = NETunnelProviderProtocol()
        protocolConfiguration.providerBundleIdentifier = "bundle id"
        protocolConfiguration.serverAddress = "ip address"
        protocolConfiguration.providerConfiguration = [:]
        manager.protocolConfiguration = protocolConfiguration
        manager.isEnabled = true
        manager.localizedDescription = "SamplePacketTunnel"

Currently, I want to see logs from packetFlow.readPackets. I understand that without opening the connection to the server and writing to it, I would see the absence of the Internet on my machine. However, I don't want to create the whole system for my vpn tunnel for now.

The source code inside NEPacketTunnelProvider looks like:

override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) {

        os_log(.debug, log: self.log, "Tunnel started")
        let tunnelSettings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "same address as in protocol configuration")
        let ipv4Settings = NEIPv4Settings.init(addresses: ["my local ip"], subnetMasks: ["255.255.255.0"])
        var includedRoutes: [NEIPv4Route] = []
        includedRoutes.append(NEIPv4Route.default())
        ipv4Settings.includedRoutes = includedRoutes
        tunnelSettings.ipv4Settings = ipv4Settings
        setTunnelNetworkSettings(tunnelSettings) { error in
            if let error = error {
                os_log(.debug, log: self.log, "Error on tunnel start: %@", error.localizedDescription)
                completionHandler(error)
                return
            }
            os_log(.debug, log: self.log, "No errors on setTunnelNetworkSettings")
            completionHandler(nil)
            self.readTraffic()
        }
    }

and readTraffic:

private func readTraffic() {
        os_log(.debug, log: self.log, "Started reading the traffic")
        packetFlow.readPackets { dataArray, protocolsArray in
            os_log(.debug, log: self.log, "Reading packets. Traffic packets count: %@", dataArray.count)
            self.readTraffic()
        }
    }

By now I managed to see Tunnel started and Started reading the traffic logs. But there is no evidence of Reading packets. Traffic packets count messages. Moreover, in the Console I see crash report:

Thread 1 Crashed::  Dispatch queue: NEPacketTunnelFlow queue
0   libobjc.A.dylib               	       0x1a6b52588 objc_msgSend + 8
1   libsystem_trace.dylib         	       0x1a6a3cc5c _os_log_fmt_flatten_object + 132
2   libsystem_trace.dylib         	       0x1a6a3ac54 _os_log_impl_flatten_and_send + 1852
3   libswiftos.dylib              	       0x1bb8e06e8 _swift_os_log + 260
4   libswiftos.dylib              	       0x1bb8e760c specialized withVaList<A>(_:_:) + 452
5   libswiftos.dylib              	       0x1bb8e7a6c os_log(_:dso:log:_:_:) + 180
6   com.ybelikov.packet.tunnel.sample.network.extension	       0x10019a23c closure #1 in PacketTunnelProvider.readTraffic() + 256 (PacketTunnelProvider.swift:50)
7   com.ybelikov.packet.tunnel.sample.network.extension	       0x10019a2e4 thunk for @escaping @callee_guaranteed (@guaranteed [Data], @guaranteed [NSNumber]) -> () + 132
8   NetworkExtension              	       0x1b5427a04 __55-[NEPacketTunnelFlow readPacketsWithCompletionHandler:]_block_invoke + 552
9   NetworkExtension              	       0x1b5487134 NEVirtualInterfaceReadMultiplePackets + 1024
10  NetworkExtension              	       0x1b548a970 __NEVirtualInterfaceCreateReadSource_block_invoke_2 + 80
11  libdispatch.dylib             	       0x1a6b081b4 _dispatch_client_callout + 20
12  libdispatch.dylib             	       0x1a6b0b670 _dispatch_continuation_pop + 500
13  libdispatch.dylib             	       0x1a6b1e8e0 _dispatch_source_invoke + 1596
14  libdispatch.dylib             	       0x1a6b0f784 _dispatch_lane_serial_drain + 376
15  libdispatch.dylib             	       0x1a6b10404 _dispatch_lane_invoke + 392
16  libdispatch.dylib             	       0x1a6b1ac98 _dispatch_workloop_worker_thread + 648
17  libsystem_pthread.dylib       	       0x1a6cc8360 _pthread_wqthread + 288
18  libsystem_pthread.dylib       	       0x1a6cc7080 start_wqthread + 8

Could you suggest where a mistake in the tunnel settings is? I want only to read outgoing packages for now. I understand that this is not how VPN clients are supposed to work, but I am doing that only for a little experiment, so I know that in such a manner I will break the connection on my computer.

Answered by DTS Engineer in 725941022

This is just a bug in your logging. This line:

os_log(.debug, log: self.log, "Reading packets. Traffic packets count: %@", dataArray.count)

is wrong. The %@ should be a %zd.

I make this mistake all the time )-:

If you are able to raise your deployment target then I encourage you to adopt Swift’s Logger type; that will prevent you from ever having to do with this problem again.

Share and Enjoy

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

Accepted Answer

This is just a bug in your logging. This line:

os_log(.debug, log: self.log, "Reading packets. Traffic packets count: %@", dataArray.count)

is wrong. The %@ should be a %zd.

I make this mistake all the time )-:

If you are able to raise your deployment target then I encourage you to adopt Swift’s Logger type; that will prevent you from ever having to do with this problem again.

Share and Enjoy

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

Ah, exactly. Thank you!

NEPacketTunnelProvider::packetFlow.readPackets is not called and network extension crashes
 
 
Q