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.
 
 
 
 
 
 

1546 lines
28 KiB

/*++
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
//