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
Network Extension
RSS for tagCustomize 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
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 ?
Hi Team,
We are using the above mentioned api by apple to get the securityType of WiFi available and connected, but for all the type of WiFi it is giving that the security type is open even if the Wifi security type is not open.
Can you please help in providing a solution for getting the correct securityType of the available and connected WiFi
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?
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.
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
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?
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.
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!
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.
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?
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?
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!
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
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?
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
Our inhouse app has allowed VPN, and it works fine for most users, however, some users come to this NEVPNErrorDomain Code=5 "permission denied" error and could never start the VPN connection. It happens on
iOS 17.1.2 + iPhone16,2
iOS 17.0.2 + iPhone16,2
Any clue? Thx.
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
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!!
NEHotspotConfigurationManager-(void)applyConfiguration:(NEHotspotConfiguration *)configuration completionHandler:
There was only once to call the applyConfiguration, the completionHandler was never be called. After this, the phone can not connect any other hotspot until restart the phone.
Pls check this issue. Thanks.