Post

Replies

Boosts

Views

Activity

Reply to NEAppProxyUDPFlow.writeDatagrams fails with "The datagram was too large" on macOS 15.x, macOS 26.x
Hi Quinn, Thanks a lot for the detailed explanation about NEAppProxyFlowErrorDatagramTooLarge and the flow’s max datagram size. You were absolutely right that the problem wasn’t the endpoint flavour but the flow not being fully opened yet when I started writing datagrams. I updated my handleNewFlow(_:) to explicitly await udpFlow.open(withLocalFlowEndpoint: nil) before connecting to the upstream and to gate writeDatagrams on a simple “flow opened” flag. After this change the error disappeared, and dig google.com now resolves successfully every time, including the 67‑byte responses that previously triggered “The datagram was too large”. Your pointers about when the max datagram size is established and how openWithLocalFlowEndpoint fits into that saved me a lot of time. Really appreciate your help. Best regards,
Apr ’26
Reply to NEAppProxyUDPFlow.writeDatagrams fails with "The datagram was too large" on macOS 15.x, macOS 26.x
Hi Quinn, I have an additional clarification about the logs from the target Mac, now that I’ve instrumented the code more precisely. On this machine I actually see two different behaviours for NEAppProxyUDPFlow.writeDatagrams: In the main DNS path (NEDNSProxyProvider → NEAppProxyUDPFlow → TCP upstream via SwiftNIO), writeDatagrams always fails with The datagram was too large, even for very small responses (for example 33, 50, 66, 67, 147, 193 bytes). The only writeDatagrams OK entries I see in the logs come from a separate passthrough handler that talks directly to a fallback DNS server (8.8.8.8) and uses a different code path. So, for the specific flow we are discussing (the proxy that forwards DNS over TCP to our upstream and then sends the response back to the client), writeDatagrams never succeeds on this Mac: every attempt ends with The datagram was too large, regardless of the actual payload size. This seems to match what you described about the subtle differences between endpoint types and how the deprecated APIs interact with the newer implementation under macOS 26.x, but from the app’s perspective the failure mode is effectively “100% repro” for this TCP‑upstream DNS path on this machine, while the passthrough path using the same NEAppProxyUDPFlow type can still succeed. If it would be useful, I can prepare a minimal sample based exactly on this working / non‑working split: one code path (passthrough) where writeDatagrams succeeds, and another (the TCP upstream DNS proxy) where the same API consistently fails on the same machine.
Apr ’26
Reply to NEAppProxyUDPFlow.writeDatagrams fails with "The datagram was too large" on macOS 15.x, macOS 26.x
Hi Quinn, Following up on your earlier advice about using NEAppProxyUDPFlowHandling and the async readDatagrams / writeDatagrams API. I’ve updated my DNS proxy as follows: I now implement NEAppProxyUDPFlowHandling and handle DNS over UDP via the async API. For each flow, I store the Network.NWEndpoint that comes from readDatagrams() and then pass that same endpoint back into writeDatagrams. I no longer use NWHostEndpoint / NetworkExtension.NWEndpoint anywhere in this path. Relevant code (stripped down): private func readFirstDatagrams(from udpFlow: NEAppProxyUDPFlow, into flow: Flow, channel: Channel) { Task { let (pairs, error) = await udpFlow.readDatagrams() if let error = error { // handle error... return } guard let pairs = pairs, !pairs.isEmpty else { // retry... return } let (firstData, firstEndpoint) = pairs[0] let size = firstData.count MainLogger.shared.log(message: "UDP recv \(pairs.count) datagrams, first size=\(size) from=\(firstEndpoint) type=\(type(of: firstEndpoint))" ) // Force a hostPort endpoint let hostPortEndpoint: Network.NWEndpoint switch firstEndpoint { case let .hostPort(host, port): hostPortEndpoint = .hostPort(host: host, port: port) default: let desc = firstEndpoint.debugDescription // e.g. "192.0.2.1:53" let parts = desc.components(separatedBy: ":") let portStr = parts.last ?? "53" let hostStr = parts.dropLast().joined(separator: ":") let host = Network.NWEndpoint.Host(hostStr) let port = Network.NWEndpoint.Port(portStr) ?? .init(rawValue: 53)! hostPortEndpoint = .hostPort(host: host, port: port) } MainLogger.shared.log(message: "FORCE endpoint hostPort=\(hostPortEndpoint) type=\(type(of: hostPortEndpoint))" ) flow.updateNetworkEndpoint(hostPortEndpoint) // Validate and send to upstream (TCP via SwiftNIO) // ... } } // Flow.sendResponseToSystem func sendResponseToSystem(_ data: Data) { guard let udpFlow = udpFlow else { return } guard let endpoint = networkEndpoint else { return } MainLogger.shared.log(message: "\(logPrefix) sendResponseToSystem: \(data.count) bytes → \(endpoint)" ) let preview = data.prefix(4).map { String(format: "%02X", $0) }.joined(separator: " ") MainLogger.shared.log(message: "\(logPrefix) data preview: \(preview)" ) MainLogger.shared.log(message: "\(logPrefix) endpoint type=\(type(of: endpoint)) desc=\(endpoint)" ) Task { do { try await udpFlow.writeDatagrams([(data, endpoint)]) MainLogger.shared.log(message: "\(logPrefix) writeDatagrams OK") } catch { MainLogger.shared.log(message: "\(logPrefix) writeDatagrams error: \(error.localizedDescription)" ) } } } On macOS 26.x (DNS proxy system extension), with this code I still consistently hit The datagram was too large on a small, valid DNS response (67 bytes). Here is a complete log for a single dig example.com flow, with upstream details anonymised: FLOW new from=com.apple.dig type=NEAppProxyUDPFlow remoteEndpoint=192.168.0.1:53 … upstream TCP connection to our DNS backend is established successfully … UDP recv 1 datagrams, first size=39 from=192.168.0.1:53 type=NWEndpoint ✅ FORCE endpoint hostPort=192.168.0.1:53 type=NWEndpoint ✅ ✅ Flow@… updateNetworkEndpoint=192.168.0.1:53 type=NWEndpoint ✅ DNS valid packet size=39, datagrams=1 → sendPackets … TCP write of the DNS query over the upstream connection … FlowChannelHandler: complete response 67 bytes → client ✅ ✅ Flow@… sendResponseToSystem: 67 bytes → 192.168.0.1:53 ✅ ⚠️ Flow@… data preview: 58 C8 81 80 ⚠️ // looks like a normal DNS answer ✅ Flow@… endpoint type=NWEndpoint desc=192.168.0.1:53 🆘 Flow@… writeDatagrams error: The datagram was too large 🆘 So, at this point: I’m using the async readDatagrams / writeDatagrams API. I store and reuse Network.NWEndpoint (a .hostPort endpoint), no NWHostEndpoint. The response is small (67 bytes) and looks like a valid DNS answer. Yet writeDatagrams([(data, endpoint)]) still fails with The datagram was too large. Is there any known issue or additional requirement for NEAppProxyUDPFlow.writeDatagrams on macOS 26.x that could explain this error in this configuration? Or is this something you’d like me to file as a bug with a sysdiagnose? Thanks in advance for any pointers.
Mar ’26
Reply to NEAppProxyUDPFlow.writeDatagrams fails with "The datagram was too large" on macOS 15.x, macOS 26.x
Hi Quinn, Thank you so much for the detailed explanation and the link to your NWEndpoint History and Advice post — that was exactly what we needed. Following your advice we: Adopted the NEAppProxyUDPFlowHandling protocol and implemented handleNewUDPFlow (_:initialRemoteFlowEndpoint:) Switched to the new Swift async readDatagrams() API which returns [(Data, Network.NWEndpoint)] Stored the Network.NWEndpoint directly without any conversion Used the new async writeDatagrams(_:) API passing the endpoint directly This resolved our long-standing "The datagram was too large" error which was caused by NWHostEndpoint internally creating an NWAddressEndpoint on macOS 15. We are currently testing the solution. Will report back with the final results. Thank you again for your time and expertise!
Mar ’26
Reply to Title: Developer ID + DNS Proxy system extension: profile mismatch for `com.apple.developer.networking.networkextension`
Update (MDM‑managed macOS 14.4 device): After some additional testing with our third‑party MDM, the Custom macOS app now does get installed via MDM (the notarized Developer ID PKG is assigned to a group with Install Method = MDM and Auto Deploy, and /Applications/MyProxy.app appears on the target Mac with the expected bundle id and version). However, on that MDM‑managed macOS 14.4 (Apple Silicon) device the app still cannot be launched. Finder shows a generic “MyProxy can’t be opened” error, and the process is killed immediately on launch. The key detail from the system log is that the decision is coming from the ConfigurationProfiles / MDM side rather than from Gatekeeper: taskgated-helper[…]: (ConfigurationProfiles) [com.apple.ManagedClient:ProvisioningProfiles] Disallowing com.myapp.agent.MyProxy because no eligible provisioning profiles found At the same time: spctl --assess -vvv -t exec /Applications/MyProxy.app reports source=Notarized Developer ID. codesign -dvv confirms the app is signed with our Developer ID Application certificate and has com.apple.developer.networking.networkextension = dns-proxy-systemextension, com.apple.developer.system-extension.install, sandbox, and app group entitlements only. The PKG is signed with Developer ID Installer, notarized with notarytool (status: Accepted), and passes pkgutil --check-signature. So on a non‑MDM machine the same notarized Developer ID PKG installs and the app launches and runs its DNS Proxy system extension successfully. On an MDM‑managed machine, the app installs via MDM but taskgated-helper (ConfigurationProfiles) blocks the launch with “no eligible provisioning profiles found”, as if a provisioning profile were required for these entitlements even though this is a Developer ID distribution. This leads to a follow‑up question for DTS: Is this behavior (ConfigurationProfiles / taskgated-helper requiring an “eligible provisioning profile” for a Developer ID app that has dns-proxy-systemextension entitlements and was delivered via MDM as a Custom macOS app) expected, or is it a bug in how macOS 14.x applies MDM/ConfigurationProfiles policy to Developer ID Network Extensions? If this is expected, any clarification on the intended model for deploying Developer ID DNS Proxy system extensions via MDM (in particular, whether MDM delivery is supposed to place additional provisioning‑profile‑like requirements on such apps) would be very helpful.
Feb ’26
Reply to Title: Developer ID + DNS Proxy system extension: profile mismatch for `com.apple.developer.networking.networkextension`
As a follow‑up for anyone hitting the same issue: Per Quinn’s advice, I switched to manual signing outside Xcode and followed the “Exporting a Developer ID Network Extension” guidance. The code signing / notarization side now looks correct and works locally: Host app and DNS Proxy system extension are both signed with Developer ID Application for our team (for example, TEAMID1234). com.apple.developer.networking.networkextension in both host and system extension entitlements uses `dns-proxy-systemextension. The app bundle identifier is com.myapp.agent.MyProxy. The installer pkg is signed with Developer ID Installer: MyApp Inc (TEAMID1234), notarized with notarytool (status: Accepted), stapled, and passes `pkgutil --check-signature. On the test Mac (macOS 14.4, Apple Silicon), sudo installer -pkg MyProxy_…pkg -target / succeeds, the app appears in/Applications, and spctl --assess -vvv -t exec reportssource=Notarized Developer ID`. The app launches and the DNS Proxy system extension runs (any remaining issues are now inside our Network Extension code, not related to installation). The remaining problem is MDM deployment (third‑party MDM): The notarized pkg is uploaded as a Custom macOS app (Delivery shows “MDM, Munki”). In the relevant group, the Install Method for this app is set to MDM; the device is not in any Munki assignment group and has no Munki client installed. Other macOS apps from the same group generate InstallApplication commands and install successfully on this device. This particular app (bundle id com.myapp.agent.MyProxy) never gets an InstallApplication / InstallEnterpriseApplication command for this Mac, despite the assignment being present. From the vendor’s description it appears to be evaluated as “NotApplicable” on their backend A System Extension Policy profile is present on the device, allowing our Team ID (e.g. TEAMID1234) and system extension bundle ID com.myapp.agent.MyProxy.dnsProxy for the Network extension type. Device‑level installation has been tested both enabled and disabled in the app settings; manual installation via installer works in both cases. So we effectively have: A Developer ID–signed, notarized pkg that installs and runs correctly when executed manually on the same Mac. A healthy MDM‑managed device that successfully installs other apps via InstallApplication. Only this one Developer ID DNS Proxy app being treated as “not applicable” for MDM installation. My questions for DTS / anyone familiar with the MDM side of Developer ID Network Extensions: Are there any additional constraints (beyond code signing and notarization) that could cause an MDM server to treat a notarized Developer ID pkg containing a dns-proxy-systemextension as NotApplicable on macOS 14.x Apple Silicon, even when the same pkg installs and runs correctly via installer? Are there any recommended pkg‑level metadata or structure requirements (minimum OS version, architecture filters, specific Info.plist keys, etc.) that MDM implementations are expected to enforce for Developer ID Network Extensions when deciding whether to send InstallApplication? Is there any Apple guidance or known limitation around using `InstallApplication with Developer ID DNS Proxy system extensions on macOS 14.x that MDM vendors should be following? Any pointers on how to verify that a given Developer ID DNS Proxy pkg is “MDM‑deployable” (beyond notarization and spctl) would be greatly appreciated.
Feb ’26
Reply to DNS Proxy system extension – OSSystemExtensionErrorDomain error 9 “validationFailed” on clean macOS machine
After switching to the new DNS Proxy system extension extension point, I’m seeing a mismatch between the current Info.plist on disk and what nesessionmanager reports during validation. Current Info.plist of the installed system extension: plutil -p "/Applications/MyMacProxy.app/Contents/Library/SystemExtensions/com.example.agent.MyMacProxy.dnsProxy.systemextension/Contents/Info.plist" { "CFBundleIdentifier" => "com.example.agent.MyMacProxy.dnsProxy" "CFBundlePackageType" => "SYSX" "NSExtension" => { "NSExtensionPointIdentifier" => "com.apple.dns-proxy" "NSExtensionPrincipalClass" => "com_example_agent_MyMacProxy_dnsProxy.DNSProxyProvider" } "NSSystemExtensionUsageDescription" => "SYSTEM_EXTENSION_USAGE_DESCRIPTION" ... } There is no NetworkExtension key in this Info.plist. However, when the host app tries to activate the DNS proxy system extension, I still get: Validating system extension com.example.agent.MyMacProxy.dnsProxy System Extension validation failed: Error Domain=NetworkExtensionErrorDomain Code=2 "The system extension com.example.agent.MyMacProxy.dnsProxy has an invalid NetworkExtension key in its Info.plist: the value for the NetworkExtension key must be a non-empty dictionary." Spotlight does not show any other copies of this bundle ID: mdfind 'kMDItemCFBundleIdentifier == "com.example.agent.MyMacProxy.dnsProxy"' no results Is there any known caching behaviour in nesessionmanager or in the NetworkExtension validation logic that could cause it to keep expecting a NetworkExtension dictionary, even when the current Info.plist only declares the com.apple.dns-proxy extension point?
Jan ’26
Reply to DNS Proxy system extension – OSSystemExtensionErrorDomain error 9 “validationFailed” on clean macOS machine
Thanks for the clarification about Developer ID vs Apple Development and for the links. Per your advice, I’ve switched both the host app and the DNS Proxy system extension to Apple Development signing and the legacy dns-proxy entitlement. Current setup macOS: 15.7.3 (24G419) Xcode: 26.2 (17C52) Host app bundle ID: com.example.agent.MyMacProxy DNS Proxy system extension bundle ID: com.example.agent.MyMacProxy.dnsProxy System extension entitlements: <key>com.apple.developer.networking.networkextension</key> <array> <string>dns-proxy</string> </array> System extension Info.plist (built .systemextension inside the host app): <key>NSExtension</key> <dict> <key>NSExtensionPointIdentifier</key> <string>com.apple.system_extension.network_extension</string> <key>NSExtensionPrincipalClass</key> <string>MyMacProxy.DNSProxyProvider</string> </dict> There is no NetworkExtension key in this Info.plist (confirmed with plutil -p on the built .systemextension in both DerivedData and /Applications). The system extension is embedded at: MyMacProxy.app/Contents/Library/SystemExtensions/com.example.agent.MyMacProxy.dnsProxy.systemextension The host app (from /Applications) configures the DNS Proxy via NEDNSProxyManager with: providerBundleIdentifier = "com.example.agent.MyMacProxy.dnsProxy" What happens If I add a NetworkExtension dictionary with NEProviderClasses and try different keys like: <key>NetworkExtension</key> <dict> <key>dns-proxy</key> <array> <string>MyMacProxy.DNSProxyProvider</string> </array> </dict> (or DNSProxy, or NEDNSProxy as the key), I consistently get Code=4 errors, for example: Validating system extension com.example.agent.MyMacProxy.dnsProxy System Extension validation failed: Error Domain=NetworkExtensionErrorDomain Code=4 "The system extension com.example.agent.MyMacProxy.dnsProxy has an invalid extension point in its NetworkExtension key in its Info.plist: dns-proxy." If I then remove the NetworkExtension dictionary entirely (leaving only the NSExtension dictionary shown above), the Code=4 error goes away, but nesessionmanager still reports Code=2 about NetworkExtension needing to be a non‑empty dictionary, even though that key is no longer present in the current Info.plist. To try to reset state, I’ve done the following: Remove standalone product, keep only embedded systemextension (reconfigured build to only embed) systemextensionsctl uninstall <TEAM_ID> com.example.agent.MyMacProxy.dnsProxy systemextensionsctl reset killall nesessionmanager killall systemextensionsd Reboot and reinstall host app into /Applications The behaviour does not change: either Code=4 if NetworkExtension is present, or Code=2 complaining about NetworkExtension even when it’s not in the current plist. Questions For a DNS Proxy implemented as a Network Extension system extension under Apple Development signing, is the intended pattern to have no NetworkExtension dictionary at all (only NSExtensionPointIdentifier = com.apple.system_extension.network_extension plus the dns-proxy entitlement), or should DNS Proxy system extensions still declare a NetworkExtension dictionary with NEProviderClasses? If a NetworkExtension dictionary is required, what are the currently valid keys for a DNS Proxy system extension? dns-proxy, DNSProxy, and NEDNSProxy all trigger NetworkExtensionErrorDomain Code=4 with “invalid extension point” in my tests. Do you have a minimal, known‑good DNS Proxy system extension sample (Info.plist + entitlements) that passes this validation on current macOS (15.7.3 / Xcode 26.2)? A small reference example would be extremely helpful to compare against my configuration. Share and Enjoy, and thanks again for your time!
Jan ’26
Reply to DNS Proxy system extension – OSSystemExtensionErrorDomain error 9 “validationFailed” on clean macOS machine
Thanks for the clarification about Developer ID vs Apple Development and for the links. Previously I started with Developer ID and the dns-proxy-systemextension entitlement, but per your advice I’ve now switched both the host app and the DNS Proxy system extension to Apple Development signing and the legacy dns-proxy value. Current Apple Development setup macOS: 15.7.3 (24G419) Xcode: 26.2 (17C52) Host: com.example.agent.MyMacProxy DNS Proxy system extension: com.example.agent.MyMacProxy.dnsProxy System extension entitlement: xml com.apple.developer.networking.networkextension dns-proxy System extension Info.plist (built .systemextension inside the host app): xml NSExtension NSExtensionPointIdentifier com.apple.system_extension.network_extension NSExtensionPrincipalClass MyMacProxy.DNSProxyProvider There is no NetworkExtension key in this plist (confirmed with plutil -p on the built .systemextension in both DerivedData and /Applications). The system extension is embedded at: MyMacProxy.app/Contents/Library/SystemExtensions/com.example.agent.MyMacProxy.dnsProxy.systemextension The host app (from /Applications) configures DNS Proxy via NEDNSProxyManager with: swift providerBundleIdentifier = "com.example.agent.MyMacProxy.dnsProxy" What happens If I add a NetworkExtension dictionary with NEProviderClasses and try different keys like: dns-proxy DNSProxy NEDNSProxy I consistently get Code=4 errors such as: text Validating system extension com.example.agent.MyMacProxy.dnsProxy System Extension validation failed: Error Domain=NetworkExtensionErrorDomain Code=4 "The system extension com.example.agent.MyMacProxy.dnsProxy has an invalid extension point in its NetworkExtension key in its Info.plist: dns-proxy." If I then remove the NetworkExtension dictionary entirely (leaving only the NSExtension dict shown above), Code=4 goes away, but nesessionmanager still reports Code=2 about NetworkExtension needing to be a non‑empty dictionary, even though that key is no longer present in the current Info.plist. I’ve tried: removing the standalone .systemextension product (keeping only the embedded one) systemextensionsctl uninstall com.example.agent.MyMacProxy.dnsProxy and systemextensionsctl reset killing nesessionmanager / systemextensionsd rebooting and reinstalling the host app into /Applications The behaviour doesn’t change. Questions For a DNS Proxy implemented as a Network Extension system extension under Apple Development signing, is the intended pattern to have no NetworkExtension dictionary at all (only NSExtensionPointIdentifier = com.apple.system_extension.network_extension plus the dns-proxy entitlement), or should DNS Proxy system extensions still declare a NetworkExtension dictionary with NEProviderClasses? If a NetworkExtension dictionary is required, what are the currently valid keys for a DNS Proxy system extension (given that dns-proxy, DNSProxy, and NEDNSProxy all trigger Code=4 for “invalid extension point”)? If you have a minimal, known‑good DNS Proxy system extension sample (Info.plist + entitlements) that passes this validation on current macOS, that would be extremely helpful as a reference.
Jan ’26
Reply to DNS Proxy system extension – OSSystemExtensionErrorDomain error 9 “validationFailed” on clean macOS machine
I updated the App ID for the DNS Proxy system extension and noticed that Developer Portal only exposes the legacy dns-proxy value under Network Extensions. There is no option for dns-proxy-systemextension. My extension’s entitlements currently contain: xml com.apple.developer.networking.networkextension dns-proxy-systemextension When I create a Mac App Development provisioning profile for this App ID and try to use it for signing the system extension target, Xcode fails with: Provisioning profile "Dev-Mac-App-DNSProxy" doesn't match the entitlements file's value for the com.apple.developer.networking.networkextension entitlement. So at this point the entitlements and the Developer Portal capabilities cannot be made to match: the profile only knows about dns-proxy, while my extension needs dns-proxy-systemextension. Is dns-proxy-systemextension the correct entitlement value for a DNS Proxy packaged as a system extension today, and if so, how should this be represented/configured in the Developer Portal so that the Mac App Development profile matches the entitlement?
Jan ’26
Reply to DNS Proxy system extension – OSSystemExtensionErrorDomain error 9 “validationFailed” on clean macOS machine
Thanks for the pointers and links. To answer your question: this is actually the first time I’m bringing up this NE system extension. I started directly with Developer ID because the final goal is MDM deployment, but I haven’t yet verified the setup with Apple Development signing. I’ll now switch both the host app and the DNS Proxy system extension to Apple Development signing, follow the “System Extension Hints” and “Debugging a Network Extension Provider” flow (post‑build copy to /Applications, run from there, first‑light log in main.swift, attach debugger, etc.), and see if the provider can be started successfully in that configuration. If I still get OSSystemExtensionErrorDomain error 9 / “extension category returned error” with Apple Development signing on a clean dev machine, I’ll update this thread with the exact steps, logs, and configuration.
Jan ’26
Reply to NEAppProxyUDPFlow.writeDatagrams fails with "The datagram was too large" on macOS 15.x, macOS 26.x
Hi Quinn, Thanks a lot for the detailed explanation about NEAppProxyFlowErrorDatagramTooLarge and the flow’s max datagram size. You were absolutely right that the problem wasn’t the endpoint flavour but the flow not being fully opened yet when I started writing datagrams. I updated my handleNewFlow(_:) to explicitly await udpFlow.open(withLocalFlowEndpoint: nil) before connecting to the upstream and to gate writeDatagrams on a simple “flow opened” flag. After this change the error disappeared, and dig google.com now resolves successfully every time, including the 67‑byte responses that previously triggered “The datagram was too large”. Your pointers about when the max datagram size is established and how openWithLocalFlowEndpoint fits into that saved me a lot of time. Really appreciate your help. Best regards,
Replies
Boosts
Views
Activity
Apr ’26
Reply to NEAppProxyUDPFlow.writeDatagrams fails with "The datagram was too large" on macOS 15.x, macOS 26.x
Hi Quinn, I have an additional clarification about the logs from the target Mac, now that I’ve instrumented the code more precisely. On this machine I actually see two different behaviours for NEAppProxyUDPFlow.writeDatagrams: In the main DNS path (NEDNSProxyProvider → NEAppProxyUDPFlow → TCP upstream via SwiftNIO), writeDatagrams always fails with The datagram was too large, even for very small responses (for example 33, 50, 66, 67, 147, 193 bytes). The only writeDatagrams OK entries I see in the logs come from a separate passthrough handler that talks directly to a fallback DNS server (8.8.8.8) and uses a different code path. So, for the specific flow we are discussing (the proxy that forwards DNS over TCP to our upstream and then sends the response back to the client), writeDatagrams never succeeds on this Mac: every attempt ends with The datagram was too large, regardless of the actual payload size. This seems to match what you described about the subtle differences between endpoint types and how the deprecated APIs interact with the newer implementation under macOS 26.x, but from the app’s perspective the failure mode is effectively “100% repro” for this TCP‑upstream DNS path on this machine, while the passthrough path using the same NEAppProxyUDPFlow type can still succeed. If it would be useful, I can prepare a minimal sample based exactly on this working / non‑working split: one code path (passthrough) where writeDatagrams succeeds, and another (the TCP upstream DNS proxy) where the same API consistently fails on the same machine.
Replies
Boosts
Views
Activity
Apr ’26
Reply to NEAppProxyUDPFlow.writeDatagrams fails with "The datagram was too large" on macOS 15.x, macOS 26.x
Hi Quinn, Following up on your earlier advice about using NEAppProxyUDPFlowHandling and the async readDatagrams / writeDatagrams API. I’ve updated my DNS proxy as follows: I now implement NEAppProxyUDPFlowHandling and handle DNS over UDP via the async API. For each flow, I store the Network.NWEndpoint that comes from readDatagrams() and then pass that same endpoint back into writeDatagrams. I no longer use NWHostEndpoint / NetworkExtension.NWEndpoint anywhere in this path. Relevant code (stripped down): private func readFirstDatagrams(from udpFlow: NEAppProxyUDPFlow, into flow: Flow, channel: Channel) { Task { let (pairs, error) = await udpFlow.readDatagrams() if let error = error { // handle error... return } guard let pairs = pairs, !pairs.isEmpty else { // retry... return } let (firstData, firstEndpoint) = pairs[0] let size = firstData.count MainLogger.shared.log(message: "UDP recv \(pairs.count) datagrams, first size=\(size) from=\(firstEndpoint) type=\(type(of: firstEndpoint))" ) // Force a hostPort endpoint let hostPortEndpoint: Network.NWEndpoint switch firstEndpoint { case let .hostPort(host, port): hostPortEndpoint = .hostPort(host: host, port: port) default: let desc = firstEndpoint.debugDescription // e.g. "192.0.2.1:53" let parts = desc.components(separatedBy: ":") let portStr = parts.last ?? "53" let hostStr = parts.dropLast().joined(separator: ":") let host = Network.NWEndpoint.Host(hostStr) let port = Network.NWEndpoint.Port(portStr) ?? .init(rawValue: 53)! hostPortEndpoint = .hostPort(host: host, port: port) } MainLogger.shared.log(message: "FORCE endpoint hostPort=\(hostPortEndpoint) type=\(type(of: hostPortEndpoint))" ) flow.updateNetworkEndpoint(hostPortEndpoint) // Validate and send to upstream (TCP via SwiftNIO) // ... } } // Flow.sendResponseToSystem func sendResponseToSystem(_ data: Data) { guard let udpFlow = udpFlow else { return } guard let endpoint = networkEndpoint else { return } MainLogger.shared.log(message: "\(logPrefix) sendResponseToSystem: \(data.count) bytes → \(endpoint)" ) let preview = data.prefix(4).map { String(format: "%02X", $0) }.joined(separator: " ") MainLogger.shared.log(message: "\(logPrefix) data preview: \(preview)" ) MainLogger.shared.log(message: "\(logPrefix) endpoint type=\(type(of: endpoint)) desc=\(endpoint)" ) Task { do { try await udpFlow.writeDatagrams([(data, endpoint)]) MainLogger.shared.log(message: "\(logPrefix) writeDatagrams OK") } catch { MainLogger.shared.log(message: "\(logPrefix) writeDatagrams error: \(error.localizedDescription)" ) } } } On macOS 26.x (DNS proxy system extension), with this code I still consistently hit The datagram was too large on a small, valid DNS response (67 bytes). Here is a complete log for a single dig example.com flow, with upstream details anonymised: FLOW new from=com.apple.dig type=NEAppProxyUDPFlow remoteEndpoint=192.168.0.1:53 … upstream TCP connection to our DNS backend is established successfully … UDP recv 1 datagrams, first size=39 from=192.168.0.1:53 type=NWEndpoint ✅ FORCE endpoint hostPort=192.168.0.1:53 type=NWEndpoint ✅ ✅ Flow@… updateNetworkEndpoint=192.168.0.1:53 type=NWEndpoint ✅ DNS valid packet size=39, datagrams=1 → sendPackets … TCP write of the DNS query over the upstream connection … FlowChannelHandler: complete response 67 bytes → client ✅ ✅ Flow@… sendResponseToSystem: 67 bytes → 192.168.0.1:53 ✅ ⚠️ Flow@… data preview: 58 C8 81 80 ⚠️ // looks like a normal DNS answer ✅ Flow@… endpoint type=NWEndpoint desc=192.168.0.1:53 🆘 Flow@… writeDatagrams error: The datagram was too large 🆘 So, at this point: I’m using the async readDatagrams / writeDatagrams API. I store and reuse Network.NWEndpoint (a .hostPort endpoint), no NWHostEndpoint. The response is small (67 bytes) and looks like a valid DNS answer. Yet writeDatagrams([(data, endpoint)]) still fails with The datagram was too large. Is there any known issue or additional requirement for NEAppProxyUDPFlow.writeDatagrams on macOS 26.x that could explain this error in this configuration? Or is this something you’d like me to file as a bug with a sysdiagnose? Thanks in advance for any pointers.
Replies
Boosts
Views
Activity
Mar ’26
Reply to NEAppProxyUDPFlow.writeDatagrams fails with "The datagram was too large" on macOS 15.x, macOS 26.x
Hi Quinn, Thank you so much for the detailed explanation and the link to your NWEndpoint History and Advice post — that was exactly what we needed. Following your advice we: Adopted the NEAppProxyUDPFlowHandling protocol and implemented handleNewUDPFlow (_:initialRemoteFlowEndpoint:) Switched to the new Swift async readDatagrams() API which returns [(Data, Network.NWEndpoint)] Stored the Network.NWEndpoint directly without any conversion Used the new async writeDatagrams(_:) API passing the endpoint directly This resolved our long-standing "The datagram was too large" error which was caused by NWHostEndpoint internally creating an NWAddressEndpoint on macOS 15. We are currently testing the solution. Will report back with the final results. Thank you again for your time and expertise!
Replies
Boosts
Views
Activity
Mar ’26
Reply to Title: Developer ID + DNS Proxy system extension: profile mismatch for `com.apple.developer.networking.networkextension`
Update (MDM‑managed macOS 14.4 device): After some additional testing with our third‑party MDM, the Custom macOS app now does get installed via MDM (the notarized Developer ID PKG is assigned to a group with Install Method = MDM and Auto Deploy, and /Applications/MyProxy.app appears on the target Mac with the expected bundle id and version). However, on that MDM‑managed macOS 14.4 (Apple Silicon) device the app still cannot be launched. Finder shows a generic “MyProxy can’t be opened” error, and the process is killed immediately on launch. The key detail from the system log is that the decision is coming from the ConfigurationProfiles / MDM side rather than from Gatekeeper: taskgated-helper[…]: (ConfigurationProfiles) [com.apple.ManagedClient:ProvisioningProfiles] Disallowing com.myapp.agent.MyProxy because no eligible provisioning profiles found At the same time: spctl --assess -vvv -t exec /Applications/MyProxy.app reports source=Notarized Developer ID. codesign -dvv confirms the app is signed with our Developer ID Application certificate and has com.apple.developer.networking.networkextension = dns-proxy-systemextension, com.apple.developer.system-extension.install, sandbox, and app group entitlements only. The PKG is signed with Developer ID Installer, notarized with notarytool (status: Accepted), and passes pkgutil --check-signature. So on a non‑MDM machine the same notarized Developer ID PKG installs and the app launches and runs its DNS Proxy system extension successfully. On an MDM‑managed machine, the app installs via MDM but taskgated-helper (ConfigurationProfiles) blocks the launch with “no eligible provisioning profiles found”, as if a provisioning profile were required for these entitlements even though this is a Developer ID distribution. This leads to a follow‑up question for DTS: Is this behavior (ConfigurationProfiles / taskgated-helper requiring an “eligible provisioning profile” for a Developer ID app that has dns-proxy-systemextension entitlements and was delivered via MDM as a Custom macOS app) expected, or is it a bug in how macOS 14.x applies MDM/ConfigurationProfiles policy to Developer ID Network Extensions? If this is expected, any clarification on the intended model for deploying Developer ID DNS Proxy system extensions via MDM (in particular, whether MDM delivery is supposed to place additional provisioning‑profile‑like requirements on such apps) would be very helpful.
Replies
Boosts
Views
Activity
Feb ’26
Reply to Title: Developer ID + DNS Proxy system extension: profile mismatch for `com.apple.developer.networking.networkextension`
As a follow‑up for anyone hitting the same issue: Per Quinn’s advice, I switched to manual signing outside Xcode and followed the “Exporting a Developer ID Network Extension” guidance. The code signing / notarization side now looks correct and works locally: Host app and DNS Proxy system extension are both signed with Developer ID Application for our team (for example, TEAMID1234). com.apple.developer.networking.networkextension in both host and system extension entitlements uses `dns-proxy-systemextension. The app bundle identifier is com.myapp.agent.MyProxy. The installer pkg is signed with Developer ID Installer: MyApp Inc (TEAMID1234), notarized with notarytool (status: Accepted), stapled, and passes `pkgutil --check-signature. On the test Mac (macOS 14.4, Apple Silicon), sudo installer -pkg MyProxy_…pkg -target / succeeds, the app appears in/Applications, and spctl --assess -vvv -t exec reportssource=Notarized Developer ID`. The app launches and the DNS Proxy system extension runs (any remaining issues are now inside our Network Extension code, not related to installation). The remaining problem is MDM deployment (third‑party MDM): The notarized pkg is uploaded as a Custom macOS app (Delivery shows “MDM, Munki”). In the relevant group, the Install Method for this app is set to MDM; the device is not in any Munki assignment group and has no Munki client installed. Other macOS apps from the same group generate InstallApplication commands and install successfully on this device. This particular app (bundle id com.myapp.agent.MyProxy) never gets an InstallApplication / InstallEnterpriseApplication command for this Mac, despite the assignment being present. From the vendor’s description it appears to be evaluated as “NotApplicable” on their backend A System Extension Policy profile is present on the device, allowing our Team ID (e.g. TEAMID1234) and system extension bundle ID com.myapp.agent.MyProxy.dnsProxy for the Network extension type. Device‑level installation has been tested both enabled and disabled in the app settings; manual installation via installer works in both cases. So we effectively have: A Developer ID–signed, notarized pkg that installs and runs correctly when executed manually on the same Mac. A healthy MDM‑managed device that successfully installs other apps via InstallApplication. Only this one Developer ID DNS Proxy app being treated as “not applicable” for MDM installation. My questions for DTS / anyone familiar with the MDM side of Developer ID Network Extensions: Are there any additional constraints (beyond code signing and notarization) that could cause an MDM server to treat a notarized Developer ID pkg containing a dns-proxy-systemextension as NotApplicable on macOS 14.x Apple Silicon, even when the same pkg installs and runs correctly via installer? Are there any recommended pkg‑level metadata or structure requirements (minimum OS version, architecture filters, specific Info.plist keys, etc.) that MDM implementations are expected to enforce for Developer ID Network Extensions when deciding whether to send InstallApplication? Is there any Apple guidance or known limitation around using `InstallApplication with Developer ID DNS Proxy system extensions on macOS 14.x that MDM vendors should be following? Any pointers on how to verify that a given Developer ID DNS Proxy pkg is “MDM‑deployable” (beyond notarization and spctl) would be greatly appreciated.
Replies
Boosts
Views
Activity
Feb ’26
Reply to DNS Proxy system extension – OSSystemExtensionErrorDomain error 9 “validationFailed” on clean macOS machine
After switching to the new DNS Proxy system extension extension point, I’m seeing a mismatch between the current Info.plist on disk and what nesessionmanager reports during validation. Current Info.plist of the installed system extension: plutil -p "/Applications/MyMacProxy.app/Contents/Library/SystemExtensions/com.example.agent.MyMacProxy.dnsProxy.systemextension/Contents/Info.plist" { "CFBundleIdentifier" => "com.example.agent.MyMacProxy.dnsProxy" "CFBundlePackageType" => "SYSX" "NSExtension" => { "NSExtensionPointIdentifier" => "com.apple.dns-proxy" "NSExtensionPrincipalClass" => "com_example_agent_MyMacProxy_dnsProxy.DNSProxyProvider" } "NSSystemExtensionUsageDescription" => "SYSTEM_EXTENSION_USAGE_DESCRIPTION" ... } There is no NetworkExtension key in this Info.plist. However, when the host app tries to activate the DNS proxy system extension, I still get: Validating system extension com.example.agent.MyMacProxy.dnsProxy System Extension validation failed: Error Domain=NetworkExtensionErrorDomain Code=2 "The system extension com.example.agent.MyMacProxy.dnsProxy has an invalid NetworkExtension key in its Info.plist: the value for the NetworkExtension key must be a non-empty dictionary." Spotlight does not show any other copies of this bundle ID: mdfind 'kMDItemCFBundleIdentifier == "com.example.agent.MyMacProxy.dnsProxy"' no results Is there any known caching behaviour in nesessionmanager or in the NetworkExtension validation logic that could cause it to keep expecting a NetworkExtension dictionary, even when the current Info.plist only declares the com.apple.dns-proxy extension point?
Replies
Boosts
Views
Activity
Jan ’26
Reply to DNS Proxy system extension – OSSystemExtensionErrorDomain error 9 “validationFailed” on clean macOS machine
Thanks for the clarification about Developer ID vs Apple Development and for the links. Per your advice, I’ve switched both the host app and the DNS Proxy system extension to Apple Development signing and the legacy dns-proxy entitlement. Current setup macOS: 15.7.3 (24G419) Xcode: 26.2 (17C52) Host app bundle ID: com.example.agent.MyMacProxy DNS Proxy system extension bundle ID: com.example.agent.MyMacProxy.dnsProxy System extension entitlements: <key>com.apple.developer.networking.networkextension</key> <array> <string>dns-proxy</string> </array> System extension Info.plist (built .systemextension inside the host app): <key>NSExtension</key> <dict> <key>NSExtensionPointIdentifier</key> <string>com.apple.system_extension.network_extension</string> <key>NSExtensionPrincipalClass</key> <string>MyMacProxy.DNSProxyProvider</string> </dict> There is no NetworkExtension key in this Info.plist (confirmed with plutil -p on the built .systemextension in both DerivedData and /Applications). The system extension is embedded at: MyMacProxy.app/Contents/Library/SystemExtensions/com.example.agent.MyMacProxy.dnsProxy.systemextension The host app (from /Applications) configures the DNS Proxy via NEDNSProxyManager with: providerBundleIdentifier = "com.example.agent.MyMacProxy.dnsProxy" What happens If I add a NetworkExtension dictionary with NEProviderClasses and try different keys like: <key>NetworkExtension</key> <dict> <key>dns-proxy</key> <array> <string>MyMacProxy.DNSProxyProvider</string> </array> </dict> (or DNSProxy, or NEDNSProxy as the key), I consistently get Code=4 errors, for example: Validating system extension com.example.agent.MyMacProxy.dnsProxy System Extension validation failed: Error Domain=NetworkExtensionErrorDomain Code=4 "The system extension com.example.agent.MyMacProxy.dnsProxy has an invalid extension point in its NetworkExtension key in its Info.plist: dns-proxy." If I then remove the NetworkExtension dictionary entirely (leaving only the NSExtension dictionary shown above), the Code=4 error goes away, but nesessionmanager still reports Code=2 about NetworkExtension needing to be a non‑empty dictionary, even though that key is no longer present in the current Info.plist. To try to reset state, I’ve done the following: Remove standalone product, keep only embedded systemextension (reconfigured build to only embed) systemextensionsctl uninstall <TEAM_ID> com.example.agent.MyMacProxy.dnsProxy systemextensionsctl reset killall nesessionmanager killall systemextensionsd Reboot and reinstall host app into /Applications The behaviour does not change: either Code=4 if NetworkExtension is present, or Code=2 complaining about NetworkExtension even when it’s not in the current plist. Questions For a DNS Proxy implemented as a Network Extension system extension under Apple Development signing, is the intended pattern to have no NetworkExtension dictionary at all (only NSExtensionPointIdentifier = com.apple.system_extension.network_extension plus the dns-proxy entitlement), or should DNS Proxy system extensions still declare a NetworkExtension dictionary with NEProviderClasses? If a NetworkExtension dictionary is required, what are the currently valid keys for a DNS Proxy system extension? dns-proxy, DNSProxy, and NEDNSProxy all trigger NetworkExtensionErrorDomain Code=4 with “invalid extension point” in my tests. Do you have a minimal, known‑good DNS Proxy system extension sample (Info.plist + entitlements) that passes this validation on current macOS (15.7.3 / Xcode 26.2)? A small reference example would be extremely helpful to compare against my configuration. Share and Enjoy, and thanks again for your time!
Replies
Boosts
Views
Activity
Jan ’26
Reply to DNS Proxy system extension – OSSystemExtensionErrorDomain error 9 “validationFailed” on clean macOS machine
Thanks for the clarification about Developer ID vs Apple Development and for the links. Previously I started with Developer ID and the dns-proxy-systemextension entitlement, but per your advice I’ve now switched both the host app and the DNS Proxy system extension to Apple Development signing and the legacy dns-proxy value. Current Apple Development setup macOS: 15.7.3 (24G419) Xcode: 26.2 (17C52) Host: com.example.agent.MyMacProxy DNS Proxy system extension: com.example.agent.MyMacProxy.dnsProxy System extension entitlement: xml com.apple.developer.networking.networkextension dns-proxy System extension Info.plist (built .systemextension inside the host app): xml NSExtension NSExtensionPointIdentifier com.apple.system_extension.network_extension NSExtensionPrincipalClass MyMacProxy.DNSProxyProvider There is no NetworkExtension key in this plist (confirmed with plutil -p on the built .systemextension in both DerivedData and /Applications). The system extension is embedded at: MyMacProxy.app/Contents/Library/SystemExtensions/com.example.agent.MyMacProxy.dnsProxy.systemextension The host app (from /Applications) configures DNS Proxy via NEDNSProxyManager with: swift providerBundleIdentifier = "com.example.agent.MyMacProxy.dnsProxy" What happens If I add a NetworkExtension dictionary with NEProviderClasses and try different keys like: dns-proxy DNSProxy NEDNSProxy I consistently get Code=4 errors such as: text Validating system extension com.example.agent.MyMacProxy.dnsProxy System Extension validation failed: Error Domain=NetworkExtensionErrorDomain Code=4 "The system extension com.example.agent.MyMacProxy.dnsProxy has an invalid extension point in its NetworkExtension key in its Info.plist: dns-proxy." If I then remove the NetworkExtension dictionary entirely (leaving only the NSExtension dict shown above), Code=4 goes away, but nesessionmanager still reports Code=2 about NetworkExtension needing to be a non‑empty dictionary, even though that key is no longer present in the current Info.plist. I’ve tried: removing the standalone .systemextension product (keeping only the embedded one) systemextensionsctl uninstall com.example.agent.MyMacProxy.dnsProxy and systemextensionsctl reset killing nesessionmanager / systemextensionsd rebooting and reinstalling the host app into /Applications The behaviour doesn’t change. Questions For a DNS Proxy implemented as a Network Extension system extension under Apple Development signing, is the intended pattern to have no NetworkExtension dictionary at all (only NSExtensionPointIdentifier = com.apple.system_extension.network_extension plus the dns-proxy entitlement), or should DNS Proxy system extensions still declare a NetworkExtension dictionary with NEProviderClasses? If a NetworkExtension dictionary is required, what are the currently valid keys for a DNS Proxy system extension (given that dns-proxy, DNSProxy, and NEDNSProxy all trigger Code=4 for “invalid extension point”)? If you have a minimal, known‑good DNS Proxy system extension sample (Info.plist + entitlements) that passes this validation on current macOS, that would be extremely helpful as a reference.
Replies
Boosts
Views
Activity
Jan ’26
Reply to DNS Proxy system extension – OSSystemExtensionErrorDomain error 9 “validationFailed” on clean macOS machine
I updated the App ID for the DNS Proxy system extension and noticed that Developer Portal only exposes the legacy dns-proxy value under Network Extensions. There is no option for dns-proxy-systemextension. My extension’s entitlements currently contain: xml com.apple.developer.networking.networkextension dns-proxy-systemextension When I create a Mac App Development provisioning profile for this App ID and try to use it for signing the system extension target, Xcode fails with: Provisioning profile "Dev-Mac-App-DNSProxy" doesn't match the entitlements file's value for the com.apple.developer.networking.networkextension entitlement. So at this point the entitlements and the Developer Portal capabilities cannot be made to match: the profile only knows about dns-proxy, while my extension needs dns-proxy-systemextension. Is dns-proxy-systemextension the correct entitlement value for a DNS Proxy packaged as a system extension today, and if so, how should this be represented/configured in the Developer Portal so that the Mac App Development profile matches the entitlement?
Replies
Boosts
Views
Activity
Jan ’26
Reply to DNS Proxy system extension – OSSystemExtensionErrorDomain error 9 “validationFailed” on clean macOS machine
Thanks for the pointers and links. To answer your question: this is actually the first time I’m bringing up this NE system extension. I started directly with Developer ID because the final goal is MDM deployment, but I haven’t yet verified the setup with Apple Development signing. I’ll now switch both the host app and the DNS Proxy system extension to Apple Development signing, follow the “System Extension Hints” and “Debugging a Network Extension Provider” flow (post‑build copy to /Applications, run from there, first‑light log in main.swift, attach debugger, etc.), and see if the provider can be started successfully in that configuration. If I still get OSSystemExtensionErrorDomain error 9 / “extension category returned error” with Apple Development signing on a clean dev machine, I’ll update this thread with the exact steps, logs, and configuration.
Replies
Boosts
Views
Activity
Jan ’26