title: iOS Packet Tunnel Provider with Local On-Device Server
body: <p>I'm using the Network Extension framework provided by Apple to build a packet sniffing/monitoring application similar to Charles Proxy and Surge 4 for iOS.</p>
  <p>So far, I have the basic structure of the project up and running with the Main Application triggering the PacketTunnelProvider Extension where I can see packets being forwarded via the packetFlow.readPackets(completionHandler:) method. My background isn't in networking so I'm confused on the basic structure of these kinds of apps. Do they host a server on the device that act as the proxy which intercepts network requests? Could anyone provide a diagram of the general flow of the network requests? I.e. what is the relationship between the Packet Tunnel Provider, Proxy Server, Virtual Interface, and Tunnel?</p>
  <p>If these apps do use a local on-device server, how do you configure the NEPacketTunnelNetworkSettings to allow for a connection? I have tried incorporating a local on-device server such as <a href="https://github.com/swisspol/GCDWebServer" rel="noreferrer">GCDWebServer</a> with no luck in establishing a link between the two.</p>
  <p>For example, if the GCDWebServer was reachable at <strong>192.168.1.231:8080</strong>, how would I change the code below for the client to communicate with the server?</p>
  <p>Main App:</p>
  <pre><code>    let proxyServer = NEProxyServer(address: &quot;192.168.1.231&quot;, port: 8080)
      
      let proxySettings = NEProxySettings()
      proxySettings.exceptionList = []
      proxySettings.httpEnabled = true
      proxySettings.httpServer = proxyServer
      
      let providerProtocol = NETunnelProviderProtocol()
      providerProtocol.providerBundleIdentifier = self.tunnelBundleId
      providerProtocol.serverAddress = &quot;My Server&quot;
      providerProtocol.providerConfiguration = [:]
      providerProtocol.proxySettings = proxySettings
      
      let newManager = NETunnelProviderManager()
      newManager.localizedDescription = &quot;Custom VPN&quot;
      newManager.protocolConfiguration = providerProtocol
      newManager.isEnabled = true
      saveLoadManager()
      self.vpnManager = newManager
  </code></pre>
  <p>PacketTunnelProviderExtension:</p>
  <pre><code>func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -&gt; Void) {
    ...
          let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: &quot;127.0.0.143&quot;)
          settings.ipv4Settings = NEIPv4Settings(addresses: [&quot;198.17.203.2&quot;], subnetMasks: [&quot;255.255.255.255&quot;])
          settings.ipv4Settings?.includedRoutes = [NEIPv4Route.default()]
          settings.ipv4Settings?.excludedRoutes = []
          settings.dnsSettings = NEDNSSettings(servers: [&quot;8.8.8.8&quot;, &quot;8.8.4.4&quot;])
  
          settings.dnsSettings?.matchDomains = [&quot;&quot;]
          self.setTunnelNetworkSettings(settings) { error in
              if let e = error {
                  NSLog(&quot;Settings error %@&quot;, e.localizedDescription)
              } else {
                  completionHandler(error)
                  self.readPackets()
              }
          }
    ...
  }
  </code></pre>