1547 lines
28 KiB
C
1547 lines
28 KiB
C
/*++
|
||
|
||
Copyright (c) 2000-2000 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
ip.c
|
||
|
||
Abstract:
|
||
|
||
DNS Resolver Service.
|
||
|
||
IP list and change notification.
|
||
|
||
Author:
|
||
|
||
Jim Gilroy (jamesg) November 2000
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
|
||
#include "local.h"
|
||
#include "iphlpapi.h"
|
||
|
||
|
||
//
|
||
// IP notify thread globals
|
||
//
|
||
|
||
HANDLE g_IpNotifyThread;
|
||
DWORD g_IpNotifyThreadId;
|
||
|
||
HANDLE g_IpNotifyEvent;
|
||
HANDLE g_IpNotifyHandle;
|
||
OVERLAPPED g_IpNotifyOverlapped;
|
||
|
||
|
||
//
|
||
// IP Address list values
|
||
//
|
||
|
||
PDNS_ADDR_ARRAY g_LocalAddrArray;
|
||
|
||
PIP_ARRAY g_ClusterIpArray;
|
||
IP_ADDRESS g_OldClusterIp;
|
||
|
||
|
||
//
|
||
// Cluster record TTLs -- use max TTL
|
||
//
|
||
|
||
#define CLUSTER_RECORD_TTL (g_MaxCacheTtl)
|
||
|
||
|
||
//
|
||
// Shutdown\close locking
|
||
//
|
||
// Since GQCS and GetOverlappedResult() don't directly wait
|
||
// on StopEvent, we need to be able to close notification handle
|
||
// and port in two different threads.
|
||
//
|
||
// Note: this should probably be some general CS that is
|
||
// overloaded to do service control stuff.
|
||
// I'm not using the server control CS because it's not clear
|
||
// that the functions it does in dnsrslvr.c even need locking.
|
||
//
|
||
|
||
#define LOCK_IP_NOTIFY_HANDLE() EnterCriticalSection( &NetworkFailureCritSec )
|
||
#define UNLOCK_IP_NOTIFY_HANDLE() LeaveCriticalSection( &NetworkFailureCritSec )
|
||
|
||
CRITICAL_SECTION g_IpListCS;
|
||
|
||
#define LOCK_IP_LIST() EnterCriticalSection( &g_IpListCS );
|
||
#define UNLOCK_IP_LIST() LeaveCriticalSection( &g_IpListCS );
|
||
|
||
|
||
|
||
//
|
||
// Cluster Tag
|
||
//
|
||
|
||
#define CLUSTER_TAG 0xd734453d
|
||
|
||
|
||
|
||
VOID
|
||
CloseIpNotifyHandle(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Close IP notify handle.
|
||
|
||
Wrapping up code since this close must be MT
|
||
safe and is done in several places.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
LOCK_IP_NOTIFY_HANDLE();
|
||
if ( g_IpNotifyHandle )
|
||
{
|
||
//CloseHandle( g_IpNotifyHandle );
|
||
PostQueuedCompletionStatus(
|
||
g_IpNotifyHandle,
|
||
0, // no bytes
|
||
0, // no key
|
||
& g_IpNotifyOverlapped );
|
||
|
||
g_IpNotifyHandle = NULL;
|
||
}
|
||
UNLOCK_IP_NOTIFY_HANDLE();
|
||
}
|
||
|
||
|
||
|
||
DNS_STATUS
|
||
IpNotifyThread(
|
||
IN LPVOID pvDummy
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
IP notification thread.
|
||
|
||
Arguments:
|
||
|
||
pvDummy -- unused
|
||
|
||
Return Value:
|
||
|
||
NO_ERROR on normal service shutdown
|
||
Win32 error on abnormal termination
|
||
|
||
--*/
|
||
{
|
||
DNS_STATUS status;
|
||
DWORD bytesRecvd;
|
||
BOOL fstartedNotify;
|
||
BOOL fhaveIpChange = FALSE;
|
||
BOOL fsleep = FALSE;
|
||
HANDLE notifyHandle;
|
||
|
||
|
||
DNSDBG( INIT, ( "\nStart IpNotifyThread.\n" ));
|
||
|
||
g_IpNotifyHandle = NULL;
|
||
|
||
//
|
||
// wait in loop on notifications
|
||
//
|
||
|
||
while ( !g_StopFlag )
|
||
{
|
||
//
|
||
// spin protect
|
||
// - if error in previous NotifyAddrChange or
|
||
// GetOverlappedResult do short sleep to avoid
|
||
// chance of hard spin
|
||
//
|
||
|
||
if ( fsleep )
|
||
{
|
||
WaitForSingleObject(
|
||
g_hStopEvent,
|
||
60000 );
|
||
fsleep = FALSE;
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// start notification
|
||
//
|
||
// do this before checking result as we want notification
|
||
// down BEFORE we read so we don't leave window where
|
||
// IP change is not picked up
|
||
//
|
||
|
||
RtlZeroMemory(
|
||
&g_IpNotifyOverlapped,
|
||
sizeof(OVERLAPPED) );
|
||
|
||
if ( g_IpNotifyEvent )
|
||
{
|
||
g_IpNotifyOverlapped.hEvent = g_IpNotifyEvent;
|
||
ResetEvent( g_IpNotifyEvent );
|
||
}
|
||
notifyHandle = 0;
|
||
fstartedNotify = FALSE;
|
||
|
||
status = NotifyAddrChange(
|
||
& notifyHandle,
|
||
& g_IpNotifyOverlapped );
|
||
|
||
if ( status == ERROR_IO_PENDING )
|
||
{
|
||
DNSDBG( INIT, (
|
||
"NotifyAddrChange()\n"
|
||
"\tstatus = %d\n"
|
||
"\thandle = %d\n"
|
||
"\toverlapped event = %d\n",
|
||
status,
|
||
notifyHandle,
|
||
g_IpNotifyOverlapped.hEvent ));
|
||
|
||
g_IpNotifyHandle = notifyHandle;
|
||
fstartedNotify = TRUE;
|
||
}
|
||
else
|
||
{
|
||
DNSDBG( ANY, (
|
||
"NotifyAddrChange() FAILED\n"
|
||
"\tstatus = %d\n"
|
||
"\thandle = %d\n"
|
||
"\toverlapped event = %d\n",
|
||
status,
|
||
notifyHandle,
|
||
g_IpNotifyOverlapped.hEvent ));
|
||
|
||
fsleep = TRUE;
|
||
}
|
||
|
||
if ( g_StopFlag )
|
||
{
|
||
goto Done;
|
||
}
|
||
|
||
//
|
||
// previous notification -- refresh data
|
||
//
|
||
// FlushCache currently include local IP list
|
||
// sleep keeps us from spinning in this loop
|
||
//
|
||
// DCR: better spin protection;
|
||
// if hit X times then sleep longer?
|
||
//
|
||
|
||
if ( fhaveIpChange )
|
||
{
|
||
DNSDBG( ANY, ( "\nIP notification, flushing cache and restarting.\n" ));
|
||
HandleConfigChange(
|
||
"IP-notification",
|
||
TRUE // flush cache
|
||
);
|
||
fhaveIpChange = FALSE;
|
||
}
|
||
|
||
//
|
||
// starting --
|
||
// clear list to force rebuild of IP list AFTER starting notify
|
||
// so we can know that we don't miss any changes;
|
||
// need this on startup, but also to protect against any
|
||
// NotifyAddrChange failues
|
||
//
|
||
|
||
else if ( fstartedNotify )
|
||
{
|
||
ClearLocalAddrArray();
|
||
}
|
||
|
||
//
|
||
// anti-spin protection
|
||
// - 15 second sleep between any notifications
|
||
//
|
||
|
||
WaitForSingleObject(
|
||
g_hStopEvent,
|
||
15000 );
|
||
|
||
if ( g_StopFlag )
|
||
{
|
||
goto Done;
|
||
}
|
||
|
||
//
|
||
// wait on notification
|
||
// - save notification result
|
||
// - sleep on error, but never if notification
|
||
//
|
||
|
||
if ( fstartedNotify )
|
||
{
|
||
fhaveIpChange = GetOverlappedResult(
|
||
g_IpNotifyHandle,
|
||
& g_IpNotifyOverlapped,
|
||
& bytesRecvd,
|
||
TRUE // wait
|
||
);
|
||
fsleep = !fhaveIpChange;
|
||
|
||
status = NO_ERROR;
|
||
if ( !fhaveIpChange )
|
||
{
|
||
status = GetLastError();
|
||
}
|
||
DNSDBG( ANY, (
|
||
"GetOverlappedResult() => %d.\n"
|
||
"\t\tstatus = %d\n",
|
||
fhaveIpChange,
|
||
status ));
|
||
}
|
||
}
|
||
|
||
Done:
|
||
|
||
DNSDBG( ANY, ( "Stop IP Notify thread on service shutdown.\n" ));
|
||
|
||
CloseIpNotifyHandle();
|
||
|
||
return( status );
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
ZeroInitIpListGlobals(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Zero-init IP globals just for failure protection.
|
||
|
||
The reason to have this is there is some interaction with
|
||
the cache from the notify thread. To avoid that being a
|
||
problem we start the cache first.
|
||
|
||
But just for safety we should at least zero init these
|
||
globals first to protect us from cache touching them.
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
NO_ERROR on normal service shutdown
|
||
Win32 error on abnormal termination
|
||
|
||
--*/
|
||
{
|
||
//
|
||
// clear out globals to smoothly handle failure cases
|
||
//
|
||
|
||
g_LocalAddrArray = NULL;
|
||
g_ClusterIpArray = NULL;
|
||
g_OldClusterIp = 0;
|
||
|
||
g_IpNotifyThread = NULL;
|
||
g_IpNotifyThreadId = 0;
|
||
g_IpNotifyEvent = NULL;
|
||
g_IpNotifyHandle = NULL;
|
||
}
|
||
|
||
|
||
|
||
DNS_STATUS
|
||
InitIpListAndNotification(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Start IP notification thread.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Globals:
|
||
|
||
Initializes IP list and notify thread globals.
|
||
|
||
Return Value:
|
||
|
||
NO_ERROR on normal service shutdown
|
||
Win32 error on abnormal termination
|
||
|
||
--*/
|
||
{
|
||
DNS_STATUS status = NO_ERROR;
|
||
|
||
DNSDBG( TRACE, ( "InitIpListAndNotification()\n" ));
|
||
|
||
//
|
||
// CS for IP list access
|
||
//
|
||
|
||
InitializeCriticalSection( &g_IpListCS );
|
||
|
||
//
|
||
// create event for overlapped I/O
|
||
//
|
||
|
||
g_IpNotifyEvent = CreateEvent(
|
||
NULL, // no security descriptor
|
||
TRUE, // manual reset event
|
||
FALSE, // start not signalled
|
||
NULL // no name
|
||
);
|
||
if ( !g_IpNotifyEvent )
|
||
{
|
||
status = GetLastError();
|
||
DNSDBG( ANY, ( "\nFAILED IpNotifyEvent create.\n" ));
|
||
goto Done;
|
||
}
|
||
|
||
//
|
||
// fire up IP notify thread
|
||
//
|
||
|
||
g_IpNotifyThread = CreateThread(
|
||
NULL,
|
||
0,
|
||
(LPTHREAD_START_ROUTINE) IpNotifyThread,
|
||
NULL,
|
||
0,
|
||
& g_IpNotifyThreadId
|
||
);
|
||
if ( !g_IpNotifyThread )
|
||
{
|
||
status = GetLastError();
|
||
DNSDBG( ANY, (
|
||
"FAILED to create IP notify thread = %d\n",
|
||
status ));
|
||
}
|
||
|
||
Done:
|
||
|
||
// not currently stopping on init failure
|
||
|
||
return( ERROR_SUCCESS );
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
ShutdownIpListAndNotify(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Stop IP notify thread.
|
||
|
||
Note: currently this is blocking call, we'll wait until
|
||
thread shuts down.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
DNSDBG( TRACE, ( "ShutdownIpListAndNotify()\n" ));
|
||
|
||
//
|
||
// MUST be stopping
|
||
// - if not thread won't wake
|
||
//
|
||
|
||
ASSERT( g_StopFlag );
|
||
|
||
g_StopFlag = TRUE;
|
||
|
||
//
|
||
// close IP notify handles -- waking thread if still running
|
||
//
|
||
|
||
if ( g_IpNotifyEvent )
|
||
{
|
||
SetEvent( g_IpNotifyEvent );
|
||
}
|
||
CloseIpNotifyHandle();
|
||
|
||
//
|
||
// wait for thread to stop
|
||
//
|
||
|
||
ThreadShutdownWait( g_IpNotifyThread );
|
||
g_IpNotifyThread = NULL;
|
||
|
||
//
|
||
// cleanup IP lists
|
||
//
|
||
|
||
if ( g_LocalAddrArray )
|
||
{
|
||
GENERAL_HEAP_FREE( g_LocalAddrArray );
|
||
g_LocalAddrArray = NULL;
|
||
}
|
||
if ( g_ClusterIpArray )
|
||
{
|
||
GENERAL_HEAP_FREE( g_ClusterIpArray );
|
||
g_ClusterIpArray = NULL;
|
||
g_OldClusterIp = 0;
|
||
}
|
||
|
||
//
|
||
// close event
|
||
//
|
||
|
||
CloseHandle( g_IpNotifyEvent );
|
||
g_IpNotifyEvent = NULL;
|
||
|
||
//
|
||
// kill off CS
|
||
//
|
||
|
||
DeleteCriticalSection( &g_IpListCS );
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// IP list routines
|
||
//
|
||
|
||
DWORD
|
||
SizeForAddrArray(
|
||
IN DWORD AddrCount
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Determine size for addr array of given count.
|
||
|
||
Arguments:
|
||
|
||
AddrCount -- count of addresses
|
||
|
||
Return Value:
|
||
|
||
Size in bytes required for addr array.
|
||
|
||
--*/
|
||
{
|
||
return sizeof(DNS_ADDR_ARRAY) + (AddrCount * sizeof(DNS_ADDR_INFO));
|
||
}
|
||
|
||
|
||
|
||
PDNS_ADDR_ARRAY
|
||
CopyAddrArray(
|
||
IN PDNS_ADDR_ARRAY pAddrArray
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Create copy of address info array.
|
||
|
||
Arguments:
|
||
|
||
pAddrArray -- ptr to addr info array to copy
|
||
|
||
Return Value:
|
||
|
||
Ptr to new addr array.
|
||
|
||
--*/
|
||
{
|
||
PDNS_ADDR_ARRAY pnew;
|
||
DWORD size;
|
||
|
||
DNSDBG( TRACE, ( "CopyAddrArray()\n" ));
|
||
|
||
//
|
||
// alloc memory and copy
|
||
//
|
||
|
||
size = SizeForAddrArray( pAddrArray->AddrCount );
|
||
|
||
pnew = (PDNS_ADDR_ARRAY) GENERAL_HEAP_ALLOC( size );
|
||
if ( pnew )
|
||
{
|
||
RtlCopyMemory(
|
||
pnew,
|
||
pAddrArray,
|
||
size
|
||
);
|
||
}
|
||
|
||
return pnew;
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
ClearLocalAddrArray(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Clear the IP list data.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Globals:
|
||
|
||
Updates IP list globals.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
PDNS_ADDR_ARRAY poldArray;
|
||
|
||
DNSDBG( TRACE, ( "ClearLocalAddrArray()\n" ));
|
||
|
||
//
|
||
// clear new list
|
||
//
|
||
// must go through lock even if no list, in case another
|
||
// thread started building new list before our call
|
||
//
|
||
|
||
LOCK_IP_LIST();
|
||
|
||
poldArray = g_LocalAddrArray;
|
||
g_LocalAddrArray = NULL;
|
||
|
||
UNLOCK_IP_LIST();
|
||
|
||
// free old list
|
||
|
||
if ( poldArray )
|
||
{
|
||
GENERAL_HEAP_FREE( poldArray );
|
||
}
|
||
}
|
||
|
||
|
||
|
||
PDNS_ADDR_ARRAY
|
||
GetLocalAddrArray(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Get copy of local IP address info list.
|
||
|
||
Note: caller must free list.
|
||
|
||
//
|
||
// DCR: just direct return of counted array
|
||
// - include IPv6
|
||
//
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Globals:
|
||
|
||
May update IP list globals.
|
||
|
||
Return Value:
|
||
|
||
Ptr to local addr info array. Caller must free.
|
||
NULL on allocation failure.
|
||
|
||
--*/
|
||
{
|
||
PDNS_ADDR_ARRAY pnew = NULL;
|
||
DWORD size;
|
||
|
||
DNSDBG( TRACE, ( "GetLocalAddrArray()\n" ));
|
||
|
||
LOCK_IP_LIST();
|
||
|
||
//
|
||
// if no current list -- try to get one
|
||
//
|
||
|
||
if ( !g_LocalAddrArray )
|
||
{
|
||
g_LocalAddrArray = DnsGetLocalAddrArrayDirect();
|
||
if ( !g_LocalAddrArray )
|
||
{
|
||
goto Unlock;
|
||
}
|
||
IF_DNSDBG( INIT )
|
||
{
|
||
DnsDbg_DnsAddrArray(
|
||
"New IP address info:",
|
||
g_LocalAddrArray
|
||
);
|
||
}
|
||
}
|
||
|
||
//
|
||
// alloc memory and copy
|
||
//
|
||
|
||
pnew = CopyAddrArray( g_LocalAddrArray );
|
||
|
||
Unlock:
|
||
|
||
UNLOCK_IP_LIST();
|
||
|
||
return pnew;
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
RegisterClusterIp4Address(
|
||
IN IP_ADDRESS ClusterIp,
|
||
IN BOOL fAdd
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Register IP4 cluster IP.
|
||
|
||
Arguments:
|
||
|
||
ClusterIp -- IP of cluster
|
||
|
||
fAdd -- TRUE if adding cluster IP, FALSE if deleting
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
DNSLOG_F1( "RegisterClusterIp4Address" );
|
||
|
||
DNSDBG( RPC, (
|
||
"RegisterClusterIp4Address\n"
|
||
"\tClusterIp = %s\n"
|
||
"\tfAdd = %d\n",
|
||
IP_STRING( ClusterIp ),
|
||
fAdd ));
|
||
|
||
LOCK_IP_LIST();
|
||
|
||
//
|
||
// adding, add to exclusion list
|
||
//
|
||
|
||
if ( fAdd )
|
||
{
|
||
// put IP in cluster array
|
||
// - if array is full (or nonexistant), allocate bigger one
|
||
// and slap IP in again
|
||
|
||
if ( ! Dns_AddIpToIpArray(
|
||
g_ClusterIpArray,
|
||
ClusterIp ) )
|
||
{
|
||
g_ClusterIpArray = Dns_CopyAndExpandIpArray(
|
||
g_ClusterIpArray,
|
||
25, // expand by 20 slots
|
||
TRUE // delete existing copy
|
||
);
|
||
Dns_AddIpToIpArray(
|
||
g_ClusterIpArray,
|
||
ClusterIp );
|
||
}
|
||
}
|
||
|
||
//
|
||
// deleting remove from exclusion list
|
||
// - but save old cluster IP as global until we are
|
||
// sure it is gone
|
||
//
|
||
|
||
else
|
||
{
|
||
g_OldClusterIp = ClusterIp;
|
||
|
||
if ( !g_ClusterIpArray )
|
||
{
|
||
goto Refresh;
|
||
}
|
||
Dns_ClearIpFromIpArray(
|
||
g_ClusterIpArray,
|
||
ClusterIp );
|
||
}
|
||
|
||
Refresh:
|
||
|
||
// no need to clear local array
|
||
//
|
||
// IP help gives us notification of cluster IP change; since
|
||
// cluster calls us after making change, we've probably already
|
||
// been notified and done reread; since we don't keep a global
|
||
// filtered list there's no need to dump it
|
||
//
|
||
|
||
// ClearLocalAddrArray();
|
||
|
||
IF_DNSDBG( INIT )
|
||
{
|
||
DnsDbg_IpArray(
|
||
"Cluster Exclusion Array:",
|
||
NULL,
|
||
g_ClusterIpArray
|
||
);
|
||
DnsDbg_Printf(
|
||
"Old Cluster IP = %s\n",
|
||
IP_STRING( g_OldClusterIp ) );
|
||
}
|
||
|
||
UNLOCK_IP_LIST();
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
RemoveClusterIpFromAddrArray(
|
||
IN OUT PDNS_ADDR_ARRAY pAddrArray
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Screen cluster addresses from IP list.
|
||
|
||
Note, assumes caller has network info locked.
|
||
|
||
Arguments:
|
||
|
||
pAddrArray -- array with unscreened address info
|
||
|
||
AddrCount -- count of addresses
|
||
|
||
Return Value:
|
||
|
||
Count after screening
|
||
|
||
--*/
|
||
{
|
||
DWORD loadIndex = 0;
|
||
DWORD testIndex;
|
||
IP_ADDRESS ip;
|
||
BOOL fexclusion = FALSE;
|
||
BOOL fexcludeOldCluster = FALSE;
|
||
|
||
|
||
DNSDBG( TRACE, (
|
||
"RemoveClusterIpFromAddrArray()\n" ));
|
||
|
||
//
|
||
// screen IP address list for cluster IPs
|
||
//
|
||
// note, we do a push down here because we want to maintain order
|
||
// or remaining IP addresses
|
||
//
|
||
// note, we could have this function do a copy from source to
|
||
// destination, so we aren't copying twice in this case;
|
||
// i don't see this as a big win
|
||
//
|
||
|
||
for ( testIndex = 0;
|
||
testIndex < pAddrArray->AddrCount;
|
||
testIndex++ )
|
||
{
|
||
ip = pAddrArray->AddrArray[testIndex].IpAddr;
|
||
|
||
if ( ip == g_OldClusterIp )
|
||
{
|
||
DNSDBG( INIT, (
|
||
"Screened old cluster IP %s from local list.\n",
|
||
IP_STRING(ip) ));
|
||
fexclusion = TRUE;
|
||
fexcludeOldCluster = TRUE;
|
||
continue;
|
||
}
|
||
if ( Dns_IsAddressInIpArray( g_ClusterIpArray, ip ) )
|
||
{
|
||
DNSDBG( INIT, (
|
||
"Screened cluster IP %s from local list.\n",
|
||
IP_STRING(ip) ));
|
||
fexclusion = TRUE;
|
||
continue;
|
||
}
|
||
|
||
// once have exclusion must push down addresses
|
||
|
||
if ( fexclusion )
|
||
{
|
||
RtlCopyMemory(
|
||
& pAddrArray->AddrArray[loadIndex],
|
||
& pAddrArray->AddrArray[testIndex],
|
||
sizeof(DNS_ADDR_INFO)
|
||
);
|
||
}
|
||
loadIndex++;
|
||
}
|
||
|
||
pAddrArray->AddrCount = loadIndex;
|
||
|
||
// clear old cluster IP, if no longer in local list
|
||
// - keep excluding until it doesn't show up anymore
|
||
// if it shows up after that then it is legitimate address
|
||
|
||
if ( !fexcludeOldCluster )
|
||
{
|
||
g_OldClusterIp = 0;
|
||
}
|
||
|
||
return( loadIndex );
|
||
}
|
||
|
||
|
||
|
||
PDNS_ADDR_ARRAY
|
||
GetLocalAddrArrayFiltered(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Get filtered addr info array.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Globals:
|
||
|
||
May update IP list globals.
|
||
|
||
Return Value:
|
||
|
||
Ptr to local addr info array. Caller must free.
|
||
NULL on allocation failure.
|
||
|
||
--*/
|
||
{
|
||
PDNS_ADDR_ARRAY pnew = NULL;
|
||
DWORD count;
|
||
|
||
DNSDBG( TRACE, ( "GetLocalAddrArrayFiltered()\n" ));
|
||
|
||
LOCK_IP_LIST();
|
||
|
||
//
|
||
// create cluster filtered list
|
||
//
|
||
// - created copy of full list
|
||
// - screen out cluster IPs
|
||
// - note NET lock protects use of cluster list also
|
||
//
|
||
// note: if filter alloc fails, treats as no filtering avail
|
||
//
|
||
|
||
pnew = GetLocalAddrArray();
|
||
if ( !pnew )
|
||
{
|
||
goto Unlock;
|
||
}
|
||
|
||
RemoveClusterIpFromAddrArray( pnew );
|
||
|
||
Unlock:
|
||
|
||
UNLOCK_IP_LIST();
|
||
|
||
IF_DNSDBG( INIT )
|
||
{
|
||
DnsDbg_DnsAddrArray(
|
||
"Filtered IP address info:",
|
||
pnew
|
||
);
|
||
}
|
||
|
||
return pnew;
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Remote IP list routines
|
||
//
|
||
|
||
VOID
|
||
R_ResolverGetLocalAddrInfoArray(
|
||
IN DNS_RPC_HANDLE Reserved,
|
||
OUT PDNS_ADDR_ARRAY * ppAddrArray,
|
||
IN ENVAR_DWORD_INFO FilterInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Get local IP address list from resolver.
|
||
|
||
Arguments:
|
||
|
||
Reserved -- RPC handle
|
||
|
||
ppIpAddrList -- addr to recv ptr to array
|
||
|
||
FilterInfo -- FilterClusterIp environment variable info
|
||
|
||
Return Value:
|
||
|
||
Count of IP addresses returned
|
||
|
||
--*/
|
||
{
|
||
PDNS_ADDR_ARRAY preturnList = NULL;
|
||
|
||
DNSLOG_F1( "R_ResolverGetLocalAddrInfoArray()" );
|
||
DNSDBG( RPC, ( "R_ResolverGetLocalAddrInfoArray()\n" ));
|
||
|
||
//
|
||
// validate
|
||
//
|
||
|
||
if ( !ppAddrArray )
|
||
{
|
||
return; // ERROR_INVALID_PARAMETER;
|
||
}
|
||
if ( ClientThreadNotAllowedAccess() )
|
||
{
|
||
DNSLOG_F1( "R_ResolverGetLocalAddrInfoArray() - ERROR_ACCESS_DENIED" );
|
||
goto Done;
|
||
}
|
||
|
||
//
|
||
// determine if need to filter
|
||
//
|
||
// default is don't filter unless environment variable is
|
||
// explicitly set
|
||
//
|
||
|
||
if ( FilterInfo.fFound && FilterInfo.Value )
|
||
{
|
||
preturnList = GetLocalAddrArrayFiltered();
|
||
}
|
||
else
|
||
{
|
||
preturnList = GetLocalAddrArray();
|
||
}
|
||
|
||
Done:
|
||
|
||
*ppAddrArray = preturnList;
|
||
|
||
DNSDBG( RPC, ( "Leave R_ResolverGetLocalAddrInfoArray()\n" ));
|
||
}
|
||
|
||
|
||
VOID
|
||
R_ResolverRegisterClusterIp(
|
||
IN DNS_RPC_HANDLE Handle,
|
||
IN IP_ADDRESS ClusterIp,
|
||
IN DWORD Tag,
|
||
IN BOOL fAdd
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Make the query to remote DNS server.
|
||
|
||
Arguments:
|
||
|
||
Handle -- RPC handle
|
||
|
||
ClusterIp -- IP of cluster
|
||
|
||
fAdd -- TRUE if adding cluster IP, FALSE if deleting
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
DNSLOG_F1( "R_ResolverRegisterClusterIp" );
|
||
|
||
DNSDBG( RPC, (
|
||
"R_ResolverRegisterClusterIp\n"
|
||
"\tClusterIp = %s\n"
|
||
"\tfAdd = %d\n",
|
||
IP_STRING( ClusterIp ),
|
||
fAdd ));
|
||
|
||
//
|
||
// DCR: should have security
|
||
//
|
||
|
||
if ( ClientThreadNotAllowedAccess() )
|
||
{
|
||
DNSLOG_F1( "R_ResolverFlushCache - ERROR_ACCESS_DENIED" );
|
||
return;
|
||
}
|
||
if ( Tag != CLUSTER_TAG )
|
||
{
|
||
return;
|
||
}
|
||
|
||
RegisterClusterIp4Address(
|
||
ClusterIp,
|
||
fAdd );
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Cluster IP manipulation.
|
||
//
|
||
|
||
#if 0
|
||
BOOL
|
||
Resolver_IsClusterIpCallback(
|
||
IN PIP_UNION pIpUnion,
|
||
IN BOOL fCopyName,
|
||
OUT PWCHAR * ppName
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Detect cluster address.
|
||
|
||
Arguments:
|
||
|
||
pIpUnion -- address to test
|
||
|
||
fCopyName -- want the name back
|
||
|
||
ppName -- addr to recv ptr to name
|
||
|
||
Return Value:
|
||
|
||
TRUE if cluster IP
|
||
FALSE if regular IP
|
||
|
||
--*/
|
||
{
|
||
IP4_ADDRESS ip;
|
||
|
||
|
||
DNSDBG( TRACE, (
|
||
"Resolver_IsClusterIpCallback()\n" ));
|
||
|
||
//
|
||
// no IP6 support yet
|
||
//
|
||
|
||
*ppName = NULL;
|
||
|
||
//
|
||
// DCR: keep cluster as combo IP list with ptr to cluster name
|
||
//
|
||
|
||
if ( pIpUnion->IsIp6 )
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
ip = pIpUnion.Ip4;
|
||
|
||
if ( ip == g_OldClusterIp )
|
||
{
|
||
DNSDBG( INIT, (
|
||
"IP is old cluster IP %s.\n",
|
||
IP_STRING(ip) ));
|
||
return TRUE;
|
||
}
|
||
|
||
LOCK_IP_LIST();
|
||
|
||
fresult = Dns_IsAddressInIpArray( g_ClusterIpArray, ip );
|
||
|
||
UNLOCK_IP_LIST();
|
||
if ( fresult )
|
||
{
|
||
DNSDBG( INIT, (
|
||
"IP is current cluster IP %s.\n",
|
||
IP_STRING(ip) ));
|
||
return TRUE;
|
||
}
|
||
|
||
// not cluster IP
|
||
|
||
return FALSE;
|
||
}
|
||
#endif
|
||
|
||
|
||
|
||
//
|
||
// Cluster filtering callback routines
|
||
//
|
||
|
||
BOOL
|
||
IsClusterIp4Addr(
|
||
IN IP4_ADDRESS IpAddr
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Check if cluster address.
|
||
|
||
Arguments:
|
||
|
||
IpAddr -- IP4 address
|
||
|
||
Return Value:
|
||
|
||
TRUE if cluster IP.
|
||
FALSE otherwise.
|
||
|
||
--*/
|
||
{
|
||
DNSDBG( TRACE, (
|
||
"IsClusterIp4Addr( %08x )\n", IpAddr ));
|
||
|
||
if ( Dns_IsAddressInIpArray( g_ClusterIpArray, IpAddr ) )
|
||
{
|
||
DNSDBG( INIT, (
|
||
"IP %s is cluster address.\n",
|
||
IP_STRING(IpAddr) ));
|
||
return TRUE;
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
IsClusterAddress(
|
||
IN OUT PQUERY_BLOB pBlob,
|
||
IN PIP_UNION pIpUnion
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Cluster filtering callback.
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
TRUE if cluster IP.
|
||
FALSE otherwise.
|
||
|
||
--*/
|
||
{
|
||
IP4_ADDRESS ip4;
|
||
|
||
DNSDBG( TRACE, (
|
||
"IsClusterAddress( %p, %p )\n",
|
||
pBlob,
|
||
pIpUnion ));
|
||
|
||
if ( !g_ClusterIpArray )
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// determine if cluster address
|
||
//
|
||
// DCR: create cluster IP records
|
||
// - match cluster name and create forward record
|
||
// - match IP and create reverse record to cluster name
|
||
//
|
||
|
||
if ( IPUNION_IS_IP4(pIpUnion) )
|
||
{
|
||
BOOL fresult;
|
||
IP4_ADDRESS ip4;
|
||
|
||
ip4 = IPUNION_GET_IP4( pIpUnion );
|
||
|
||
LOCK_IP_LIST();
|
||
fresult = Dns_IsAddressInIpArray( g_ClusterIpArray, ip4 );
|
||
UNLOCK_IP_LIST();
|
||
|
||
return fresult;
|
||
}
|
||
|
||
// DCR: no IP6 cluster support yet
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
|
||
DNS_STATUS
|
||
R_ResolverRegisterCluster(
|
||
IN DNS_RPC_HANDLE Handle,
|
||
IN DWORD Tag,
|
||
IN PWSTR pwsName,
|
||
IN PRPC_IP_UNION pIpUnion,
|
||
IN DWORD Flag
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Make the query to remote DNS server.
|
||
|
||
Arguments:
|
||
|
||
Handle -- RPC handle
|
||
|
||
Tag -- RPC API tag
|
||
|
||
pwsName -- name of cluster
|
||
|
||
pIpUnion -- IP union
|
||
|
||
Flag -- registration flag
|
||
DNS_CLUSTER_ADD
|
||
DNS_CLUSTER_DELETE_NAME
|
||
DNS_CLUSTER_DELETE_IP
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
PDNS_RECORD prrAddr = NULL;
|
||
PDNS_RECORD prrPtr = NULL;
|
||
WORD wtype;
|
||
PIP_UNION pip = (PIP_UNION) pIpUnion;
|
||
DNS_STATUS status;
|
||
BOOL fadd;
|
||
|
||
|
||
DNSLOG_F1( "R_ResolverRegisterCluster" );
|
||
|
||
ASSERT( sizeof(IP_UNION) == sizeof(RPC_IP_UNION) );
|
||
|
||
DNSDBG( RPC, (
|
||
"R_ResolverRegisterCluster()\n"
|
||
"\tpName = %s\n"
|
||
"\tpIpUnion = %p\n"
|
||
"\tFlag = %08x\n",
|
||
pwsName,
|
||
pip,
|
||
Flag ));
|
||
|
||
//
|
||
// DCR: should have security
|
||
//
|
||
|
||
if ( ClientThreadNotAllowedAccess() )
|
||
{
|
||
DNSLOG_F1( "R_ResolverRegisterClusterIp - ERROR_ACCESS_DENIED" );
|
||
return ERROR_ACCESS_DENIED;
|
||
}
|
||
if ( Tag != CLUSTER_TAG )
|
||
{
|
||
return ERROR_ACCESS_DENIED;
|
||
}
|
||
|
||
//
|
||
// get type
|
||
//
|
||
|
||
wtype = DNS_TYPE_A;
|
||
if ( IPUNION_IS_IP6(pip) )
|
||
{
|
||
wtype = DNS_TYPE_AAAA;
|
||
}
|
||
fadd = (Flag == DNS_CLUSTER_ADD);
|
||
|
||
//
|
||
// cluster add -- cache cluster records
|
||
// - forward and reverse
|
||
//
|
||
|
||
if ( !pwsName )
|
||
{
|
||
DNSDBG( ANY, ( "WARNING: no cluster name given!\n" ));
|
||
goto AddrList;
|
||
}
|
||
|
||
//
|
||
// build records
|
||
// - address and corresponding PTR
|
||
//
|
||
|
||
prrAddr = Dns_CreateForwardRecord(
|
||
pwsName,
|
||
pip,
|
||
CLUSTER_RECORD_TTL,
|
||
DnsCharSetUnicode,
|
||
DnsCharSetUnicode );
|
||
|
||
if ( !prrAddr )
|
||
{
|
||
status = GetLastError();
|
||
if ( status == ERROR_SUCCESS )
|
||
{
|
||
status = ERROR_INVALID_DATA;
|
||
}
|
||
return status;
|
||
}
|
||
SET_RR_CLUSTER( prrAddr );
|
||
|
||
prrPtr = Dns_CreatePtrRecordEx(
|
||
pip,
|
||
pwsName,
|
||
CLUSTER_RECORD_TTL,
|
||
DnsCharSetUnicode,
|
||
DnsCharSetUnicode );
|
||
if ( prrPtr )
|
||
{
|
||
SET_RR_CLUSTER( prrPtr );
|
||
}
|
||
|
||
//
|
||
// add records to cache
|
||
//
|
||
|
||
if ( Flag == DNS_CLUSTER_ADD )
|
||
{
|
||
Cache_RecordSetAtomic(
|
||
NULL, // record name
|
||
0, // record type
|
||
prrAddr );
|
||
|
||
if ( prrPtr )
|
||
{
|
||
Cache_RecordSetAtomic(
|
||
NULL, // record name
|
||
0, // record type
|
||
prrPtr );
|
||
}
|
||
prrAddr = NULL;
|
||
prrPtr = NULL;
|
||
}
|
||
|
||
//
|
||
// if delete cluster, flush cache entries for name\type
|
||
//
|
||
// DCR: don't have way to STRONG flush a name and type
|
||
// assume cluster name goes away wholesale
|
||
//
|
||
// DCR: need delete of cluster PTR record
|
||
// must be name specific
|
||
//
|
||
// DCR: build reverse name independently so whack works
|
||
// even without cluster name
|
||
//
|
||
|
||
else if ( Flag == DNS_CLUSTER_DELETE_NAME )
|
||
{
|
||
Cache_FlushRecords(
|
||
pwsName,
|
||
FLUSH_LEVEL_STRONG,
|
||
0 );
|
||
|
||
// delete record matching PTR
|
||
}
|
||
|
||
else if ( Flag == DNS_CLUSTER_DELETE_IP )
|
||
{
|
||
Cache_FlushRecords(
|
||
pwsName,
|
||
FLUSH_LEVEL_STRONG,
|
||
0 );
|
||
|
||
Cache_FlushRecords(
|
||
prrPtr->pName,
|
||
FLUSH_LEVEL_STRONG,
|
||
0 );
|
||
}
|
||
|
||
//
|
||
// IP4 address list backcompat processing
|
||
//
|
||
// note: could use sockaddr to IP6 routine here
|
||
// if want list of IP6 addrs; if build combined
|
||
// type then should have conversion routine
|
||
//
|
||
// my take here is that IP6 cluster addresses won't show
|
||
// up period
|
||
//
|
||
|
||
AddrList:
|
||
|
||
if ( wtype == DNS_TYPE_A )
|
||
{
|
||
IP4_ADDRESS ip4 = IPUNION_GET_IP4(pip);
|
||
|
||
if ( !fadd &&
|
||
Flag != DNS_CLUSTER_DELETE_IP )
|
||
{
|
||
goto Done;
|
||
}
|
||
|
||
RegisterClusterIp4Address(
|
||
ip4,
|
||
fadd );
|
||
}
|
||
|
||
Done:
|
||
|
||
// cleanup uncached records
|
||
|
||
Dns_RecordFree( prrAddr );
|
||
Dns_RecordFree( prrPtr );
|
||
|
||
return ERROR_SUCCESS;
|
||
}
|
||
|
||
|
||
//
|
||
// End ip.c
|
||
//
|