Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1433 lines
37 KiB

/*++
Copyright (c) 1999-2000 Microsoft Corporation
Module Name:
mcast.c
Abstract:
DNS Resolver Service
Multicast routines.
Author:
Glenn Curtis (glennc) December 1999
Revision History:
James Gilroy (jamesg) February 2000 cleanup
--*/
#include "local.h"
//
// Globals
//
HANDLE g_hMulticastThread = NULL;
BOOL g_MulticastStop = FALSE;
SOCKET g_MulticastUnicastSocket = 0;
PSOCKET_CONTEXT g_MulticastIoContextList = NULL;
HANDLE g_MulticastCompletionPort = NULL;
//
// Should be read from netinfo blob
//
PSTR g_HostName = NULL;
//
// Multicast config globals
//
// DCR: regkeys for multicast values
//
#define DNS_DEFAULT_ALLOW_MULTICAST_RESOLVER_OPERATION 0 // Off
#define DNS_DEFAULT_ALLOW_MULTICAST_RESOLVER_AS_PROXY 0 // Off
#define DNS_DEFAULT_ALLOW_MULTICAST_DNS_SRV_RECORD 0 // Off
#define DNS_DEFAULT_MULTICAST_RESOLVER_RECORD_TTL 10*60 // 10 minutes
DWORD g_MulticastRecordTTL = DNS_DEFAULT_MULTICAST_RESOLVER_RECORD_TTL;
BOOL g_AllowMulticastAsProxy = FALSE;
BOOL g_AllowMulticastDnsSrvRecord = FALSE;
//
// Private prototypes
//
BOOL
IsLocalMachineQuery(
IN LPSTR pName,
IN WORD Type,
OUT PDNS_RECORD * ppRecord
);
VOID
FixupNameOwnerPointers(
IN OUT PDNS_RECORD pRecord
);
PDNS_RECORD
BuildPTR(
IN LPSTR pName,
IN LPSTR pHostname,
IN LPSTR pDomain,
IN LPSTR pPrimaryDomain
);
PDNS_RECORD
BuildARecord(
IN LPSTR Name,
IN IP_ADDRESS Address );
PDNS_RECORD
BuildDNSServerRecord(
IN IP_ADDRESS Address );
PDNS_RECORD
BuildLocalAddressRecords(
IN LPSTR Name );
BOOL
IsLocalAddress(
IN IP_ADDRESS Ip );
PSOCKET_CONTEXT
AllocateIoContext(
IN IP_ADDRESS ipAddr );
VOID
FreeIoContextList(
IN PSOCKET_CONTEXT pContext,
IN BOOL fIssueSocketShutdown );
VOID
DropReceive(
IN PSOCKET_CONTEXT pContext );
VOID
MulticastThread(
VOID
)
/*++
Routine Description:
Multicast response thread.
Runs while cache is running, responding to multicast queries.
Arguments:
None.
Return Value:
None.
--*/
{
DNS_STATUS status = NO_ERROR;
PDNS_NETINFO ptempNetInfo = NULL;
PSOCKET_CONTEXT pcontext;
DWORD iter;
DWORD bytesRecvd;
LPOVERLAPPED poverlapped;
//
// init globals for safe cleanup on failure
//
g_MulticastStop = FALSE;
g_MulticastCompletionPort = NULL;
g_MulticastUnicastSocket = 0;
g_MulticastIoContextList = NULL;
//
// We are going to create a completion port with
// socket contexts for each of the primary IP addresses of each
// adapter on the system.
//
//
// Get a copy of the network adapter information
//
ptempNetInfo = GrabNetworkInfo();
if ( ! ptempNetInfo )
{
goto Cleanup;
}
//
// create multicast completion port
//
g_MulticastCompletionPort = CreateIoCompletionPort(
INVALID_HANDLE_VALUE,
NULL,
0,
0 );
if ( ! g_MulticastCompletionPort )
{
DNSLOG_F1( "Error: Failed to create io completion port." );
goto Cleanup;
}
// We create two sockets here, one for multicast receives and
// one for the unicast response. This shouldn't be necessary;
// there should be nothing preventing us from responding via
// unicast even with a socket that's joined to a multicast address.
// In most cases, it does in fact work; but it seems that
// packets sent to the local address do not arrive if they are
// sent from a socket that is configured for multicast receive.
// Apparently, such a socket sends all packets onto the wire
// without checking the destination address. I imagine this is
// a bug in the TCP stack, perhaps, but for now, creating two
// separate sockets is a simple workaround. - tbrown 10/19/99
g_MulticastUnicastSocket = Dns_CreateSocket(
SOCK_DGRAM,
INADDR_ANY,
DNS_PORT_NET_ORDER );
if ( g_MulticastUnicastSocket == 0 ||
g_MulticastUnicastSocket == INVALID_SOCKET )
{
DNSLOG_F1( "Error: Failed to create unicast socket." );
goto Cleanup;
}
//
// build context list
// - create socket\context for each adapters first IP
// - associate socket with completion port
//
g_MulticastIoContextList = NULL;
pcontext = NULL;
for ( iter = 0; iter < ptempNetInfo->cAdapterCount; iter++ )
{
PIP_ARRAY pipArray;
pipArray = ptempNetInfo->AdapterArray[iter]->pAdapterIPAddresses;
if ( pipArray &&
pipArray->AddrCount )
{
PSOCKET_CONTEXT pnewContext;
pnewContext = AllocateIoContext( pipArray->AddrArray[0] );
if ( pnewContext )
{
HANDLE hport = NULL;
if ( pcontext )
{
pcontext->pNext = pnewContext;
pcontext = pnewContext;
}
else
{
g_MulticastIoContextList = pnewContext;
pcontext = pnewContext;
}
hport = CreateIoCompletionPort(
(HANDLE) pnewContext->Socket,
g_MulticastCompletionPort,
(UINT_PTR) pnewContext,
0 );
if ( !hport )
{
DNSLOG_F1( "Error: Failed to add socket to io completion port." );
goto Cleanup;
}
}
}
}
//
// if no sockets -- done
//
if ( ! g_MulticastIoContextList )
{
goto Cleanup;
}
//
// drop listen on sockets
//
pcontext = g_MulticastIoContextList;
while ( pcontext )
{
DropReceive( pcontext );
pcontext = pcontext->pNext;
}
//
// main listen loop
//
do
{
if ( g_LogTraceInfo )
{
DNSLOG_F1( " Multicast Resolver: Going to listen for message." );
DNSLOG_F1( "" );
}
if ( GetQueuedCompletionStatus(
g_MulticastCompletionPort,
& bytesRecvd,
& (ULONG_PTR) pcontext,
& poverlapped,
INFINITE ) )
{
//
// We received notice that something happened on a given
// completion port, get the socket from the context and
// do a receive to see what we got.
//
if ( pcontext && bytesRecvd )
{
WORD Xid;
IP4_ADDRESS Ip;
BYTE Opcode;
WORD QuestionCount;
WORD AnswerCount;
WORD NameServerCount;
WORD AdditionalCount;
Ip = MSG_REMOTE_IP4( pcontext->pMsg );
Xid = pcontext->pMsg->MessageHead.Xid;
Opcode = pcontext->pMsg->MessageHead.Opcode;
QuestionCount = pcontext->pMsg->MessageHead.QuestionCount;
AnswerCount = pcontext->pMsg->MessageHead.AnswerCount;
NameServerCount = pcontext->pMsg->MessageHead.NameServerCount;
AdditionalCount = pcontext->pMsg->MessageHead.AdditionalCount;
if ( g_LogTraceInfo )
{
DNSLOG_F1( " Multicast Resolver: Received DNS message." );
DNSLOG_F1( " Message contained . . ." );
DNSLOG_F2( " Xid : 0x%x", Xid );
DNSLOG_F2( " IP Address : %s", IP_STRING( Ip ) );
DNSLOG_F2( " Opcode : 0x%x", Opcode );
DNSLOG_F1( "" );
}
if ( g_MulticastStop )
{
DNSLOG_F1( " Multicast Resolver detected stop signal." );
DNSLOG_F1( " Will not process last received message." );
DNSLOG_F1( "" );
continue;
}
if ( IsLocalAddress( Ip ) )
{
if ( g_LogTraceInfo )
{
DNSLOG_F1( " Multicast Resolver: Skip query from local machine." );
DNSLOG_F1( "" );
}
continue;
}
if ( Opcode == DNS_OPCODE_QUERY &&
QuestionCount == 1 &&
AnswerCount == 0 &&
NameServerCount == 0 &&
AdditionalCount == 0 )
{
char QuestionName[ DNS_MAX_NAME_BUFFER_LENGTH ];
WORD QuestionNameLength = DNS_MAX_NAME_BUFFER_LENGTH;
PCHAR pch;
WORD QuestionType = 0;
WORD QuestionClass = 0;
PDNS_RECORD pRecord = NULL;
pch = (PCHAR) &pcontext->pMsg->MessageBody;
//
// Get DNS Question name from packet
//
pch = Dns_ReadPacketName(
QuestionName,
&QuestionNameLength,
0,
0,
pch,
(PCHAR) &pcontext->pMsg->MessageHead,
pcontext->pMsg->pBufferEnd );
if ( !pch )
{
DNSLOG_F1( " Multicast Resolver: Dns_ReadPacketName failed" );
DNSLOG_F2( " with error: 0x%x" , DNS_RCODE_FORMAT_ERROR );
DNSLOG_F1( "" );
continue;
}
//
// Get DNS Question type from packet
//
QuestionType = ntohs( *(UNALIGNED WORD *) pch );
pch += sizeof( WORD );
//
// Get DNS Question class from packet
//
QuestionClass = ntohs( *(UNALIGNED WORD *) pch );
pch += sizeof( WORD );
DNSLOG_F1( " Multicast Resolver - Valid query for . . ." );
DNSLOG_F2( " Name : %s", QuestionName );
DNSLOG_F2( " Type : %d", QuestionType );
DNSLOG_F2( " Class : %d", QuestionClass );
DNSLOG_F1( "" );
//
// Set pCurrent so that question section is included
// in response packet.
//
pcontext->pMsg->pCurrent = pch;
pcontext->pMsg->MessageHead.IsResponse = TRUE;
pcontext->pMsg->MessageHead.ResponseCode = 0;
pcontext->pMsg->MessageHead.RecursionAvailable = 0;
pcontext->pMsg->MessageHead.Authoritative = 0;
if ( IsLocalMachineQuery( QuestionName,
QuestionType,
&pRecord ) )
{
DNSLOG_F1( " Multicast Resolver: Got valid local machine query" );
pcontext->pMsg->MessageHead.Authoritative = TRUE;
status = Dns_AddRecordsToMessage( pcontext->pMsg,
pRecord,
FALSE );
Dns_RecordListFree( pRecord );
// Switch to the unicast socket
pcontext->pMsg->Socket = g_MulticastUnicastSocket;
Dns_Send( pcontext->pMsg );
}
else if ( g_AllowMulticastAsProxy )
{
LPSTR lpTempName = NULL;
WORD wNameLen;
DNSLOG_F1( " Multicast Resolver: Going to proxy query for client" );
wNameLen = (WORD) strlen( QuestionName );
lpTempName = MCAST_HEAP_ALLOC_ZERO(
(wNameLen + 1) * sizeof(WCHAR) );
if ( lpTempName == NULL )
{
DNSLOG_F1( " Multicast Resolver: HeapAlloc failed" );
continue;
}
Dns_NameCopy( lpTempName,
NULL,
QuestionName,
wNameLen,
DnsCharSetUtf8,
DnsCharSetUnicode );
status = R_ResolverQuery(
NULL,
(LPWSTR) lpTempName,
QuestionType,
0,
&pRecord );
MCAST_HEAP_FREE( lpTempName );
if ( status == DNS_ERROR_RCODE_NAME_ERROR )
{
DNSLOG_F1( " Multicast Resolver: returning DNS_RCODE_NAME_ERROR" );
pcontext->pMsg->MessageHead.ResponseCode = DNS_RCODE_NAME_ERROR;
// Switch to the unicast socket
pcontext->pMsg->Socket = g_MulticastUnicastSocket;
Dns_Send( pcontext->pMsg );
}
else if ( status == DNS_ERROR_NAME_DOES_NOT_EXIST )
{
DNSLOG_F1( " Multicast Resolver: returning DNS_RCODE_NXDOMAIN" );
pcontext->pMsg->MessageHead.ResponseCode = DNS_RCODE_NXDOMAIN;
// Switch to the unicast socket
pcontext->pMsg->Socket = g_MulticastUnicastSocket;
Dns_Send( pcontext->pMsg );
}
else if ( status == DNS_ERROR_RCODE_NXRRSET )
{
DNSLOG_F1( " Multicast Resolver: returning DNS_RCODE_NXRRSET" );
pcontext->pMsg->MessageHead.ResponseCode = DNS_RCODE_NXRRSET;
// Switch to the unicast socket
pcontext->pMsg->Socket = g_MulticastUnicastSocket;
Dns_Send( pcontext->pMsg );
}
else if ( status == NO_ERROR )
{
if ( pRecord )
{
FixupNameOwnerPointers( pRecord );
status = Dns_AddRecordsToMessage(
pcontext->pMsg,
pRecord,
FALSE );
Dns_RecordListFree( pRecord );
if ( status != ERROR_SUCCESS )
{
DNSLOG_F1( " Multicast Resolver: Dns_AddRecordsToMessage failed" );
DNSLOG_F2( " with error: 0x%x" , status );
continue;
}
// Switch to the unicast socket
pcontext->pMsg->Socket = g_MulticastUnicastSocket;
Dns_Send( pcontext->pMsg );
}
}
else if ( pRecord )
{
DNSLOG_F1( " Multicast Resolver: Nothing to return" );
Dns_RecordListFree( pRecord );
}
}
else
{
DNSLOG_F1( " Multicast Resolver: Nothing can be done for this client query" );
}
DNSLOG_F1( "" );
}
//
// Now send down another receive request to wait on.
//
DropReceive( pcontext );
}
else
{
DNSLOG_F1( " Multicast Resolver: GQCP returned no context!" );
DNSLOG_F1( " Could be terminating resolver service?" );
DNSLOG_F1( "" );
}
}
else
{
//
// GQCP failed, see what the failure was and handle accordingly
//
status = GetLastError();
if ( !pcontext )
{
continue;
}
//
// Now send down another receive request to wait on.
//
DropReceive( pcontext );
}
}
while( !g_MulticastStop );
Cleanup :
//
// cleanup multicast stuff
// - sockets, contexts, i/o completion port
//
NetInfo_Free( ptempNetInfo );
if ( g_MulticastUnicastSocket )
{
Dns_CloseSocket( g_MulticastUnicastSocket );
g_MulticastUnicastSocket = 0;
}
FreeIoContextList( g_MulticastIoContextList, FALSE );
g_MulticastIoContextList = NULL;
if ( g_MulticastCompletionPort )
{
CloseHandle( g_MulticastCompletionPort );
g_MulticastCompletionPort = 0;
}
DNSLOG_F1( "MulticastThread exiting." );
}
VOID
MulticastThreadSignalStop(
VOID
)
/*++
Routine Description:
Stop the multicast thread.
Note, not synchronous, simply signals shutdown.
Arguments:
None.
Return Value:
None
--*/
{
g_MulticastStop = TRUE;
PostQueuedCompletionStatus(
g_MulticastCompletionPort,
0,
0,
NULL );
}
BOOL
IsLocalMachineQuery(
IN LPSTR pName,
IN WORD Type,
OUT PDNS_RECORD * ppRecord
)
{
PDNS_NETINFO ptempNetworkInfo = NULL;
LPSTR pszPrimaryDomain = NULL;
DWORD iter;
DWORD iter2;
PDNS_RECORD presultRecords = NULL;
//
// if no hostname -- bail
//
// note: MUST INSURE hostname is never NULL afterwards or
// (preferred) take local copy under lock
//
if ( !g_HostName )
{
return FALSE;
}
//
// get local copy of network info
//
// DCR_FIX: cleanup net-info creation
//
ptempNetworkInfo = GrabNetworkInfo();
if ( ! ptempNetworkInfo )
{
return FALSE;
}
// get primary domain name -- if any
if ( ptempNetworkInfo->pSearchList )
{
pszPrimaryDomain = ptempNetworkInfo->pSearchList->pszDomainOrZoneName;
}
//
// A record query
//
if ( Type == DNS_TYPE_A )
{
char testName[DNS_MAX_NAME_LENGTH * 2];
//
// host name with PDN if available
//
strcpy( testName, g_HostName );
if ( pszPrimaryDomain )
{
strcat( testName, "." );
strcat( testName, pszPrimaryDomain );
}
// name matches hostname -- return name (with PDN if available)
if ( Dns_NameCompare_UTF8( pName, g_HostName ) )
{
presultRecords = BuildLocalAddressRecords( testName );
goto Done;
}
// name matches full PDN -- return full PDN
if ( pszPrimaryDomain &&
Dns_NameCompare_UTF8( pName, testName ) )
{
presultRecords = BuildLocalAddressRecords( testName );
goto Done;
}
//
// is name ".local" query
//
strcpy( testName, g_HostName );
strcat( testName, "." );
strcat( testName, MULTICAST_DNS_LOCAL_DOMAIN );
if ( Dns_NameCompare_UTF8( pName, testName ) )
{
presultRecords = BuildLocalAddressRecords( testName );
goto Done;
}
//
// see if name matches any adapter name
//
for ( iter = 0; iter < ptempNetworkInfo->cAdapterCount; iter++ )
{
PIP_ARRAY pipArray = ptempNetworkInfo->AdapterArray[iter]->
pAdapterIPAddresses;
LPSTR pszDomain = ptempNetworkInfo->AdapterArray[iter]->
pszAdapterDomain;
if ( pszDomain )
{
strcpy( testName, g_HostName );
strcat( testName, "." );
strcat( testName, pszDomain );
if ( pipArray &&
Dns_NameCompare_UTF8( pName, testName ) )
{
PDNS_RECORD pPrev = NULL;
for ( iter2 = 0; iter2 < pipArray->AddrCount; iter2++ )
{
PDNS_RECORD pNew = BuildARecord(
testName,
pipArray->AddrArray[iter2] );
if ( pNew )
{
if ( pPrev )
pPrev->pNext = pNew;
else
presultRecords = pNew;
pPrev = pNew;
}
}
}
}
}
goto Done;
}
//
// PTR query
//
else if ( Type == DNS_TYPE_PTR )
{
//
// check for loopback
// Dnslib uses this address to 'ping' adapters, must always respond
//
if ( Dns_NameCompare_UTF8( pName, "1.0.0.127.in-addr.arpa." ) )
{
presultRecords = BuildPTR(
pName,
g_HostName,
NULL,
pszPrimaryDomain );
goto Done;
}
//
// check all IPs on box (one adapter at a time)
//
for ( iter = 0; iter < ptempNetworkInfo->cAdapterCount; iter++ )
{
PIP_ARRAY pipArray = ptempNetworkInfo ->
AdapterArray[iter] ->
pAdapterIPAddresses;
LPSTR pszDomain = ptempNetworkInfo ->
AdapterArray[iter] ->
pszAdapterDomain;
if ( pipArray )
{
// check if query matches IP for this adapter
//
// ENHANCE: this is backwards; ought to covert query to IP
// and then check IPs, rather than turning every IP into
// reverse name; then could even use standard routines
// to build PTR
for ( iter2 = 0; iter2 < pipArray->AddrCount; iter2++ )
{
CHAR reverseName[DNS_MAX_REVERSE_NAME_BUFFER_LENGTH];
IP4_ADDRESS ip = pipArray->AddrArray[iter2];
Dns_Ip4AddressToReverseName_A(
reverseName,
ip );
if ( Dns_NameCompare_UTF8( pName, reverseName ) )
{
presultRecords = BuildPTR(
pName,
g_HostName,
pszDomain,
pszPrimaryDomain );
goto Done;
}
}
}
}
}
//
// SRV query
//
else if ( Type == DNS_TYPE_SRV )
{
//
// check if ".local" query
//
if ( Dns_NameCompare_UTF8( pName, MULTICAST_DNS_SRV_RECORD_NAME ) )
{
if ( g_AllowMulticastDnsSrvRecord &&
ptempNetworkInfo->cAdapterCount &&
ptempNetworkInfo->AdapterArray[0]->cServerCount )
{
presultRecords = BuildDNSServerRecord(
ptempNetworkInfo->
AdapterArray[0]->
ServerArray[0].IpAddress );
goto Done;
}
}
}
Done:
// cleanup
// return records
// if found records TRUE; otherwise FALSE
NetInfo_Free( ptempNetworkInfo );
*ppRecord = presultRecords;
return( presultRecords != NULL );
}
VOID
FixupNameOwnerPointers(
IN OUT PDNS_RECORD pRpcRecord
)
{
PDNS_RECORD pTempRecord = pRpcRecord;
LPWSTR lpNameOwner = pRpcRecord->pName;
DNSDBG( TRACE, ( "FixupNameOwnerPointers()\n" ));
while ( pTempRecord )
{
if ( pTempRecord->pName == NULL )
pTempRecord->pName = lpNameOwner;
else
lpNameOwner = pTempRecord->pName;
pTempRecord = pTempRecord->pNext;
}
}
PDNS_RECORD
BuildPTR(
IN LPSTR pName,
IN LPSTR pHostname,
IN LPSTR pDomain,
IN LPSTR pPrimaryDomain
)
{
PDNS_RECORD prr1 = NULL;
PDNS_RECORD prr2 = NULL;
LPSTR pdata1 = NULL;
LPSTR pdata2 = NULL;
LPSTR pnameOwner = NULL;
DWORD length;
//
// DCR_FIX: duplicates a lot of Dns_CreatePtrRecord
//
// DCR_FIX: build generic name-appending counter and
// builder
//
// DCR_FIX0: records are not unicode is this ok?
//
prr1 = Dns_AllocateRecord( sizeof( DNS_PTR_DATA ) );
if ( !prr1 )
{
return( NULL );
}
//
// create owner name
// create data name
//
pnameOwner = RECORD_HEAP_ALLOC( strlen(pName) + 1 );
if ( !pnameOwner )
{
goto Failed;
}
strcpy( pnameOwner, pName );
//
// create PTR data
//
length = strlen( pHostname ) + 2;
if ( pDomain )
{
length += strlen( pDomain ) + 2;
}
strcpy( pdata1, pHostname );
strcat( pdata1, "." );
if ( pDomain )
{
strcat( pdata1, pDomain );
}
//
// create, fill-in record
//
pdata1 = RECORD_HEAP_ALLOC( length );
if ( !pdata1 )
{
goto Failed;
}
prr1->pNext = NULL;
prr1->pName = (PDNS_NAME) pnameOwner;
prr1->wType = DNS_TYPE_PTR;
prr1->Flags.S.Section = DNSREC_ANSWER;
SET_FREE_DATA( prr1 );
SET_FREE_OWNER( prr1 );
prr1->dwTtl = g_MulticastRecordTTL;
prr1->Data.Ptr.pNameHost = (PDNS_NAME) pdata1;
//
// build record for primary domain name
// - if exists and different from domain name
//
if ( pPrimaryDomain &&
! Dns_NameCompare_UTF8( pDomain, pPrimaryDomain ) )
{
pdata2 = RECORD_HEAP_ALLOC(
strlen( pHostname ) + strlen( pPrimaryDomain ) + 2 );
if ( !pdata2 )
{
goto Failed;
}
strcpy( pdata2, pHostname );
strcat( pdata2, "." );
strcat( pdata2, pPrimaryDomain );
prr2 = Dns_AllocateRecord( sizeof( DNS_PTR_DATA ) );
if ( !prr2 )
{
goto Failed;
}
prr2->pNext = NULL;
prr2->pName = (PDNS_NAME) pnameOwner;
prr2->wType = DNS_TYPE_PTR;
prr2->Flags.S.Section = DNSREC_ANSWER;
SET_FREE_DATA( prr2 );
prr2->dwTtl = g_MulticastRecordTTL;
prr2->Data.Ptr.pNameHost = (PDNS_NAME) pdata2;
}
//
// set next field
// - appends record for primary name (if any)
// - or sets pNext=NULL
//
prr1->pNext = prr2;
return prr1;
Failed:
RECORD_HEAP_FREE( prr1 );
RECORD_HEAP_FREE( pnameOwner );
RECORD_HEAP_FREE( pdata1 );
RECORD_HEAP_FREE( prr2 );
RECORD_HEAP_FREE( pdata2 );
return NULL;
}
PDNS_RECORD
BuildARecord(
IN LPSTR pName,
IN IP_ADDRESS IpAddress
)
{
PDNS_RECORD prr;
LPSTR pnameOwner;
prr = Dns_AllocateRecord( sizeof(DNS_A_DATA) );
if ( !prr )
{
return NULL;
}
pnameOwner = RECORD_HEAP_ALLOC( strlen(pName) + 1 );
if ( ! pnameOwner )
{
goto Failed;
}
strcpy( pnameOwner, pName );
prr->pNext = NULL;
prr->pName = (PDNS_NAME) pnameOwner;
prr->wType = DNS_TYPE_A;
prr->dwTtl = g_MulticastRecordTTL;
prr->Flags.S.Section = DNSREC_ANSWER;
SET_FREE_OWNER( prr );
SET_FREE_DATA( prr );
prr->Data.A.IpAddress = IpAddress;
return prr;
Failed:
RECORD_HEAP_FREE( prr );
return NULL;
}
PDNS_RECORD
BuildDNSServerRecord(
IN IP_ADDRESS IpAddress
)
{
PDNS_RECORD prr = NULL;
PDNS_RECORD prrAdditional = NULL;
LPSTR pnameOwner = NULL;
LPSTR pnameTarget = NULL;
//
// DCR_FIX: where to start? geez
//
// DCR_FIX: character set issue -- what's the paradigm here?
//
//
// build additional record
//
prrAdditional = BuildARecord( MULTICAST_DNS_A_RECORD_NAME, IpAddress );
if ( ! prrAdditional )
{
goto Failed;
}
prrAdditional->Flags.S.Section = DNSREC_ADDITIONAL;
//
// build SRV record
//
prr = Dns_AllocateRecord( sizeof( DNS_SRV_DATA ) );
if ( !prr )
{
return( NULL );
}
pnameOwner = RECORD_HEAP_ALLOC( strlen(MULTICAST_DNS_SRV_RECORD_NAME) + 1 );
if ( !pnameOwner )
{
goto Failed;
}
strcpy( pnameOwner, MULTICAST_DNS_SRV_RECORD_NAME );
prr->pNext = prrAdditional;
prr->pName = (PDNS_NAME) pnameOwner;
prr->Flags.S.Section = DNSREC_ANSWER;
SET_FREE_OWNER( prr );
prr->wType = DNS_TYPE_SRV;
prr->dwTtl = g_MulticastRecordTTL;
prr->Data.SRV.pNameTarget = RECORD_HEAP_ALLOC(
strlen( MULTICAST_DNS_A_RECORD_NAME ) + 1 );
if ( ! pnameTarget )
{
goto Failed;
}
strcpy(
pnameTarget,
MULTICAST_DNS_A_RECORD_NAME );
prr->Data.SRV.wPriority = 0;
prr->Data.SRV.wWeight = 0;
prr->Data.SRV.wPort = DNS_PORT_HOST_ORDER;
prr->Data.SRV.pNameTarget = (PDNS_NAME) pnameTarget;
SET_FREE_DATA( prr );
return prr;
Failed:
// cleanup
// - additional rr done wholesale
// - SRV record done in pieces
Dns_RecordFree( prrAdditional );
RECORD_HEAP_FREE( pnameOwner );
RECORD_HEAP_FREE( pnameTarget );
RECORD_HEAP_FREE( prr );
return NULL;
}
PDNS_RECORD
BuildLocalAddressRecords(
IN LPSTR Name )
{
return NULL;
#if 0
PDNS_RECORD pList = NULL;
PDNS_RECORD pPrev = NULL;
DWORD iter;
EnterCriticalSection( &NetworkListCritSec );
if ( g_IpAddressList &&
g_IpAddressListCount )
{
for ( iter = 0; iter < g_IpAddressListCount; iter++ )
{
PDNS_RECORD pNew = BuildARecord( Name,
g_IpAddressList[iter].ipAddress );
if ( pNew )
{
if ( pPrev )
pPrev->pNext = pNew;
else
pList = pNew;
pPrev = pNew;
}
}
}
LeaveCriticalSection( &NetworkListCritSec );
return pList;
#endif
}
BOOL
IsLocalAddress(
IN IP_ADDRESS IpAddress
)
{
return( FALSE );
#if 0
DWORD iter;
BOOL bisLocal = FALSE;
EnterCriticalSection( &NetworkListCritSec );
if ( g_IpAddressList )
{
for ( iter = 0; iter < g_IpAddressListCount; iter++ )
{
if ( IpAddress == g_IpAddressList[iter].ipAddress )
{
bisLocal = TRUE;
break;
}
}
}
LeaveCriticalSection( &NetworkListCritSec );
return bisLocal;
#endif
}
PSOCKET_CONTEXT
AllocateIoContext(
IN IP_ADDRESS IpAddr
)
{
PSOCKET_CONTEXT pcontext;
SOCKET socket = 0;
// allocate and clear context
pcontext = MCAST_HEAP_ALLOC_ZERO( sizeof(SOCKET_CONTEXT) );
if ( !pcontext )
{
DNSLOG_F1( "Error: Failed to allocate multicast socket context." );
return NULL;
}
// create multicast socket
// - bound to this address and DNS port
socket = Dns_CreateMulticastSocket(
SOCK_DGRAM,
IpAddr,
DNS_PORT_NET_ORDER,
FALSE,
TRUE );
if ( socket == 0 || socket == INVALID_SOCKET )
{
DNSLOG_F1( "Error: Failed to create multicast socket." );
goto Failed;
}
// create message buffer for socket
pcontext->pMsg = Dns_AllocateMsgBuf( 0 );
if ( !pcontext->pMsg )
{
DNSLOG_F1( "Error: Failed to allocate message buffer." );
goto Failed;
}
pcontext->Socket = socket;
pcontext->IpAddress = IpAddr;
pcontext->pMsg->fTcp = FALSE;
return pcontext;
Failed:
if ( socket )
{
Dns_CloseSocket( socket );
}
MCAST_HEAP_FREE( pcontext );
return NULL;
}
VOID
FreeIoContextList(
IN OUT PSOCKET_CONTEXT pContext,
IN BOOL fIssueSocketShutdown
)
{
PSOCKET_CONTEXT ptempContext;
//
// cleanup context list
// - shutdown socket
// - close socket
// - free message buffer
// - free context
//
while ( pContext )
{
ptempContext = pContext;
pContext = pContext->pNext;
if ( fIssueSocketShutdown )
{
shutdown( ptempContext->Socket, SD_BOTH );
}
Dns_CloseSocket( ptempContext->Socket );
if ( ptempContext->pMsg )
{
Dns_Free( ptempContext->pMsg );
}
// QUESTION: should we tag memory free?
MCAST_HEAP_FREE( ptempContext );
}
}
VOID
DropReceive(
IN OUT PSOCKET_CONTEXT pContext
)
/*++
Routine Description:
Drop down UDP receive request.
Arguments:
pContext -- context for socket being recieved
Return Value:
None
--*/
{
DNS_STATUS status;
WSABUF WsaBuf;
DWORD bytesRecvd;
DWORD dwFlags = 0;
if ( !pContext->pMsg )
{
return;
}
WsaBuf.len = DNS_MAX_UDP_PACKET_BUFFER_LENGTH;
WsaBuf.buf = (PCHAR) (&pContext->pMsg->MessageHead);
pContext->pMsg->Socket = pContext->Socket;
//
// loop until successful WSARecvFrom() is down
//
// this loop is only active while we continue to recv
// WSAECONNRESET or WSAEMSGSIZE errors, both of which
// cause us to dump data and retry;
//
// note loop rather than recursion (to this function) is
// required to aVOID possible stack overflow from malicious
// send
//
// normal returns from WSARecvFrom() are
// SUCCESS -- packet was waiting, GQCS will fire immediately
// WSA_IO_PENDING -- no data yet, GQCS will fire when ready
//
while ( 1 )
{
status = WSARecvFrom(
pContext->Socket,
& WsaBuf,
1,
& bytesRecvd,
& dwFlags,
(PSOCKADDR) & pContext->pMsg->RemoteAddress,
& pContext->pMsg->RemoteAddressLength,
& pContext->Overlapped,
NULL );
if ( status == ERROR_SUCCESS )
{
return;
}
status = GetLastError();
if ( status == WSA_IO_PENDING )
{
return;
}
//
// when last send ICMP'd
// - set flag to indicate retry and repost send
// - if over some reasonable number of retries, assume error
// and fall through recv failure code
//
if ( status == WSAECONNRESET )
{
continue;
}
if ( status == WSAEMSGSIZE )
{
continue;
}
return;
}
}
//
// End mcast.c
//