NEPacketTunnelFlow.readPackets not working

Hi There,

I have setup a PacketTunnelProvider as this:
Code Block
class PacketTunnelProvider: NEPacketTunnelProvider {
  override func startTunnel(
   options: [String: NSObject]?,
completionHandler: @escaping (Error?) -> Void
  ) {
   NSLog("Tunnel started")
   remoteEndpoint =
NWHostEndpoint(hostname: "192.168.0.27",
port: "62165")
   readPackets()
 }
  override func stopTunnel(
   with reason: NEProviderStopReason,
completionHandler: @escaping () -> Void
  ) {
   NSLog("Tunnel Stopped")
  completionHandler()
 }
}
extension PacketTunnelProvider {
 private func readPackets() {
   NSLog("readPackets called")
    self?.packetFlow.readPackets { (_, _) in
     NSLog("Did read packets")
    }
  }
}


After running the extension on a device using XCode, I can see completion handler in the
Code Block
NEPacketTunnelFlow.readPackets

is never being called according to logs:
Code Block
default 16:00:07.447406-0800 VPNTestAppExtension Tunnel started
default 16:00:07.466064-0800 VPNTestAppExtension Did finish setting network: nil
default 16:00:07.466629-0800 VPNTestAppExtension readPackets called


Did I miss anything here? To test, I have an app keep sending a UDP packet to a UDP server, I am expecting readPackets method should capture these UDP packets after the tunnel is started.


After running the extension on a device using XCode, I can see completion handler in the

You will need to configure your NEPacketTunnelNetworkSettings and then set them to the NEPacketTunnelProvider using setTunnelNetworkSettings to claim any kind of traffic for your tunnel. If that is set successfully then you should be able to start reading packets from the virtual interface.

I typically setup another class to handle the packet reading and writing and then setup my network transfers from there. Something like:

1) Create your virtual interface settings with NEPacketTunnelNetworkSettings.
2) Set those settings from (1) to the NEPacketTunnelProvider using setTunnelNetworkSettings. This is usually done inside startTunnelWithOptions method.
3) Upon the success of setTunnelNetworkSettings call your packet managing class to start reading / writing packets. and then call the completion handler on startTunnelWithOptions.

4) In your packet manager class use the provider's NEPacketTunnelFlow to call readPacketsWithCompletionHandler. You will receive an array of packets. You then need to decide what you need to do with those packets and at this point it is usually a wise choice to parse these packets to an IPPacket format to extract the transports headers etc..


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
Hi Matt!

Thanks for the hints and suggestions! I made the suggested changes as below:
Code Block
override func startTunnel(
  options: [String: NSObject]?,
completionHandler: @escaping (Error?) -> Void
 ) {
NSLog("Tunnel started")
  remoteEndpoint = NWHostEndpoint(hostname: "192.168.0.27", port: "62165")
let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "192.168.0.27")
setTunnelNetworkSettings(settings) { [weak self] (error) in
    NSLog("Did finish setting network: \(error)")
    completionHandler(error)
    self?.readPackets()
  }
}


The the log on the app side is:
Code Block
Launched
manager is enabled: true
connecting...
connected
connection did send, data: {length = 11, bytes = 0x68656c6c6f20776f726c64}
connection did send, data: {length = 11, bytes = 0x68656c6c6f20776f726c64}
connection did send, data: {length = 11, bytes = 0x68656c6c6f20776f726c64}

The log on the packet tunnel provider side is:
Code Block
default 09:54:14.886492-0800 kernel memorystatus: set assertion priority(3) target VPNTestAppExtension:2490
default 09:54:14.915952-0800 VPNTestAppExtension Hello, I'm launching as euid = 501, uid = 501, personaid = 1000, type = DEFAULT, name = <private>
default 09:54:14.935892-0800 VPNTestAppExtension Initializing connection
default 09:54:14.935951-0800 VPNTestAppExtension Removing all cached process handles
default 09:54:14.936009-0800 VPNTestAppExtension Sending handshake request attempt #1 to server
default 09:54:14.936120-0800 VPNTestAppExtension Creating connection to com.apple.runningboard
default 09:54:14.938035-0800 VPNTestAppExtension Handshake succeeded
default 09:54:14.938097-0800 VPNTestAppExtension Identity resolved as xpcservice<com.test.test.extension([daemon<com.apple.neagent-ios>:313:313])>
default 09:54:14.938528-0800 VPNTestAppExtension Bootstrapping; Bootstrap complete. Ready for handshake from host.
default 09:54:14.939788-0800 VPNTestAppExtension [u C4AA1961-9F06-4C18-BD46-BBA24C2EDC14] [(null)((null))] Prepare received as euid = 501, uid = 501, personaid = 1000, type = DEFAULT, name = <private>
default 09:54:14.942125-0800 VPNTestAppExtension [u 9B875CFD-574F-4F52-8EB0-B9004E7FA876] [<private>(<private>)] Set sole personality.
default 09:54:14.947329-0800 VPNTestAppExtension [u 9B875CFD-574F-4F52-8EB0-B9004E7FA876] [<private>(<private>)] Begin using received as euid = 501, uid = 501, personaid = 1000, type = DEFAULT, name = <private>
default 09:54:14.950351-0800 kernel memorystatus: set assertion priority(14) target VPNTestAppExtension:2490
default 09:54:14.956485-0800 VPNTestAppExtension networkd_settings_read_from_file initialized networkd settings by reading plist directly
default 09:54:14.956536-0800 VPNTestAppExtension networkd_settings_read_from_file initialized networkd settings by reading plist directly
default 09:54:14.957400-0800 VPNTestAppExtension nw_path_evaluator_start [71AC9ED0-F79D-4CA6-BA18-C06BBD3A6746 <NULL> generic, indefinite]
path: satisfied (Path is satisfied), interface: en0, ipv4, ipv6, dns
default 09:54:14.973144-0800 VPNTestAppExtension [Extension com.test.test.extension]: Calling startTunnelWithOptions with options 0x102d0dd70
default 09:54:14.973443-0800 VPNTestAppExtension Tunnel started
default 09:54:14.974246-0800 VPNTestAppExtension [Extension com.test.test.extenison]: provider set tunnel configuration to
tunnelRemoteAddress = <12-char-str>
default 09:54:14.997253-0800 VPNTestAppExtension Did finish setting network: nil
default 09:54:14.997659-0800 VPNTestAppExtension Did try reading packets using packFlow: Optional(<NEPacketTunnelFlow: 0x102c09c00>)


Looks like I did successful NEPacketTunnelNetworkSettings as it prints error as nil. However, I still cannot getting packets using the <NEPacketTunnelFlow: 0x102c09c00>. Any other things should I do?

However, I still cannot getting packets using the NEPacketTunnelFlow

Yeah, you NEPacketTunnelNetworkSettings do not look correct. You could try some combination of these settings:

Code Block swift
let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "x.x.x.x")
let ipv4Settings = NEIPv4Settings.init(addresses: ["x.x.x.x"], subnetMasks: ["x.x.x.x"])
let neIPv4Route = NEIPv4Route.init(destinationAddress: "x.x.x.x", subnetMask: "x.x.x.x")
var includedRoutes: [NEIPv4Route] = []
includedRoutes.append(neIPv4Route)
/* You could also add the default route if you do not want to define specific NEIPv4Route's */
/* includedRoutes.append(NEIPv4Route.default()) */
ipv4Settings.includedRoutes = includedRoutes
let dnsSettings = NEDNSSettings(servers: ["x.x.x.x"])
dnsSettings.matchDomains = ["mydomain.com"]
dnsSettings.matchDomainsNoSearch = true
settings.dnsSettings = dnsSettings
settings.ipv4Settings = ipv4Settings


These settings will vary, so if you configure something and it does not work, pay attention to how you have configured your routes and NEIPv4Settings.


Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com

@yijiexu did you resolve it? I'm facing with the same problem.

If my NEIPv4Settings points to my local server that it's reading on 127.0.0.1, and NEIPv4Route contains 127.0.0.1 + default & my tunnel remote is the same, I cannot read packets from the flow.

@meaton If I need to send my packets to my local device server, that acts as proxy and then reflow them to internet, which is the best approach with this settings?

My proxy server must to redirect packets to internet or the O.S do it by itself?

Thanks

@meaton If I need to send my packets to my local device server, that acts as proxy and then reflow them to internet, which is the best approach with this settings? My proxy server must to redirect packets to internet or the O.S do it by itself?

Redirecting packets outside of the packet tunnel is not a recommended workflow. If you wish to create a proxy, use one of the NEAppProxyProvider or NEDNSProxyProvider APIs out there.

Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
NEPacketTunnelFlow.readPackets not working
 
 
Q