IMPORTANT This FAQ has been replaced by TN3179 Understanding local network privacy. I’m leaving this post in place as a historical curiosity, but please consult the technote going forward.
I regularly get asked questions about local network privacy. This is my attempt to collect together the answers for the benefit of all. Before you delve into the details, familiarise yourself with the basics by watching WWDC 2020 Session 10110 Support local network privacy in your app.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
Local Network Privacy FAQ
With local network privacy, any app that wants to interact with devices on your network must ask for permission the first time that it attempts that access. Local network privacy is implemented on iOS, iPadOS, visionOS, and macOS. It’s not implemented on other platforms, most notably tvOS.
IMPORTANT macOS 15 (currently in beta) introduced local network privacy support to the Mac. WWDC 2024 Session 10123 What’s new in privacy is the official announcement. This works much like it does on iOS, but there are some subtle differences. I’ll update this FAQ as I gain more experience with this change.
Some common questions about local network privacy are:
FAQ-1 What is a local network?
FAQ-2 What operations require local network access?
FAQ-3 What operations require the multicast entitlement?
FAQ-4 Do I need the multicast entitlement?
FAQ-5 I’ve been granted the multicast entitlement; how do I enable it?
FAQ-6 Can App Clips access the local network?
FAQ-7 How does local network privacy work with app extensions?
FAQ-8 How do I explicitly trigger the local network privacy alert?
FAQ-9 How do I tell whether I’ve been granted local network access?
FAQ-10 How do I use the unsatisfied reason property?
FAQ-11 Do I need a local network usage description property?
FAQ-12 Can I test on the simulator?
FAQ-13 Once my app has displayed the local network privacy alert, how can I reset its state so that it shows again?
FAQ-14 How do I map my Multipeer Connectivity service type to an entry in the Bonjour services property?
FAQ-15 My app presents the local network privacy alert unexpectedly. Is there a way to track down the cause?
FAQ-16 On a small fraction of devices my app fails to present the local network privacy alert. What’s going on?
FAQ-17 Why does local network privacy get confused when I install two variants of my app?
FAQ-18 Can my app trigger the local network privacy alert when the device is on WWAN?
Revision History
2024-10-31 Added a link to this FAQ’s replacement, TN3179 Understanding local network privacy.
2024-07-22 Added a callout explaining that local network privacy is now an issue on macOS.
2023-10-31 Fixed a bug in the top-level FAQ that mistakenly removed some recent changes. Added FAQ-18.
2023-10-19 Added a preamble to clarify that local network privacy is only relevant on specific platforms.
2023-09-14 Added FAQ-17.
2023-08-29 Added FAQ-16.
2023-03-13 Added connecting a UDP socket to FAQ-2.
2022-10-04 Added screen shots to FAQ-11.
2022-09-22 Fixed the pointer from FAQ-9 to FAQ-10.
2022-09-19 Updated FAQ-3 to cover iOS 16 changes. Made other minor editorial changes.
2020-11-12 Made a minor tweak to FAQ-9.
2020-10-17 Added FAQ-15. Added a second suggestion to FAQ-13.
2020-10-16 First posted.
Bonjour
RSS for tagBonjour, also known as zero-configuration networking, enables automatic discovery of devices and services on a local network using industry standard.
Posts under Bonjour tag
43 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
IMPORTANT The approach used by this code no longer works. See TN3179 Understanding local network privacy for a replacement.
Currently there is no way to explicitly trigger the local network privacy alert (r. 69157424). However, you can bring it up implicitly by sending dummy traffic to a local network address. The code below shows one way to do this. It finds all IPv4 and IPv6 addresses associated with broadcast-capable network interfaces and sends a UDP datagram to each one. This should trigger the local network privacy alert, assuming the alert hasn’t already been displayed for your app.
Oh, and if Objective-C is more your style, use this code instead.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"
import Foundation
/// Does a best effort attempt to trigger the local network privacy alert.
///
/// It works by sending a UDP datagram to the discard service (port 9) of every
/// IP address associated with a broadcast-capable interface. This should
/// trigger the local network privacy alert, assuming the alert hasn’t already
/// been displayed for this app.
///
/// This code takes a ‘best effort’. It handles errors by ignoring them. As
/// such, there’s guarantee that it’ll actually trigger the alert.
///
/// - note: iOS devices don’t actually run the discard service. I’m using it
/// here because I need a port to send the UDP datagram to and port 9 is
/// always going to be safe (either the discard service is running, in which
/// case it will discard the datagram, or it’s not, in which case the TCP/IP
/// stack will discard it).
///
/// There should be a proper API for this (r. 69157424).
///
/// For more background on this, see [Triggering the Local Network Privacy Alert](https://developer.apple.com/forums/thread/663768).
func triggerLocalNetworkPrivacyAlert() {
let sock4 = socket(AF_INET, SOCK_DGRAM, 0)
guard sock4 >= 0 else { return }
defer { close(sock4) }
let sock6 = socket(AF_INET6, SOCK_DGRAM, 0)
guard sock6 >= 0 else { return }
defer { close(sock6) }
let addresses = addressesOfDiscardServiceOnBroadcastCapableInterfaces()
var message = [UInt8]("!".utf8)
for address in addresses {
address.withUnsafeBytes { buf in
let sa = buf.baseAddress!.assumingMemoryBound(to: sockaddr.self)
let saLen = socklen_t(buf.count)
let sock = sa.pointee.sa_family == AF_INET ? sock4 : sock6
_ = sendto(sock, &message, message.count, MSG_DONTWAIT, sa, saLen)
}
}
}
/// Returns the addresses of the discard service (port 9) on every
/// broadcast-capable interface.
///
/// Each array entry is contains either a `sockaddr_in` or `sockaddr_in6`.
private func addressesOfDiscardServiceOnBroadcastCapableInterfaces() -> [Data] {
var addrList: UnsafeMutablePointer<ifaddrs>? = nil
let err = getifaddrs(&addrList)
guard err == 0, let start = addrList else { return [] }
defer { freeifaddrs(start) }
return sequence(first: start, next: { $0.pointee.ifa_next })
.compactMap { i -> Data? in
guard
(i.pointee.ifa_flags & UInt32(bitPattern: IFF_BROADCAST)) != 0,
let sa = i.pointee.ifa_addr
else { return nil }
var result = Data(UnsafeRawBufferPointer(start: sa, count: Int(sa.pointee.sa_len)))
switch CInt(sa.pointee.sa_family) {
case AF_INET:
result.withUnsafeMutableBytes { buf in
let sin = buf.baseAddress!.assumingMemoryBound(to: sockaddr_in.self)
sin.pointee.sin_port = UInt16(9).bigEndian
}
case AF_INET6:
result.withUnsafeMutableBytes { buf in
let sin6 = buf.baseAddress!.assumingMemoryBound(to: sockaddr_in6.self)
sin6.pointee.sin6_port = UInt16(9).bigEndian
}
default:
return nil
}
return result
}
}
Hi,
I am facing a strange issue in my app with iOS14 there is a intermittent crash, i am using NetServiceBrowser for MDNS discovery not sure if that is causing the problem crash log has below information:
Crashed: com.apple.main-thread
0 CoreFoundation 0x1a906c4c4 CFAssertMismatchedTypeID + 108
1 CoreFoundation 0x1a8f7db0c CFRunLoopSourceRemoveFromRunLoop + 298
2 CFNetwork 0x1a96255b0 CFNetServiceBrowserStopSearch + 460
3 CoreFoundation 0x1a8f81240 CFRUNLOOPISCALLINGOUTTOASOURCE0PERFORMFUNCTION + 24
4 CoreFoundation 0x1a8f81140 CFRunLoopDoSource0 + 204
5 CoreFoundation 0x1a8f80488 CFRunLoopDoSources0 + 256
6 CoreFoundation 0x1a8f7aa40 CFRunLoopRun + 776
7 CoreFoundation 0x1a8f7a200 CFRunLoopRunSpecific + 572
8 GraphicsServices 0x1bf075598 GSEventRunModal + 160
9 UIKitCore 0x1ab840004 -[UIApplication run] + 1052
10 UIKitCore 0x1ab8455d8 UIApplicationMain + 164