// 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;
}
Exemple #6
0
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);
	}
Exemple #9
0
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;
	}
Exemple #12
0
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);
	}
Exemple #20
0
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);
	}
Exemple #21
0
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);
	}
Exemple #22
0
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);
	}