Networking

RSS for tag

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

Networking Documentation

Post

Replies

Boosts

Views

Activity

Sharing settings between processes and users
Hi everybody, what is recommended way to share settings (user defaults or any other way of storing preferences) between different processes with different ownership? For example we have a UI app, which runs from user, daemon and system extension which both run from root. How can we do some configuration on user level and read it in daemon/system extension safely, without providing some exploits. Bonus: how to observe changes in this scenario?
1
0
360
Sep ’23
Notes App with pdf
I have a problem with the Notes app on ios17. When I open a pdf file that I created from scanning a document with my iPhone 14, I can't select any text from the pdf. This makes it impossible to copy and paste anything from my pdf. Is anyone else having this issue?
2
0
323
Sep ’23
NEHotspotNetwork BSSID missing first character?
please consider this code: [NEHotspotNetwork fetchCurrentWithCompletionHandler:^(NEHotspotNetwork *network) { if (network) { DebugLog(@"Network ssid: %@, bssid: %@", network.SSID, network.BSSID); } else { DebugLog(@"No available network"); } }]; For me, I have a strange situation - say that the BSSID of my network is "01:34:56:78:90" the string in the property is missing the first character! what is contains (and is printed) is "1:34:56:78:90" - the leading "0" is missing. So, I was wondering if this is a know thing, or if perhaps it's only Asus (my router)? Or, am I doing something wrong? Pointers would be much appreciated.
2
0
419
Sep ’23
NWPathMonitor return .unsatisfied on iOS 17.*
I am using NWPathMonitor to check the connectivity status. let monitor = NWPathMonitor() monitor.pathUpdateHandler = { path in if path.status == .satisfied { print("Satisfied") } else { print("Not Satisfied") } } This method functioned properly before iOS 17. However, with iOS 17 and later versions, I notice the following log output: nw_path_evaluator_cancel [00000000-0000-0000-0000-000000000000] cancel Interestingly, this issue with MWPathMonitor only appears in my live app. I don't encounter any unusual behavior in Testflight or XCode. I'd appreciate any assistance on this matter.
1
0
353
Sep ’23
Excluding a single application from full tunnel packet tunnel.
We have a Developer Id signed VPN application using both NEPacketTunnelProvider and NEAppProxyProvider packaged as a single system extension. The requirement is for the application to implement a full tunnel VPN (has default route 0.0.0.0 on the utun interface) with the exception of another specific Developer Id signed application which needs its connections to bypass the tunnel. Originally, we attempted to use NETransparentProxyProvider to bypass the tunnel (for the single application) with the idea being to intercept the flows for the desired application in the transparent proxy and proxy these flows via a new NWConnection forced via the direct interface to bypass the tunnel. The problem we ran into was that the NEPacketTunnelProvider always get the packets before the NETranparentProxyProvider even though the proxy is started before the packet tunnel. So next attempt was to use NEAppProxyProvider with an NEAppRule set to capture flows for the specific application of interest. The good news is we get the application flows prior to the packet tunnel but the problem is the NEAppRule only seems to work for App Store signed applications, for example Safari. For Developer Id signed applications (for example Chrome) flows are actually blocked when an NEAppRule is added to the proxy configuration. This seems like a bug to me. The system log will show some messages about the http flow being blocked by policy. For the Safari case, when the NEAppRule is added we can see socket redirect policies added (system log). In the Developer Id signed apps there appears to be an error when OS is checking the apps certificate. What is the recommended way to implement our apps requirement? We have a full packet tunnel with the exception of a single, Developer Id signed, application.
6
0
595
Sep ’23
What CoreBluetooth physical layer?
We have a process in our iPhone app that uses CoreBluetooth to transfer a large amount of data over time using Bluetooth LE. Now I'm looking for ways to speed up this process. From what I have gathered, there is no way to set a preferred phyaical layer (PHY) for CoreBluetooth. How does iOS determine the best PHY to use? Is there any way I can influence it? I was not able to locate any documentation from Apple mentioning "physical layer" or "phy" for CoreBluetooth, only a brief GitHub Issue for a multiplatform networking library that discussed setting a "PreferredPhy" for iOS.
0
0
558
Sep ’23
NEFilterPacketProvider, NEFilterManager, and permission denied
As I mentioned elsewhere, I am trying to add a packet filter to our app. I can load load the extension, but I am getting permission denied when I try to save the preferences with it. I am building for release, using a Developer ID Application certificate (macOS, if that wasn't clear). I am starting to worry that I can't do this except on an MDM-managed system.
6
0
654
Oct ’23
How to commission a device to our fabric after adding it using Matter.Support
How to commission a device to our fabric after adding it using Matter.Support We have the following configuration: eero border router our own thermostat device that we are developing no home pod or home TV are used We have followed this guide https://developer.apple.com/documentation/mattersupport/adding-matter-support-to-your-ecosystem and implemented Matter Extension, as Matter.Framework is no more allowed to pair device. In Matter Extension the following callbacks are fired: override func selectThreadNetwork(from threadScanResults: [MatterAddDeviceExtensionRequestHandler.ThreadScanResult]) async throws -> MatterAddDeviceExtensionRequestHandler.ThreadNetworkAssociation override func commissionDevice(in home: MatterAddDeviceRequest.Home?, onboardingPayload: String, commissioningID: UUID) async throws In our demo app the following function completes without errors try await request.perform() The thermostat device seems to be successfully commissioned. In https://developer.apple.com/documentation/mattersupport/adding-matter-support-to-your-ecosystem there is a comment that says: Use Matter.Framework APIs to pair the accessory to your application with the provided onboardingPayload. How should this thing be done ? We tried to start the matter controller in the old way: func start() -> Bool { if (self.matterController == nil) { let storage = MatterStorage.shared let factory = MTRDeviceControllerFactory.sharedInstance() let factoryParams = MTRDeviceControllerFactoryParams(storage: storage) do { try factory.start(factoryParams) } catch { return false } let keys = FabricKeys() let params = MTRDeviceControllerStartupParams(signing: keys, fabricId: UInt64(fabricId), ipk: keys.ipk) params.vendorID = NSNumber(value: self.vendorId) self.matterController = try? factory.createController(onExistingFabric: params) let controllerNid = self.matterController?.controllerNodeID if (self.matterController == nil) { self.matterController = try? factory.createController(onNewFabric: params) } } return (self.matterController != nil) } Certificate are generated locally as in Matter Darwin example. We tried to call let params = MTRCommissioningParameters() matterController?.commissionNode(withID: NSNumber(value: self.deviceNid), commissioningParams: params) in commissionDevice of Matter Extension but we get error: Invalid object state.
1
0
829
Oct ’23
Different behaviour for IP packets when establishing connections from different targets.
We have a PacketTunnelProvider in a SystemExtension with split tunneling. We are configuring a private IP address range of 240.0.0.1/10 as included routes and specifying a few matching domains using NEPacketTunnelNetworkSettings. Once TunnelNetworkSettings has been applied successfully, a new utunx interface is created, and it includes routes for the 240.0.0.1/10 IP range. In our case, the interface name is utun3, where 'x' represents an integer value. According to our business logic, we need to establish connections with some IPs from this range. To achieve this, we are utilizing the NWConnection class API to create connections with IP addresses Like this func establishConnection() { // Specify the destination host and port let host = "240.0.0.19" let port = 80 // Create an NWHostEndpoint let endpoint = NWHostEndpoint(hostname: host, port: "\(port)") // Create an NWConnection let connection = NWConnection(to: endpoint, using: .tcp) connection.start(queue: .global()) } For the above code, we have observed different behaviour for IP packets when creating connections from different targets. In the first case, when we create a connection to the IP address 240.0.0.19 from the Main app target using the provided code, the IP packets correctly go through the utun3 interface because this address falls within the 240.0.0/10 range, which is part of the included routes. However, in the second case, when we use the same code to create a connection to 240.0.0.19 from the Extension target, the IP packets go through the primary interface en0 rather than the utun3 interface. **Question : ** Why do we have different behaviour for the same code? How can we achieve the same behaviour as the Main app target in the System Extension target? -- Thanks
9
0
738
Oct ’23
Sporadic EINVAL on writev syscall with nonblocking TCP socket
I'm experiencing sporadic EINVAL result when I call writev syscall with a nonblocking TCP socket. The error happens at this line of doctest I don't see any errors when I run this test in Linux container. The test sends a static string "test" compiled into binary. The tested runtime allocates io_vec structure with a single buffer inside a loop until the whole buffer is fully sent. The io slice is captured in a task future (the only one in the test) that is allocated on the heap by async executor. The future is desugared into a state machine that has scopes corresponding to async functions nested in the task future. Rust compiler drops the io slice in the end of send function scope. This happens after each successfully finished write (when syscall result is not EAGAIN). The runtime retries writev syscall when kqueue driver signals that the socket file descriptor is readable. I get the EINVAL error in about 25% of test runs. Environment: macOS Ventura 13.5.2, Intel CPU.
1
0
239
Oct ’23
Audit token provided by NEFilterDataProvider sometimes fails to provide code object with SecCodeCopyGuestWithAttributes
I'm using this code to get the path of an executable from the audit token provided in NEFilterDataProvider.handleNewFlow(_:), forwarded from the Network Extension to the main app via IPC: private func securePathFromAuditToken(_ auditToken: Data) throws -> String { let secFlags = SecCSFlags() var secCode: SecCode? var status = SecCodeCopyGuestWithAttributes(nil, [kSecGuestAttributeAudit: auditToken] as CFDictionary, secFlags, &secCode) guard let secCode = secCode else { throw NSError(domain: NSOSStatusErrorDomain, code: Int(status)) } var secStaticCode: SecStaticCode? status = SecCodeCopyStaticCode(secCode, secFlags, &secStaticCode) guard let secStaticCode = secStaticCode else { throw NSError(domain: NSOSStatusErrorDomain, code: Int(status)) } var url: CFURL? status = SecCodeCopyPath(secStaticCode, secFlags, &url) guard let url = url as URL? else { throw NSError(domain: NSOSStatusErrorDomain, code: Int(status)) } return url.path } This code sometimes returns paths like /System/Library/PrivateFrameworks/HelpData.framework/Versions/A/Resources/helpd or /Library/Developer/CoreSimulator/Volumes/iOS_21A328/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 17.0.simruntime/Contents/Resources/RuntimeRoot/usr/libexec/mobileassetd. But sometimes the SecCodeCopyGuestWithAttributes fails with status 100001 which is defined in MacErrors.h as kPOSIXErrorEPERM = 100001, /* Operation not permitted */. In these cases I resort to this code, which I have read is not as secure: private func insecurePathFromAuditToken(_ auditToken: Data) throws -> String? { if auditToken.count == MemoryLayout<audit_token_t>.size { let pid = auditToken.withUnsafeBytes { buffer in audit_token_to_pid(buffer.baseAddress!.assumingMemoryBound(to: audit_token_t.self).pointee) } let pathbuf = UnsafeMutablePointer<Int8>.allocate(capacity: Int(PROC_PIDPATHINFO_SIZE)) defer { pathbuf.deallocate() } let ret = proc_pidpath(pid, pathbuf, UInt32(PROC_PIDPATHINFO_SIZE)) if ret <= 0 { throw NSError(domain: NSPOSIXErrorDomain, code: Int(errno)) } return String(cString: pathbuf) } return nil } This insecure code then returns paths like /usr/libexec/trustd, /usr/libexec/rapportd, /usr/libexec/nsurlsessiond and /usr/libexec/timed. From what I can see, SecCodeCopyGuestWithAttributes fails for all processes in /usr/libexec. Some of these processes have executables with the same name placed in another directory, like /Library/Developer/CoreSimulator/Volumes/iOS_21A328/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 17.0.simruntime/Contents/Resources/RuntimeRoot/usr/libexec/mobileassetd for which it succeeds, while for /usr/libexec/mobileassetd it fails. Occasionally, both the secure and the insecure methods fail and in these cases the secure one returns status code 100003, which is defined as kPOSIXErrorESRCH = 100003, /* No such process */. When can this happen? This seems to happen with both NEFilterFlow.sourceAppAuditToken and sourceProcessAuditToken. What is the problem?
10
0
884
Oct ’23
Permission denied when installing Content Filter for individual-use Screen Time app
I'm using a Distribution-ready Family Controls Entitlement and it seems like I'm unable to save Content Filter configurations in my individual-use Screen Time app when I download a production build from TestFlight. For development builds, everything works fine. From nehelper: slowdown trying to create a content filter configuration through an app. Creating a content filter configuration is only allowed through profile in production version of slowdown. From the app: Failed to save configuration Slowdown: Error Domain=NEConfigurationErrorDomain Code=10 "permission denied" UserInfo={NSLocalizedDescription=permission denied} -[NEFilterManager saveToPreferencesWithCompletionHandler:]_block_invoke_3: failed to save the new configuration: Error Domain=NEFilterErrorDomain Code=5 "permission denied" UserInfo={NSLocalizedDescription=permission denied} TN3134 seems to suggest that Content Filters are allowed for Screen Time apps Platform: iOS, Packaged as: app extension, Minimum OS: 15.0, Restrictions: Screen Time apps TN3120 suggest the same: There are two ways to deploy a content filter on iOS. In a managed environment, use MDM to deploy a content filter to supervised devices. In an unmanaged environment, deploy your content filter as part of a Screen Time app. These technotes lead me to assume that this should be a supported use case. Any idea how to progress from here?
3
0
605
Oct ’23
Cannot connect with another computer over avahi
I installed Gentoo in virtual machine using Apple Virtualization framework. In linux then I installed avahi, configured the network in Bridge mode. Now I want to connect from this virtual machine to other computer in local network. I can see other computers on the local network, and connect with them using local IP address. But for some reason these are not detected using .local domain. I run avahi-browse -at|grep PS3 and it detected 4 entries for this computer: IPV4 _ssh._tcp local IPV6 _ssh._tcp local IPV4 _sftp-ssh._tcp local IPV6 _sftp-ssh._tcp local Also avahi-resolve -n PS3.local correctly detects IPv6 address of this machine. So why cannot I connect with the computer using PS3.local name?
1
0
718
Oct ’23
What's the advantage of applying settings with NEFilterDataProvider.apply(_:) over manually checking incoming network flows?
I cannot find in the documentation if using NEFilterDataProvider.apply(_:) has any advantage over manually inspecting incoming flows in handleNewFlow(_:) other than being a shortcut. Or are those rules guaranteed to be applied even if the network extension crashes or similar? If it has no practical advantages, then manually inspecting each flow allows to set up more flexible dynamic rules.
7
0
440
Oct ’23
VPN Watchguard broken after last beta?
Background I am struggling with dock freezes and other strange problems, so I have moved some Launch agents, and also did a reinstall of the latest beta. After that I can't open the WatchGuard application. As it is, I haven't used that VPN since the last beta update, so I am not sure if it's due to me moving files, or if it's actually the beta that broke this. Error What happens is that the Watchguard tries to open, but closes immediately. If I open the sh file that's inside the app package I get this: Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[NSViewController loadView] loaded the "(null)" nib but no view was set.' Test It's easy to test: Just download this app and see if it opens. https://cdn.watchguard.com/SoftwareCenter/Files/MUVPN_SSL/12_10/WG-MVPN-SSL_12_10.dmg Solution As it is now I don't know what to do. I have reinstalled the app with various versions to no avail. I removed ALL files that have anything to do with watchguard, and did an install after that. Same problem. I have cleaned all cache files, started up at another account on this Mac and tried to install from there. Same problem (This suggests that the fault actually is in the beta). I don't understand the error message or know what "NSInternalInconsistencyException" is. I guess the answer lies there. Any ideas?
4
0
320
Oct ’23
NWConnection.receive doesn't return expected data
I'm using an NWConnection to talk to a TCP endpoint. The connection steps are working fine and I'm able to receive some data, but not all the data I expect. I am posting to see if I misunderstand how the NWConnection is supposed to behave. The messages I want to receive have a header and a payload. The header tells me how many bytes are in the payload. To do that I am trying to call receive twice on the connection. The first receive looks something like connection.receive(minimumIncompleteLength: MessageHeader.PackedDataCount, maximumLength: MessageHeader.PackedDataCount) { … } The second receive call is very similar and tries to grab the payload. It looks something like: let payloadLength = messageHeader.payloadLength connection.receive(minimumIncompleteLength: payloadLength, maximumLength: payloadLength) { … } The first message sent by the server has the bytes [0x0F, 0x00, 0x01, 0x02]. The first three bytes are the header and indicate that the message type is 0x0F, of length 1 byte (0x0001) and the payload is one byte, 0x02. When I run my code, the first call to receive works fine. I get three of the four bytes sent by the server. The second call to receive, however, never returns the one remaining byte (the callback is never invoked). If I change the first receive call to ask for 1024 as a maximum length then I can see all 4 bytes from the server in the response so I know all the data I want was sent. But I can't receive it in two subsequent calls to the connection. Do I misunderstand the way that receive is supposed to behave? If the server sends four bytes, do I have to read them all in one call to receive?
2
0
420
Oct ’23
nesessionmanager sometimes not deallocating tunnel on VPN disconnect
We're seeing nessionmanager problems caused by having a configuration present on the system which. Has includeAllNetworks set in the protocol Was previously connected &amp; then disconnected After VPN disconnection we sometimes see that DNS and other things are not working. The VPN extension is no longer running, so I'd expect that settings would have been cleaned up, but they aren't in some cases. The system won't recover on its own, and when we delete the VPN configuration we see a set of messages from VPN session manager. There are two I've seen, on different systems. One shows the utun interface being cleaned up, and various network settings being removed. The other refers to deregistering an Enterprise VPN Session, [NESMVPNSession unsetDefaultDropAll], and IP Drop-All disabled. In both of these cases the cleanup is being done hours after the session was disconnected and the extension unloaded from memory. Does anyone know what exactly is happening there, and why the OS isn't cleaning up on disconnect?
7
0
782
Oct ’23
I want to use a QUIC stream with Swift's NWProtocolQUIC
I would like to use NWProtocolQUIC in Swift's Network.framework to prepare multiple QUIC Streams and send different data to the server for each. class QuicConnection { var acceptConnection: NWConnection? var openConnection: NWConnection? var acceptConnectionState: NWConnection.State? var openConnectionState: NWConnection.State? var receiveFromAcceptConnection: String? static func makeNWParameters() -> NWParameters { let options = NWProtocolQUIC.Options(alpn: ["echo"]) options.direction = .bidirectional let securityProtocolOptions: sec_protocol_options_t = options.securityProtocolOptions sec_protocol_options_set_verify_block(securityProtocolOptions, { (_: sec_protocol_metadata_t, _: sec_trust_t, complete: @escaping sec_protocol_verify_complete_t) in complete(true) }, DispatchQueue.main) return NWParameters(quic: options) } let group: NWConnectionGroup init() { print("init") let parameters = Self.makeNWParameters() let descriptor = NWMultiplexGroup(to: .hostPort(host: "192.168.0.20", port: 4242)) group = NWConnectionGroup(with: descriptor, using: parameters) //subscribe() group.stateUpdateHandler = { (state: NWConnectionGroup.State) in print("state: \(state)") switch state { case .ready: print("quic connected!") default: break } } group.newConnectionHandler = { [weak self] (connection: NWConnection) in print("new connection: \(connection)") self?.acceptConnection = connection self?.acceptConnection?.stateUpdateHandler = { [weak self] (state: NWConnection.State) in self?.acceptConnectionState = state } self?.subscribeAcceptConnection() self?.acceptConnection?.start(queue: DispatchQueue.main) } group.start(queue: DispatchQueue.main) } func createStream() { //guard let group else { return } let options = NWProtocolQUIC.Options() options.direction = .bidirectional let securityProtocolOptions: sec_protocol_options_t = options.securityProtocolOptions sec_protocol_options_set_verify_block(securityProtocolOptions, { (_: sec_protocol_metadata_t, _: sec_trust_t, complete: @escaping sec_protocol_verify_complete_t) in complete(true) // Insecure !!! }, DispatchQueue.main) openConnection = NWConnection(from: group) openConnectionState = openConnection?.state openConnection?.stateUpdateHandler = { [weak self] (state: NWConnection.State) in self?.openConnectionState = state print("state: \(state)") switch state { case .ready: print("stream connected!") DispatchQueue.main.asyncAfter(deadline: .now() + 2) { self?.send(message: "marker1") } default: break } } openConnection?.start(queue: DispatchQueue.main) } func send(message: String) { print("send start") let completion: NWConnection.SendCompletion = .contentProcessed { (error: Error?) in if let error = error { print("send error: \(error)") } else { print("send successful") } } openConnection?.send(content: message.data(using: .utf8)!, contentContext: .defaultMessage, isComplete: true, completion: completion) print("message: \(message)") } } When the app starts, it calls the init function of this QuicConnection class to create an instance and build the QUIC tunnel." quic connected" log appears, and when a specific action is performed in the app, the createStream function is called to put up a stream." stream connected" log is displayed, but when I then try to send data using the send function, the "send successful" message is displayed, but there is no output on the server side indicating that the message was received from the client. However, when I try to send data using the send function after that, I get a "send successful" message. I don't think there is a problem on the server side, because I can communicate well when only NWConnection is used without NQConnectionGroup. The server is using quic-go. I would like to borrow knowledge from those who have handled QUIC streams in Swift. Below are Apple's announcement and official documents that I referred to. I wrote the code referring to these, but even though I can connect the QUIC tunnels, I can not send data by setting up individual streams. https://developer.apple.com/videos/play/wwdc2021/10094/ https://developer.apple.com/documentation/network/nwprotocolquic
3
1
1.1k
Oct ’23