// RegisterService() is a simple wrapper function which takes C string
// parameters, converts them to domainname parameters, and calls mDNS_RegisterService()
mDNSlocal void RegisterService(mDNS *m, ServiceRecordSet *recordset,
	UInt16 PortAsNumber, const char txtinfo[],
	const domainlabel *const n, const char type[], const char domain[])
	{
	domainname t;
	domainname d;
	char buffer[MAX_ESCAPED_DOMAIN_NAME];
	UInt8 txtbuffer[512];

	MakeDomainNameFromDNSNameString(&t, type);
	MakeDomainNameFromDNSNameString(&d, domain);
	
	if (txtinfo)
		{
		strncpy((char*)txtbuffer+1, txtinfo, sizeof(txtbuffer)-1);
		txtbuffer[0] = (UInt8)strlen(txtinfo);
		}
	else
		txtbuffer[0] = 0;

	mDNS_RegisterService(m, recordset,
		n, &t, &d,									// Name, type, domain
		mDNSNULL, mDNSOpaque16fromIntVal(PortAsNumber),
		txtbuffer, (mDNSu16)(1+txtbuffer[0]),		// TXT data, length
		mDNSNULL, 0,								// Subtypes (none)
		mDNSInterface_Any,							// Interface ID
		Callback, mDNSNULL);						// Callback and context

	ConvertDomainNameToCString(recordset->RR_SRV.resrec.name, buffer);
	printf("Made Service Records for %s\n", buffer);
	}
// RegisterService() is a simple wrapper function which takes C string
// parameters, converts them to domainname parameters, and calls mDNS_RegisterService()
mDNSlocal void RegisterService(mDNS *m, ServiceRecordSet *recordset,
                               const char name[], const char type[], const char domain[],
                               const domainname *host, mDNSu16 PortAsNumber, int argc, char **argv)
{
    domainlabel n;
    domainname t, d;
    unsigned char txtbuffer[1024], *bptr = txtbuffer;
    char buffer[MAX_ESCAPED_DOMAIN_NAME];

    MakeDomainLabelFromLiteralString(&n, name);
    MakeDomainNameFromDNSNameString(&t, type);
    MakeDomainNameFromDNSNameString(&d, domain);
    while (argc)
    {
        int len = strlen(argv[0]);
        if (len > 255 || bptr + 1 + len >= txtbuffer + sizeof(txtbuffer)) break;
        printf("STR: %s\n", argv[0]);
        bptr[0] = len;
        strcpy((char*)(bptr+1), argv[0]);
        bptr += 1 + len;
        argc--;
        argv++;
    }

    mDNS_RegisterService(m, recordset,
                         &n, &t, &d, // Name, type, domain
                         host, mDNSOpaque16fromIntVal(PortAsNumber),
                         txtbuffer, bptr-txtbuffer, // TXT data, length
                         mDNSNULL, 0, // Subtypes
                         mDNSInterface_Any, // Interface ID
                         ServiceCallback, mDNSNULL, 0); // Callback, context, flags

    ConvertDomainNameToCString(recordset->RR_SRV.resrec.name, buffer);
    printf("Made Service Records for %s\n", buffer);
}
// CreateProxyRegistrationForRealService() checks to see if the given port is currently
// in use, and if so, advertises the specified service as present on that port.
// This is useful for advertising existing real services (Personal Web Sharing, Personal
// File Sharing, etc.) that currently don't register with mDNS Service Discovery themselves.
static DNSServiceErrorType CreateProxyRegistrationForRealService(RegisteredService *rs,
	const char *servicetype, UInt16 PortAsNumber, const char txtinfo[])
	{
	mDNSOpaque16 OpaquePort = mDNSOpaque16fromIntVal(PortAsNumber);
	InetAddress ia;
	TBind bindReq;
	OSStatus err;
	TEndpointInfo endpointinfo;
	EndpointRef ep = OTOpenEndpoint(OTCreateConfiguration(kTCPName), 0, &endpointinfo, &err);
	if (!ep || err) { printf("OTOpenEndpoint (CreateProxyRegistrationForRealService) failed %d", err); return(err); }

	ia.fAddressType = AF_INET;
	ia.fPort        = OpaquePort.NotAnInteger;
	ia.fHost        = 0;
	bindReq.addr.maxlen = sizeof(ia);
	bindReq.addr.len    = sizeof(ia);
	bindReq.addr.buf    = (UInt8*)&ia;
	bindReq.qlen        = 0;
	err = OTBind(ep, &bindReq, NULL);

	if (err == kOTBadAddressErr)
		err = RegisterService(rs, OpaquePort, "", servicetype, "local.", txtinfo);
	else if (err)
		printf("OTBind failed %d", err);

	OTCloseProvider(ep);
	return(err);
	}
// CreateProxyRegistrationForRealService() checks to see if the given port is currently
// in use, and if so, advertises the specified service as present on that port.
// This is useful for advertising existing real services (Personal Web Sharing, Personal
// File Sharing, etc.) that currently don't register with mDNS Service Discovery themselves.
mDNSlocal OSStatus CreateProxyRegistrationForRealService(mDNS *m, UInt16 PortAsNumber, const char txtinfo[],
	const char *servicetype, ServiceRecordSet *recordset)
	{
	InetAddress ia;
	TBind bindReq;
	OSStatus err;
	TEndpointInfo endpointinfo;
	EndpointRef ep = OTOpenEndpoint(OTCreateConfiguration(kTCPName), 0, &endpointinfo, &err);
	if (!ep || err) { printf("OTOpenEndpoint (CreateProxyRegistrationForRealService) failed %d", err); return(err); }

	ia.fAddressType = AF_INET;
	ia.fPort        = mDNSOpaque16fromIntVal(PortAsNumber).NotAnInteger;
	ia.fHost        = 0;
	bindReq.addr.maxlen = sizeof(ia);
	bindReq.addr.len    = sizeof(ia);
	bindReq.addr.buf    = (UInt8*)&ia;
	bindReq.qlen        = 0;
	err = OTBind(ep, &bindReq, NULL);

	if (err == kOTBadAddressErr)
		RegisterService(m, recordset, PortAsNumber, txtinfo, &m->nicelabel, servicetype, "local.");
	else if (err)
		debugf("OTBind failed %d", err);

	OTCloseProvider(ep);
	return(noErr);
	}
Example #5
0
static mStatus RegisterOneService(const char *  richTextName, 
                                  const char *  serviceType, 
                                  const char *  serviceDomain, 
                                  const mDNSu8  text[],
                                  mDNSu16       textLen,
                                  long          portNumber)
{
    mStatus             status;
    PosixService *      thisServ;
    domainlabel         name;
    domainname          type;
    domainname          domain;
    
    status = mStatus_NoError;
    thisServ = (PosixService *) malloc(sizeof(*thisServ));
    if (thisServ == NULL) {
        status = mStatus_NoMemoryErr;
    }
    if (status == mStatus_NoError) {
        MakeDomainLabelFromLiteralString(&name,  richTextName);
        MakeDomainNameFromDNSNameString(&type, serviceType);
        MakeDomainNameFromDNSNameString(&domain, serviceDomain);
        status = mDNS_RegisterService(&mDNSStorage, &thisServ->coreServ,
                &name, &type, &domain,				// Name, type, domain
                NULL, mDNSOpaque16fromIntVal(portNumber),
                text, textLen,						// TXT data, length
                NULL, 0,							// Subtypes
                mDNSInterface_Any,					// Interface ID
                RegistrationCallback, thisServ);	// Callback and context
    }
    if (status == mStatus_NoError) {
        thisServ->serviceID = gServiceID;
        gServiceID += 1;

        thisServ->next = gServiceList;
        gServiceList = thisServ;

        if (gMDNSPlatformPosixVerboseLevel > 0) {
            fprintf(stderr, 
                    "%s: Registered service %d, name '%s', type '%s', port %ld\n", 
                    gProgramName, 
                    thisServ->serviceID, 
                    richTextName,
                    serviceType,
                    portNumber);
        }
    } else {
        if (thisServ != NULL) {
            free(thisServ);
        }
    }
    return status;
}
mDNSlocal void handleLNTPortMappingResponse(tcpLNTInfo *tcpInfo)
	{
	mDNS             *m       = tcpInfo->m;
	mDNSIPPort        extport = zeroIPPort;
	mDNSu8           *ptr     = (mDNSu8*)tcpInfo->Reply;
	mDNSu8           *end     = (mDNSu8*)tcpInfo->Reply + tcpInfo->nread;
	NATTraversalInfo *natInfo;
	mDNSs16 http_result;

	for (natInfo = m->NATTraversals; natInfo; natInfo=natInfo->next) { if (natInfo == tcpInfo->parentNATInfo) break; }

	if (!natInfo) { LogInfo("handleLNTPortMappingResponse: can't find matching tcpInfo in NATTraversals!"); return; }

	http_result = ParseHTTPResponseCode(&ptr, end); // Note: modifies ptr
	if (http_result == HTTPCode_200)
		{
		LogInfo("handleLNTPortMappingResponse: got a valid response, sending reply to natTraversalHandlePortMapReply(internal %d external %d retries %d)",
			mDNSVal16(natInfo->IntPort), RequestedPortNum(natInfo), tcpInfo->retries);
	
		// Make sure to compute extport *before* we zero tcpInfo->retries
		extport = mDNSOpaque16fromIntVal(RequestedPortNum(natInfo));
		tcpInfo->retries = 0;
		natTraversalHandlePortMapReply(m, natInfo, m->UPnPInterfaceID, mStatus_NoError, extport, NATMAP_DEFAULT_LEASE);
		}
	else if (http_result == HTTPCode_500)
		{
		while (ptr && ptr != end)
			{
			if (((*ptr == 'c' || *ptr == 'C') && end - ptr >= 8 && strncasecmp((char*)ptr, "Conflict", 8) == 0) || (*ptr == '>' && end - ptr >= 15 && strncasecmp((char*)ptr, ">718</errorCode", 15) == 0))
				{
				if (tcpInfo->retries < 100)
					{ 
					tcpInfo->retries++; SendPortMapRequest(tcpInfo->m, natInfo); 
					mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.PortMapRequest", "noop", "Conflict", "Retry %d", tcpInfo->retries);
					}
				else
					{
					LogMsg("handleLNTPortMappingResponse too many conflict retries %d %d", mDNSVal16(natInfo->IntPort), mDNSVal16(natInfo->RequestedPort));
					mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.PortMapRequest", "noop", "Conflict - too many retries", "Retries: %d", tcpInfo->retries);
					natTraversalHandlePortMapReply(m, natInfo, m->UPnPInterfaceID, NATErr_Res, zeroIPPort, 0);
					}
				return;
				}
			ptr++;
			}
		}
	else if (http_result == HTTPCode_Bad) LogMsg("handleLNTPortMappingResponse got data that was not a valid HTTP response");
	else if (http_result == HTTPCode_Other) LogMsg("handleLNTPortMappingResponse got unexpected response code");
	else if (http_result == HTTPCode_404) LNT_ClearState(m);
	if (http_result != HTTPCode_200 && http_result != HTTPCode_500)
		mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.PortMapRequest", "noop", "HTTP Result", "HTTP code: %d", http_result);
	}
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);
	}
// 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;
	}
Example #9
0
static ServiceRecordSet *
foobar_register(mDNSu16 port)
{
	ServiceRecordSet *srs;
	mStatus status;
	domainlabel name;
	domainname type;
	domainname domain;

	srs = calloc(1, sizeof(*srs));
	assert(srs != NULL);

	MakeDomainLabelFromLiteralString(&name, "foobar");
	MakeDomainNameFromDNSNameString(&type, "_foobar._tcp");
	MakeDomainNameFromDNSNameString(&domain, "local.");

	status = mDNS_RegisterService(&mDNSStorage, srs, &name, &type, &domain,
	    NULL, mDNSOpaque16fromIntVal(port), NULL, 0, NULL, 0,
	    mDNSInterface_Any, foobar_callback, srs, 0);
	assert(status == mStatus_NoError);

	return srs;
}
Example #10
0
// RegisterFakeServiceForTesting() simulates the effect of services being registered on
// dynamically-allocated port numbers. No real service exists on that port -- this is just for testing.
static DNSServiceErrorType RegisterFakeServiceForTesting(RegisteredService *rs,
	const char name[], const char type[], const char domain[], const char txtinfo[])
	{
	static UInt16 NextPort = 0xF000;
	return RegisterService(rs, mDNSOpaque16fromIntVal(NextPort++), name, type, domain, txtinfo);
	}
// 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);
	}