Network Extension

RSS for tag

Customize and extend the core networking features of iOS, iPad OS, and macOS using Network Extension.

Posts under Network Extension tag

200 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

Personal VPN install error
We have an app that among other things installs a Personal VPN. This has been working fine for many years but recently we have gotten reports from customers that they are getting an error when installing the VPN. This has only started happening on iOS/iPadOS 17. I hadn't been able to reproduce the issue myself until I tried on an iPad with iPadOS 17.1.1 installed and this actually ties in with one of the customer reports. When I get the error I see the following: Xcode debug console: Updating selectors after delegate addition failed with: Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service with pid 90 named com.apple.commcenter.coretelephony.xpc was invalidated from this process." UserInfo={NSDebugDescription=The connection to service with pid 90 named com.apple.commcenter.coretelephony.xpc was invalidated from this process.} Failed to save configuration [App Name]: Error Domain=NEConfigurationErrorDomain Code=10 "permission denied" UserInfo={NSLocalizedDescription=permission denied} Failed to save configuration: Error Domain=NEVPNErrorDomain Code=5 "permission denied" UserInfo={NSLocalizedDescription=permission denied} Mac Console: Saving configuration [App Name] with existing signature (null) Failed to save configuration [App Name]: Error Domain=NEConfigurationErrorDomain Code=10 "permission denied" UserInfo={NSLocalizedDescription=permission denied} Failed to save configuration: Error Domain=NEVPNErrorDomain Code=5 "permission denied" UserInfo={NSLocalizedDescription=permission denied} When the error occurs you don't even see the system prompt to allow the VPN be installed. We are using the code below to save the configuration and as stated it fails when trying saveToPreferences without ever showing the prompt private func setup(with vpnProtocol: NEVPNProtocol, rules: [NEOnDemandRule], completion: @escaping VPNConfigurationCompletionHandler) { let setupBlock: (NEVPNManager) -> () = {manager in manager.isEnabled = true manager.isOnDemandEnabled = true manager.localizedDescription = L("app.vpn.description") manager.protocolConfiguration = vpnProtocol manager.onDemandRules = rules manager.saveToPreferences { (error) in completion(self.extractErrorCode(from: error)) } } vpnManager.loadFromPreferences { (error) in if error == nil { setupBlock(self.vpnManager) } else { completion(.generalFailure) } } } Any suggestions as to what may be going wrong? Thanks Alan
2
0
600
Nov ’23
The custom port for the URL of a DNS-over-HTTPS server has no effect.
According to the document serverURL, the serverURL compliant RFC8484, which is based on RFC6570, which is based on RFC3986. According to the Section-3.2.3 of RFC3986, the URL should support the optional port number in decimal 3.2.3. Port The port subcomponent of authority is designated by an optional port number in decimal following the host and delimited from it by a single colon (":") character. port = *DIGIT A scheme may define a default port. For example, the "http" scheme defines a default port of "80", corresponding to its reserved TCP port number. The type of port designated by the port number (e.g., TCP, UDP, SCTP) is defined by the URI scheme. URI producers and normalizers should omit the port component and its ":" delimiter if port is empty or if its value would be the same as that of the scheme's default. But I found that iOS ignores the :port specified in the serverURL and always connect to the port 443. Is this intended or a bug ?
1
0
249
Nov ’23
Capturing ipv6 traffic with AppProxyProvider on MacOS
I have implemented an AppProxyProvider (NETransparentProxyProvider) and I am able to capture traffic with it. I am also able to define network rules allowing me to exclude some traffic: let settings = NETransparentProxyNetworkSettings(tunnelRemoteAddress: "127.0.0.1:8080") settings.includedNetworkRules = [ NENetworkRule(remoteNetwork: NWHostEndpoint(hostname: "0.0.0.0", port: "0", remotePrefix: 0, localNetwork: nil, localPrefix: 0, protocol: .TCP, direction: .outbound) ] Now the documentation states that if I want to capture localhost traffic, I need to explicitly add the following rule: NENetworkRule(remoteNetwork: NWHostEndpoint(hostname: "127.0.0.0", port: "0", remotePrefix: 8, localNetwork: nil, localPrefix: 0, protocol: .TCP, direction: .outbound) and if I want to capture ipv6 localhost address: NENetworkRule(remoteNetwork: NWHostEndpoint(hostname: "::1", port: "0", remotePrefix: 128, localNetwork: nil, localPrefix: 0, protocol: .TCP, direction: .outbound) All this works great. Now I am having trouble capturing external ipv6 traffic. For example my ISP supports ipv6 and facebook.com resolves to 2a03:2880:f128:181:face:b00c:0:25de on my machine. I am unable to write any rule allowing me to capture with the system extension such traffic. Either I get errors that the network mask cannot be greater than 32 or the traffic simply doesn't flow through the extension. Here's an example request that I would like to capture: curl https://facebook.com -kvp * Trying [2a03:2880:f128:181:face:b00c:0:25de]:443... * Connected to facebook.com (2a03:2880:f128:181:face:b00c:0:25de) port 443 (#0) * ALPN: offers h2,http/1.1 * (304) (OUT), TLS handshake, Client hello (1): * (304) (IN), TLS handshake, Server hello (2): * (304) (IN), TLS handshake, Unknown (8): * (304) (IN), TLS handshake, Certificate (11): * (304) (IN), TLS handshake, CERT verify (15): * (304) (IN), TLS handshake, Finished (20): * (304) (OUT), TLS handshake, Finished (20): * SSL connection using TLSv1.3 / AEAD-CHACHA20-POLY1305-SHA256 * ALPN: server accepted h2 * Server certificate: * subject: C=US; ST=California; L=Menlo Park; O=Meta Platforms, Inc.; CN=*.facebook.com * start date: Aug 26 00:00:00 2023 GMT * expire date: Nov 24 23:59:59 2023 GMT * issuer: C=US; O=DigiCert Inc; OU=www.digicert.com; CN=DigiCert SHA2 High Assurance Server CA * SSL certificate verify ok. * using HTTP/2 * h2 [:method: GET] * h2 [:scheme: https] * h2 [:authority: facebook.com] * h2 [:path: /] * h2 [user-agent: curl/8.1.2] * h2 [accept: */*] * Using Stream ID: 1 (easy handle 0x7fcb5c011e00) > GET / HTTP/2 > Host: facebook.com > User-Agent: curl/8.1.2 > Accept: */* > < HTTP/2 301 < location: https://www.facebook.com/ < strict-transport-security: max-age=15552000; preload < content-type: text/html; charset="utf-8" < x-fb-debug: uWVEw8FZUIXozHae5VgKvIDY5lgH/4Aph+h+nJNJpIr7jFZIFGy9LRLGCSwPudcFBdi4Mf4rLaKsNGCBxHDmrA== < content-length: 0 < date: Fri, 17 Nov 2023 14:14:03 GMT < alt-svc: h3=":443"; ma=86400 < * Connection #0 to host facebook.com left intact Can this be achieved?
3
0
487
Nov ’23
NEFilterPacketProvider severely reduces bandwidth
Hello everyone, I'm currently developing a firewall using a network extension that employs two methods: NEFilterDataProvider, which specifically filters UDP and TCP connections, and NEFilterPacketProvider, designed to filter all packets. However, I've noticed that utilizing NEFilterPacketProvider results in a 50% reduction in bandwidth compared to when it's not in use. Within my packetHandler closure, I'm only returning 'allow.' I suspect this slowdown might be due to the packet data cache being passed to my extension, with only one active thread available to handle it. I'm wondering if there's a way to adjust the size of the packet buffer, increase the number of threads dedicated to processing packets, or configure specific rules to mitigate this issue. Thank you.
1
0
278
Nov ’23
After stopping the tunnel, the included routes for the PacketTunnelProvider are not being cleared/removed
We have a PakcetTunnelProvider in SystemExtension with split tunnelling. We are setting up a private range of IP address (240.0.0.1/10) as include routes and a few match domains using NEPacketTunnelNetworkSettings. Everything works fine. We are able to setup tunnel settings and receive DNS as well as data traffic as per our rules. However, when we execute the netstat -rn -f inet command in Terminal, it shows the following output: 240.0.0/10 link#8 UCS utun0 240.0.0.1 10.211.55.1 UGHS en0 240.0.0.2 10.211.55.1 UGHS en0 240.0.0.3 link#8 UHWIi utun0 After stopping the tunnel, some stale entries remain in the route table, as evidenced by the output of netstat -rn -f inet: 240.0.0/10 link#8 UCS utun0 240.0.0.3 link#8 UHWIi utun0 The expected behavior is that included routes should automatically clear once the tunnel stops. ** It's noteworthy that we've only observed this behaviour on Monterey OS; ** it works as expected on Ventura and Sonoma (where routes are automatically removed upon tunnel cessation) We have tried to set the tunnel settings to nil explicitly, but no luck. setTunnelNetworkSettings(nil) { _ in} We're unsure why the routes aren't clearing properly on Monterey OS. Thanks - Happy questioning
1
0
290
Nov ’23
Captive Portal not working on LAN
We have a tool that provides internet access via WLAN or LAN. For the captive portal we do send the DHCP option 114 with the captive portal URL. DHCP Option: 114 (Captive-Portal) Length: 38 Value: https://example.org/captive-portal/api This all works fine on WLAN for iOS and MacOS. But on MacOS on LAN it does not. When doing a packet capture on MacOS with Wireshark we see that the Option 114 DHCP Captive-Portal is recieved by the Mac but it does not open the captive portal window. When Safari is forced to a HTTP site then the Portal page is shown. How can this be solved?
0
0
268
Nov ’23
Returning NEPacketTunnelProvider packetFlow.readPacketObjects packets to macOS kernel
Can we return NEPacketTunnelProvider's NEPacket to macOS kernel? Snippet- packetFlow.readPacketObjects {[weak self] packets in As per network rules, packets read from packetFlow. After parsing packets, in some conditional use cases(such as ip), if we decide not to handle the packets, could we return it to kernel? We can easily achieve it in NETransparentProxyProvider by returning false from below method. We are looking for similar mechanisms to do return the traffic to Kernel. override func handleNewFlow(_ flow: NEAppProxyFlow) -> Bool May we achieve the same with any other Network.framework or low level API? If any advance Code-level support could solve this issue, we could raise a TSI as well.
1
0
311
Nov ’23
Local Push Connectivity API - Got 'Provisioning profile failed qualification' while distributing an app to the store
I have an app which uses the Local Push Connectivity API. I have requested and received the entitlement and everything is working in dev-mode, but once I try to distribute the app to the AppStore I got the following error: Provisioning profile failed qualification Profile doesn't match the entitlements file's value for the com.apple.developer.networking.networkextension entitlement. I was wondering if I need an other entitlement for this, mine is called Local Push Provider iOS Dev which makes me feel like there should be a Store counterpart - but I did not see how to request it on the Entitlement Request Page. Thanks for any hints!
10
0
678
Dec ’23
Network Extension Location Header Redirect | iOS
Hi, I am wondering if there is a way to get the redirection URL caused by a "Location" header? A typical example would be when opening an image link from Google Images for Instagram. I cannot post the Google url here as it is not permitted, however if you search "Mr ***** Instagram" on Google Images then open an Instagram link from there it will occur. I have implemented both the NEFilterDataProvider and NEFilterControlProvider handleNewFlow methods which trigger on the initial request where I get the Google url (full url in the DataProvider and Host and Path in the ControlProvider) so this is working as expected for both Providers. However, this does not trigger when the redirect happens. Which I have seemed to trace back to the location header being returned from Google which then redirects to Instagram.
1
0
215
Dec ’23
Lost network after updating to macOS 14.1.2, System Extension issues
Today, I applied the latest security patch to my Mac Studio, and on reboot, I had no networking. It appears to have been a system extension issue. At one point, I needed to "Allow" Apple system software in System Settings. I found that strange. I thought I'd document the issue and my resolution in case someone else runs into this. (1) I did the usual - reboot, shutdown & restart, reboot my Eero mesh; changed from Wi-Fi to wired Ethernet. Nothing worked. (2) I do have my own application that uses a network system extension, so I went through the system extension uninstall process (using the API). Still no joy. I then tried to reinstall the network extensions, but that didn't seem to work. I was never prompted to open the System Settings app. I think the network system extension had not actually been removed. I deleted the app (which should remove the network system extension). Still no joy. Interestingly, launchctl still showed a crashed network system extension (no PID, status -9) (3) I then disabled SIP, rebooted, and used systemextensionsctl to remove the network system extension. While doing this, I discovered an old network system extension from several years ago tied to one of my old organizations and may have been built for Intel CPU. I deleted that too. (If I had to guess, it might have been that old network system extension that caused the problem.) Reenabled SIP Rebooted. (4) At some point I got an interesting alert from Apple about System Extension errors. And when I opened System Settings, I had to allow an extension from Apple?! (5) Networking is now working. I reinstalled my application from TestFlight, installed the network system extension, and everything is still working. (6) Summary I lost networking after applying the security update. Worried that it might be my program, I tried uninstalling the network system extension, but I could not cleanly uninstall and reinstall my network system extension as I've done many times before. I found an old network system extension; deleted both network system extensions with SIP disabled. I had to Allow Apple software. Everything works (including my app with its network system extension installed). I am not sure what the root cause was. My old network system extension? The fact I needed to Allow Apple software? My current app and its network system extension?
1
0
838
Dec ’23
network system extension + Safari 17.1.2 BREAKS protocol stack
Someone else may want to test this with their network system extension, but I found a nasty interaction with Apple's latest software update for Safari and my network system extension. Summary: When I had my network system extension installed and updated to Safari 17.1.2, all networking was lost. I first ran into this problem yesterday and documented in this thread. Today, I tried to pin it down on Ventura. This test Hardware: M1 Mac mini OS: macOS Ventura 13.6.1 (downloaded from Mac App Store) Safari version 16.6 Network system extension (mine) When I updated to Safari Version 17.1.2, I lost all networking! Furthermore, I could not uninstall my network extension. Deleting the app with the network system extension didn't help. Fix 1: Disabled SIP Removed my network system extension (at which point networking worked fine again) Reenabled SIP Reinstalled my network system extension Everything works fine. Fix 2 I re-ran the experiment (same initial set up) Hardware: M1 Mac mini OS: macOS Ventura 13.6.1 (downloaded from Mac App Store) Safari version 16.6 Network system extension (mine) This time: I removed my network system extension first I updated to Safari 17.1.2 (this time no problems) I reinstalled my network system extension Everything works fine Having the network system extension in place and then updating Safari to 17.1.2 broke things pretty badly for me. Was there something I did wrong with my network system extension design?
3
0
658
Dec ’23
Connecting to only one SSID when the network has multiple BSSIDs
Hi there! I’m developing an iOS app which requires the user to connect to a Wi-Fi network broadcasted from a device. The problem arises when multiple devices are in the phone’s vicinity, as they all have the same SSID, and the phone randomly switches from one device to another; I need the phone to “fixate” on a single device. Of course, the devices’ MAC addresses/BSSIDs are unique, so I thought I could use that information to differentiate between them and programmatically choose to connect to a single network. Is there any way I can obtain the BSSIDs of the available networks, and, within the app’s context, connect to a single one of them? Is there another way for the phone to “fixate” on a single BSSID that I might have missed? It would be ideal for the solution not to require changing the device's firmware. Moreover, the device has to be able to connect to other non-Apple devices. Thanks in advance!
5
0
376
Dec ’23
SimpleFirewall example is not working
I download https://developer.apple.com/documentation/networkextension/filtering_network_traffic example Build OK and I saw extension loaded. NEProvider.startSystemExtensionMode() was called. But FilterDataProvider init did not called. I tried to disable SIP also. it does not work I saw some warning like /Applications/SimpleFirewall.app/Contents/Library/SystemExtensions/com.example.apple-samplecode.SimpleFirewallML4HRHFY98.SimpleFirewallExtension.systemextension: entitlement com.apple.developer.endpoint-security.client not present or not true
6
0
451
Dec ’23
[macOS] need to support domain specific dns server (custom DNS)
Hi Team, I'm currently using a system extension with NETransparentProxyProvider (with root privileges). I want to support custom DNS (specific to domains) with a search domain to accommodate a single-level domain support. For this, I'm creating a new entry inside /etc/resolver/, using below command. sudo sh -c 'echo "domain corp.test.com\nsearch corp.test.com\nnameserver 9.9.9.9\nnameserver 9.9.2.2" > /etc/resolver/corp.test.com' The above command works fine for me when I execute it via the terminal, creating a new file inside the resolver as described below. So, when I access a single-label domain like https://test, it appends 'corp.test.com,' resulting in hitting the domain as https://test.corp.test.com. Furthermore, it selects either the DNS server 9.9.9.9 or 9.9.2.2. File: /private/etc/resolver/corp.test.com domain corp.test.com search corp.test.com nameserver 9.9.9.9 nameserver 9.9.2.2 File permission total 8 -rw-r--r-- 1 root wheel 80 Dec 5 18:20 corp.test.com scutil --dns resolver #8 domain : corp.test.com search domain[0] : corp.test.com nameserver[0] : 9.9.9.9 nameserver[1] : 9.9.2.2 flags : Request A records, Request AAAA records reach : 0x00000002 (Reachable) However, when I execute the same command within the extension using NSTask, it generates the new file but fails to work as per above. it creates below file File: /private/etc/resolver/corp.test.com domain corp.test.com search corp.test.com nameserver 9.9.9.9 nameserver 9.9.2.2 File permission total 8 -rw-r--r-- 1 root wheel 80 Dec 5 18:25 corp.test.com scutil --dns resolver #8 domain : corp.test.com search domain[0] : corp.test.com nameserver[0] : 9.9.9.9 nameserver[1] : 9.9.2.2 flags : Request A records, Request AAAA records reach : 0x00000002 (Reachable) I don't notice any difference in file permissions and in scutil --dns entry. even we tried running sudo killall -HUP mDNSResponder to refresh its records. Could you please suggest what might be the reason?
11
0
1.2k
Dec ’23
NEFilterDataProvider not receiving all traffic
I have implemented the NEFilterDataProvider with the handleNewFlow method and it seems to be working for the most part, but there are some requests (which I can see with Proxyman) that aren't going through the filter. Is there a way to fix this? Would a slow response to one flow cause another flow to bypass the filter? Can multiple flows call handleNewFlow simultaneously or is it all run on a single thread? Thanks
3
0
361
Dec ’23
How to multiplex possibly thousands of NEAppProxyFlows ?
Hi, I am writing a transparent proxy (using NETransparentProxyProvider) which could potentially multiplex thousands of flows. When i've done this in the past on other platforms i've used libev or epoll - but NEAppProxyFlow (such as NEAppProxyTcpFlow) don't work with any of those approaches afaict, it doesn't even appear to work with swift-nio - what is the recommended way to multiplex thousands of flows? I still intend to use swift-nio when i manage the real sockets (which proxy the flows), but how do i multiplex the NEAppProxyFlows themselves? Can someone suggest a highly scalable design? I'm new to this, and haven't found a good solution yet. Thanks
3
1
491
Dec ’23
Manage multiple NEAppProxyFlow(s)
Hello! I am using a NETransparentProxy and I need to manage multiple NEAppProxyFlow. I am dealing with hundreds / thousands connections, so the one-thread-per-connection approach is really not feasible. Regarding raw bsd sockets, I know multiple ways of achieving good results when managing a large number of sockets using: poll() kqueue SwiftNIO library but I am struggling to find a way to do something similar with flows. My current "solution" is to create a new Task.detached for each new connection and have this Task 'block' on readData / readDatagrams. It works for low numbers of connections but it does not scale well when the number of connections increases. Is there a way to achieve a similar result as poll() for sockets for flows? Otherwise, is there a way to make my current solution work? (even though I don't think it is able to scale well) I can provide more details about the architecture if needed, or code snippets. Thank you!!
4
2
348
Dec ’23