Reading and writing on virtual interface created by NEPacketTunnelProvider in separate process

Hi,

We have NEPacketTunnelProvider which creates a virtual interface. I am trying to Read and write virtual interface in separate process(c++ command line project). Read works fine, but write is not working.

Reading packet in separate process as below:

    int bpf = 0;
    
    for (int i = 0; i < 99; ++i) {
        snprintf(buf, 11, "/dev/bpf%i", i);
        bpf = open(buf, O_RDWR);
        
        if (bpf != -1) break;
    }
    struct ifreq interface;
    strcpy(interface.ifr_name, interfaceName.c_str());
    if(ioctl(bpf, BIOCSETIF, &interface) > 0) {
        return errno;
    }
    
    unsigned int one = 1;
    if (ioctl(bpf, BIOCIMMEDIATE, &one) == -1) {
        return errno;
    }

    int bufLength = 1;
    if (ioctl(bpf, BIOCGBLEN, &bufLength) == -1) {
        return errno;
    }
    
    if (ioctl(bpf, BIOCPROMISC, NULL) == -1) {
        return errno;
    }

//Reading bpf as below
readBytes = (int)read(bpf, bpfBuffer, bufLength);

**Whenever traffic routed to Packet Tunnel provider interface as per network rule, Read works fine in this process(separate c++ process). We are able to read valid packet. **

//Writing as below
    ssize_t writtenBytes = write(bpf, packet, size);
    if (writtenBytes < 1)
    {
        return false;
    } else {
        return true;
    }

Above write API is not giving any error, returning byte written correctly.

But after write, packet is not reaching to application which generated traffic. For example, for ping, it is showing 1 packets transmitted, 0 packets received, 100.0% packet loss

I also tried sending it over raw socket. Since separate process is command line and not sandboxed, raw socket getting openned.

`ssize_t bytes = sendto (fRawSocket, packet, size, 0, (sockaddr*) dest, sizeof(*dest)); //dest is packet tunnel virtual interface ip addres`

This also not returning any error but this packet is also not reaching to application which generated traffic.

There is packetFlow.writePacketObjects which works fine in swift. but due to some architecture constraint, i am reading and writing packet in separate process.

is this something macOS doesn't allow or i am doing something wrong?

Accepted Reply

There is packetFlow.writePacketObjects which works fine in swift. but due to some architecture constraint, i am reading and writing packet in separate process.

This isn’t going to work. The only supported way to read and write from the flow is via the methods on the NEPacketTunnelFlow object, and you can’t pass that object between processes.

I’ve seen folks play games like this in the past and they tend to break horribly. Apple platforms are moving towards a user-space networking architecture and, as that effort proceeds, your assumptions about how things work won’t necessarily hold. For example, folks assume that an NEPacketTunnelFlow object is a wrapper around a UTUN socket, but that’s an implementation detail. There’s no guarantee that it’ll work that way in the future. One goal of the NEPacketTunnelFlow API is to isolate you from such changes.

The easiest way to fix this is to move the code that works with the packets into your NE provider process. If that’s too hard, you’ll need to implement your own IPC mechanism, that is, have a stub in the NE provider process that works with the NEPacketTunnelFlow object and passes packets through to your other process via some IPC mechanism that you control.

Share and Enjoy

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

Replies

There is packetFlow.writePacketObjects which works fine in swift. but due to some architecture constraint, i am reading and writing packet in separate process.

This isn’t going to work. The only supported way to read and write from the flow is via the methods on the NEPacketTunnelFlow object, and you can’t pass that object between processes.

I’ve seen folks play games like this in the past and they tend to break horribly. Apple platforms are moving towards a user-space networking architecture and, as that effort proceeds, your assumptions about how things work won’t necessarily hold. For example, folks assume that an NEPacketTunnelFlow object is a wrapper around a UTUN socket, but that’s an implementation detail. There’s no guarantee that it’ll work that way in the future. One goal of the NEPacketTunnelFlow API is to isolate you from such changes.

The easiest way to fix this is to move the code that works with the packets into your NE provider process. If that’s too hard, you’ll need to implement your own IPC mechanism, that is, have a stub in the NE provider process that works with the NEPacketTunnelFlow object and passes packets through to your other process via some IPC mechanism that you control.

Share and Enjoy

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