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;
	}
mDNSlocal unsigned int AddSOAPArguments(char *buf, unsigned int maxlen, int numArgs, Property *a)
	{
	static const char f1[] = "<%s>%s</%s>";
	static const char f2[] = "<%s xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"%s\">%s</%s>";
	int i, len = 0;
	*buf = 0;
	for (i = 0; i < numArgs; i++)
		{
		if (a[i].type) len += mDNS_snprintf(buf + len, maxlen - len, f2, a[i].name, a[i].type, a[i].value, a[i].name);
		else           len += mDNS_snprintf(buf + len, maxlen - len, f1, a[i].name,            a[i].value, a[i].name);
		}
	return(len);
	}
mDNSlocal mStatus mDNS_RegisterProxyHost(mDNS *m, ProxyHost *p)
{
    char buffer[32];

    mDNS_SetupResourceRecord(&p->RR_A,   mDNSNULL, mDNSInterface_Any, kDNSType_A,   60, kDNSRecordTypeUnique,      AuthRecordAny, HostNameCallback, p);
    mDNS_SetupResourceRecord(&p->RR_PTR, mDNSNULL, mDNSInterface_Any, kDNSType_PTR, 60, kDNSRecordTypeKnownUnique, AuthRecordAny, HostNameCallback, p);

    p->RR_A.namestorage.c[0] = 0;
    AppendDomainLabel(&p->RR_A.namestorage, &p->hostlabel);
    AppendLiteralLabelString(&p->RR_A.namestorage, "local");

    // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
    mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.", p->ip.b[3], p->ip.b[2], p->ip.b[1], p->ip.b[0]);
    MakeDomainNameFromDNSNameString(&p->RR_PTR.namestorage, buffer);
    p->RR_PTR.ForceMCast = mDNStrue; // This PTR points to our dot-local name, so don't ever try to write it into a uDNS server

    p->RR_A.resrec.rdata->u.ipv4 = p->ip;
    AssignDomainName(&p->RR_PTR.resrec.rdata->u.name, p->RR_A.resrec.name);

    mDNS_Register(m, &p->RR_A);
    mDNS_Register(m, &p->RR_PTR);

    debugf("Made Proxy Host Records for %##s", p->RR_A.resrec.name->c);

    return(mStatus_NoError);
}
Пример #4
0
mDNSlocal void PrintHash(mDNSu8 *digest, int digestlen, char *buffer, int buflen)
{
    int length = 0;
    for (int j = 0; j < digestlen; j++)
    {
        length += mDNS_snprintf(buffer+length, buflen-length-1, "%x", digest[j]);
    }
}
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;
	}
Пример #6
0
mDNSlocal void LinkTrustAnchor(mDNS *const m, TrustAnchor *ta)
{
    int length = 0;
    int i;
    mDNSu8 *p;
    TrustAnchor **t = &m->TrustAnchors;
    char buffer[256];

    while (*t)
        t = &((*t)->next);
    *t = ta;

    buffer[0] = 0;
    p = ta->rds.digest;
    for (i = 0; i < ta->digestLen; i++)
    {
        length += mDNS_snprintf(buffer+length, sizeof(buffer)-1-length, "%x", p[i]);
    }
    LogInfo("LinkTrustAnchor: Zone %##s, keytag %d, alg %d, digestType %d, digestLen %d, digest %s", ta->zone.c, ta->rds.keyTag,
        ta->rds.alg, ta->rds.digestType, ta->digestLen, buffer);
}
Пример #7
0
mDNSlocal int RegisterNotification(mDNS *const m, unsigned int interval)
{
    int len = strlen("com.apple.system.notify.service.timer:+") + 21; // 21 bytes to accomodate the interval
    char buffer[len];
    unsigned int blen;
    int status;

    // Starting "interval" second from now (+ below indicates relative) register for a notification
    blen = mDNS_snprintf(buffer, sizeof(buffer), "com.apple.system.notify.service.timer:+%us", interval);
    if (blen >= sizeof(buffer))
    {
        LogMsg("RegisterNotification: Buffer too small blen %d, buffer size %d", blen, sizeof(buffer));
        return -1;
    } 
    LogInfo("RegisterNotification: buffer %s", buffer);
    if (m->notifyToken)
    {
        notify_cancel(m->notifyToken);
        m->notifyToken = 0;
    }
    status = notify_register_dispatch(buffer, &m->notifyToken,
                dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
                ^(int t) { (void) t; FetchRootTA(m); });
mDNSexport void LNT_SendDiscoveryMsg(mDNS *m)
	{
	static const char msg[] =
		"M-SEARCH * HTTP/1.1\r\n"
		"Host:239.255.255.250:1900\r\n"
		"ST:urn:schemas-upnp-org:service:WAN%sConnection:1\r\n"
		"Man:\"ssdp:discover\"\r\n"
		"MX:3\r\n\r\n";
	static const mDNSAddr multicastDest = { mDNSAddrType_IPv4, { { { 239, 255, 255, 250 } } } };
	
	mDNSu8* buf = (mDNSu8*)&m->omsg; //m->omsg is 8952 bytes, which is plenty
	unsigned int bufLen;
	
	if (!mDNSIPPortIsZero(m->UPnPRouterPort))
		{
		if (m->SSDPSocket) { debugf("LNT_SendDiscoveryMsg destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; }
		if (mDNSIPPortIsZero(m->UPnPSOAPPort) && !m->tcpDeviceInfo.sock) GetDeviceDescription(m, &m->tcpDeviceInfo);
		return;
		}

	// Always query for WANIPConnection in the first SSDP packet
	if (m->retryIntervalGetAddr <= NATMAP_INIT_RETRY) m->SSDPWANPPPConnection = mDNSfalse;

	// Create message
	bufLen = mDNS_snprintf((char*)buf, sizeof(m->omsg), msg, m->SSDPWANPPPConnection ? "PPP" : "IP");

	debugf("LNT_SendDiscoveryMsg Router %.4a Current External Address %.4a", &m->Router.ip.v4, &m->ExternalAddress);

	if (!mDNSIPv4AddressIsZero(m->Router.ip.v4))
		{
		if (!m->SSDPSocket) { m->SSDPSocket = mDNSPlatformUDPSocket(m, zeroIPPort); debugf("LNT_SendDiscoveryMsg created SSDPSocket %p", &m->SSDPSocket); }
		mDNSPlatformSendUDP(m, buf, buf + bufLen, 0, m->SSDPSocket, &m->Router,     SSDPPort);
		mDNSPlatformSendUDP(m, buf, buf + bufLen, 0, m->SSDPSocket, &multicastDest, SSDPPort);
		}
		
	m->SSDPWANPPPConnection = !m->SSDPWANPPPConnection;
	}
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);
	}
Пример #10
0
mDNSexport int main(int argc, char **argv)
{
    const char *progname = strrchr(argv[0], '/') ? strrchr(argv[0], '/') + 1 : argv[0];
    int this_arg = 1;
    mStatus status;
    struct in_addr s4;
#if HAVE_IPV6
    struct in6_addr s6;
#endif
    char buffer[256];
    DNSQuestion q;

    if (argc < 2) goto usage;

    // Since this is a special command-line tool, we want LogMsg() errors to go to stderr, not syslog
    mDNS_DebugMode = mDNStrue;

    // Initialise the mDNS core.
    status = mDNS_Init(&mDNSStorage, &PlatformStorage,
                       gRRCache, RR_CACHE_SIZE,
                       mDNS_Init_DontAdvertiseLocalAddresses,
                       mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
    if (status) { fprintf(stderr, "Daemon start: mDNS_Init failed %d\n", (int)status); return(status); }

    signal(SIGINT, HandleSIG);  // SIGINT is what you get for a Ctrl-C
    signal(SIGTERM, HandleSIG);

    while (this_arg < argc)
    {
        char *arg = argv[this_arg++];
        if (this_arg > 2) printf("\n");

        lastid = id = zeroID;
        hostaddr = target = zeroAddr;
        hostname[0] = hardware[0] = software[0] = 0;
        NumAddr = NumAAAA = NumHINFO = 0;

        if (inet_pton(AF_INET, arg, &s4) == 1)
        {
            mDNSu8 *p = (mDNSu8 *)&s4;
            // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
            mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.", p[3], p[2], p[1], p[0]);
            printf("%s\n", buffer);
            target.type = mDNSAddrType_IPv4;
            target.ip.v4.NotAnInteger = s4.s_addr;
            DoQuery(&q, buffer, kDNSType_PTR, &target, NameCallback);
            if (StopNow == 2) break;
        }
#if HAVE_IPV6
        else if (inet_pton(AF_INET6, arg, &s6) == 1)
        {
            int i;
            mDNSu8 *p = (mDNSu8 *)&s6;
            for (i = 0; i < 16; i++)
            {
                static const char hexValues[] = "0123456789ABCDEF";
                buffer[i * 4    ] = hexValues[p[15-i] & 0x0F];
                buffer[i * 4 + 1] = '.';
                buffer[i * 4 + 2] = hexValues[p[15-i] >> 4];
                buffer[i * 4 + 3] = '.';
            }
            mDNS_snprintf(&buffer[64], sizeof(buffer)-64, "ip6.arpa.");
            target.type = mDNSAddrType_IPv6;
            mDNSPlatformMemCopy(&target.ip.v6, &s6, sizeof(target.ip.v6));
            DoQuery(&q, buffer, kDNSType_PTR, &target, NameCallback);
            if (StopNow == 2) break;
        }
#endif
        else
        {
            if (strlen(arg) >= sizeof(hostname))
// Build port mapping request with new port (up to max) and send it
mDNSlocal mStatus SendPortMapRequest(mDNS *m, NATTraversalInfo *n)
	{
	char              externalPort[6];
	char              internalPort[6];
	char              localIPAddrString[30];
	char              publicPortString[40];
	Property          propArgs[8];
	mDNSu16           ReqPortNum = RequestedPortNum(n);
	NATTraversalInfo *n2 = m->NATTraversals;

	// Scan our m->NATTraversals list to make sure the external port we're requesting is locally unique.
	// UPnP gateways will report conflicts if different devices request the same external port, but if two
	// clients on the same device request the same external port the second one just stomps over the first.
	// One way this can happen is like this:
	// 1. Client A binds local port 80
	// 2. Client A requests external port 80 -> internal port 80
	// 3. UPnP NAT gateway refuses external port 80 (some other client already has it)
	// 4. Client A tries again, and successfully gets external port 80 -> internal port 81
	// 5. Client B on same machine tries to bind local port 80, and fails
	// 6. Client B tries again, and successfully binds local port 81
	// 7. Client B now requests external port 81 -> internal port 81
	// 8. UPnP NAT gateway allows this, stomping over Client A's existing mapping

	while (n2)
		{
		if (n2 == n || RequestedPortNum(n2) != ReqPortNum) n2=n2->next;
		else
			{
			if (n->tcpInfo.retries < 100)
				{
				n->tcpInfo.retries++;
				ReqPortNum = RequestedPortNum(n);	// Pick a new port number
				n2 = m->NATTraversals;				// And re-scan the list looking for conflicts
				}
			else
				{
				natTraversalHandlePortMapReply(m, n, m->UPnPInterfaceID, NATErr_Res, zeroIPPort, 0);
				return mStatus_NoError;
				}
			}
		}

	// create strings to use in the message
	mDNS_snprintf(externalPort,      sizeof(externalPort),      "%u",   ReqPortNum);
	mDNS_snprintf(internalPort,      sizeof(internalPort),      "%u",   mDNSVal16(n->IntPort));
	mDNS_snprintf(publicPortString,  sizeof(publicPortString),  "iC%u", ReqPortNum);
	mDNS_snprintf(localIPAddrString, sizeof(localIPAddrString), "%u.%u.%u.%u",
	    m->AdvertisedV4.ip.v4.b[0], m->AdvertisedV4.ip.v4.b[1], m->AdvertisedV4.ip.v4.b[2], m->AdvertisedV4.ip.v4.b[3]);

	// build the message
	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";
	propArgs[3].name  = "NewInternalPort";
	propArgs[3].type  = "ui2";
	propArgs[3].value = internalPort;
	propArgs[4].name  = "NewInternalClient";
	propArgs[4].type  = "string";
	propArgs[4].value = localIPAddrString;
	propArgs[5].name  = "NewEnabled";
	propArgs[5].type  = "boolean";
	propArgs[5].value = "1";
	propArgs[6].name  = "NewPortMappingDescription";
	propArgs[6].type  = "string";
	propArgs[6].value = publicPortString;
	propArgs[7].name  = "NewLeaseDuration";
	propArgs[7].type  = "ui4";
	propArgs[7].value = "0";

	LogInfo("SendPortMapRequest: internal %u external %u", mDNSVal16(n->IntPort), ReqPortNum);
	return SendSOAPMsgControlAction(m, &n->tcpInfo, "AddPortMapping", 8, propArgs, LNTPortMapOp);
	}