Get socket's file descriptor in NEFilterDataProvider callbacks

Few years ago I developed kext with socket filter which I used to implement firewall and split tunneling. Since kext will be banned from macOS 10.16, I'm trying to use SystemExtension and NEFilterDataProvider to replace the kext. I managed to implement firewall using NEFilterDataProvider, but not split tunneling. Is there a way in which I can get socket's file descriptor in handleNewFlow, handleInboundData, handleOutboundData callbacks? I need it to bind sockets to specific network interface in order to implement split tunneling. I noticed that descriptor can be retrieved from NEPacketTunnelFlow:

packetFlow.value(forKeyPath: "socket.fileDescriptor") as? Int32,

but that doesn't work with NEFilterSocketFlow.

Replies

You are assuming that flows are based on BSD Sockets, which is not something guaranteed by the API. One important goal of the NKE-ectomy is to allow macOS to adopt the new user space networking stack, and that networking stack does not use sockets.

Apropos that, you wrote:

I noticed that descriptor can be retrieved from

NEPacketTunnelFlow
:
packetFlow.value(forKeyPath: "socket.fileDescriptor") as? Int32,

Do not even think about doing that in production code! Using KVC to access private ivars is clearly not supported and likely to lead to binary compatibility problems.

As to your main goal, I recommend that you look at implementing a transparent proxy provider. Filter providers are designed to filter, that is, allow or block a connection. They don’t provide any facility to modify a connection, and that’s what you’re trying to do here.

Share and Enjoy

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

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

Thank you for the help.

I implemented transparent proxy but I'm experiencing some issues.

I'm getting new flows in handleNewFlow(_ flow: NEAppProxyFlow) callback, but I completely loose network connection every time I enable the proxy. Here is my NEAppProxyProvider implementation:


override func startProxy(options: [String : Any]? = nil, completionHandler: @escaping (Error?) -> Void) {

var includedRules = [NENetworkRule]()

os_log("I have proxy start")

let remoteNetwork = NWHostEndpoint(hostname: "8.8.8.8", port: "0")

let networkRule = NENetworkRule(remoteNetwork: remoteNetwork,

remotePrefix: 0,

localNetwork: nil,

localPrefix: 0,

protocol: .any,

direction: .outbound)

includedRules.append(networkRule)

let settings = NETransparentProxyNetworkSettings(tunnelRemoteAddress: "127.0.0.1")

settings.includedNetworkRules = includedRules

setTunnelNetworkSettings(settings) { error in

if error != nil {

os_log("I have proxy start error")

} else {

os_log("I have proxy start success")

}

completionHandler(error)

}

}

override func handleNewFlow(_ flow: NEAppProxyFlow) -> Bool {

os_log("I have proxy flow")

flow.open(withLocalEndpoint: nil) { error in

if error != nil {

os_log("I have proxy open error")

} else {

//flow.networkInterface = nw_interface_create_with_name("en0")

os_log("I have proxy open success")

}

flow.closeReadWithError(error)

flow.closeWriteWithError(error)

}

return true

}


Do you maybe have some transparent proxy code samples so I could see what I'm doing wrong?

I implemented transparent proxy but I'm experiencing some issues.

Please drop me a line via email (my address is in my signature).

Share and Enjoy

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

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

I sent you an email with following subject:

Apple Developer Forum - Get socket's file descriptor in NEFilterDataProvider callbacks

Hello,


is it possible to use third-party libraries in system extension? If I import any library using cocoapods, my system extension doesn't want to start, even if I don't reference the library in code at all.

Have you checked whether the library you are using is actually embedded in your SystemExtension ?


At "installation time" it is going to be copied out of the App into a directory under /Library/SystemExtensions, so it needs to be entirely self-contained.


For example, if it is linked against a non-OS framework, that framework needs to be in


/Library/SystemExtensions/<UUID><your-system-extension>/Contents/Frameworks

I am facing the same issue with Cocoapods. Did you manage to resolve it Galactico?