Question

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.

Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top