问题描述
我有一个Local
VPN
应用,它使用“ NETunnelProvider
/ NetworkExtentsion
”,在我的解决方案中,我在设备本身上创建了一个拆分隧道以进行跟踪使用NEKit
进行DNS请求,我就可以窥视数据包并根据目标地址(let's call ita UDP listener for DNS requests).
过滤正在进行的请求
此解决方案在iOS 13.7及更低版本上运行良好,最近是Apple版本iOS 14
,我的解决方案停止工作,VPN
连接仍然建立,但用户无法访问任何网站,我调试了代码,发现networkExtision
仅从用户活动中没有收到任何packets
。
我正在使用CocoaAsyncSocket
库。
func udpSocket(_ sock: GCDAsyncUdpSocket,didReceive data: Data,fromAddress address: Data,withFilterContext filterContext: Any?) {
let host = GCDAsyncUdpSocket.host(fromAddress: address)
guard let message = DNSMessage(payload: data) else {
return
}
guard let session = pendingSession.removeValue(forKey: message.transactionID) else {
return
}
session.realResponseMessage = message
session.realIP = message.resolvedIPv4Address
let domain = session.requestMessage.queries[0].name
let udpParser = UDPProtocolParser()
udpParser.sourcePort = Port(port: dnsServerPort)
udpParser.destinationPort = (session.requestIPPacket!.protocolParser as! UDPProtocolParser).sourcePort
udpParser.payload = session.realResponseMessage!.payload
let ipPacket = IPPacket()
ipPacket.sourceAddress = IPAddress(fromString: dnsServerAddress)
ipPacket.destinationAddress = session.requestIPPacket!.sourceAddress
ipPacket.protocolParser = udpParser
ipPacket.transportProtocol = .udp
ipPacket.buildPacket()
packetFlow.writePackets([ipPacket.packetData],withProtocols: [NSNumber(value: AF_INET as Int32)])
}
let dummyTunnelAddress = "127.0.0.1"
let dnsServerAddress = "8.8.4.4"
let dnsServerPort: UInt16 = 53
// Tunnel confg.
let tunnelAddress = "192.168.0.1"
let tunnelsubnetMask = "255.255.255.0"
关于触发“本地网络权限”,这不是这里的问题(我认为我的解决方案不需要此权限),基于apple文档,某些应用程序需要请求本地网络权限,因此我将权限添加到info.plist
,但不会触发本地网络权限。
========================== 更新#1 ==========================
我发现我可以捕获数据包并做自己的事情,然后将数据包写回packetFlow packetFlow.writePackets
,但是在iOS 14上,浏览器不加载网站并保持加载,直到显示超时为止。 / p>
解决方法
我有一个想法,也许可以为您提供解决方案。从 iOS 版本 14 开始,C 函数 connect() 开始在网络扩展中失败,VPN 必须在这些扩展中运行,并显示来自内核的以下日志消息:
Sandbox: VPN Extensio(8335) deny(1) network-outbound*:<port #>
但是,它确实可以在应用程序中使用,如果您在扩展程序中需要它,它几乎没用。 GCDAsyncUdpSocket 是一个很薄的层,在其背后调用 socket() 和 connect()。
NWConnection 确实在网络扩展中工作,如果可以移植您的代码并且您不需要实际的套接字描述符,它应该对您有用。但是如果你必须支持设备