Network Extension

RSS for tag

Customize and extend the core networking features of iOS, iPad OS, and macOS using Network Extension.

Posts under Network Extension tag

200 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

NEFilterDataProvider.apply cause all tcp connection disconnected once
my content netfilter systemextension is like this: class FilterDataProvider: NEFilterDataProvider { override func startFilter(completionHandler: @escaping (Error?) -> Void) { let ipv4LocalHost = NWHostEndpoint(hostname: "127.0.0.1", port: "0") let ipv4LocalNetworkRule = NENetworkRule(remoteNetwork: ipv4LocalHost, remotePrefix: 0, localNetwork: ipv4LocalHost, localPrefix: 0, protocol: .any, direction: .any) let ipv4LocalFilterRule = NEFilterRule(networkRule: ipv4LocalNetworkRule, action: .filterData) let ipv6LocalHost = NWHostEndpoint(hostname: "::1", port: "0") let ipv6LocalNetworkRule = NENetworkRule(remoteNetwork: ipv6LocalHost, remotePrefix: 0, localNetwork: ipv6LocalHost, localPrefix: 0, protocol: .any, direction: .any) let ipv6LocalFilterRule = NEFilterRule(networkRule: ipv6LocalNetworkRule, action: .filterData) let normalNetworkRule = NENetworkRule(remoteNetwork: nil, remotePrefix: 0, localNetwork: nil, localPrefix: 0, protocol: .any, direction: .any) let normalFilterRule = NEFilterRule(networkRule: normalNetworkRule, action: .filterData) let filterSettings = NEFilterSettings(rules: [ipv4LocalFilterRule, ipv6LocalFilterRule, normalFilterRule], defaultAction: .filterData) apply(filterSettings) { error in completionHandler(error) if error != nil { log.error("Failed to apply filter settings [\(error!)]") } else { log.info("Start content filter successfully.") } } } override func handleNewFlow(_ flow: NEFilterFlow) -> NEFilterNewFlowVerdict { return .allow() } } when startFilter is called, all tcp connections disconnected, but i can connect again.
1
0
379
Aug ’23
VPN not working / ignored under Ventura 13.5
I'm implementing a VPN using the Network Extension Framework. I've recently noticed that our VPN was sometimes reporting to be connected, but when I checked my IP address it would be my public one. This was a drastic change of behavior that didn't seem to be associated with any specific change we have done recently. Originally I was trying to debug this issue in our App, but then I noticed that another VPN I'm using that's directly set up through System Settings in macOS (Ventura 13.5), and that is not running any of our code, is showing the same behavior. In this case the VPN was set up through System Settings as an IKEv2 VPN, so there's no 3rd party vendor code running - just macOS doing its thing. Both times I had this issue, the only thing that would fix it was rebooting the computer. When checking netstat -nr -f inet I noticed that the order of the default routes changed when the issue got resolved: When the VPN was connected but being ignored, the topmost route was en0, and the second route was ipsec. When the VPN was connected and working fine, the topmost route was ipsec, and the second route was en0. The same routing difference was visible for our own VPN network extension. Any thoughts about how I can debug this further? Given that this is not affecting only our VPN, but is also affecting an unrelated VPN managed by macOS it feels like it may be a macOS bug, but I'm not sure how to validate for that.
2
0
684
Aug ’23
Network Extension launching even on non Safari domains
We have configured VPN for Safari domains on iOS. Facebook.com is configured as Safari domain. So ideally VPN should be triggered when Facebook.com is opened. But we found that as soon as Safari is launched with any site, VPN icon appears although traffic is not sent to VPN. E.g. We opened Safari and opened cnn.com and it launched VPN.This gives end user feel that all Safari traffic is being processed. Our expectation is that VPN icon should display only for safari search domains. Is this expected as per Apple design or should I file a bug with Apple?
0
0
406
Aug ’23
iOS PacketTunnelProvider fails when using IPv6 DNS Server
I've implemented a PacketTunnelProvider for iOS. When I set an IPv4 address as the tunnel's DNS server, everything works as expected: all DNS queries from the device are sent through the tunnel. However, when I try to use an IPv6 address, no queries are sent (in fact, no IPv6 packets are sent at all) and the device is unable to resolve domain names. Here's the relevant code: let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "1.2.3.4") let settings4 = NEIPv4Settings(addresses: ["192.128.1.2"], subnetMasks: ["255.255.255.255"]) settings4.includedRoutes = [NEIPv4Route.default()] settings4.excludedRoutes = [] settings.ipv4Settings = settings4 let settings6 = NEIPv6Settings(addresses: ["2001:4860:123:456::"], networkPrefixLengths: [64]) settings6.includedRoutes = [NEIPv6Route.default()] settings6.excludedRoutes = [] settings.ipv6Settings = settings6 // If I use this DNS server, everything works normally //let dnsSettings = NEDNSSettings.init(servers: ["8.8.8.8"]) // With this DNS server, no DNS queries are sent through the tunnel let dnsSettings = NEDNSSettings.init(servers: ["2001:4860:4860::8888"]) dnsSettings.matchDomains = [""] settings.dnsSettings = dnsSettings
1
0
325
Aug ’23
Connecting IP Packets to Processes
Is there a way to find out which process an IP packet is going to or coming from? For example, I can examine each packet that comes and goes through the IP layer by using NEFilterPacketProvider. However, I want to know which process on the system is either expecting it or sent it. I don't want to use NEFilterDataProvider though. Or, is there a way to programmatically get all the open/listening socket/port information so that I can piece together the process with the parsed packet data? I can get a list of all the running processes, but I can't seem to link these two pieces together to fully examine the network.
5
0
524
Aug ’23
How to upstream DNS Request from virtual interface to physical interface?
We have implemented System Extension with the capability of Packet Tunnel Provider. Our Tunnel is full tunnel, so we are getting all packets for all traffic(DNS requests packets, app data packets). There are some DNS requests, we are not interested to resolve them. so we want to upstream these request to physical interface to resolve them. so how can we upstream DNS request from one interface to other interface?
1
0
366
Aug ’23
Two problems in the program compilation of the new version of xcode (the target code is the content filter of the network extension)
I'm trying to debug the official network extension sample code simplefirewall. Although it has been able to run normally and pops up user pop-up windows for the specified filter conditions, there are still two warnings and errors: [Window] Warning: Window NSWindow 0x1007315f0 ordered front from a non-active application and may order beneath the active application's windows. [default] CGSWindowShmemCreateWithPort failed on port 0 For the first warning, I followed the method given in https://developer.apple.com/forums/thread/729496 and added windo.makeKey() and window.orderFrontRegardless(), but this warning didn't go away. As for the second default, I haven't been able to find the corresponding root cause and solution of the problem. I would like to ask, can anyone give me some advice? Xcode:Version 14.3.1 (14E300c)
1
1
815
Aug ’23
SimpleFirewall not working after stop and restart
Although I was able to get simplefirewall to work, I still have a problem. When I start it for the first time (start button), every target traffic will be captured normally, but when I pause (stop button) and start again (start button), the same target traffic will not be captured. If I want it to work again, I need to stop it from xcode start the program again. What is the reason? Any suggestions?
7
1
746
Aug ’23
The ‘NEVPNProtocol.includeAllNetworks’ is not working on iOS 16+
https://developer.apple.com/documentation/networkextension/nevpnprotocol/3131931-includeallnetworks The ‘includeAllNetworks’ property was introduced in iOS 14 to allow VPN configuration on iOS to force all network traffic through the VPN tunnel, to prevent any leaks outside the tunnel. Older version of this document said:
 "A Boolean value that indicates whether the system sends all network traffic over the tunnel." Current documentation says: "A Boolean value that indicates whether the system sends most network traffic over the tunnel." There are a few issues with this change: The change in functionality was introduced without any notice or change in developer documentation. The documentation was updated almost a year after the change in functionality. The property should have been deprecated in iOS 16, and the new property should have been introduced. I would suggest a more accurate name - ‘includeMostNetworks’ instead of ‘includeAllNetworks’. After reading the updated documentation, it is not clear what the ‘includeAllNetworks’ actually does, as when it is disabled, the VPN also sends most network traffic over the tunnel. In iOS 16 and above, there is no way to configure a VPN tunnel without iOS bypassing the tunnel and leaking traffic to Apple servers.
1
0
412
Aug ’23
Is DNS-over-HTTPS or -TLS possible with system configuration settings when a NEFilterDataProvider is running/activated?
I'm trying to figure out how to enable DNS-over-HTTPS or -TLS on macOS 12 or later when a NEFilterDataProvider is activated. From what I'm observing, this can not be done using a configuration profile as the DNS Settings will then appear as not running or disabled in the Network/Filters pref pane (using a MDM or not). Correct me if I'm wrong but, from what I'm understanding in the last answer of this thread, Private Relay (Oblivious DoH?) would not work either. [Q] Is it possible to configure DNS-over-HTTPS or -TLS at the system level when a NEFilterDataProvider is activated? If it is, how is it supposed to be done?
4
0
1.7k
Aug ’23
Kernel seems to ignore packets written to utun interface
Hello, I am developing a VPN client that set up a utun network interface, then attach to it for reading / writing packets. The first thing I try to achieve is reading SYN TCP packets issued from local applications then craft / send RST packets in response. I was able to setup the utun interface with the IP address configuration and the associated route: ifconfig utun3 utun3: flags=8151<UP,POINTOPOINT,RUNNING,PROMISC,MULTICAST> mtu 1500 inet 44.10.0.1 --> 44.10.0.1 netmask 0xff000000 netstat -rn Destination Gateway Flags Netif Expire 44.10/16 44.10.0.1 UGSc utun3 44.10.0.1 44.10.0.1 UH utun3 My program is currently able to read packets from the utun3 interface. It seems it is also able to write out packets to the interface: Wireshark displays the packets generated. However, the kernel seems to ignore them. If I try a simple curl command : curl 44.10.0.240 The program correctly reads the SYN packet from the utun interface Wireshark displays the SYN packet My program generates and correctly writes a RST packet to the utun interface Wireshark displays the RST packet. No format error The curl program sent SYN packets again because it was not alerted of the connection reset. Note that if I try to listen on the interface with netcat, I am not able to accept connections: nc -l 44.10.0.1 8080 -> This works, and netcat is listening for connections curl 44.10.0.1:8080 -> This fails. Netcat never receives the request. Wireshark only displays SYN packets. No SYN/ACK are sent. This behavior does not appear on the loopback interface lo0. Is there something I am missing like a firewall or a network setting I should know?
1
0
356
Aug ’23
Unable to get local ip and port correctly
Why is the local ip and port obtained through localEndpoint 0.0.0.0:0 when handlenewflow (outbound flow), the remote ip and port are normal, and the local/remote ip and port for the inbound flow are normal. override func handleNewFlow(_ flow: NEFilterFlow) -> NEFilterNewFlowVerdict { guard let socketFlow = flow as? NEFilterSocketFlow, let remoteEndpoint = socketFlow.remoteEndpoint as? NWHostEndpoint, let localEndpoint = socketFlow.localEndpoint as? NWHostEndpoint else { return .allow() } os_log("Got a new flow with local endpoint %@, remote endpoint %@", localEndpoint, remoteEndpoint) let flowInfo = [ FlowInfoKey.localPort.rawValue: localEndpoint.port, FlowInfoKey.remoteAddress.rawValue: remoteEndpoint.hostname ] let flowInfo2 = [ FlowInfoKey2.localAddress.rawValue: localEndpoint.hostname, FlowInfoKey2.remotePort.rawValue: remoteEndpoint.port ] …………………… }
1
0
439
Aug ’23
macOS NEFilterDataProvider best practices?
I've seen some discussion around performance on the forums but nothing official. What is the best practice for [handleNewFlow:] , [handleOutboundDataFromFlow:], and [handleInboundDataFromFlow:] callbacks in a content filter? Are all flows funneled through a single serial queue that calls into my subclass? If so this seems like we are back in the days of early OS X with the kernel network funnel serializing all network traffic. Should I offload flow processing onto a concurrent queue and then pause the flow and return from my callback? Or just do all processing in the callbacks? And once I return an allow/deny verdict for the flow (without asking for more data) do I no longer see that flow's traffic in my content filter? That's what I would expect and it seems to be the case in actual practice too. For reference I never need to interact with the user. All of the rules are loaded from an EDR platform. I bring this up because we have users complaining of "stuttering" during Google Meet / Zoom, etc when our extension is active and from our perf metrics time spent in the callbacks are minimal (a few hundred usecs). But if all traffic is serialized through our content filter and the system is very busy I wonder if this could lead to dropped packets. What if multiple content filters are present? Are they all serialized with each other? Oof.
4
0
534
Aug ’23
DNSProxyProvider - High CPU usage
Hello everyone, I am currently experiencing an issue with a network extension that we've developed, which seems to be causing problems on a select number of machines. Problem Overview: Our extension is designed to analyze all DNS traffic and block access to suspicious domains. Most of the time, this works seamlessly. However, I've observed repeated log messages on a few machines that hint at some network-related problems. Accompanying these logs, I've also noticed occasional spikes in CPU usage. Logs: Below are the logs captured from the Console that are repeated over and over again: [C659 IPv6#3738d855.53 udp, attribution: developer] restart [C659 IPv6#3738d855.53 waiting parent-flow (unsatisfied (No network route), dns)] event: path:restart @14383.841s, uuid: C7F27BD5-E86F-4076-A03E-1BD6A9C4C405 [C659 IPv6#3738d855.53 waiting parent-flow (unsatisfied (No network route), dns)] event: path:unsatisfied @14383.841s, uuid: C7F27BD5-E86F-4076-A03E-1BD6A9C4C405 [C659 IPv6#3738d855.53 in_progress parent-flow (unsatisfied (No network route), dns)] event: flow:start_child @14383.841s nw_connection_report_state_with_handler_on_nw_queue [C659] reporting state preparing [C659.157 IPv6#3738d855.53 initial path ((null))] event: path:start @14383.841s [C659.157 IPv6#3738d855.53 waiting path (unsatisfied (No network route), dns)] event: path:unsatisfied @14383.842s, uuid: C7F27BD5-E86F-4076-A03E-1BD6A9C4C405 [C659.157 IPv6#3738d855.53 failed path (unsatisfied (No network route), dns)] event: null:null @14383.842s [C659 IPv6#3738d855.53 waiting parent-flow (unsatisfied (No network route), dns)] event: flow:child_failed @14383.842s nw_connection_report_state_with_handler_on_nw_queue [C659] reporting state waiting [C659 IPv6#3738d855.53 waiting parent-flow (unsatisfied (No network route), dns)] event: path:restart @14383.842s, uuid: C7F27BD5-E86F-4076-A03E-1BD6A9C4C405 [C659 IPv6#3738d855.53 udp, attribution: developer] restart Details & Observations: The high CPU usage appears randomly, and I haven't discerned any specific pattern. When CPU usage increase, the only way to go back to 0-0.3, is to restart the computer or restart the extension. A considerable amount of the above logs are generated over and over again, in the console, in a very short amount of time (in 15 seconds there are about ok 500k logs) Of the 600 machines using this extension, only 4 are exhibiting this issue. I've thoroughly checked the network configuration of the problematic machines, and I haven't found any disparities when compared to the ones working seamlessly. In cases where our extension can't determine if access to a specific domain should be blocked, we forward a request to our backend for verification. The code snippet used for this is: URLRequest(url: requestUrl) ... urlSession.dataTask(with: request)...resume(). Given that this method works perfectly on other machines, I'm inclined to believe this isn't the root issue. I'm reaching out to understand if anyone has encountered a similar problem or if there are any insights into what might be causing this. Any guidance or suggestions would be greatly appreciated. Also would be helpful if anyone can help me to break down the anatomy of the logs. Here is the main classes that handle the entire UDP flow, maybe you can spot any issue in the code. If I have to guess, a single flow fails, and then automatically tries to resolve over and over again, but I don't know how to add a counter for the number of retries. Thank you in advance for your assistance! PS: A ScreenShot from the console to see the times between logs: https://ibb.co/pvjVD89
4
0
400
Aug ’23
NEHotspotConfigurationManager.apply() is not triggering.
Whenever I turn off Wi-Fi in the Setting.app, NEHotspotConfigurationManager.apply() doesn't get triggered. If I restart my app, the apply function responds with Error Domain=NEHotspotConfigurationErrorDomain Code=8 "internal error." UserInfo={NSLocalizedDescription=internal error.} After restarting the device, this issue occurs again. I observed this issue on iOS 16.6, and I'm not sure if it's the same on other versions.
4
0
664
Aug ’23
[NETransparentProxyProvider] NEAppProxyUDPFlow.writeDatagrams sentByEndpoints ipv4 address will become "", ipv6 address can work.
Sorry, my English is not good. I use NETransparentProxyProvider to implement a global proxy program, and the tcp and udp connections will be passed to the remote proxy server by the TransparentProxy system extension. But now I have a problem, the package sent through NEAppProxyUDPFlow.writeDatagrams, when the address is ipv6, the normal program taken over by the proxy can correctly get the address of the udp package. But when the address is IPv4, the normal program taken over by the proxy can only get the source port number of the packet, and the obtained ip address will be blank. TransparentProxy system extension NEAppProxyUDPFlow.writeDatagrams code to send packets: // NWHostEndpoint *hostAddr = [NWHostEndpoint endpointWithHostname:@"::11:22:33:44" port:@"5566"]; NWHostEndpoint *hostAddr = [NWHostEndpoint endpointWithHostname:@"1.2.3.4" port:@"5566"]; NWEndpoint* addr = hostAddr; // _internalEndpoint NWOSAddressEndpoint * 0x151804ce0 0x0000000151804ce0 os_log(OS_LOG_DEFAULT, "[DEBUG] appproxy-test-LocalUdpConn(%{public}@)-writeLoop uFlow writeDatagrams addr:%{public}@ ",uuid,addr.debugDescription); [uFlow writeDatagrams:@[udpPack.data] sentByEndpoints:@[addr] completionHandler:^(NSError *error) { ... } TransparentProxy system extension log: [DEBUG] appproxy-test-LocalUdpConn(6B0C27A0-588E-4D2B-8544-AE927522DD25)-writeLoop uFlow writeDatagrams addr:1.2.3.4:5566 The log shows that the address should be 1.2.3.4:5566. But the ip address actually obtained by the local program taken over by the extension is empty, see below. Local udp test program: package main import ( "log" "net" ) func main() { l, err := net.ListenUDP("udp", &net.UDPAddr{ IP: net.IPv4(0, 0, 0, 0), Port: 0, Zone: "", }) if err != nil { panic(err) } defer l.Close() wData := []byte("0123456789") addr, err := net.ResolveUDPAddr("udp", "1.2.3.4:8088") if err != nil { panic(err) } for { log.Printf("Send a ping to %v...", addr) n, err := l.WriteTo(wData, addr) if err != nil { log.Printf("l.writeTo(%v), %v", addr, err) return } if n != len(wData) { log.Printf("%v!=%v", n, len(wData)) } buf := make([]byte, 1024) log.Printf("Receive pong...") n, rAddr, err := l.ReadFromUDP(buf) if err != nil { log.Printf("%v", err) return } log.Printf("rAddr:%v", rAddr) } } Local test program log: 2023/08/14 19:34:34 Send a ping to 1.2.3.4:8088... 2023/08/14 19:34:34 Receive pong... 2023/08/14 19:34:34 rAddr:[::]:5566 2023/08/14 19:34:34 Send a ping to 1.2.3.4:8088... 2023/08/14 19:34:34 Receive pong... 2023/08/14 19:34:34 rAddr:[::]:5566 2023/08/14 19:34:34 Send a ping to 1.2.3.4:8088... 2023/08/14 19:34:34 Receive pong... 2023/08/14 19:34:34 rAddr:[::]:5566 2023/08/14 19:34:34 Send a ping to 1.2.3.4:8088... 2023/08/14 19:34:34 Receive pong... After changing to IPv6 address, the ip address can be obtained normally. System extensions: NWHostEndpoint *hostAddr = [NWHostEndpoint endpointWithHostname:@"::11:22:33:44" port:@"5566"]; // NWHostEndpoint *hostAddr = [NWHostEndpoint endpointWithHostname:@"1.2.3.4" port:@"5566"]; Local test program log: 2023/08/14 19:43:27 Send a ping to 1.2.3.4:8088... 2023/08/14 19:43:27 Receive pong... 2023/08/14 19:43:27 rAddr:[::11:22:33:44]:5566 2023/08/14 19:43:27 Send a ping to 1.2.3.4:8088... 2023/08/14 19:43:27 Receive pong... 2023/08/14 19:43:27 rAddr:[::11:22:33:44]:5566 2023/08/14 19:43:27 Send a ping to 1.2.3.4:8088... 2023/08/14 19:43:27 Receive pong... 2023/08/14 19:43:27 rAddr:[::11:22:33:44]:5566 2023/08/14 19:43:27 Send a ping to 1.2.3.4:8088... 2023/08/14 19:43:27 Receive pong... It can be seen that when the address is an IPv6 address, the ip address can be obtained correctly. Where should this be the problem? How should it be corrected? Thank you so much.
2
0
318
Aug ’23
Per App Web Content Filter - No NEFilterBrowserFlow?
Since iOS 16 it is possible to use content filter on managed apps instead of supervised devices using the new ContentFilterUUID attribute. I built a simple test project for this and found that even when targeting browser apps, no flow in the data filter is NEFilterBrowserFlow and thus can be remediated with a blocking page. All received flows are socket flows. When changing the configuration via NEFilterManager to filterSockets=false and filterBrowsers=true nothing passes through the content filter. Is this by design? is there no way to show blocking pages using per app content filter?
4
0
533
Aug ’23
NEPacketTunnelNetworkSettings excludedRoutes not working for few ip's such as: 239.255.255.250
Hi, We are observing few NEPacketTunnelNetworkSettings excludedRoutes ip's in PacketTunnel even-though it is added in exclude routes. As you can see in network setting where we have added destinationAddress = 239.255.255.0 destinationSubnetMask = 255.255.255.0 in exclude route, still traffic of IP 239.255.255.250 coming to packet tunnel. We also observing other IP's traffic that is not added in include route such as: 20.192.170.9 //Network Settings for Packet Tunnel IPv4Settings = { configMethod = PPP addresses = ( 10.10.10.10, ) subnetMasks = ( 255.255.255.255, ) includedRoutes = ( { destinationAddress = 10.10.10.10 destinationSubnetMask = 255.255.255.255 gatewayAddress = 10.10.10.10 }, ) excludedRoutes = ( { destinationAddress = 192.168.0.0 destinationSubnetMask = 255.255.0.0 }, { destinationAddress = 10.0.0.0 destinationSubnetMask = 255.0.0.0 }, { destinationAddress = 127.0.0.1 destinationSubnetMask = 255.255.255.255 }, { destinationAddress = 172.16.0.0 destinationSubnetMask = 255.240.0.0 }, { destinationAddress = 239.255.255.0 destinationSubnetMask = 255.255.255.0 }, ) am i doing something wrong in setting NEPacketTunnelNetworkSettings?
4
1
784
Sep ’23
OSSystemExtensionRequest not superseding previous requests
I'm working on a VPN App that uses a NEPacketTunnelProvider system extension. On my computer, when sending out the first OSSystemExtensionRequest requesting that the extension is installed / activated, a system alert is shown to the user informing them that the extension installation was blocked. This is fine. Each time the user starts the process again (for whatever reason) we're sending out a new OSSystemExtensionRequest. And this is where it gets strange: On my computers (I've tried on my development and personal one) the previous request is immediately cancelled with a OSSystemExtensionErrorRequestSuperseded error and a new alert is shown. For everyone else trying this out, the previous request is not being cancelled at all and it seems like requests are silently piling up. Newly-sent requests do trigger the delegate's requestNeedsUserApproval(_:). But because they're piling up users are not shown a new system alert, breaking the UX. I guess I could evaluate if there's an existing request to avoid sending out a new one, but this is only supported in macOS 12+ through (propertiesRequest(forExtensionWithIdentifier:queue:)). My questions: Which of the above is the correct behaviour? Why could it be that only I am seeing a different behaviour?
2
0
454
Aug ’23