General:
DevForums tag: Network Extension
Network Extension framework documentation
Network Extension and VPN Glossary DevForums post
Debugging a Network Extension Provider DevForums post
Exporting a Developer ID Network Extension DevForums post
Network Extension vs ad hoc techniques on macOS DevForums post
Extra-ordinary Networking DevForums post
Wi-Fi management:
Wi-Fi Fundamentals DevForums post
TN3111 iOS Wi-Fi API overview technote
How to modernize your captive network developer news post
iOS Network Signal Strength DevForums post
See also Networking Resources.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
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
Hi,
I'm adding a Content Filtering (FilterDataProvider) on macOS to an existing app and using MDM to avoid user interaction.
I start by pushing the following payloads to my machine:
com.apple.system-extension-policy
com.apple.webcontent-filter
And then installing notarized pkg containing my app and the NE.
Inspecting the system logs shows the following error:
neagent Failed to find a com.apple.networkextension.filter-data extension inside of app com.company_name.app_name.daemon
And calling
submit(request: .activationRequest(forExtensionWithIdentifier: bundleId, queue: queue))
results in:
Missing entitlement com.apple.developer.system-extension.install
Installing from Xcode on a SIP disabled machine works fine and both NE and CF are working as expected.
I followed the steps mentioned here https://developer.apple.com/forums/thread/737894 however the embedded entitlements already contained -systemextension suffix so I'm not sure if re signing and the subsequent steps are needed.
I also double checked that com.apple.developer.system-extension.install is present, certificates are not expired and that get-task-allow is not present in the embedded profile.
Here is what my release entitlement file looks like:
<?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>com.apple.developer.networking.networkextension</key>
<array>
<string>content-filter-provider-systemextension</string>
</array>
<key>com.apple.security.application-groups</key>
<array>
<string>com.company_name.app_name.network-extension.content-filter</string>
</array>
</dict>
and my release app entitlement:
<?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>com.apple.developer.endpoint-security.client</key>
<true/>
<key>com.apple.developer.networking.networkextension</key>
<array>
<string>content-filter-provider-systemextension</string>
</array>
<key>com.apple.developer.system-extension.install</key>
<true/>
</dict>
</plist>
redacted logs
@eskimo may I ask for your help here!
Hi everyone,
Our app helps users block adult websites to promote focus and digital wellness. During the App Store review, it was flagged under Guideline 2.5.1 for using a VPN profile to block content, with Apple advising us to remove this feature.
Since blocking adult content is core to our app, we’re looking for compliant alternatives:
Can Network Extensions Framework (e.g., NEDNSProxyProvider) be used for on-device filtering?
Would pre-configured safe DNS (e.g., CleanBrowsing) be acceptable?
Are there compliant examples of similar apps?
Any advice on achieving this functionality within Apple’s guidelines would be greatly appreciated.
Thanks!
We want to ressolve dns for predefined sets of private app domains.
We've added this rule:
NENetworkRule(destinationHost: NWHostEndpoint(hostname: Private Domain1(example.com), port: 53), protocol: .UDP)
As per apple documentation: A rule that matches all DNS queries/responses for hosts in the example.com domain.
do you think it will work i.e it will forward DNS requests UDP flow to transparent provider in all the cases?
or do you think the text is a bit misleading. it should instead say: "A rule that matches all DNS queries/responses for nameservers in the example.com domain"?
This rule that look for port 53 of that domain only works if the system really asks a nameserver of that specific domain, right?
So, what if a local DNS server or a different nameserver are taking care of the resolution?
I need to check how long we can run an app in background which act as a consumer of data / control filter. What is the max time we get to run our app in background without any of these app strategies?
https://developer.apple.com/documentation/backgroundtasks/choosing-background-strategies-for-your-app
On iOS beta, monitoring network usage using the getifaddrs API sporadically causes system volume spikes. This happens even though the application does not interact with any audio-related code. The issue persists across different polling intervals (e.g., 0.05s to 1s) and only occurs when invoking getifaddrs. Replacing the API calls with mock data eliminates the problem, suggesting a potential issue with getifaddrs in the beta environment.
The application updates UI elements based on network activity, but the volume spikes occur independently of UI or other observable app behavior.
Steps to Reproduce:
Create an app that monitors network usage using the getifaddrs API.
Fetch network statistics on a timer (e.g., every 0.05 seconds).
Observe system behavior while running the app on iOS beta.
Note sporadic volume spikes during app runtime.
Expected Result:
Polling network usage with getifaddrs should not affect system volume or other unrelated resources.
Actual Result:
System volume spikes occasionally when network statistics are retrieved using getifaddrs.
iOS 18.2 Beta, Tested on physical device ( iPhone 15 Pro )
Hi,
TLDR: On iOS, when my PacketTunnel is running, can I exclude DNS requests from going into the tunnel?
I have a test app, using Apple's AsyncDNSResolver, that makes a DNS call and it works when the tunnel is not running.
If the tunnel is running it times out after 30 seconds and I get the error -65568.
Here's how I'm setting up the tunnel
func setup(tunnelRemoteAddress: String) {
let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: tunnelRemoteAddress)
settings.ipv4Settings = NEIPv4Settings(addresses: [tunnelRemoteAddress], subnetMasks: ["255.255.255.255"])
settings.ipv4Settings?.includedRoutes = [NEIPv4Route.default()]
let proxySettings = NEProxySettings()
proxySettings.httpEnabled = true
proxySettings.httpServer = NEProxyServer(address: ProxyServerConfiguration.host, port: ProxyServerConfiguration.port)
proxySettings.httpsEnabled = true
proxySettings.httpsServer = NEProxyServer(address: LocalProxyServerConfiguration.host, port: LocalProxyServerConfiguration.port)
proxySettings.excludeSimpleHostnames = true
proxySettings.exceptionList = nil
let dnsSettings = NEDNSSettings(servers: ["8.8.8.8"])
settings.dnsSettings = dnsSettings
settings.proxySettings = proxySettings
setTunnelNetworkSettings(settings) { error in
// ...
}
}
I've tried all combinations of setting/excluding the NEDNSSettings but the DNS call always fails when the tunnel is running.
Thanks for any help.
Whenever I'm working on my content filter for macOS, I usually keep SIP disabled and with developer mode on (systemextensionsctl) as a convenience.
The issue: content filter stopped receiving any kind of traffic when SIP is disabled. I don't see any log lines in Console for new flows, and the filter can't block anything, since it doesn't get any flows. Issue started yesterday.
I tried several things and did some investigation, here are some findings:
Reboot: rebooting did not fix the issue (while keeping SIP disabled).
Reenabling SIP fixes the issue for both App Store and Xcode builds.
Code: latest published version also stopped working with SIP disabled. This version is stable and confirmed to work as reported by users.
Clean Xcode + rebuild did not fix the issue.
Lastly, I inspected the logs and did not see any errors standing out. I noticed the filter does get started (startFilter is called) and registered, but after that there are no errors/new flows or anything, just silence (logs below).
com.apple.networkextension default 15:22:22.270746-0300 : Calling startFilterWithCompletionHandler
com.extension.MyExtension info 15:22:22.270998-0300 Success applying filter settings
com.apple.networkextension debug 15:22:22.272705-0300 NESMFilterSession[My Extension:B9F3F30E-E0E0-4E53-8B32-EFC285E3CF6A]: Checking providerBundleIdentifier com.extension.MyExtension for pluginClass 4
com.apple.networkextension debug 15:22:22.272717-0300 Checking for com.extension.MyExtension - com.apple.networkextension.filter-data
com.apple.networkextension default 15:22:22.272728-0300 Found 1 registrations for com.extension.MyExtension (com.apple.networkextension.filter-data)
com.apple.networkextension debug 15:22:22.272778-0300 NESMFilterSession[My Extension:B9F3F30E-E0E0-4E53-8B32-EFC285E3CF6A]: com.extension.MyExtension is registered for pluginClass 4
Here are some additional info about my system:
macOS 15.1
Between yesterday and today, the only new Installation is XProtectPlistConfigData at 12:10AM
Thanks!
We use as content filter in our app to monitor flows, we gather data about the flow and block flows deemed suspicious.
Our content filter is activated/deactivated by a UI app but the flows are reported via XPC to a separate daemon process for analysis.
As of macOS 15, we are seeing cases where flows are missing or flows are not received at all by the content filter. The behaviour is not consistent, some devices seem to receive flows normally but others don't. It appears Intel devices are much less prone to showing the problem, whereas Arm devices routinely exhibit missing flows.
On macOS 14 or earlier, there is no sign of missing flows.
Testing on earlier beta versions of macOS 15 did not appear to show the problem, however I can't rule out if issue was present but it wasn't spotted.
Experimenting with simple examples of using a content filter (e.g. QNE2FilterMac) does not appear to reproduce the issue.
Questions,
What has changed between macOS 14 and 15 that could be the cause of the lack of flows?
Is our approach to using an app activated content filter reporting to a daemon connected via XPC unsupported?
Hello all,
I have a question,
I am developing an application that uses the apply() function of the NEHotspotConfigurationManager class to switch the Wifi of the device.
In the completionHandler of the apply() function, the error argument contains “Internal Error(8)” and the wifi switching may fail.
We have never seen this problem during development, and since it occurs only in the market, we are at a loss as to the cause and countermeasure.
Do you know the cause of the “Internal Error(8)” and how to fix it?
A similar phenomenon has already been discussed in the following thread, but after countermeasures were taken in iOS12, it also occurs in iOS13 and later and no progress has been made since then.
https://developer.apple.com/forums/thread/107851
I would appreciate it if someone could clarify what is happening with this error, as there is not much information on the web regarding this error.
Thank you in advance.
Hello,
I have a company laptop thats connected to the internet without a VPN. I need to be able to resolve my company's sub domains using a specific dns server, and have all other domains resolved by the system wide name server.
In windows, this is trivial to do. In an admin powershell I run
"Add-DnsClientNrptRule -Namespace ".foo.mycompany.com" -Nameserver "127.0.0.1"
and resolution requests for *.foo.mycompany.com is sent to a name server running on the localhost. All other dns resolution requests are handled by the system configured resolver.
MacOS does have the /etc/resolver/ solution for this, but my understanding from these forums is that this is not the recommended approach. Note - I have tried it and it works.
AFAIU, the recommended approach is to create a system Network extension using NEDNSProxyProvider, override handleNewFlow() and do what's necessary.
The issue with this solution is that it requires
handling all the dns flow
parsing of DNS datagrams to extract the host
forwarding the datagrams to the appropriate dns server
Handle responses.
Deal with flow control
Handle edge cases.
I was hoping for something much simpler than us needing to implement datagram parsing.
Could you please shed light on our options and how we could proceed ?
I'm use iPad OS 17.5.1, when I try to use socket to connect to an ipv6 address created by PacketTunnelProvider in my iOS device, an error occurs. Here is the code to create socket server and client:
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
int dx_create_ipv6_server(const char *ipv6_address, int port) {
int server_fd;
struct sockaddr_in6 server_addr;
server_fd = socket(AF_INET6, SOCK_STREAM, 0);
if (server_fd == -1) {
perror("socket() failed");
return -1;
}
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin6_family = AF_INET6;
server_addr.sin6_port = htons(port);
if (inet_pton(AF_INET6, ipv6_address, &server_addr.sin6_addr) <= 0) {
perror("inet_pton() failed");
close(server_fd);
return -1;
}
if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
perror("bind() failed");
close(server_fd);
return -1;
}
if (listen(server_fd, 5) == -1) {
perror("listen() failed");
close(server_fd);
return -1;
}
printf("Server is listening on [%s]:%d\n", ipv6_address, port);
return server_fd;
}
int dx_accept_client_connection(int server_fd) {
int client_fd;
struct sockaddr_in6 client_addr;
socklen_t client_addr_len = sizeof(client_addr);
client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_addr_len);
if (client_fd == -1) {
perror("accept() failed");
return -1;
}
char client_ip[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &client_addr.sin6_addr, client_ip, sizeof(client_ip));
printf("Client connected: [%s]\n", client_ip);
return client_fd;
}
int dx_connect_to_ipv6_server(const char *ipv6_address, int port) {
int client_fd;
struct sockaddr_in6 server_addr;
client_fd = socket(AF_INET6, SOCK_STREAM, 0);
if (client_fd == -1) {
perror("socket() failed");
return -1;
}
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin6_family = AF_INET6;
server_addr.sin6_port = htons(port);
if (inet_pton(AF_INET6, ipv6_address, &server_addr.sin6_addr) <= 0) {
perror("inet_pton() failed");
close(client_fd);
return -1;
}
if (connect(client_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
perror("connect() failed");
close(client_fd);
return -1;
}
printf("Connected to server [%s]:%d\n", ipv6_address, port);
close(client_fd);
return 0;
}
@implementation SocketTest
+ (void)startSever:(NSString *)addr port:(int)port {
[[NSOperationQueue new] addOperationWithBlock:^{
int server_fd = dx_create_ipv6_server(addr.UTF8String, port);
if (server_fd == -1) {
return;
}
int client_fd = dx_accept_client_connection(server_fd);
if (client_fd == -1) {
close(server_fd);
return;
}
close(client_fd);
close(server_fd);
}];
}
+ (void)clientConnect:(NSString *)addr port:(int)port{
[[NSOperationQueue new] addOperationWithBlock:^{
dx_connect_to_ipv6_server(addr.UTF8String, port);
}];
}
@end
PacketTunnelProvider code:
override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) {
let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "fd84:306d:fc4e::1")
let ipv6 = NEIPv6Settings(addresses: ["fd84:306d:fc4e::1"], networkPrefixLengths: 64)
settings.ipv6Settings = ipv6
setTunnelNetworkSettings(settings) { error in
if error == nil {
self.readPackets()
}
completionHandler(error)
}
}
private func readPackets() {
// do nothing
packetFlow.readPackets { [self] packets, protocols in
self.packetFlow.writePackets(packets, withProtocols: protocols)
self.readPackets()
}
}
At main target, in viewcontroller's viewDidAppear, after starting the VPN, executed following code:
[SocketTest startSever:@"fd84:306d:fc4e::1" port:12345];
sleep(3);
[SocketTest clientConnect:@"fd84:306d:fc4e::1" port:12345];
The startSever is executed correctly, but when executing:
connect(client_fd, (struct sockaddr *)&server_addr, sizeof(server_addr))
in clientConnect, the code is blocked until it times out and returns -1.
**Even if I use GCDAsyncSocket or BlueSocket, I get the same error. The strange thing is that if I use the ipv4 address in PacketTunnelProvider, and change the above code to the ipv4 version and connect to ipv4 address, or use GCDAsyncSocket to perform the corresponding operation, it can be executed correctly.
**
I tried to search Google for problems with ios-related ipv6 addresses, but I still couldn't find a solution. Is this a bug in the ios system or is there something wrong with my code? I hope to get your help!
Stackoverflow url: iOS Socket cannot connect ipv6 address when use PacketTunnelProvider
When I try to use socket to connect to an ipv6 address created by PacketTunnelProvider in my iOS device, an error occurs. Here is the code to create socket server and client:
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
int dx_create_ipv6_server(const char *ipv6_address, int port) {
int server_fd;
struct sockaddr_in6 server_addr;
server_fd = socket(AF_INET6, SOCK_STREAM, 0);
if (server_fd == -1) {
perror("socket() failed");
return -1;
}
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin6_family = AF_INET6;
server_addr.sin6_port = htons(port);
if (inet_pton(AF_INET6, ipv6_address, &server_addr.sin6_addr) <= 0) {
perror("inet_pton() failed");
close(server_fd);
return -1;
}
if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
perror("bind() failed");
close(server_fd);
return -1;
}
if (listen(server_fd, 5) == -1) {
perror("listen() failed");
close(server_fd);
return -1;
}
printf("Server is listening on [%s]:%d\n", ipv6_address, port);
return server_fd;
}
int dx_accept_client_connection(int server_fd) {
int client_fd;
struct sockaddr_in6 client_addr;
socklen_t client_addr_len = sizeof(client_addr);
client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_addr_len);
if (client_fd == -1) {
perror("accept() failed");
return -1;
}
char client_ip[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &client_addr.sin6_addr, client_ip, sizeof(client_ip));
printf("Client connected: [%s]\n", client_ip);
return client_fd;
}
int dx_connect_to_ipv6_server(const char *ipv6_address, int port) {
int client_fd;
struct sockaddr_in6 server_addr;
client_fd = socket(AF_INET6, SOCK_STREAM, 0);
if (client_fd == -1) {
perror("socket() failed");
return -1;
}
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin6_family = AF_INET6;
server_addr.sin6_port = htons(port);
if (inet_pton(AF_INET6, ipv6_address, &server_addr.sin6_addr) <= 0) {
perror("inet_pton() failed");
close(client_fd);
return -1;
}
if (connect(client_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
perror("connect() failed");
close(client_fd);
return -1;
}
printf("Connected to server [%s]:%d\n", ipv6_address, port);
close(client_fd);
return 0;
}
@implementation SocketTest
+ (void)startSever:(NSString *)addr port:(int)port {
[[NSOperationQueue new] addOperationWithBlock:^{
int server_fd = dx_create_ipv6_server(addr.UTF8String, port);
if (server_fd == -1) {
return;
}
int client_fd = dx_accept_client_connection(server_fd);
if (client_fd == -1) {
close(server_fd);
return;
}
close(client_fd);
close(server_fd);
}];
}
+ (void)clientConnect:(NSString *)addr port:(int)port{
[[NSOperationQueue new] addOperationWithBlock:^{
dx_connect_to_ipv6_server(addr.UTF8String, port);
}];
}
@end
PacketTunnelProvider code:
override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) {
let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "fd84:306d:fc4e::1")
let ipv6 = NEIPv6Settings(addresses: ["fd84:306d:fc4e::1"], networkPrefixLengths: 64)
settings.ipv6Settings = ipv6
setTunnelNetworkSettings(settings) { error in
if error == nil {
self.readPackets()
}
completionHandler(error)
}
}
private func readPackets() {
// do nothing
packetFlow.readPackets { [self] packets, protocols in
self.packetFlow.writePackets(packets, withProtocols: protocols)
self.readPackets()
}
}
At main target, in viewcontroller's viewDidAppear, after starting the VPN, executed following code:
[SocketTest startSever:@"fd84:306d:fc4e::1" port:12345];
sleep(3);
[SocketTest clientConnect:@"fd84:306d:fc4e::1" port:12345];
The startSever is executed correctly, but when executing:
connect(client_fd, (struct sockaddr *)&server_addr, sizeof(server_addr))
in clientConnect, the code is blocked until it times out and returns -1.
Even if I use GCDAsyncSocket or BlueSocket, I get the same error.
The strange thing is that if I use the ipv4 address in PacketTunnelProvider, and change the above code to the ipv4 version and connect to ipv4 address, or use GCDAsyncSocket to perform the corresponding operation, it can be executed correctly.
I tried to search Google for problems with ios-related ipv6 addresses, but I still couldn't find a solution. Is this a bug in the ios system or is there something wrong with my code? I hope to get your help!
I am working on developing a Mac app (WireGuard Apple VPN) that will be distributed outside the App Store.
I have added the network extension which is included in the system extension with packet tunneling capability.
I have created a build following these steps here: https://developer.apple.com/forums/thread/737894
as per your suggestions in my accepted post: https://developer.apple.com/forums/thread/761251
It works fine in this case when the machine has SIP disabled and systemextensionsctl developer enabled.
As soon as I have made changes on the machine to disable systemextensionsctl developer and enable SIP, it loads the system extension and also asks for network extension permission. But it does not connect to the VPN.
I have copied the app to the "/Applications" directory before opening it.
This issue is specific to macOS 15.1. It works fine for macOS 14.* and 13.*. Speaking of macOS 15.0, it didn't work in both cases with SIP enabled or disabled. So, it seems that it must be a bug in macOS 15.0 and it seems that this bug was partially fixed in macOS 15.1. Is that right?
I am currently planning to distribute the app to testers for final testing before rolling it out to a wider audience.
Am I missing something? Thanks in advance.
I have a need to do a coverage test for the networkextension function code implemented by the system extension, but I don't know how to implement this method.
For example, how do you use gtest or how do you use xctest to achieve these capabilities?
If you know, please let me know. Thanks
I'm working on a network extension that provides a VPN tunnel. The logic behind the tunnel provider requires me to connect the backend to pull recent configuration and then configure the routing. It works in general but fails with some circumstances. I have 100% reproducible fails if I run OpenVPN tunnel in parallel. When it happens it looks like the network extension cannot connect the backend (any internet resource actually). Requests fail by timeout.
To troubleshoot this situations I've added NWPathMonitor at my NEPacketTunnelProvider subclass:
pathMonitor?.pathUpdateHandler = { path in
logger.info("Path update: \(path)")
logger.info(" : \(path.availableInterfaces)")
}
On successful scenarios I observed logs:
14:53:19:829 Starting VPN tunnel...
14:53:19:895 Path update: satisfied (Path is satisfied), interface: en0[802.11], scoped, ipv4, ipv6, dns, uses wifi
14:53:19:899 : [en0]
14:53:22:237 Path update: satisfied (Path is satisfied), interface: en0[802.11], scoped, ipv4, ipv6, dns, uses wifi
14:53:22:253 : [en0, utun12]
14:53:22:325 VPN tunnel is started.
But if I start another tunnel first using OpenVPN (it's our corporate VPN) I observe failures with such log messages:
14:54:26:113 Starting VPN tunnel...
14:54:26:140 Path update: satisfied (Path is satisfied), interface: en0[802.11], scoped, ipv4, ipv6, dns, uses wifi
14:54:26:141 : [en0]
14:55:28:259 Failed to start VPN tunnel.
utun12 that was used by the extension in case of success is now occupied by the OpenVPN tunnel. The system creates utun13 for me but it feels like its misconfigured:
> ifconfig
(omitted most of the output)
utun12: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1500
inet 172.28.11.236 --> 172.28.10.1 netmask 0xfffffe00
nd6 options=201<PERFORMNUD,DAD>
utun13: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1500
options=6460<TSO4,TSO6,CHANNEL_IO,PARTIAL_CSUM,ZEROINVERT_CSUM>
Is it a system bug and what else can I do to diagnose the root cause of these failures?
Starting on macOS Sequoia, flows originated in Firefox have an empty sourceAppAuditToken. Other apps contain a valid token.
Background: in order to fetch process info for a certain NEFilterFlow, my content filter extension uses sourceAppAuditToken, audit_token_to_pid() and proc_* (as recommended in #126820). When that fails, we use SecCodeCopyGuestWithAttributes, recommended in some other thread as a better alternative. Both approaches break when the sourceAppAuditToken is empty since they need the pid.
Debugging:
My logging shows audit token is empty for Firefox
Typical logs from com.apple.networkextension also indicate it fails to fetch the same info I'm looking for:
com.apple.networkextension debug 11:22:07.024588-0300 Fetching appInfo from cache for pid: 948 uuid: 5C40B765-C6C9-3641-A822-2BC44D264361 bundle id: (null)
com.apple.networkextension debug 11:22:07.024657-0300 Calling delegate lookup handler with pid: 948, uuid: 5C40B765-C6C9-3641-A822-2BC44D264361, bundleID: (null)
com.apple.networkextension debug 11:22:07.025856-0300 Could not look up appInfo for pid: 948 bundle id: (null) uuid: 5C40B765-C6C9-3641-A822-2BC44D264361
com.apple.networkextension error 11:22:07.025897-0300 Could not find app info, return the original flow without filling in app info
Handling new flow:
identifier = D89B5B5D-793C-4940-D992-4E90F2AD1900
procPID = 953
eprocPID = 948
direction = outbound
inBytes = 0
outBytes = 0
signature = {length = 32, bytes = 0x4afeafde b484aa0c c5cb8698 0567343d ... 7cdee33e 135666dd }
socketID = 19adf2904e92d9
localEndpoint = 0.0.0.0:0
remoteEndpoint = 17.33.202.170:443
protocol = 6
family = 2
type = 1
procUUID = 0C68E603-967E-3643-B225-378BD2A655F7
eprocUUID = 5C40B765-C6C9-3641-A822-2BC44D264361
Perhaps there's a bug when generating the audit token or could it be something with the Firefox signature?
I double-checked Firefox and it seems fine:
$ codesign --verify --verbose /Applications/Firefox.app
/Applications/Firefox.app: valid on disk
/Applications/Firefox.app: satisfies its Designated Requirement
Not sure if relevant, but codesign with -dv showed different flags in CodeDirectory when compared to chrome:
codesign -dv /Applications/Firefox.app
...
CodeDirectory v=20500 size=863 flags=0x10000(runtime) hashes=18+5
...
Versus chrome
CodeDirectory v=20500 size=1821 flags=0x12a00(kill,restrict,library-validation,runtime) hashes=46+7 location=embedded
Hi,
I developed a system extension that uses the content filter providers of the network extension. When I am using a VPN, I turn on the network extension and the VPN is disconnected. Can this problem be avoided? How to prevent VPN disconnection
There could be a case where-in multiple transparent proxies might exist in the system (for ex., Cisco AnyConnect, GlobalProtect, etc).
We want to know if there is a way to order transparent proxies so that the desired transparent proxy gets the request first. During our research, we found a resource which talks about ordering transparent proxies through MDM.
https://developer.apple.com/documentation/devicemanagement/vpn/transparentproxy
Using this reference, we tried to create a profile and push it through JAMF. Below is the profile that we created and pushed with JAMF.
Property List -
<?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>TransparentProxy</key>
<array>
<dict>
<key>ProviderBundleIdentifier</key>
<string>com.paloaltonetworks.GlobalProtect.client.extension</string>
<key>Order</key>
<string>1</string>
</dict>
<dict>
<key>ProviderBundleIdentifier</key>
<string>com.cisco.anyconnect.macos.acsockext</string>
<key>Order</key>
<string>2</string>
</dict>
<dict>
<key>ProviderBundleIdentifier</key>
<string>com.mydomain.transparentproxy</string>
<key>Order</key>
<string>3</string>
</dict>
</array>
We are not sure if this is the right way to create the profile, though JAMF is not throwing any error while pushing this profile.
We see this profile on the local machine as "/Library/Managed Preferences/com.apple.networking.vpn-transparent-list.plist".
Is there a way to know if the profile took effect and the order of transparent proxies has changed.
Thanks in advance.
Hello Apple Developer Community,
I am currently working on a macOS project where my primary goal is to intercept IP packets, modify them (specifically the TCP payload), and then forward them. My intended use case involves selectively intercepting outgoing packets based on their destination IP, altering their content, and sending them on their way to the original destination.
What I’ve Tried:
NEAppProxyProvider:
• I explored using App Proxy Provider to handle new TCP and UDP flows.
• While it allowed me to read the data, handling direct packet modification and forwarding without creating a new connection or proxy setup proved challenging, especially for maintaining TCP state and handling TLS traffic.
System Extension with NEFilterPacketProvider:
• I considered NEFilterPacketProvider for intercepting and modifying network packets.
• However, the documentation implies that packet filtering only supports allow/block actions, not modification and reinjection of packets back into the system.
I am planning to try NEPacketTunnelProvider: But the documentation states that this is not the right use case. Packets are expected to go into the tunnel. Since I don't have any requirement to create and maintain a tunnel, this doesn't look like an option for me.
Transparent proxy setups like NETransparentProxyProvider do not appear to offer direct packet modification capabilities without involving a user-space proxy approach.
Implementing packet-level interception outside of the Network Extension framework (e.g., Network Kernel Extension) seems unsupported in newer macOS versions (Sequoia and later).
My Questions:
Is there a recommended approach or combination of Network Extension capabilities that would allow intercepting and modifying IP packets directly?
Can NEFilterPacketProvider or any other extension be utilized in a way to modify and reinject packets back into the system?
Are there any examples or sample projects that achieve similar functionality, possibly using a blend of Network Extension and lower-level networking frameworks?
I appreciate any insights or pointers to documentation or examples that could help achieve this.
Thanks and Regards.
Prasanna.
Hello there!
We have an app that connects to an external device via Wi-Fi to send and query content from it. This external device generates a hidden AP that the phone connects against. However, sometimes the app fails to connect to the external device with the system alert "Unable to join the network...".
We have been debugging for a couple but couldn't find any clear reason of why this thing is happening. What could be the reason behind this alert appearing?
For the connection, we are using the NEHotspotConfigurationManager to connect to the AP of this external device.
The configuration for the connection is the following:
NEHotspotConfiguration(
ssid: ssid,
passphrase: password,
isWEP: false
)
configuration.hidden = true
There are some logs that we extracted that show two connections.
One happened at 20:37, which was a successful connection.
wifi_logs_success 2.log
Another connection was made at 20:38, which failed.
wifi_logs_failure.log
Inspecting the logs, one difference that I see between them is the __WiFiDeviceManagerDispatchUserForcedAssociationCallback: result %lld, which in the successful case is 0 and in the failed case is 1.
Can anyone help with this? We're very lost on why this configuration could be an issue at all.