Get file descriptor of VPN TUN interface

Regarding the new iOS9 Network Extension classes NEPacketTunnelProvider and NEPacketTunnelFlow, is it possible to get the file descriptor (FD) of TUN interface associated to tunnel so that the FD can be used to sending/receiving packets to/from the interface (rather than receiving/sending through the functions readPacketsWithCompletionHandlerprovided()/writePackets() by NEPacketTunnelFlow).

Replies

… is it possible to get the file descriptor (FD) of TUN interface associated to tunnel so that the FD can be used to sending/receiving packets to/from the interface (rather than receiving/sending through the functions readPacketsWithCompletionHandlerprovided()/writePackets() by NEPacketTunnelFlow).

No. The design requires that you tunnel provider use the NEPacketTunnelFlow to transfer data.

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

I have found that you can obtain the file descriptor in this way:


let tunFd = self.packetFlow.value(forKeyPath: "socket.fileDescriptor") as! Int32;


If you are going to be reading directly from this fd, be aware that iOS's tun implementation appends a 4-byte protocol information header to each packet. If we had more control we would create the tun with the IFF_NO_PI option to prevent this, but instead we just throw away the first four bytes.

Hi Spensaurus,

Can you please let me know how you removed first 4 bytes from data correctly ? I am trying but it seems corrupted the whole data?


BR

Dinesh

I’m not sure how I missed this back in August but…

I have found that you can obtain the file descriptor in this way:

This technique is unsupported and I strongly recommend that you not use it in production code. As I mentioned earlier, there is no supported way to get a TUN file descriptor for a

NEPacketTunnelFlow
. This isn’t an accidental omission, but a deliberate design based on the fact that iOS is in the process of moving to a user space networking stack.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Spensaurus, how did you make it work? I ran into the exact same issue. Simply stripping the leading 4 bytes of the packets read from tun FD didn't do the trick. Do you stripe it under certain conditions only? Do you have to add such 4 bytes when writing into the tun fd?


Thanks

It's end-year 2021, and the file-descriptor method works till now, like:

let tunFd = self.packetFlow.value(forKeyPath: "socket.fileDescriptor") as! Int32;

.

But we need to do:

  1. Remove beginning's 4 byte prefix when reading.
  2. Maybe prefix with Mac-header instead (if tap-layer packet is required).
  3. Later, when writing add back the 4 bytes (and remove any Mac-header instead).

See also How to parse network-extension packets?

  • Today 24-03-2022, I found it don’t work! I want to know there are other way to implement it? I am designing a custom vpn protocol .

Add a Comment

the file-descriptor method works till now

To reiterate this is not a supported technique. If you use it in product code you run the risk of both business and technically problems.

Share and Enjoy

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