Пример #1
0
// 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;
}
Пример #2
0
mDNSexport void FreeAnonInfo(AnonymousInfo *ai)
{
    if (ai->nsec3RR)
        mDNSPlatformMemFree(ai->nsec3RR);
    if (ai->AnonData)
        mDNSPlatformMemFree(ai->AnonData);
    mDNSPlatformMemFree(ai);
}
Пример #3
0
static void DNSServiceBrowseDispose(mDNS_DirectOP *op)
	{
	mDNS_DirectOP_Browse *x = (mDNS_DirectOP_Browse*)op;
	//LogMsg("DNSServiceBrowseDispose");
	mDNS_StopBrowse(&mDNSStorage, &x->q);
	mDNSPlatformMemFree(x);
	}
Пример #4
0
static void DNSServiceResolveDispose(mDNS_DirectOP *op)
	{
	mDNS_DirectOP_Resolve *x = (mDNS_DirectOP_Resolve*)op;
	if (x->qSRV.ThisQInterval >= 0) mDNS_StopQuery(&mDNSStorage, &x->qSRV);
	if (x->qTXT.ThisQInterval >= 0) mDNS_StopQuery(&mDNSStorage, &x->qTXT);
	mDNSPlatformMemFree(x);
	}
Пример #5
0
mDNSlocal mDNSBool ParseElement(xmlDocPtr tadoc, xmlNode * a_node, TrustAnchor *ta)
{
    xmlNode *cur_node = NULL;

    for (cur_node = a_node; cur_node; cur_node = cur_node->next)
    {
        if (cur_node->type == XML_ELEMENT_NODE)
        {
            // There could be multiple KeyDigests per TrustAnchor. We keep parsing till we
            // reach the last one or we encounter an error in parsing the document.
            if (!xmlStrcmp(cur_node->name, (const xmlChar *)"KeyDigest"))
            {
                if (ta->rds.digest)
                    mDNSPlatformMemFree(ta->rds.digest);
                ta->rds.digestType = 0;
                ta->digestLen = 0;
            }
            if (!ParseElementChildren(tadoc, cur_node->children, ta))
                return mDNSfalse;
            if (!ParseElement(tadoc, cur_node->children, ta))
                return mDNSfalse;
        }
    }
    return mDNStrue;
}
Пример #6
0
mDNSlocal void FreeDNSServiceRegistration(mDNS_DirectOP_Register *x)
	{
	while (x->s.Extras)
		{
		ExtraResourceRecord *extras = x->s.Extras;
		x->s.Extras = x->s.Extras->next;
		if (extras->r.resrec.rdata != &extras->r.rdatastorage)
			mDNSPlatformMemFree(extras->r.resrec.rdata);
		mDNSPlatformMemFree(extras);
		}

	if (x->s.RR_TXT.resrec.rdata != &x->s.RR_TXT.rdatastorage)
			mDNSPlatformMemFree(x->s.RR_TXT.resrec.rdata);

	if (x->s.SubTypes) mDNSPlatformMemFree(x->s.SubTypes);
	
	mDNSPlatformMemFree(x);
	}
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;
	}
Пример #8
0
mDNSlocal void DelTrustAnchor(mDNS *const m, const domainname *zone)
{
    TrustAnchor **ta = &m->TrustAnchors;
    TrustAnchor *tmp;

    while (*ta && !SameDomainName(&(*ta)->zone, zone))
        ta = &(*ta)->next;

    // First time, we won't find the TrustAnchor in the list as it has
    // not been added.
    if (!(*ta))
        return;

    tmp = *ta;
    *ta = (*ta)->next;                  // Cut this record from the list
    tmp->next = mDNSNULL;
    if (tmp->rds.digest)
        mDNSPlatformMemFree(tmp->rds.digest);
    mDNSPlatformMemFree(tmp);
}
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 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;
	}
Пример #11
0
mDNSexport mStatus AlgDestroy(AlgContext *ctx)
{
    AlgFuncs *func = mDNSNULL;

    if (ctx->type == CRYPTO_ALG)
        func = CryptoAlgFuncs[ctx->alg];
    else if (ctx->type == DIGEST_ALG)
        func = DigestAlgFuncs[ctx->alg];
    else if (ctx->type == ENC_ALG)
        func = EncAlgFuncs[ctx->alg];

    if (!func)
    {
        LogMsg("AlgDestroy: ERROR!! func is NULL");
        mDNSPlatformMemFree(ctx);
        return mStatus_BadParamErr;
    }

    if (func->Destroy)
        func->Destroy(ctx);

    mDNSPlatformMemFree(ctx);
    return mStatus_NoError;
}
Пример #12
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);
	}
Пример #13
0
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;
}
Пример #14
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);
    }
Пример #15
0
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;
}
Пример #16
0
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;
}
Пример #17
0
static void DNSServiceQueryRecordDispose(mDNS_DirectOP *op)
	{
	mDNS_DirectOP_QueryRecord *x = (mDNS_DirectOP_QueryRecord*)op;
	if (x->q.ThisQInterval >= 0) mDNS_StopQuery(&mDNSStorage, &x->q);
	mDNSPlatformMemFree(x);
	}
// This function parses the xml body of the device description response from the router. Basically, we look to make sure this is a response
// referencing a service we care about (WANIPConnection or WANPPPConnection), look for the "controlURL" header immediately following, and copy the addressing and URL info we need
mDNSlocal void handleLNTDeviceDescriptionResponse(tcpLNTInfo *tcpInfo)
	{
	mDNS    *m    = tcpInfo->m;
	char    *ptr  = (char *)tcpInfo->Reply;
	char    *end  = (char *)tcpInfo->Reply + tcpInfo->nread;
	char    *stop = mDNSNULL;
	mDNSs16 http_result;
	
	if (!mDNSIPPortIsZero(m->UPnPSOAPPort)) return; // already have the info we need

	http_result = ParseHTTPResponseCode((mDNSu8**)&ptr, (mDNSu8*)end); // Note: modifies ptr
	if (http_result == HTTPCode_404) LNT_ClearState(m);
	if (http_result != HTTPCode_200) 
		{
		mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.DeviceDescription", "noop", "HTTP Result", "HTTP code: %d", http_result);
		return;
		}

	// Always reset our flag to use WANIPConnection.  We'll use WANPPPConnection if we find it and don't find WANIPConnection.
	m->UPnPWANPPPConnection = mDNSfalse;

	// find either service we care about
	while (ptr && ptr < end)
		{
		if (*ptr == 'W' && (strncasecmp(ptr, "WANIPConnection:1", 17) == 0)) break;
		ptr++;
		}
	if (ptr == end)
		{
		ptr = (char *)tcpInfo->Reply;
		while (ptr && ptr < end)
			{
			if (*ptr == 'W' && (strncasecmp(ptr, "WANPPPConnection:1", 18) == 0))
				{
				m->UPnPWANPPPConnection = mDNStrue;
				break;
				}
			ptr++;
			}
		}
	if (ptr == mDNSNULL || ptr == end) { LogInfo("handleLNTDeviceDescriptionResponse: didn't find WANIPConnection:1 or WANPPPConnection:1 string"); return; }

	// find "controlURL", starting from where we left off
	while (ptr && ptr < end)
		{
		if (*ptr == 'c' && (strncasecmp(ptr, "controlURL", 10) == 0)) break;			// find the first 'c'; is this controlURL? if not, keep looking
		ptr++;
		}
	if (ptr == mDNSNULL || ptr == end) { LogInfo("handleLNTDeviceDescriptionResponse: didn't find controlURL string"); return; }
	ptr += 11;							// skip over "controlURL>"
	if (ptr >= end) { LogInfo("handleLNTDeviceDescriptionResponse: past end of buffer and no body!"); return; } // check ptr again in case we skipped over the end of the buffer

	// find the end of the controlURL element
	for (stop = ptr; stop < end; stop++) { if (*stop == '<') { end = stop; break; } }

	// fill in default port
	m->UPnPSOAPPort = m->UPnPRouterPort;

	// free string pointers and set to NULL	
	if (m->UPnPSOAPAddressString != mDNSNULL)
		{
		mDNSPlatformMemFree(m->UPnPSOAPAddressString);
		m->UPnPSOAPAddressString = mDNSNULL;
		}
	if (m->UPnPSOAPURL != mDNSNULL)
		{
		mDNSPlatformMemFree(m->UPnPSOAPURL);
		m->UPnPSOAPURL = mDNSNULL; 
		}
	
	if (ParseHttpUrl(ptr, end, &m->UPnPSOAPAddressString, &m->UPnPSOAPPort, &m->UPnPSOAPURL) != mStatus_NoError) return;
	// the SOAPURL should look something like "/uuid:0013-108c-4b3f0000f3dc"

	if (m->UPnPSOAPAddressString == mDNSNULL)
		{
		ptr = (char *)tcpInfo->Reply;
		while (ptr && ptr < end)
			{
			if (*ptr == 'U' && (strncasecmp(ptr, "URLBase", 7) == 0))		break;
			ptr++;
			}

		if (ptr < end)		// found URLBase
			{
			LogInfo("handleLNTDeviceDescriptionResponse: found URLBase");			
			ptr += 8; // skip over "URLBase>"
			// find the end of the URLBase element
			for (stop = ptr; stop < end; stop++) { if (*stop == '<') { end = stop; break; } }
			if (ParseHttpUrl(ptr, end, &m->UPnPSOAPAddressString, &m->UPnPSOAPPort, mDNSNULL) != mStatus_NoError)
				{
				LogInfo("handleLNTDeviceDescriptionResponse: failed to parse URLBase");
				}
			}
		
		// if all else fails, use the router address string
		if (m->UPnPSOAPAddressString == mDNSNULL)  AllocAndCopy(&m->UPnPSOAPAddressString, m->UPnPRouterAddressString);
		}
	if (m->UPnPSOAPAddressString == mDNSNULL) LogMsg("handleLNTDeviceDescriptionResponse: UPnPSOAPAddressString is NULL");
	else LogInfo("handleLNTDeviceDescriptionResponse: SOAP address string [%s]", m->UPnPSOAPAddressString);

	if (m->UPnPSOAPURL == mDNSNULL) AllocAndCopy(&m->UPnPSOAPURL, m->UPnPRouterURL);
	if (m->UPnPSOAPURL == mDNSNULL) LogMsg("handleLNTDeviceDescriptionResponse: UPnPSOAPURL is NULL");
	else LogInfo("handleLNTDeviceDescriptionResponse: SOAP URL [%s]", m->UPnPSOAPURL);
	}
mDNSlocal void DisposeInfoFromUnmapList(mDNS *m, tcpLNTInfo *tcpInfo)
	{
	tcpLNTInfo **ptr = &m->tcpInfoUnmapList;
	while (*ptr && *ptr != tcpInfo) ptr = &(*ptr)->next;
	if (*ptr) { *ptr = (*ptr)->next; mDNSPlatformMemFree(tcpInfo); }	// If we found it, cut it from our list and free the memory
	}
Пример #20
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);
	}
mDNSlocal void tcpConnectionCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEstablished, mStatus err)
	{
	mStatus     status  = mStatus_NoError;
	tcpLNTInfo *tcpInfo = (tcpLNTInfo *)context;
	mDNSBool    closed  = mDNSfalse;
	long        n       = 0;
	long        nsent   = 0;

	if (tcpInfo == mDNSNULL) { LogInfo("tcpConnectionCallback: no tcpInfo context"); status = mStatus_Invalid; goto exit; }

	// The handlers below expect to be called with the lock held
	mDNS_Lock(tcpInfo->m);
	
	if (err) { LogInfo("tcpConnectionCallback: received error"); goto exit; }

	if (ConnectionEstablished)		// connection is established - send the message
		{
		LogInfo("tcpConnectionCallback: connection established, sending message");
		nsent = mDNSPlatformWriteTCP(sock, (char *)tcpInfo->Request, tcpInfo->requestLen);
		if (nsent != (long)tcpInfo->requestLen) { LogMsg("tcpConnectionCallback: error writing"); status = mStatus_UnknownErr; goto exit; }
		}
	else
		{
		n = mDNSPlatformReadTCP(sock, (char *)tcpInfo->Reply + tcpInfo->nread, tcpInfo->replyLen - tcpInfo->nread, &closed);
		LogInfo("tcpConnectionCallback: mDNSPlatformReadTCP read %d bytes", n);

		if      (n < 0)  { LogInfo("tcpConnectionCallback - read returned %d", n);                           status = mStatus_ConnFailed; goto exit; }
		else if (closed) { LogInfo("tcpConnectionCallback: socket closed by remote end %d", tcpInfo->nread); status = mStatus_ConnFailed; goto exit; }

		tcpInfo->nread += n;
		LogInfo("tcpConnectionCallback tcpInfo->nread %d", tcpInfo->nread);
		if (tcpInfo->nread > LNT_MAXBUFSIZE)
			{
			LogInfo("result truncated...");
			tcpInfo->nread = LNT_MAXBUFSIZE;
			}

		switch (tcpInfo->op)
			{
			case LNTDiscoveryOp:     handleLNTDeviceDescriptionResponse (tcpInfo); break;
			case LNTExternalAddrOp:  handleLNTGetExternalAddressResponse(tcpInfo); break;
			case LNTPortMapOp:       handleLNTPortMappingResponse       (tcpInfo); break;
			case LNTPortMapDeleteOp: status = mStatus_ConfigChanged;               break;
			default: LogMsg("tcpConnectionCallback: bad tcp operation! %d", tcpInfo->op); status = mStatus_Invalid; break;
			}
		}
exit:
	if (err || status)
		{
		mDNS   *m = tcpInfo->m;
		switch (tcpInfo->op)
			{
			case LNTDiscoveryOp:     if (m->UPnPSOAPAddressString == mDNSNULL)
										mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.DeviceDescription", "failure", "SOAP Address", "");
									 if (m->UPnPSOAPURL == mDNSNULL)
										mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.DeviceDescription", "failure", "SOAP path", "");
									 if (m->UPnPSOAPAddressString && m->UPnPSOAPURL)
										mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.DeviceDescription", "success", "success", "");
									 break;
			case LNTExternalAddrOp:	 mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.AddressRequest", mDNSIPv4AddressIsZero(m->ExternalAddress) ? "failure" : "success", mDNSIPv4AddressIsZero(m->ExternalAddress) ? "failure" : "success", "");
									 break;
			case LNTPortMapOp:       if (tcpInfo->parentNATInfo)	
										mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.PortMapRequest", (tcpInfo->parentNATInfo->Result) ? "failure" : "success", 
											(tcpInfo->parentNATInfo->Result) ? "failure" : "success", "Result: %d", tcpInfo->parentNATInfo->Result);
									 break;
			case LNTPortMapDeleteOp: break;
			default:				 break;
			}

		mDNSPlatformTCPCloseConnection(tcpInfo->sock);
		tcpInfo->sock = mDNSNULL;
		if (tcpInfo->Request) { mDNSPlatformMemFree(tcpInfo->Request); tcpInfo->Request = mDNSNULL; }
		if (tcpInfo->Reply  ) { mDNSPlatformMemFree(tcpInfo->Reply);   tcpInfo->Reply   = mDNSNULL; }
		}

	if (tcpInfo) mDNS_Unlock(tcpInfo->m);

	if (status == mStatus_ConfigChanged) DisposeInfoFromUnmapList(tcpInfo->m, tcpInfo);
	}
Пример #22
0
static void DNSServiceGetAddrInfoDispose(mDNS_DirectOP *op)
{
    mDNS_DirectOP_GetAddrInfo *x = (mDNS_DirectOP_GetAddrInfo*)op;
    if (x->aQuery) DNSServiceRefDeallocate(x->aQuery);
    mDNSPlatformMemFree(x);
}
Пример #23
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);
	}
// This function parses the response to our SSDP discovery message. Basically, we look to make sure this is a response
// referencing a service we care about (WANIPConnection or WANPPPConnection), then look for the "Location:" header and copy the addressing and
// URL info we need.
mDNSexport void LNT_ConfigureRouterInfo(mDNS *m, const mDNSInterfaceID InterfaceID, mDNSu8 *data, mDNSu16 len)
	{
	char *ptr = (char *)data;
	char *end = (char *)data + len;
	char *stop = ptr;
	
	if (!mDNSIPPortIsZero(m->UPnPRouterPort)) return; // already have the info we need

	// The formatting of the HTTP header is not always the same when it comes to the placement of
	// the service and location strings, so we just look for each of them from the beginning for every response
	
	// figure out if this is a message from a service we care about
	while (ptr && ptr != end)
		{
		if (*ptr == 'W' && (strncasecmp(ptr, "WANIPConnection:1", 17) == 0)) break;
		ptr++;
		}
	if (ptr == end)
		{
		ptr = (char *)data;
		while (ptr && ptr != end)
			{
			if (*ptr == 'W' && (strncasecmp(ptr, "WANPPPConnection:1", 18) == 0)) break;
			ptr++;
			}
		}
	if (ptr == mDNSNULL || ptr == end) return;	// not a message we care about

	// find "Location:", starting from the beginning
	ptr = (char *)data;
	while (ptr && ptr != end)
		{
		if ((*ptr & 0xDF) == 'L' && (strncasecmp(ptr, "Location:", 9) == 0)) break;			// find the first 'L'; is this Location? if not, keep looking
		ptr++;
		}
	if (ptr == mDNSNULL || ptr == end) 
		{
		mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "failure", "Location", "");
		return;	// not a message we care about
		}
	ptr += 9; //Skip over 'Location:'
	while (*ptr == ' ' && ptr < end) ptr++; // skip over spaces
	if (ptr >= end) return;
	
	// find the end of the line
	for (stop = ptr; stop != end; stop++) { if (*stop == '\r') { end = stop; break; } }
	
	// fill in default port
	m->UPnPRouterPort = mDNSOpaque16fromIntVal(80);

	// free string pointers and set to NULL	
	if (m->UPnPRouterAddressString != mDNSNULL)
		{
		mDNSPlatformMemFree(m->UPnPRouterAddressString);
		m->UPnPRouterAddressString = mDNSNULL;
		}
	if (m->UPnPRouterURL != mDNSNULL)
		{
		mDNSPlatformMemFree(m->UPnPRouterURL);
		m->UPnPRouterURL = mDNSNULL; 
		}
	
	// the Router URL should look something like "/dyndev/uuid:0013-108c-4b3f0000f3dc"
	if (ParseHttpUrl(ptr, end, &m->UPnPRouterAddressString, &m->UPnPRouterPort, &m->UPnPRouterURL) != mStatus_NoError)
		{
		mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "failure", "Parse URL", "");
		return;
		}

	m->UPnPInterfaceID = InterfaceID;

	if (m->UPnPRouterAddressString == mDNSNULL) 
		{
		mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "failure", "Router address", "");
		LogMsg("LNT_ConfigureRouterInfo: UPnPRouterAddressString is NULL");
		}
	else LogInfo("LNT_ConfigureRouterInfo: Router address string [%s]", m->UPnPRouterAddressString);

	if (m->UPnPRouterURL == mDNSNULL) 
		{
		mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "failure", "Router path", "");
		LogMsg("LNT_ConfigureRouterInfo: UPnPRouterURL is NULL");
		}
	else LogInfo("LNT_ConfigureRouterInfo: Router URL [%s]", m->UPnPRouterURL);

	LogInfo("LNT_ConfigureRouterInfo: Router port %d", mDNSVal16(m->UPnPRouterPort));
	LogInfo("LNT_ConfigureRouterInfo: Router interface %d", m->UPnPInterfaceID);

	// Don't need the SSDP socket anymore
	if (m->SSDPSocket) { debugf("LNT_ConfigureRouterInfo destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; }

	mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "success", "success", "");
	// now send message to get the device description
	GetDeviceDescription(m, &m->tcpDeviceInfo);
	}