I have a server application running on a device on the LAN that is discoverable via DNS-SD (i.e. Zeroconf/Bonjour/Avahi). Client devices, also on the LAN, connect to this server. I have no control over what application is used to connect to my server application, but I do know that they are likely using DNS-SD and mDNS to discover and connect to the server. How can I retrieve the link-local domain name identifying these client devices given only their IP address in C or C++?
According to RFC 6762 Multicast DNS - Section 4. Reverse Address Mapping:
"Like ".local.", the IPv4 and IPv6 reverse mapping domains are also defined to be link-local...Since names under this domain correspond to IPv4 link-local addresses, it is logical that the local link is the best place to find information pertaining to those names."
So theoretically, it should be possible to look up the link-local domain names by IP address. Does anyone know how? Maybe I'm not looking in the right places, but I don't see a API call for this within the Bonjour docs.
I ended up getting an answer to this question via Apple's Bonjour Dev mailing list.
As per Quinn "The Eskimo!", here is how you can do it:
static void DNSCallback(
DNSServiceRef sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
DNSServiceErrorType errorCode,
const char *fullname,
uint16_t rrtype,
uint16_t rrclass,
uint16_t rdlen,
const void *rdata,
uint32_t ttl,
void *context
)
{
const uint8_t * cursor;
fprintf(stderr, "DNSCallback\n");
assert(rrtype == kDNSServiceType_PTR);
assert(rrclass == kDNSServiceClass_IN);
cursor = (const uint8_t *) rdata;
while ( *cursor != 0 ) {
fprintf(stderr, "%.*s.", (int) *cursor, cursor + 1);
cursor += *cursor + 1;
}
fprintf(stderr, "\n");
}
static void SocketCallBack(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info)
{
DNSServiceErrorType err;
fprintf(stderr, "SocketCallBack\n");
err = DNSServiceProcessResult(((AppDelegate *) info)->sdRef);
fprintf(stderr, "err = %d\n", (int) err);
}
- (IBAction)testAction:(id)sender
{
DNSServiceErrorType err;
int sock;
CFSocketRef cfSock;
fprintf(stderr, "-[AppDelegate testAction:]\n");
assert(self->sdRef == NULL);
err = DNSServiceQueryRecord(
&self->sdRef,
kDNSServiceFlagsForceMulticast,
0,
"9.40.0.10.in-addr.arpa.",
kDNSServiceType_PTR,
kDNSServiceClass_IN,
DNSCallback,
self
);
fprintf(stderr, "err = %d\n", (int) err);
sock = DNSServiceRefSockFD(self->sdRef);
fprintf(stderr, "sock = %d\n", sock);
CFSocketContext context = { 0, self, NULL, NULL, NULL };
cfSock = CFSocketCreateWithNative(NULL, sock, kCFSocketReadCallBack, SocketCallBack, &context);
assert(cfSock != NULL);
CFRunLoopSourceRef rls;
rls = CFSocketCreateRunLoopSource(NULL, cfSock, 0);
assert(rls != NULL);
CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
}
This example will find the link-local host name for the IP address 10.0.40.9. The IP address is inserted in reverse order.