How to change packet from TUN interface

Hello!

I am trying to make a VPN-client on custom protocol. I had read many things on apple.com and others and find that it’s not easy way.


My collegue write Android app and how is work: he take all traffic from android, filter tcp-packets and after incapsulate tcp packet on own protocol and send to server via tcp-connection. Can I make do same thing on iOS?


I found that thread https://forums.developer.apple.com/thread/13503and find that we can make access to FileDescriptor. But I don't know how to "see" (or print) a packet from TUN interface. I know that it can be possibility to make to operate with packets and handle them.


This what I mean about to "see" a packets:

packetFlow.readPackets { (packets: [Data], protocols: [NSNumber]) in

for packet in packets {

print("packet: ", packet)

}


Thank you very much!

Replies

NetworkExtension providers do not talk to the TUN interface directly. Rather, they should use the API appropriate for their specific type of provider. For example, a packet tunnel provider typically works as follows:

  • It reads packets from the kernel using the

    NEPacketTunnelFlow
    .
  • It encapsulates those packets as it sees fit.

  • It sends those packets down the tunnel to the server using any networking API (commonly

    NWTCPConnnection
    , but that’s not a requirement).
  • It reads packets from the tunnel using any networking API.

  • In de-encapsulates those packets as it sees fit.

  • It writes those packets back to the tunnel using

    NEPacketTunnelFlow
    .

Share and Enjoy

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

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

Thanks to my boss I found solution "how to see" a packet.

You just need to use NSLog and macos console.app (find in commad + space).


In PacketTunnelProvider class try this (for training I use this project) :


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

conf = (self.protocolConfiguration as! NETunnelProviderProtocol).providerConfiguration! as [String : AnyObject]


packetFlow.readPackets { (packets: [Data], protocols: [NSNumber]) in

for packet in packets {

NSLog("Packet lenght %d", packet.count) // it will appear packet lenght in MacOs console app when your iOs device is connected (for a comfort you need to use special filter to your application in iPhone)



let byteArray = [UInt8](packet) // transfer packet to array

NSLog("Byte array %@", byteArray) // see the array of bytes



}

}


The only question is WHY xcode console doesn't print anything in PacketTunnelProvider class and why I can't find that simple solution anywhere. I can't even breakpoint anything in PacketTunnelProvider. But the same question was asking many times yers ago...


Thank you very much

When creating a NetworkExtension provider, it’s better to log with

os_log
rather than
NSLog
.
NSLog
is good for a quick hack, but your provider will need proper logging in the long term (it’s the only way to debug problems coming in from the field) and thus it’s a good idea to start on that early.

With regards this code:

packetFlow.readPackets { (packets: [Data], protocols: [NSNumber]) in
    …
}

it’s generally easier to use the new

-readPacketObjectsWithCompletionHandler:
method, so you don’t have to deal with parallel arrays of packets and protocol numbers.

With regards this code:

let byteArray = [UInt8](packet) // transfer packet to array
NSLog("Byte array %@", byteArray) // see the array of bytes

the following is both easier and produces nicer results:

NSLog("Byte array %@", packet as NSData)

The only question is WHY xcode console doesn't print anything in PacketTunnelProvider class

Your packet tunnel provider is running in a separate process. If you want to debug it (pause, set breakpoints, look at state), you’ll need to attach to it (via Xcode’s Debug > Attach to Process). However, this won’t let you see console output. Xcode can only show console output for processes that it launched, and your packet tunnel provider was launched by the system.

My recommended approach is to use the macOS Console utility to view the system log from an iOS device attached via USB. It also supports filtering, making it easy to focus on your debugging output.

This ties in nicely with my first point. If you use

os_log
then you can set subsystem and category values that make it easy to filter in the Console utility.

Share and Enjoy

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

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

If i will print like you said

NSLog("Byte array %@", packet as NSData)


what i will see:

<4500003b b43a0000 ff11ea5c 0a080909 02020808 e94a0035 00276724 beea0100 00010000 00000000 03777777 05617070 6c650363 6f6d0000 010001>


The packet.count = 59. How I can understand information for each byte fron this mess?


If i print like this:

  1. let byteArray = [UInt8](packet) // transfer packet to array
  2. NSLog("Byte array %@", byteArray)


The result will be easy to understand for start (packet.count = 60 and equal to elements in array):


69,0,0, 60, 68,13,0, 0, 255, 17, 90, 137, 10, 8, 9, 9, 2, 2, 8, 8, 247, 203, 0, 53, 0, 40, 143, 159, 115, 170, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 4, 109, 101, 115, 117, 5, 97, 112, 112, 108, 101, 3, 99, 111, 109, 0, 0, 1, 0, 1


with this array I can work to each byte dirrectly.

How I can understand information for each byte … ?

That’s a pretty standard hex dump, with a space between each group of 4 bytes, surrounded by angle bracket delimiters. The fact that it starts with an 0x45 is a strong hint that this as an IPv4 packet.

Share and Enjoy

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

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