Every now and then I talk to someone who’s trying to use Bonjour and just can’t get over the first hurdle. That happened today, and so I decided to share my write-up for the benefit of others.
Questions or comments? Put them in a new thread here on DevForums, tagging it with Bonjour so that I see it.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
Getting Started with Bonjour
Bonjour is an Apple term for a variety of Internet standards [1]. Bonjour allows your app to browse for and connect to services on the network without infrastructure support. For example, Bonjour lets you find and connect to a printer even if the network has no DHCP server to hand out IP addresses.
If you’re new to Bonjour, a good place to start is the Bonjour Overview. It’s in the documentation archive, so it hasn’t been updated in a while, but the fundamentals haven’t changed.
There are, however, two things that have changed:
Network framework has new Bonjour APIs, and the old ones are now deprecated.
iOS 14 introduced local network privacy.
This post shows how to get started with Bonjour, taking into account these new developments.
[1] Specifically:
RFC 3927 Dynamic Configuration of IPv4 Link-Local Addresses
RFC 6762 Multicast DNS
RFC 6763 DNS-Based Service Discovery
Start Browsing
Let’s start by implementing a service browser. To simplify things, this browses for SSH services. That way you can get started with the browser without first having to implement a server to register your service. If you don’t already have an SSH service registered on your network, start one by enabling System Settings > General > Sharing > Remote Login on your Mac.
The SSH service type is, unsurprisingly, _ssh._tcp. First, on your Mac, run the dns-sd tool to confirm that you have an SSH service visible on your network:
% dns-sd -B "_ssh._tcp" "local."
% dns-sd -B "_ssh._tcp" "local."
…
Timestamp A-R Flags if Domain Service Type Instance Name
…
11:54:43.315 Add 2 6 local. _ssh._tcp. Fluffy
…
11:54:43.725 Add 2 6 local. _ssh._tcp. SAM the Robot 12
^C
This shows that I have two services, one called Fluffy and the other called SAM the Robot 12. Let’s write some iOS code to browse for those. To start, create an app from the iOS > App template and connect a button to the startStop() method of a class like this:
import Foundation
import Network
class AppModel {
var browserQ: NWBrowser? = nil
func start() -> NWBrowser {
print("browser will start")
let descriptor = NWBrowser.Descriptor.bonjour(type: "_ssh._tcp", domain: "local.")
let browser = NWBrowser(for: descriptor, using: .tcp)
browser.stateUpdateHandler = { newState in
print("browser did change state, new: \(newState)")
}
browser.browseResultsChangedHandler = { updated, changes in
print("browser results did change:")
for change in changes {
switch change {
case .added(let result):
print("+ \(result.endpoint)")
case .removed(let result):
print("- \(result.endpoint)")
case .changed(old: let old, new: let new, flags: _):
print("± \(old.endpoint) \(new.endpoint)")
case .identical:
fallthrough
@unknown default:
print("?")
}
}
}
browser.start(queue: .main)
return browser
}
func stop(browser: NWBrowser) {
print("browser will stop")
browser.stateUpdateHandler = nil
browser.cancel()
}
func startStop() {
if let browser = self.browserQ {
self.browserQ = nil
self.stop(browser: browser)
} else {
self.browserQ = self.start()
}
}
}
Note I’m using SwiftUI, but if you chose to use UIKit you could add this code directly to your view controller. Of course, whether you want to add networking code to your view controller is another question. The answer is, natch, “No”, except when creating a tiny test project like this one (-:
Now build and run in the simulator and click your buton. It’ll print something like this:
browser will start
browser did change state, new: ready
browser results did change:
+ SAM the Robot 12._ssh._tcp.local.
+ Fluffy._ssh._tcp.local.
As you can see, it’s found our two SSH services. Yay!
Run on the Device
Now stop the app and run it on a real device. This time the Test button results in:
browser will start
…
browser did change state, new: failed(-65555: NoAuth)
This is local network privacy kicking in. There are two things you need to do:
Add a NSBonjourServices property to your Info.plist to declare what service types you’re using.
Add a NSLocalNetworkUsageDescription property to your Info.plist to explain what you’re doing with the local network.
Do that and run your app again. On tapping the Test button you’ll see an alert asking you to grant your app access to the local network. Tap Allow and the browser will start generating results as before.
Respond to Updates
When working with Bonjour it’s important to keep your browser running to update your app’s state. To test this, start a Remote Login on a different machine and look for a new result being printed:
browser results did change:
+ Slimey._ssh._tcplocal.
And then turn it off:
browser results did change:
- Slimey._ssh._tcplocal.
If you don’t have another Mac to test this with, start a dummy service using dns-sd:
% dns-sd -R "Guy Smiley" "_ssh._tcp" "local." 12345
Registering Service Test._ssh._tcp.local. port 12345
…
Press control-C to stop the dns-sd tool, which unregisters the service.
Connect
When the user choose a service, it’s time to connect. There are two ways to do this, depending on the networking API you use to run your connection.
NWConnection can connect directly to a Bonjour service endpoint. For example, you might have code that connects to a DNS name and port:
func makeConnection(host: String, port: UInt16) -> NWConnection {
let host = NWEndpoint.Host(host)
let port = NWEndpoint.Port(rawValue: port)!
let endpoint = NWEndpoint.hostPort(host: host, port: port)
return NWConnection(to: endpoint, using: .tcp)
}
Replace that with code that takes the endpoint you get back from the browser:
func makeConnection(endpoint: NWEndpoint) -> NWConnection {
return NWConnection(to: endpoint, using: .tcp)
}
If you’re using a legacy API, like BSD Sockets, you’ll need to resolve the Bonjour service endpoint to a DNS name and then pass that DNS name into your connection code. Network framework does not support resolving Bonjour service endpoints out of the box, so you’ll have to do that yourself. For an example of how you might do this, see this post.
IMPORTANT For this to work reliably, your BSD Sockets code must support Happy Eyeballs. See TN3151 Choosing the right networking API for specific advice on that front.
Register a Service
Now let’s look at the server side. To listen for connections with Network framework, you might write code like this:
import Foundation
import Network
class AppModel {
var listenerQ: NWListener? = nil
func start() -> NWListener? {
print("listener will start")
guard let listener = try? NWListener(using: .tcp) else { return nil }
listener.stateUpdateHandler = { newState in
print("listener did change state, new: \(newState)")
}
listener.newConnectionHandler = { connection in
connection.cancel()
}
listener.start(queue: .main)
return listener
}
func stop(listener: NWListener) {
print("listener will stop")
listener.stateUpdateHandler = nil
listener.cancel()
}
func startStop() {
if let listener = self.listenerQ {
self.listenerQ = nil
self.stop(listener: listener)
} else {
self.listenerQ = self.start()
}
}
}
To register your service with Bonjour, add these lines before the call to start(queue:):
listener.service = .init(type: "_ssh._tcp")
listener.serviceRegistrationUpdateHandler = { change in
print(change)
}
The listener calls your service registration update handler to tell you the name of the service. Typically you display this value somewhere in your UI. For more about this, see Showing Connection Information in an iOS Server.
To confirm that your service is running, open Terminal and choose Shell > New Remote Command. Your service should show up in the Secure Shell (ssh) list.
Alternatively, browse for SSH services using the dns-sd tool, as illustrated in the Start Browsing section above.
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
48 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
Hello 👋
I need to implement a logic for searching for devices with our own service type using Bonjour. Using the NWBrowser, I can receive a list of all devices and connect to them. I need to utilize a WebSocket connection. By the property endpoint of NWBrowser.Result objects I can create NWConnection. Below is my implementation which works fine on iOS 17:
let params = NWParameters.tcp
let webSocketOptions = NWProtocolWebSocket.Options()
params.defaultProtocolStack.applicationProtocols.insert(webSocketOptions, at: 0)
// The `endpoint` is from `browseResultsChangedHandler` of NWBrowser
let connection = NWConnection(to: endpoint, using: params)
However, it doesn't work on iOS 15 and 16 because of the crash:
2024-06-01 16:07:18.136068+0300 MyApp[591:16845549] [] nw_endpoint_get_url called with null endpoint
2024-06-01 16:07:18.136932+0300 MyApp[591:16845549] [] nw_endpoint_get_url called with null endpoint, dumping backtrace:
[arm64] libnetcore-3100.102.1
0 Network 0x000000018530e174 __nw_create_backtrace_string + 188
1 Network 0x000000018538ba20 nw_endpoint_get_url + 852
2 Network 0x0000000185310020 nw_ws_create_client_request + 84
3 Network 0x0000000184f4b3cc __nw_ws_create_state_block_invoke + 416
4 Network 0x000000018504bc68 nw_protocol_options_access_handle + 92
5 Network 0x0000000184f41e98 nw_ws_create_state + 204
6 Network 0x0000000184f41aec __nw_protocol_copy_ws_definition_block_invoke_2 + 176
7 Network 0x0000000184f69188 nw_framer_protocol_connected + 348
8 Network 0x00000001854a6638 _ZL29nw_socket_handle_socket_eventP9nw_socket + 1560
9 libdispatch.dylib 0x0000000126b89d50 _dispatch_client_callout + 16
10 libdispatch.dylib 0x0000000126b8d208 _dispatch_continuation_pop + 756
11 libdispatch.dylib 0x0000000126ba48d4 _dispatch_source_invoke + 1676
12 libdispatch.dylib 0x0000000126b94398 _dispatch_workloop_invoke + 2428
13 libdispatch.dylib 0x0000000126ba0b74 _dispatch_workloop_worker_thread + 1716
14 libsystem_pthread.dylib 0x000000012371f814 _pthread_wqthread + 284
15 libsystem_pthread.dylib 0x000000012371e5d4 start_wqthread + 8
Also, there is the stack trace of bt-command in the debug console:
* thread #20, queue = 'com.apple.network.connections', stop reason = EXC_BAD_ACCESS (code=1, address=0x0)
* frame #0: 0x0000000123078c24 libsystem_platform.dylib`_platform_strlen + 4
frame #1: 0x00000001803c538c CoreFoundation`CFStringCreateWithCString + 40
frame #2: 0x0000000185310030 Network`nw_ws_create_client_request + 100
frame #3: 0x0000000184f4b3cc Network`__nw_ws_create_state_block_invoke + 416
frame #4: 0x000000018504bc68 Network`nw_protocol_options_access_handle + 92
frame #5: 0x0000000184f41e98 Network`nw_ws_create_state + 204
frame #6: 0x0000000184f41aec Network`__nw_protocol_copy_ws_definition_block_invoke_2 + 176
frame #7: 0x0000000184f69188 Network`nw_framer_protocol_connected + 348
frame #8: 0x00000001854a6638 Network`nw_socket_handle_socket_event(nw_socket*) + 1560
frame #9: 0x0000000126b89d50 libdispatch.dylib`_dispatch_client_callout + 16
frame #10: 0x0000000126b8d208 libdispatch.dylib`_dispatch_continuation_pop + 756
frame #11: 0x0000000126ba48d4 libdispatch.dylib`_dispatch_source_invoke + 1676
frame #12: 0x0000000126b94398 libdispatch.dylib`_dispatch_workloop_invoke + 2428
frame #13: 0x0000000126ba0b74 libdispatch.dylib`_dispatch_workloop_worker_thread + 1716
frame #14: 0x000000012371f814 libsystem_pthread.dylib`_pthread_wqthread + 284
I have found out a couple things:
There are no crashes if I initialize the NWConnection object with using, for instance, the NWEndpoint.url(_:). initializer:
let urlHost = URL(string: "ws://10.20.30.40:5060")!
let endpoint = NWEndpoint.url(urlHost)
let params = NWParameters.tcp
let webSocketOptions = NWProtocolWebSocket.Options()
params.defaultProtocolStack.applicationProtocols.insert(webSocketOptions, at: 0)
let connection = NWConnection(to: endpoint, using: params)
self.connection = connection
But, in this case, I must extract IP-addresses 🙇♂️ Meanwhile, there is a topic such as Don’t Try to Get the Device’s IP Address..
I have tried to find anything that could help me move forward in this problem and run into some odd behaviour. There is a property skipHandshake of NWProtocolWebSocket.Options object. If I set the property value to true, there are no crashes as well as no connection to a device.
I have an app that utilizes the Network Extension ( Packet Tunnel Provider ), but also uses MDNS to find local devices for data transfer via Network Extensions.
However, once connected over Peer to Peer using AWDL0 or NWConnections, it works as expected until a user shuts the screen down. It looks like there's a difference in behavior when the device is plugged in vs when it's on just battery alone.
So we can be happily sending data over p2p ( awdl0 ) then a screen shuts off and it kills the connection.
Is this expected behavior and if so is there documentation?
Also, Network Extensions do not appear to be able to discover over P2P, they can only connect to endpoints directly. Is this expected behavior?
My thoughts;
If a user allows both the Network Extension Permission and Local Network Permissions that the Network Extension should be able to discover peers via p2p. The connections ( if not asleep ) should stay active while in use.
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
Hi,
I observed some unexpected behavior and hope that someone can enlighten me as to what this is about:
mDNSResponder prepends IP / network based default search domains that are checked before any other search domain. E.g. 0.1.168.192.in-addr.arpa. would be used for an interface with an address in the the 192.168.1.0/24 subnet. This is done for any configured non-link-local IP address.
I tried to find any mention of an approach like this in RFCs but couldn't spot anything.
Please note that this is indeed a search domain and different from reverse-DNS lookups.
Example output of tcpdump for ping devtest:
10:02:13.850802 IP (tos 0x0, ttl 64, id 43461, offset 0, flags [none], proto UDP (17), length 92)
192.168.1.2.52319 > 192.168.1.1.53: 54890+ [1au] A? devtest.0.1.168.192.in-addr.arpa. (64)
I was able to identify the code that adds those default IP subnet based search domains but failed to spot any indication as to what this is about: https://github.com/apple-oss-distributions/mDNSResponder/blob/d5029b5/mDNSMacOSX/mDNSMacOSX.c#L4171-L4211
Does anyone here have an ideas as to what this might be about?
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?
I am trying to download XCode apps from my Mac to my Apple Vision Pro for testing. I have tried following the instructions by going into Settings->General->Remote Devices on my Apple Vision Pro, but there my Mac does not show up as a possible connection.
Per this page, I have made sure that both devices are connected to the same WiFi network, updated my Mac to Sonoma, and updated my AVP to the latest OS, and everything else that it asks for.
I am able to mirror my display from my Mac but downloading apps from XCode does not work.
I have also looked to enable Developer Mode by going to Settings -> Privacy & Security -> Enable Developer Mode, but there is no option for enabling developer mode here.
Per this forum, my best guess is that it is a Bonjour Protocol compatibility issue since both devices are on university wifi (WPA2), but I also tried connecting both over a hotspot which also did not work.
Since the Multipeer Connectivity framework no longer supports Bluetooth.
(https://developer.apple.com/forums/thread/749346)
Why does its official documentation still mention "In iOS, the framework uses infrastructure Wi-Fi networks, peer-to-peer Wi-Fi, and Bluetooth personal area networks for the underlying transport." ?(https://developer.apple.com/documentation/multipeerconnectivity)
What is the purpose of using Bluetooth personal area networks for the underlying transport?
Hello, In this inquiry(https://developer.apple.com/forums/thread/747860), I came across this conclusion.
“Apple disabled TCP/IP networking over Bluetooth completely. Apple’s peer-to-peer networking APIs now run exclusively over Wi-Fi."
I have three questions I would like to ask.
The Multipeer Connectivity Framework supports Wi-Fi networks, peer-to-peer Wi-Fi, and Bluetooth personal area networks. Since the framework abstracts away the underlying protocols, we cannot specify which protocol to choose. Can this framework still establish a pure Bluetooth connection now? (Not just using Bluetooth for the discovery phase).
Given that the framework supports Bluetooth protocols, why does it not require Bluetooth permissions but only local network permissions?
Does the Bluetooth protocol supported by the framework have the capability to discover traditional Bluetooth devices and services that the Core Bluetooth framework can discover?
I am currently attempting to resolve the hostname of a device connected to the same Wi-Fi network as mine. However, I've been unable to find sufficient resources or documentation on utilising the NBNS (NetBIOS Name Service) protocol for this purpose. Can someone please provide guidance on how to achieve this?
I compiled the Bonjour source code myself both for Linux and windows.
Then I succeed in publishing and detecting services for two Windows devices.
But I can't use Bonjour between a windows device and a Linux device.
So is this a limitation? If not, any tips on how to solve it?
Local network permissions are required to use the Bonjour service, But Bonjour service can also detect nearby devices through Bluetooth scanning without Bluetooth permission.
https://developer.apple.com/library/archive/qa/qa1753/_index.html#apple_ref/doc/uid/DTS40011315/
Did I misunderstand? Or is there an issue with Apple's design here?
Using the Bonjour service requires obtaining local network permissions, but the Bonjour service also scans nearby devices through Bluetooth. Why doesn't Bluetooth permission be required?
https://developer.apple.com/library/archive/qa/qa1753/_index.html#apple_ref/doc/uid/DTS40011315/
Did I misunderstand? Is there an issue with the design of iOS here?
unresolved external symbol _mdns_malloc@4 referenced in function _syslog dnssd \mDNSResponder-2200.80.16\mDNSWindows\DLL\dnssd_clientstub.obj
unresolved external symbol _mdns_free@4 referenced in function _syslog dnssd \mDNSResponder-2200.80.16\mDNSWindows\DLL\dnssd_clientstub.obj
Hello!
I'm working on VLC, that is a multimedia playback app available for any platform.
Among many things, we support discovery of servers on the local network using Bonjour, UPnP and NETBIOS with consecutive connections to those servers for media playback purposes. Additionally, we allow connections to unicast and multicast streams based on any domain name or IP (i.e. "rtsp://207.254.***.***"). Discovery of the mentioned services works very well with the Multicast entitlement along with NSLocalNetworkUsageDescription also on iOS 17.
According to documentation, iOS 17 prohibits any IP based connections by default, which breaks the entire functionality mentioned above that was previously enabled by including the NSAllowsArbitraryLoads key with the value TRUE in Info.plist.
We amended the Info.plist with the following configuration and still fail to connect to hosts in that IP range.
<key>NSAllowsLocalNetworking</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>192.168.0.0/24</key>
<dict>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSExceptionAllowsLocalNetworking</key>
<true/>
</dict>
</dict>
Additionally, there does not seem to be a viable, publicly documented solution to connect to any server on the internet based on an IP address. Further, the process for IPv6 seems unclear.
Any help how to solve this so we can transition to the iOS/tvOS 17 SDK in time would be very much appreciated.
I am facing this error on my SDK project. Could not identify what's the actual issue. I've added the Firebase crash logs below.
Crashed: com.apple.root.default-qos
0 libdispatch.dylib 0x1a778 dispatch_channel_cancel + 12
1 libdispatch.dylib 0x1a778 dispatch_source_cancel + 12
2 libsystem_dnssd.dylib 0x2084 DNSServiceProcessResult + 860
3 Common 0x2df04 __swift_memcpy5_4 + 25916
4 Common 0x10b00 block_destroy_helper.10 + 188
5 libdispatch.dylib 0x26a8 _dispatch_call_block_and_release + 32
6 libdispatch.dylib 0x4300 _dispatch_client_callout + 20
7 libdispatch.dylib 0x744c _dispatch_queue_override_invoke + 928
8 libdispatch.dylib 0x15be4 _dispatch_root_queue_drain + 392
9 libdispatch.dylib 0x163ec _dispatch_worker_thread2 + 156
10 libsystem_pthread.dylib 0x1928 _pthread_wqthread + 228
11 libsystem_pthread.dylib 0x1a04 start_wqthread + 8
How to get full DNS responses from the system resolver? DNSServiceQueryRecord not returning errors..
I would like to get the full DNS responses from the system resolver. I'm using DNSServiceQueryRecord, but I can't get negative responses. How do I get the negative responses?
I need the full response because they have clues about network-level censorship. For instance, mismatched case in the name, bad answer RR type, missing SOA record on no answers response.
On Android I can use android_res_nquery, but I couldn't find anything similar on iOS and macOS. The closest I found was DNSServiceQueryRecord, which at least gives me resource records, so I can inspect TTL and name case.
After some struggle, I was able to make it work. I'm using Go with cgo for that: https://github.com/fortuna/gio-test/blob/fortuna-dns/sysresolver_darwin.go
https://github.com/fortuna/gio-test/blob/fortuna-dns/sysresolver_darwin_export.go
My sequence of calls is:
DNSServiceQueryRecord(sdRef, 0, 0, fullname, rrtype, rrclass, (DNSServiceQueryRecordReply)goCallback, context);
fd := C.DNSServiceRefSockFD(sdRef)
nReady, err := unix.Poll([]unix.PollFd{{Fd: int32(fd), Events: unix.POLLIN | unix.POLLERR | unix.POLLHUP}}, timeout)
serviceErr = C.DNSServiceProcessResult(sdRef)
// Here my callback gets called, multiple times for multiple answers.
C.DNSServiceRefDeallocate(sdRef)
I'm able to get positive answers, even multiple answers. But the Poll doesn't return when there are no answers (like for CNAME www.example.com). I expected the poll to return on negative answers, and my callback to be called with an error when calling DNSServiceProcessResult.
Is that not the expected behavior? How do I get notified that a query has no answers?
Hi,
I have a strange problem. In my local network, I have some apple devices (including mac, iphone, ipad) and a windows computer. The windows pc and any of the apple devices can ping each other, while every two of the apple devices can't ping each other. Whether udp or tcp are in the same situation. As is the situation, the firewall/mask/local ip are not the problems. I can't use wireshark to debug, because there is not any packet between these apple devices.
Does someone know what the problem it may be? Or could someone tell me how to debug this?
Thanks in advance!
After upgrading to iOS 17 (now 17.2.1) on iPhone 11 pro the device does not appear to be discoverable on the local network via Bonjour. This is impeding, e.g., connecting to the device with iMazing etc. I looked at the local network with the Discovery app for Bonjour and while an iPad running iOS 16 is visible, the iPhone with iOS 17 is not. Any ideas ? We need to connect with iMazing via wifi since the mighty lightning port is predictably hosed for USB connection. Any insight appreciated. Thanks!
It worked fine before iOS 17.1. Just checked with iOS 16 on real device. And my teammate from QA department confirmed it works for iOS 17.0.1.
The problem occurs only with device in local network connected via ethernet. The device itself has two options for connection - via Wi-Fi and Ethernet. It works for all iOS versions via Wi-Fi. But it can't resolve host for Ethernet connection.
Error appears in
func netService(_ sender: NetService, didNotResolve errorDict: [String : NSNumber])
looks like that:
(NSNetServicesErrorDomain: 10,
NSNetServicesErrorCode: -72007)
Could you please explain this error code?
I expect there is a shockingly obvious answer to this, but I've been stuck a couple of days on Problem Obvious and could use a tip / cake-with-file to escape from development jail.
I have used DNSServiceRef / Bonjour to advertise my service, and have used the same to get a list of what is advertised (using the hit on lo0 for the moment since still testing). So, now I have a machine name "mymachine.local." and the right port number to connect to. Yay!
What I can not figure out is how to get that information into a (IPV6) sockaddr so I can use it with connect. The point of confusion for me is that DNSServiceGetAddrInfo() does not take a port argument, and I see no other place to squeeze this information into the sockaddr returned by the DNSServiceGetAddrInfoReply.
If I just use a IPV6 socket with that sockaddr, I get back EADDRNOTAVAIL. Haven't tried IPv4. No error is returned from DNSServiceGetAddrInfo. I'm reading around that this may be because the port is 0, and indeed I can't find any spot in this pathway to squeeze that information in.
I'll attach an obligatory bit of code so that the reader may feel more grounded:
// My DNSServiceGetAddrInfoReply
void ServiceList::Node::AddressInfoCallback( DNSServiceRef __nonnull _sdRef,
DNSServiceFlags _flags,
uint32_t _interfaceIndex,
DNSServiceErrorType _errorCode,
const char * __nullable _hostname,
const struct sockaddr * __nullable _address,
uint32_t UNUSED _ttl, void * __nonnull context)
{
printf( "AddressInfo: \"%s\"\n", _hostname);
AddrInfo * info = (AddrInfo*) context;
if( kDNSServiceErr_NoError != _errorCode || NULL == _hostname || NULL == _address)
{
LOG_ERROR("Failed to get address info on \"%s\"\n", (const char*) info->hostTarget);
delete info;
return;
}
int err = connect(info->socket, _address, _address->sa_len); // returns EADDRNOTAVAIL on IPv6 socket.
What am I really trying to do? I'd like to connect to the address and port that I from my DNSServiceResolveReply.