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

DNS Proxy shows as "Invalid"
My current goal is to be able to intercept DNS traffic, and log it. To do so I've added a network extension and enabled "DNS Proxy" and "DNS Settings". The NEDNSProxyProvider is currently just exactly what's created for you upon adding it, then I'm trying to add it like so self.manager.localizedDescription = "Example" let proxy = NEDNSProxyProviderProtocol() proxy.providerBundleIdentifier = "software.eskimo.example.Proxy" // the bundle of the proxy extension i added self.manager.providerProtocol = proxy self.manager.isEnabled = true When launching the app I get a nice popup that has me add the configuration but when I go to enable it it shows as "Invalid" next to it.
1
0
306
Sep ’23
Connect On Demand not working as predicted on macOS browsers except Safari
We set below rule for IKEv2 / IPSec / NETunnelProviderManager custom protocols. where trusted domain contains www.whatismyipaddress.com and manually connected to VPN. NEEvaluateConnectionRule *evalConnectionRule = [[NEEvaluateConnectionRule alloc] initWithMatchDomains:self.trustedDomains andAction:NEEvaluateConnectionRuleActionNeverConnect]; NEOnDemandRuleEvaluateConnection *onDemandRule = [NEOnDemandRuleEvaluateConnection new]; onDemandRule.connectionRules = @[ evalConnectionRule ]; [activeRules addObject:onDemandRule]; [NEVPNManager sharedManager].onDemandRules = [evalConnectionRule]; [NEVPNManager sharedManager].onDemandEnabled = YES; [NEVPNManager sharedManager].enabled = YES; [[NEVPNManager sharedManager].connection startVPNTunnelAndReturnError:&connError]; www.whatismyipaddress.com shows correct public IP address and www.whatismyip.com shows correct VPN server address on Safari. Above code snippet working fine on iOS / iPadOS on all bowsers but not on macOS browsers except Safari. Is there something I'm missing here? Are there other settings that we have to configure in our NEVPNManager/NETunnelProviderManager for macOS specifically? We are testing this in macOS Ventura.
1
0
405
Sep ’23
Route not deleted after 'setTunnelNetworkSettings:nil'
We have a packettunnelprovider which we are using for intercepting IP packets. We define includeroutes while setting tunnel using 'setTunnelNetworkSettings'. But later when we want to disable packet interception, we want to do it from packettunnelprovider extension itself by reseting tunnel settings, for which we set 'NETunnelNetworkSettings' to nil in setTunnelNetworkSettings call. This deletes most of the routes added by includeroutes but few are always left out. % ifconfig utun3 utun3: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1300 options=6463<RXCSUM,TXCSUM,TSO4,TSO6,CHANNEL_IO,PARTIAL_CSUM,ZEROINVERT_CSUM> % netstat -rn -f inet | grep utun3 11.99/24 link#25 UCS utun3 269.254 link#25 UCS utun3 192.168.0 link#25 UCS utun3 Code which we use to reset packet tunnel: [g_PacketTunnelProvider setTunnelNetworkSettings:nil completionHandler:^(NSError * _Nullable errorNE) { if (errorNE != nil) { // handle error } else { // handle success } }]; Can you please help in what could be the reason behind it? Note: I am aware that VPN can be disabled from provider app, but I want to handle this in packettunnelprovider extension by resetting 'NETunnelNetworkSettings'.
5
0
678
Sep ’23
NEPacketTunnelProvider sleepWithCompletionHandler: and wake methods are called with high frequency
The documentation explains that the NEPacketTunnelProvider's sleepWithCompletionHandler: and wake methods are called when the device is going to sleep or waking up. The expectation is that the device will enter and remain in a sleep state for some extended period of time. On iOS 17 we're seeing the PacketTunnelProvider receive wake calls almost immediately. Is there a known issue where the PacketTunnelProvider does Not remain in a sleep state? In our logging, we see the PacketTunnelProvider is constantly alternating between sleep/wake states. On iOS 16, these methods are called on an average of 42 seconds apart from each other. In some cases, we do see the device in a sleep state for 2 to 3 minutes. On iOS 17, these methods are called on an average of 6 seconds apart from each other. The device only sleeps for a few seconds and Not for minutes. This will drain the battery. Will the app be charged for battery usage if the OS decides Not to remain in sleep mode? Is there a bug where the an iOS 17 device running a VPN will not stay in sleep mode? Also, we do Not modify the NEVPNProtocol's disconnectOnSleep field. ie Should be defaulting to NO On a device running iOS 16.3.1, with the screen locked and un-plugged from a power source PID 4574: across 9.6 minutes (576 seconds) Connected to Wi-Fi. 10 calls (5 sleep / 5 wake) Avg frequency of 57.6 seconds apart. PID 4581: across 10.3 minutes (616 seconds) Wi-Fi disabled, Connected to Cellular. 22 calls (11 sleep / 11 wake) Avg frequency of 28 seconds apart. PID 4600: across 10.6 minutes (635 seconds) Connected to Wi-Fi. 12 calls (6 sleep / 6 wake) Avg frequency of 52.92 seconds apart. (576 + 616 + 635) = 1827 seconds. (10 + 22 + 12) = 44 calls. 1827 / 44 = 41.52 seconds. On a device running iOS 17.0 (Build 21A5326a), connected to Wi-Fi: PID 14357: across 94.7 minutes (5682 seconds) 1034 calls (517 sleep / 517 wake) Avg frequency of 5.5 seconds apart. PID 14412: across 92.5 minutes (5547 seconds) 508 calls (254 sleep / 254 wake) Avg frequency of 10.9 seconds apart. PID 14721: across 92.5 minutes (5547 seconds) 1248 calls (624 sleep / 624 wake) Avg frequency of 4.4 seconds apart. (5682 + 5547 + 5547) = 16776 seconds. (1034 + 508 + 1248) = 2790 calls. 16776 / 2790 = 6.01 seconds.
1
0
302
Sep ’23
Perform MTLS connection with another device
Hello there! In our team we are looking for a way to connect to an external device to get and send live information through it. We need to do this because our app is required to work on offline environments and we can't expect to have Internet connection. The device that we connect against is a PC that may not have Internet connection as well. Because of that, we decided to implement live updates via WiFi: The PC generates a WiFi access point. The PC launches an internal server in a local IP of that local network. The phone connects to the access point and queries the PC through the server's local IP. Also we wanted to have security for this interaction. So we agreed on doing MTLS on the connection step, so we can both verify that the server is talking to the phone and viceversa. We do this storing p12 on both phone and PC and verifying their identities via certificates that contain those ids. In our phone configuration, we use the NEHotspotConfigurationManager to connect to the PC's network. Then we make sure that we are connected to the WiFi network using NEHotspotNetwork.fetchCurrent. After that, we are using URLSession to connect to the PC's server with the local IP. We are using the SessionDelegate and implement the didReceiveChallenge method. We do it in a very similar way to the one found in this other DevForum thread. Do you think we are following the right approach to this problem? Do you see any potential gaps in this implementation?
1
0
389
Sep ’23
Regarding NEPacketTunnelProvider's NEPacket src ip
We gets NEPacket during packetFlow.readPacketObjects. Each packet contains src ip as packet tunnel utun virtual interface address. for example if packet tunnel utun address is 10.10.10.10, then src ip of every packet is 10.10.10.10. Can we configure packet tunnel in such a way that it gives src ip as ip assigned to system via dhcp/static (primary Ethernet interface en0) instead of 10.10.10.10? I want to do this because tunnel server uses this src ip to perform some business logic. What if we assigns primary Ethernet interface en0 address to packet tunnel utun address?
0
0
459
Sep ’23
Cannot enable content filter - macOS Ventura
I have a content filter hosted as system extension. Once you go through initial approvals for system extension & network filter everything seems fine. But if I navigate to System Settings --> Network --> Filters & disable the network filter, I am not able to enable it back again. It just stays in yellow, it does not go back to green. Reboot does not help, in fact the network extension process does not even get spawned. This is not desirable at all Has anyone ran into this ? Workarounds : Uninstall the app & perform the installation again by approving prompts.
7
0
1.4k
Nov ’23
Porting NetworkExtension packet tunnel VPN to SystemExtension
We're looking at taking a Network Extension VPN implemented as an App Extension, and porting it to a System Extension. We still intend to distribute through the app store as well, but have requests for out-of-store distribution. I remember seeing a thread about this some time back, but I haven't been able to locate it. If someone has a link to that thread please point me that way :-) We have some questions about bundle IDs, APIs, and entitlements, because we're looking to minimize customer disruption. Can we just add the SystemExtension entitlement to the current App ID for the network extension, update the profile, and continue with the same ID, or will we need to define a new ID? What will happen if someone installs the application from a package outside the app store, and then goes to the app store page for the application? Will the App Store recognize that the app is already installed? What about version differences? It looks like our management app can still use sendProviderMessage to communicate with the extension, and that we don't need XPC unless we want to give other applications the ability to talk with the extension. Is this correct? Can a System Extension use the NSWorkspace openURL API? It looks like a System Extension doesn't have the option of writing to a file, because it's not running as a logged in user and doesn't have access to a user's file systems. Is this correct? For certificate-based authentication the SystemExtension needs to be able to access and use a client certificate. Is there a recommended way for the extension to access the client certificate, e.g, if the extension starts without the GUI because of an on-demand VPN configuration? In that case it doesn't seem like it would have keychain access.
3
0
457
Sep ’23
%awdl0 in local and remote name for network system extension
I have a network system extension that sends flow records to my GUI app, and I saw an unusual string (%awdl0) appended to the local and remote IPv6 addresses in flow records from the UniversalControl program on my Intel iMac Pro. fe80::f42d:14ff:fe38:7db7%awdl0 fe80::18d7:9bff:feae:2e32%awdl0 Any idea why the suffix is appended to the IPv6 address and what it means? Here are more details about the event: { "localPort" : "56604", "socketProtocol" : 6, "version" : 0, "programLastComponent" : "UniversalControl", "localName" : "fe80::f42d:14ff:fe38:7db7%awdl0", "time" : 716847716.50096297, "socketType" : 1, "remotePort" : "57968", "socketFamily" : 30, "procInfo" : { "path" : "\/System\/Library\/CoreServices\/UniversalControl.app\/Contents\/MacOS\/UniversalControl", "lastComponent" : "UniversalControl", "teamId" : "", "signingId" : "" }, "timeStr" : "2023-09-19T20:21:56Z", "remoteName" : "fe80::18d7:9bff:feae:2e32%awdl0", "pid" : 667, "webHost" : "", "webUrl" : "" } And here is the flurry of flows reported including their ports:
2
0
1.2k
Sep ’23
Per App VPN Manual Profile
I Found I can use Per App VPN without MDM using Test Per App VPN. I created a profile which contains VPNUUID, PayloadType, VPNTYPE, VPNSubType etc (profile attached & it is created manually ). when I sent profile using air drop to my iPhone (from my Mac). profile appears in settings to install. 2A. after this installation failed with the message: THE VPN SERVICE "VPN" could not be installed. Here is my info.plist of my source app <key>NETestAppMapping</key> <dict> <key>825886EA-BB00-4805-ADD6-1616161616</key> <array> <string>added the app ids for which I want to implement per App VPN like chrome and Firefox bundle identifier</string> </array> </dict> Here is my profile <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>PayloadContent</key> <array> <dict> <key>PayloadUUID</key> <string>E6671FFB-66C2-49F7-AB1B-CD5A0CD5A0</string> <key>PayloadType</key> <string>com.apple.vpn.managed.applayer</string> <key>PayloadIdentifier</key> <string>com.apple.vpn.managed.applayer.388257C2-7902-42B5-BDAE-6E69A441C3A2</string> <key>VPNType</key> <string>VPN</string> <key>VPNSubType</key> <string>Here bundle identifier of my source app Main target</string> <key>UserDefinedName</key> <string>VPN_CONFIG</string> <key>PayloadDescription</key> <string>VPN Configuring</string> <key>PayloadDisplayName</key> <string>VPN_Config</string> <key>PayloadVersion</key> <integer>1</integer> <key>VPNUUID</key> <string>825886EA-BB00-4805-ADD6-1616161616</string> </dict> </array> <key>PayloadDisplayName</key> <string>Name not set</string> <key>PayloadIdentifier</key> <string>Ignored</string> <key>PayloadRemovalDisallowed</key> <false /> <key>PayloadType</key> <string>Configuration</string> <key>PayloadUUID</key> <string>Ignored</string> <key>PayloadVersion</key> <integer>1</integer> </dict> </plist>
3
0
389
Sep ’23
Exporting a Developer ID Network Extension
macOS allows you to independently distribute a Network Extension using Developer ID signing, but with an important wrinkle. This post explains that wrinkle, its affect on Xcode, and how you get around it. If you have questions or comments, put them in a new thread here on DevForums. Tag it with Network Extension so that I see it. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Exporting a Developer ID Network Extension macOS supports a variety of Network Extension (NE) provider types. Starting with macOS 10.15, it’s possible to distribute an app containing NE providers independently, using Developer ID signing. See TN3134 Network Extension provider deployment for the full list of supported provider types. For your NE provider to work when distributed independently, it must: Be packaged as a system extension. Use Developer ID specific entitlements This post is focused on that second point, because it’s common source of confusion. This post assumes that you’re building your app with Xcode; if you’re building your app outside of Xcode, you’ll have to adapt these steps to your build system. Entitlement Matters A Network Extension system extension and its container app must be signed with the Network Extension entitlement (com.apple.developer.networking.networkextension). That entitlement is an array, with a variety of different element values based on the provider type. For example, a standard NE content filter provider must include the content-filter-provider value. There are two groups of these values: the standard ones and the ones with the -systemextension suffix. During development and for App Store distribution, use the appropriate standard value. For independent distribution using Developer ID, use the corresponding value with the -systemextension suffix. For example, a Developer ID signed NE content filter must use content-filter-provider-systemextension instead of content-filter-provider. Xcode Issues Xcode is currently not aware of this requirement. If you build your NE provider container app using Xcode, you might expect to export it for independent distribution using the Direct Distribution workflow in the Xcode organiser. This does not work (r. 108838909). To get around this, manually export your app from your Xcode archive. Before attempting that, there’s a few things to confirm: By default Xcode’s Signing & Capabilities editor uses the standard values for the NE entitlement. Leave them that way. During day-to-day development it’s best to use an Apple Development signing identity [1], and the standard values work with that. Continue to use Build > Archive [2] to create an Xcode archive for your product. The steps below replace the Direct Distribution workflow, and they assume you’re starting with an Xcode archive. [1] Don’t use Developer ID for day-to-day development; see The Care and Feeding of Developer ID for more on that topic. [2] Or, if you’re automating this, the archive action in xcodebuild. Assemble Your Assets Imagine you’re working on a content filter for the Mac called WaffleFilter. You’ve used Xcode to build the app into an Xcode archive: % ls "WaffleFilter.xcarchive/Products/Applications" WaffleFilter.app That app is development signed: % codesign -d -vvv "WaffleFilter.xcarchive/Products/Applications/WaffleFilter.app" … Authority=Apple Development: … … IMPORTANT The steps in this section are based on the much more comprehensive instructions in Creating Distribution-Signed Code for Mac. If anything is unclear, read that post for clarification. To re-sign this app for independent distribution you’ll need three things: A Developer ID application signing identity. This is named Developer ID Application: TTT, where TTT identifies your team. A Developer ID provisioning profile for the app. In this example I’ve called this WaffleFilter_Dev_ID.provisionprofile. A Developer ID provisioning profile for the system extension. In this example I’ve named this WaffleFilter_WFProvider_DevID.provisionprofile. If you’re not sure how to create these things, see Developer Account Help. Re-sign the App To start, make a copy of the app: % ditto "WaffleFilter.xcarchive/Products/Applications/WaffleFilter.app" "WaffleFilter.app" Dump the entitlements of the app and its embedded system extension: % codesign -d --entitlements "WaffleFilter.entitlements" --xml "WaffleFilter.app" % codesign -d --entitlements "WaffleFilter_WFProvider.entitlements" --xml "WaffleFilter.app/Contents/Library/SystemExtensions/com.example.apple-samplecode.WaffleFilter.WFProvider.systemextension" And reformat them to make them more readable: % plutil -convert xml1 "WaffleFilter.entitlements" % plutil -convert xml1 "WaffleFilter_WFProvider.entitlements" Now edit these files to add the -systemextension suffix. The result will look something like this: % cat "WaffleFilter.entitlements" … <dict> … <key>com.apple.developer.networking.networkextension</key> <array> <string>content-filter-provider-systemextension</string> </array> … </dict> </plist> % cat "WaffleFilter_WFProvider.entitlements" … <dict> … <key>com.apple.developer.networking.networkextension</key> <array> <string>content-filter-provider-systemextension</string> </array> … </dict> </plist> Before you re-sign with these entitlements, replace the embedded provisioning profiles with their Developer ID profiles variants: % cp "WaffleFilter_Dev_ID.provisionprofile" "WaffleFilter.app/Contents/embedded.provisionprofile" % cp "WaffleFilter_WFProvider_DevID.provisionprofile" "WaffleFilter.app/Contents/Library/SystemExtensions/com.example.apple-samplecode.WaffleFilter.WFProvider.systemextension/Contents/embedded.provisionprofile" Now re-sign the app and the system extension with their new entitlements, from the inside out: % codesign -s "Developer ID Application" -f --entitlements "WaffleFilter_WFProvider.entitlements" --timestamp -o runtime "WaffleFilter.app/Contents/Library/SystemExtensions/com.example.apple-samplecode.WaffleFilter.WFProvider.systemextension" WaffleFilter.app/Contents/Library/SystemExtensions/com.example.apple-samplecode.WaffleFilter.WFProvider.systemextension: replacing existing signature % codesign -s "Developer ID Application" -f --entitlements "WaffleFilter.entitlements" --timestamp -o runtime "WaffleFilter.app" WaffleFilter.app: replacing existing signature If you have multiple Developer ID Application signing identities, you’ll need to replace Developer ID Application with the name of the specific identity you want to use. IMPORTANT If your app contains other code items, like frameworks or an app extension, re-sign those as well. For advice on how to manually re-sign a more complex app, see Creating Distribution-Signed Code for Mac. And you’re done! Manually Notarise Xcode’s Direct Distribution workflow also deals with notarisation. As you’re not using that workflow, manually notarise your app. For advice on how to do that, see Customizing the notarization workflow. You should also look at Packaging Mac Software for Distribution, which has a bunch of general info about packaging Mac apps.
0
0
810
Sep ’23
Uninstallation of Network Extension fails if version mismatches
I have an app which hosts network extensions(Packet Tunnel, Filter). I am facing uninstallation issue in scenario 2. Uninstall API: OSSystemExtensionRequest.deactivationRequest Scenarion 1: app version 1.0.0.1, extension inside app bundle version 1.0.0.1 Installed extension -> version 1.0.0.1 Uninstallation works fine. Scenarion 2: app version 1.0.0.2, extension inside app bundle version 1.0.0.2 Installed extension -> version 1.0.0.1 Uninstallation fails with below error: deactivation failed for client: /Applications/Remo Security Endpoint Client/ep-client.app/Contents/MacOS/ep-client, error: Error Domain=OSSystemExtensionErrorDomain Code=4 "(null)" Question 1: is this by design or we can do something to make uninstall works in case application upgraded and tries to uninstall previous extension version. Snippet from Apple Doc for API: OSSystemExtensionRequest.deactivationRequest A deactivation request may require a restart before deactivating the extension. If the request succeeds but requires a restart to complete, the extension may still appear operational until the next restart. Question 2: How do we know if restart needed or not?
3
0
526
Sep ’23
Apple TVOS 17 VPN Packet Tunnel error
Thread 4: "*** NSExtensionPrincipalClass PacketTunnel.PacketTunnelProvider must implement at least one public protocol" warning: Module "/Users/username/Library/Developer/Xcode/tvOS DeviceSupport/AppleTV11,1 17.0 (21J354)/Symbols/usr/lib/system/libsystem_kernel.dylib" uses triple "arm64e-apple-tvos17.0.0", which is not compatible with the target triple "arm64-apple-tvos-unknown". Enabling per-module Swift scratch context. I can't run VPN. Same code IOS,MacOS are ok.
5
0
828
Oct ’23
Ask to Buy not working with Network extension
We are working on an app that uses network extension(https://developer.apple.com/documentation/networkextension) with content filter. Our app filters both browser and socket flows. The NEFilterProviderConfiguration has both ‘filterBrowsers’ and ‘filterSockets’ set to true as given below. NEFilterManager.shared().loadFromPreferences { error in if let error { NSLog("Preferences load error: \(error.localizedDescription)") return } let newFilterConfig = NEFilterProviderConfiguration() newFilterConfig.filterBrowsers = true newFilterConfig.filterSockets = true NEFilterManager.shared().providerConfiguration = newFilterConfig //enabling content filter NEFilterManager.shared().isEnabled = true //saving the preference NEFilterManager.shared().saveToPreferences { error in if let error { NSLog("Preference save error: \(error.localizedDescription)") return } } } In the context of Family Sharing, we have established a group comprising one parent and two children, aged 4 and 15, and have enabled the 'Ask to Buy' feature for both children. When attempting to install an app from the App Store on a device linked to one of the child's iCloud accounts, a pop-up appears, guiding us to initiate the app installation request. However, upon initiating the request from the child's device, we expected the app installation notification to appear on the Apple device associated with the parent's iCloud account. Unfortunately, the notification is not received on the parent's device. It's worth noting that app installation request notifications are displayed on the parent's device if we set the 'filterSockets' parameter of the NEFilterProviderConfiguration to false. NEFilterDataProvider All the flows received in the ‘NEFilterDataProvider’ are allowed. override func handleNewFlow(_ flow: NEFilterFlow) -> NEFilterNewFlowVerdict { return .allow() } Child Device details: iPad (8th generation), iPadOS 16.7
5
1
623
Nov ’23
What does macOS promise when it upgrades/downgrade a Network Extension?
[Q] When a Network Extension is being upgraded/downgraded (and the .app Network Extension wrapper accepts it), what does macOS promise when it comes to the order of operations? a) Will the "new" extension be only started when the running one is fully exited? b) Will the "new" extension be started just after the first attempt to exit the running one has been triggered? I have not found any official documentation about this (Apple dev website, quick search of WWDC video transcripts) so far. From what I'm observing, macOS follows case b): there is an attempt to kill/terminate the running extension a watchdog is installed to check whether the extension is still running after x seconds. the system does not wait for the exit to be confirmed before launching the "new" extension. So if there are issues killing/terminating the previously running extension, there can be 2 extensions running at the same time. Until the watchdog leads to a stronger attempt to exit the old extension. [Q] What is the promise regarding the calls to startFilterWithCompletionHandler: and stopFilterWithReason:? Will the XPC message that calls startFilterWithCompletionHandler: be sent only when the previously running extension is fully exited? Or as long as stopFilterWithReason: from the previously running extension did complete, the XPC message will be sent?
0
0
381
Sep ’23
System NetworkExtension and daemons
Hi everybody, I have some questions regarding daemons and system network extensions. I’ve read here (https://developer.apple.com/forums/thread/721674): “System extensions are effectively launchd daemons”. So I have a question, can we launch system extension somehow directly via providing com.example.plist file into Library/LaunchDaemons and loading it? Or, for example, by loading it via SMAppService.daemon(). We need our network extension to run before user session. If above is not possible, and we’ll have a separate daemon, which only purpose is to start network extension, how can we listen to the lifecycle of the network extension? For example (I’ve already made some experiments): we start daemon, it starts NE, we unregister daemon (via SMAppService), but NE still lives. Is it possible to get callback/signal in the daemon, that it was unregistered and shutdown gracefully?
1
0
483
Sep ’23
Sharing settings between processes and users
Hi everybody, what is recommended way to share settings (user defaults or any other way of storing preferences) between different processes with different ownership? For example we have a UI app, which runs from user, daemon and system extension which both run from root. How can we do some configuration on user level and read it in daemon/system extension safely, without providing some exploits. Bonus: how to observe changes in this scenario?
1
0
359
Sep ’23