Issues with VOIP Calls on iOS Local Proxy Server using NEPacketTunnelProvider

Hello! I recently used Connect Proxy with iOS's NEPacketTunnelProvider to set up a local proxy server. I also referenced this to simultaneously support HTTP proxy. Currently, when I open Safari or Chrome on my iOS device, it works great!

However, when I use some instant messenger app to make VOIP calls, I can't make successful calls. What could be the possible reason for this? I want my proxy server to intercept only HTTP/HTTPS requests but not interfere with or block VOIP calls. Is there any configuration parameter that can achieve this?

I'm sorry, I'm not very familiar with proxy servers and VOIP. If there's anything else you need to know, please let me know. I appreciate any guidance!

Here is how I've configured my Local Proxy Server:

let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)
let bootstrap = ServerBootstrap(group: group)
    .serverChannelOption(ChannelOptions.socket(SOL_SOCKET, SO_REUSEADDR), value: 1)
    .childChannelOption(ChannelOptions.socket(SOL_SOCKET, SO_REUSEADDR), value: 1)
    .childChannelInitializer { channel in
        channel.pipeline.addHandler(ByteToMessageHandler(HTTPRequestDecoder(leftOverBytesStrategy: .forwardBytes)))
            .flatMap {
                channel.pipeline
                    .addHandler(HTTPResponseEncoder())
            }
            .flatMap {
                if channel.localAddress?.port == self.localhostHttpPort {
                    channel.pipeline
                        .addHandler(ConnectHttpHandler())
                } else {
                    channel.pipeline
                        .addHandler(ConnectHttpsHandler())
                }
            }
    }

And here is how I start Packet Tunnel:

let tunnelNetworkSettings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: localhostIP)

let proxySettings = NEProxySettings()
proxySettings.httpServer = NEProxyServer(address: localhostIP, port: localhostHttpPort)
proxySettings.httpsServer = NEProxyServer(address: localhostIP, port: localhostHttpsPort)
proxySettings.autoProxyConfigurationEnabled = false
proxySettings.httpEnabled = true
proxySettings.httpsEnabled = true
proxySettings.excludeSimpleHostnames = true
proxySettings.exceptionList = ["192.168.0.0/16", "10.0.0.0/8", "172.16.0.0/12", "127.0.0.1", "localhost", "*.local"]
tunnelNetworkSettings.proxySettings = proxySettings

tunnelNetworkSettings.ipv4Settings = NEIPv4Settings(addresses: ["10.8.0.2"], subnetMasks: ["255.255.255.0"])
tunnelNetworkSettings.mtu = 1500
let dns = NEDNSSettings(servers: ["8.8.8.8"])
dns.matchDomains = [""]
tunnelNetworkSettings.dnsSettings = dns
tunnelNetworkSettings.ipv4Settings?.includedRoutes = [NEIPv4Route.default()]
tunnelNetworkSettings.ipv4Settings?.excludedRoutes = [
    NEIPv4Route(destinationAddress: "192.168.0.0", subnetMask: "255.255.0.0"),
    NEIPv4Route(destinationAddress: "10.0.0.0", subnetMask: "255.0.0.0"),
    NEIPv4Route(destinationAddress: "172.16.0.0", subnetMask: "255.240.0.0")
]

setTunnelNetworkSettings(tunnelNetworkSettings) { error in
    self.pendingCompletion?(error)
    self.pendingCompletion = nil
}
2 Likes

I think this is a conversation worth taking to the apple developer forums: it doesn't sound like a SwiftNIO problem to me. Can you link your thread on the forums back here when you create it?

OK~ Thanks for your response! I've posted this issue on the Apple Developer forum.

By the way, many thanks for your reply in the http proxy server discussion and explain how Connect Proxy works. I've learned a lot from the implementation process, and find this piece of code really clever!

I'm curious, does the Connect Proxy only handle HTTP/HTTPS requests, or does it not deal with socket or streaming requests?

It only handles HTTP/HTTPS requests. However, for HTTPS requests the actual content is totally invisible to the connect proxy, so it doesn't need to know how websockets work. It would only need to know for unencrypted websocket requests, which are vanishingly rare.

1 Like

I see, thank you! My earlier question on the Apple Developer Forum has been answered, and it appears that my code may not be entirely correct in terms of the usage of packet tunnel and proxy server.