Hello, I was referring to the post - https://developer.apple.com/forums/thread/663769 to determine if my app has been granted access to Local Network or not. I am starting an NWConnection for a local network address and checking if the currentPath?.unsatisfiedReason == .localNetworkDenied. This is not working as expected.
Even when I accept the local network permission prompt, I still get the unsatisfied reason as .localNetworkDenied. I have also tried turning off/on the permission toggle from the settings app. I have also checked this with the 2nd method in the above post about using pathUpdateHandler and getting the same results. I am using an iOS 17.4.1 device.
Is this method reliable? Is there some other method/api that I can use to check for local network access in my app?
Networking
RSS for tagExplore the networking protocols and technologies used by the device to connect to Wi-Fi networks, Bluetooth devices, and cellular data services.
Post
Replies
Boosts
Views
Activity
I've implemented a NEPacketTunnelProvider implementation, but I can't see any packets in packet flow. Here is the settings
override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) {
...
let networkSettings = self.initTunnelSettings()
setTunnelNetworkSettings(networkSettings) { (error) in
if let error = error {
completionHandler(error)
return
}
NSLog("Proxy address: \(networkSettings.proxySettings?.httpsServer?.address)")
self.readPackets()
completionHandler(nil)
}
private func initTunnelSettings() -> NEPacketTunnelNetworkSettings {
let settings: NEPacketTunnelNetworkSettings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "85.182.68.10")
/* ipv4 settings */
settings.ipv4Settings = NEIPv4Settings(addresses: ["1.2.3.4"], subnetMasks: ["255.255.255.255"])
settings.ipv4Settings?.includedRoutes = [NEIPv4Route.default()]
/* MTU */
settings.mtu = 1500
return settings
}
There is even more strange thing.
If I add more specific route into includedRoutes array, I can see packets from that route traffic
settings.ipv4Settings?.includedRoutes = [NEIPv4Route.default(), NEIPv4Route(destinationAddress: "192.168.0.103", subnetMask: "255.255.255.252")]
With this changes I will see packets with the destination IP "192.168.0.103", but if change mask to 255.255.255.0 no packet in the packet flow again
settings.ipv4Settings?.includedRoutes = [NEIPv4Route.default(), NEIPv4Route(destinationAddress: "192.168.0.103", subnetMask: "255.255.255.0")]
Anyway my goal is to route all traffic through virtual interface and get all packets in the packetFlow.
Can you help me? What should I change?
This app has crashed because it attempted to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSBluetoothAlwaysUsageDescription key with a string value explaining to the user how the app uses this data.
I don't know how to add these permissions when i can't find plist files. It is not when any tutorial or document says it is
I work on an app that includes a network extension. The app is essentially just to activate the extension, and the extension typically has long-running background sessions. Analyzing/monitoring metrics for the network extension is very important for us. However, in the Xcode Organizer screen, only the app itself is shown in the drop down menu - the associated network extension is not an option.
For Xcode Organizer screens like Termination metrics and Battery Usage metrics, does the app's background metrics include the network extension, or just the app itself? If just the app, is there any way to get these metrics for the network extension?
Description:
I am experiencing a persistent issue with establishing a VPN connection through a custom app I've developed using Swift. While the VPN configuration appears to be loaded successfully, attempts to connect result in immediate disconnection. Here are the details:
Problem Summary:
I have implemented a VPN connection using Swift with the NetworkExtension and TunnelKit frameworks. My application successfully loads the VPN configuration, but when attempting to connect, the VPN status quickly changes from connecting to disconnected without ever achieving a stable connection. Manually attempting to toggle the connection from device settings results in the toggle switching off as soon as it is turned on. The console logs indicate a transition from 'connecting' to 'disconnected' almost simultaneously.
Technical Details:
Here is an overview of the relevant part of the code used for setting up and managing the VPN connection:
import TunnelKitOpenVPNCore
import NetworkExtension
import TunnelKit
class VPNManager {
static let shared = VPNManager()
private var providerManager: NETunnelProviderManager?
init() {
NotificationCenter.default.addObserver(self, selector: #selector(vpnStatusDidChange), name: .NEVPNStatusDidChange, object: nil)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
@objc func vpnStatusDidChange(notification: Notification) {
guard let status = self.providerManager?.connection.status else { return }
switch status {
case .connecting:
print("VPN is connecting")
case .connected:
print("VPN is connected")
case .disconnecting:
print("VPN is disconnecting")
case .disconnected:
print("VPN is disconnected")
case .invalid:
print("VPN configuration is invalid")
case .reasserting:
print("VPN is reasserting")
@unknown default:
print("Unknown VPN status")
}
}
func loadAndCreateVPNProfile(completion: @escaping (Bool, Error?) -> Void) {
self.providerManager = NETunnelProviderManager()
guard let ovpnURL = Bundle.main.url(forResource: "client", withExtension: "ovpn"),
let ovpnContents = try? String(contentsOf: ovpnURL) else {
completion(false, NSError(domain: "VPNManagerError", code: 1, userInfo: [NSLocalizedDescriptionKey: "Configuration file could not be read or found."]))
return
}
// Parsing and configuration logic here...
self.providerManager?.saveToPreferences { error in
if let error = error {
print("Error saving preferences: \(error.localizedDescription)")
completion(false, error)
} else {
print("VPN profile saved successfully.")
completion(true, nil)
}
}
}
func connect() {
self.providerManager?.loadFromPreferences { [weak self] error in
guard let strongSelf = self else {
print("Reference to VPNManager lost.")
return
}
if let error = error {
print("Failed to load preferences: \(error.localizedDescription)")
return
}
do {
try strongSelf.providerManager?.connection.startVPNTunnel()
} catch NEVPNError.configurationInvalid {
print("VPN Configuration is invalid.")
} catch NEVPNError.configurationDisabled {
print("VPN Configuration is disabled.")
} catch let error {
print("Unexpected error: \(error.localizedDescription)")
}
}
}
func disconnect() {
providerManager?.connection.stopVPNTunnel()
}
}
Like the post at https://forums.developer.apple.com/forums/thread/118035, I'm hitting an issue where I'm receiving:
boringssl_session_set_peer_verification_state_from_session(448) [C1.1.1.1:2][0x12b667210] Unable to extract cached certificates from the SSL_SESSION object
In my app logs. I tried to pin the SSL version to TLS 1.2 per Quinn's advice in that post, and then started digging further enabling CFNETWORK_DIAGNOSTICS=3 to see what was exposed on the Console.log (since it didn't show up in the Xcode console)
The related log lines:
0 debug boringssl 15:43:04.978874-0700 MeetingNotes boringssl_context_log_message(2206) [C5:2][0x11080a760] Reading SSL3_RT_HANDSHAKE 16 bytes
0 debug boringssl 15:43:04.979007-0700 MeetingNotes boringssl_context_log_message(2206) [C5:2][0x11080a760] Writing SSL3_RT_CHANGE_CIPHER_SPEC 1 bytes
0 debug boringssl 15:43:04.979141-0700 MeetingNotes boringssl_context_log_message(2206) [C5:2][0x11080a760] Writing SSL3_RT_HANDSHAKE 16 bytes
0 debug boringssl 15:43:04.979260-0700 MeetingNotes nw_protocol_boringssl_write_bytes(87) [C5:2][0x11080a760] write request: 51
0 debug boringssl 15:43:04.979387-0700 MeetingNotes nw_protocol_boringssl_write_bytes(158) [C5:2][0x11080a760] total bytes written: 51
921460 debug boringssl 15:43:09.937961-0700 MeetingNotes boringssl_context_log_message(2206) [C5:2][0x11080a760] Writing SSL3_RT_ALERT 2 bytes
0 error boringssl 15:43:04.979630-0700 MeetingNotes boringssl_session_set_peer_verification_state_from_session(448) [C5:2][0x11080a760] Unable to extract cached certificates from the SSL_SESSION object
Have a number of references to SSL3_RT in the messages, and I was curious if that indicated that I was using TLS1.3, which apparently doesn't support private shared keys.
The constraints that I used riffs on the sample code from the tic-tac-toe example project:
private static func tlsOptions(passcode: String) -> NWProtocolTLS.Options {
let tlsOptions = NWProtocolTLS.Options()
let authenticationKey = SymmetricKey(data: passcode.data(using: .utf8)!)
let authenticationCode = HMAC<SHA256>.authenticationCode(
for: "MeetingNotes".data(using: .utf8)!,
using: authenticationKey
)
let authenticationDispatchData = authenticationCode.withUnsafeBytes {
DispatchData(bytes: $0)
}
// Private Shared Key (https://datatracker.ietf.org/doc/html/rfc4279) is *not* supported in
// TLS 1.3 [https://tools.ietf.org/html/rfc8446], so this pins the TLS options to use version 1.2:
// @constant tls_protocol_version_TLSv12 TLS 1.2 [https://tools.ietf.org/html/rfc5246]
sec_protocol_options_set_max_tls_protocol_version(tlsOptions.securityProtocolOptions, .TLSv12)
sec_protocol_options_set_min_tls_protocol_version(tlsOptions.securityProtocolOptions, .TLSv12)
sec_protocol_options_add_pre_shared_key(
tlsOptions.securityProtocolOptions,
authenticationDispatchData as __DispatchData,
stringToDispatchData("MeetingNotes")! as __DispatchData
)
/* RFC 5487 - PSK with SHA-256/384 and AES GCM */
// Forcing non-standard cipher suite value to UInt16 because for
// whatever reason, it can get returned as UInt32 - such as in
// GitHub actions CI.
let ciphersuiteValue = UInt16(TLS_PSK_WITH_AES_128_GCM_SHA256)
sec_protocol_options_append_tls_ciphersuite(
tlsOptions.securityProtocolOptions,
tls_ciphersuite_t(rawValue: ciphersuiteValue)!
)
return tlsOptions
}
Is there something I'm missing in setting up the proper constraints to request TLS version 1.2 with a private shared key to be used? And beyond that, any suggestions for debugging or narrowing down what might be failing?
MacOS Version: 14.3 (23D56)
In my testing of PacketTunnelProvider on MacOS I have observed that when I do a system shutdown or reboot, PacketTunnelProvider::stopTunnelWithReason() is getting called with reason: NEProviderStopReasonUserInitiated. Note: when I try to disconnect the VPN from system settings PacketTunnelProvider::stopTunnelWithReason() is called with the same reason: NEProviderStopReasonUserInitiated.
I am facing an issue here to identify what caused PacketTunnelProvider::stopTunnelWithReason(), system shutdown or any user action?
Hi, I was working on some new filtering logic for my Content Filter that I would like to add. It involves making requests to remote DNS resolvers. Is it possible to use it within sync override func handleNewFlow(_ flow: NEFilterFlow) -> NEFilterNewFlowVerdict of the NEFilterDataProvider?
As of right now, I have a concept working in Command Line Tool and playground, however, when I try to add working module to the main project, it's not working (connections are not loading).
Function that makes requests to the servers: In this function I use DispatchGroup and notify for non-main queue
@available(iOS 12, *)
public class NetworkService {
private let nonMainQueue: DispatchQueue = DispatchQueue(label: "non-main-queue")
func isBlocked(hostname: String, completion: @escaping (Bool) -> Void) {
var isAnyBlocked = false
let group = DispatchGroup()
for server in servers {
group.enter()
let endpoint = NWEndpoint.Host(server)
query(host: endpoint, domain: hostname, queue: .global()) { response, error in
defer {
group.leave()
}
/*
* some code that determines the filtering logic
* if condition is true => isAnyBlocked = true & return
*/
}
}
group.notify(queue: nonMainQueue) {
completion(isAnyBlocked)
}
}
}
And, for example, in playground Semaphores make it work as expected, but the same approach doesn't work with the NEFilterDataProvider
playground code sample
let hostname = "google.com"
func returnResponse() -> String {
var result = ""
let semaphore = DispatchSemaphore(value: 0)
DispatchQueue.global().async {
NetworkService.isBlocked(hostname: hostname) { isBlocked in
result = isBlocked ? "blocked" : "allowed"
semaphore.signal()
}
}
semaphore.wait()
return result
}
print(returnResponse())
Output: allowed
Whenever I open a .unix socket (i.e.: /var/run/usbmuxd) I get the following errors in Xcode console:
nw_socket_set_common_sockopts [C13:1] setsockopt SO_NECP_CLIENTUUID failed [22: Invalid argument]
Type: Error | Timestamp: 2024-04-18 15:48:44.813556-04:00 | Process: TH Dev | Library: Network | Subsystem: com.apple.network | Category: connection | TID: 0x425e2
nw_socket_set_common_sockopts setsockopt SO_NECP_CLIENTUUID failed [22: Invalid argument]
Type: Error | Timestamp: 2024-04-18 15:48:44.813682-04:00 | Process: TH Dev | Library: Network | Subsystem: com.apple.network | Category: | TID: 0x425e2
nw_socket_copy_info [C13:1] getsockopt TCP_INFO failed [102: Operation not supported on socket]
Type: Error | Timestamp: 2024-04-18 15:48:44.814484-04:00 | Process: TH Dev | Library: Network | Subsystem: com.apple.network | Category: connection | TID: 0x425e2
nw_socket_copy_info getsockopt TCP_INFO failed [102: Operation not supported on socket]
Type: Error | Timestamp: 2024-04-18 15:48:44.814523-04:00 | Process: TH Dev | Library: Network | Subsystem: com.apple.network | Category: | TID: 0x425e2
While communication to/from the socket seems to work, the operations leading to these errors shouldn't be attempted if the socket doesn't support them.
I'm trying to build a feature which allows:
Peripheral send some info (up to 512 bytes) to central
Central connects to all nearby peripheral, and display the connected peripherals as a list
When user tap on any of the peripheral from the list, central send back some info back.
In order to achieve this, I need to make sure to connect to the discovered peripherals before sending over the data because the data i want to send through BLE is larger than advertisementData MTU while peripheral starts broadcasting.
However, I also saw some discussion suggesting that I should stop scanning first before establish connection.
I wonder if you have any recommendation for my scenario. (Let's assume BLE is the ONLY approach I can go with for transferring data because I want to do this cross Android and iOS offline)
Should I maintain 2 peripheral arrays to tracked the discovered and connected peripherals?
Am I supposed to connect to the peripheral while scanning?
If not, any recommendations?
Thank you!
Hey everyone,
I'm currently working on an app where I've already implemented a packet tunnel provider. Now, I'm looking to introduce a content filter. One crucial feature I need is the ability to read the bundle ID of the app originating the network flows.
However, I've hit a roadblock when combining both components; When I run the content filter sans packet tunnel provider, I can read the originating app's bundle ID for network flows just fine. But when I add packet tunnel provider, the app's bundle ID defaults to my own app's bundle ID, which is unexpected.
Has anyone else encountered this? Any thoughts on why it's happening or how to fix it?
Cheers!
Hello,
I have some networking code that checks whether a proxy is configured via:
`CFStringRef host = (CFStringRef)CFDictionaryGetValue(globalSettings, kCFNetworkProxiesHTTPProxy);`
`CFNumberRef port = (CFNumberRef)CFDictionaryGetValue(globalSettings, kCFNetworkProxiesHTTPPort);`
I need to do this fairly frequently, so I am wondering if there is an announcer I can subscribe to instead?
Hi,
I am wanting to create an app but am looking for a way to get raw IQ data from the cellular radio(s) on an iPhone. This would probably be gathered when cellular is turned off on the iPhone so as not to mess with its carrier services. Specifically, I would like to use the antenna(s)/radio(s) in an iPhone to get IQ data from a specified frequency and bandwidth.
Is this possible? I haven't found anything in the developer documentation pointing to an API that would provide this. If it is a restricted API, are there steps I can go through to get access?
Thanks
Hello, I would like to ask if I can use ThreadNetwork.framework. My project has been configured with com.apple.developer. networking. manage thread network credentials according to the documentation, but the relevant API still cannot be used. Currently, there is an error message:
Client: - [THClient getConnectionEntitlementValidity] block invoice - Error: (null)
Client: [THClient retrieveAllCredits:] _block_invoke - Error: Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service with pid 555 named com. apple. ThreadNetwork. xpc was validated from this process." UserInfo={NSDebugDescription=The connection to service with pid 555 named com. apple. ThreadNetwork. xpc was validated from this process.}
May I ask if I can use the relevant API
I spent 3 days sorting out an app that worked with net7.0 and Xcode 14.x.
Namely my Httpsclient requests to the API crashed the iOS after 6-9 cycles.
Ater re-coding with no luck, tracking the Crash codes and recoding with no luck, I finally found a forum that articulates 15.3 and net8.0 is a no go. Downgrade to 15.2.
I did the downgrade and my original code worked just fine.
I read most of the posts on 15.3 and did not see this issue noted. Has anyone seen the same issue and if so found a work around?
Others have seen an HttpsClient issue with authentication with 2 suggestions but no workable solution in 15.3. They downgraded.
How can you change the behaviour of the system resolver on iOS?
need help eskimo..!
hi, I made an interface for VPN applications for iOS, and I just need to make a connection to the protocol, I wanted to use wireguard, but I can’t do it, what can you suggest me?
I want to use Network Extension Relay to implement a system-wide proxy. First, I will setup a local http2 proxy and forward to a local http proxy. The problem is
How to implement this http2relayurl link to? Is it a regular http2 proxy protocol?
What should I pass to raw public keys? Is it a bytes like rsa public key, or is .pem, .pub like plain text string? And I will use self signed certificate, will it be a problem?
On the [documentation page](Implement a completely custom DNS proxying protocol) it says
For example, a DNS proxy provider might:
Implement a completely custom DNS proxying protocol
I would like to add some filtering logic to the NEDNSProxyProvider (for example, return nxdomain if the flow is not passing the filtering process). Is it possible to implement with NEDNSProxyProvider? It also says that
func handleNewFlow(_ flow: NEAppProxyFlow) -> Bool
from NEDNSProxyProvider returns a Boolean value set to true if the proxy implementation decides to handle the flow, or false if it instead decides to terminate the flow link. Does it mean that the filtering logic could be added here by just returning false for the flows that are not matching the rules?
Because I first tried to handle UDP flows like this in handleNewFlow(_ flow: NEAppProxyUDPFlow) function and form my own packets in connection.transferData, by first passing empty Data object and then by setting RCODE to 3, which is supposedly a nxdomain response code. However, both implementations didn't work: even though I was getting logs about handling failure, the flow was still able to go through.
try await flow.open(withLocalEndpoint: flow.localEndpoint as? NWHostEndpoint)
let datagrams = try await flow.readDatagrams()
let results = try await datagrams.parallelMap {
let connection = try DatagramConnection($0)
return try await connection.transferData()
}
try await flow.writeDatagrams(results)
flow.closeReadWithError(nil)
flow.closeWriteWithError(nil)
I am new to NEDNSProxyProvider and my networking knowledge is on a pretty basic level, so I would be very grateful to hear any suggestions. Thank you!
I am working on a VPN app featuring Wireguard. The app was working fine. I planned to make a Framework for the Wireguard Target, Network Extension Target and the Code managing VPN, Now after removing all errors, resolving Bundle IDs and making all the targets compatible to iOS 16.0, I am getting this error in the Settings app as shown in the following
In short, same code is not working when moved into the framework.
I have read the similar thread talking about lowering the minimum deployments. All of my minimum deployments are set to iOS 16.0.
Any suggestions would be appreciated.
Thanking you in anticipation.
Ali.