|
|
/*++
Copyright (c) 1996-2001 Microsoft Corporation
Module Name:
asyncreg.c
Abstract:
Domain Name System (DNS) API
Client IP/PTR dynamic update.
Author:
Glenn Curtis (GlennC) Feb-16-1998
Revision History:
Jim Gilroy (jamesg) May\June 2001 - eliminate duplicate code - simplify lines - PTR reg only if forward successful - alternate names
--*/
#include "local.h"
#include <netevent.h>
#define ENABLE_DEBUG_LOGGING 1
#include "logit.h"
//
// Flags for debugging for this module
//
#define DNS_DBG_DHCP DNS_DBG_UPDATE
#define DNS_DBG_DHCP2 DNS_DBG_UPDATE2
//
// Registry values
//
#define ADAPTER_NAME_CLASS "AdapterNameClass"
#define REGISTERED_ADDRS "RegisteredAddresses"
#define REGISTERED_ADDRS_COUNT "RegisteredAddressCount"
#define REGISTERED_NAME "RegisteredName"
//
// DCR_CLEANUP: tag these definitions to avoid collision
// with registry.h defs
//
#define REGISTERED_HOST_NAME "HostName"
#define REGISTERED_HOST_NAME_W L"HostName"
#define REGISTERED_DOMAIN_NAME "DomainName"
#define REGISTERED_DOMAIN_NAME_W L"DomainName"
#define SENT_UPDATE_TO_IP "SentUpdateToIp"
#define SENT_PRI_UPDATE_TO_IP "SentPriUpdateToIp"
#define REGISTERED_TTL "RegisteredTTL"
#define FLAGS "RegisteredFlags"
#define REGISTERED_SINCE_BOOT "RegisteredSinceBoot"
#define DNS_SERVER_ADDRS "DNSServerAddresses"
#define DNS_SERVER_ADDRS_COUNT "DNSServerAddressCount"
#define DEFAULT_REG_LOCATION "System\\CurrentControlSet\\Services\\Tcpip\\Parameters\\DNSRegisteredAdapters"
#define DEFAULT_REG_LOCATION_WIN95 "System\\CurrentControlSet\\Services\\VxD\\MSTCP\\Parameters\\DNSRegisteredAdapters"
#define NT_INTERFACE_REG_LOCATION "System\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\"
#define TCPIP_REG_LOCATION "System\\CurrentControlSet\\Services\\Tcpip\\Parameters"
#define DYN_DNS_ROOT_CLASS "DynDRootClass"
#define BOOT_TIME "BootTime"
#define DHCPVER_WIN95 2
#define DHCPVER_WINNT 1
#define DHCPVER_UNINIT 0
#define FIRST_RETRY_INTERVAL 5*60 // 5 minutes
#define SECOND_RETRY_INTERVAL 10*60 // 10 minutes
#define FAILED_RETRY_INTERVAL 60*60 // 1 hour
#define ASYNC_INIT_CALLED() (g_dwVersion != DHCPVER_UNINIT)
#define CLEAR_ASYNC_INIT() g_dwVersion = DHCPVER_UNINIT ;
//
// Registry state flags
//
#define REGISTERED_FORWARD 0x00000001
#define REGISTERED_PRIMARY 0x00000002
#define REGISTERED_POINTER 0x00000004
//
// Update type
//
// Multiple types of updates for a given entry.
// These identify which type (which name) being updated.
//
typedef enum _UpType { UPTYPE_PRIMARY = 1, UPTYPE_DOMAIN, UPTYPE_ALTERNATE, UPTYPE_PTR } UPTYPE, *PUPTYPE;
#define IS_UPTYPE_PRIMARY(UpType) ((UpType)==UPTYPE_PRIMARY)
#define IS_UPTYPE_DOMAIN(UpType) ((UpType)==UPTYPE_DOMAIN)
#define IS_UPTYPE_ALTERNATE(UpType) ((UpType)==UPTYPE_ALTERNATE)
#define IS_UPTYPE_PTR(UpType) ((UpType)==UPTYPE_PTR)
//
// On unjoin, deregistration wait no more than two minutes
// to clean up -- then just get outta Dodge
//
#if DBG
#define REMOVE_REGISTRATION_WAIT_LIMIT (0xffffffff)
#else
#define REMOVE_REGISTRATION_WAIT_LIMIT (120000) // 2 minutes in ms
#endif
//
// definition of client list element
//
#define DNS_SIG_TOP 0x123aa321
#define DNS_SIG_BOTTOM 0x321bb123
typedef struct _DnsUpdateEntry { LIST_ENTRY List; DWORD SignatureTop; PSTR AdapterName; PSTR HostName; PSTR PrimaryDomainName; PSTR DomainName; PSTR AlternateNames; DWORD AlternateIndex; DWORD HostAddrCount; PREGISTER_HOST_ENTRY HostAddrs; PIP_ARRAY DnsServerList; IP_ADDRESS SentUpdateToIp; IP_ADDRESS SentPriUpdateToIp; DWORD TTL; DWORD Flags; BOOL fNewElement; BOOL fFromRegistry; BOOL fRemove; BOOL fRegisteredPRI; BOOL fRegisteredFWD; BOOL fRegisteredALT; BOOL fRegisteredPTR; BOOL fDisableErrorLogging; DWORD RetryCount; DWORD RetryTime; PREGISTER_HOST_STATUS pRegisterStatus; DWORD SignatureBottom; } UPDATE_ENTRY, *PUPDATE_ENTRY;
//
// globals
//
//
// the behavior of the system at boot differs from when it is not at
// boot. At boot time we collect a bunch of requests and register them
// in one shot. One thread does this. After boot, we register them
// as requests come in, one at a time.
//
BOOL g_fAtBoot = TRUE; BOOL g_fPurgeRegistrations = FALSE; BOOL g_fPurgeRegistrationsInitiated = FALSE; BOOL g_fRegistrationThreadRunning = FALSE; BOOL g_fNoMoreDDNSUpdates = FALSE; BOOL g_fShutdown = FALSE; DWORD g_dwTime = 0; // To determine boot time or not
//
// The following global is used to eliminate multiple calls to GetVersion()
//
DWORD g_dwVersion = DHCPVER_UNINIT; // is 1 for winnt and 2 for win95
LIST_ENTRY g_RegistrationList;
HANDLE g_hStopEvent = NULL; HANDLE g_hThreadDeadEvent = NULL; HANDLE g_hNewItemEvent = NULL;
HANDLE g_hRegistrationThread = NULL;
BOOL g_fQuit = FALSE; HKEY g_hKey = NULL; DWORD g_dwBootTime = 60;
//
// Private heap
//
#define INITIAL_DDNS_HEAP (16*1024)
HANDLE g_DDNSHeap;
#define PHEAP_ALLOC_ZERO( s ) HeapAlloc( g_DDNSHeap, HEAP_ZERO_MEMORY, (s) )
#define PHEAP_ALLOC( s ) HeapAlloc( g_DDNSHeap, HEAP_ZERO_MEMORY, (s) )
#define PHEAP_FREE( p ) HeapFree( g_DDNSHeap, 0, (p) )
//
// Private protos
//
DNS_STATUS AllocateUpdateEntry( IN PSTR AdapterName, IN PSTR HostName, IN PSTR DomainName, IN PSTR PrimaryDomainName, IN PSTR AlternateNames, IN DWORD HostAddrCount, IN PREGISTER_HOST_ENTRY HostAddrs, IN DWORD DnsServerCount, IN PIP_ADDRESS DnsServerList, IN IP_ADDRESS SentUpdateToIp, IN IP_ADDRESS SentPriUpdateToIp, IN DWORD TTL, IN DWORD Flags, IN DWORD RetryCount, IN DWORD RetryTime, IN PREGISTER_HOST_STATUS RegisterStatus, OUT PUPDATE_ENTRY * ppUpdateEntry );
VOID FreeUpdateEntry( IN OUT PUPDATE_ENTRY pUpdateEntry );
VOID FreeUpdateEntryList( IN PLIST_ENTRY pUpdateEntry );
DWORD WINAPI RegistrationThread( VOID );
VOID WriteUpdateEntryToRegistry( IN PUPDATE_ENTRY pUpdateEntry );
PUPDATE_ENTRY ReadUpdateEntryFromRegistry( IN PSTR pszAdapterName );
VOID MarkAdapterAsPendingUpdate( IN PSTR pAdapterName );
DWORD GetNextUpdateEntryFromList( OUT PUPDATE_ENTRY * ppUpdateEntry, OUT PDWORD pdwWaitTime );
VOID ProcessUpdateEntry( IN OUT PUPDATE_ENTRY pUpdateEntry, IN BOOL fPurgeMode );
DNS_STATUS ModifyAdapterRegistration( IN OUT PUPDATE_ENTRY pUpdateEntry, IN OUT PUPDATE_ENTRY pRegistryEntry, IN PDNS_RECORD pUpdateRecord, IN PDNS_RECORD pRegRecord, IN BOOL fPrimaryDomain );
VOID ResetAdaptersInRegistry( VOID );
VOID
DeregisterUnusedAdapterInRegistry( IN BOOL fPurgeMode );
PDNS_RECORD GetPreviousRegistrationInformation( IN PUPDATE_ENTRY pUpdateEntry, IN BOOL fPrimaryDomain, OUT PIP_ADDRESS pServerIp );
PDNS_RECORD CreateDnsRecordSetUnion( IN PDNS_RECORD pSet1, IN PDNS_RECORD pSet2 );
#if 1 // DBG
VOID LogHostEntries( IN DWORD dwHostAddrCount, IN PREGISTER_HOST_ENTRY pHostAddrs ); #define DNSLOG_HOST_ENTRYS( a, b ) LogHostEntries( a, b )
#else
#define DNSLOG_HOST_ENTRYS( a, b )
#endif
#if 1 // DBG
VOID LogPipAddress( IN DWORD dwServerListCount, IN PIP_ADDRESS pServers ); #define DNSLOG_PIP_ADDRESS( a, b ) LogPipAddress( a, b )
#else
#define DNSLOG_PIP_ADDRESS( a, b )
#endif
#if 1 // DBG
VOID LogPipArray( IN PIP_ARRAY pServers ); #define DNSLOG_PIP_ARRAY( a ) LogPipArray( a )
#else
#define DNSLOG_PIP_ARRAY( a )
#endif
DNS_STATUS alertOrStartRegistrationThread( VOID );
VOID registerUpdateStatus( IN OUT PREGISTER_HOST_STATUS pRegStatus, IN DNS_STATUS Status );
VOID enqueueUpdate( IN OUT PUPDATE_ENTRY pUpdate );
VOID enqueueUpdateMaybe( IN OUT PUPDATE_ENTRY pUpdate );
PLIST_ENTRY dequeueAndCleanupUpdate( IN OUT PLIST_ENTRY pUpdateEntry );
BOOL searchForOldUpdateEntriesAndCleanUp( IN PSTR pszAdapterName, IN PUPDATE_ENTRY pUpdateEntry OPTIONAL, IN BOOL fLookInRegistry );
BOOL compareUpdateEntries( IN PUPDATE_ENTRY pUdapteEntry1, IN PUPDATE_ENTRY pUpdateEntry2 );
BOOL compareHostEntryAddrs( IN PREGISTER_HOST_ENTRY Addrs1, IN PREGISTER_HOST_ENTRY Addrs2, IN DWORD Count );
BOOL compareServerLists( IN PIP_ARRAY List1, IN PIP_ARRAY List2 );
DWORD GetRegistryValue( HKEY KeyHandle, PSTR ValueName, DWORD ValueType, LPBYTE BufferPtr );
//
// Jim routines
//
VOID LogRegistration( IN PUPDATE_ENTRY pUpdateEntry, IN DNS_STATUS Status, IN DWORD UpType, IN BOOL fDeregister, IN IP4_ADDRESS DnsIp, IN IP4_ADDRESS UpdateIp );
VOID AsyncLogUpdateEntry( IN PSTR pszHeader, IN PUPDATE_ENTRY pEntry );
#define ASYNCREG_UPDATE_ENTRY(h,p) AsyncLogUpdateEntry(h,p)
VOID DnsPrint_UpdateEntry( IN PRINT_ROUTINE PrintRoutine, IN PPRINT_CONTEXT PrintContext, IN PSTR pszHeader, IN PUPDATE_ENTRY pUpdateEntry );
#if DBG
#define DnsDbg_UpdateEntry(h,p) DnsPrint_UpdateEntry(DnsPR,NULL,h,p)
#else
#define DnsDbg_UpdateEntry(h,p)
#endif
PDNS_RECORD CreateForwardRecords( IN PUPDATE_ENTRY pUpdateEntry, IN BOOL fUsePrimaryName );
PDNS_RECORD CreatePtrRecord( IN PSTR pszHostName, IN PSTR pszDomainName, IN IP4_ADDRESS Ip4Addr, IN DWORD Ttl );
VOID UpdatePtrRecords( IN OUT PUPDATE_ENTRY pUpdateEntry, IN BOOL fAdd );
VOID SetUpdateStatus( IN OUT PUPDATE_ENTRY pUpdateEntry, IN DNS_STATUS Status, IN BOOL fPrimary );
//
// Public functions
//
DNS_STATUS WINAPI DnsAsyncRegisterInit( IN PSTR pszRootRegKey ) /*++
Routine Description:
Initialize asynchronous DNS registration.
Process must call (one time) before calling DnsAsyncRegisterHostAddrs.
Arguments:
None.
Return Value:
DNS or Win32 error code.
--*/ { DWORD Status = ERROR_SUCCESS; DWORD disposition; DWORD disallowUpdate;
//
// Initialize debug logging funtion
//
ASYNCREG_INIT();
ASYNCREG_F1( "Inside function DnsAsyncRegisterInit" ); ASYNCREG_TIME(); ASYNCREG_F2( " pszRootRegKey value set to %s", pszRootRegKey );
//
// g_dwVersion is only set once and this function must be called exactly
// once until the corresponding TERM is called.
//
if ( ASYNC_INIT_CALLED() ) { //
// we are calling this more than once!
//
DNS_ASSERT(FALSE) ; return ERROR_INTERNAL_ERROR ; } else { DWORD sysVersion;
if ( g_fRegistrationThreadRunning ) { //
// we encountered a previous problem while trying to stop
// the registration thread, do not allow any further update
// operations for this process!
//
DNS_ASSERT(FALSE) ; return ERROR_INTERNAL_ERROR ; }
sysVersion = GetVersion();
if ( sysVersion < 0x80000000 ) { g_dwVersion = DHCPVER_WINNT; } else { g_dwVersion = DHCPVER_WIN95; } }
//
// if not supplied, use default
//
if ( !pszRootRegKey ) { if ( g_dwVersion == DHCPVER_WINNT ) { pszRootRegKey = DEFAULT_REG_LOCATION ; } else if ( g_dwVersion == DHCPVER_WIN95 ) { pszRootRegKey = DEFAULT_REG_LOCATION_WIN95 ; } else { // we did not set g_dwVersion
DNS_ASSERT(FALSE) ; pszRootRegKey = DEFAULT_REG_LOCATION ; } }
//
// Create private heap
//
g_DDNSHeap = HeapCreate( 0, INITIAL_DDNS_HEAP, 0 ); if ( g_DDNSHeap == NULL ) { g_DDNSHeap = GetProcessHeap(); if ( g_DDNSHeap == NULL ) { ASYNCREG_F1( "ERROR: DnsAsyncRegisterInit function failed to create heap" ); Status = DNS_ERROR_NO_MEMORY; goto ErrorExit; } }
//
// get registration configuration info
// - just insure we have the latest copy
//
// DCR_FIX: when available get latest copy from resolver
// does not need to be done on init, may be done on call
//
Reg_ReadGlobalsEx( 0, NULL );
//
// Open the registry location used to store this info
//
// Note that Win95 does not support WideCharacter types
// The result is that we are forced to use RegCreateKeyExA for
// both
//
Status = RegCreateKeyExA( HKEY_LOCAL_MACHINE, pszRootRegKey, 0, // reserved
DYN_DNS_ROOT_CLASS, REG_OPTION_NON_VOLATILE, // options
KEY_READ | KEY_WRITE, // desired access
NULL, &g_hKey, &disposition );
if ( Status != NO_ERROR ) { goto ErrorExit; }
if ( !( g_hStopEvent = CreateEvent( NULL, TRUE, FALSE, NULL ) ) ) { Status = GetLastError(); goto ErrorExit; }
if ( !( g_hThreadDeadEvent = CreateEvent( NULL, TRUE, FALSE, NULL ) ) ) { Status = GetLastError(); goto ErrorExit; }
if ( !( g_hNewItemEvent = CreateEvent( NULL, TRUE, FALSE, NULL ) ) ) { Status = GetLastError(); goto ErrorExit; }
EnterCriticalSection( &g_RegistrationListCS ); InitializeListHead( &g_RegistrationList ); LeaveCriticalSection( &g_RegistrationListCS );
//
// the following call is needed for determining if we are still in
// boot time or not
//
g_dwTime = Dns_GetCurrentTimeInSeconds(); g_fQuit = FALSE; g_fAtBoot = TRUE; g_fPurgeRegistrations = FALSE; g_fPurgeRegistrationsInitiated = FALSE; g_fNoMoreDDNSUpdates = FALSE;
ResetAdaptersInRegistry();
return NO_ERROR;
ErrorExit:
if ( g_DDNSHeap && g_DDNSHeap != GetProcessHeap() ) { HeapDestroy( g_DDNSHeap ); g_DDNSHeap = NULL; }
if ( g_hStopEvent ) { CloseHandle(g_hStopEvent); g_hStopEvent = NULL; }
if ( g_hThreadDeadEvent ) { CloseHandle(g_hThreadDeadEvent); g_hThreadDeadEvent = NULL; }
if ( g_hNewItemEvent ) { CloseHandle(g_hNewItemEvent); g_hNewItemEvent = NULL; }
if ( g_hKey ) { RegCloseKey( g_hKey ); g_hKey = NULL; }
CLEAR_ASYNC_INIT(); // reset this so we are no longer in use
return(Status); }
DNS_STATUS WINAPI DnsAsyncRegisterTerm( VOID ) /*++
Routine Description:
Stop DNS registration. Shutdown DNS registration thread.
Initialization routine each process should call exactly on exit after using DnsAsyncRegisterHostAddrs. This will signal to us that if our thread is still trying to talk to a server, we'll stop trying.
Arguments:
None.
Return Value:
DNS or Win32 error code.
--*/ { DWORD waitResult;
ASYNCREG_F1( "Inside function DnsAsyncRegisterTerm" ); ASYNCREG_TIME(); ASYNCREG_F1( "" );
if ( ASYNC_INIT_CALLED() ) { if ( g_hStopEvent && g_fRegistrationThreadRunning ) { SetEvent(g_hStopEvent);
waitResult = WaitForSingleObject( g_hThreadDeadEvent, INFINITE );
switch ( waitResult ) { case WAIT_OBJECT_0 : ASYNCREG_F1( "DNSAPI.DLL: Registration thread signaled it was finished" ); ASYNCREG_F1( "" );
break;
case WAIT_TIMEOUT : ASYNCREG_F1( "DNSAPI.DLL: Registration thread won't stop! " ); ASYNCREG_F1( "" ); DNS_ASSERT( FALSE );
break; }
if ( g_fRegistrationThreadRunning ) { ASYNCREG_F1( "DNSAPI.DLL: Registration thread wasn't stopped! " ); ASYNCREG_F1( "" );
DNS_ASSERT(FALSE) ;
CLEAR_ASYNC_INIT(); // reset this so we are no longer in use
return ERROR_INTERNAL_ERROR ; } }
EnterCriticalSection( &g_RegistrationThreadCS );
//
// Close the thread handles if they aren't already.
//
if ( g_hRegistrationThread ) { CloseHandle( g_hRegistrationThread ); g_hRegistrationThread = NULL; }
if ( g_hStopEvent ) { CloseHandle(g_hStopEvent); g_hStopEvent = NULL; }
if ( g_hThreadDeadEvent ) { CloseHandle(g_hThreadDeadEvent); g_hThreadDeadEvent = NULL; }
if ( g_hNewItemEvent ) { CloseHandle(g_hNewItemEvent); g_hNewItemEvent = NULL; }
g_fQuit = TRUE;
if ( g_hKey ) { RegCloseKey(g_hKey); g_hKey = NULL; }
LeaveCriticalSection( &g_RegistrationThreadCS );
Dns_TimeoutSecurityContextList( TRUE );
CLEAR_ASYNC_INIT(); // reset this so we are no longer in use
if ( g_DDNSHeap && g_DDNSHeap != GetProcessHeap() ) { HeapDestroy( g_DDNSHeap ); g_DDNSHeap = NULL; }
return NO_ERROR; } else { //
// This is being called more than once! Or the Init function has
// not yet been called!
//
DNS_ASSERT(FALSE) ; return ERROR_INTERNAL_ERROR ; } }
DNS_STATUS WINAPI DnsRemoveRegistrations( VOID ) /*++
Routine Description:
Remove DNS host registrations for this machine.
This will be called by DHCP client on domain unjoin. Removes DNS registrations for the box, then terminates the registration thread to disable further registrations.
Registrations can only be reenabled by calling DnsAsyncRegisterInit() again.
Arguments:
None.
Return Value:
ERROR_SUCCESS if successful. ErrorCode on failure.
--*/ { PLIST_ENTRY pListEntry; PLIST_ENTRY pTopOfList;
ASYNCREG_F1( "Inside function DnsRemoveRegistrations" ); ASYNCREG_TIME(); DNSDBG( TRACE, ( "DnsRemoveRegistrations()\n" ));
DNS_ASSERT(ASYNC_INIT_CALLED()); // make sure init was called
if ( !ASYNC_INIT_CALLED() ) { ASYNCREG_F1( "DnsAsyncRemoveRegistrations returning ERROR_SERVICE_NOT_ACTIVE" ); ASYNCREG_F1( "This is an error in DHCP client code, it forgot to call DnsAsyncRegisterInit()" ); return ERROR_SERVICE_NOT_ACTIVE; }
//
// Set a global flag to disable any further adapter registration calls
//
g_fNoMoreDDNSUpdates = TRUE;
//
// Get the Registration list lock
//
EnterCriticalSection( &g_RegistrationListCS );
//
// Mark any and all adapter registration information in the registry
// as non-registered. These will be later interpreted as non-existant
// and deregistered by the RegistrationThread.
//
ResetAdaptersInRegistry();
//
// Walk the list of pending update entries and clear out the
// non-neccessary updates.
//
pTopOfList = &g_RegistrationList; pListEntry = pTopOfList->Flink;
while ( pListEntry != pTopOfList ) { if ( ((PUPDATE_ENTRY) pListEntry)->SignatureTop != DNS_SIG_TOP || ((PUPDATE_ENTRY) pListEntry)->SignatureBottom != DNS_SIG_BOTTOM ) { //
// Someone trashed our registration list!
//
DNS_ASSERT( FALSE );
//
// We'll reset it and try to move on . . .
//
InitializeListHead( &g_RegistrationList ); pTopOfList = &g_RegistrationList; pListEntry = pTopOfList->Flink; continue; }
if ( !((PUPDATE_ENTRY) pListEntry)->fRemove ) { //
// There is an update entry in the registration list
// that has not yet been processed. Since it is an
// add update, we'll blow it away.
//
pListEntry = dequeueAndCleanupUpdate( pListEntry ); continue; } else { ((PUPDATE_ENTRY) pListEntry)->fNewElement = TRUE; ((PUPDATE_ENTRY) pListEntry)->fRegisteredFWD = FALSE; ((PUPDATE_ENTRY) pListEntry)->fRegisteredPRI = FALSE; ((PUPDATE_ENTRY) pListEntry)->fRegisteredPTR = FALSE; ((PUPDATE_ENTRY) pListEntry)->fDisableErrorLogging = FALSE; ((PUPDATE_ENTRY) pListEntry)->RetryCount = 2; ((PUPDATE_ENTRY) pListEntry)->RetryTime = Dns_GetCurrentTimeInSeconds();
pListEntry = pListEntry->Flink; } }
LeaveCriticalSection( &g_RegistrationListCS );
g_fPurgeRegistrations = TRUE;
//
// start async registration thread if not started
//
alertOrStartRegistrationThread();
//
// wait for async registration thread to terminate
//
// however we'll bag it after a few minutes -- a robustness check
// to avoid long hang; Generally the machine will be rebooted
// so failure to cleanup the list and terminate is not critical;
// Registrations will have to be cleaned up by admin action or
// aging on the DNS server
//
#if DBG
{ DWORD waitResult; waitResult = WaitForSingleObject( g_hThreadDeadEvent, REMOVE_REGISTRATION_WAIT_LIMIT ); if ( waitResult != WAIT_OBJECT_0 ) { ASYNCREG_F1( "ERROR: RemoveRegistration() wait expired before async thread\n" "\ttermination!\n" ); } } #else
WaitForSingleObject( g_hThreadDeadEvent, REMOVE_REGISTRATION_WAIT_LIMIT ); #endif
return NO_ERROR; }
DNS_STATUS WINAPI privateAsyncRegisterHostAddrs( IN PSTR pszAdapterName, IN PSTR pszHostName, IN PREGISTER_HOST_ENTRY pHostAddrs, IN DWORD dwHostAddrCount, IN PIP4_ADDRESS pipDnsServerList, IN DWORD dwDnsServerCount, IN PSTR pszDomainName, IN PREGISTER_HOST_STATUS pRegisterStatus, IN DWORD dwTTL, IN DWORD dwFlags ) /*++
Routine Description:
Registers host address with DNS server. This is called by DHCP client to register a particular IP.
This is the working UTF8 version of the DnsAsyncRegisterHostAddrs() unicode routine actually called by the DHCP client.
Arguments:
Return Value:
ERROR_SUCCESS if successful. Error code on failure.
--*/ { DWORD status = NO_ERROR; PUPDATE_ENTRY pupEntry = NULL; PSTR padapterDN = NULL; PSTR pprimaryDN = NULL; REG_UPDATE_INFO updateInfo; BOOL fcleanupUpdateInfo = FALSE;
ASYNCREG_F1( "Inside function privateDnsAsyncRegisterHostAddrs, parameters are:" ); ASYNCREG_F2( " pszAdapterName : %s", pszAdapterName ); ASYNCREG_F2( " pszHostName : %s", pszHostName ); ASYNCREG_F2( " dwHostAddrCount : %d", dwHostAddrCount ); DNSLOG_HOST_ENTRYS( dwHostAddrCount, pHostAddrs ); ASYNCREG_F2( " dwDnsServerCount : %d", dwDnsServerCount ); if ( dwDnsServerCount && pipDnsServerList ) { DNSLOG_PIP_ADDRESS( dwDnsServerCount, pipDnsServerList ); } ASYNCREG_F2( " pszDomainName : %s", pszDomainName ); ASYNCREG_F2( " dwTTL : %d", dwTTL ); ASYNCREG_F2( " dwFlags : %d", dwFlags ); ASYNCREG_F1( "" ); ASYNCREG_TIME();
DNSDBG( TRACE, ( "privateAsyncRegisterHostAddrs()\n" "\tadapter name = %s\n" "\thost name = %s\n" "\tadapter domain = %s\n" "\tpHostAddrs = %p\n" "\tAddrCount = %d\n" "\tpDNSServers = %p\n" "\tServerCount = %d\n" "\tFlags = %08x\n", pszAdapterName, pszHostName, pszDomainName, pHostAddrs, dwHostAddrCount, pipDnsServerList, dwDnsServerCount, dwTTL ));
//
// first things first, need to inform underlying code that something
// has changed in the list of net adapters. Glenn is going to be called
// now so that he can re read the registry (or do any appropriate query)
// to now note the changed state.
//
if ( !(dwFlags & DYNDNS_DEL_ENTRY) ) { DnsNotifyResolver( 0, NULL ); }
DNS_ASSERT(ASYNC_INIT_CALLED()); // make sure init was called
if ( !ASYNC_INIT_CALLED() ) { DNSDBG( ANY, ( "ERROR: AsyncRegisterHostAddrs called before Init routine!!!\n" )); status = ERROR_SERVICE_NOT_ACTIVE; goto Exit; }
if ( g_fNoMoreDDNSUpdates ) { DNSDBG( ANY, ( "ERROR: AsyncRegisterHostAddrs called after RemoveRegistrations()!!!\n" )); status = ERROR_SERVICE_NOT_ACTIVE; goto Exit; }
//
// Validate parameters
//
if ( !pszAdapterName || !(*pszAdapterName) ) { DNSDBG( ANY, ( "ERROR: RegisterHostAddrs invalid adaptername!\n" )); status = ERROR_INVALID_PARAMETER; goto Exit; } if ( ( !pszHostName || !(*pszHostName) ) && !( dwFlags & DYNDNS_DEL_ENTRY ) ) { DNSDBG( ANY, ( "ERROR: RegisterHostAddrs invalid hostname!\n" )); status = ERROR_INVALID_PARAMETER; goto Exit; } if ( dwHostAddrCount && !pHostAddrs ) { DNSDBG( ANY, ( "ERROR: RegisterHostAddrs invalid host addresses!\n" )); status = ERROR_INVALID_PARAMETER; goto Exit; }
//
// get adapter update configuration
//
status = Reg_ReadUpdateInfo( pszAdapterName, & updateInfo ); if ( status != ERROR_SUCCESS ) { DNSDBG( INIT, ( "Update registry read failure %d\n", status )); goto Exit; } fcleanupUpdateInfo = TRUE;
//
// skip WAN, if not doing WAN by policy
//
if ( (dwFlags & DYNDNS_REG_RAS) && !g_RegisterWanAdapters ) { ASYNCREG_F1( "privateAsyncRegisterHostAddrs returning NO_ERROR, because WAN adapter registrations are disabled" ); goto NoActionExit; }
//
// policy DNS servers, override passed in list
//
if ( updateInfo.pDnsServerArray ) { pipDnsServerList = updateInfo.pDnsServerArray->AddrArray; dwDnsServerCount = updateInfo.pDnsServerArray->AddrCount; }
//
// must have DNS servers to update adapter
// - don't update IP on one interface starting with DNS servers
// from another
//
if ( dwDnsServerCount && !pipDnsServerList ) { ASYNCREG_F1( "privateAsyncRegisterHostAddrs returning ERROR_INVALID_PARAMETER" ); ASYNCREG_F1( "ERROR_INVALID_PARAMETER reason 4" ); status = ERROR_INVALID_PARAMETER; goto Exit; } if ( ! dwDnsServerCount && ! (dwFlags & DYNDNS_DEL_ENTRY) ) { ASYNCREG_F1( "privateAsyncRegisterHostAddrs returning NO_ERROR, because adapter does not have any DNS servers configured" ); status = ERROR_INVALID_PARAMETER; goto Exit; }
//
// no update on adpater => delete outstanding updates
// note, we do before delete check below for event check
//
if ( !updateInfo.fRegistrationEnabled ) { ASYNCREG_F1( "privateAsyncRegisterHostAddrs returning NO_ERROR, because adapter is disabled" );
if ( pRegisterStatus ) { pRegisterStatus->dwStatus = NO_ERROR; SetEvent( pRegisterStatus->hDoneEvent ); } if ( searchForOldUpdateEntriesAndCleanUp( pszAdapterName, NULL, TRUE ) ) { goto CheckThread; } status = NO_ERROR; goto Exit; //goto NoActionExit;
}
//
// delete update -- cleanup and delete
// - delete outstanding update in list
// - cleanup registry
// - do delete
//
if ( dwFlags & DYNDNS_DEL_ENTRY ) { if ( searchForOldUpdateEntriesAndCleanUp( pszAdapterName, NULL, TRUE ) ) { goto CheckThread; } }
//
// limit IP registration count
// if doing registration and no addresses -- bail
//
if ( updateInfo.RegistrationMaxAddressCount < dwHostAddrCount ) { dwHostAddrCount = updateInfo.RegistrationMaxAddressCount; ASYNCREG_F2( "Restricting adapter registration to the first %d addresses", dwHostAddrCount ); } if ( dwHostAddrCount == 0 ) { ASYNCREG_F1( "privateAsyncRegisterHostAddrs returning NO_ERROR" ); ASYNCREG_F1( "We are done, there are no addresses to register in DNS" ); goto NoActionExit; }
//
// no\empty host name or zero IP => bogus
//
if ( !pszHostName || !(*pszHostName) || ( dwHostAddrCount && ( pHostAddrs[0].Addr.ipAddr == 0 ) ) ) { ASYNCREG_F1( "privateAsyncRegisterHostAddrs returning ERROR_INVALID_PARAMETER" ); ASYNCREG_F1( "ERROR_INVALID_PARAMETER reason 5" ); status = ERROR_INVALID_PARAMETER; goto Exit; }
//
// determine domain names to update
// - get PDN
// - adapter name
// - none if adapter name registration off
// - else check policy override
// - else name passed in
// - but treat empty as NULL
//
pprimaryDN = updateInfo.pszPrimaryDomainName;
if ( updateInfo.fRegisterAdapterName ) { if ( updateInfo.pszAdapterDomainName ) { padapterDN = updateInfo.pszAdapterDomainName; } else { padapterDN = pszDomainName; } if ( padapterDN && !(*padapterDN) ) { padapterDN = NULL; } }
//
// no domains => nothing to register, we're done
//
if ( !padapterDN && !pprimaryDN ) { ASYNCREG_F1( "privateAsyncRegisterHostAddrs returning ERROR_SUCCESS" ); ASYNCREG_F1( "no adapter name and no PDN" ); goto NoActionExit; }
// if adapter name same as PDN -- just one update
if ( pprimaryDN && padapterDN && Dns_NameCompare_UTF8( pprimaryDN, padapterDN ) ) { padapterDN = NULL; }
// build update
status = AllocateUpdateEntry( pszAdapterName, pszHostName, padapterDN, pprimaryDN, updateInfo.pmszAlternateNames, dwHostAddrCount, pHostAddrs, dwDnsServerCount, pipDnsServerList, 0, // No particular server IP at this time
0, // No particular server IP at this time
(dwTTL == 0xffffffff || dwTTL == 0) ? g_RegistrationTtl : dwTTL, dwFlags, 0, Dns_GetCurrentTimeInSeconds(), pRegisterStatus, &pupEntry );
if ( status != NO_ERROR ) { goto Exit; }
//
// More WAN adapter hacks . . .
// If DDNS is not disabled for WAN adapters, then the default
// behavior for logging update events is disabled on these type
// adapters. There is a registry key that can turn on the logging
// of WAN adapter updates if such a user is interested. We configure
// those settings here.
//
if ( dwFlags & DYNDNS_REG_RAS ) { //pupEntry->fDisableErrorLogging = !g_EnableWanDynamicUpdateEventLog;
pupEntry->fDisableErrorLogging = TRUE; }
//
// When adding an entry to the registration list, first walk the
// list to look for any other updates for the same adapter.
// If there is already an add update in the list, blow it away.
// If there is already a delete update in the list with the same
// information, blow it away.
//
// Then put update into registration list.
//
searchForOldUpdateEntriesAndCleanUp( pupEntry->AdapterName, pupEntry, FALSE );
//
// Since we are about to queue up an update entry for a given
// adapter, we need to mark any possible previous registration
// information that could be in the registry as pending. This
// marking will prevent the old data from being incorrectly
// queued as a disabled adapter if any errors are encountered
// on the update attempts. i.e failed update attempts on a given
// adapter should not be regarded as a disabled adapter that needs
// to have it's stale records cleaned up.
//
MarkAdapterAsPendingUpdate( pszAdapterName );
EnterCriticalSection( &g_RegistrationListCS ); InsertTailList( &g_RegistrationList, (PLIST_ENTRY) pupEntry ); LeaveCriticalSection( &g_RegistrationListCS );
CheckThread:
//
// DCR: do we need cleanup if thread is dead?
//
alertOrStartRegistrationThread(); status = NO_ERROR; goto Exit;
NoActionExit:
//
// exit for no-action no-error exit
//
DNSDBG( UPDATE, ( "privateAsyncRegisterHostAddrs()\n" "\tno-update no-error exit\n" ));
status = NO_ERROR;
if ( pRegisterStatus ) { pRegisterStatus->dwStatus = NO_ERROR; SetEvent( pRegisterStatus->hDoneEvent ); }
Exit:
//
// cleanup allocated update info
//
if ( fcleanupUpdateInfo ) { Reg_FreeUpdateInfo( &updateInfo, FALSE // no free struct, it's on stack
); }
DNSDBG( UPDATE, ( "Leaving privateAsyncRegisterHostAddrs()\n" "\tstatus = %d\n", status ));
return( status ); }
DNS_STATUS WINAPI DnsAsyncRegisterHostAddrs( IN PWSTR pwsAdapterName, IN PWSTR pwsHostName, IN PREGISTER_HOST_ENTRY pHostAddrs, IN DWORD dwHostAddrCount, IN PIP_ADDRESS pipDnsServerList, IN DWORD dwDnsServerCount, IN PWSTR pwsDomainName, IN PREGISTER_HOST_STATUS pRegisterStatus, IN DWORD dwTTL, IN DWORD dwFlags ) /*++
Routine Description:
Registers host address with DNS server.
This is called by DHCP client to register a particular IP.
Arguments:
Return Value:
ERROR_SUCCESS if successful. Error code on failure.
--*/ { CHAR adapterName[2*MAX_PATH]; CHAR hostName[ DNS_MAX_LABEL_BUFFER_LENGTH ]; CHAR domainName[ DNS_MAX_NAME_BUFFER_LENGTH ]; PSTR padapterName = NULL; PSTR phostName = NULL; PSTR pdomainName = NULL;
DNSDBG( TRACE, ( "DnsAsyncRegisterHostAddrs()\n" "\tadapter name = %S\n" "\thost name = %S\n" "\tadapter domain = %S\n" "\tpHostAddrs = %p\n", pwsAdapterName, pwsHostName, pwsDomainName, pHostAddrs )); //
// convert unicode strings to UTF8
//
if ( pwsAdapterName ) { Dns_NameCopy( adapterName, NULL, (PCHAR) pwsAdapterName, 0, DnsCharSetUnicode, DnsCharSetUtf8 );
padapterName = adapterName; }
if ( pwsHostName ) { Dns_NameCopy( hostName, NULL, (PCHAR) pwsHostName, 0, DnsCharSetUnicode, DnsCharSetUtf8 );
phostName = hostName; }
if ( pwsDomainName ) { Dns_NameCopy( domainName, NULL, (PCHAR) pwsDomainName, 0, DnsCharSetUnicode, DnsCharSetUtf8 );
pdomainName = domainName; }
return privateAsyncRegisterHostAddrs( padapterName, phostName, pHostAddrs, dwHostAddrCount, pipDnsServerList, dwDnsServerCount, pdomainName, pRegisterStatus, dwTTL, dwFlags ); }
//
// Async registration utilities
//
PSTR CreateNarrowStringCopy( IN PSTR pString ) { PSTR pnew = NULL;
if ( pString ) { pnew = HeapAlloc( g_DDNSHeap, 0, strlen(pString) + 1 ); if ( pnew ) { strcpy( pnew, pString ); } }
return pnew; }
VOID PrivateHeapFree( IN PVOID pVal ) { if ( pVal ) { HeapFree( g_DDNSHeap, 0, pVal ); } }
DNS_STATUS AllocateUpdateEntry( IN PSTR AdapterName, IN PSTR HostName, IN PSTR DomainName, IN PSTR PrimaryDomainName, IN PSTR AlternateNames, IN DWORD HostAddrCount, IN PREGISTER_HOST_ENTRY HostAddrs, IN DWORD DnsServerCount, IN PIP_ADDRESS DnsServerList, IN IP_ADDRESS SentUpdateToIp, IN IP_ADDRESS SentPriUpdateToIp, IN DWORD TTL, IN DWORD Flags, IN DWORD RetryCount, IN DWORD RetryTime, IN PREGISTER_HOST_STATUS Registerstatus, OUT PUPDATE_ENTRY * ppUpdateEntry ) /*++
Routine Description:
Create update info blob.
Arguments:
Return Value:
ERROR_SUCCESS if successful. Error code on failure.
--*/ { PUPDATE_ENTRY pupEntry = NULL; DWORD status = ERROR_SUCCESS; PSTR ptempDomain = DomainName; PSTR ptempPrimaryDomain = PrimaryDomainName;
if ( ptempDomain && !(*ptempDomain) ) { ptempDomain = NULL; } if ( ptempPrimaryDomain && !(*ptempPrimaryDomain) ) { ptempPrimaryDomain = NULL; } if ( AdapterName && !(*AdapterName) ) { AdapterName = NULL; } if ( HostName && !(*HostName) ) { HostName = NULL; }
DNSDBG( TRACE, ( "AllocateUpdateEntry()\n" )); DNSDBG( DHCP, ( "AllocateUpdateEntry()\n" "\tAdapterName = %s\n" "\tHostName = %s\n" "\tPrimaryDomain = %s\n" "\tAdapterDomain = %s\n" "\tAlternateNames = %s\n" "\tHostAddrCount = %d\n" "\tpHostAddrs = %p\n" "\tTTL = %d\n" "\tFlags = %08x\n" "\tHostAddrCount = %d\n" "\tTime = %d\n", AdapterName, HostName, PrimaryDomainName, DomainName, AlternateNames, HostAddrCount, HostAddrs, TTL, Flags, RetryTime ));
if ( !AdapterName || !HostName || !HostAddrCount ) { ASYNCREG_F1( "AllocateUpdateEntry returing error : ERROR_INVALID_PARAMETER" ); ASYNCREG_F1( "" ); status = ERROR_INVALID_PARAMETER; goto Exit; }
pupEntry = PHEAP_ALLOC_ZERO( sizeof(UPDATE_ENTRY) ); if ( !pupEntry ) { status = DNS_ERROR_NO_MEMORY; goto Exit; }
InitializeListHead( &(pupEntry->List) );
pupEntry->SignatureTop = DNS_SIG_TOP; pupEntry->SignatureBottom = DNS_SIG_BOTTOM;
//
// copy strings
//
pupEntry->AdapterName = CreateNarrowStringCopy( AdapterName ); if ( !pupEntry->AdapterName ) { status = DNS_ERROR_NO_MEMORY; goto Exit; } if ( HostName ) { pupEntry->HostName = CreateNarrowStringCopy( HostName ); if ( !pupEntry->HostName ) { status = DNS_ERROR_NO_MEMORY; goto Exit; } } if ( ptempDomain ) { pupEntry->DomainName = CreateNarrowStringCopy( ptempDomain ); if ( !pupEntry->DomainName ) { status = DNS_ERROR_NO_MEMORY; goto Exit; } } if ( ptempPrimaryDomain ) { pupEntry->PrimaryDomainName = CreateNarrowStringCopy( ptempPrimaryDomain ); if ( !pupEntry->PrimaryDomainName ) { status = DNS_ERROR_NO_MEMORY; goto Exit; } } if ( AlternateNames ) { pupEntry->AlternateNames = MultiSz_Copy_A( AlternateNames ); if ( !pupEntry->AlternateNames ) { status = DNS_ERROR_NO_MEMORY; goto Exit; } }
if ( HostAddrCount ) { pupEntry->HostAddrs = PHEAP_ALLOC( sizeof(REGISTER_HOST_ENTRY) * HostAddrCount );
if ( !pupEntry->HostAddrs ) { status = DNS_ERROR_NO_MEMORY; goto Exit; } memcpy( pupEntry->HostAddrs, HostAddrs, sizeof(REGISTER_HOST_ENTRY) * HostAddrCount ); } pupEntry->HostAddrCount = HostAddrCount;
if ( DnsServerCount ) { pupEntry->DnsServerList = Dns_BuildIpArray( DnsServerCount, DnsServerList ); if ( !pupEntry->DnsServerList ) { status = DNS_ERROR_NO_MEMORY; goto Exit; } }
pupEntry->SentUpdateToIp = SentUpdateToIp; pupEntry->SentPriUpdateToIp = SentPriUpdateToIp; pupEntry->pRegisterStatus = Registerstatus; pupEntry->TTL = TTL; pupEntry->Flags = Flags; pupEntry->fRemove = Flags & DYNDNS_DEL_ENTRY ? TRUE : FALSE; pupEntry->fNewElement = TRUE; pupEntry->RetryCount = RetryCount; pupEntry->RetryTime = RetryTime;
Exit:
if ( status!=ERROR_SUCCESS && pupEntry ) { FreeUpdateEntry( pupEntry ); pupEntry = NULL; }
*ppUpdateEntry = pupEntry;
return (status); }
VOID FreeUpdateEntry( IN OUT PUPDATE_ENTRY pUpdateEntry ) /*++
Routine Description:
Free update blob entry.
Arguments:
pUpdateEntry -- update entry blob to free
Return Value:
None
--*/ { DNSDBG( TRACE, ( "FreeUpdateEntry( %p )\n", pUpdateEntry ));
//
// deep free the update entry
//
if ( pUpdateEntry ) { PrivateHeapFree( pUpdateEntry->AdapterName ); PrivateHeapFree( pUpdateEntry->HostName ); PrivateHeapFree( pUpdateEntry->DomainName ); PrivateHeapFree( pUpdateEntry->PrimaryDomainName ); PrivateHeapFree( pUpdateEntry->AlternateNames ); PrivateHeapFree( pUpdateEntry->HostAddrs );
// note that server list is created by Dns_BuildIpArray()
// (uses dnslib heap) so must free by Dns_Free()
Dns_Free( pUpdateEntry->DnsServerList );
PrivateHeapFree( pUpdateEntry ); } }
VOID FreeUpdateEntryList( IN OUT PLIST_ENTRY pUpdateEntry ) /*++
Routine Description:
Free all updates in update list.
Arguments:
pUpdateEntry -- update list head
Return Value:
None
--*/ { PLIST_ENTRY pentry = NULL;
DNSDBG( TRACE, ( "FreeUpdateEntryList( %p )\n", pUpdateEntry ));
while ( !IsListEmpty( pUpdateEntry ) ) { pentry = RemoveHeadList( pUpdateEntry ); if ( pentry ) { FreeUpdateEntry( (PUPDATE_ENTRY) pentry ); } } }
DWORD WINAPI RegistrationThread( VOID ) /*++
Routine Description:
Asynchronous registration thread.
This thread does actual updates, and stays alive until they are completed, allowing registration API calls to return.
This thread is created at boot time as soon as the first register request comes in. The thread simply waits for a certain amount of time given by boot time or be signaled by DnsAsyncRegisterHostEntries.
This function collects all the requests and does the appropriate aggregation of requests and sends off the modify/add/delete commands to the DNS Server. When the call is successful, it makes a note of this in the registry
Arguments:
None
Return Value:
ERROR_SUCCESS if successful. ErrorCode on failure.
--*/ { DWORD waitResult; PUPDATE_ENTRY pupEntry = NULL; HANDLE handle[2]; DWORD status = NO_ERROR; DWORD dwWaitTime = g_dwBootTime; DWORD rcode = 0;
if ( !g_hKey ) { return(ERROR_INVALID_PARAMETER); }
//
// Note that this thread is running by setting a global flag
//
g_fRegistrationThreadRunning = TRUE;
//
// for use at a subsequent WFMO
//
handle[0] = g_hStopEvent; handle[1] = g_hNewItemEvent;
//
// Check to see this thread is at boot time or not.
// At boot time we simply wait for BOOT_TIME, otherwise move on.
// The global g_fAtBoot is not protected by critical section because
// only one thread accesses it at any time.
//
if ( !g_fAtBoot || g_fPurgeRegistrations ) { dwWaitTime = 0; }
dwWaitTime *= 1000;
waitResult = WaitForSingleObject( g_hStopEvent, dwWaitTime );
switch( waitResult ) { case WAIT_OBJECT_0 : //
// kill event
//
goto CleanUpAndDie;
case WAIT_TIMEOUT : //
// Means we can start processing the elements in the queue now
//
break; }
//
// loop through update list, doing any update
// - do new updates
// - do retries that have reached retry time
// - when list empty, terminate thread
//
while ( 1 ) { // if empty list and not-booting or purging
// => get out
EnterCriticalSection( &g_RegistrationListCS );
if ( IsListEmpty( &g_RegistrationList ) && ! g_fAtBoot && ! g_fPurgeRegistrations ) { LeaveCriticalSection( &g_RegistrationListCS ); break; }
//
// get "updateable" update from list (if any)
// 0 -- new update, or retry update ready
// 1 -- retry update, not yet ready
// -1 -- list empty
//
rcode = GetNextUpdateEntryFromList( &pupEntry, &dwWaitTime );
if ( &g_RegistrationList == (PLIST_ENTRY) pupEntry ) { DNS_ASSERT(&g_RegistrationList != (PLIST_ENTRY) pupEntry);
LeaveCriticalSection( &g_RegistrationListCS ); goto CleanUpAndDie; }
LeaveCriticalSection( &g_RegistrationListCS );
//
// rcode==0 -- new update in list
//
// DCR_QUESTION: not clear that this terminates updates in the
// purging updates case
//
if ( rcode == 0 ) { //
// See if we have been signaled to stop running . . .
//
waitResult = WaitForMultipleObjects( 2, handle, FALSE, 1 ); // a very small wait
switch( waitResult ) { case WAIT_OBJECT_0 : //
// kill event
//
FreeUpdateEntry( pupEntry ); goto CleanUpAndDie;
default : //
// Keep going, process next item in registration list
//
break; }
ProcessUpdateEntry( pupEntry, g_fPurgeRegistrations ); continue; }
//
// rcode==1 -- update needs retry
//
else if ( rcode == 1 && ! g_fAtBoot && ! g_fPurgeRegistrations ) { waitResult = WaitForMultipleObjects( 2, handle, FALSE, dwWaitTime ); switch( waitResult ) { case WAIT_OBJECT_0 : //
// kill event
//
goto CleanUpAndDie;
case WAIT_OBJECT_0 + 1 : //
// new item has been added to registration list
//
break;
case WAIT_TIMEOUT : //
// process next item in registration list
//
break; } continue; }
//
// rcode == (-1) -- list empty
// OR
// rcode == (1) -- reties, not booting or purging
//
else { if ( !g_fAtBoot && !g_fPurgeRegistrations ) { goto CleanUpAndDie; }
if ( g_fPurgeRegistrationsInitiated ) { goto CleanUpAndDie; }
if ( g_fPurgeRegistrations ) { ResetAdaptersInRegistry(); }
//
// Remove any adapter configurations from the registry
// that were not processed. Do this by attempting to
// remove the related DNS records from the DNS server(s).
//
DeregisterUnusedAdapterInRegistry( g_fPurgeRegistrations );
if ( g_fPurgeRegistrations ) { g_fPurgeRegistrationsInitiated = TRUE; }
g_fAtBoot = FALSE;
continue; } }
CleanUpAndDie :
ASYNCREG_F1( "RegistrationThread - terminating" ); ASYNCREG_F1( "" );
EnterCriticalSection( &g_RegistrationThreadCS ); EnterCriticalSection( &g_RegistrationListCS );
g_fQuit = TRUE; g_fAtBoot = FALSE; g_fPurgeRegistrations = FALSE; g_fPurgeRegistrationsInitiated = FALSE;
//
// Blow away the registration list
//
FreeUpdateEntryList( &g_RegistrationList ); InitializeListHead( &g_RegistrationList );
LeaveCriticalSection( &g_RegistrationListCS );
//
// Blow away any cached security handles
//
Dns_TimeoutSecurityContextList( TRUE );
//
// Close the thread handle.
//
if ( g_hRegistrationThread ) { CloseHandle( g_hRegistrationThread ); g_hRegistrationThread = NULL; }
//
// Note that this thread is NOT running by setting a global flag
//
g_fRegistrationThreadRunning = FALSE;
//
// Now signal that we've finished
//
ASYNCREG_F1( "RegistrationThread - Signaling ThreadDeadEvent" ); ASYNCREG_F1( "" );
// clear purge incase of later restart
//g_fPurgeRegistrations = FALSE;
// currently must go through Init routine which clears this flag
SetEvent( g_hThreadDeadEvent );
LeaveCriticalSection( &g_RegistrationThreadCS );
ASYNCREG_F1( "RegistrationThread - Finished" ); ASYNCREG_F1( "" );
return NO_ERROR; }
VOID WriteUpdateEntryToRegistry( IN PUPDATE_ENTRY pUpdateEntry ) { HKEY hAdapterKey = NULL; DWORD disposition; DWORD status = ERROR_SUCCESS; DWORD dwRegistered = 0; DWORD dwFlags = 0; WCHAR uName[ DNS_MAX_NAME_BUFFER_LENGTH ];
ASYNCREG_UPDATE_ENTRY( "Inside function WriteUpdateEntryToRegistry", pUpdateEntry );
DNSDBG( TRACE, ( "WriteUpdateEntryToRegistry( %p )\n", pUpdateEntry ));
//
// write only add update
//
// remove's should not be non-volatile as don't know anything
// about state when come back up
//
if ( !pUpdateEntry->fRemove ) { if ( pUpdateEntry->fRegisteredFWD ) { dwFlags |= REGISTERED_FORWARD; } if ( pUpdateEntry->fRegisteredPRI ) { dwFlags |= REGISTERED_PRIMARY; } if ( pUpdateEntry->fRegisteredPTR ) { dwFlags |= REGISTERED_POINTER; }
if ( dwFlags ) { dwRegistered = 1; }
status = RegCreateKeyExA ( g_hKey, pUpdateEntry->AdapterName, 0, ADAPTER_NAME_CLASS, REG_OPTION_NON_VOLATILE, // options
KEY_READ | KEY_WRITE, // desired access
NULL, &hAdapterKey, &disposition ); if ( status ) { goto Exit; }
Dns_Utf8ToUnicode( pUpdateEntry->HostName, strlen( pUpdateEntry->HostName ), uName, 256 );
status = RegSetValueExW( hAdapterKey, REGISTERED_HOST_NAME_W, 0, REG_SZ, (LPBYTE)uName, ( wcslen( uName ) + 1 ) * sizeof(WCHAR) );
if ( status ) { goto Exit; }
if ( pUpdateEntry->DomainName && pUpdateEntry->fRegisteredFWD ) { Dns_Utf8ToUnicode( pUpdateEntry->DomainName, strlen( pUpdateEntry->DomainName ), uName, 256 );
status = RegSetValueExW( hAdapterKey, REGISTERED_DOMAIN_NAME_W, 0, REG_SZ, (LPBYTE)uName, ( wcslen( uName ) + 1 ) * sizeof(WCHAR) );
if ( status ) { goto Exit; } } else { status = RegSetValueExA( hAdapterKey, REGISTERED_DOMAIN_NAME, 0, REG_SZ, (LPBYTE)"", ( strlen( "" ) + 1 ) * sizeof(CHAR) );
if ( status ) { goto Exit; } }
if ( pUpdateEntry->PrimaryDomainName && pUpdateEntry->fRegisteredPRI ) { Dns_Utf8ToUnicode( pUpdateEntry->PrimaryDomainName, strlen( pUpdateEntry->PrimaryDomainName ), uName, 256 );
status = RegSetValueExW( hAdapterKey, PRIMARY_DOMAIN_NAME, 0, REG_SZ, (LPBYTE)uName, ( wcslen( uName ) + 1 ) * sizeof(WCHAR) );
if ( status ) { goto Exit; } } else { status = RegSetValueExA( hAdapterKey, PRIMARY_DOMAIN_NAME_A, 0, REG_SZ, (LPBYTE)"", ( strlen( "" ) + 1 ) * sizeof(CHAR) );
if ( status ) { goto Exit; } }
RegSetValueExA( hAdapterKey, SENT_UPDATE_TO_IP, 0, REG_DWORD, (LPBYTE)&pUpdateEntry->SentUpdateToIp, sizeof(DWORD) );
RegSetValueExA( hAdapterKey, SENT_PRI_UPDATE_TO_IP, 0, REG_DWORD, (LPBYTE)&pUpdateEntry->SentPriUpdateToIp, sizeof(DWORD) );
RegSetValueExA( hAdapterKey, REGISTERED_TTL, 0, REG_DWORD, (LPBYTE)&pUpdateEntry->TTL, sizeof(DWORD) );
RegSetValueExA( hAdapterKey, FLAGS, 0, REG_DWORD, (LPBYTE)&dwFlags, sizeof(DWORD) );
//
// ignore error on the last two. Non critical
//
status = RegSetValueExA( hAdapterKey, REGISTERED_ADDRS, 0, REG_BINARY, (LPBYTE) pUpdateEntry->HostAddrs, pUpdateEntry->HostAddrCount * sizeof(REGISTER_HOST_ENTRY) ); if ( status ) { goto Exit; }
status = RegSetValueExA( hAdapterKey, REGISTERED_ADDRS_COUNT, 0, REG_DWORD, (LPBYTE)&pUpdateEntry->HostAddrCount, sizeof(DWORD) ); if ( status ) { goto Exit; }
status = RegSetValueExA( hAdapterKey, REGISTERED_SINCE_BOOT, 0, REG_DWORD, (LPBYTE)&dwRegistered, sizeof(DWORD) ); if ( status ) { goto Exit; }
if ( pUpdateEntry->DnsServerList ) { status = RegSetValueExA( hAdapterKey, DNS_SERVER_ADDRS, 0, REG_BINARY, (LPBYTE) pUpdateEntry -> DnsServerList -> AddrArray, pUpdateEntry -> DnsServerList -> AddrCount * sizeof(IP_ADDRESS) ); if ( status ) { goto Exit; }
status = RegSetValueExA( hAdapterKey, DNS_SERVER_ADDRS_COUNT, 0, REG_DWORD, (LPBYTE) &pUpdateEntry -> DnsServerList -> AddrCount, sizeof(DWORD) ); if ( status ) { goto Exit; } } else { DWORD count = 0;
status = RegSetValueExA( hAdapterKey, DNS_SERVER_ADDRS_COUNT, 0, REG_DWORD, (LPBYTE) &count, sizeof(DWORD) ); if ( status ) { goto Exit; }
status = RegSetValueExA( hAdapterKey, DNS_SERVER_ADDRS, 0, REG_BINARY, (LPBYTE) NULL, 0 ); if ( status ) { goto Exit; } }
RegCloseKey( hAdapterKey ); return; }
Exit:
//
// remove or failure -- kill adapter key
//
RegDeleteKey( g_hKey, pUpdateEntry->AdapterName );
if ( hAdapterKey ) { RegCloseKey( hAdapterKey ); } }
PUPDATE_ENTRY ReadUpdateEntryFromRegistry( IN PSTR AdapterName ) { PREGISTER_HOST_ENTRY pHostAddrs = NULL; PUPDATE_ENTRY pupEntry = NULL; DWORD status = NO_ERROR; PSTR pregHostName = NULL; PSTR pregDomain = NULL; PSTR pregPrimary = NULL; IP_ADDRESS ipSentUpdateTo = 0; IP_ADDRESS ipSentPriUpdateTo = 0; DWORD dwTTL = 0; DWORD dwFlags = 0; DWORD dwHostAddrCount = 0; DWORD dwServerAddrCount = 0; PIP_ADDRESS pServerList = NULL; PSTR pdomain; PSTR pprimary; HKEY hAdapterKey = NULL; DWORD dwType; DWORD dwBytesRead = MAX_PATH -1; DWORD dwBufferSize = 2048; BOOL fRegFWD = FALSE; BOOL fRegPRI = FALSE; BOOL fRegPTR = FALSE;
DNSDBG( TRACE, ( "ReadUpdateEntryFromRegistry( %s )\n", AdapterName ));
//
// implementation note
//
// two different heaps here
// - g_DDNSHeap specific for this module
// - general DnsApi heap which all the stuff which is
// allocated by GetRegistryValue() is using
//
// GetRegistryValue() uses ALLOCATE_HEAP() (general dnsapi heap)
// so all the stuff it creates must be freed by FREE_HEAP()
//
pHostAddrs = (PREGISTER_HOST_ENTRY) PHEAP_ALLOC( dwBufferSize ); if ( !pHostAddrs ) { goto Exit; }
pServerList = (PIP_ADDRESS) PHEAP_ALLOC( dwBufferSize ); if ( !pServerList ) { goto Exit; }
status = RegOpenKeyEx( g_hKey, AdapterName, 0, KEY_ALL_ACCESS, &hAdapterKey ); if ( status ) { hAdapterKey = NULL; goto Exit; }
//
// read each value in turn
//
// note that registry flags are not the API flags but the
// flags denoting successful registration
status = GetRegistryValue( hAdapterKey, FLAGS, REG_DWORD, (PBYTE)&dwFlags ); if ( status ) { goto Exit; } fRegPRI = !!( dwFlags & REGISTERED_PRIMARY ); fRegFWD = !!( dwFlags & REGISTERED_FORWARD ); fRegPTR = !!( dwFlags & REGISTERED_POINTER );
status = GetRegistryValue( hAdapterKey, REGISTERED_HOST_NAME, REG_SZ, (PBYTE)&pregHostName ); if ( status ) { goto Exit; }
if ( fRegPRI ) { status = GetRegistryValue( hAdapterKey, PRIMARY_DOMAIN_NAME_A, REG_SZ, (LPBYTE)&pregPrimary ); if ( status ) { goto Exit; } }
if ( fRegFWD ) { status = GetRegistryValue( hAdapterKey, REGISTERED_DOMAIN_NAME, REG_SZ, (LPBYTE)&pregDomain ); if ( status ) { goto Exit; } }
status = GetRegistryValue( hAdapterKey, SENT_UPDATE_TO_IP, REG_DWORD, (LPBYTE)&ipSentUpdateTo ); if ( status ) { goto Exit; }
status = GetRegistryValue( hAdapterKey, SENT_PRI_UPDATE_TO_IP, REG_DWORD, (LPBYTE)&ipSentPriUpdateTo ); if ( status ) { goto Exit; }
status = GetRegistryValue( hAdapterKey, REGISTERED_TTL, REG_DWORD, (LPBYTE)&dwTTL ); if ( status ) { goto Exit; }
status = GetRegistryValue( hAdapterKey, REGISTERED_ADDRS_COUNT, REG_DWORD, (LPBYTE)&dwHostAddrCount ); if ( status ) { goto Exit; }
dwBytesRead = dwBufferSize; status = RegQueryValueEx( hAdapterKey, REGISTERED_ADDRS, 0, &dwType, (LPBYTE)pHostAddrs, &dwBytesRead );
if( status == ERROR_MORE_DATA ) { PrivateHeapFree( pHostAddrs );
pHostAddrs = (PREGISTER_HOST_ENTRY) PHEAP_ALLOC( dwBytesRead ); if ( !pHostAddrs ) { goto Exit; } status = RegQueryValueEx( hAdapterKey, REGISTERED_ADDRS, 0, &dwType, (LPBYTE)pHostAddrs, &dwBytesRead ); } if ( status ) { goto Exit; }
if ( dwBytesRead/sizeof(REGISTER_HOST_ENTRY) < dwHostAddrCount ) { goto Exit; }
status = GetRegistryValue( hAdapterKey, DNS_SERVER_ADDRS_COUNT, REG_DWORD, (LPBYTE)&dwServerAddrCount ); if ( status ) { dwServerAddrCount = 0; }
if ( dwServerAddrCount ) { dwBytesRead = dwBufferSize;
status = RegQueryValueEx( hAdapterKey, DNS_SERVER_ADDRS, 0, &dwType, (LPBYTE)pServerList, &dwBytesRead );
if ( status == ERROR_MORE_DATA ) { PHEAP_FREE( pServerList );
pServerList = (PIP_ADDRESS) PHEAP_ALLOC( dwBytesRead ); if ( !pServerList ) { goto Exit; } status = RegQueryValueEx( hAdapterKey, DNS_SERVER_ADDRS, 0, &dwType, (LPBYTE)pServerList, &dwBytesRead ); } if ( status ) { goto Exit; }
if ( dwBytesRead/sizeof(IP_ADDRESS) < dwServerAddrCount ) { goto Exit; } } else { pServerList = NULL; }
//
// validate domain names non-empty
//
pdomain = pregDomain; if ( pdomain && strlen( pdomain ) == 0 ) { pdomain = NULL; }
pprimary = pregPrimary; if ( pprimary && strlen( pprimary ) == 0 ) { pprimary = NULL; }
status = AllocateUpdateEntry( AdapterName, pregHostName, pdomain, pprimary, NULL, // no alternate names
dwHostAddrCount, pHostAddrs, dwServerAddrCount, pServerList, ipSentUpdateTo, ipSentPriUpdateTo, dwTTL, ( fRegPTR ) ? DYNDNS_REG_PTR : 0, 0, Dns_GetCurrentTimeInSeconds(), NULL, &pupEntry ); if ( status ) { DNS_ASSERT( pupEntry == NULL ); pupEntry = NULL; goto Exit; }
pupEntry->fFromRegistry = TRUE; pupEntry->fRegisteredFWD = fRegFWD; pupEntry->fRegisteredPRI = fRegPRI; pupEntry->fRegisteredPTR = fRegPTR;
Exit:
//
// cleanup
// - close registry
// - dump local data
//
if ( hAdapterKey ) { RegCloseKey( hAdapterKey ); }
PrivateHeapFree( pHostAddrs ); PrivateHeapFree( pServerList );
FREE_HEAP( pregHostName ); FREE_HEAP( pregDomain ); FREE_HEAP( pregPrimary ); // set return value
ASYNCREG_UPDATE_ENTRY( "Leaving ReadUpdateEntryFromRegistry:", pupEntry );
IF_DNSDBG( TRACE ) { DnsDbg_UpdateEntry( "Leave ReadUpdateEntryFromRegistry():", pupEntry ); }
return pupEntry; }
VOID MarkAdapterAsPendingUpdate( IN PSTR AdapterName ) { DWORD status = NO_ERROR; DWORD dwRegistered = 1; HKEY hAdapterKey = NULL;
DNSDBG( TRACE, ( "MarkAdapterAsPendingUpdate( %s )\n", AdapterName ));
status = RegOpenKeyEx( g_hKey, AdapterName, 0, KEY_ALL_ACCESS, &hAdapterKey ); if ( status ) { return; }
RegSetValueExA( hAdapterKey, REGISTERED_SINCE_BOOT, 0, REG_DWORD, (LPBYTE) &dwRegistered, sizeof(DWORD) );
RegCloseKey( hAdapterKey ); }
DWORD GetNextUpdateEntryFromList( OUT PUPDATE_ENTRY * ppUpdateEntry, OUT PDWORD pdwWaitTime ) /*++
Routine Description:
Dequeue update entry from update list.
//
// If a new entry is found, set ppUpdateEntry to point
// to it and return 0 (prefering deletes over adds).
//
// If there are only retry entries in the list, and one or more
// have reached their retry time interval, then set ppUpdateEntry
// to point to the one with the least retry time and return 0.
//
// If there are only retry entries in the list, but none have
// yet reached there retry time interval then set pdwWaitTime to
// the time remaining to wait for the entry with the least retry
// interval and return 1 (WAIT)
//
// If there are no more records in list, return (-1)
//
Arguments:
Return Value:
(0) -- returning entry in ppUpdateEntry - new entry if found - retry which is past its retry time
(1) -- list has only retries which have NOT reached retry time - set pdwWaitTime to remaining time to first retry
(-1) -- list is empty
--*/ { PLIST_ENTRY pentry; PLIST_ENTRY plistHead; PLIST_ENTRY pleastWaitEntry = NULL; DWORD minWaitTime = 0xffffffff; INT waitTime;
ASYNCREG_F1( "Inside function GetNextUpdateEntryFromList" );
DNSDBG( TRACE, ( "GetNextUpdateEntryFromList()" ));
if ( IsListEmpty( &g_RegistrationList ) ) { *ppUpdateEntry = NULL; *pdwWaitTime = 0; ASYNCREG_F1( "GetNextUpdateEntryFromList - returning (NO_MORE_RECORDS)" ); ASYNCREG_F1( "" ); return(-1); }
//
// Loop through list looking for a new delete related update entry.
// If so, remove it from list and return it.
//
plistHead = &g_RegistrationList; pentry = plistHead->Flink;
while ( pentry != plistHead ) { if ( ((PUPDATE_ENTRY) pentry)->fRemove && ((PUPDATE_ENTRY) pentry)->fNewElement ) { RemoveEntryList( pentry ); *ppUpdateEntry = (PUPDATE_ENTRY) pentry; *pdwWaitTime = 0; ASYNCREG_F1( "GetNextUpdateEntryFromList - returning new remove entry (SUCCESS)" ); ASYNCREG_F1( "" ); return 0; } else { pentry = pentry->Flink; } }
//
// Now loop through list looking for any new update.
// If so, remove it from list and return it.
//
plistHead = &g_RegistrationList; pentry = plistHead->Flink;
while ( pentry != plistHead ) { if ( ((PUPDATE_ENTRY) pentry)->fNewElement ) { RemoveEntryList( pentry ); *ppUpdateEntry = (PUPDATE_ENTRY) pentry; *pdwWaitTime = 0; ASYNCREG_F1( "GetNextUpdateEntryFromList - returning new entry (SUCCESS)" ); ASYNCREG_F1( "" ); return 0; } else { pentry = pentry->Flink; } }
//
// There are no new update entries to process, now need to
// loop through list looking for the next possible update to
// wait on. If wait time has expired return it, otherwise
// set pdwWaitTime to time remaining and return 1.
//
plistHead = &g_RegistrationList; pentry = plistHead->Flink;
while ( pentry != plistHead ) { if ( ((PUPDATE_ENTRY) pentry)->RetryTime < minWaitTime ) { minWaitTime = ((PUPDATE_ENTRY) pentry)->RetryTime; pleastWaitEntry = pentry; }
pentry = pentry->Flink; }
waitTime = (INT) ( minWaitTime - Dns_GetCurrentTimeInSeconds() );
if ( waitTime > 0 ) { waitTime *= 1000; *ppUpdateEntry = NULL; *pdwWaitTime = (DWORD) waitTime; ASYNCREG_F1( "GetNextUpdateEntryFromList - returning (WAIT)" ); ASYNCREG_F1( "" ); return 1; } else { RemoveEntryList( pleastWaitEntry ); *ppUpdateEntry = (PUPDATE_ENTRY) pleastWaitEntry; *pdwWaitTime = 0; ASYNCREG_F1( "GetNextUpdateEntryFromList - returning wait entry (SUCCESS)" ); ASYNCREG_F1( "" ); return 0; } }
//
// Update entry processing
//
DNS_STATUS DoRemoveUpdate( IN OUT PUPDATE_ENTRY pRemoveEntry, IN OUT PDNS_RECORD pRemoveRecord, IN UPTYPE UpType ) /*++
Routine Description:
Do a remove update.
Helper routine for DoUpdate(). Routine simply avoids duplicate code as this is called with both registry entry and with update entry.
Arguments:
pRemoveEntry -- entry to remove, from update or registry
pRemoveRecord -- record to remove
fPrimary -- TRUE for primary update; FALSE otherwise
Return Value:
DNS or Win32 error code.
--*/ { DNS_STATUS status = NO_ERROR;
DNSDBG( TRACE, ( "DoRemoveUpdate( %p, %p, %d )\n", pRemoveEntry, pRemoveRecord, UpType ));
//
// try remove
// - don't track failure, this is a one shot deal before
// adapter goes down
//
status = DnsModifyRecordsInSet_UTF8( NULL, // no add records
pRemoveRecord, // delete records
DNS_UPDATE_CACHE_SECURITY_CONTEXT, NULL, // no context handle
(PIP4_ARRAY) pRemoveEntry->DnsServerList, NULL // reserved
);
SetUpdateStatus( pRemoveEntry, status, UpType );
if ( IS_UPTYPE_PRIMARY(UpType) ) { LogRegistration( pRemoveEntry, status, UpType, TRUE, // deregistration
0, // default server IP
0 // default update IP
); }
#if 0
// doing entire update entry PTR dereg at once
// in ProcessUpdate() once done
//
// deregister the PTR records
//
if ( (pRemoveEntry->Flags & DYNDNS_REG_PTR) && g_RegisterReverseLookup ) { UpdatePtrRecords( pRemoveEntry, FALSE // remove records
); } #endif
return status; }
DNS_STATUS ModifyAdapterRegistration( IN PUPDATE_ENTRY pUpdateEntry, IN PUPDATE_ENTRY pRegistryEntry, IN PDNS_RECORD pUpdateRecord, IN PDNS_RECORD pRegRecord, IN BOOL fPrimaryDomain ) { DNS_STATUS status = NO_ERROR; PDNS_RECORD potherRecords = NULL; PDNS_RECORD pNewUpdateRecord = NULL; PDNS_RECORD pNewRegRecord = NULL; IP_ADDRESS serverIp = 0;
DNSDBG( TRACE, ( "ModifyAdapterRegistration()\n" "\tpUpdateEntry = %p\n" "\tpUpdateRecords = %p\n" "\tpRegistryEntry = %p\n" "\tpRegistryRecords = %p\n" "\tfPrimary = %d\n", pUpdateEntry, pRegistryEntry, pUpdateRecord, pRegRecord, fPrimaryDomain ));
//
// multi-adapter registration test
//
// check other adapters for registrations on the same name
// if found, include in updates
//
potherRecords = GetPreviousRegistrationInformation( pUpdateEntry, fPrimaryDomain, &serverIp ); if ( potherRecords ) { IP_ARRAY ipArray;
DNSDBG( DHCP, ( "Have registry update data for other adapters!\n" "\tCreating combined update record sets.\n" ));
ipArray.AddrCount = 1; ipArray.AddrArray[0] = serverIp;
pNewUpdateRecord = CreateDnsRecordSetUnion( pUpdateRecord, potherRecords ); if ( pRegRecord && Dns_NameCompare_UTF8( pRegRecord->pName, pUpdateRecord->pName ) && CompareMultiAdapterSOAQueries( pUpdateRecord->pName, pUpdateEntry->DnsServerList, pRegistryEntry->DnsServerList ) ) { pNewRegRecord = CreateDnsRecordSetUnion( pRegRecord, potherRecords ); } else { if ( pRegRecord ) { //
// The record found in the registry for this adapter
// is stale and should be deleted. Otherwise we set the
// current list of records to only that of potherRecords.
//
ASYNCREG_F1( "DoUpdateForPrimaryName - Found stale registry entry:" ); ASYNCREG_F2( " Name : %s", pRegRecord->pName ); ASYNCREG_F1( " Address :" ); DNSLOG_PIP_ADDRESS( 1, &(pRegRecord->Data.A.IpAddress) ); ASYNCREG_F1( "" ); ASYNCREG_F1( " Calling DnsRemoveRecords_UTF8 to get rid of it" );
status = DnsModifyRecordsInSet_UTF8( NULL, // no add records
pRegRecord, // delete records
DNS_UPDATE_CACHE_SECURITY_CONTEXT, NULL, // no context handle
(PIP4_ARRAY) pRegistryEntry->DnsServerList, NULL // reserved
);
ASYNCREG_F3( " DnsRemoveRecords_UTF8 returned: 0x%x\n\t%s", status, Dns_StatusString( status ) ); }
pNewRegRecord = potherRecords; potherRecords = NULL; }
if ( !pNewUpdateRecord || !pNewRegRecord ) { DNSDBG( ANY, ( "ERROR: failed to build combined record set for update!\n" )); status = DNS_ERROR_NO_MEMORY; goto Exit; }
ASYNCREG_F1( "ModifyAdapterRegistration - Calling DnsModifyRecordSet_UTF8" ); ASYNCREG_F1( " (current update + previous records)" );
if ( serverIp ) { //
// DCR: just do replace from the start
//
ASYNCREG_F1( " (sending update to specific server)" ); DNSLOG_PIP_ARRAY( &ipArray );
status = DnsModifyRecordSet_UTF8( NULL, // no creds
pNewRegRecord, // previous set
pNewUpdateRecord, // new set
DNS_UPDATE_CACHE_SECURITY_CONTEXT, &ipArray );
ASYNCREG_F3( " DnsModifyRecordSet_UTF8 returned: 0x%x\n\t%s", status, Dns_StatusString( status ) );
if ( status == DNS_ERROR_RCODE_SERVER_FAILURE || status == ERROR_TIMEOUT ) { goto SendUpdate1; }
if ( status == DNS_ERROR_NOT_UNIQUE && g_RegistrationOverwritesInConflict ) { ASYNCREG_F1( "ModifyAdapterRegistration - Calling DnsReplaceRecordSet_UTF8" ); ASYNCREG_F1( " (current update + previous records)" );
status = DnsReplaceRecordSetUTF8( pNewUpdateRecord, // replace set
DNS_UPDATE_CACHE_SECURITY_CONTEXT, NULL, // no security context
(PIP4_ARRAY) &ipArray, // DNS servers
NULL // reserved
);
ASYNCREG_F3( " DnsReplaceRecordSet_UTF8 returned: 0x%x\n\t%s", status, Dns_StatusString( status ) ); } } else {
SendUpdate1 :
ASYNCREG_F1( " (sending update to adapter server list)" ); DNSLOG_PIP_ARRAY( pUpdateEntry->DnsServerList );
status = DnsModifyRecordSet_UTF8( NULL, // no creds
pNewRegRecord, // previous set
pNewUpdateRecord, // new set
DNS_UPDATE_CACHE_SECURITY_CONTEXT, pUpdateEntry->DnsServerList );
ASYNCREG_F3( " DnsModifyRecordSet_UTF8 returned: 0x%x\n\t%s", status, Dns_StatusString( status ) );
if ( status == DNS_ERROR_NOT_UNIQUE && g_RegistrationOverwritesInConflict ) { ASYNCREG_F1( "ModifyAdapterRegistration - Calling DnsReplaceRecordSet_UTF8" ); ASYNCREG_F1( " (current update + previous records)" );
status = DnsReplaceRecordSetUTF8( pNewUpdateRecord, // replace set
DNS_UPDATE_CACHE_SECURITY_CONTEXT, NULL, // no security context
(PIP4_ARRAY) pUpdateEntry->DnsServerList, NULL // reserved
);
ASYNCREG_F3( " DnsReplaceRecordSet_UTF8 returned: 0x%x\n\t%s", status, Dns_StatusString( status ) ); } } } else { if ( pRegRecord && Dns_NameCompare_UTF8( pRegRecord->pName, pUpdateRecord->pName ) && CompareMultiAdapterSOAQueries( pUpdateRecord->pName, pUpdateEntry->DnsServerList, pRegistryEntry->DnsServerList ) ) { ASYNCREG_F1( "ModifyAdapterRegistration - Calling DnsModifyRecordSet_UTF8" ); ASYNCREG_F1( " (current update record only)" );
status = DnsModifyRecordSet_UTF8( NULL, // no creds
pRegRecord, // previous set
pUpdateRecord, // new set
DNS_UPDATE_CACHE_SECURITY_CONTEXT, pUpdateEntry->DnsServerList );
ASYNCREG_F3( " DnsModifyRecordSet_UTF8 returned: 0x%x\n\t%s", status, Dns_StatusString( status ) ); } else { if ( pRegRecord ) { //
// The record found in the registry for this adapter
// is stale and should be deleted. Otherwise we set the
// current list of records to only that of potherRecords.
//
ASYNCREG_F1( "DoUpdateForPrimaryName - Found stale registry entry:" ); ASYNCREG_F2( " Name : %s", pRegRecord->pName ); ASYNCREG_F1( " Address :" ); DNSLOG_PIP_ADDRESS( 1, &(pRegRecord->Data.A.IpAddress) ); ASYNCREG_F1( "" ); ASYNCREG_F1( " Calling DnsRemoveRecords_UTF8 to get rid of it" );
status = DnsModifyRecordsInSet_UTF8( NULL, // no add records
pRegRecord, // delete records
DNS_UPDATE_CACHE_SECURITY_CONTEXT, NULL, // no context handle
pRegistryEntry->DnsServerList, NULL // reserved
);
ASYNCREG_F3( " DnsRemoveRecords_UTF8 returned: 0x%x\n\t%s", status, Dns_StatusString( status ) ); }
ASYNCREG_F1( "ModifyAdapterRegistration - Calling DnsAddRecordSet_UTF8" );
status = DnsAddRecordSet_UTF8( NULL, // no creds
pUpdateRecord, DNS_UPDATE_CACHE_SECURITY_CONTEXT, pUpdateEntry->DnsServerList );
ASYNCREG_F3( " DnsAddRecordSet_UTF8 returned: 0x%x\n\t%s", status, Dns_StatusString( status ) ); }
if ( status == DNS_ERROR_NOT_UNIQUE && g_RegistrationOverwritesInConflict ) { ASYNCREG_F1( "ModifyAdapterRegistration - Calling DnsReplaceRecordSet_UTF8" ); ASYNCREG_F1( " (current update record only)" );
status = DnsReplaceRecordSetUTF8( pUpdateRecord, // replace set
DNS_UPDATE_CACHE_SECURITY_CONTEXT, NULL, // no security context
(PIP4_ARRAY) pUpdateEntry->DnsServerList, NULL // reserved
);
ASYNCREG_F3( " DnsReplaceRecordSet_UTF8 returned: 0x%x\n\t%s", status, Dns_StatusString( status ) ); } }
Exit:
Dns_RecordListFree( potherRecords ); Dns_RecordListFree( pNewUpdateRecord ); Dns_RecordListFree( pNewRegRecord );
return status; }
DNS_STATUS DoModifyUpdate( IN OUT PUPDATE_ENTRY pUpdateEntry, IN OUT PDNS_RECORD pUpdateRecord, IN PUPDATE_ENTRY pRegistryEntry, OPTIONAL IN OUT PDNS_RECORD pRegRecord, OPTIONAL IN UPTYPE UpType ) /*++
Routine Description:
Standard modify registration.
Helper routine for DoUpdate(). This handles modify for typical non-remove case. - Forward records updated - Old PTR removed if new address. - New PTR added (or name modified).
Arguments:
pUpdateEntry -- update entry
pUpdateRecord -- records for update
pRegistryEntry -- registry entry
pRegRecord -- records from registry entry
fPrimary -- TRUE if update for primary domain name FALSE for adapter domain name
Return Value:
DNS or Win32 error code.
--*/ { DNS_STATUS status = NO_ERROR; IP4_ADDRESS ip = 0; BOOL fregistered = FALSE;
DNSDBG( TRACE, ( "DoModifyUpdate()\n" "\tUpdateEntry = %p\n" "\tUpType = %d\n", pUpdateEntry, UpType ));
DNS_ASSERT( pUpdateEntry != NULL ); DNS_ASSERT( pUpdateRecord != NULL );
//
// do forward registration modify
//
status = ModifyAdapterRegistration( pUpdateEntry, // add
pRegistryEntry, // remove
pUpdateRecord, pRegRecord, IS_UPTYPE_PRIMARY(UpType) );
//
// save success info
//
SetUpdateStatus( pUpdateEntry, status, UpType );
//
// PTR records
//
// deregister previous PTR registration
// - registry entry indicates previous registration
// - not the same address as current (otherwise it's an update)
//
// note: adding new registration takes place in DoUpdate() once
// ALL forward updates are complete
//
if ( g_RegisterReverseLookup ) { if ( pRegistryEntry && (pRegistryEntry->Flags & DYNDNS_REG_PTR) && !compareUpdateEntries( pRegistryEntry, pUpdateEntry ) ) { UpdatePtrRecords( pRegistryEntry, FALSE // remove previous PTR
); } }
//
// Log registration status in EventLog
//
if ( pUpdateEntry->RetryCount == 2 || status == DNS_ERROR_RCODE_NOT_IMPLEMENTED || status == DNS_ERROR_RCODE_REFUSED ) { LogRegistration( pUpdateEntry, status, UpType, FALSE, // registration
0, // default server IP
0 // default update IP
); }
DNSDBG( TRACE, ( "Leave DoModifyUpdate() => %d\n", status ));
return status; }
DNS_STATUS DoUpdate( IN OUT PUPDATE_ENTRY pRegistryEntry OPTIONAL, IN OUT PUPDATE_ENTRY pUpdateEntry, IN UPTYPE UpType ) /*++
Routine Description:
Do update for a particular name.
Helper routine for ProcessUpdate(). Handles one name, called separately for AdapaterDomainName and PrimaryDomainName.
Arguments:
pUpdateEntry -- update entry
pRegistryEntry -- registry entry
fPrimary -- TRUE if update for primary domain name FALSE for adapter domain name
Return Value:
DNS or Win32 error code.
--*/ { PDNS_RECORD prrRegistry = NULL; PDNS_RECORD prrUpdate = NULL; DNS_STATUS status = NO_ERROR;
ASYNCREG_UPDATE_ENTRY( "DoUpdate() -- UpdateEntry:", pUpdateEntry ); ASYNCREG_UPDATE_ENTRY( "DoUpdate() -- RegistryEntry:", pRegistryEntry );
IF_DNSDBG( TRACE ) { DnsDbg_UpdateEntry( "DoUpdate() -- UpdateEntry:", pUpdateEntry ); DnsDbg_UpdateEntry( "DoUpdate() -- RegistryEntry:", pRegistryEntry ); } DNS_ASSERT( pUpdateEntry != NULL );
//
// build records from update entrys
//
prrUpdate = CreateForwardRecords( pUpdateEntry, UpType ); if ( ! prrUpdate ) { DNSDBG( TRACE, ( "No forward records created for update entry (%p) for update type %d!", pUpdateEntry, UpType )); return NO_ERROR; }
if ( pRegistryEntry ) { prrRegistry = CreateForwardRecords( pRegistryEntry, UpType ); DNS_ASSERT( !IS_UPTYPE_ALTERNATE(UpType) || prrRegistry==NULL ); }
//
// remove?
// - remove previous registry entry if exists
// - remove update entry
//
if ( pUpdateEntry->fRemove ) { if ( prrRegistry ) { // we don't lookup registry entries on fRemove updates, so i
// don't see how we'd get here
DNS_ASSERT( FALSE );
DoRemoveUpdate( pRegistryEntry, prrRegistry, UpType ); } status = DoRemoveUpdate( pUpdateEntry, prrUpdate, UpType ); }
//
// add\modify registration
//
else { status = DoModifyUpdate( pUpdateEntry, prrUpdate, pRegistryEntry, prrRegistry, UpType ); }
//
// cleanup records
//
Dns_RecordListFree( prrRegistry ); Dns_RecordListFree( prrUpdate );
return status; }
BOOL IsQuickRetryError( IN DNS_STATUS Status ) { return( Status != NO_ERROR && ( Status == DNS_ERROR_RCODE_REFUSED || Status == DNS_ERROR_RCODE_SERVER_FAILURE || Status == DNS_ERROR_TRY_AGAIN_LATER || Status == DNS_ERROR_NO_DNS_SERVERS || Status == WSAECONNREFUSED || Status == WSAETIMEDOUT || Status == ERROR_TIMEOUT ) );
}
VOID ProcessUpdateEntry( IN OUT PUPDATE_ENTRY pUpdateEntry, IN BOOL fPurgeMode ) /*++
Routine Description:
Main routine processing an update.
Arguments:
pUpdateEntry -- update entry to execute note: this routine frees pUpdateEntry when complete
fPurgeMode -- TRUE if purging update queue
Return Value:
DNS or Win32 error code.
--*/ { DNS_STATUS status; DNS_STATUS statusPri = NO_ERROR; DNS_STATUS statusAdp = NO_ERROR; DNS_STATUS statusAlt = NO_ERROR; PUPDATE_ENTRY pregEntry = NULL; DWORD retryInterval;
DNSDBG( TRACE, ( "ProcessUpdateEntry( %p, purge=%d )\n", pUpdateEntry, fPurgeMode ));
IF_DNSDBG( TRACE ) { DnsDbg_UpdateEntry( "Enter ProcessUpdateEntry():", pUpdateEntry ); }
//
// add (not remove)
//
if ( !pUpdateEntry->fRemove ) { // no adds during purge mode
if ( fPurgeMode ) { goto Cleanup; }
//
// get any prior update info from registry
//
// if hostname change, then delete on prior update
//
pregEntry = ReadUpdateEntryFromRegistry( pUpdateEntry->AdapterName ); if ( pregEntry ) { if ( ! Dns_NameCompare_UTF8( pregEntry->HostName, pUpdateEntry->HostName ) ) { DNSDBG( TRACE, ( "Prior registry data with non-matching hostname!\n" "\tqueuing delete for prior data and doing standard add.\n" ));
//
// Create delete update entry for registry information and
// add to registration list. Clear registry in the mean time.
//
pregEntry->fRemove = TRUE; pregEntry->Flags |= DYNDNS_DEL_ENTRY; pregEntry->fRegisteredFWD = FALSE; pregEntry->fRegisteredPRI = FALSE; pregEntry->fRegisteredPTR = FALSE; if ( fPurgeMode ) { pregEntry->RetryCount = 2; pregEntry->RetryTime = Dns_GetCurrentTimeInSeconds(); } //
// Clear registry key for adapter
//
WriteUpdateEntryToRegistry( pregEntry ); //
// Put update in registration list
// - clear registry entry PTR so not used below
//
enqueueUpdate( pregEntry ); pregEntry = NULL;
// fall through to do standard add update with no prior data
} } }
//
// do updates
// - primary
// - adapter domain
// - alternate name
//
if ( ! pUpdateEntry->fRegisteredFWD ) { statusAdp = DoUpdate( pregEntry, pUpdateEntry, UPTYPE_DOMAIN ); } if ( ! pUpdateEntry->fRegisteredPRI ) { statusPri = DoUpdate( pregEntry, pUpdateEntry, UPTYPE_PRIMARY // primary update
); } if ( ! pUpdateEntry->fRegisteredALT ) { PSTR pname = pUpdateEntry->AlternateNames; DNS_STATUS statusTmp; DWORD count = 0;
//
// update each alternate name in MULTISZ
// - must set index in update blob to use correct name in
// record building
// - any failure fails ALT names
//
statusAlt = NO_ERROR;
while ( pname ) { pUpdateEntry->AlternateIndex = count++;
DNSDBG( DHCP, ( "Update with alternate name %s\n" "\tindex = %d\n", pname, count-1 ));
statusTmp = DoUpdate( NULL, // not saving alternate info in registry
// pregEntry,
pUpdateEntry, UPTYPE_ALTERNATE ); if ( statusTmp != NO_ERROR ) { statusAlt = statusTmp; } pname = MultiSz_NextString_A( pname ); }
pUpdateEntry->fRegisteredALT = (statusAlt == NO_ERROR); }
//
// update PTRs once forward done
//
// doing this outside DoUpdate() because will ONLY do PTRs
// for forwards that succeed, so want all forward updates
// completed first; but this also helps in that it combines
// the reverse updates
//
if (( pUpdateEntry->Flags & DYNDNS_REG_PTR) && g_RegisterReverseLookup) { UpdatePtrRecords( pUpdateEntry, !pUpdateEntry->fRemove // add update
); }
//
// write completed update info to registry
//
if ( !pUpdateEntry->fRemove ) { WriteUpdateEntryToRegistry( pUpdateEntry ); }
//
// setup retry on failure
//
if ( statusPri != NO_ERROR ) { status = statusPri; goto ErrorRetry; } else if ( statusAdp != NO_ERROR ) { status = statusAdp; goto ErrorRetry; } else if ( statusAlt != NO_ERROR ) { status = statusAlt; goto ErrorRetry; }
//
// successful update
// - signal update event (if given)
// - cleanup if remove or purging
// - requeue if add
//
if ( pUpdateEntry->pRegisterStatus ) { registerUpdateStatus( pUpdateEntry->pRegisterStatus, ERROR_SUCCESS ); }
if ( pUpdateEntry->fRemove || fPurgeMode || g_fPurgeRegistrations ) { DNSDBG( TRACE, ( "Leaving ProcessUpdate() => successful remove\\purge.\n" )); goto Cleanup; } else { pUpdateEntry->fNewElement = FALSE; pUpdateEntry->fRegisteredFWD = FALSE; pUpdateEntry->fRegisteredPRI = FALSE; pUpdateEntry->fRegisteredPTR = FALSE; pUpdateEntry->RetryCount = 0; pUpdateEntry->fDisableErrorLogging = TRUE; pUpdateEntry->RetryTime = Dns_GetCurrentTimeInSeconds() + g_RegistrationRefreshInterval;
if ( pUpdateEntry->pRegisterStatus ) { pUpdateEntry->pRegisterStatus = NULL; } enqueueUpdate( pUpdateEntry );
DNSDBG( TRACE, ( "Leaving ProcessUpdate( %p ) => successful => requeued.\n", pUpdateEntry ));
pUpdateEntry = NULL; goto Cleanup; }
ErrorRetry:
// failures during purge mode are not retried
// just free entry and bail
if ( fPurgeMode || g_fPurgeRegistrations ) { DNSDBG( TRACE, ( "Leaving ProcessUpdate() => failed purging.\n" )); goto Cleanup; }
//
// set retry time
//
// less than two retries and more transient errors
// => short retry
//
// third failure or longer term error code
// => push retry back to an hour
//
if ( pUpdateEntry->RetryCount < 2 && ( IsQuickRetryError(statusAdp) || IsQuickRetryError(statusPri) || IsQuickRetryError(statusAlt) ) ) { pUpdateEntry->RetryCount++; retryInterval = (pUpdateEntry->RetryCount == 1) ? FIRST_RETRY_INTERVAL : SECOND_RETRY_INTERVAL; } else { retryInterval = FAILED_RETRY_INTERVAL; pUpdateEntry->RetryCount = 0; pUpdateEntry->fDisableErrorLogging = TRUE;
if ( pUpdateEntry->pRegisterStatus ) { registerUpdateStatus( pUpdateEntry->pRegisterStatus, status ); pUpdateEntry->pRegisterStatus = NULL; } }
pUpdateEntry->fNewElement = FALSE; pUpdateEntry->RetryTime = Dns_GetCurrentTimeInSeconds() + retryInterval;
//
// requeue
// - entry dumped if another update for adapter already queued
//
enqueueUpdateMaybe( pUpdateEntry );
DNSDBG( TRACE, ( "Leaving ProcessUpdate( %p ) => failed => requeued.\n", pUpdateEntry ));
pUpdateEntry = NULL;
Cleanup:
//
// cleanup
// - registry entry
// - update entry if not requeued
//
FreeUpdateEntry( pregEntry ); FreeUpdateEntry( pUpdateEntry ); }
VOID ResetAdaptersInRegistry( VOID ) { DWORD retVal = NO_ERROR; DWORD status = NO_ERROR; CHAR szName[ MAX_PATH ]; HKEY hAdapterKey = NULL; DWORD dwType; INT index; DWORD dwBytesRead = MAX_PATH -1; DWORD dwRegistered = 0;
ASYNCREG_F1( "Inside function ResetAdaptersInRegistry" ); ASYNCREG_F1( "" );
index = 0;
while ( !retVal ) { dwBytesRead = MAX_PATH - 1;
retVal = RegEnumKeyEx ( g_hKey, index, szName, &dwBytesRead, NULL, NULL, NULL, NULL ); if ( retVal ) { goto Exit; }
status = RegOpenKeyEx( g_hKey, szName, 0, KEY_ALL_ACCESS, &hAdapterKey ); if ( status ) { goto Exit; }
//
// Found an adapter in the registry, set registered since
// boot to FALSE.
//
status = RegSetValueExA( hAdapterKey, REGISTERED_SINCE_BOOT, 0, REG_DWORD, (LPBYTE)&dwRegistered, // 0 - False
sizeof(DWORD) ); if ( status ) { goto Exit; }
RegCloseKey( hAdapterKey ); hAdapterKey = NULL; index++; }
Exit :
if ( hAdapterKey ) { RegCloseKey( hAdapterKey ); } }
VOID DeregisterUnusedAdapterInRegistry( IN BOOL fPurgeMode ) { DWORD retVal = NO_ERROR; DWORD status = NO_ERROR; CHAR szName[MAX_PATH]; HKEY hAdapterKey = NULL; INT index; DWORD dwBytesRead = MAX_PATH -1; DWORD dwRegistered = 0; PUPDATE_ENTRY pregEntry = NULL;
ASYNCREG_F1( "Inside function DeregisterUnusedAdapterInRegistry" ); ASYNCREG_F1( "" );
index = 0;
while ( !retVal ) { dwBytesRead = MAX_PATH - 1; retVal = RegEnumKeyEx ( g_hKey, index, szName, &dwBytesRead, NULL, NULL, NULL, NULL );
if ( retVal != ERROR_SUCCESS ) { goto Exit; }
status = RegOpenKeyEx( g_hKey, szName, 0, KEY_ALL_ACCESS, &hAdapterKey );
if ( status != ERROR_SUCCESS ) { goto Exit; }
//
// Found an adapter in the registry, read registered since
// boot value to see if FALSE.
//
status = GetRegistryValue( hAdapterKey, REGISTERED_SINCE_BOOT, REG_DWORD, (LPBYTE)&dwRegistered );
RegCloseKey( hAdapterKey ); hAdapterKey = NULL;
if ( status != ERROR_SUCCESS ) { goto Exit; }
if ( dwRegistered == 0 && (pregEntry = ReadUpdateEntryFromRegistry( szName )) ) { if ( pregEntry->fRegisteredFWD || pregEntry->fRegisteredPRI || pregEntry->fRegisteredPTR ) { ASYNCREG_F2( "Found unused adapter: %s", szName ); ASYNCREG_F1( "Removing entry from registry and adding" ); ASYNCREG_F1( "delete entry to registration list" );
//
// This adapter has not been configured since boot time,
// create delete update entry for registry information
// and add to registration list. Clear registry in the
// mean time.
//
pregEntry->fRemove = TRUE; pregEntry->Flags |= DYNDNS_DEL_ENTRY;
pregEntry->fRegisteredFWD = FALSE; pregEntry->fRegisteredPRI = FALSE; pregEntry->fRegisteredPTR = FALSE;
if ( fPurgeMode ) { pregEntry->RetryCount = 2; pregEntry->RetryTime = Dns_GetCurrentTimeInSeconds(); }
//
// Clear registry key for adapter
//
WriteUpdateEntryToRegistry( pregEntry ); index--;
//
// Put update in registration list
//
enqueueUpdate( pregEntry );
PulseEvent( g_hNewItemEvent ); } else { ASYNCREG_F2( "Found unused adapter: %s", szName ); ASYNCREG_F1( "This adapter is still pending an update, ignoring . . ." );
//
// We are only just starting to try to update this entry.
// Do not queue up a delete for it since the entry shows
// that no records have been registered anyhow.
//
FreeUpdateEntry( pregEntry ); pregEntry = NULL; } }
index++; }
Exit :
if ( hAdapterKey ) { RegCloseKey( hAdapterKey ); } }
PDNS_RECORD GetPreviousRegistrationInformation( IN PUPDATE_ENTRY pUpdateEntry, IN BOOL fPrimaryDomain, OUT PIP_ADDRESS pServerIp ) { DWORD retVal = NO_ERROR; DWORD status = NO_ERROR; CHAR szName[MAX_PATH]; INT index; DWORD dwBytesRead = MAX_PATH -1; DWORD dwRegistered = 0; PUPDATE_ENTRY pregEntry = NULL; PDNS_RECORD precords = NULL; PSTR pdomain;
DNSDBG( TRACE, ( "GetPreviousRegistrationInformation( %p )\n", pUpdateEntry ));
//
// determine desired domain name to use
//
if ( fPrimaryDomain ) { pdomain = pUpdateEntry->PrimaryDomainName; } else { pdomain = pUpdateEntry->DomainName; } if ( !pdomain ) { goto Exit; }
index = 0;
while ( !retVal ) { dwBytesRead = MAX_PATH - 1;
retVal = RegEnumKeyEx( g_hKey, index, szName, &dwBytesRead, NULL, NULL, NULL, NULL ); if ( retVal ) { goto Exit; }
//
// Skip past registry information for the given adapter name
//
if ( !_stricmp( szName, pUpdateEntry->AdapterName ) ) { index++; continue; }
//
// Found an adapter in the registry
//
pregEntry = ReadUpdateEntryFromRegistry( szName ); if ( pregEntry ) { //
// See if registered entry is related to update entry
// ( same HostName and DomainName )
//
if ( Dns_NameCompare_UTF8( pregEntry->HostName, pUpdateEntry->HostName ) && ( Dns_NameCompare_UTF8( pregEntry->DomainName, pdomain ) || Dns_NameCompare_UTF8( pregEntry->PrimaryDomainName, pdomain ) ) ) { BOOL fUsePrimary = TRUE;
if ( Dns_NameCompare_UTF8( pregEntry->DomainName, pdomain ) ) { fUsePrimary = FALSE; }
//
// PHASE 1 - COMPARE SOAS FROM REGISTRY AND UPDATE ENTRIES
// IF SAME, ADD TO LIST. ELSE, TOSS.
//
// PHASE 2 - COMPARE NS RECORDS FROM BOTH ENTRIES
// IF SAME ZONE AND SERVER, ADD TO LIST. ELSE, TOSS.
//
// PHASE 3 - COMPARE NS RECORDS FROM BOTH ENTRIES
// IF SAME ZONE AND THERE IS AN INTERSECTION OF
// SERVERS, ADD TO LIST. ELSE, TOSS.
// NOTE: FOR THIS PHASE, THERE HAD BETTER BE ALL
// SOAS RETURNED TO TEST INTERSECTION?
//
if ( CompareMultiAdapterSOAQueries( pdomain, pUpdateEntry->DnsServerList, pregEntry->DnsServerList ) ) { PDNS_RECORD prr;
//
// Convert registered entry to a PDNS_RECORD and
// add to current list
//
prr = CreateForwardRecords( pregEntry, fUsePrimary ); if ( prr ) { precords = Dns_RecordListAppend( precords, prr ); if ( pServerIp && *pServerIp == 0 && pUpdateEntry->RetryCount == 0 && pregEntry->SentUpdateToIp ) { *pServerIp = pregEntry->SentUpdateToIp; } } } }
FreeUpdateEntry( pregEntry ); pregEntry = NULL; }
index++; }
Exit:
DNSDBG( TRACE, ( "Leave GetPreviousRegistrationInformation()\n" "\tprevious records = %p\n", precords ));
return( precords ); }
PDNS_RECORD CreateDnsRecordSetUnion( IN PDNS_RECORD pSet1, IN PDNS_RECORD pSet2 ) { PDNS_RECORD pSet1Copy = NULL; PDNS_RECORD pSet2Copy = NULL;
pSet1Copy = Dns_RecordSetCopyEx( pSet1, DnsCharSetUtf8, DnsCharSetUtf8 ); if ( !pSet1Copy ) { return NULL; } pSet2Copy = Dns_RecordSetCopyEx( pSet2, DnsCharSetUtf8, DnsCharSetUtf8 ); if ( !pSet2Copy ) { Dns_RecordListFree( pSet1Copy ); return NULL; }
return Dns_RecordListAppend( pSet1Copy, pSet2Copy ); }
//
// Logging
//
#if 1 // DBG
VOID LogHostEntries( IN DWORD dwHostAddrCount, IN PREGISTER_HOST_ENTRY pHostAddrs ) { DWORD iter;
for ( iter = 0; iter < dwHostAddrCount; iter++ ) { ASYNCREG_F3( " HostAddrs[%d].dwOptions : 0x%x", iter, pHostAddrs[iter].dwOptions );
if ( pHostAddrs->dwOptions & REGISTER_HOST_A ) { ASYNCREG_F6( " HostAddrs[%d].Addr.ipAddr : %d.%d.%d.%d", iter, ((BYTE *) &pHostAddrs[iter].Addr.ipAddr)[0], ((BYTE *) &pHostAddrs[iter].Addr.ipAddr)[1], ((BYTE *) &pHostAddrs[iter].Addr.ipAddr)[2], ((BYTE *) &pHostAddrs[iter].Addr.ipAddr)[3] ); } else if ( pHostAddrs->dwOptions & REGISTER_HOST_AAAA ) { ASYNCREG_F6( " HostAddrs[%d].Addr.ipV6Addr : %d.%d.%d.%d", iter, ((DWORD *) &pHostAddrs[iter].Addr.ipV6Addr)[0], ((DWORD *) &pHostAddrs[iter].Addr.ipV6Addr)[1], ((DWORD *) &pHostAddrs[iter].Addr.ipV6Addr)[2], ((DWORD *) &pHostAddrs[iter].Addr.ipV6Addr)[3] ); } else { ASYNCREG_F1( "ERROR: HostAddrs[%d].Addr UNKNOWN ADDRESS TYPE!" ); } } }
#endif
#if 1 // DBG
VOID LogPipAddress( IN DWORD dwServerListCount, IN PIP_ADDRESS pServers ) { DWORD iter;
for ( iter = 0; iter < dwServerListCount; iter++ ) { ASYNCREG_F6( " Server [%d] : %d.%d.%d.%d", iter, ((BYTE *) &pServers[iter])[0], ((BYTE *) &pServers[iter])[1], ((BYTE *) &pServers[iter])[2], ((BYTE *) &pServers[iter])[3] ); } }
#endif
#if 1 // DBG
VOID LogPipArray( IN PIP_ARRAY pServers ) { DWORD count; DWORD iter;
if ( pServers ) { count = pServers->AddrCount; } else { return; }
for ( iter = 0; iter < count; iter++ ) { ASYNCREG_F6( " Server [%d] : %d.%d.%d.%d", iter, ((BYTE *) &pServers->AddrArray[iter])[0], ((BYTE *) &pServers->AddrArray[iter])[1], ((BYTE *) &pServers->AddrArray[iter])[2], ((BYTE *) &pServers->AddrArray[iter])[3] ); } }
#endif
DNS_STATUS alertOrStartRegistrationThread( VOID ) /*++
Routine Description:
Alerts registration thread of new update, starting thread if necessary.
This is called in registration\deregistration functions to ensure thread has been started.
Arguments:
None
Return Value:
ERROR_SUCCESS if successful. Error code on failure.
--*/ { DWORD threadId; DNS_STATUS Status;
ASYNCREG_F1( "Inside alertOrStartRegistrationThread()\n" );
//
// must lock to avoid multiple async start
//
// DCR_PERF: use a single general CS for init protect issues
// simply check
// - done => bail
// - not done => dumb wait (sleep, check)
//
EnterCriticalSection( &g_RegistrationThreadCS );
if ( g_hRegistrationThread ) { LeaveCriticalSection( &g_RegistrationThreadCS ); PulseEvent( g_hNewItemEvent );
return( ERROR_SUCCESS ); }
//
// if not started, fire it up
//
Status = ERROR_SUCCESS; g_fQuit = FALSE; g_fShutdown = FALSE; ResetEvent( g_hStopEvent ); ResetEvent( g_hThreadDeadEvent );
g_hRegistrationThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE) RegistrationThread, NULL, 0, & threadId );
if ( ! g_hRegistrationThread ) { Status = GetLastError(); }
LeaveCriticalSection( &g_RegistrationThreadCS ); return( Status ); }
VOID registerUpdateStatus( IN OUT PREGISTER_HOST_STATUS pRegstatus, IN DNS_STATUS Status ) /*++
Routine Description:
Set Status and signal completion.
Arguments:
pRegstatus -- registration Status block to indicate
Status -- Status to indicate
Return Value:
None
--*/ { // test for existence and event
if ( !pRegstatus || !pRegstatus->hDoneEvent ) { return; }
// set return Status
// signal event
pRegstatus->dwStatus = Status;
SetEvent( pRegstatus->hDoneEvent ); }
VOID enqueueUpdate( IN OUT PUPDATE_ENTRY pUpdate ) /*++
Routine Description:
Queue update on registration queue.
Arguments:
pUpdate -- update completed
Return Value:
None
--*/ { EnterCriticalSection( &g_RegistrationListCS ); InsertTailList( &g_RegistrationList, (PLIST_ENTRY)pUpdate ); LeaveCriticalSection( &g_RegistrationListCS ); }
VOID enqueueUpdateMaybe( IN OUT PUPDATE_ENTRY pUpdate ) /*++
Routine Description:
Queue update on registration queue, only if there does not exist any updates in the queue already for the given adapter.
Arguments:
pUpdate -- update completed
Return Value:
None
--*/ { PLIST_ENTRY plistHead; PLIST_ENTRY pentry; BOOL fAdd = TRUE;
EnterCriticalSection( &g_RegistrationListCS );
plistHead = &g_RegistrationList; pentry = plistHead->Flink;
while ( pentry != plistHead ) { if ( !_stricmp( ((PUPDATE_ENTRY) pentry)->AdapterName, pUpdate->AdapterName ) ) { fAdd = FALSE; break; }
pentry = pentry->Flink; }
if ( fAdd ) { InsertTailList( &g_RegistrationList, (PLIST_ENTRY)pUpdate ); } else { FreeUpdateEntry( pUpdate ); }
LeaveCriticalSection( &g_RegistrationListCS ); }
PLIST_ENTRY dequeueAndCleanupUpdate( IN OUT PLIST_ENTRY pUpdateEntry ) /*++
Routine Description:
Dequeue and free update.
Includes any registration Status setting.
Arguments:
pUpdateEntry -- pUpdateEntry
Return Value:
Ptr to next update in queue.
--*/ { PLIST_ENTRY pnext = pUpdateEntry->Flink;
RemoveEntryList( pUpdateEntry );
if ( ((PUPDATE_ENTRY)pUpdateEntry)->pRegisterStatus ) { registerUpdateStatus( ((PUPDATE_ENTRY)pUpdateEntry)->pRegisterStatus, ERROR_SUCCESS ); }
FreeUpdateEntry( (PUPDATE_ENTRY) pUpdateEntry );
return( pnext ); }
BOOL searchForOldUpdateEntriesAndCleanUp( IN PSTR pszAdapterName, IN PUPDATE_ENTRY pUpdateEntry, OPTIONAL IN BOOL fLookInRegistry ) /*++
Routine Description:
Searches registry for any previous registrations for a given adapter name and queues up a delete update entry for it. Then walks the update registration list to remove any add updates for the given adapter.
Arguments:
pszAdapterName -- name of adapters that is going away (disabled for DDNS or now removed).
Return Value:
Flag to indicate whether a delete update has been queued up ready to be processed.
--*/ { PUPDATE_ENTRY pregEntry = NULL; BOOL fReturn = FALSE; PLIST_ENTRY plistHead; PLIST_ENTRY pentry;
//
// See if this adapter has been previously registered
//
if ( fLookInRegistry && (pregEntry = ReadUpdateEntryFromRegistry( pszAdapterName )) ) { pregEntry->fRemove = TRUE; pregEntry->Flags |= DYNDNS_DEL_ENTRY;
pregEntry->fRegisteredFWD = FALSE; pregEntry->fRegisteredPRI = FALSE; pregEntry->fRegisteredPTR = FALSE;
//
// Clear registry key for adapter
//
WriteUpdateEntryToRegistry( pregEntry );
//
// Put update in registration list
//
enqueueUpdate( pregEntry );
fReturn = TRUE; // We have queued a delete update to process.
}
//
// Now walk the pending update list looking for updates that should
// be removed for the given adapter name.
//
EnterCriticalSection( &g_RegistrationListCS );
plistHead = &g_RegistrationList; pentry = plistHead->Flink;
while ( pentry != plistHead ) { if ( !_stricmp( ((PUPDATE_ENTRY) pentry)->AdapterName, pszAdapterName ) && !((PUPDATE_ENTRY) pentry)->fRemove ) { //
// There is an update entry in the registration list
// that has the same adapter name. We need to get rid of
// this entry since the adapter is being deleted.
//
if ( pUpdateEntry && compareUpdateEntries( (PUPDATE_ENTRY) pentry, pUpdateEntry ) ) { //
// The adapter entry in the queue is the same as the
// one being being processed. i.e. All of the adapter
// information seems to be the same and we must have
// just been called to refresh the adapter info in DNS.
// Since they are the same, if we have previously tried
// an update with these settings and failed and have
// already logged an event, then there is no reason to
// repeat the error event in the retries to follow
// on the new pUpdateEntry. That said, we'll copy over
// the flag from the queued update to the new one . . .
//
pUpdateEntry->fDisableErrorLogging = ((PUPDATE_ENTRY) pentry)->fDisableErrorLogging; }
pentry = dequeueAndCleanupUpdate( pentry ); continue; } else if ( !_stricmp( ((PUPDATE_ENTRY) pentry)->AdapterName, pszAdapterName ) ) { if ( !fLookInRegistry && pUpdateEntry && compareUpdateEntries( (PUPDATE_ENTRY) pentry, pUpdateEntry ) ) { //
// There is a delete update entry in the registration list
// that has the same adapter data. Get rid of this delete
// entry since the adapter is being updated again.
//
pentry = dequeueAndCleanupUpdate( pentry ); continue; } else { //
// There is a delete update entry in the registration list for
// the same adapter that contains different data, have the
// delete update set to new with a retry count of 2.
//
((PUPDATE_ENTRY) pentry)->fNewElement = TRUE; ((PUPDATE_ENTRY) pentry)->fRegisteredFWD = FALSE; ((PUPDATE_ENTRY) pentry)->fRegisteredPRI = FALSE; ((PUPDATE_ENTRY) pentry)->fRegisteredPTR = FALSE; ((PUPDATE_ENTRY) pentry)->fDisableErrorLogging = FALSE; ((PUPDATE_ENTRY) pentry)->RetryCount = 2; ((PUPDATE_ENTRY) pentry)->RetryTime = Dns_GetCurrentTimeInSeconds();
pentry = pentry->Flink; } } else { pentry = pentry->Flink; } }
LeaveCriticalSection( &g_RegistrationListCS );
return fReturn; }
BOOL compareHostEntryAddrs( IN PREGISTER_HOST_ENTRY Addrs1, IN PREGISTER_HOST_ENTRY Addrs2, IN DWORD Count ) { DWORD iter;
for ( iter = 0; iter < Count; iter++ ) { if ( ( Addrs1[iter].dwOptions & REGISTER_HOST_A ) && ( Addrs2[iter].dwOptions & REGISTER_HOST_A ) ) { if ( memcmp( &Addrs1[iter].Addr.ipAddr, &Addrs2[iter].Addr.ipAddr, sizeof( IP_ADDRESS ) ) ) { return FALSE; } } else if ( ( Addrs1[iter].dwOptions & REGISTER_HOST_AAAA ) && ( Addrs2[iter].dwOptions & REGISTER_HOST_AAAA ) ) { if ( memcmp( &Addrs1[iter].Addr.ipV6Addr, &Addrs2[iter].Addr.ipV6Addr, sizeof( IP6_ADDRESS ) ) ) { return FALSE; } } else { return FALSE; } }
return TRUE; }
//
// Routines for update entry comparison
//
BOOL compareServerLists( IN PIP_ARRAY List1, IN PIP_ARRAY List2 ) { if ( List1 && List2 ) { if ( List1->AddrCount != List2->AddrCount ) { return FALSE; }
if ( memcmp( List1->AddrArray, List2->AddrArray, sizeof( IP_ADDRESS ) * List1->AddrCount ) ) { return FALSE; } }
return TRUE; }
BOOL compareUpdateEntries( IN PUPDATE_ENTRY pUpdateEntry1, IN PUPDATE_ENTRY pUpdateEntry2 ) /*++
Routine Description:
Compares to update entries to see if they are describing the same adapter configuration settings. Tests the domain names, the IP address(es), host names, and the DNS server lists.
Arguments:
pUdapteEntry1 - one of the update entries to compare against the other. pUdapteEntry2 - one of the update entries to compare against the other.
Return Value:
Flag to indicate whether a the two updates are the same.
--*/ { if ( !pUpdateEntry1 || !pUpdateEntry2 ) { return FALSE; }
if ( ( pUpdateEntry1->HostName || pUpdateEntry2->HostName ) && !Dns_NameCompare_UTF8( pUpdateEntry1->HostName, pUpdateEntry2->HostName ) ) { return FALSE; }
if ( ( pUpdateEntry1->DomainName || pUpdateEntry2->DomainName ) && !Dns_NameCompare_UTF8( pUpdateEntry1->DomainName, pUpdateEntry2->DomainName ) ) { return FALSE; }
if ( ( pUpdateEntry1->PrimaryDomainName || pUpdateEntry2->PrimaryDomainName ) && ! Dns_NameCompare_UTF8( pUpdateEntry1->PrimaryDomainName, pUpdateEntry2->PrimaryDomainName ) ) { return FALSE; }
if ( pUpdateEntry1->HostAddrCount != pUpdateEntry2->HostAddrCount || ! compareHostEntryAddrs( pUpdateEntry1->HostAddrs, pUpdateEntry2->HostAddrs, pUpdateEntry1->HostAddrCount ) ) { return FALSE; }
if ( pUpdateEntry1->DnsServerList && pUpdateEntry2->DnsServerList && ! compareServerLists( pUpdateEntry1->DnsServerList, pUpdateEntry2->DnsServerList ) ) { return FALSE; }
return TRUE; }
//
// Glenn's old registry function
//
// No longer in use anywhere else but still used in these
// registration (dynreg and asyncreg) modules.
//
DWORD GetRegistryValue( HKEY KeyHandle, PSTR ValueName, DWORD ValueType, PBYTE BufferPtr ) /*++
Routine Description:
This function retrieves the value of the specified value field. This function allocates memory for variable length fields such as REG_SZ. For REG_DWORD data type, it copies the field value directly into BufferPtr. If fIsWin9X is NOT set, all string types are read as UNICODE (W) and then converted to UTF8 format. Currently it can handle only the following fields :
REG_DWORD, REG_SZ, REG_MULTI_SZ, REG_EXPAND_SZ REG_BINARY
Arguments:
KeyHandle : handle of the key whose value field is retrieved.
ValueName : name of the value field.
ValueType : Expected type of the value field.
BufferPtr : Pointer to DWORD location where a DWORD datatype value is returned or a buffer pointer for REG_SZ or REG_BINARY datatype value is returned.
Return Value:
Registry Errors.
--*/ { DWORD Error; DWORD LocalValueType; DWORD ValueSize; PBYTE DataBuffer = NULL; PBYTE AllotedBuffer = NULL; PWSTR ValueNameW = NULL;
//
// DCR_PERF: heap buffer for name is stupid (MAX_PATH covers it)
//
DWORD Length = ( strlen( ValueName ) + 1 ) * sizeof( WCHAR ); ValueNameW = ALLOCATE_HEAP( Length );
if ( !ValueNameW ) { return DNS_ERROR_NO_MEMORY; }
Dns_Utf8ToUnicode( ValueName, strlen( ValueName ), ValueNameW, Length );
//
// Query DataType and BufferSize.
//
Error = RegQueryValueExW( KeyHandle, ValueNameW, 0, &LocalValueType, NULL, &ValueSize );
if ( Error != ERROR_SUCCESS ) { FREE_HEAP( ValueNameW ); return(Error); }
switch( ValueType ) { case REG_DWORD: DataBuffer = BufferPtr; break;
case REG_SZ: case REG_MULTI_SZ: case REG_EXPAND_SZ: case REG_BINARY:
if ( ValueSize == 0 ) { //
// if string not found in the registry,
// allocate space for null string.
//
ValueSize = sizeof(WCHAR); }
AllotedBuffer = DataBuffer = ALLOCATE_HEAP( ValueSize );
if ( DataBuffer == NULL ) { return( DNS_ERROR_NO_MEMORY ); }
break;
default: FREE_HEAP( ValueNameW ); return( ERROR_INVALID_PARAMETER ); }
//
// retrieve data.
//
Error = RegQueryValueExW( KeyHandle, ValueNameW, 0, &LocalValueType, DataBuffer, &ValueSize );
FREE_HEAP( ValueNameW );
if ( Error != ERROR_SUCCESS ) { if ( AllotedBuffer ) { FREE_HEAP( AllotedBuffer ); }
*(DWORD *)BufferPtr = 0;
return(Error); } switch( ValueType ) { case REG_BINARY:
if ( ValueSize == 0 ) { //
// if string no found in the registry,
// return null string.
//
*(LPWSTR)DataBuffer = '\0'; }
*(LPBYTE *)BufferPtr = DataBuffer;
break;
case REG_SZ: case REG_EXPAND_SZ: case REG_MULTI_SZ:
if ( ValueSize == 0 ) { //
// if string no found in the registry,
// return null string.
//
*(LPWSTR)DataBuffer = '\0'; }
{ LPBYTE Utf8Buffer = ALLOCATE_HEAP( ValueSize * 2 );
if ( Utf8Buffer == NULL ) { return( DNS_ERROR_NO_MEMORY ); }
if ( !Dns_UnicodeToUtf8( (LPWSTR) DataBuffer, ValueSize / sizeof(WCHAR), Utf8Buffer, ValueSize * 2 ) ) { FREE_HEAP( DataBuffer ); return ERROR_INVALID_PARAMETER; }
FREE_HEAP( DataBuffer ); *(LPBYTE *)BufferPtr = Utf8Buffer; } break;
default: break; }
return( Error ); }
//
// Jim Utils
//
PDNS_RECORD CreatePtrRecord( IN PSTR pszHostName, IN PSTR pszDomainName, IN IP4_ADDRESS Ip4Addr, IN DWORD Ttl ) /*++
Routine Description:
Create PTR record for update from IP and host and domain names.
Arguments:
Return Value:
PTR record to use in update.
--*/ { IP_UNION ipUnion;
DNSDBG( TRACE, ( "CreatePtrRecord( %s, %s, %s )\n", pszHostName, pszDomainName, IP_STRING( Ip4Addr ) ));
IPUNION_SET_IP4( &ipUnion, Ip4Addr );
return Dns_CreatePtrRecordExEx( & ipUnion, pszHostName, pszDomainName, Ttl, DnsCharSetUtf8, // from UTF8
DnsCharSetUtf8 // to UTF8
); }
VOID UpdatePtrRecords( IN OUT PUPDATE_ENTRY pUpdateEntry, IN BOOL fAdd ) /*++
Routine Description:
Register PTR records for an update entry.
Arguments:
pUpdateEntry -- update being processed
fAdd -- TRUE for add; FALSE for delete
Return Value:
PTR record to use in update.
--*/ { DWORD iter; PDNS_RECORD prr = NULL; DNS_STATUS status = NO_ERROR; IP_ADDRESS ipServer; DNS_RRSET rrset; PSTR pdomain = NULL; PSTR pprimary = NULL; DWORD ttl = pUpdateEntry->TTL; PSTR phostname = pUpdateEntry->HostName;
DNSDBG( TRACE, ( "UpdatePtrRecords( %p, fAdd=%d )\n", pUpdateEntry, fAdd ));
IF_DNSDBG( TRACE ) { DnsDbg_UpdateEntry( "Entering UpdatePtrRecords:", pUpdateEntry ); }
//
// make sure we have update to do
// only do ADD updates if forward registrations were
// successful
//
pdomain = pUpdateEntry->DomainName; pprimary = pUpdateEntry->PrimaryDomainName;
if ( fAdd ) { if ( !pUpdateEntry->fRegisteredFWD ) { pdomain = NULL; } if ( !pUpdateEntry->fRegisteredPRI ) { pprimary = NULL; } } if ( !pdomain && !pprimary ) { DNSDBG( TRACE, ( "UpdatePtrRecords() => no forward registrations" "-- skipping PTR update.\n" )); return; }
//
// build PTR (or set) for each IP in update entry
//
for ( iter = 0; iter < pUpdateEntry->HostAddrCount; iter++ ) { IP4_ADDRESS ip = pUpdateEntry->HostAddrs[iter].Addr.ipAddr;
if ( ip == 0 || ip == DNS_NET_ORDER_LOOPBACK ) { DNS_ASSERT( FALSE ); continue; }
//
// build update PTR set
// - primary name
// - adapter name
//
DNS_RRSET_INIT( rrset );
if ( pprimary ) { prr = CreatePtrRecord( phostname, pprimary, ip, ttl ); if ( prr ) { DNS_RRSET_ADD( rrset, prr ); } } if ( pdomain ) { prr = CreatePtrRecord( phostname, pdomain, ip, ttl ); if ( prr ) { DNS_RRSET_ADD( rrset, prr ); } } prr = rrset.pFirstRR; if ( !prr ) { continue; }
//
// do update
//
// for ADD => replace, we own the IP address now
// for REMOVE => modify, as another update might have already
// written correct info
//
if ( fAdd ) { status = DnsReplaceRecordSetUTF8( prr, // update set
DNS_UPDATE_CACHE_SECURITY_CONTEXT, NULL, // no security context
(PIP4_ARRAY) pUpdateEntry->DnsServerList, NULL // reserved
); } else { status = DnsModifyRecordsInSet_UTF8( NULL, // no add records
prr, // delete records
DNS_UPDATE_CACHE_SECURITY_CONTEXT, NULL, // no context handle
pUpdateEntry->DnsServerList, NULL // reserved
); } DNSDBG( TRACE, ( "%s on PTRs for IP %s => %d (%s)\n", fAdd ? "Replace" : "Modify (remove)", IP_STRING(ip), status, Dns_StatusString(status) ));
ipServer = 0;
if ( status == NO_ERROR || // status == DNS_ERROR_RCODE_SERVER_FAILURE ||
status == DNS_ERROR_RCODE_NOT_IMPLEMENTED || status == DNS_ERROR_RCODE_REFUSED || status == DNS_ERROR_RCODE_YXRRSET || status == DNS_ERROR_RCODE_NXRRSET ) { ipServer = DnsGetLastServerUpdateIP(); }
if ( !fAdd || pUpdateEntry->RetryCount == 2 ) { LogRegistration( pUpdateEntry, status, UPTYPE_PTR, !fAdd, ipServer, ip ); }
// note successful PTR registrations (adds)
if ( fAdd && status==NO_ERROR ) { pUpdateEntry->fRegisteredPTR = TRUE; } Dns_RecordListFree( prr ); }
DNSDBG( TRACE, ( "Leave UpdatePtrRecords()\n" )); }
PDNS_RECORD CreateForwardRecords( IN PUPDATE_ENTRY pUpdateEntry, IN UPTYPE UpType ) /*++
Routine Description:
Create A records for update.
Arguments:
pUpdateEntry -- update entry
UpType -- update type UPTYPE_DOMAIN UPTYPE_PRIMARY UPTYPE_ALTERNATE
Return Value:
Ptr to list of A records.
--*/ { PDNS_RECORD prr = NULL; PSTR pname; DWORD iter; CHAR nameBuffer[ DNS_MAX_NAME_BUFFER_LENGTH ]; DNS_RRSET rrset;
DNSDBG( TRACE, ( "CreateForwardRecords( %p, %d )\n", pUpdateEntry, UpType ));
//
// build FQDN
//
// for alternate name, go to name for desired index
//
if ( IS_UPTYPE_ALTERNATE(UpType) ) { DWORD count = pUpdateEntry->AlternateIndex;
pname = pUpdateEntry->AlternateNames; while ( count-- ) { pname = MultiSz_NextString_A( pname ); if ( !pname ) { DNSDBG( ANY, ( "ERROR: Alternate count %d does NOT exist in name!\n", pUpdateEntry->AlternateIndex )); DNS_ASSERT( FALSE ); return NULL; } } DNSDBG( DHCP, ( "Create records with alternate name %s\n", pname )); } else { PSTR pdomain = pUpdateEntry->DomainName;
if ( IS_UPTYPE_PRIMARY(UpType) ) { pdomain = pUpdateEntry->PrimaryDomainName; } if ( !pdomain || !pUpdateEntry->HostName ) { return NULL; } if ( !Dns_NameAppend_A( nameBuffer, DNS_MAX_NAME_BUFFER_LENGTH, pUpdateEntry->HostName, pdomain ) ) { return NULL; } pname = nameBuffer; }
//
// create records for name
//
DNS_RRSET_INIT( rrset );
for ( iter = 0; iter < pUpdateEntry->HostAddrCount; iter++ ) { if ( !(pUpdateEntry->HostAddrs[iter].dwOptions & REGISTER_HOST_A) ) { continue; }
prr = Dns_CreateARecord( pname, pUpdateEntry->HostAddrs[iter].Addr.ipAddr, pUpdateEntry->TTL, DnsCharSetUtf8, DnsCharSetUtf8 ); if ( !prr ) { SetLastError( DNS_ERROR_NO_MEMORY ); Dns_RecordListFree( rrset.pFirstRR ); return NULL; }
DNS_RRSET_ADD( rrset, prr ); }
DNSDBG( TRACE, ( "Leave CreateForwardRecords() => %p\n", rrset.pFirstRR ));
return rrset.pFirstRR; }
VOID SetUpdateStatus( IN OUT PUPDATE_ENTRY pUpdateEntry, IN DNS_STATUS Status, IN UPTYPE UpType ) /*++
Routine Description:
Set update Status info in update entry.
Arguments:
pUpdateEntry -- entry to set Status in
Status -- result of update
fPrimary -- TRUE if update was for primary name; FALSE otherwise
Return Value:
None
--*/ { IP4_ADDRESS ipServer = 0; BOOL fregistered = FALSE;
DNSDBG( TRACE, ( "SetUpdateStatus()\n" ));
DNS_ASSERT( pUpdateEntry != NULL );
fregistered = ( Status == NO_ERROR ); ipServer = DnsGetLastServerUpdateIP();
if ( IS_UPTYPE_PRIMARY(UpType) ) { pUpdateEntry->SentPriUpdateToIp = ipServer; pUpdateEntry->fRegisteredPRI = fregistered; } else if ( IS_UPTYPE_DOMAIN(UpType) ) { pUpdateEntry->SentUpdateToIp = ipServer; pUpdateEntry->fRegisteredFWD = fregistered; } }
VOID DnsPrint_UpdateEntry( IN PRINT_ROUTINE PrintRoutine, IN OUT PPRINT_CONTEXT pContext, IN PSTR pszHeader, IN PUPDATE_ENTRY pEntry ) /*++
Routine Description:
Print update entry.
Arguments:
PrintRoutine - routine to print with
pszHeader - header
pEntry - ptr to update entry
Return Value:
None.
--*/ { DWORD i;
if ( !pszHeader ) { pszHeader = "Update Entry:"; }
if ( !pEntry ) { PrintRoutine( pContext, "%s %s\r\n", pszHeader, "NULL Update Entry ptr." ); return; }
// print the struct
PrintRoutine( pContext, "%s\r\n" "\tPtr = %p\n" "\tSignatureTop = %08x\n" "\tAdapterName = %s\n" "\tHostName = %s\n" "\tDomainName = %s\n" "\tPrimaryDomainName = %s\n" "\tAlternateName = %s\n" "\tAlternateIndex = %d\n" "\tHostAddrCount = %d\n" "\tHostAddrs = %p\n" "\tDnsServerList = %p\n" "\tSentUpdateToIp = %s\n" "\tSentPriUpdateToIp = %s\n" "\tTTL = %d\n" "\tFlags = %08x\n" "\tfNewElement = %d\n" "\tfFromRegistry = %d\n" "\tfRemove = %d\n" "\tfRegisteredFWD = %d\n" "\tfRegisteredPRI = %d\n" "\tfRegisteredPTR = %d\n" "\tfDisableLogging = %d\n" "\tRetryCount = %d\n" "\tRetryTime = %d\n" "\tpRegisterStatus = %p\n" "\tSignatureBottom = %08x\n", pszHeader, pEntry, pEntry->SignatureTop, pEntry->AdapterName, pEntry->HostName, pEntry->DomainName, pEntry->PrimaryDomainName, pEntry->AlternateNames, pEntry->AlternateIndex, pEntry->HostAddrCount, pEntry->HostAddrs, pEntry->DnsServerList, IP_STRING( pEntry->SentUpdateToIp ), IP_STRING( pEntry->SentPriUpdateToIp ), pEntry->TTL, pEntry->Flags, pEntry->fNewElement, pEntry->fFromRegistry, pEntry->fRemove, pEntry->fRegisteredFWD, pEntry->fRegisteredPRI, pEntry->fRegisteredPTR, pEntry->fDisableErrorLogging, pEntry->RetryCount, pEntry->RetryTime, pEntry->pRegisterStatus, pEntry->SignatureBottom ); }
VOID AsyncLogUpdateEntry( IN PSTR pszHeader, IN PUPDATE_ENTRY pEntry ) { if ( !pEntry ) { return; }
ASYNCREG_F2( " %s", pszHeader ); ASYNCREG_F1( " Update Entry" ); ASYNCREG_F1( " ______________________________________________________" ); ASYNCREG_F2( " AdapterName : %s", pEntry->AdapterName ); ASYNCREG_F2( " HostName : %s", pEntry->HostName ); ASYNCREG_F2( " DomainName : %s", pEntry->DomainName ); ASYNCREG_F2( " PrimaryDomainName : %s", pEntry->PrimaryDomainName ); ASYNCREG_F2( " HostAddrCount : %d", pEntry->HostAddrCount ); DNSLOG_HOST_ENTRYS( pEntry->HostAddrCount, pEntry->HostAddrs ); if ( pEntry->DnsServerList ) { DNSLOG_PIP_ARRAY( pEntry->DnsServerList ); } ASYNCREG_F2( " TTL : %d", pEntry->TTL ); ASYNCREG_F2( " Flags : %d", pEntry->Flags ); ASYNCREG_F2( " fNewElement : %d", pEntry->fNewElement ); ASYNCREG_F2( " fRemove : %d", pEntry->fRemove ); ASYNCREG_F2( " fRegisteredFWD : %d", pEntry->fRegisteredFWD ); ASYNCREG_F2( " fRegisteredPRI : %d", pEntry->fRegisteredPRI ); ASYNCREG_F2( " fRegisteredPTR : %d", pEntry->fRegisteredPTR ); ASYNCREG_F2( " RetryCount : %d", pEntry->RetryCount ); ASYNCREG_F2( " RetryTime : %d", pEntry->RetryTime ); ASYNCREG_F1( "" ); }
//
// Logging
//
DWORD RegistrationEventArray[6][6] = { EVENT_DNSAPI_REGISTRATION_FAILED_TIMEOUT, EVENT_DNSAPI_REGISTRATION_FAILED_SERVERFAIL, EVENT_DNSAPI_REGISTRATION_FAILED_NOTSUPP, EVENT_DNSAPI_REGISTRATION_FAILED_REFUSED, EVENT_DNSAPI_REGISTRATION_FAILED_SECURITY, EVENT_DNSAPI_REGISTRATION_FAILED_OTHER,
EVENT_DNSAPI_DEREGISTRATION_FAILED_TIMEOUT, EVENT_DNSAPI_DEREGISTRATION_FAILED_SERVERFAIL, EVENT_DNSAPI_DEREGISTRATION_FAILED_NOTSUPP, EVENT_DNSAPI_DEREGISTRATION_FAILED_REFUSED, EVENT_DNSAPI_DEREGISTRATION_FAILED_SECURITY, EVENT_DNSAPI_DEREGISTRATION_FAILED_OTHER,
EVENT_DNSAPI_REGISTRATION_FAILED_NOTSUPP_PRIMARY_DN, EVENT_DNSAPI_REGISTRATION_FAILED_REFUSED_PRIMARY_DN, EVENT_DNSAPI_REGISTRATION_FAILED_TIMEOUT_PRIMARY_DN, EVENT_DNSAPI_REGISTRATION_FAILED_SERVERFAIL_PRIMARY_DN, EVENT_DNSAPI_REGISTRATION_FAILED_SECURITY_PRIMARY_DN, EVENT_DNSAPI_REGISTRATION_FAILED_OTHER_PRIMARY_DN,
EVENT_DNSAPI_DEREGISTRATION_FAILED_NOTSUPP_PRIMARY_DN, EVENT_DNSAPI_DEREGISTRATION_FAILED_REFUSED_PRIMARY_DN, EVENT_DNSAPI_DEREGISTRATION_FAILED_TIMEOUT_PRIMARY_DN, EVENT_DNSAPI_DEREGISTRATION_FAILED_SERVERFAIL_PRIMARY_DN, EVENT_DNSAPI_DEREGISTRATION_FAILED_SECURITY_PRIMARY_DN, EVENT_DNSAPI_DEREGISTRATION_FAILED_OTHER_PRIMARY_DN,
EVENT_DNSAPI_PTR_REGISTRATION_FAILED_TIMEOUT, EVENT_DNSAPI_PTR_REGISTRATION_FAILED_SERVERFAIL, EVENT_DNSAPI_PTR_REGISTRATION_FAILED_NOTSUPP, EVENT_DNSAPI_PTR_REGISTRATION_FAILED_REFUSED, EVENT_DNSAPI_PTR_REGISTRATION_FAILED_SECURITY, EVENT_DNSAPI_PTR_REGISTRATION_FAILED_OTHER,
EVENT_DNSAPI_PTR_DEREGISTRATION_FAILED_TIMEOUT, EVENT_DNSAPI_PTR_DEREGISTRATION_FAILED_SERVERFAIL, EVENT_DNSAPI_PTR_DEREGISTRATION_FAILED_NOTSUPP, EVENT_DNSAPI_PTR_DEREGISTRATION_FAILED_REFUSED, EVENT_DNSAPI_PTR_DEREGISTRATION_FAILED_SECURITY, EVENT_DNSAPI_PTR_DEREGISTRATION_FAILED_OTHER };
//
// Map update status to index into table
//
// This is the outside -- fast varying -- index
//
#define EVENTINDEX_TIMEOUT (0)
#define EVENTINDEX_SERVFAIL (1)
#define EVENTINDEX_NOTSUPP (2)
#define EVENTINDEX_REFUSED (3)
#define EVENTINDEX_SECURITY (4)
#define EVENTINDEX_OTHER (5)
//
// Map adapter, primary, PTR registration into index into table
//
// This index +0 for reg, +1 for dereg gives inside index into
// event table.
//
#define EVENTINDEX_ADAPTER (0)
#define EVENTINDEX_PRIMARY (2)
#define EVENTINDEX_PTR (4)
DWORD GetUpdateEventId( IN DNS_STATUS Status, IN UPTYPE UpType, IN BOOL fDeregister, OUT PDWORD pdwLevel ) /*++
Routine Description:
Get event ID.
Arguments:
Status -- status from update call
fDeregister -- TRUE if deregistration, FALSE for registration
fPtr -- TRUE if PTR, FALSE for forward
fPrimary -- TRUE for primary domain name
Return Value:
Event Id. Zero if no event.
--*/ { DWORD level = EVENTLOG_WARNING_TYPE; DWORD statusIndex; DWORD typeIndex;
//
// find status code
//
switch ( Status ) { case NO_ERROR :
// success logging in disabled
return 0;
case ERROR_TIMEOUT:
statusIndex = EVENTINDEX_TIMEOUT; break;
case DNS_ERROR_RCODE_SERVER_FAILURE:
statusIndex = EVENTINDEX_SERVFAIL; break;
case DNS_ERROR_RCODE_NOT_IMPLEMENTED:
// NOT_IMPL means no update on DNS server, not a client
// specific problem so informational level
statusIndex = EVENTINDEX_NOTSUPP; level = EVENTLOG_INFORMATION_TYPE; break;
case DNS_ERROR_RCODE_REFUSED:
statusIndex = EVENTINDEX_REFUSED; break;
case DNS_ERROR_RCODE_BADSIG: case DNS_ERROR_RCODE_BADKEY: case DNS_ERROR_RCODE_BADTIME:
statusIndex = EVENTINDEX_SECURITY; break;
default:
statusIndex = EVENTINDEX_OTHER; break; }
//
// determine interior index for type of update
// - all PTR logging is at informational level
// - dereg events are one group behind registration events
// in table; just inc index
if ( IS_UPTYPE_PTR(UpType) ) { typeIndex = EVENTINDEX_PTR; } else if ( IS_UPTYPE_PRIMARY(UpType) ) { typeIndex = EVENTINDEX_PRIMARY; } else { typeIndex = EVENTINDEX_ADAPTER; }
if ( fDeregister ) { typeIndex++; }
//
// get event from table
//
*pdwLevel = level;
return RegistrationEventArray[ typeIndex ][ statusIndex ]; }
VOID LogRegistration( IN PUPDATE_ENTRY pUpdateEntry, IN DNS_STATUS Status, IN DWORD UpType, IN BOOL fDeregister, IN IP4_ADDRESS DnsIp, IN IP4_ADDRESS UpdateIp ) /*++
Routine Description:
Log register\deregister failure.
Arguments:
pUpdateEntry -- update entry being executed
Status -- status from update call
Type -- UPTYPE (PRIMARY, ADAPTER, PTR)
fDeregister -- TRUE if deregistration, FALSE for registration
DnsIp -- DNS server IP that failed update
UpdateIp -- IP we tried to update
Return Value:
None
--*/ { PSTR insertStrings[ 7 ]; CHAR serverIpBuffer[ IP4_ADDRESS_STRING_BUFFER_LENGTH ]; CHAR serverListBuffer[ (IP4_ADDRESS_STRING_BUFFER_LENGTH+2)*9 ]; CHAR ipListBuffer[ (IP4_ADDRESS_STRING_BUFFER_LENGTH+2)*9 ]; CHAR hostnameBuffer[ DNS_MAX_NAME_BUFFER_LENGTH ]; CHAR domainBuffer[ DNS_MAX_NAME_BUFFER_LENGTH*2 ]; CHAR errorCodeBuffer[ 25 ]; DWORD iter; IP4_ADDRESS ip; PSTR pname; DWORD eventId; DWORD level;
DNSDBG( TRACE, ( "LogRegistration()\n" "\tpEntry = %p\n" "\tStatus = %d\n" "\tUpType = %d\n" "\tfDereg = %d\n" "\tDNS IP = %s\n" "\tUpdate IP = %s\n", pUpdateEntry, Status, UpType, fDeregister, IP_STRING( DnsIp ), IP_STRING( UpdateIp ) ));
//
// not logging?
// - no success logging
// - disabled
// - on DNS server (which registers itself)
//
if ( Status == NO_ERROR || pUpdateEntry->fDisableErrorLogging || g_IsDnsServer ) { return; }
//
// adapter name
//
insertStrings[0] = pUpdateEntry->AdapterName;
//
// hostname
//
Dns_NameCopy( (PCHAR) hostnameBuffer, NULL, pUpdateEntry->HostName, 0, DnsCharSetUtf8, DnsCharSetAnsi );
insertStrings[1] = hostnameBuffer;
//
// domain name
// - name depends on type
// - if no name, no logging
if ( IS_UPTYPE_PTR(UpType) ) { pname = pUpdateEntry->PrimaryDomainName; if ( !pname ) { pname = pUpdateEntry->DomainName; } } else if ( IS_UPTYPE_PRIMARY(UpType) ) { pname = pUpdateEntry->PrimaryDomainName; } else { pname = pUpdateEntry->DomainName; }
if ( !pname ) { return; }
Dns_NameCopy( (PCHAR) domainBuffer, NULL, pname, 0, DnsCharSetUtf8, DnsCharSetAnsi );
insertStrings[2] = domainBuffer;
//
// DNS server list
// - layout comma separated, four per line, limit 8
{ PCHAR pch = serverListBuffer; DWORD count = 0;
*pch = 0;
if ( pUpdateEntry->DnsServerList ) { count = pUpdateEntry->DnsServerList->AddrCount; }
for ( iter=0; iter < count; iter++ ) { if ( iter == 0 ) { strcpy( pch, "\t" ); pch++; } else { *pch++ = ','; *pch++ = ' ';
if ( iter == 4 ) { strcpy( pch, "\r\n\t" ); pch += 3; } else if ( iter > 8 ) { strcpy( pch, "..." ); break; } } pch = Dns_Ip4AddressToString_A( pch, & pUpdateEntry->DnsServerList->AddrArray[iter] ); }
if ( pch == serverListBuffer ) { strcpy( serverListBuffer, "\t<?>" ); } insertStrings[3] = serverListBuffer; }
//
// DNS server IP
//
ip = DnsIp; if ( ip == 0 ) { if ( IS_UPTYPE_PRIMARY(UpType) ) { ip = pUpdateEntry->SentPriUpdateToIp; } else { ip = pUpdateEntry->SentUpdateToIp; } } if ( ip ) { sprintf( serverIpBuffer, "%d.%d.%d.%d", (ip & 0xff), ((ip>8) & 0xff), ((ip>16) & 0xff), ((ip>24) & 0xff) ); } else { strcpy( serverIpBuffer, "<?>" ); }
insertStrings[4] = serverIpBuffer;
//
// Update IP
// - passed in (for PTR)
// - OR get IP list from update entry
// - layout comma separated, four per line, limit 8
//
ip = UpdateIp; if ( ip ) { sprintf( ipListBuffer, "%d.%d.%d.%d", (ip & 0xff), ((ip>8) & 0xff), ((ip>16) & 0xff), ((ip>24) & 0xff) ); } else { DWORD count = pUpdateEntry->HostAddrCount; PCHAR pch = ipListBuffer;
*pch = 0;
for ( iter=0; iter < count; iter++ ) { if ( iter > 0 ) { *pch++ = ','; *pch++ = ' ';
if ( iter == 4 ) { strcpy( pch, "\r\n\t" ); pch += 3; } else if ( iter > 8 ) { strcpy( pch, "..." ); break; } } pch = Dns_Ip4AddressToString_A( pch, & pUpdateEntry->HostAddrs[iter].Addr.ipAddr ); }
if ( pch == ipListBuffer ) { strcpy( ipListBuffer, "<?>" ); } } insertStrings[5] = ipListBuffer;
// terminate insert string array
insertStrings[6] = NULL;
//
// get event ID for type of update and update status
//
eventId = GetUpdateEventId( Status, UpType, fDeregister, & level ); if ( !eventId ) { DNS_ASSERT( FALSE ); return; }
//
// log the event
//
DNSDBG( TRACE, ( "Logging registration event:\n" "\tid = %d\n" "\tlevel = %d\n" "\tstatus = %d\n" "\tfor uptype = %d\n", eventId, level, Status, UpType ));
DnsLogEvent( eventId, (WORD) level, 7, insertStrings, Status ); }
//
// End asyncreg.c
//
|