I am writing to seek clarification on two technical issues related to iOS frameworks (CoreBluetooth and NetworkExtension). These observations are critical for optimizing our app's performance, and I would appreciate any official guidance or documentation references.
CoreBluetooth Scanning Frequency and Cycle
Issue:
We noticed inconsistent BLE device discovery times (ranging from 0.5s to 1.5s) despite the peripheral advertising at 2Hz (500ms interval).
Questions:
Does iOS regulate the BLE scan interval or duty cycle internally? If yes, what factors affect this behavior (e.g., foreground/background state, connected devices)?
Are there recommended practices to reduce discovery latency for peripherals with fixed advertising intervals?
Is there a way to configure scan parameters (e.g., scan window/interval) programmatically, similar to Android's BluetoothLeScanner?
Test Context:
Device: iPhone 13 mini (iOS 17.6.1)
Code: CBCentralManager.scanForPeripherals(withServices: nil, options: [CBCentralManagerScanOptionAllowDuplicatesKey: true])
NEHotspotConfigurationManager Workflow and Latency
Issue:
Using NEHotspotConfigurationManager.shared.apply(_:) to connect to Wi-Fi occasionally takes up to 8 seconds to complete.
Questions:
What is the internal workflow of the apply method? Does it include user permission checks, SSID scanning, authentication, or IP assignment steps?
Are there known scenarios where this method would block for extended periods (e.g., waiting for user interaction, network timeouts)?
Is the latency related to system-level retries or radio coexistence with other wireless activities (e.g., Bluetooth)?
Test Context:
Configuration: NEHotspotConfiguration(ssid: "TestSSID")
Behavior: Delay occurs even when the Wi-Fi network is in range and credentials are correct.
Networking
RSS for tagExplore the networking protocols and technologies used by the device to connect to Wi-Fi networks, Bluetooth devices, and cellular data services.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I am writing to seek clarification on two technical issues related to iOS frameworks (CoreBluetooth and NetworkExtension). These observations are critical for optimizing our app's performance, and I would appreciate any official guidance or documentation references.
CoreBluetooth Scanning Frequency and Cycle
Issue:
We noticed inconsistent BLE device discovery times (ranging from 0.5s to 1.5s) despite the peripheral advertising at 2Hz (500ms interval).
Questions:
Does iOS regulate the BLE scan interval or duty cycle internally? If yes, what factors affect this behavior (e.g., foreground/background state, connected devices)?
Are there recommended practices to reduce discovery latency for peripherals with fixed advertising intervals?
Is there a way to configure scan parameters (e.g., scan window/interval) programmatically, similar to Android's BluetoothLeScanner?
Test Context:
Device: iPhone 13 mini (iOS 17.6.1)
Code: CBCentralManager.scanForPeripherals(withServices: nil, options: [CBCentralManagerScanOptionAllowDuplicatesKey: true])
NEHotspotConfigurationManager Workflow and Latency
Issue:
Using NEHotspotConfigurationManager.shared.apply(_:) to connect to Wi-Fi occasionally takes up to 8 seconds to complete.
Questions:
What is the internal workflow of the apply method? Does it include user permission checks, SSID scanning, authentication, or IP assignment steps?
Are there known scenarios where this method would block for extended periods (e.g., waiting for user interaction, network timeouts)?
Is the latency related to system-level retries or radio coexistence with other wireless activities (e.g., Bluetooth)?
Test Context:
Configuration: NEHotspotConfiguration(ssid: "TestSSID")
Behavior: Delay occurs even when the Wi-Fi network is in range and credentials are correct.
In TN3179 under "macOS considerations" there are a set of instances where local network privacy does not apply:
macOS automatically allows local network access by:
Any daemon started by launchd
Any program running as root
Command-line tools run from Terminal or over SSH, including any child processes they spawn
I am running some tests in my app that use the local network, attempting to run them from both the terminal app and from a VScode terminal and I am getting permissions prompts. After allowing these pop ups, some of the tests still fail as if networking was blocked.
I have a question regarding /etc/pf.conf.
If I use this rule,
rdr pass on bridge100 inet proto tcp from 192.168.2.104 to any port {80, 443, 8883} -> 127.0.0.1 port 8080
all other traffic on bridge100 will not function properly, even the traffic that is not destined for 192.168.2.104.
Additionally, the hotspot generated through bridge100 will also become unavailable.
Even if I comment out this rule and run sudo pfctl -e -f /etc/pf.conf, the problem still persists. The situation will only return to normal when I restart my Mac.
my macos:15.3.2
my /etc/pf.conf
#
scrub-anchor "com.apple/*"
nat-anchor "com.apple/*"
rdr-anchor "com.apple/*"
rdr pass on bridge100 inet proto tcp from 192.168.2.104 to any port {80, 443, 8883} -> 127.0.0.1 port 8080
dummynet-anchor "com.apple/*"
anchor "com.apple/*"
load anchor "com.apple" from "/etc/pf.anchors/com.apple"
Topic:
App & System Services
SubTopic:
Networking
We're encountering an issue with our Network Extension (utilizing NEPacketTunnelProvider and NETransparentProxy) on macOS 14.5 (23F79).
On some systems, the VPN fails to automatically start after a reboot despite calling startVPNTunnel(). There are no error messages.
Our code attempts to start the tunnel:
.......
do {
try manager.connection.startVPNTunnel()
Logger.default("Started tunnel successfully")
} catch {
Logger.error("Failed to launch tunnel")
}
......
System log analysis reveals the tunnel stopping due to userLogout (NEProviderStopReason(rawValue: 12)) during reboot.
However, the Transparent Proxy stops due to userInitiated (NEProviderStopReason(rawValue: 1)) for the same reboot.
We need to understand:
Why the VPNTunnel isn't starting automatically.
Why the userLogout reason is triggered during reboot.
Additional Context:
We have manually started the VPN from System Settings before reboot.
I am working on a macos application that uses NetworkExtension and works fine in the debug environment. However, when I use the Release package, I am always prompted that my description file does not contain NetworkExtension. I am sure that my description file does contain NetworkExtension. How to solve this problem
I have a question regarding /etc/pf.conf.
If I use this rule,
rdr pass on bridge100 inet proto tcp from 192.168.2.104 to any port {80, 443, 8883} -> 127.0.0.1 port 8080
all other traffic on bridge100 will not function properly, even the traffic that is not destined for 192.168.2.104.
Additionally, the hotspot generated through bridge100 will also become unavailable.
Even if I comment out this rule and run sudo pfctl -e -f /etc/pf.conf, the problem still persists. The situation will only return to normal when I restart my Mac. my macos:15.3.2
my /etc/pf.conf
#
scrub-anchor "com.apple/*"
nat-anchor "com.apple/*"
rdr-anchor "com.apple/*"
rdr pass on bridge100 inet proto tcp from 192.168.2.104 to any port {80, 443, 8883} -> 127.0.0.1 port 8080
dummynet-anchor "com.apple/*"
anchor "com.apple/*"
load anchor "com.apple" from "/etc/pf.anchors/com.apple"
Topic:
App & System Services
SubTopic:
Networking
Hi~
I implemented network filtering on iOS using NEFilterControlProvider and NEFilterDataProvider.
However, I found that their usage is restricted when distributing through the App Store.
Does ADEP-based distribution allow the use of NEFilterControlProvider and NEFilterDataProvider?
In TN3134, it states that NEPacketTunnelProvider requires MDM.
Should I assume that NEFilterControlProvider and NEFilterDataProvider also require MDM in the same way?
Thanks
你好,是这样的,目的我使用的是mac mini进行软件测试,我目前测试的软件会通过本地回环地址127.0.0.1进行数据传输,这种数据传输不是网络请求,所以用网络抓包的手段,没法测试。所以,我目前的想法是修改您macOS的本地回环地址优先级,定向到我自己的代理服务器,进行数据测试和请求检测。我对liunx系统的作比较了解,但是对于macos上面这方面设置的修改不太清楚。 希望您可以解答!
Topic:
App & System Services
SubTopic:
Networking
Tags:
Inter-process communication
Entitlements
macOS
Hi~
I implemented network filtering on iOS using NEFilterControlProvider and NEFilterDataProvider.
However, I found that their usage is restricted when distributing in the App Store.
Does ADEP-based distribution allow the use of NEFilterControlProvider and NEFilterDataProvider?
In TN3134, it states that NEPacketTunnelProvider requires MDM.
Should I assume that NEFilterControlProvider and NEFilterDataProvider also require MDM in the same way?
thanks.
Title: Loss of Internet Connectivity on iOS Device When Packet Tunnel Crashes
Feedback ticket: https://feedbackassistant.apple.com/feedback/14162605
Product: iPhone 12
Version: iOS - 17.5.1
Configuration: NETunnelProviderManager Configuration
Description: We are developing an iOS VPN client and have configured our packet tunnel provider according to Apple's guidelines. The configuration is as follows:
includeAllNetworks = YES
excludeLocalNetworks = NO
enforceRoutes = NO
This setup works as expected when the VPN successfully connects. However, we encounter a blocker issue where the device loses internet connectivity if the packet tunnel crashes.
Steps to Reproduce:
Configure the NETunnelProviderManager with the above settings.
Connect the VPN, which successfully establishes a connection.
Verify that resources are accessible and internet connectivity is functional.
Packet tunnel to crash unexpectedly.Observe that the NE process (Packet Tunnel) restarts automatically, as expected and attempts to reconnect the VPN;
however, the device now lacks internet connectivity, preventing VPN reconnection.
Try accessing resources using Safari or any other internet-dependent app, resulting in an error indicating the device is not connected to the internet.
Actual Results: The device loses internet connectivity after the packet tunnel crashes and fails to regain it automatically, preventing the VPN from reconnecting.
Expected Results: The device should maintain internet connectivity or recover connectivity to allow the VPN to reconnect successfully after the packet tunnel process restarts.
Workaround - iPhone device needs a restart to regain internet connectivity .
Hello, I'm having some problems starting my DNS proxy network extension.
Even after I call NEDNSProxyManager.saveToPreference() successfully I don't see any logs from my dns proxy.
This is the code from the user space app:
import SwiftUI
import NetworkExtension
func configureDNSProxy() {
let dnsProxyManager = NEDNSProxyManager.shared()
dnsProxyManager.loadFromPreferences { error in
if let error = error {
print("Error loading DNS proxy preferences: \(error)")
return
}
dnsProxyManager.localizedDescription = "my DNS proxy"
let proto = NEDNSProxyProviderProtocol()
proto.providerBundleIdentifier = "com.myteam.dns-proxy-tests.ne"
dnsProxyManager.providerProtocol = proto
// Enable the DNS proxy.
dnsProxyManager.isEnabled = true
dnsProxyManager.saveToPreferences { error in
if let error = error {
print("Error saving DNS proxy preferences: \(error)")
} else {
NSLog("DNS Proxy enabled successfully")
}
}
}
}
@main
struct dns_proxy_testsApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
init() {
configureDNSProxy()
}
}
This is the code for my network extension(DNSProxyProvider.swift):
import NetworkExtension
class DNSProxyProvider: NEDNSProxyProvider {
override func startProxy(options:[String: Any]? = nil, completionHandler: @escaping (Error?) -> Void) {
NSLog("dns proxy ne started")
completionHandler(nil)
}
override func stopProxy(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
NSLog("dns proxy ne stopped")
completionHandler()
}
override func sleep(completionHandler: @escaping () -> Void) {
NSLog("dns proxy ne sleep")
completionHandler()
}
override func wake() {
NSLog("dns proxy ne wake")
}
override func handleNewFlow(_ flow: NEAppProxyFlow) -> Bool {
NSLog("dns proxy ne flow")
return true
}
}
The bundle identifier for my network extension is: com.myteam.dns-proxy-tests.ne and both the user space app and the network extension have the DNS Proxy capability. Both have the same app group capability with the same group name group.com.myteam.dns-proxy-test.
The info.plist from the network extension look like this(I didn't really modify it from the default template created by xcode)
<?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>NetworkExtension</key>
<dict>
<key>NEMachServiceName</key>
<string>$(TeamIdentifierPrefix)com.example.app-group.MySystemExtension</string>
<key>NEProviderClasses</key>
<dict>
<key>com.apple.networkextension.dns-proxy</key>
<string>$(PRODUCT_MODULE_NAME).DNSProxyProvider</string>
</dict>
</dict>
</dict>
</plist>
In the logs I do see DNS Proxy enabled successfully and also I see:
NESMDNSProxySession[Primary Tunnel:my DNS proxy:<...>:(null)] starting with configuration: {
name = my DNS proxy
identifier = <..>
applicationName = dns-proxy-tests
application = com.myteam.dns-proxy-tests
grade = 1
dnsProxy = {
enabled = YES
protocol = {
type = dnsProxy
identifier = <...>
identityDataImported = NO
disconnectOnSleep = NO
disconnectOnIdle = NO
disconnectOnIdleTimeout = 0
disconnectOnWake = NO
disconnectOnWakeTimeout = 0
disconnectOnUserSwitch = NO
disconnectOnLogout = NO
includeAllNetworks = NO
excludeLocalNetworks = NO
excludeCellularServices = YES
excludeAPNs = YES
excludeDeviceCommunication = YES
enforceRoutes = NO
pluginType = com.myteam.dns-proxy-tests
providerBundleIdentifier = com.myteam.dns-proxy-tests.ne
designatedRequirement = identifier "com.myteam.dns-proxy-tests.ne" <...> /* exists */
}
}
}
But then I see:
Checking for com.myteam.dns-proxy-tests.ne - com.apple.networkextension.dns-proxy
But then finally
Found 0 registrations for com.myteam.dns-proxy-tests.ne (com.apple.networkextension.dns-proxy)
So I think that last log probably indicates the problem.
I'm a bit lost at what I'm doing wrong so I'd be super thankful for any pointer!
We're experiencing an issue with Local Network Permission. When trying to connect to a socket, the Local Network Permission alert pops up. To trigger the permission request at the start of the app, we used the following code to ask for permission and receive a callback on whether it's granted. However, this approach doesn't always trigger the permission alert, or it gets automatically dismissed after 30 seconds, only to reappear later. What could be causing this inconsistent behavior?
func checkLocalNetworkPermission(_ completed: Optional<(Bool) -> Void> = .none) {
DispatchQueue.global(qos: .userInitiated).async {
let hostName = ProcessInfo.processInfo.hostName
let isGranted = hostName.contains(".local")
if let completed {
DispatchQueue.main.async {
completed(isGranted)
}
}
}
}
Sometimes when adding a VPN configuration, it just redirects to the Settings app and doesn’t continue with the rest of the configuration process like prompting for passcode. But it proceeds as normal after the 2nd or 3rd try.
This issue is occurring on iOS 18.5 build 22F5068a but it has been a problem over several versions now.
Feedback ID: FB17458055
Hello,
I am in a very similar situation as described in the thread: https://developer.apple.com/forums/thread/655183
Context: I am working on an app that receives data from a hardware device through its Wifi network, and the hardware is not connected to the internet. Now, I would need to call some API while still connected to hardware so I would need to use the cellular data.
As mentioned on the thread, I can achieve this via Network framework, using the requiredInterfaceType property. But Is there any other way I can achieve this? I can also do some suggestion on the hardware if that's helpful.
Thank you!
I created a self signed CA and use it to generate/sign a client cert using openssl. Then I use the self signed client cert to do TLS client authentication with my server (which also uses the self signed CA). The issue I have is when I validate the self signed CA, by calling SecTrustEvaluateAsyncWithError, it always complains this error “'DigiCert Global Root G3' certificate is not trusted". However that CA (DigiCert Global Root G3) is not my self signed CA (my CA is 'MQTTSampleCA' and I attached a dump of the my CA cert in the PR in the end of this post), so I'm confused why the API keeps complaining that CA. After some researching, I see that is a well known CA so I download its cert from https://www.digicert.com/kb/digicert-root-certificates.htm, install and trust it on my iOS device, but that doesn't help and I still get the same error. I provide all the repro steps in this PR: https://github.com/liumiaojq/EmCuTeeTee/pull/1, including how I generate the certs and the source codes of a test app that I used to do cert validation. I appreciate if anyone can share insights how to resolve this error.
I'm simply trying to use a proxy to route a http request in Swift to measure the average round trip time of a list of proxies. I've went through multiple Stack Overflow threads on this topic but they are all super old / outdated.
format:host:port:username:password
I also added the info.plist entry:
NSAllowsArbitraryLoads -> NSExceptionDomains
When I call the function below I am prompted with a menu that says
"Proxy authentication required. Enter the password for HTTP proxy ... in settings"
I closed this menu inside my app and tried the function below again and it worked without giving me the menu a second time. However even though the function works without throwing any errors, it does NOT use the proxies to route the request.
Why does the request work (throws no errors) but does not use the proxies? I'm assuming it's because the password isn't entered in the settings as the alert said. My users will want to test proxy speeds for many different Hosts/Ports, it doesn't make sense to enter the password in settings every time. How can I fix this issue?
func averageProxyGroupSpeed(proxies: [String], completion: @escaping (Int, String) -> Void) {
let numProxies = proxies.count
if numProxies == 0 {
completion(0, "No proxies")
return
}
var totalTime: Int64 = 0
var successCount = 0
let group = DispatchGroup()
let queue = DispatchQueue(label: "proxyQueue", attributes: .concurrent)
let lock = NSLock()
let shuffledProxies = proxies.shuffled()
let selectedProxies = Array(shuffledProxies.prefix(25))
for proxy in selectedProxies {
group.enter()
queue.async {
let proxyDetails = proxy.split(separator: ":").map(String.init)
guard proxyDetails.count == 4,
let port = Int(proxyDetails[1]),
let url = URL(string: "http://httpbin.org/get") else {
completion(0, "Invalid proxy format")
group.leave()
return
}
var request = URLRequest(url: url)
request.timeoutInterval = 15
let configuration = URLSessionConfiguration.default
configuration.connectionProxyDictionary = [
AnyHashable("HTTPEnable"): true,
AnyHashable("HTTPProxy"): proxyDetails[0],
AnyHashable("HTTPPort"): port,
AnyHashable("HTTPSEnable"): false,
AnyHashable("HTTPUser"): proxyDetails[2],
AnyHashable("HTTPPassword"): proxyDetails[3]
]
let session = URLSession(configuration: configuration)
let start = Date()
let task = session.dataTask(with: request) { _, _, error in
defer { group.leave() }
if let error = error {
print("Error: \(error.localizedDescription)")
} else {
let duration = Date().timeIntervalSince(start) * 1000
lock.lock()
totalTime += Int64(duration)
successCount += 1
lock.unlock()
}
}
task.resume()
}
}
group.notify(queue: DispatchQueue.main) {
if successCount == 0 {
completion(0, "Proxies Failed")
} else {
let averageTime = Int(Double(totalTime) / Double(successCount))
completion(averageTime, "")
}
}
}
Hey!
We are investigating a problem pf rules being ignored by some processes. Despite blocking all traffic, some outgoing unicast packets can be seen in tcpdump. Issue is present in MacOS 15.0.0 - 15.3.1 (Newest at the time of writing). I tested MacOS 14.7.4 and pf rules there behaved as expected. Steps to reproduce the issue:
$ cat pf.conf
block all
$ sudo pfctl -e -F all -f ./pf.conf
Password:
pfctl: Use of -f option, could result in flushing of rules
present in the main ruleset added by the system at startup.
See /etc/pf.conf for further details.
No ALTQ support in kernel
ALTQ related functions disabled
rules cleared
nat cleared
dummynet cleared
0 tables deleted.
196 states cleared
source tracking entries cleared
pf: statistics cleared
pf: interface flags reset
pfctl: pf already enabled
After executing these commands MacOS 14 will block all outgoing unicast traffic, and on MacOS 15 data can be sent to arbitrary addresses:
$ ifconfig en0
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
options=6460<TSO4,TSO6,CHANNEL_IO,PARTIAL_CSUM,ZEROINVERT_CSUM>
ether b6:5e:a5:c5:1e:db
inet6 fe80::1090:9c8:4325:329a%en0 prefixlen 64 secured scopeid 0xe
inet 192.168.50.144 netmask 0xffffff00 broadcast 192.168.50.255
nd6 options=201<PERFORMNUD,DAD>
media: autoselect
status: active
$ sudo tcpdump -k A -i any -n src 192.168.50.144
tcpdump: data link type PKTAP
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type PKTAP (Apple DLT_PKTAP), snapshot length 524288 bytes
12:05:12.673472 (en0, proc com.apple.geod:1286:, svc BE, out, ch, flowid 0x0, ttag 0x0, dlt 0x1, cmpgc 0x0) IP 192.168.50.144.52012 > 17.253.15.196.443: Flags [P.], seq 1888882378:1888882402, ack 3554898220, win 2048, options [nop,nop,TS val 2752050055 ecr 1291585385], length 24
12:05:13.793937 (en0, proc com.apple.WebKit:974:, eproc Safari:804:, svc BE, out, ch, flowid 0x0, ttag 0x0, dlt 0x1, cmpgc 0x0) IP 192.168.50.144.52024 > 3.65.102.105.443: Flags [P.], seq 2011312019:2011312073, ack 673002582, win 2048, options [nop,nop,TS val 777228223 ecr 484269939], length 54
Was there any change in the way pfctl is used or is this a bug? This issue affects negatively privacy features of our product.
Topic:
App & System Services
SubTopic:
Networking
I would like to develop a macOS app that would automatically switch Network Locations based on certain criteria. I want to publish this on the Mac App Store, but I'm unsure if this functionality is permitted.
I've searched through the App Store Review Guidelines and documentation on NetworkExtension and SystemConfiguration frameworks, but I haven't found clear information on whether:
Programmatically changing Network Locations is allowed in sandboxed App Store apps
What specific entitlements would be required
If there are any API-approved ways to do this without shell commands
I'd like to avoid investing significant development time if this type of functionality would ultimately be rejected. As a relatively new Apple platform developer, any guidance on:
The appropriate frameworks/APIs to use
Required entitlements
Whether this functionality is even permitted for App Store distribution
would be incredibly helpful.
Thank you in advance for any insights!
Topic:
App & System Services
SubTopic:
Networking
Tags:
Network Extension
System Configuration
CFNetwork
I'm using the NEHotspotConfigurationManager class, with joinOnce = false, to connect to a Wi-Fi network that lacks internet access (IoT device).
After restarting my iPhone, the first connection to this network disconnects automatically in less than a minute. All subsequent connections remain stable without disconnecting. What could be causing this?