6408 lines
158 KiB
C
6408 lines
158 KiB
C
/*++
|
||
|
||
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
|
||
//
|