6

I'm having a Local VPN app that using "NETunnelProvider / NetworkExtentsion", In my solution, I created a split tunnel on the device itself to track the DNS request, using NEKit I was able to peek inside the packets and filter the ongoing request based on the destination address (let's call ita UDP listener for DNS requests).

This solution was working fine on iOS 13.7 and less, recently apple release iOS 14, and my solution stop working, VPN connection still established but the user can't access any webSite, I debugged the code and found out the networkExtision does not receive any packets from user activity only.

I'm using the CocoaAsyncSocket library.

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"

Regarding triggering"Local Network permissions" which is not the issue here (I don't think my solution need to have this permission), Based on the apple document some apps need to request local network permissions, I added the permission to the info.plist but local network permissions are not triggered.

========================== Update #1 ============================

I found out that I was able to capture the packets and do my own things then write packets back to the packetFlow packetFlow.writePackets, But on iOS 14 browsers not loading the websites and keep loading until show time out.

enter image description here

Omarj
  • 1,151
  • 2
  • 16
  • 43
  • Which entitlements have you activated? Did you include com.apple.developer.networking.multicast? – Asperi Oct 16 '20 at 04:07
  • @Asperi no, but the real question here, do I need? does my solution consider one of those cases that I need to trigger local network permission? – Omarj Oct 16 '20 at 23:47
  • @Asperi As I know I need to enable/include networking.multicast when I'm Sending/Receiving UDP multicast/broadcast, but does my solution consider one of those ?? I don't think so – Omarj Oct 17 '20 at 08:28
  • @Asperi check my update, please – Omarj Mar 10 '21 at 16:35

1 Answers1

0

I have an idea, and maybe a solution for you. Starting in iOS version 14, the C function connect() started failing in network extensions, where VPNs have to run, with the following log message from the kernel:

Sandbox: VPN Extensio(8335) deny(1) network-outbound*:<port #>

However, it does work in the app, which is next to useless if you need it in the extension. GCDAsyncUdpSocket is a thin layer that right under the covers is calling socket() and connect().

NWConnection does work in a network extension, and it should work for you if it is feasible to port your code and you don't need the actual socket descriptor. But you will have to conditionally compile if you have to support devices < ios 12.

larryp
  • 1
  • 1
  • 1
  • I forgot to include this only happens if the device has a public ip address. That is, wifi is disabled or it is not connected to a wifi network. No problems if the device is on wifi. – larryp May 04 '21 at 17:54