mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
6407 lines
158 KiB
6407 lines
158 KiB
/*++
|
|
|
|
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
|
|
//
|