Hello!We use `NWPathMonitor` within our SDK to read the network connection details. Recently, we discovered a crash which makes me considering the thread safety of `NWPath` struct. In following code, the program passed the line `12`, but crashed on line `13`:import Network
@available(iOS 12, *)
extension NWPathMonitor {
var current: NetworkConnectionInfo {
let info = currentPath
return NetworkConnectionInfo(
reachability: NetworkConnectionInfo.Reachability(from: info.status),
availableInterfaces: Array(fromInterfaceTypes: info.availableInterfaces.map { $0.type }),
supportsIPv4: info.supportsIPv4, // <- passed
supportsIPv6: info.supportsIPv6, // <- crashed
isExpensive: info.isExpensive
)
}
}To my best understanding, something did happen concurrently between the current thread advanced from line `12` to `13`. Thus, I consider thread safety issue around `NWPath` returned by the `currentPath`. What I can't understand however, is why this crashes at all, given that `NWPath` is a struct, so its immutable value captured on `let info` should be thread safe.Crash details:Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000020
VM Region Info: 0x20 is not in any region. Bytes before following region: 4369170400
REGION TYPE START - END [ VSIZE] PRT/MAX SHRMOD REGION DETAIL
UNUSED SPACE AT START
--->
__TEXT 00000001046c4000-0000000104ee8000 [ 8336K] r-x/r-x SM=COW ...g.app/Datadog
Termination Signal: Segmentation fault: 11
Termination Reason: Namespace SIGNAL, Code 0xb
Terminating Process: exc handler [18544]
Thread 10 name: Dispatch queue: com.datadoghq.ios-sdk-logs-upload
Thread 10 Crashed:
0 libswiftCore.dylib 0x00000001ba2cf978 swift_unknownObjectRelease + 16
1 Datadog 0x0000000106508694 0x1064bc000 + 312980
2 Datadog 0x0000000106506e78 0x1064bc000 + 306808
3 Datadog 0x00000001065069b8 0x1064bc000 + 305592
4 Datadog 0x0000000106507618 0x1064bc000 + 308760
5 Datadog 0x00000001064cbfa8 0x1064bc000 + 65448
6 Datadog 0x00000001064d133c 0x1064bc000 + 86844
7 Datadog 0x00000001064d251c 0x1064bc000 + 91420
8 libdispatch.dylib 0x00000001ac41033c _dispatch_client_callout + 20Note: we discovered this crash on iOS13.x device and couldn't manage to reproduce more times. In the crashing version of SDK, we do pass following `queue` to synchronize `NWPathMonitor` updates:let queue = DispatchQueue(
label: "com.datadoghq.network-connection-info",
qos: .utility,
attributes: [],
target: DispatchQueue.global(qos: .utility)
)
Post
Replies
Boosts
Views
Activity
Hello,
TL;DR; I'm looking for a way to recognise and filter out private IPs resolved from our NTP hosts using CFHostStartInfoResolution(_:_:_:). I suspect that it returns addresses within local network range sporadically, which leads to bringing up the Local Network Privacy alert when sending UDP packages (for NTP sync).
Our customers report that our SDK brings up the "Local Network Privacy" alert to the fraction of their end users. This behaviour is very rare and volatile, so we couldn't manage to reproduce it on our side on any device. We're trying to find out the the root cause, as local networking attempt is definitely not expected to happen in our SDK. I'm pretty familiar with the content of Local Network Privacy FAQ, but couldn't find an answer in there, hence I'm looking for any clues to move forward.
Certainly the issue is coming from NTP sync our SDK does with the use of CFNetwork APIs. The logic starts with resolving one of our NTP pools:
0.datadog.pool.ntp.org
1.datadog.pool.ntp.org
2.datadog.pool.ntp.org
3.datadog.pool.ntp.org
into a sequence of IP addresses with CFHostStartInfoResolution(_:_:_:). Then we query each IP with CFSocketConnectToAddress(_:_:_:) by exchanging NTP messages through CFSocket.
Now, given that the issue is rare and volatile our first assumption was that in some network circumstances our DNS phase can lead to resolving private IPs. This hypothesis was proven in telemetry we collected with using NWConnection API and method described in How do I use the unsatisfied reason property?. Among thousands of attempts, we found one that failed on .localNetworkDenied when querying 192.168.1.250.
To filter out local IPs, we ran through IETF RFCs on IPv4 and IPV6 specifics, coming up with the filter that should prevent from sending UDP to local network. Our "private IP" definition includes:
IPv6 addresses containing:
local IP FC00::/7 prefix (RFC-4193);
multicast IPs with FF prefix (RFC-4291);
IPv4 addresses:
reserved for private internets of ranges A, B and C (RFC-1918);
multicast addresses within range 224.0.0.0 - 239.255.255.255 and broadcast 255.255.255.255 (as suggested in What is a local network?)
With recent user reports, it turns out that this filter is either too weak or the entire idea of IP filtering is too flaky. The problem is still being reported. One report included a list of IPs out of which at least one must have lead to private networking and bringing up the alert on a device using regular 4G network:
82.64.172.48
178.170.37.31
62.210.244.146
188.165.236.162
193.200.43.105
51.15.175.180
95.81.173.74
51.195.117.133
151.80.211.8
92.222.117.115
51.75.17.219
64:ff9b::5be0:9529
2a05:f480:1400:53d::123
64:ff9b::a29f:c801
64:ff9b::253b:3f7d
2a05:f480:2000:1834::123
64:ff9b::c2b1:2274
64:ff9b::5cf3:605
2001:41d0:305:2100::3f3e
64:ff9b::33c3:7585
64:ff9b::d453:9e53
2001:41d0:8:7a7d::1
64:ff9b:1::5cde:7573
Looking at this list (even trying to hit these IPs with UDP) none seems to be commonly known local IP, hence my question is which IP ranges / RFCs are included in Apple's definition of local network? Is there anything obvious that I am missing?
PS1. I'm familiar with categories listed in What operations require local network access?
PS2. I know that CFNetwork APIs are deprecated and we should use Network APIs - however I don't suppose the problem will be gone only by migrating our logic to new code, hence I want to find the flaw in our filtering.