Networking

RSS for tag

Explore the networking protocols and technologies used by the device to connect to Wi-Fi networks, Bluetooth devices, and cellular data services.

Networking Documentation

Post

Replies

Boosts

Views

Activity

Content Filter Providers in unsupervised and unmanaged iOS devices
I'm looking at implementing an iOS app that has includes a Content Filter Provider to block access to certain domains when accessed on the device. This uses NEFilterManager, NEFilterDataProvider and NEFilterControlProvider to handle configuration and manage the network flows and block as necessary. My question is can you deploy this in an iOS 18+ app on the App Store to devices which are unmanaged, unsupervised and don't use Screen Time APIs? Although not 100% clear, this technote seems to say it is not possible: https://developer.apple.com/documentation/Technotes/tn3134-network-extension-provider-deployment Testing this on a Developer device and build works successfully without any MDM profiles installed. A similar approach using the same APIs also works on macOS once user permissions have been given. If it can't work on unsupervised, unmanaged iOS devices, is possible for the user to first manually install a MDM profile which includes the required 'Content Filter' details and then have it work? If not, how would you filter iOS network traffic on an unmanaged, unsupervised device? Is it necessary to use a VPN or DNS approach instead (which may be a lot less privacy compliant)?
4
0
156
1d
Issue with app not waking up intermittently due to Pushkit (VOIP)
I am developing a VoIP service. Usually, when receiving a VoIP Push, Callkit is exposed immediately after receiving the message and the app is designed to be used. However, there is an extremely intermittent phenomenon (not well reproduced) where the app does not wake up even when receiving a VoIP Push. And after a long time, the app wakes up and Callkit is activated. (A long time after receiving the call…) Has anyone experienced the above phenomenon? I wonder if there are any reported parts depending on the OS version. (I have identified that it does not occur in the 17.x version, but it is difficult to guarantee because it occurs extremely intermittently) The app is not running in the background, but... Could this be happening if there are a lot of pending operations in the background? I need help urgently
3
0
80
1d
Can NETunnelProviderManager.protocolConfiguration be changed on the fly?
I am learning about layer 3 VPN implementations for MacOS, and am slowly making my way through docs and tutorials. I noticed that part of creating an instance of NETunnelProviderManager on the app side of the project requires the specification of protocolConfiguration via an instance of NETunnelProviderProtocol. One of the arguments for this class is serverAdress, which to my understanding, tells the OS where to route traffic towards at the end of the day. My question: many VPNs these days allow the option to specify the location for which you want your traffic to be routed through. I imagine this would necessitate changing this serverAddress field in the backend. However, setting this option (on a commercially available VPN) doesn't typically prompt the OS notification that you get when initially installing a VPN configuration for the first time. How is this functionality achieved? I could see one possible solution being that most VPN providers route through a main service beforehand (so the first IP in the chain never has to change), though I could see this being problematic for a number of other reasons. Assuming you have a valid NETunnelProviderManager object called manager, is this valid? self.manager?.protocolConfiguration?.serverAddress = "somewhereElse" Even if it compiles, will the traffic be properly re-routed? My understanding of the flow right now is that in order to "lock in" a new configuration, or modify it, you need to call manager.saveToPreferences, which triggers the OS notification I mentioned earlier.
1
0
141
2d
[networkextesion] dnsproxy
hello I am testing the use of network extension. When we use dnsproxy to proxy DNS requests, we will send you a message that the udp pcbcount of your system continues to increase. For example for ((i=1; i<=99999; i++));do echo "Attempt $i:" dig google.com done when the dig command is used continuously, the dig command will show the following errors when pcbcount reaches a certain number. isc_socket_bind: address not available Can you help us determine what the problem might be? thank you
1
0
75
4d
Best Way To Determine If Host Is Not Reachable in NWConnection
I have an app that is communicating with a non-HTTP server over TCP/IP. Most everything is working, but I was testing some error conditions and the first one I tried was turning the server off and then trying to send it a message. I'm using code that uses NWConnection and involves an async method that includes a withCheckedContinuation. Inside this code are checks for errors in the closures, etc. You've seen the example code posted here in the forums. But none of the error code ever gets invoked. I also have a state handler to check the state of the TCP connection. What I see when I send the request is: connection goes to .preparing state nothing happens for about 45 seconds I then get two errors: inline-code nw_endpoint_flow_failed_with_error [C4.1.1 192.168.86.44:3040 in_progress channel-flow (satisfied (Path is satisfied), viable, interface: en0[802.11], ipv4, dns, uses wifi)] already failing, returning inline-code nw_endpoint_flow_failed_with_error [C4.1.1 192.168.86.44:3040 cancelled channel-flow ((null))] already failing, returning then the connection state goes to .waiting and nothing else happens. I would really like to capture the errors I see in the Xcode console, but I don't know how to catch them. Anyone have any ideas? Is there a better way to send the first message (or a ping or whatever) to a non-HTTP server and see if it is there? Thanks, Robert
3
0
126
5d
macOS 15.3 Local Network Permission regressions
Hi folks, I would like to ask for clarification regarding Local Network Policy. I found 2 cases where I think the behaviour differs from the documentation. 1. Use case In a CI environment, we have multiple services (LaunchAgents) which require Local Network Access. We are fine by manually approving the Local Network Permission once (per service), but we also require these services to be able to self-update. Self update results in downloading the a binary with an (obviously) different UUID, which seems to result in re-triggering the Local Network Consent prompt. Strange thing: If I don't click either buttons (Allow of Reject), just restart macOS, it will result in an enabled entry in Privacy &amp; Security &gt; Local Network. I read a reply somewhere on this forum by an Apple engineer that the approval process is a mix of Bundle ID + UUID + other components, so I would expect a new binary with the same properties (but different UUID) to be already whitelisted. Is this behaviour intended? 2. Use Case Given the first issue, I decided to do this in the "right way". I was happy to read this sentence in the documentation: If you ship a launchd agent that’s not installed using SMAppService, make macOS aware of the responsible code by setting the AssociatedBundleIdentifiers property in your launchd property list. I have a properly setup (and code signed) Application, for which I have enabled Local Network permission in Privacy &amp; Security. I have a standalone LaunchAgent, which runs a long running binary from a user directory. The agent is managed with launchd, and in this sense it is "independent" from the main Application Bundle. I have setup AssociatedBundleIdentifiers in the Agent plist, to associate it with the Application. The TeamIdentifier of the 2 binaries are the same. Based on the documentation, this should be enough for my agent to signal macOS that the responsible code is the Application Bundle (which is already enabled from Local Network POV). Instead, once the LaunchAgent starts, the Local Network Consent popup appears for the binary. I would expect the Application to be the responsible code, thus no more Consent popup. Is this behaviour intended? I need this service to run as user, so I cannot just circumvent the Consent popup by running as a Daemon or Root. Nor I would like to manage the Agent with ServiceManagement. What do you guys think, have I misunderstood the documentation?
4
10
365
2w
Multiple PushProviders Instantiated at one time
I have an issue that causes multiple instances of the push provider to be initialized. And I'd like to ask you what could trigger the instantiation NEAppPushProvider subclass. It seems like it's being triggered excessively. If there's documentation that I have overlooked then just show it to me and I'll be on my way. Here's the details. But really all I want to know is why is my subclass for NEAppPushProvider keeps getting initialized. If you can answer me that than maybe all these details don't really matter but here they are. Here's why I believe there's multiple push provider. I see logs for my push provider initializing but I don't see it de-initializing. I also see redundant logs showing multiple instances trying to log into my server. Each time it initializes, an additional log is added for trying to log into my server. In the app, the system saves it's configuration shortly after initialization, after saving and loading the push configuration, the app doesn't touch config. Meanwhile in the extension, after 8 or so hours, the extension starts creating a new instance of the push provider. Then a few hours later it does it again. And again. Until the watch dog kills us for wasting too much CPU. Normally on a fresh install, I'll observe turning off the wifi to call stop on the push provider and later have the push provider de-initialize. The extension maintains a socket connection to the server, the server can send it messages to display push notifications. The software runs on hospital networks, which will not have access to the internet. It seems like the connection to the server is stable from the logs. I don't detect any disconnections. I'll check with the server to confirm. In the app I call removeFromPreferences to clear out any extensions before logging in/saving push configurations. And I call saveToPreferences on the NEAppPushManager. I do this to make sure I don't have more than one push configuration saved at one time. I also have many logs looking out for this. I used the sample code from apple as the basis of the my own Push Manager. I can post code if you deem it necessary. Hope to here from you soon. Thank you.
9
0
290
3w
OAuth login from NEPacketTunnelProvider
How can NEPacketTunnelProvider launch the companion application, or notify user to launch the application? I have built an iOS VPN that uses credentials stored in the keychain, and it works as expected. Now I'm trying to add OAuth login support. Everything works fine at first. I login from the companion application, store tokens in the keychain, then launch the VPN from either System Settings or the companion application. However, when the OAuth refresh tokens expire, or the OAuth IdP otherwise requires login, I can't perform the OAuth login from the NEPacketTunnelProvider. Login must happen from the companion application, which likely isn't running. I need the NEPacketTunnelProvider to either launch the companion application directly or to notify the user to do so. Searching and reading docs yields: You can't perform OAuth login from within the NEPacketTunnelProvider because it requires user interaction There is no way to guarantee that the companion application is running on iOS (otherwise one would use NEVPNStatusDidChange) You can't launch the companion application from NEPacketTunnelProvider using a custom URL because of security concerns You might be able to launch the companion application from a system extension... Some sources say you still can't guarantee that the system extension is loaded whenever the NEPacketTunnelProvider needs it anyway. Of course, any of these conclusions could be wrong. At this point I'm not sure where to begin. Is there another approach that could be initiated by the NEPacketTunnelProvider (push notifications, system notifications, smoke signals)? Any help would be appreciated. Thanks, Bill Welch
1
0
126
5d
Download speed Issue with Per-App VPN Using WireGuard Protocol
DESCRIPTION OF PROBLEM We have developed an app and server based on the WireGuard protocol. While we have successfully implemented device-wide VPN, we are now working on enabling per-app VPN functionality. The per-app VPN payload is successfully delivered, and the designated app can read the configuration and establish a connection to the VPN server. However, we are experiencing extremely slow download data rates, measuring only in bytes. Steps Taken: Created an app-layer payload. Configured NETestAppMapping in the app’s Info.plist, using the VPNUUID defined in the payload for the Chrome app. Despite these configurations, data transfer remains significantly slow. We would appreciate any insights into potential causes or recommendations to resolve this performance issue. Thank you for your assistance.
3
0
208
6d
Controlling the number of Pending Send Completions using NWConnection
Context: We are using NWConnection for UDP and TCP Connections, and wanted to know the best way to keep the number of pending send completions in control to limit resource usage Questions: Is there a way to control the send rate, such that too many 'send pending completion' does not get queued. Say if I do a ‘extremely dense flurry of 10 million NWConnection.send’ will all go asynchronous without any complications? Or I would be informed once it reaches some threshold. Or no? And is it the responsibility of the application using NWConnection.send to limit the outstanding completion , as if they were beyond a certain limit, it would have an impact on outstanding and subsequent requests? If so – how would one know ‘what is supposed to be the limit’ at runtime? Is this a process level or system level limit. Will errors like EAGAIN and ETIMEOUT ever will be reported. In the test I simulated, where the TCP Server was made to not do receive, causing the 'socket send buffer' to become full on the sender side. On the sender side my send stopped getting complete, and became pending. Millions of sends were pending for long duration, hence wanted to know if we will ever get EAGAIN or ETIMEOUT.
21
0
546
4w
Unable to use CoreWLAN under root permission
I am working on developing a client to complete 8021.x wireless authentication by python. According to the CoreWLAN Documentation scanForNetworks(withName:), I'm going to use scanForNetworksWithName_error_ and associateToEnterpriseNetwork_identity_username_password_error_ provided in CoreWLAN. And I wrote a script to have a try. import os import pwd from CoreWLAN import CWWiFiClient from Foundation import NSString def get_real_user(): sudo_user = os.environ.get('SUDO_USER') if sudo_user: return sudo_user return os.environ.get('USER', 'root') def run_as_user(username): if os.geteuid() == 0: uid = pwd.getpwnam(username).pw_uid gid = pwd.getpwnam(username).pw_gid os.setuid(uid) def connect_to_enterprise_network(ssid, username, password): try: real_user = get_real_user() if os.geteuid() == 0: run_as_user(real_user) client = CWWiFiClient.sharedWiFiClient() interface = client.interface() if not interface: print("no interface") return False print("scaning...") error = None scan_result, error = interface.scanForNetworksWithName_error_(ssid, None) if error: print(f"scan fialed: {error.localizedDescription()}") return False target_network = None for network in scan_result.allObjects(): if network.ssid() == ssid: target_network = network break if not target_network: print("no target network") return False success, error = interface.associateToEnterpriseNetwork_identity_username_password_error_( target_network, None, NSString.stringWithString_(username), NSString.stringWithString_(password), None ) if not success: print(f"connect failed: {error.localizedDescription() if error else 'unknown error'}") return False print("connect successfully") return True except Exception as e: print(f"exception: {str(e)}") return False if __name__ == "__main__": ssid = "ssid" username = "username" password = "password" success = connect_to_enterprise_network(ssid, username, password) However, I can only execute this script normally under non-root permissions. When I switch to root and execute it, the variable "scan_result.allObjects()" will be an object without any ssid and bssid. Finally the function prints "no target network" and returned. &lt;CWNetwork: 0x107104080&gt; [ssid=(null), bssid=(null), security=WPA2 Enterprise, rssi=-52, channel=&lt;CWChannel: 0x11e8a1fd0&gt; [channelNumber=44(5GHz), channelWidth={20MHz}], ibss=0] Compared with the value without sudo: [&lt;CWNetwork: 0x144650580&gt; [ssid=ssid, bssid=&lt;redacted&gt;, security=WPA2 Enterprise, rssi=-55, channel=&lt;CWChannel: 0x1247040d0&gt; [channelNumber=149(5GHz), channelWidth={20MHz}], ibss=0]] My python code will be included in an app that must be executed as a root user, so this issue can't be ignored and waiting for your help. THANKS!
2
0
168
6d
CentralManager won't connect to device for watchOS, but will for iOS?
Hi there, I'm having an issue hoping someone could help. We have an iOS app that uses CoreBluetooth to connect to peripherals using the central manager. The app works great - However, when using the same exact central manager for our watchos app, it will attempt to connect, but I never get a callback for either didConnect or didFailToConnect. The watch can connect successfully to other BLE devices, so the watch itself is capable of BLE connectivity. Here's a list of thing's I've tried (unsuccessfully): 1) Added every bluetooth-related entitlement to info.plist Privacy - Bluetooth Always Usage Description Privacy - Bluetooth Peripheral Usage Description Background Modes: App communicates using CoreBluetooth, App shares data using CoreBluetooth 2) Checked for Single-Connection Limits Verified that the iPhone was fully disconnected from the peripheral to ensure the device wasn’t limited to one connection. Attempted to connect on watchOS alone (with iPhone turned off) 3) Tried various options for CBCentralManager, scanForPeripherals, and connect I went through all the keys for various options and tried just setting them, they had no effect CBCentralManagerOptionShowPowerAlertKey, CBConnectPeripheralOptionEnableTransportBridgingKey Item 2 4) Tried .registerForConnectionEvents() 5) Set peripheral's delegate to the central in the didDiscover, stored it in a variable to ensure a strong reference to it I get no warnings either. The last time I ran into something like this, I found out the watchOS blocks TCP sockets. If I print out the CBPeripheralState a few seconds after trying to connect, it shows its stuck on CBPeripheralStateConnecting. Any advice or direction is greatly appreciated Below is the code and various print outs (day 2 into debugging, so it's not pretty) class WatchBLEManager:NSObject,CBCentralManagerDelegate, ObservableObject{ var centralManager: CBCentralManager? @Published var devices : [String:AtomBLEDevice] = [:] private var scanningDevice:AtomBLEDevice? var bleStatus:WatchBLEStatus = .blePoweredOff func startBLE() { centralManager = CBCentralManager(delegate: self, queue: nil,options: [CBCentralManagerOptionShowPowerAlertKey: true]) self.centralManager?.delegate = self } func startScan() { self.centralManager?.scanForPeripherals(withServices: [],options: [CBCentralManagerScanOptionAllowDuplicatesKey : true]) self.centralManager?.delegate = self } func stopScan() { print("stopping scan") self.centralManager?.stopScan() filterName = "" scanningDevice = nil } func centralManagerDidUpdateState(_ central: CBCentralManager) { switch (central.state) { //... other states omitted case .poweredOff: bleStatus = .blePoweredOff // bleStateDelegate?.didBlePoweredOff() for device in devices.values{ device.isConnected = false } print("BLE is Powered Off") case .poweredOn: bleStatus = .blePoweredOn // bleStateDelegate?.didBlePoweredOn() startScan() centralManager?.registerForConnectionEvents() print("Central supports extended scan and connect: ", CBCentralManager.supports(.extendedScanAndConnect)) print("powered on") @unknown default: print("BLE is Unknown") } } private let connectionQueue = DispatchQueue(label: "com.atom.connectionQueue") var connectingTo: String? = nil var peripheral: CBPeripheral? = nil func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) { guard let localName = advertisementData[CBAdvertisementDataLocalNameKey] as? String else { return} if localName.contains("Atom") { print("\nConnecting to \(localName)") print("\tAdvertising data: \(advertisementData)") print("\tANCS Authorized: ",peripheral.ancsAuthorized) print("\tServices", peripheral.services, "\n") self.peripheral = peripheral self.peripheral?.delegate = self // central.registerForConnectionEvents() // central.delegate = self peripheral.delegate = self DispatchQueue.main.async { // central.connect(peripheral) self.centralManager?.connect(peripheral, options: [ CBConnectPeripheralOptionEnableTransportBridgingKey: true]) } DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) { print("\tState", String(describing: peripheral.state)) print("Connected Peripherals: \(self.centralManager?.retrieveConnectedPeripherals(withServices: []))") } } } // Never gets called for watchos func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { print("Connected to peripheral: \(peripheral.identifier)") if let atomDevice = getAtomBLEDevice(peripheral: peripheral) { //atomDevice.setPeripheral(perpipheral: <#T##CBPeripheral?#>) atomDevice.isConnected = true atomDevice.isConnecting = false //delegate?.didConnected(atomBLE: atomDevice!) atomDevice.startDiscoveringService() //atomDevice?.delegate?.didConnected(atomBLE: atomDevice!) print("Connected: \(peripheral.name)") } else { print("no matching atom device found for didConnect") print("connected peripheral :",peripheral.identifier.uuidString) } } func centralManager(_ central: CBCentralManager, connectionEventDidOccur event: CBConnectionEvent, for peripheral: CBPeripheral) { print("Connection event: \(event)") } func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: (any Error)?) { print("Failed to connect: \(error?.localizedDescription)") } func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) { let atomDevice = getAtomBLEDevice(peripheral: peripheral) atomDevice?.isConnected = false print("Peripheral disconnected:\(peripheral.name)") } func clearData() { filterName = "" for device in devices.values{ disconnect(atomBLEDevice: device) device.perpipheral?.delegate = nil } devices = [:] scanningDevice = nil // delegate = nil centralManager = nil } } extension WatchBLEManager: CBPeripheralDelegate { }```
1
0
106
5d
NEHotspotHelper “unresponsive” or “timed out” logs—Are they triggered by .evaluate?
I’m working with the NEHotspotHelper API in my iOS app, and I noticed the following log message in Console: "(BUNDLE ID ) is using NEHotspotHelper API and it's unresponsive to API's evaluate command. The API gives 45 seconds to 3rd party apps to respond, and then it launches WebSheet to allow user to interact with the portal." I have two different apps that both register a NEHotspotHelper handler: App A checks for .evaluate and calls createResponse(.unsupportedNetwork) if we don’t manage that particular network. App B registers for hotspot events but does not handle .evaluate at all. In App A, whenever I see that “unresponsive” or “45 seconds” log, the system eventually launches the standard captive portal WebSheet. In App B, I never see those logs. I have a few questions: Are these “unresponsive” logs indeed triggered by the .evaluate command specifically? In other words, do we only see that 45-second timeout and the subsequent WebSheet message if our app is registered to handle Evaluate but doesn’t respond quickly (or responds with .unsupportedNetwork)? Is it best practice (or required) to always respond to .evaluate—for example, sending .unsupportedNetwork if we don’t plan on managing the user’s login or captive portal? Does ignoring .evaluate lead to other unexpected behavior or logs? Should we still explicitly respond to Evaluate with .unsupportedNetwork? Or is it okay to skip Evaluate handling entirely on every app or invocation? I’d love to confirm whether .evaluate handling is the direct cause of these logs, and how best to avoid the “unresponsive”/“45 seconds” fallback if our app isn’t intended to manage the portal. Thanks in advance for any insights!
3
0
199
Jan ’25
How to Confirm Wi-Fi Connection Success in App Clip Without Access Wi-Fi Information Entitlement?
My app helps users connect to Wi-Fi networks, and I have requested the Access Wi-Fi information entitlement. This allows the app to retrieve the current Wi-Fi information to ensure the user’s connection is successful. Now, we are trying to implement an App Clip that enables users to connect to a specific Wi-Fi network through a QR code scan or NFC in certain scenarios. In the App Clip, I’ve requested the Hotspot entitlement, which allows the app to use the hotspot manager to configure Wi-Fi networks. However, since I cannot access the current Wi-Fi information in the App Clip, I’m unable to confirm whether the connection was successful.
2
0
162
6d
Not getting packets in PacketTunnel on iOS
Hi, I've created a packet tunnel but my packetFlow object isn't get called with any packets. Do I need to do something else to configure the packetFlow? Maybe I have to link it to a NWUDPSession? Thanks, Dave class PacketTunnelProvider: NEPacketTunnelProvider { override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) { let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: tunnelRemoteAddress) settings.ipv4Settings = NEIPv4Settings(addresses: [tunnelRemoteAddress], subnetMasks: ["255.255.255.255"]) settings.ipv4Settings?.includedRoutes = [NEIPv4Route.default()] setTunnelNetworkSettings(settings) { error in completionHandler(error) self.readPacketObjects() } } private func readPacketObjects() { self.packetFlow.readPacketObjects() { packets in // It never gets here. self.logMessage("Got '\(packets.count)' packet(s)") self.packetFlow.writePacketObjects(packets) self.readPacketObjects() } } }
5
0
233
Jan ’25
Does a lightweight server with HTTPS support exist?🥺
I am looking for a lightweight server that can run inside an app. The key requirement is that it must support local IP communication over HTTPS. I have searched Google and found several frameworks, but as far as I know, support for HTTPS in this environment has been discontinued or is no longer available. If anyone knows a solution that meets these criteria, I would greatly appreciate your guidance. Thank you in advance!😀
15
0
307
2w