// This function should be used only if you know that the question and // the resource record belongs to the same set. The main usage is // in ProcessQuery where we find the question to be part of the same // set as the resource record, but it needs the AnonData to be // initialized so that it can walk the cache records to see if they // answer the question. mDNSexport void SetAnonData(DNSQuestion *q, ResourceRecord *rr, mDNSBool ForQuestion) { if (!q->AnonInfo || !rr->AnonInfo) { LogMsg("SetAnonData: question %##s(%p), rr %##s(%p), NULL", q->qname.c, q->AnonInfo, rr->name->c, rr->AnonInfo); return; } debugf("SetAnonData: question %##s(%p), rr %##s(%p)", q->qname.c, q->AnonInfo, rr->name->c, rr->AnonInfo); if (ForQuestion) { if (!q->AnonInfo->AnonData) { q->AnonInfo->AnonData = mDNSPlatformMemAllocate(rr->AnonInfo->AnonDataLen); if (!q->AnonInfo->AnonData) return; } mDNSPlatformMemCopy(q->AnonInfo->AnonData, rr->AnonInfo->AnonData, rr->AnonInfo->AnonDataLen); q->AnonInfo->AnonDataLen = rr->AnonInfo->AnonDataLen; } else { if (!rr->AnonInfo->AnonData) { rr->AnonInfo->AnonData = mDNSPlatformMemAllocate(q->AnonInfo->AnonDataLen); if (!rr->AnonInfo->AnonData) return; } mDNSPlatformMemCopy(rr->AnonInfo->AnonData, q->AnonInfo->AnonData, q->AnonInfo->AnonDataLen); rr->AnonInfo->AnonDataLen = q->AnonInfo->AnonDataLen; } }
static void DNSSD_API DNSServiceGetAddrInfoResponse( DNSServiceRef inRef, DNSServiceFlags inFlags, uint32_t inInterfaceIndex, DNSServiceErrorType inErrorCode, const char * inFullName, uint16_t inRRType, uint16_t inRRClass, uint16_t inRDLen, const void * inRData, uint32_t inTTL, void * inContext ) { mDNS_DirectOP_GetAddrInfo * x = (mDNS_DirectOP_GetAddrInfo*)inContext; struct sockaddr_in sa4; mDNSPlatformMemZero(&sa4, sizeof(sa4)); if (inErrorCode == kDNSServiceErr_NoError && inRRType == kDNSServiceType_A) { sa4.sin_family = AF_INET; mDNSPlatformMemCopy(&sa4.sin_addr.s_addr, inRData, 4); } x->callback((DNSServiceRef)x, inFlags, inInterfaceIndex, inErrorCode, inFullName, (const struct sockaddr *) &sa4, inTTL, x->context); }
// When a service is started or a browse is started with the Anonymous data, we allocate a new random // number and based on that allocate a new NSEC3 resource record whose hash is a function of random number (salt) and // the anonymous data. // // If we receive a packet with the NSEC3 option, we need to cache that along with the resource record so that we can // check against the question to see whether it answers them or not. In that case, we pass the "rr" that we received. mDNSexport AnonymousInfo *AllocateAnonInfo(const domainname *service, const mDNSu8 *data, int len, const ResourceRecord *rr) { AnonymousInfo *ai; ai = (AnonymousInfo *)mDNSPlatformMemAllocate(sizeof(AnonymousInfo)); if (!ai) { return mDNSNULL; } mDNSPlatformMemZero(ai, sizeof(AnonymousInfo)); if (rr) { if (!CopyNSEC3ResourceRecord(ai, rr)) { mDNSPlatformMemFree(ai); return mDNSNULL; } return ai; } ai->salt = mDNSRandom(0xFFFFFFFF); ai->AnonData = mDNSPlatformMemAllocate(len); if (!ai->AnonData) { mDNSPlatformMemFree(ai); return mDNSNULL; } ai->AnonDataLen = len; mDNSPlatformMemCopy(ai->AnonData, data, len); ai->nsec3RR = ConstructNSEC3Record(service, data, len, ai->salt); if (!ai->nsec3RR) { mDNSPlatformMemFree(ai); return mDNSNULL; } return ai; }
mDNSlocal ResourceRecord *CopyNSEC3ResourceRecord(AnonymousInfo *si, const ResourceRecord *rr) { int len; domainname *name; ResourceRecord *nsec3rr; if (rr->rdlength < MCAST_NSEC3_RDLENGTH) { LogMsg("CopyNSEC3ResourceRecord: rdlength %d smaller than MCAST_NSEC3_RDLENGTH %d", rr->rdlength, MCAST_NSEC3_RDLENGTH); return mDNSNULL; } // Allocate space for the name and the rdata along with the ResourceRecord len = DomainNameLength(rr->name); nsec3rr = mDNSPlatformMemAllocate(sizeof(ResourceRecord) + len + sizeof(RData)); if (!nsec3rr) return mDNSNULL; *nsec3rr = *rr; name = (domainname *)((mDNSu8 *)nsec3rr + sizeof(ResourceRecord)); nsec3rr->name = (const domainname *)name; AssignDomainName(name, rr->name); nsec3rr->rdata = (RData *)((mDNSu8 *)nsec3rr->name + len); mDNSPlatformMemCopy(nsec3rr->rdata->u.data, rr->rdata->u.data, rr->rdlength); si->nsec3RR = nsec3rr; return nsec3rr; }
mDNSlocal mDNSBool InitializeNSEC3Record(ResourceRecord *rr, const mDNSu8 *AnonData, int len, mDNSu32 salt) { const mDNSu8 *ptr; rdataNSEC3 *nsec3 = (rdataNSEC3 *)rr->rdata->u.data; mDNSu8 *tmp, *nxt; unsigned short iter = ANON_NSEC3_ITERATIONS; int hlen; const mDNSu8 hashName[NSEC3_MAX_HASH_LEN]; // Construct the RDATA first and construct the owner name based on that. ptr = (const mDNSu8 *)&salt; debugf("InitializeNSEC3Record: %x%x%x%x, name %##s", ptr[0], ptr[1], ptr[2], ptr[3], rr->name->c); // Set the RDATA nsec3->alg = SHA1_DIGEST_TYPE; nsec3->flags = 0; nsec3->iterations = swap16(iter); nsec3->saltLength = 4; tmp = (mDNSu8 *)&nsec3->salt; *tmp++ = ptr[0]; *tmp++ = ptr[1]; *tmp++ = ptr[2]; *tmp++ = ptr[3]; // hashLength, nxt, bitmap *tmp++ = SHA1_HASH_LENGTH; // hash length nxt = tmp; tmp += SHA1_HASH_LENGTH; *tmp++ = 0; // window number *tmp++ = NSEC_MCAST_WINDOW_SIZE; // window length mDNSPlatformMemZero(tmp, NSEC_MCAST_WINDOW_SIZE); tmp[kDNSType_PTR >> 3] |= 128 >> (kDNSType_PTR & 7); // Hash the base service name + salt + AnonData if (!NSEC3HashName(rr->name, nsec3, AnonData, len, hashName, &hlen)) { LogMsg("InitializeNSEC3Record: NSEC3HashName failed for ##s", rr->name->c); return mDNSfalse; } if (hlen != SHA1_HASH_LENGTH) { LogMsg("InitializeNSEC3Record: hlen wrong %d", hlen); return mDNSfalse; } mDNSPlatformMemCopy(nxt, hashName, hlen); return mDNStrue; }
mDNSexport int main(int argc, char **argv) { const char *progname = strrchr(argv[0], '/') ? strrchr(argv[0], '/') + 1 : argv[0]; int this_arg = 1; mStatus status; struct in_addr s4; #if HAVE_IPV6 struct in6_addr s6; #endif char buffer[256]; DNSQuestion q; if (argc < 2) goto usage; // Since this is a special command-line tool, we want LogMsg() errors to go to stderr, not syslog mDNS_DebugMode = mDNStrue; // Initialise the mDNS core. status = mDNS_Init(&mDNSStorage, &PlatformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_DontAdvertiseLocalAddresses, mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext); if (status) { fprintf(stderr, "Daemon start: mDNS_Init failed %d\n", (int)status); return(status); } signal(SIGINT, HandleSIG); // SIGINT is what you get for a Ctrl-C signal(SIGTERM, HandleSIG); while (this_arg < argc) { char *arg = argv[this_arg++]; if (this_arg > 2) printf("\n"); lastid = id = zeroID; hostaddr = target = zeroAddr; hostname[0] = hardware[0] = software[0] = 0; NumAddr = NumAAAA = NumHINFO = 0; if (inet_pton(AF_INET, arg, &s4) == 1) { mDNSu8 *p = (mDNSu8 *)&s4; // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.", p[3], p[2], p[1], p[0]); printf("%s\n", buffer); target.type = mDNSAddrType_IPv4; target.ip.v4.NotAnInteger = s4.s_addr; DoQuery(&q, buffer, kDNSType_PTR, &target, NameCallback); if (StopNow == 2) break; } #if HAVE_IPV6 else if (inet_pton(AF_INET6, arg, &s6) == 1) { int i; mDNSu8 *p = (mDNSu8 *)&s6; for (i = 0; i < 16; i++) { static const char hexValues[] = "0123456789ABCDEF"; buffer[i * 4 ] = hexValues[p[15-i] & 0x0F]; buffer[i * 4 + 1] = '.'; buffer[i * 4 + 2] = hexValues[p[15-i] >> 4]; buffer[i * 4 + 3] = '.'; } mDNS_snprintf(&buffer[64], sizeof(buffer)-64, "ip6.arpa."); target.type = mDNSAddrType_IPv6; mDNSPlatformMemCopy(&target.ip.v6, &s6, sizeof(target.ip.v6)); DoQuery(&q, buffer, kDNSType_PTR, &target, NameCallback); if (StopNow == 2) break; } #endif else { if (strlen(arg) >= sizeof(hostname))