This is a bit of a kludge, until I find something better. We simply
iterate through all FDs, and call getsockopt on each one until we find
the utun FD. This works, and completes rather quickly (fd is usually 6
or 7). Rather than maintain the old path for older kernels, just use
this for all versions, to get more coverage. Other techniques involve
undocumented APIs; this one has the advantage of using nothing
undocumented.
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
/// Tunnel device file descriptor.
private var tunnelFileDescriptor: Int32? {
- return self.packetTunnelProvider?.packetFlow.value(forKeyPath: "socket.fileDescriptor") as? Int32
+ var buf = [CChar](repeating: 0, count: Int(IFNAMSIZ))
+ for fd: Int32 in 0...1024 {
+ var len = socklen_t(buf.count)
+ if getsockopt(fd, SYSPROTO_CONTROL, 2, &buf, &len) == 0 && String(cString: buf).hasPrefix("utun") {
+ return fd
+ }
+ }
+ return nil
}
/// Returns a WireGuard version.