// 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; } }
// 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; }
// This function does a simple parse of an HTTP URL that may include a hostname, port, and path // If found in the URL, addressAndPort and path out params will point to newly allocated space (and will leak if they were previously pointing at allocated space) mDNSlocal mStatus ParseHttpUrl(char* ptr, char* end, mDNSu8** addressAndPort, mDNSIPPort* port, mDNSu8** path) { // if the data begins with "http://", we assume there is a hostname and possibly a port number if (end - ptr >= 7 && strncasecmp(ptr, "http://", 7) == 0) { int i; char* stop = end; char* addrPtr = mDNSNULL; ptr += 7; //skip over "http://" if (ptr >= end) { LogInfo("ParseHttpUrl: past end of buffer parsing host:port"); return mStatus_BadParamErr; } // find the end of the host:port addrPtr = ptr; for (i = 0; addrPtr && addrPtr != end; i++, addrPtr++) if (*addrPtr == '/') break; // allocate the buffer (len i+1 so we have space to terminate the string) if ((*addressAndPort = (mDNSu8 *) mDNSPlatformMemAllocate(i+1)) == mDNSNULL) { LogMsg("ParseHttpUrl: can't allocate address string"); return mStatus_NoMemoryErr; } strncpy((char *)*addressAndPort, ptr, i); (*addressAndPort)[i] = '\0'; // find the port number in the string, by looking backwards for the ':' stop = ptr; // can't go back farther than the original start ptr = addrPtr; // move ptr to the path part for (addrPtr--;addrPtr>stop;addrPtr--) { if (*addrPtr == ':') { int tmpport; addrPtr++; // skip over ':' tmpport = (int)strtol(addrPtr, mDNSNULL, 10); *port = mDNSOpaque16fromIntVal(tmpport); // store it properly converted break; } } } // ptr should now point to the first character we haven't yet processed // everything that remains is the path if (path && ptr < end) { if ((*path = (mDNSu8 *)mDNSPlatformMemAllocate(end - ptr + 1)) == mDNSNULL) { LogMsg("ParseHttpUrl: can't mDNSPlatformMemAllocate path"); return mStatus_NoMemoryErr; } strncpy((char *)*path, ptr, end - ptr); (*path)[end - ptr] = '\0'; } return mStatus_NoError; }
mDNSlocal mDNSu8 *ConvertDigest(char *digest, int digestType, int *diglen) { int i, j; mDNSu8 *dig; switch (digestType) { case SHA1_DIGEST_TYPE: *diglen = CC_SHA1_DIGEST_LENGTH; break; case SHA256_DIGEST_TYPE: *diglen = CC_SHA256_DIGEST_LENGTH; break; default: LogMsg("ConvertDigest: digest type %d not supported", digestType); return mDNSNULL; } dig = mDNSPlatformMemAllocate(*diglen); if (!dig) { LogMsg("ConvertDigest: malloc failure"); return mDNSNULL; } for (j=0,i=0; i<*diglen*2; i+=2) { int l, h; l = HexVal(digest[i]); h = HexVal(digest[i+1]); if (l<0 || h<0) { LogMsg("ConvertDigest: Cannot convert digest"); return NULL;} dig[j++] = (mDNSu8)((l << 4) | h); } return dig; }
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; }
DNSServiceErrorType DNSSD_API DNSServiceQueryRecord ( DNSServiceRef *sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, const char *fullname, uint16_t rrtype, uint16_t rrclass, DNSServiceQueryRecordReply callback, void *context /* may be NULL */ ) { mStatus err = mStatus_NoError; const char *errormsg = "Unknown"; mDNS_DirectOP_QueryRecord *x; (void)flags; // Unused (void)interfaceIndex; // Unused // Allocate memory, and handle failure x = (mDNS_DirectOP_QueryRecord *)mDNSPlatformMemAllocate(sizeof(*x)); if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; } // Set up object x->disposefn = DNSServiceQueryRecordDispose; x->callback = callback; x->context = context; x->q.ThisQInterval = -1; // So that DNSServiceResolveDispose() knows whether to cancel this question x->q.InterfaceID = mDNSInterface_Any; x->q.Target = zeroAddr; MakeDomainNameFromDNSNameString(&x->q.qname, fullname); x->q.qtype = rrtype; x->q.qclass = rrclass; x->q.LongLived = (flags & kDNSServiceFlagsLongLivedQuery) != 0; x->q.ExpectUnique = mDNSfalse; x->q.ForceMCast = (flags & kDNSServiceFlagsForceMulticast) != 0; x->q.ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0; x->q.SuppressUnusable = (flags & kDNSServiceFlagsSuppressUnusable) != 0; x->q.SearchListIndex = 0; x->q.AppendSearchDomains = 0; x->q.RetryWithSearchDomains = mDNSfalse; x->q.WakeOnResolve = 0; x->q.qnameOrig = mDNSNULL; x->q.QuestionCallback = DNSServiceQueryRecordResponse; x->q.QuestionContext = x; err = mDNS_StartQuery(&mDNSStorage, &x->q); if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery"; goto fail; } // Succeeded: Wrap up and return *sdRef = (DNSServiceRef)x; return(mStatus_NoError); fail: LogMsg("DNSServiceQueryRecord(\"%s\", %d, %d) failed: %s (%ld)", fullname, rrtype, rrclass, errormsg, err); return(err); }
mDNSlocal mStatus SendSOAPMsgControlAction(mDNS *m, tcpLNTInfo *info, char *Action, int numArgs, Property *Arguments, LNTOp_t op) { // SOAP message header format - // - control URL // - action (string) // - router's host/port ("host:port") // - content-length static const char header[] = "POST %s HTTP/1.1\r\n" "Content-Type: text/xml; charset=\"utf-8\"\r\n" "SOAPAction: \"urn:schemas-upnp-org:service:WAN%sConnection:1#%s\"\r\n" "User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x)\r\n" "Host: %s\r\n" "Content-Length: %d\r\n" "Connection: close\r\n" "Pragma: no-cache\r\n" "\r\n" "%s\r\n"; static const char body1[] = "<?xml version=\"1.0\"?>\r\n" "<SOAP-ENV:Envelope" " xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"" " SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" "<SOAP-ENV:Body>" "<m:%s xmlns:m=\"urn:schemas-upnp-org:service:WAN%sConnection:1\">"; static const char body2[] = "</m:%s>" "</SOAP-ENV:Body>" "</SOAP-ENV:Envelope>\r\n"; mStatus err; char *body = (char *)&m->omsg; // Typically requires 1110-1122 bytes; m->omsg is 8952 bytes, which is plenty int bodyLen; if (mDNSIPPortIsZero(m->UPnPSOAPPort) || m->UPnPSOAPURL == mDNSNULL || m->UPnPSOAPAddressString == mDNSNULL) // if no SOAP URL or address exists get out here { LogInfo("SendSOAPMsgControlAction: no SOAP port, URL or address string"); return mStatus_Invalid; } // Create body bodyLen = mDNS_snprintf (body, sizeof(m->omsg), body1, Action, m->UPnPWANPPPConnection ? "PPP" : "IP"); bodyLen += AddSOAPArguments(body + bodyLen, sizeof(m->omsg) - bodyLen, numArgs, Arguments); bodyLen += mDNS_snprintf (body + bodyLen, sizeof(m->omsg) - bodyLen, body2, Action); // Create info->Request; the header needs to contain the bodyLen in the "Content-Length" field if (!info->Request) info->Request = mDNSPlatformMemAllocate(LNT_MAXBUFSIZE); if (!info->Request) { LogMsg("SendSOAPMsgControlAction: Can't allocate info->Request"); return mStatus_NoMemoryErr; } info->requestLen = mDNS_snprintf((char *)info->Request, LNT_MAXBUFSIZE, header, m->UPnPSOAPURL, m->UPnPWANPPPConnection ? "PPP" : "IP", Action, m->UPnPSOAPAddressString, bodyLen, body); err = MakeTCPConnection(m, info, &m->Router, m->UPnPSOAPPort, op); if (err) { mDNSPlatformMemFree(info->Request); info->Request = mDNSNULL; } return err; }
mDNSexport void ReadDDNSSettingsFromConfFile(mDNS *const m, const char *const filename, domainname *const hostname, domainname *const domain, mDNSBool *DomainDiscoveryDisabled) { char buf[MAX_ESCAPED_DOMAIN_NAME] = ""; char knn[MAX_ESCAPED_DOMAIN_NAME] = ""; domainname keyName; mDNSIPPort port; keyName.c[0] = knn[0] = 0; mStatus err; FILE *f = fopen(filename, "r"); if (hostname) hostname->c[0] = 0; if (domain) domain->c[0] = 0; if (DomainDiscoveryDisabled) *DomainDiscoveryDisabled = mDNSfalse; port = UnicastDNSPort; if (f) { if (DomainDiscoveryDisabled && GetConfigOption(buf, "DomainDiscoveryDisabled", f) && !strcasecmp(buf, "true")) *DomainDiscoveryDisabled = mDNStrue; if (hostname && GetConfigOption(buf, "hostname", f) && !MakeDomainNameFromDNSNameString(hostname, buf)) goto badf; if (domain && GetConfigOption(buf, "zone", f) && !MakeDomainNameFromDNSNameString(domain, buf)) goto badf; if (GetConfigOption(buf, "port", f)) { port = mDNSOpaque16fromIntVal(strtol(buf, (char **)NULL, 10)); } buf[0] = 0; GetConfigOption(buf, "secret-64", f); // failure means no authentication if (GetConfigOption(knn, "secret-name", f)) MakeDomainNameFromDNSNameString(&keyName, knn); fclose(f); f = NULL; } else { if (errno != ENOENT) LogMsg("ERROR: Config file exists, but cannot be opened."); return; } if (domain && domain->c[0] && buf[0]) { DomainAuthInfo *info = (DomainAuthInfo*)mDNSPlatformMemAllocate(sizeof(*info)); // for now we assume keyname = service reg domain and we use same key for service and hostname registration err = mDNS_SetSecretForDomain(m, info, domain, (keyName.c[0] ? &keyName : domain), buf, hostname, &port, NULL); if (err) LogMsg("ERROR: mDNS_SetSecretForDomain returned %d for domain %##s", err, domain->c); } return; badf: LogMsg("ERROR: malformatted config file"); if (f) fclose(f); }
DNSServiceErrorType DNSServiceBrowse ( DNSServiceRef *sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, const char *regtype, const char *domain, /* may be NULL */ DNSServiceBrowseReply callback, void *context /* may be NULL */ ) { mStatus err = mStatus_NoError; const char *errormsg = "Unknown"; domainname t, d; mDNS_DirectOP_Browse *x; (void)flags; // Unused (void)interfaceIndex; // Unused // Check parameters if (!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype)) { errormsg = "Illegal regtype"; goto badparam; } if (!MakeDomainNameFromDNSNameString(&d, *domain ? domain : "local.")) { errormsg = "Illegal domain"; goto badparam; } // Allocate memory, and handle failure x = (mDNS_DirectOP_Browse *)mDNSPlatformMemAllocate(sizeof(*x)); if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; } // Set up object x->disposefn = DNSServiceBrowseDispose; x->callback = callback; x->context = context; x->q.QuestionContext = x; // Do the operation err = mDNS_StartBrowse(&mDNSStorage, &x->q, &t, &d, mDNSInterface_Any, (flags & kDNSServiceFlagsForceMulticast) != 0, FoundInstance, x); if (err) { mDNSPlatformMemFree(x); errormsg = "mDNS_StartBrowse"; goto fail; } // Succeeded: Wrap up and return *sdRef = (DNSServiceRef)x; return(mStatus_NoError); badparam: err = mStatus_BadParamErr; fail: LogMsg("DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", regtype, domain, errormsg, err); return(err); }
mDNSexport AlgContext *AlgCreate(AlgType type, mDNSu8 alg) { AlgFuncs *func = mDNSNULL; AlgContext *ctx; if (type == CRYPTO_ALG) { if (alg >= CRYPTO_ALG_MAX) return mDNSNULL; func = CryptoAlgFuncs[alg]; } else if (type == DIGEST_ALG) { if (alg >= DIGEST_TYPE_MAX) return mDNSNULL; func = DigestAlgFuncs[alg]; } else if (type == ENC_ALG) { if (alg >= ENC_ALG_MAX) return mDNSNULL; func = EncAlgFuncs[alg]; } if (!func) { // If there is no support from the platform, this case can happen. LogInfo("AlgCreate: func is NULL"); return mDNSNULL; } if (func->Create) { mStatus err; ctx = mDNSPlatformMemAllocate(sizeof(AlgContext)); if (!ctx) return mDNSNULL; // Create expects ctx->alg to be initialized ctx->alg = alg; err = func->Create(ctx); if (err == mStatus_NoError) { ctx->type = type; return ctx; } mDNSPlatformMemFree(ctx); } return mDNSNULL; }
mDNSexport mStatus LNT_UnmapPort(mDNS *m, NATTraversalInfo *n) { char externalPort[10]; Property propArgs[3]; tcpLNTInfo *info; tcpLNTInfo **infoPtr = &m->tcpInfoUnmapList; mStatus err; // If no NAT gateway to talk to, no need to do all this work for nothing if (mDNSIPPortIsZero(m->UPnPSOAPPort) || !m->UPnPSOAPURL || !m->UPnPSOAPAddressString) return mStatus_NoError; mDNS_snprintf(externalPort, sizeof(externalPort), "%u", mDNSVal16(mDNSIPPortIsZero(n->RequestedPort) ? n->IntPort : n->RequestedPort)); mDNSPlatformMemZero(propArgs, sizeof(propArgs)); propArgs[0].name = "NewRemoteHost"; propArgs[0].type = "string"; propArgs[0].value = ""; propArgs[1].name = "NewExternalPort"; propArgs[1].type = "ui2"; propArgs[1].value = externalPort; propArgs[2].name = "NewProtocol"; propArgs[2].type = "string"; propArgs[2].value = (n->Protocol == NATOp_MapUDP) ? "UDP" : "TCP"; n->tcpInfo.parentNATInfo = n; // clean up previous port mapping requests and allocations if (n->tcpInfo.sock) LogInfo("LNT_UnmapPort: closing previous open connection"); if (n->tcpInfo.sock ) { mDNSPlatformTCPCloseConnection(n->tcpInfo.sock); n->tcpInfo.sock = mDNSNULL; } if (n->tcpInfo.Request) { mDNSPlatformMemFree(n->tcpInfo.Request); n->tcpInfo.Request = mDNSNULL; } if (n->tcpInfo.Reply ) { mDNSPlatformMemFree(n->tcpInfo.Reply); n->tcpInfo.Reply = mDNSNULL; } // make a copy of the tcpInfo that we can clean up later (the one passed in will be destroyed by the client as soon as this returns) if ((info = mDNSPlatformMemAllocate(sizeof(tcpLNTInfo))) == mDNSNULL) { LogInfo("LNT_UnmapPort: can't allocate tcpInfo"); return(mStatus_NoMemoryErr); } *info = n->tcpInfo; while (*infoPtr) infoPtr = &(*infoPtr)->next; // find the end of the list *infoPtr = info; // append err = SendSOAPMsgControlAction(m, info, "DeletePortMapping", 3, propArgs, LNTPortMapDeleteOp); if (err) DisposeInfoFromUnmapList(m, info); return err; }
mDNSexport AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p) { AuthRecord *st = mDNSNULL; if (NumSubTypes) { mDNSs32 i; st = mDNSPlatformMemAllocate(NumSubTypes * sizeof(AuthRecord)); if (!st) return(mDNSNULL); for (i = 0; i < NumSubTypes; i++) { mDNS_SetupResourceRecord(&st[i], mDNSNULL, mDNSInterface_Any, kDNSQType_ANY, kStandardTTL, 0, AuthRecordAny, mDNSNULL, mDNSNULL); while (*p) p++; p++; if (!MakeDomainNameFromDNSNameString(&st[i].namestorage, p)) { mDNSPlatformMemFree(st); return(mDNSNULL); } } } return(st); }
mDNSlocal mStatus MakeTCPConnection(mDNS *const m, tcpLNTInfo *info, const mDNSAddr *const Addr, const mDNSIPPort Port, LNTOp_t op) { mStatus err = mStatus_NoError; mDNSIPPort srcport = zeroIPPort; if (mDNSIPv4AddressIsZero(Addr->ip.v4) || mDNSIPPortIsZero(Port)) { LogMsg("LNT MakeTCPConnection: bad address/port %#a:%d", Addr, mDNSVal16(Port)); return(mStatus_Invalid); } info->m = m; info->Address = *Addr; info->Port = Port; info->op = op; info->nread = 0; info->replyLen = LNT_MAXBUFSIZE; if (info->Reply != mDNSNULL) mDNSPlatformMemZero(info->Reply, LNT_MAXBUFSIZE); // reuse previously allocated buffer else if ((info->Reply = (mDNSs8 *) mDNSPlatformMemAllocate(LNT_MAXBUFSIZE)) == mDNSNULL) { LogInfo("can't allocate reply buffer"); return (mStatus_NoMemoryErr); } if (info->sock) { LogInfo("MakeTCPConnection: closing previous open connection"); mDNSPlatformTCPCloseConnection(info->sock); info->sock = mDNSNULL; } info->sock = mDNSPlatformTCPSocket(m, kTCPSocketFlags_Zero, &srcport); if (!info->sock) { LogMsg("LNT MakeTCPConnection: unable to create TCP socket"); mDNSPlatformMemFree(info->Reply); info->Reply = mDNSNULL; return(mStatus_NoMemoryErr); } LogInfo("MakeTCPConnection: connecting to %#a:%d", &info->Address, mDNSVal16(info->Port)); err = mDNSPlatformTCPConnect(info->sock, Addr, Port, 0, tcpConnectionCallback, info); if (err == mStatus_ConnPending) err = mStatus_NoError; else if (err == mStatus_ConnEstablished) { mDNS_DropLockBeforeCallback(); tcpConnectionCallback(info->sock, info, mDNStrue, mStatus_NoError); mDNS_ReclaimLockAfterCallback(); err = mStatus_NoError; } else { // Don't need to log this in customer builds -- it happens quite often during sleep, wake, configuration changes, etc. LogInfo("LNT MakeTCPConnection: connection failed"); mDNSPlatformTCPCloseConnection(info->sock); // Dispose the socket we created with mDNSPlatformTCPSocket() above info->sock = mDNSNULL; mDNSPlatformMemFree(info->Reply); info->Reply = mDNSNULL; } return(err); }
mDNSlocal ResourceRecord *ConstructNSEC3Record(const domainname *service, const mDNSu8 *AnonData, int len, mDNSu32 salt) { ResourceRecord *rr; int dlen; domainname *name; // We are just allocating an RData which has StandardAuthRDSize if (StandardAuthRDSize < MCAST_NSEC3_RDLENGTH) { LogMsg("ConstructNSEC3Record: StandardAuthRDSize %d smaller than MCAST_NSEC3_RDLENGTH %d", StandardAuthRDSize, MCAST_NSEC3_RDLENGTH); return mDNSNULL; } dlen = DomainNameLength(service); // Allocate space for the name and RData. rr = mDNSPlatformMemAllocate(sizeof(ResourceRecord) + dlen + sizeof(RData)); if (!rr) return mDNSNULL; name = (domainname *)((mDNSu8 *)rr + sizeof(ResourceRecord)); rr->RecordType = kDNSRecordTypePacketAuth; rr->InterfaceID = mDNSInterface_Any; rr->name = (const domainname *)name; rr->rrtype = kDNSType_NSEC3; rr->rrclass = kDNSClass_IN; rr->rroriginalttl = kStandardTTL; rr->rDNSServer = mDNSNULL; rr->rdlength = MCAST_NSEC3_RDLENGTH; rr->rdestimate = MCAST_NSEC3_RDLENGTH; rr->rdata = (RData *)((mDNSu8 *)rr->name + dlen); AssignDomainName(name, service); if (!InitializeNSEC3Record(rr, AnonData, len, salt)) { mDNSPlatformMemFree(rr); return mDNSNULL; } return rr; }
DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo( DNSServiceRef * outRef, DNSServiceFlags inFlags, uint32_t inInterfaceIndex, DNSServiceProtocol inProtocol, const char * inHostName, DNSServiceGetAddrInfoReply inCallback, void * inContext ) { const char * errormsg = "Unknown"; DNSServiceErrorType err; mDNS_DirectOP_GetAddrInfo * x; // Allocate memory, and handle failure x = (mDNS_DirectOP_GetAddrInfo *)mDNSPlatformMemAllocate(sizeof(*x)); if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; } // Set up object x->disposefn = DNSServiceGetAddrInfoDispose; x->callback = inCallback; x->context = inContext; x->aQuery = mDNSNULL; // Start the query. // (It would probably be more efficient to code this using mDNS_StartQuery directly, // instead of wrapping DNSServiceQueryRecord, which then unnecessarily allocates // more memory and then just calls through to mDNS_StartQuery. -- SC June 2010) err = DNSServiceQueryRecord(&x->aQuery, inFlags, inInterfaceIndex, inHostName, kDNSServiceType_A, kDNSServiceClass_IN, DNSServiceGetAddrInfoResponse, x); if (err) { DNSServiceGetAddrInfoDispose((mDNS_DirectOP*)x); errormsg = "DNSServiceQueryRecord"; goto fail; } *outRef = (DNSServiceRef)x; return(mStatus_NoError); fail: LogMsg("DNSServiceGetAddrInfo(\"%s\", %d) failed: %s (%ld)", inHostName, inProtocol, errormsg, err); return(err); }
mDNSlocal void AddTrustAnchor(mDNS *const m, const domainname *zone, mDNSu16 keytag, mDNSu8 alg, mDNSu8 digestType, int diglen, mDNSu8 *digest) { TrustAnchor *ta, *tmp; mDNSu32 t = (mDNSu32) time(NULL); // Check for duplicates tmp = m->TrustAnchors; while (tmp) { if (SameDomainName(zone, &tmp->zone) && tmp->rds.keyTag == keytag && tmp->rds.alg == alg && tmp->rds.digestType == digestType && !memcmp(tmp->rds.digest, digest, diglen)) { LogMsg("AddTrustAnchors: Found a duplicate"); return; } tmp = tmp->next; } ta = (TrustAnchor *)mDNSPlatformMemAllocate(sizeof(TrustAnchor)); if (!ta) { LogMsg("AddTrustAnchor: malloc failure ta"); return; } ta->rds.keyTag = keytag; ta->rds.alg = alg; ta->rds.digestType = digestType; ta->rds.digest = digest; ta->digestLen = diglen; ta->validFrom = t; ta->validUntil = t + TEST_TA_EXPIRE_INTERVAL; AssignDomainName(&ta->zone, zone); ta->next = mDNSNULL; LinkTrustAnchor(m, ta); }
mDNSlocal mStatus GetDeviceDescription(mDNS *m, tcpLNTInfo *info) { // Device description format - // - device description URL // - host/port static const char szSSDPMsgDescribeDeviceFMT[] = "GET %s HTTP/1.1\r\n" "Accept: text/xml, application/xml\r\n" "User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)\r\n" "Host: %s\r\n" "Connection: close\r\n" "\r\n"; if (!mDNSIPPortIsZero(m->UPnPSOAPPort)) return mStatus_NoError; // already have the info we need if (m->UPnPRouterURL == mDNSNULL || m->UPnPRouterAddressString == mDNSNULL) { LogInfo("GetDeviceDescription: no router URL or address string!"); return (mStatus_Invalid); } // build message if (info->Request != mDNSNULL) mDNSPlatformMemZero(info->Request, LNT_MAXBUFSIZE); // reuse previously allocated buffer else if ((info->Request = (mDNSs8 *) mDNSPlatformMemAllocate(LNT_MAXBUFSIZE)) == mDNSNULL) { LogInfo("can't allocate send buffer for discovery"); return (mStatus_NoMemoryErr); } info->requestLen = mDNS_snprintf((char *)info->Request, LNT_MAXBUFSIZE, szSSDPMsgDescribeDeviceFMT, m->UPnPRouterURL, m->UPnPRouterAddressString); LogInfo("Describe Device: [%s]", info->Request); return MakeTCPConnection(m, info, &m->Router, m->UPnPRouterPort, LNTDiscoveryOp); }
mDNSlocal void FetchRootTA(mDNS *const m) { CFStringRef urlString = CFSTR("https://data.iana.org/root-anchors/root-anchors.xml"); CFDataRef xmlData; CFStringRef fileRef = NULL; const char *xmlFileName = NULL; char buf[512]; CFURLRef url = NULL; static unsigned int RootTAFetchInterval = InitialTAFetchInterval; (void) m; TrustAnchor *ta = (TrustAnchor *)mDNSPlatformMemAllocate(sizeof(TrustAnchor)); if (!ta) { LogMsg("FetchRootTA: TrustAnchor alloc failed"); return; } memset(ta, 0, sizeof(TrustAnchor)); url = CFURLCreateWithString(NULL, urlString, NULL); if (!url) { LogMsg("FetchRootTA: CFURLCreateWithString error"); mDNSPlatformMemFree(ta); return; } // If we can't fetch the XML file e.g., network problems, trigger a timer. All other failures // should hardly happen in practice for which schedule the normal interval to refetch the TA. if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, url, &xmlData, NULL, NULL, NULL)) { LogInfo("FetchRootTA: CFURLCreateDataAndPropertiesFromResource error"); CFRelease(url); mDNSPlatformMemFree(ta); RegisterNotification(m, RootTAFetchInterval); RootTAFetchInterval *= 2 + 1; return; } // get the name of the last component from the url, libxml will use it if // it has to report an error fileRef = CFURLCopyLastPathComponent(url); if (fileRef) { xmlFileName = CFStringGetCStringPtr(fileRef, kCFStringEncodingUTF8); if (!xmlFileName) { if (!CFStringGetCString(fileRef, buf, sizeof(buf), kCFStringEncodingUTF8) ) strlcpy(buf, "nofile.xml", sizeof(buf)); xmlFileName = (const char *)buf; } } // Parse the XML and get the CFXMLTree. xmlDocPtr tadoc = xmlReadMemory((const char*)CFDataGetBytePtr(xmlData), (int)CFDataGetLength(xmlData), xmlFileName, NULL, 0); CFRelease(fileRef); CFRelease(url); CFRelease(xmlData); if (!tadoc) { LogMsg("FetchRootTA: xmlReadMemory failed"); goto done; } xmlNodePtr root = xmlDocGetRootElement(tadoc); if (!root) { LogMsg("FetchRootTA: Cannot get root element"); goto done; } if (ParseElement(tadoc, root, ta) && ValidateTrustAnchor(ta)) { // Do the actual addition of TA on the main queue. mDNSPlatformDispatchAsync(m, ta, TAComplete); } else { if (ta->rds.digest) mDNSPlatformMemFree(ta->rds.digest); mDNSPlatformMemFree(ta); } done: if (tadoc) xmlFreeDoc(tadoc); RegisterNotification(m, ROOT_TA_UPDATE_INTERVAL); RootTAFetchInterval = InitialTAFetchInterval; return; }
// Note that this function assumes src is already NULL terminated mDNSlocal void AllocAndCopy(mDNSu8** dst, mDNSu8* src) { if (src == mDNSNULL) return; if ((*dst = (mDNSu8 *) mDNSPlatformMemAllocate(strlen((char*)src) + 1)) == mDNSNULL) { LogMsg("AllocAndCopy: can't allocate string"); return; } strcpy((char *)*dst, (char*)src); }
DNSServiceErrorType DNSServiceResolve ( DNSServiceRef *sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, const char *name, const char *regtype, const char *domain, DNSServiceResolveReply callback, void *context /* may be NULL */ ) { mStatus err = mStatus_NoError; const char *errormsg = "Unknown"; domainlabel n; domainname t, d, srv; mDNS_DirectOP_Resolve *x; (void)flags; // Unused (void)interfaceIndex; // Unused // Check parameters if (!name[0] || !MakeDomainLabelFromLiteralString(&n, name )) { errormsg = "Bad Instance Name"; goto badparam; } if (!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype)) { errormsg = "Bad Service Type"; goto badparam; } if (!domain[0] || !MakeDomainNameFromDNSNameString(&d, domain )) { errormsg = "Bad Domain"; goto badparam; } if (!ConstructServiceName(&srv, &n, &t, &d)) { errormsg = "Bad Name"; goto badparam; } // Allocate memory, and handle failure x = (mDNS_DirectOP_Resolve *)mDNSPlatformMemAllocate(sizeof(*x)); if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; } // Set up object x->disposefn = DNSServiceResolveDispose; x->callback = callback; x->context = context; x->SRV = mDNSNULL; x->TXT = mDNSNULL; x->qSRV.ThisQInterval = -1; // So that DNSServiceResolveDispose() knows whether to cancel this question x->qSRV.InterfaceID = mDNSInterface_Any; x->qSRV.Target = zeroAddr; AssignDomainName(&x->qSRV.qname, &srv); x->qSRV.qtype = kDNSType_SRV; x->qSRV.qclass = kDNSClass_IN; x->qSRV.LongLived = mDNSfalse; x->qSRV.ExpectUnique = mDNStrue; x->qSRV.ForceMCast = mDNSfalse; x->qSRV.QuestionCallback = FoundServiceInfo; x->qSRV.QuestionContext = x; x->qTXT.ThisQInterval = -1; // So that DNSServiceResolveDispose() knows whether to cancel this question x->qTXT.InterfaceID = mDNSInterface_Any; x->qTXT.Target = zeroAddr; AssignDomainName(&x->qTXT.qname, &srv); x->qTXT.qtype = kDNSType_TXT; x->qTXT.qclass = kDNSClass_IN; x->qTXT.LongLived = mDNSfalse; x->qTXT.ExpectUnique = mDNStrue; x->qTXT.ForceMCast = mDNSfalse; x->qTXT.QuestionCallback = FoundServiceInfo; x->qTXT.QuestionContext = x; err = mDNS_StartQuery(&mDNSStorage, &x->qSRV); if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery qSRV"; goto fail; } err = mDNS_StartQuery(&mDNSStorage, &x->qTXT); if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery qTXT"; goto fail; } // Succeeded: Wrap up and return *sdRef = (DNSServiceRef)x; return(mStatus_NoError); badparam: err = mStatus_BadParamErr; fail: LogMsg("DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%ld)", name, regtype, domain, errormsg, err); return(err); }
DNSServiceErrorType DNSServiceRegister ( DNSServiceRef *sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, const char *name, /* may be NULL */ const char *regtype, const char *domain, /* may be NULL */ const char *host, /* may be NULL */ uint16_t notAnIntPort, uint16_t txtLen, const void *txtRecord, /* may be NULL */ DNSServiceRegisterReply callback, /* may be NULL */ void *context /* may be NULL */ ) { mStatus err = mStatus_NoError; const char *errormsg = "Unknown"; domainlabel n; domainname t, d, h, srv; mDNSIPPort port; unsigned int size = sizeof(RDataBody); AuthRecord *SubTypes = mDNSNULL; mDNSu32 NumSubTypes = 0; mDNS_DirectOP_Register *x; (void)flags; // Unused (void)interfaceIndex; // Unused // Check parameters if (!name[0]) n = mDNSStorage.nicelabel; else if (!MakeDomainLabelFromLiteralString(&n, name)) { errormsg = "Bad Instance Name"; goto badparam; } if (!regtype || !*regtype || !MakeDomainNameFromDNSNameString(&t, regtype)) { errormsg = "Bad Service Type"; goto badparam; } if (!MakeDomainNameFromDNSNameString(&d, (domain && *domain) ? domain : "local.")) { errormsg = "Bad Domain"; goto badparam; } if (!MakeDomainNameFromDNSNameString(&h, (host && *host ) ? host : "")) { errormsg = "Bad Target Host"; goto badparam; } if (!ConstructServiceName(&srv, &n, &t, &d)) { errormsg = "Bad Name"; goto badparam; } port.NotAnInteger = notAnIntPort; // Allocate memory, and handle failure if (size < txtLen) size = txtLen; x = (mDNS_DirectOP_Register *)mDNSPlatformMemAllocate(sizeof(*x) - sizeof(RDataBody) + size); if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; } // Set up object x->disposefn = DNSServiceRegisterDispose; x->callback = callback; x->context = context; x->autoname = (!name[0]); x->autorename = mDNSfalse; x->name = n; // Do the operation err = mDNS_RegisterService(&mDNSStorage, &x->s, &x->name, &t, &d, // Name, type, domain &h, port, // Host and port txtRecord, txtLen, // TXT data, length SubTypes, NumSubTypes, // Subtypes mDNSInterface_Any, // Interface ID RegCallback, x); // Callback and context if (err) { mDNSPlatformMemFree(x); errormsg = "mDNS_RegisterService"; goto fail; } // Succeeded: Wrap up and return *sdRef = (DNSServiceRef)x; return(mStatus_NoError); badparam: err = mStatus_BadParamErr; fail: LogMsg("DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", regtype, domain, errormsg, err); return(err); }
DNSServiceErrorType DNSSD_API DNSServiceBrowse ( DNSServiceRef *sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, const char *regtype, const char *domain, /* may be NULL */ DNSServiceBrowseReply callback, void *context /* may be NULL */ ) { mStatus err = mStatus_NoError; const char *errormsg = "Unknown"; domainname t, d; mDNS_DirectOP_Browse *x; mDNSs32 NumSubTypes; char regTypeBuf[MAX_ESCAPED_DOMAIN_NAME]; (void)flags; // Unused (void)interfaceIndex; // Unused if (!regtype || !*regtype) { goto badregtype; } mDNSPlatformStrCopy(regTypeBuf, regtype); // Check parameters t.c[0] = 0; NumSubTypes = ChopSubTypes(regTypeBuf); // Note: Modifies regtype string to remove trailing subtypes if (NumSubTypes < 0 || NumSubTypes > 1) { goto badregtype; } if (NumSubTypes == 1 && !AppendDNSNameString(&t, regTypeBuf + mDNSPlatformStrLen(regTypeBuf) + 1)) { goto badregtype; } if (!regTypeBuf[0] || !AppendDNSNameString(&t, regTypeBuf)) { goto badregtype; } if (!MakeDomainNameFromDNSNameString(&d, (domain && *domain) ? domain : "local.")) { errormsg = "Illegal domain"; goto badparam; } // Allocate memory, and handle failure x = (mDNS_DirectOP_Browse *)mDNSPlatformMemAllocate(sizeof(*x)); if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; } // Set up object x->disposefn = DNSServiceBrowseDispose; x->callback = callback; x->context = context; x->q.QuestionContext = x; // Do the operation err = mDNS_StartBrowse(&mDNSStorage, &x->q, &t, &d, mDNSInterface_Any, (flags & kDNSServiceFlagsForceMulticast) != 0, FoundInstance, x); if (err) { mDNSPlatformMemFree(x); errormsg = "mDNS_StartBrowse"; goto fail; } // Succeeded: Wrap up and return *sdRef = (DNSServiceRef)x; return(mStatus_NoError); badregtype: errormsg = "Illegal regtype"; badparam: err = mStatus_BadParamErr; fail: LogMsg("DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", regtype, domain, errormsg, err); return(err); }