4809 lines
98 KiB
C++
4809 lines
98 KiB
C++
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
rdns.cxx
|
|
|
|
Abstract:
|
|
|
|
Reverse DNS service
|
|
|
|
Author:
|
|
|
|
Philippe Choquier (phillich) 5-june-1996
|
|
|
|
--*/
|
|
|
|
// only need async if not every HTTP req ends up calling DNS resolution
|
|
// if async then potentially 100s of HTTP requests
|
|
// so should be sync.
|
|
|
|
// Bind(addr) @ session start
|
|
// Init(BLOB) / CheckAccess( callbakc ) / Terminate()
|
|
// callback : yes or no, post empty completion status
|
|
|
|
#define dllexp __declspec( dllexport )
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#include <winsock2.h>
|
|
#include <time.h>
|
|
#include <stdio.h>
|
|
#include <malloc.h>
|
|
#include <windns.h>
|
|
|
|
#include <iis64.h>
|
|
#include <dbgutil.h>
|
|
|
|
#include <rdns.hxx>
|
|
#include <issched.hxx>
|
|
#include <isplat.h>
|
|
#include <inetsvcs.h>
|
|
|
|
#define DN_LEN 64
|
|
|
|
#define RDNS_REG_KEY "SYSTEM\\CurrentControlSet\\Services\\InetInfo\\Parameters"
|
|
#define RDNS_REG_MAX_THREAD "DnsMaxThread"
|
|
#define RDNS_REG_CACHE_SIZE "DnsCacheSizeInK"
|
|
#define RDNS_REG_TTL "DnsTTLInSeconds"
|
|
#define RDNS_REG_MAX_THREAD_DEF 0
|
|
#define RDNS_REG_CACHE_SIZE_DEF 256
|
|
// in seconds
|
|
#define RDNS_REG_TTL_DEF (20*60)
|
|
|
|
|
|
#define RDNS_SCAVENGER_GRANULARITY (2*60)
|
|
|
|
#define XBF_EXTEND 64
|
|
#define RDNS_HASH_SIZE 1021
|
|
|
|
#define ENTRYPTR( a, b ) (a+b-1)
|
|
|
|
#define LOCALHOST_ADDRESS 0x0100007F // 127.0.0.1
|
|
|
|
//
|
|
// Local classes
|
|
//
|
|
|
|
class RDnsCacheEntry {
|
|
public:
|
|
BOOL Init( UINT i );
|
|
void Reset();
|
|
//
|
|
UINT RemoveFromPrio( RDnsCacheEntry* );
|
|
UINT RemoveFromHash( RDnsCacheEntry* );
|
|
void InsertInPrioBefore( RDnsCacheEntry*, UINT );
|
|
void InsertInHashBefore( RDnsCacheEntry*, UINT );
|
|
UINT GetNextHash() { return m_pHashNext; }
|
|
UINT GetNextPrio() { return m_pPrioNext; }
|
|
BOOL MatchAddr(struct sockaddr *, time_t tNow );
|
|
BOOL MatchName(LPSTR pszName, time_t tNow );
|
|
BOOL CopyName(LPSTR pszResult, DWORD dwResMaxLen)
|
|
{
|
|
UINT l = strlen(m_achName) + 1;
|
|
if ( dwResMaxLen >= l )
|
|
{
|
|
memcpy( pszResult, m_achName, l );
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
BOOL CopyAddr( sockaddr* p )
|
|
{
|
|
memcpy( p, &m_addr, sizeof(m_addr) ); return TRUE;
|
|
}
|
|
DWORD GetHash() { return m_h; }
|
|
void SetFree() { m_fIsFree = TRUE; }
|
|
BOOL Store(struct sockaddr *pAddr, DWORD h, time_t Expire, LPSTR pszName );
|
|
BOOL Expired( time_t tNow ) { return !m_fIsFree && m_Expire <= tNow; }
|
|
BOOL IsIp2Dns() { return m_fIsIp2Dns; }
|
|
VOID SetIsIp2Dns( BOOL f ) { m_fIsIp2Dns = f; }
|
|
|
|
private:
|
|
struct sockaddr m_addr;
|
|
CHAR m_achName[DN_LEN];
|
|
UINT m_pHashNext;
|
|
UINT m_pHashPrev;
|
|
UINT m_pPrioNext;
|
|
UINT m_pPrioPrev;
|
|
UINT m_iIndex;
|
|
DWORD m_h;
|
|
BOOL m_fIsFree;
|
|
time_t m_Expire;
|
|
BOOL m_fIsIp2Dns;
|
|
} ;
|
|
|
|
|
|
class RDnsDict {
|
|
|
|
public:
|
|
BOOL Init()
|
|
{
|
|
m_cAlloc = 0;
|
|
m_cSize = 0;
|
|
INITIALIZE_CRITICAL_SECTION( &m_csLock );
|
|
if ( m_FreeList = Append() )
|
|
{
|
|
ENTRYPTR(m_pV,m_FreeList)->Init( m_FreeList );
|
|
}
|
|
if ( m_PrioList = Append() )
|
|
{
|
|
ENTRYPTR(m_pV,m_PrioList)->Init( m_PrioList );
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void Terminate()
|
|
{
|
|
if (m_cAlloc )
|
|
{
|
|
LocalFree( m_pV );
|
|
}
|
|
|
|
DeleteCriticalSection( &m_csLock );
|
|
}
|
|
|
|
void Lock() { EnterCriticalSection( &m_csLock ); }
|
|
void Unlock() { LeaveCriticalSection( &m_csLock ); }
|
|
|
|
// Append an entry
|
|
|
|
UINT NewEntry( struct sockaddr *pAddr, DWORD h, time_t Expire, LPSTR pszName );
|
|
UINT NewDns2IpEntry( struct sockaddr *pAddr, DWORD h, time_t Expire, LPSTR pszName );
|
|
DWORD ComputeHash( struct sockaddr* pAddr );
|
|
DWORD ComputeHash( LPSTR pszName );
|
|
BOOL Search( struct sockaddr* pAddr, DWORD h, LPSTR pszResult, DWORD dwResMaxLen );
|
|
BOOL SearchByName( struct sockaddr* pAddr, DWORD h, LPSTR pszName );
|
|
UINT GetFreeEntry();
|
|
UINT Append();
|
|
void FreeEntry( UINT i);
|
|
void Scavenger();
|
|
|
|
private:
|
|
UINT m_cAlloc; // allocated memory
|
|
UINT m_cSize; // used memory
|
|
CRITICAL_SECTION m_csLock;
|
|
RDnsCacheEntry* m_pV;
|
|
UINT m_PrioList;
|
|
UINT m_FreeList;
|
|
UINT m_pHash[RDNS_HASH_SIZE];
|
|
UINT m_pDns2IpHash[RDNS_HASH_SIZE];
|
|
} ;
|
|
|
|
|
|
//
|
|
// Local functions
|
|
//
|
|
|
|
VOID
|
|
AddrCheckDnsCallBack(
|
|
DNSARG p,
|
|
BOOL fSt,
|
|
LPSTR pDns
|
|
);
|
|
|
|
VOID
|
|
AddrCheckDnsCallBack2(
|
|
DNSARG p,
|
|
BOOL fSt,
|
|
LPSTR pDns
|
|
);
|
|
|
|
VOID
|
|
AddrCheckDnsCallBack3(
|
|
DNSARG p,
|
|
BOOL fSt,
|
|
LPSTR pDns
|
|
);
|
|
|
|
VOID
|
|
ResolveDnsCallBack(
|
|
DNSARG p,
|
|
BOOL fSt,
|
|
LPSTR pDns
|
|
);
|
|
|
|
//
|
|
// globals
|
|
//
|
|
|
|
DWORD g_cCacheSize = RDNS_REG_CACHE_SIZE_DEF * 1024;
|
|
DWORD g_cTTL = RDNS_REG_TTL_DEF;
|
|
HANDLE g_hThreadsTerminated = NULL;
|
|
HANDLE g_hDnsPort = NULL;
|
|
UINT g_cThreads;
|
|
UINT g_cMaxThreadLimit = RDNS_REG_MAX_THREAD_DEF;
|
|
long g_cAvailableThreads;
|
|
RDnsDict g_RDns;
|
|
CSidCache * g_pscPen = NULL;
|
|
DWORD g_dwScavengerWorkItem = NULL;
|
|
BOOL g_fEnableRdns = TRUE;
|
|
DNSFUNCDESC g_Dns2Ip = { RDNS_REQUEST_TYPE_DNS2IP, ::AddrCheckDnsCallBack2 };
|
|
DNSFUNCDESC g_Ip2Dns = { RDNS_REQUEST_TYPE_IP2DNS, ::AddrCheckDnsCallBack};
|
|
DNSFUNCDESC g_ResolveDns = { RDNS_REQUEST_TYPE_IP2DNS, ::ResolveDnsCallBack};
|
|
DNSFUNCDESC g_ResolveDns2Ip = { RDNS_REQUEST_TYPE_DNS2IP, ::AddrCheckDnsCallBack3 };
|
|
BYTE NULL_IP_ADDR[]="\x00\x00\x00\x00";
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
dllexp
|
|
BOOL
|
|
PenAddToCache(
|
|
PSID pS,
|
|
DWORD dwTTL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add to Pwd Exp Notification cache
|
|
|
|
Arguments:
|
|
|
|
pS - ptr to SID to add to cache
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
DBG_ASSERT(g_fEnableRdns);
|
|
return g_pscPen->AddToCache( pS, dwTTL );
|
|
}
|
|
|
|
|
|
dllexp
|
|
BOOL
|
|
PenIsInCache(
|
|
PSID pS
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check if SID in Pwd Exp Notification cache
|
|
|
|
Arguments:
|
|
|
|
pS - ptr to SID to check
|
|
|
|
Return Value:
|
|
|
|
TRUE if SID in cache, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
DBG_ASSERT(g_fEnableRdns);
|
|
return g_pscPen->IsInCache( pS );
|
|
}
|
|
|
|
|
|
dllexp
|
|
BOOL
|
|
PenCheckPresentAndResetTtl(
|
|
PSID pS,
|
|
DWORD dwTtl
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check if SID in Pwd Exp Notification cache
|
|
and update TTL
|
|
|
|
Arguments:
|
|
|
|
pS - ptr to SID to check
|
|
dwTtl - new TTL value
|
|
|
|
Return Value:
|
|
|
|
TRUE if SID in cache, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
DBG_ASSERT(g_fEnableRdns);
|
|
return g_pscPen->CheckPresentAndResetTtl( pS, dwTtl );
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
BOOL
|
|
RDnsCacheEntry::Init(
|
|
UINT i
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize a cache entry
|
|
|
|
Arguments:
|
|
|
|
i - index (1-based) of this entry in the dict array
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
DBG_ASSERT(g_fEnableRdns);
|
|
m_iIndex = i;
|
|
Reset();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void
|
|
RDnsCacheEntry::Reset(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reset a cache entry
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
{
|
|
DBG_ASSERT(g_fEnableRdns);
|
|
m_pHashNext = NULL; // non-circular list
|
|
m_pHashPrev = NULL;
|
|
m_pPrioNext = m_iIndex; // circular list
|
|
m_pPrioPrev = m_iIndex;
|
|
|
|
m_fIsFree = TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
RDnsCacheEntry::MatchAddr(
|
|
struct sockaddr * pAddr,
|
|
time_t tNow
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check if entry match specified address and not expired
|
|
|
|
Arguments:
|
|
|
|
pAddr - ptr to address
|
|
tNow - current time
|
|
|
|
Return Value:
|
|
|
|
TRUE if match and not expired, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
int l;
|
|
LPBYTE p1;
|
|
LPBYTE p2;
|
|
|
|
DBG_ASSERT(g_fEnableRdns);
|
|
switch ( pAddr->sa_family )
|
|
{
|
|
case AF_INET:
|
|
l = SIZEOF_IP_ADDRESS;
|
|
p1 = (LPBYTE)(&((PSOCKADDR_IN)pAddr)->sin_addr);
|
|
p2 = (LPBYTE)(&((PSOCKADDR_IN)&m_addr)->sin_addr);
|
|
break;
|
|
#if 0
|
|
case AF_IPX:
|
|
l = 6;
|
|
p1 = (LPBYTE)(((PSOCKADDR)pAddr)->sa_data);
|
|
p2 = (LPBYTE)(((PSOCKADDR)&m_addr)->sa_data);
|
|
break;
|
|
#endif
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
return !memcmp( p1, p2, l ) && m_Expire > tNow;
|
|
}
|
|
|
|
|
|
BOOL
|
|
RDnsCacheEntry::MatchName(
|
|
LPSTR pszName,
|
|
time_t tNow
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check if entry match specified DNS name and not expired
|
|
|
|
Arguments:
|
|
|
|
pszName - ptr to DNS name
|
|
tNow - current time
|
|
|
|
Return Value:
|
|
|
|
TRUE if match and not expired, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
DBG_ASSERT(g_fEnableRdns);
|
|
|
|
return !strcmp( pszName, m_achName ) && m_Expire > tNow;
|
|
}
|
|
|
|
|
|
BOOL
|
|
RDnsCacheEntry::Store(
|
|
struct sockaddr *pAddr,
|
|
DWORD h,
|
|
time_t Expire,
|
|
LPSTR pszName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Store a address<>name pair with expiration time
|
|
|
|
Arguments:
|
|
|
|
pAddr - ptr to address
|
|
h - hash value of this address
|
|
Expire - expiration time
|
|
pszName - DNS name
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
int l;
|
|
|
|
DBG_ASSERT(g_fEnableRdns);
|
|
memcpy( &m_addr, pAddr, sizeof(m_addr) );
|
|
if ( (l=strlen(pszName)+1) <= sizeof(m_achName) )
|
|
{
|
|
memcpy( m_achName, pszName, l );
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
m_h = h;
|
|
m_fIsFree = FALSE;
|
|
m_Expire = Expire;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
UINT
|
|
RDnsCacheEntry::RemoveFromPrio(
|
|
RDnsCacheEntry* pE
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Remove from priority list
|
|
|
|
Arguments:
|
|
|
|
pE - ptr to base of array
|
|
|
|
Return Value:
|
|
|
|
next index in the priority list
|
|
|
|
--*/
|
|
{
|
|
DBG_ASSERT(g_fEnableRdns);
|
|
if ( m_pPrioPrev )
|
|
{
|
|
ENTRYPTR(pE,m_pPrioPrev)->m_pPrioNext = m_pPrioNext;
|
|
}
|
|
if ( m_pPrioNext )
|
|
{
|
|
ENTRYPTR(pE,m_pPrioNext)->m_pPrioPrev = m_pPrioPrev;
|
|
}
|
|
|
|
return m_pPrioNext;
|
|
}
|
|
|
|
|
|
void
|
|
RDnsCacheEntry::InsertInPrioBefore(
|
|
RDnsCacheEntry* pE,
|
|
UINT i
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Insert in priority list after specified index
|
|
|
|
Arguments:
|
|
|
|
pE - ptr to base of array
|
|
i - index of element to insert before
|
|
|
|
Return Value:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
{
|
|
m_pPrioPrev = NULL;
|
|
|
|
DBG_ASSERT(g_fEnableRdns);
|
|
if ( i )
|
|
{
|
|
UINT iPrev = ENTRYPTR(pE,i)->m_pPrioPrev;
|
|
ENTRYPTR(pE,i)->m_pPrioPrev = m_iIndex;
|
|
if ( iPrev )
|
|
{
|
|
ENTRYPTR(pE,iPrev)->m_pPrioNext = m_iIndex;
|
|
m_pPrioPrev = iPrev;
|
|
}
|
|
}
|
|
m_pPrioNext = i;
|
|
}
|
|
|
|
|
|
UINT
|
|
RDnsCacheEntry::RemoveFromHash(
|
|
RDnsCacheEntry* pE
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Remove from hash list
|
|
|
|
Arguments:
|
|
|
|
pE - ptr to base of array
|
|
|
|
Return Value:
|
|
|
|
next index in the hash list
|
|
|
|
--*/
|
|
{
|
|
DBG_ASSERT(g_fEnableRdns);
|
|
if ( m_pHashPrev )
|
|
{
|
|
ENTRYPTR(pE,m_pHashPrev)->m_pHashNext = m_pHashNext;
|
|
}
|
|
if ( m_pHashNext )
|
|
{
|
|
ENTRYPTR(pE,m_pHashNext)->m_pHashPrev = m_pHashPrev;
|
|
}
|
|
|
|
return m_pHashNext;
|
|
}
|
|
|
|
|
|
void
|
|
RDnsCacheEntry::InsertInHashBefore(
|
|
RDnsCacheEntry* pE,
|
|
UINT i
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Insert in hash list after specified index
|
|
|
|
Arguments:
|
|
|
|
pE - ptr to base of array
|
|
i - index of element to insert before
|
|
|
|
Return Value:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
{
|
|
m_pHashPrev = NULL;
|
|
|
|
DBG_ASSERT(g_fEnableRdns);
|
|
if ( i )
|
|
{
|
|
UINT iPrev = ENTRYPTR(pE,i)->m_pHashPrev;
|
|
ENTRYPTR(pE,i)->m_pHashPrev = m_iIndex;
|
|
if ( iPrev )
|
|
{
|
|
ENTRYPTR(pE,iPrev)->m_pHashNext = m_iIndex;
|
|
m_pHashPrev = iPrev;
|
|
}
|
|
}
|
|
m_pHashNext = i;
|
|
}
|
|
|
|
|
|
UINT
|
|
RDnsDict::NewEntry(
|
|
struct sockaddr *pAddr,
|
|
DWORD h,
|
|
time_t Expire,
|
|
LPSTR pszName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Store a address<>name pair with expiration time
|
|
|
|
Arguments:
|
|
|
|
pAddr - ptr to address
|
|
h - hash value of this address
|
|
Expire - expiration time
|
|
pszName - DNS name
|
|
|
|
Return Value:
|
|
|
|
index (1-based) of new entry, NULL if error
|
|
|
|
--*/
|
|
{
|
|
DBG_ASSERT(g_fEnableRdns);
|
|
Lock();
|
|
UINT i = GetFreeEntry();
|
|
|
|
if ( i )
|
|
{
|
|
RDnsCacheEntry *p = ENTRYPTR(m_pV,i);
|
|
|
|
if ( !p->Store( pAddr, h, Expire, pszName ) )
|
|
{
|
|
// put back on free list
|
|
p->InsertInPrioBefore( m_pV, m_FreeList );
|
|
i = NULL;
|
|
}
|
|
else
|
|
{
|
|
p->InsertInPrioBefore( m_pV, m_PrioList );
|
|
p->InsertInHashBefore( m_pV, m_pHash[h] );
|
|
m_pHash[h] = i;
|
|
}
|
|
|
|
p->SetIsIp2Dns( TRUE );
|
|
}
|
|
|
|
Unlock();
|
|
|
|
return i;
|
|
}
|
|
|
|
|
|
UINT
|
|
RDnsDict::NewDns2IpEntry(
|
|
struct sockaddr *pAddr,
|
|
DWORD h,
|
|
time_t Expire,
|
|
LPSTR pszName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Store a address<>name pair with expiration time
|
|
|
|
Arguments:
|
|
|
|
pAddr - ptr to address
|
|
h - hash value of DNS name
|
|
Expire - expiration time
|
|
pszName - DNS name
|
|
|
|
Return Value:
|
|
|
|
index (1-based) of new entry, NULL if error
|
|
|
|
--*/
|
|
{
|
|
DBG_ASSERT(g_fEnableRdns);
|
|
Lock();
|
|
UINT i = GetFreeEntry();
|
|
|
|
if ( i )
|
|
{
|
|
RDnsCacheEntry *p = ENTRYPTR(m_pV,i);
|
|
|
|
if ( !p->Store( pAddr, h, Expire, pszName ) )
|
|
{
|
|
// put back on free list
|
|
p->InsertInPrioBefore( m_pV, m_FreeList );
|
|
i = NULL;
|
|
}
|
|
else
|
|
{
|
|
p->InsertInPrioBefore( m_pV, m_PrioList );
|
|
p->InsertInHashBefore( m_pV, m_pDns2IpHash[h] );
|
|
m_pDns2IpHash[h] = i;
|
|
}
|
|
|
|
p->SetIsIp2Dns( FALSE );
|
|
}
|
|
|
|
Unlock();
|
|
|
|
return i;
|
|
}
|
|
|
|
|
|
DWORD
|
|
RDnsDict::ComputeHash(
|
|
struct sockaddr* pAddr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Compute hash code of address
|
|
|
|
Arguments:
|
|
|
|
pAddr - ptr to address
|
|
|
|
Return Value:
|
|
|
|
Hash code <0...RDNS_HASH_SIZE>
|
|
|
|
--*/
|
|
{
|
|
UINT x;
|
|
UINT l;
|
|
DWORD h = 0;
|
|
LPBYTE p;
|
|
|
|
DBG_ASSERT(g_fEnableRdns);
|
|
switch ( pAddr->sa_family )
|
|
{
|
|
case AF_INET:
|
|
l = SIZEOF_IP_ADDRESS;
|
|
p = (LPBYTE)(&((PSOCKADDR_IN)pAddr)->sin_addr);
|
|
break;
|
|
|
|
#if 0
|
|
case AF_IPX:
|
|
l = 6;
|
|
p = (LPBYTE)pAddr->sa_data;
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
l = 8;
|
|
p = (LPBYTE)pAddr->sa_data;
|
|
break;
|
|
}
|
|
|
|
for ( x = 0 ; x < l ; ++x )
|
|
{
|
|
h = ((h<<5)|(h>>27)) ^ p[x];
|
|
}
|
|
|
|
return h % RDNS_HASH_SIZE;
|
|
}
|
|
|
|
|
|
DWORD
|
|
RDnsDict::ComputeHash(
|
|
LPSTR pszName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Compute hash code of name
|
|
|
|
Arguments:
|
|
|
|
pszName - DNS name
|
|
|
|
Return Value:
|
|
|
|
Hash code <0...RDNS_HASH_SIZE>
|
|
|
|
--*/
|
|
{
|
|
UINT x;
|
|
UINT l;
|
|
DWORD h = 0;
|
|
LPBYTE p;
|
|
|
|
DBG_ASSERT(g_fEnableRdns);
|
|
|
|
l = strlen( pszName );
|
|
p = (LPBYTE)pszName;
|
|
|
|
for ( x = 0 ; x < l ; ++x )
|
|
{
|
|
h = ((h<<5)|(h>>27)) ^ p[x];
|
|
}
|
|
|
|
return h % RDNS_HASH_SIZE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
RDnsDict::Search(
|
|
struct sockaddr* pAddr,
|
|
DWORD h,
|
|
LPSTR pszResult,
|
|
DWORD dwResMaxLen
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Search for address in cache
|
|
|
|
Arguments:
|
|
|
|
pAddr - ptr to address
|
|
h - hash code for address
|
|
pszResult - ptr to array updated with name if found
|
|
dwResMaxLen - size of pszResult array
|
|
|
|
Return Value:
|
|
|
|
TRUE if found and stored in pszResult, otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
UINT i = m_pHash[h];
|
|
RDnsCacheEntry *p;
|
|
BOOL fSt = FALSE;
|
|
time_t tNow = time(NULL);
|
|
|
|
DBG_ASSERT(g_fEnableRdns);
|
|
Lock();
|
|
|
|
while ( i )
|
|
{
|
|
p = ENTRYPTR(m_pV,i);
|
|
if ( p->MatchAddr( pAddr, tNow ) )
|
|
{
|
|
fSt = p->CopyName( pszResult, dwResMaxLen );
|
|
|
|
// update position in LRU list
|
|
p->RemoveFromPrio( m_pV );
|
|
p->InsertInPrioBefore( m_pV, m_PrioList );
|
|
|
|
break;
|
|
}
|
|
i = p->GetNextHash();
|
|
}
|
|
|
|
Unlock();
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
RDnsDict::SearchByName(
|
|
struct sockaddr* pAddr,
|
|
DWORD h,
|
|
LPSTR pszName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Search for name in cache
|
|
|
|
Arguments:
|
|
|
|
pAddr - ptr to address
|
|
h - hash code for address
|
|
pszName - name to search for
|
|
|
|
Return Value:
|
|
|
|
TRUE if found and stored in pAddr, otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
UINT i = m_pDns2IpHash[h];
|
|
RDnsCacheEntry *p;
|
|
BOOL fSt = FALSE;
|
|
time_t tNow = time(NULL);
|
|
|
|
DBG_ASSERT(g_fEnableRdns);
|
|
Lock();
|
|
|
|
while ( i )
|
|
{
|
|
p = ENTRYPTR(m_pV,i);
|
|
if ( p->MatchName( pszName, tNow ) )
|
|
{
|
|
fSt = p->CopyAddr( pAddr );
|
|
|
|
// update position in LRU list
|
|
p->RemoveFromPrio( m_pV );
|
|
p->InsertInPrioBefore( m_pV, m_PrioList );
|
|
|
|
break;
|
|
}
|
|
i = p->GetNextHash();
|
|
}
|
|
|
|
Unlock();
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
UINT
|
|
RDnsDict::GetFreeEntry(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get a free entry in cache array
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
index ( 1-based ) of free element to use
|
|
|
|
--*/
|
|
{
|
|
UINT i;
|
|
UINT iN;
|
|
RDnsCacheEntry *p;
|
|
|
|
DBG_ASSERT(g_fEnableRdns);
|
|
if ( m_PrioList == NULL || m_FreeList == NULL )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
i = ENTRYPTR(m_pV,m_FreeList)->GetNextPrio();
|
|
|
|
if ( i != m_FreeList )
|
|
{
|
|
ENTRYPTR(m_pV,i)->RemoveFromPrio( m_pV );
|
|
ENTRYPTR(m_pV,i)->Reset();
|
|
}
|
|
else
|
|
{
|
|
if ( i = Append() )
|
|
{
|
|
ENTRYPTR(m_pV,i)->Init( i );
|
|
}
|
|
else
|
|
{
|
|
// get from LRU
|
|
|
|
i = ENTRYPTR(m_pV,m_PrioList)->GetNextPrio();
|
|
|
|
if ( i != m_PrioList )
|
|
{
|
|
// remove from hash list
|
|
|
|
p = ENTRYPTR(m_pV,i);
|
|
p->RemoveFromPrio( m_pV );
|
|
iN = p->RemoveFromHash(m_pV);
|
|
// if hash entry pointed to this element, update hash entry
|
|
if ( p->IsIp2Dns() )
|
|
{
|
|
if ( m_pHash[p->GetHash()] == i )
|
|
{
|
|
m_pHash[p->GetHash()] = iN;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( m_pDns2IpHash[p->GetHash()] == i )
|
|
{
|
|
m_pDns2IpHash[p->GetHash()] = iN;
|
|
}
|
|
}
|
|
p->Reset();
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
|
|
UINT
|
|
RDnsDict::Append(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Append an entry to the cache array
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
index ( 1-based ) of new element
|
|
|
|
--*/
|
|
{
|
|
DBG_ASSERT(g_fEnableRdns);
|
|
if ( m_cSize + 1 > m_cAlloc )
|
|
{
|
|
int cNew = (( m_cSize + 1 + XBF_EXTEND )/XBF_EXTEND)*XBF_EXTEND;
|
|
if ( cNew*sizeof(RDnsCacheEntry) > g_cCacheSize )
|
|
{
|
|
return NULL;
|
|
}
|
|
LPBYTE pN = (LPBYTE)LocalAlloc( LMEM_FIXED, cNew*sizeof(RDnsCacheEntry) );
|
|
if ( pN == NULL )
|
|
{
|
|
return NULL;
|
|
}
|
|
if ( m_cSize )
|
|
{
|
|
memcpy( pN, m_pV, m_cSize*sizeof(RDnsCacheEntry) );
|
|
}
|
|
if ( m_cAlloc )
|
|
{
|
|
LocalFree( m_pV );
|
|
}
|
|
m_pV = (RDnsCacheEntry*)pN;
|
|
m_cAlloc = cNew;
|
|
}
|
|
return ++m_cSize;
|
|
}
|
|
|
|
|
|
void
|
|
RDnsDict::FreeEntry(
|
|
UINT i
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free an element in the cache array, put it on free list
|
|
|
|
Arguments:
|
|
|
|
index ( 1-based ) of element to be freed
|
|
|
|
Return Value:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
{
|
|
DBG_ASSERT(g_fEnableRdns);
|
|
|
|
UINT iN;
|
|
RDnsCacheEntry *p = ENTRYPTR(m_pV,i);
|
|
|
|
iN = p->RemoveFromHash(m_pV);
|
|
// if hash entry pointed to this element, update hash entry
|
|
if ( p->IsIp2Dns() )
|
|
{
|
|
if ( m_pHash[p->GetHash()] == i )
|
|
{
|
|
m_pHash[p->GetHash()] = iN;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( m_pDns2IpHash[p->GetHash()] == i )
|
|
{
|
|
m_pDns2IpHash[p->GetHash()] = iN;
|
|
}
|
|
}
|
|
p->SetFree();
|
|
|
|
p->RemoveFromPrio( m_pV );
|
|
p->InsertInPrioBefore( m_pV, m_FreeList );
|
|
}
|
|
|
|
|
|
void
|
|
RDnsDict::Scavenger(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Scavenger code to delete expired entries in the cache array
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
{
|
|
DBG_ASSERT(g_fEnableRdns);
|
|
Lock();
|
|
RDnsCacheEntry *p = m_pV;
|
|
UINT i;
|
|
time_t tNow = time(NULL);
|
|
|
|
for ( i = 0 ; i < m_cSize ; ++i, ++p )
|
|
{
|
|
if ( p->Expired( tNow ) )
|
|
{
|
|
FreeEntry( i + 1 );
|
|
}
|
|
}
|
|
|
|
Unlock();
|
|
}
|
|
|
|
|
|
VOID
|
|
WINAPI
|
|
RDnsScavenger(
|
|
LPVOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Scavenger function for RDns & Pen
|
|
|
|
Arguments:
|
|
|
|
LPVOID - not used
|
|
|
|
Return Value:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
{
|
|
DBG_ASSERT(g_fEnableRdns);
|
|
g_RDns.Scavenger();
|
|
|
|
if ( g_pscPen != NULL )
|
|
{
|
|
g_pscPen->Scavenger();
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
InitRDns(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Init the Reverse DNS API
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Don't enable for win95
|
|
//
|
|
|
|
if ( IISGetPlatformType() == PtWindows95 ) {
|
|
g_fEnableRdns = FALSE;
|
|
return(TRUE);
|
|
}
|
|
|
|
#if DBG
|
|
//
|
|
// check that RDNS_HASH_SIZE is prime
|
|
//
|
|
|
|
UINT x = 2;
|
|
UINT x2;
|
|
for ( x = 2 ; (x2=x*x) <= RDNS_HASH_SIZE; ++x )
|
|
{
|
|
if ( (RDNS_HASH_SIZE/x)*x == RDNS_HASH_SIZE )
|
|
{
|
|
ASSERT( FALSE );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
HKEY hKey;
|
|
|
|
// get cache size, max # threads
|
|
if ( RegOpenKey( HKEY_LOCAL_MACHINE, RDNS_REG_KEY, &hKey )
|
|
== ERROR_SUCCESS )
|
|
{
|
|
DWORD dwType;
|
|
DWORD dwValue;
|
|
|
|
DWORD dwSize = sizeof(dwValue);
|
|
if ( RegQueryValueEx( hKey,
|
|
RDNS_REG_MAX_THREAD,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)&dwValue,
|
|
&dwSize ) == ERROR_SUCCESS
|
|
&& dwType == REG_DWORD )
|
|
{
|
|
g_cMaxThreadLimit = dwValue;
|
|
}
|
|
else
|
|
{
|
|
g_cMaxThreadLimit = RDNS_REG_MAX_THREAD_DEF;
|
|
}
|
|
|
|
dwSize = sizeof(dwValue);
|
|
if ( RegQueryValueEx( hKey,
|
|
RDNS_REG_CACHE_SIZE,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)&dwValue,
|
|
&dwSize ) == ERROR_SUCCESS
|
|
&& dwType == REG_DWORD )
|
|
{
|
|
g_cCacheSize = dwValue * 1024;
|
|
}
|
|
else
|
|
{
|
|
g_cCacheSize = RDNS_REG_CACHE_SIZE_DEF * 1024;
|
|
}
|
|
|
|
dwSize = sizeof(dwValue);
|
|
if ( RegQueryValueEx( hKey,
|
|
RDNS_REG_TTL,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)&dwValue,
|
|
&dwSize ) == ERROR_SUCCESS
|
|
&& dwType == REG_DWORD )
|
|
{
|
|
g_cTTL = dwValue;
|
|
}
|
|
else
|
|
{
|
|
g_cTTL = RDNS_REG_TTL_DEF;
|
|
}
|
|
|
|
RegCloseKey( hKey );
|
|
|
|
}
|
|
|
|
if ( g_RDns.Init() == FALSE )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
g_pscPen = new CSidCache;
|
|
if ( g_pscPen == NULL )
|
|
{
|
|
return FALSE;
|
|
}
|
|
g_pscPen->Init();
|
|
|
|
g_cAvailableThreads = 0;
|
|
g_cThreads = 0;
|
|
g_hDnsPort = CreateIoCompletionPort( INVALID_HANDLE_VALUE,
|
|
NULL,
|
|
NULL,
|
|
g_cMaxThreadLimit );
|
|
|
|
g_hThreadsTerminated = IIS_CREATE_EVENT(
|
|
"g_hThreadsTerminated",
|
|
&g_hThreadsTerminated,
|
|
TRUE,
|
|
FALSE
|
|
);
|
|
|
|
if ( g_hDnsPort == NULL || g_hThreadsTerminated == NULL )
|
|
{
|
|
CloseHandle( g_hDnsPort );
|
|
CloseHandle( g_hThreadsTerminated );
|
|
g_hDnsPort = NULL;
|
|
g_hThreadsTerminated = NULL;
|
|
return FALSE;
|
|
}
|
|
|
|
g_dwScavengerWorkItem = ScheduleWorkItem( RDnsScavenger,
|
|
NULL,
|
|
1000 * RDNS_SCAVENGER_GRANULARITY,
|
|
TRUE );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void
|
|
TerminateRDns(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Terminate the Reverse DNS API
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
{
|
|
UINT x;
|
|
|
|
if ( !g_fEnableRdns ) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// post queued to everybody
|
|
// all threads will dec global count of thread, when 0 set event
|
|
// close port
|
|
|
|
if ( g_cThreads )
|
|
{
|
|
for ( x = 0 ; x < g_cThreads ; ++x )
|
|
{
|
|
PostQueuedCompletionStatus( g_hDnsPort, NULL, NULL, NULL );
|
|
}
|
|
WaitForSingleObject( g_hThreadsTerminated, 5 * 1000 );
|
|
}
|
|
|
|
CloseHandle( g_hDnsPort );
|
|
CloseHandle( g_hThreadsTerminated );
|
|
g_hDnsPort = NULL;
|
|
g_hThreadsTerminated = NULL;
|
|
|
|
if ( g_dwScavengerWorkItem != NULL )
|
|
{
|
|
RemoveWorkItem( g_dwScavengerWorkItem );
|
|
g_dwScavengerWorkItem = NULL;
|
|
}
|
|
|
|
g_RDns.Terminate();
|
|
|
|
if ( g_pscPen != NULL )
|
|
{
|
|
g_pscPen->Terminate();
|
|
delete g_pscPen;
|
|
g_pscPen = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
DWORD WINAPI
|
|
AsyncThread(
|
|
LPVOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Thread handling reverse DNS request
|
|
|
|
Arguments:
|
|
|
|
LPVOID - not used
|
|
|
|
Return Value:
|
|
|
|
Thread exit status
|
|
|
|
--*/
|
|
{
|
|
DWORD dwSize;
|
|
ULONG_PTR dwKey;
|
|
PVOID * ppInfo;
|
|
DNSARG pArg;
|
|
struct sockaddr *pAddr;
|
|
struct sockaddr EmptyAddr;
|
|
LPSTR pName;
|
|
CHAR achName[DN_LEN];
|
|
DWORD h;
|
|
BOOL fSt;
|
|
struct hostent* pH;
|
|
|
|
|
|
DBG_ASSERT(g_fEnableRdns);
|
|
|
|
while ( GetQueuedCompletionStatus( g_hDnsPort,
|
|
&dwSize,
|
|
&dwKey,
|
|
(LPOVERLAPPED*)&ppInfo,
|
|
(DWORD)-1 ) )
|
|
{
|
|
InterlockedDecrement( &g_cAvailableThreads );
|
|
|
|
//
|
|
// if pInfo is NULL it is close request
|
|
//
|
|
|
|
if ( NULL == ppInfo)
|
|
{
|
|
if ( InterlockedDecrement( (PLONG)&g_cThreads ) == 0)
|
|
{
|
|
SetEvent( g_hThreadsTerminated );
|
|
}
|
|
break;
|
|
}
|
|
|
|
pAddr = (struct sockaddr *)ppInfo[0];
|
|
pArg = ppInfo[1];
|
|
|
|
switch ( ((PDNSFUNCDESC)dwKey)->dwRequestType )
|
|
{
|
|
case RDNS_REQUEST_TYPE_IP2DNS:
|
|
h = g_RDns.ComputeHash( pAddr );
|
|
fSt = FALSE;
|
|
|
|
if ( pH = gethostbyaddr( (char*)(&((PSOCKADDR_IN)pAddr)->sin_addr),
|
|
SIZEOF_IP_ADDRESS,
|
|
PF_INET ) )
|
|
{
|
|
g_RDns.NewEntry( pAddr, h, time(NULL)+g_cTTL, pH->h_name );
|
|
fSt = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Create entry with empty name as result of negative search
|
|
//
|
|
|
|
g_RDns.NewEntry( pAddr, h, time(NULL)+g_cTTL, "" );
|
|
}
|
|
|
|
(((PDNSFUNCDESC)dwKey)->pFunc)(pArg, fSt, pH ? pH->h_name : NULL );
|
|
break;
|
|
|
|
case RDNS_REQUEST_TYPE_DNS2IP:
|
|
pName = (LPSTR)pAddr;
|
|
h = g_RDns.ComputeHash( pName );
|
|
fSt = FALSE;
|
|
|
|
if ( pH = gethostbyname( pName ) )
|
|
{
|
|
memcpy( &((sockaddr_in*)&EmptyAddr)->sin_addr, pH->h_addr, SIZEOF_IP_ADDRESS );
|
|
EmptyAddr.sa_family = AF_INET;
|
|
fSt = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Create entry with null addr as result of negative search
|
|
//
|
|
|
|
memset( &EmptyAddr, '\0', sizeof(EmptyAddr) );
|
|
}
|
|
|
|
g_RDns.NewDns2IpEntry( &EmptyAddr, h, time(NULL)+g_cTTL, pName );
|
|
(((PDNSFUNCDESC)dwKey)->pFunc)(pArg, fSt, (LPSTR)&EmptyAddr );
|
|
break;
|
|
}
|
|
|
|
InterlockedIncrement( &g_cAvailableThreads );
|
|
|
|
pAddr = NULL;
|
|
pArg = NULL;
|
|
|
|
free(ppInfo);
|
|
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//AtqPostCompletionStatus(
|
|
// IN PATQ_CONTEXT patqContext, from QueryClientConn()->QueryAtqContext()
|
|
// IN DWORD BytesTransferred will be 0
|
|
// )
|
|
|
|
BOOL
|
|
AsyncHostByAddr(
|
|
PDNSFUNCDESC pFunc, // will store DNS name, post dummy completion status
|
|
// if NULL ( or g_cMaxThreadLimit==0 ) then sync request
|
|
DNSARG pArg, // ptr to be passed to FUNC
|
|
struct sockaddr *pHostAddr,
|
|
|
|
BOOL *pfSync, // updated with TRUE if sync call
|
|
LPSTR pName,
|
|
DWORD dwMaxNameLen
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reverse DNS query
|
|
|
|
Arguments:
|
|
|
|
pFunc - ptr to function to be called for asynchronous result
|
|
pArg - argument to be supplied while calling pFunc
|
|
pHostAddr - address to reverse resolve
|
|
pfSync - updated with TRUE if synchronous result ( i.e. pName updated
|
|
with result if function returns TRUE )
|
|
pName - to be updated with DNS name if synchronous result
|
|
dwMaxNameLen - size of supplied pName buffer
|
|
|
|
Return Value:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
BOOL fRet = TRUE;
|
|
DWORD h;
|
|
|
|
DBG_ASSERT(g_fEnableRdns);
|
|
|
|
h = g_RDns.ComputeHash( pHostAddr );
|
|
|
|
if ( g_RDns.Search( pHostAddr, h, pName, dwMaxNameLen ) )
|
|
{
|
|
*pfSync = TRUE;
|
|
return TRUE;
|
|
}
|
|
|
|
if ( pFunc == NULL || g_cMaxThreadLimit == 0 )
|
|
{
|
|
struct hostent* pH;
|
|
if ( pHostAddr->sa_family == AF_INET &&
|
|
(pH = gethostbyaddr( (char*)(&((PSOCKADDR_IN)pHostAddr)->sin_addr),
|
|
SIZEOF_IP_ADDRESS,
|
|
PF_INET )) )
|
|
{
|
|
UINT l = strlen( pH->h_name ) + 1;
|
|
if ( l <= dwMaxNameLen )
|
|
{
|
|
memcpy( pName, pH->h_name, l );
|
|
fRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
*pName = '\0';
|
|
fRet = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Create entry with empty name as result of negative search
|
|
//
|
|
|
|
*pName = '\0';
|
|
fRet = FALSE;
|
|
}
|
|
|
|
g_RDns.NewEntry( pHostAddr,
|
|
h,
|
|
time(NULL)+g_cTTL,
|
|
pName );
|
|
|
|
*pfSync = TRUE;
|
|
return fRet;
|
|
}
|
|
|
|
*pfSync = FALSE;
|
|
|
|
return FireUpNewThread( pFunc, pArg, (LPVOID)pHostAddr );
|
|
}
|
|
|
|
|
|
BOOL
|
|
AsyncAddrByHost(
|
|
PDNSFUNCDESC pFunc, // will store DNS name, post dummy completion status
|
|
// if NULL ( or g_cMaxThreadLimit==0 ) then sync request
|
|
DNSARG pArg, // ptr to be passed to FUNC
|
|
struct sockaddr *pHostAddr,
|
|
|
|
BOOL *pfSync, // updated with TRUE if sync call
|
|
LPSTR pszName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
DNS query
|
|
|
|
Arguments:
|
|
|
|
pFunc - ptr to function to be called for asynchronous result
|
|
pArg - argument to be supplied while calling pFunc
|
|
pHostAddr - to be updated with address
|
|
pfSync - updated with TRUE if synchronous result ( i.e. pName updated
|
|
with result if function returns TRUE )
|
|
pName - to be updated with DNS name if synchronous result
|
|
|
|
Return Value:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
BOOL fRet = TRUE;
|
|
DWORD h;
|
|
|
|
DBG_ASSERT(g_fEnableRdns);
|
|
|
|
h = g_RDns.ComputeHash( pszName );
|
|
|
|
if ( g_RDns.SearchByName( pHostAddr, h, pszName ) )
|
|
{
|
|
*pfSync = TRUE;
|
|
return TRUE;
|
|
}
|
|
|
|
if ( pFunc == NULL || g_cMaxThreadLimit == 0 )
|
|
{
|
|
struct hostent* pH;
|
|
if ( pH = gethostbyname( pszName ) )
|
|
{
|
|
memcpy( &((sockaddr_in*)pHostAddr)->sin_addr, pH->h_addr, pH->h_length );
|
|
pHostAddr->sa_family = AF_INET;
|
|
fRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Create entry with empty name as result of negative search
|
|
//
|
|
|
|
memset( pHostAddr, '\0', sizeof(struct sockaddr) );
|
|
fRet = FALSE;
|
|
}
|
|
|
|
g_RDns.NewDns2IpEntry( pHostAddr,
|
|
h,
|
|
time(NULL)+g_cTTL,
|
|
pszName );
|
|
|
|
*pfSync = TRUE;
|
|
return fRet;
|
|
}
|
|
|
|
*pfSync = FALSE;
|
|
|
|
return FireUpNewThread( pFunc, pArg, (LPVOID)pszName );
|
|
}
|
|
|
|
|
|
BOOL
|
|
FireUpNewThread(
|
|
PDNSFUNCDESC pFunc,
|
|
DNSARG pArg,
|
|
LPVOID pOvr
|
|
)
|
|
{
|
|
//
|
|
// If no threads are available, kick a new one off up to the limit
|
|
//
|
|
|
|
if ( (g_cAvailableThreads == 0) &&
|
|
(g_cThreads < g_cMaxThreadLimit) )
|
|
{
|
|
|
|
HANDLE hThread;
|
|
DWORD dwThreadID;
|
|
|
|
InterlockedIncrement( (PLONG)&g_cThreads );
|
|
|
|
hThread = CreateThread( NULL,
|
|
0,
|
|
(LPTHREAD_START_ROUTINE)AsyncThread,
|
|
NULL,
|
|
0,
|
|
&dwThreadID );
|
|
|
|
if ( hThread )
|
|
{
|
|
CloseHandle( hThread ); // Free system resources
|
|
InterlockedIncrement( &g_cAvailableThreads );
|
|
}
|
|
else
|
|
{
|
|
|
|
//
|
|
// We fail if there are no threads running
|
|
//
|
|
|
|
if ( InterlockedDecrement( (PLONG)&g_cThreads ) == 0)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
PVOID * ppInfo = (PVOID *) malloc(2*sizeof(PVOID));
|
|
|
|
if (NULL != ppInfo)
|
|
{
|
|
ppInfo[0] = pOvr;
|
|
ppInfo[1] = pArg;
|
|
}
|
|
|
|
BOOL fRet = PostQueuedCompletionStatus( g_hDnsPort,
|
|
0,
|
|
(ULONG_PTR)pFunc,
|
|
(LPOVERLAPPED)ppInfo
|
|
);
|
|
if( !fRet )
|
|
{
|
|
free( ppInfo );
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
#if DBG
|
|
|
|
|
|
typedef struct _TEST_RDNS
|
|
{
|
|
LPSTR pIA;
|
|
char achName[32];
|
|
struct sockaddr sa;
|
|
} TEST_RDNS;
|
|
|
|
TEST_RDNS TR[]={
|
|
{ "157.55.83.72", "PHILLICH3" },
|
|
{ "157.55.91.17", "JOHNL0" },
|
|
{ "157.55.84.160", "JOHNSONA" },
|
|
{ "157.55.87.80", "MICHTH1" },
|
|
{ "157.55.86.54", "MICHTH2" },
|
|
} ;
|
|
|
|
LONG cPending = 0;
|
|
|
|
void CheckAddr( TEST_RDNS*p, LPSTR a)
|
|
{
|
|
// char achErr[80];
|
|
// wsprintf( achErr, "Arg=%d, bool=%d, addr=%s\n", a, f, p );
|
|
// OutputDebugString( achErr );
|
|
|
|
int l = strlen( p->achName );
|
|
if ( _memicmp( p->achName, a, l ) )
|
|
{
|
|
ASSERT( FALSE );
|
|
}
|
|
}
|
|
|
|
void pFunc( DNSARG a, BOOL f, LPSTR p)
|
|
{
|
|
if ( f )
|
|
{
|
|
CheckAddr( (TEST_RDNS*)a, p );
|
|
}
|
|
else
|
|
{
|
|
char achErr[80];
|
|
wsprintf( achErr, "Failed gethostbyaddr=%s\n", ((TEST_RDNS*)a)->pIA );
|
|
OutputDebugString( achErr );
|
|
}
|
|
InterlockedDecrement( &cPending );
|
|
}
|
|
|
|
|
|
DNSFUNCDESC g_TestFunc = { RDNS_REQUEST_TYPE_IP2DNS, pFunc };
|
|
|
|
|
|
void TestRDns()
|
|
{
|
|
static struct sockaddr sa;
|
|
BOOL fS;
|
|
UINT x;
|
|
UINT y;
|
|
CHAR achName[64];
|
|
UINT a,b,c,d;
|
|
|
|
|
|
for ( x = y = 0 ; x < 1000 ; ++x )
|
|
{
|
|
TEST_RDNS *p = TR+y;
|
|
|
|
sscanf( p->pIA, "%u.%u.%u.%u", &a, &b, &c, &d );
|
|
((PSOCKADDR_IN)&p->sa)->sin_addr.s_net = (u_char)a;
|
|
((PSOCKADDR_IN)&p->sa)->sin_addr.s_host = (u_char)b;
|
|
((PSOCKADDR_IN)&p->sa)->sin_addr.s_lh = (u_char)c;
|
|
((PSOCKADDR_IN)&p->sa)->sin_addr.s_impno = (u_char)d;
|
|
p->sa.sa_family = AF_INET;
|
|
|
|
if ( AsyncHostByAddr(
|
|
(PDNSFUNCDESC)&g_TestFunc,
|
|
(DNSARG)p,
|
|
&p->sa,
|
|
&fS,
|
|
achName,
|
|
sizeof(achName)
|
|
) )
|
|
{
|
|
if ( fS )
|
|
{
|
|
CheckAddr( p, achName );
|
|
}
|
|
else
|
|
{
|
|
InterlockedIncrement( &cPending );
|
|
Sleep( 500 );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASSERT( FALSE );
|
|
}
|
|
if ( ++y == sizeof(TR)/sizeof(TEST_RDNS) )
|
|
{
|
|
y = 0;
|
|
}
|
|
}
|
|
|
|
for ( ;; )
|
|
{
|
|
if ( cPending == 0 )
|
|
{
|
|
break;
|
|
}
|
|
Sleep( 1000 );
|
|
}
|
|
|
|
OutputDebugString( "Done" );
|
|
}
|
|
#endif
|
|
|
|
|
|
LPVOID
|
|
BsearchEx (
|
|
LPVOID key,
|
|
LPVOID base,
|
|
size_t num,
|
|
size_t width,
|
|
CMPFUNC compare,
|
|
LPVOID param
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Binary search with additional parameter to be passed
|
|
to compare routine
|
|
|
|
Arguments:
|
|
|
|
key - ptr to key
|
|
base - ptr to base of array
|
|
num - number of elements in array
|
|
width - size of array element
|
|
compare - compare routine, called with ptr to 2 elements and param
|
|
param - additional parameter presented to the compare routine
|
|
|
|
Return Value:
|
|
|
|
ptr to element in array if key found, else NULL
|
|
|
|
--*/
|
|
{
|
|
char *lo = (char *)base;
|
|
char *hi = (char *)base + (num - 1) * width;
|
|
char *mid;
|
|
unsigned int half;
|
|
int result;
|
|
|
|
while (lo <= hi)
|
|
if (half = num / 2)
|
|
{
|
|
mid = lo + (num & 1 ? half : (half - 1)) * width;
|
|
if (!(result = (*compare)(key,mid,param)))
|
|
return(mid);
|
|
else if (result < 0)
|
|
{
|
|
hi = mid - width;
|
|
num = num & 1 ? half : half-1;
|
|
}
|
|
else {
|
|
lo = mid + width;
|
|
num = half;
|
|
}
|
|
}
|
|
else if (num)
|
|
return((*compare)(key,lo,param) ? NULL : lo);
|
|
else
|
|
break;
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
BOOL
|
|
ADDRESS_CHECK::BindCheckList(
|
|
LPBYTE p,
|
|
DWORD c
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Bind a check list ( presented as a BLOB ) to an
|
|
ADDRESS_CHECK object
|
|
|
|
Arguments:
|
|
|
|
p - ptr to BLOB
|
|
c - size of BLOB
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
PADDRESS_CHECK_LIST pList;
|
|
UINT l;
|
|
|
|
if ( p == NULL )
|
|
{
|
|
if ( m_Storage.Init() && m_Storage.Resize( sizeof(ADDRESS_CHECK_LIST)
|
|
+ sizeof(ADDRESS_HEADER) * 2
|
|
+ sizeof(NAME_HEADER) * 2 ) )
|
|
{
|
|
DWORD i;
|
|
pList = (PADDRESS_CHECK_LIST)m_Storage.GetAlloc();
|
|
|
|
// BugFix: 47982 Whistler
|
|
// Prefix bug pList not being valid.
|
|
// EBK 5/5/2000
|
|
if (pList)
|
|
{
|
|
pList->iDenyAddr = i = MAKEREF( sizeof(ADDRESS_CHECK_LIST) );
|
|
i += sizeof(ADDRESS_HEADER);
|
|
pList->iGrantAddr = i;
|
|
i += sizeof(ADDRESS_HEADER);
|
|
pList->iDenyName = i;
|
|
i += sizeof(NAME_HEADER);
|
|
pList->iGrantName = i;
|
|
i += sizeof(NAME_HEADER);
|
|
pList->cRefSize = MAKEOFFSET(i);
|
|
pList->dwFlags = RDNS_FLAG_DODNS2IPCHECK;
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
return m_Storage.Init( p, c );
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
ADDRESS_CHECK::SetFlag(
|
|
DWORD dwFlag,
|
|
BOOL fEnable
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set flag in address check object
|
|
|
|
Arguments:
|
|
|
|
dwFlag - flag to enable/disable
|
|
fEnable - TRUE to enable, else FALSE
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
LPBYTE pStore = m_Storage.GetAlloc();
|
|
PADDRESS_CHECK_LIST pList;
|
|
|
|
if ( pStore )
|
|
{
|
|
pList = (PADDRESS_CHECK_LIST)pStore;
|
|
if ( fEnable )
|
|
{
|
|
pList->dwFlags |= dwFlag;
|
|
}
|
|
else
|
|
{
|
|
pList->dwFlags &= ~dwFlag;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
DWORD
|
|
ADDRESS_CHECK::GetFlags(
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get flags in address check object
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
Flags if object exists, otherwise 0
|
|
|
|
--*/
|
|
{
|
|
LPBYTE pStore = m_Storage.GetAlloc();
|
|
PADDRESS_CHECK_LIST pList;
|
|
|
|
if ( pStore )
|
|
{
|
|
pList = (PADDRESS_CHECK_LIST)pStore;
|
|
|
|
return pList->dwFlags;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ADDRESS_CHECK::LocateAddr(
|
|
BOOL fGrant,
|
|
DWORD iIndex,
|
|
PADDRESS_HEADER* ppHd,
|
|
PADDRESS_LIST_ENTRY* pHeader,
|
|
LPDWORD piIndexInHeader
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Locate an address in the specified list, returns ptr
|
|
to header & element in address list
|
|
|
|
Arguments:
|
|
|
|
fGrant - TRUE to locate in grant list, FALSE for deny list
|
|
iIndex - index in list (0-based )
|
|
ppHd - updated with ptr to address header
|
|
pHeader - updated with ptr to address list entry
|
|
piIndexInHeader - updated with index in array addressed by
|
|
pHeader->iFirstAddress
|
|
|
|
Return Value:
|
|
|
|
TRUE if iIndex valid in array defined by fGrant, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
LPBYTE pStore = m_Storage.GetAlloc();
|
|
PADDRESS_CHECK_LIST pList;
|
|
PADDRESS_HEADER pHd;
|
|
UINT iL;
|
|
|
|
if ( pStore )
|
|
{
|
|
pList = (PADDRESS_CHECK_LIST)pStore;
|
|
*ppHd = pHd = (PADDRESS_HEADER)MAKEPTR( pStore, fGrant ? pList->iGrantAddr : pList->iDenyAddr);
|
|
for ( iL = 0 ; iL < pHd->cEntries ; ++iL )
|
|
{
|
|
// adjust index by 1: 1st entry is mask
|
|
if ( iIndex < (pHd->Entries[iL].cAddresses-1) )
|
|
{
|
|
*pHeader = pHd->Entries+iL;
|
|
*piIndexInHeader = iIndex+1;
|
|
return TRUE;
|
|
}
|
|
iIndex -= (pHd->Entries[iL].cAddresses-1);
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ADDRESS_CHECK::GetAddr(
|
|
BOOL fGrant,
|
|
DWORD iIndex,
|
|
LPDWORD pdwFamily,
|
|
LPBYTE* pMask,
|
|
LPBYTE* pAddr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get an address entry
|
|
|
|
Arguments:
|
|
|
|
fGrant - TRUE to locate in grant list, FALSE for deny list
|
|
iIndex - index in list (0-based )
|
|
pdwFamily - updated with address family ( as in sockaddr.sa_type )
|
|
pMask - updated with ptr to mask
|
|
pAddr - updated with ptr to address
|
|
|
|
Return Value:
|
|
|
|
TRUE if iIndex valid in array defined by fGrant, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
PADDRESS_LIST_ENTRY pHeader;
|
|
PADDRESS_HEADER pHd;
|
|
DWORD iIndexInHeader;
|
|
LPBYTE pStore = m_Storage.GetAlloc();
|
|
|
|
if ( LocateAddr( fGrant, iIndex, &pHd, &pHeader, &iIndexInHeader ) )
|
|
{
|
|
UINT cS = GetAddrSize( pHeader->iFamily );
|
|
*pdwFamily = pHeader->iFamily;
|
|
pStore = MAKEPTR(pStore, pHeader->iFirstAddress);
|
|
*pMask = pStore;
|
|
*pAddr = pStore+iIndexInHeader*cS;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ADDRESS_CHECK::DeleteAddr(
|
|
BOOL fGrant,
|
|
DWORD iIndex
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Delete an address entry
|
|
|
|
Arguments:
|
|
|
|
fGrant - TRUE to locate in grant list, FALSE for deny list
|
|
iIndex - index in list (0-based )
|
|
|
|
Return Value:
|
|
|
|
TRUE if iIndex valid in array defined by fGrant, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
PADDRESS_LIST_ENTRY pHeader;
|
|
PADDRESS_HEADER pHd;
|
|
DWORD iIndexInHeader;
|
|
LPBYTE pStore = m_Storage.GetAlloc();
|
|
|
|
if ( LocateAddr( fGrant, iIndex, &pHd, &pHeader, &iIndexInHeader ) )
|
|
{
|
|
UINT cS = GetAddrSize( pHeader->iFamily );
|
|
UINT iS = MAKEOFFSET(pHeader->iFirstAddress)+iIndexInHeader*cS;
|
|
LPBYTE pAddr = MAKEPTR(pStore, iS);
|
|
|
|
memmove( pAddr,
|
|
pAddr + cS,
|
|
m_Storage.GetUsed() - iS - cS );
|
|
m_Storage.AdjustUsed( -(int)cS );
|
|
--pHeader->cAddresses;
|
|
AdjustRefs( pStore, MAKEOFFSET(pHeader->iFirstAddress)+1, -(int)cS );
|
|
--pHd->cAddresses;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
int __cdecl
|
|
AddrCmp(
|
|
LPVOID pA,
|
|
LPVOID pB,
|
|
LPVOID pP
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Compare 2 address entries.
|
|
uses mask as defined by PADDRCMPDESC pP
|
|
|
|
Arguments:
|
|
|
|
pA - ptr to 1st address entry ( as byte array )
|
|
pB - ptr to 2nd address entry ( as byte array )
|
|
pP - ptr yo ADDRCMDDESC
|
|
|
|
Return Value:
|
|
|
|
-1 if *pA < *pB, 0 if *pA == *pB, 1 if *pA > *pB
|
|
|
|
--*/
|
|
{
|
|
PADDRCMPDESC pacd = (PADDRCMPDESC)pP;
|
|
int l;
|
|
UINT a;
|
|
UINT b;
|
|
|
|
|
|
if ( pacd->cFullBytes || pacd->LastByte )
|
|
{
|
|
if ( (l = memcmp( pA, pB, pacd->cFullBytes )) )
|
|
{
|
|
return l;
|
|
}
|
|
|
|
if ( pacd->LastByte )
|
|
{
|
|
a = ((LPBYTE)pA)[pacd->cFullBytes] & pacd->LastByte;
|
|
b = ((LPBYTE)pB)[pacd->cFullBytes] & pacd->LastByte;
|
|
|
|
return a < b ? -1 : ( a==b ? 0 : 1 );
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
// bit cmp from pMask
|
|
LPBYTE pM = pacd->pMask;
|
|
LPBYTE pMM = pM + pacd->cSizeAddress;
|
|
for ( ; pM < pMM ; ++pM )
|
|
{
|
|
a = *((LPBYTE)pA) & *pM;
|
|
b = *((LPBYTE)pB) & *pM;
|
|
if ( a<b )
|
|
{
|
|
return -1;
|
|
}
|
|
else if ( a > b )
|
|
{
|
|
return 1;
|
|
}
|
|
pA = (LPVOID)(((LPBYTE)pA) + 1);
|
|
pB = (LPVOID)(((LPBYTE)pB) + 1);
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
int __cdecl
|
|
NameCmp(
|
|
LPVOID pA,
|
|
LPVOID pB,
|
|
LPVOID pP
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Compare 2 name entries.
|
|
Entry is either defined as a ptr to ASCII ( if equal to NAMECMPDESC.pName )
|
|
or as ptr to DWORD offset in LPSTR array based as NAMECMPDESC.pBase
|
|
|
|
Arguments:
|
|
|
|
pA - ptr to 1st name entry
|
|
pB - ptr to 2nd name entry
|
|
pP - ptr yo NAMECMDDESC
|
|
|
|
Return Value:
|
|
|
|
-1 if *pA < *pB, 0 if *pA == *pB, 1 if *pA > *pB
|
|
|
|
--*/
|
|
{
|
|
int l;
|
|
UINT a;
|
|
UINT b;
|
|
PNAMECMPDESC pncd = (PNAMECMPDESC)pP;
|
|
LPVOID pName = pncd->pName;
|
|
LPBYTE pBase = pncd->pBase;
|
|
|
|
|
|
if ( pA != pName )
|
|
{
|
|
pA = MAKEPTR( pBase, *(DWORD*)pA );
|
|
}
|
|
if ( pB != pName )
|
|
{
|
|
pB = MAKEPTR( pBase, *(DWORD*)pB );
|
|
}
|
|
|
|
return _stricmp( (const char*)pA, (const char*)pB );
|
|
}
|
|
|
|
|
|
BOOL
|
|
ADDRESS_CHECK::AddAddr(
|
|
BOOL fGrant,
|
|
DWORD dwFamily,
|
|
LPBYTE pMask,
|
|
LPBYTE pAddr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add an address entry
|
|
|
|
Arguments:
|
|
|
|
fGrant - TRUE to locate in grant list, FALSE for deny list
|
|
dwFamily - address family, as in sockaddr.sa_type
|
|
pMask - ptr to mask
|
|
pAddr - ptr to address
|
|
|
|
Return Value:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
LPBYTE pStore = m_Storage.GetAlloc();
|
|
PADDRESS_CHECK_LIST pList;
|
|
PADDRESS_HEADER pHd;
|
|
UINT iL;
|
|
UINT cS = GetAddrSize( dwFamily );
|
|
LPBYTE pA;
|
|
ADDRCMPDESC acd;
|
|
LPBYTE pS;
|
|
PADDRESS_LIST_ENTRY pE;
|
|
|
|
MakeAcd( &acd, pMask, cS );
|
|
|
|
if ( pStore )
|
|
{
|
|
pList = (PADDRESS_CHECK_LIST)pStore;
|
|
pHd = (PADDRESS_HEADER)MAKEPTR( pStore, fGrant ? pList->iGrantAddr : pList->iDenyAddr);
|
|
for ( iL = 0 ; iL < pHd->cEntries ; ++iL )
|
|
{
|
|
if ( pHd->Entries[iL].iFamily == dwFamily )
|
|
{
|
|
pS = MAKEPTR(pStore, pHd->Entries[iL].iFirstAddress );
|
|
int cm;
|
|
if ( !(cm = memcmp( pMask, pS, cS )) )
|
|
{
|
|
// found matching family, mask
|
|
// find where to insert
|
|
DWORD i;
|
|
for ( i= 1, cm = 1 ; i < pHd->Entries[iL].cAddresses ; ++i )
|
|
{
|
|
if ( !(cm = AddrCmp( pAddr, pS+cS*i, &acd )) )
|
|
{
|
|
// already exist
|
|
return FALSE;
|
|
}
|
|
else if ( cm < 0 )
|
|
{
|
|
// insert @ i
|
|
insert_addr:
|
|
UINT s = m_Storage.GetUsed();
|
|
if ( m_Storage.Resize( cS ) )
|
|
{
|
|
int l;
|
|
pStore = m_Storage.GetAlloc();
|
|
pList = (PADDRESS_CHECK_LIST)pStore;
|
|
pHd = (PADDRESS_HEADER)MAKEPTR( pStore, fGrant ? pList->iGrantAddr : pList->iDenyAddr);
|
|
pS = MAKEPTR(pStore, l=MAKEOFFSET(pHd->Entries[iL].iFirstAddress+i*cS) );
|
|
memmove( pS+cS, pS, s-l );
|
|
memcpy( pS, pAddr, cS );
|
|
AdjustRefs( pStore, pHd->Entries[iL].iFirstAddress+1, cS );
|
|
++pHd->Entries[iL].cAddresses;
|
|
++pHd->cAddresses;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
}
|
|
goto insert_addr;
|
|
}
|
|
else if ( cm < 0 )
|
|
{
|
|
insert_at_current_pos:
|
|
// must insert new Entry @ iL
|
|
int i = m_Storage.GetUsed()+sizeof(ADDRESS_LIST_ENTRY);
|
|
UINT cWasUsed = m_Storage.GetUsed();
|
|
if ( m_Storage.Resize( sizeof(ADDRESS_LIST_ENTRY)+cS*2 ) )
|
|
{
|
|
// refresh pointers
|
|
|
|
pStore = m_Storage.GetAlloc();
|
|
pList = (PADDRESS_CHECK_LIST)pStore;
|
|
pList->cRefSize += sizeof(ADDRESS_LIST_ENTRY);
|
|
pHd = (PADDRESS_HEADER)MAKEPTR( pStore, fGrant ? pList->iGrantAddr : pList->iDenyAddr);
|
|
pE = pHd->Entries + iL;
|
|
|
|
// SELFREFINDEX where to insert
|
|
UINT iS = DIFF((LPBYTE)(pHd->Entries+iL)-pStore);
|
|
|
|
// make room for entry
|
|
memmove( pE+1,
|
|
pE,
|
|
cWasUsed-iS );
|
|
AdjustRefs( pStore, DIFF((LPBYTE)pHd->Entries-pStore), sizeof(ADDRESS_LIST_ENTRY) );
|
|
|
|
// fill entry
|
|
pE->iFamily = dwFamily;
|
|
pE->cAddresses = 2;
|
|
pE->iFirstAddress = MAKEREF( i );
|
|
pE->cFullBytes = acd.cFullBytes;
|
|
pE->LastByte = acd.LastByte;
|
|
|
|
// copy mask & addr
|
|
pA = MAKEPTR( pStore, i );
|
|
memcpy( pA, pMask, cS );
|
|
memcpy( pA+cS, pAddr, cS );
|
|
|
|
++pHd->cEntries;
|
|
++pHd->cAddresses;
|
|
return TRUE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else if ( pHd->Entries[iL].iFamily > dwFamily )
|
|
{
|
|
goto insert_at_current_pos;
|
|
}
|
|
}
|
|
goto insert_at_current_pos;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
inline
|
|
DWORD
|
|
ADDRESS_CHECK::GetNbAddr(
|
|
BOOL fGrant
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get number of entries in list
|
|
|
|
Arguments:
|
|
|
|
fGrant - TRUE to locate in grant list, FALSE for deny list
|
|
|
|
Return Value:
|
|
|
|
Number of entries in list
|
|
|
|
--*/
|
|
{
|
|
LPBYTE pStore = m_Storage.GetAlloc();
|
|
PADDRESS_CHECK_LIST pList;
|
|
PADDRESS_HEADER pHd;
|
|
|
|
if ( pStore )
|
|
{
|
|
pList = (PADDRESS_CHECK_LIST)pStore;
|
|
pHd = (PADDRESS_HEADER)MAKEPTR( pStore, fGrant ? pList->iGrantAddr : pList->iDenyAddr);
|
|
return pHd->cAddresses;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
VOID
|
|
ADDRESS_CHECK::MakeAcd(
|
|
PADDRCMPDESC pacd,
|
|
LPBYTE pMask,
|
|
UINT cLen
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Build a ADDRCMPDESC struct based on ptr to mask and address length
|
|
|
|
Arguments:
|
|
|
|
pacd - ptr to ADDRCMPDESC to build
|
|
pMask - ptr to mask
|
|
cLen - address length
|
|
|
|
Return Value:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
{
|
|
pacd->pMask = pMask;
|
|
pacd->cFullBytes = 0;
|
|
pacd->LastByte = 0;
|
|
pacd->cSizeAddress = cLen;
|
|
|
|
while ( pacd->cFullBytes < cLen &&
|
|
pMask[pacd->cFullBytes] == 0xff )
|
|
{
|
|
++pacd->cFullBytes;
|
|
}
|
|
|
|
if ( pacd->cFullBytes < cLen )
|
|
{
|
|
UINT i;
|
|
|
|
pacd->LastByte = pMask[pacd->cFullBytes];
|
|
for ( i = pacd->cFullBytes+1 ; i < cLen ; ++i )
|
|
{
|
|
if ( pMask[i] != 0 )
|
|
{
|
|
// non-standard mask
|
|
pacd->cFullBytes = 0;
|
|
pacd->LastByte = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
ADDRESS_CHECK::IsMatchAddr(
|
|
BOOL fGrant,
|
|
DWORD dwFamily,
|
|
LPBYTE pAddr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check if address in list
|
|
|
|
Arguments:
|
|
|
|
fGrant - TRUE to locate in grant list, FALSE for deny list
|
|
dwFamily - address family, as in sockaddr.sa_type
|
|
pAddr - ptr to address
|
|
|
|
Return Value:
|
|
|
|
TRUE if address is in specified list, otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
LPBYTE pStore = m_Storage.GetAlloc();
|
|
PADDRESS_CHECK_LIST pList;
|
|
PADDRESS_HEADER pHd;
|
|
UINT iL;
|
|
UINT cS = GetAddrSize( dwFamily );
|
|
|
|
if ( pStore )
|
|
{
|
|
pList = (PADDRESS_CHECK_LIST)pStore;
|
|
pHd = (PADDRESS_HEADER)MAKEPTR( pStore, fGrant ? pList->iGrantAddr : pList->iDenyAddr);
|
|
for ( iL = 0 ; iL < pHd->cEntries ; ++iL )
|
|
{
|
|
if ( dwFamily == pHd->Entries[iL].iFamily )
|
|
{
|
|
ADDRCMPDESC acd;
|
|
LPBYTE pA = MAKEPTR( pStore, pHd->Entries[iL].iFirstAddress );
|
|
acd.cSizeAddress = cS;
|
|
acd.pMask = pA;
|
|
acd.cFullBytes = pHd->Entries[iL].cFullBytes;
|
|
acd.LastByte = pHd->Entries[iL].LastByte;
|
|
if ( BsearchEx( pAddr, pA+cS, pHd->Entries[iL].cAddresses - 1, cS, (CMPFUNC)AddrCmp, &acd ) )
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
else if ( dwFamily > pHd->Entries[iL].iFamily )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
VOID
|
|
ADDRESS_CHECK::AdjustRefs(
|
|
LPBYTE pStore,
|
|
DWORD dwCut,
|
|
DWORD dwAdj
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adjust references in ADDRESS_CHECK by offset dwAdj for references
|
|
above or equal to dwCut
|
|
|
|
Arguments:
|
|
|
|
pStore - ptr to address check binary object
|
|
dwCut - references above or equal to this parameter are to be adjusted
|
|
by dwAdj
|
|
dwAdj - offset to add to reference above or equal to dwCut
|
|
|
|
Return Value:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
{
|
|
LPBYTE pL = pStore + ((PADDRESS_CHECK_LIST)pStore)->cRefSize;
|
|
dwCut = MAKEREF( dwCut );
|
|
for ( ; pStore < pL ; pStore += sizeof(DWORD) )
|
|
{
|
|
if ( *((LPDWORD)pStore) >= dwCut )
|
|
{
|
|
*((LPDWORD)pStore) += dwAdj;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
UINT
|
|
ADDRESS_CHECK::GetAddrSize(
|
|
DWORD dwF
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns address size in byte based on family ( sockaddr.sa_type )
|
|
|
|
Arguments:
|
|
|
|
dwF - address family ( as in sockaddr.sa_type )
|
|
|
|
Return Value:
|
|
|
|
Address length, in byte. 0 for unknown address families
|
|
|
|
--*/
|
|
{
|
|
DWORD dwS;
|
|
|
|
switch ( dwF )
|
|
{
|
|
case AF_INET:
|
|
dwS = SIZEOF_IP_ADDRESS;
|
|
break;
|
|
|
|
default:
|
|
dwS = 0;
|
|
break;
|
|
}
|
|
|
|
return dwS;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ADDRESS_CHECK::DeleteAllAddr(
|
|
BOOL fGrant
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Delete all address entries in specified list
|
|
|
|
Arguments:
|
|
|
|
fGrant - TRUE to locate in grant list, FALSE for deny list
|
|
|
|
Return Value:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
while ( DeleteAddr( fGrant, 0 ) )
|
|
{
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
XAR::Resize(
|
|
DWORD dwDelta
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Resize storage by dwDelta.
|
|
This can modify storage ptr, so ptr based on value returned by GetAlloc()
|
|
are invalidated by calling this.
|
|
|
|
Arguments:
|
|
|
|
dwDelta - delta to add ( substract if (int)dwDelta < 0 )
|
|
to storage
|
|
|
|
Return Value:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
if ( (int)dwDelta > 0 )
|
|
{
|
|
if ( (m_cUsed + dwDelta > m_cAlloc) )
|
|
{
|
|
UINT cNew = ((m_cUsed+dwDelta+XAR_GRAIN)/XAR_GRAIN)*XAR_GRAIN;
|
|
LPBYTE p = (LPBYTE)LocalAlloc( LMEM_FIXED|LMEM_ZEROINIT, cNew );
|
|
if ( p )
|
|
{
|
|
memcpy( p, m_pAlloc, m_cUsed );
|
|
if ( m_fDidAlloc )
|
|
{
|
|
LocalFree( m_pAlloc );
|
|
}
|
|
m_pAlloc = p;
|
|
m_cAlloc = cNew;
|
|
m_fDidAlloc = TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
m_cUsed += dwDelta;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
AC_RESULT
|
|
ADDRESS_CHECK::CheckAddress(
|
|
struct sockaddr* pAddr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check if address is in grant or deny list
|
|
|
|
Arguments:
|
|
|
|
pAddr - ptr to address
|
|
|
|
Return Value:
|
|
|
|
TRUE if address is granted access, otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
LPBYTE p;
|
|
|
|
if ( !pAddr || !g_fEnableRdns )
|
|
{
|
|
goto ex;
|
|
}
|
|
|
|
// if deny list non empty, check not in list
|
|
switch ( pAddr->sa_family )
|
|
{
|
|
case AF_INET:
|
|
p = (LPBYTE)(&((PSOCKADDR_IN)pAddr)->sin_addr);
|
|
break;
|
|
|
|
case AF_IPX:
|
|
goto ex;
|
|
//p = (LPBYTE)(((PSOCKADDR)pAddr)->sa_data);
|
|
//break;
|
|
}
|
|
|
|
if ( GetNbAddr( FALSE ) )
|
|
{
|
|
if ( IsMatchAddr( FALSE, pAddr->sa_family, p ) )
|
|
{
|
|
return AC_IN_DENY_LIST;
|
|
}
|
|
return AC_NOT_IN_DENY_LIST;
|
|
}
|
|
|
|
// if grant list non empty, check in list
|
|
|
|
if ( GetNbAddr( TRUE ) )
|
|
{
|
|
if ( IsMatchAddr( TRUE, pAddr->sa_family, p ) )
|
|
{
|
|
return AC_IN_GRANT_LIST;
|
|
}
|
|
return AC_NOT_IN_GRANT_LIST;
|
|
}
|
|
|
|
ex:
|
|
return AC_NO_LIST;
|
|
}
|
|
|
|
|
|
VOID
|
|
AddrCheckDnsCallBack(
|
|
DNSARG p,
|
|
BOOL fSt,
|
|
LPSTR pDns
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback routine from reverse DNS resolver.
|
|
Shell for real function in ADDRESS_CHECK
|
|
|
|
Arguments:
|
|
|
|
p - ptr to ADDRESS_CHECK
|
|
fSt - TRUE if reverse DNS resolver success, otherwise FALSE
|
|
pDns - DNS name if fSt is TRUE
|
|
|
|
Return Value:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
{
|
|
((ADDRESS_CHECK*)p)->AddrCheckDnsCallBack( fSt, pDns );
|
|
}
|
|
|
|
|
|
VOID
|
|
AddrCheckDnsCallBack2(
|
|
DNSARG p,
|
|
BOOL fSt,
|
|
LPSTR pDns
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback routine from reverse DNS2 resolver.
|
|
Shell for real function in ADDRESS_CHECK
|
|
|
|
Arguments:
|
|
|
|
p - ptr to ADDRESS_CHECK
|
|
fSt - TRUE if reverse DNS resolver success, otherwise FALSE
|
|
pDns - DNS name if fSt is TRUE
|
|
|
|
Return Value:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
{
|
|
((ADDRESS_CHECK*)p)->AddrCheckDnsCallBack2( fSt, (struct sockaddr *)pDns );
|
|
}
|
|
|
|
|
|
VOID
|
|
AddrCheckDnsCallBack3(
|
|
DNSARG p,
|
|
BOOL fSt,
|
|
LPSTR pDns
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback routine from reverse DNS3 resolver.
|
|
Shell for real function in ADDRESS_CHECK
|
|
|
|
Arguments:
|
|
|
|
p - ptr to ADDRESS_CHECK
|
|
fSt - TRUE if reverse DNS resolver success, otherwise FALSE
|
|
pDns - DNS name if fSt is TRUE
|
|
|
|
Return Value:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
{
|
|
((ADDRESS_CHECK*)p)->AddrCheckDnsCallBack3( fSt, (struct sockaddr *)pDns );
|
|
}
|
|
|
|
|
|
VOID
|
|
ResolveDnsCallBack(
|
|
DNSARG p,
|
|
BOOL fSt,
|
|
LPSTR pDns
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback routine from reverse DNS resolver.
|
|
Shell for real function in ADDRESS_CHECK
|
|
|
|
Arguments:
|
|
|
|
p - ptr to ADDRESS_CHECK
|
|
fSt - TRUE if reverse DNS resolver success, otherwise FALSE
|
|
pDns - DNS name if fSt is TRUE
|
|
|
|
Return Value:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
{
|
|
((ADDRESS_CHECK*)p)->ResolveDnsCallBack( fSt, pDns );
|
|
}
|
|
|
|
|
|
VOID
|
|
ADDRESS_CHECK::AddrCheckDnsCallBack(
|
|
BOOL fSt,
|
|
LPSTR pDns
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback routine from reverse DNS resolver
|
|
|
|
Arguments:
|
|
|
|
fSt - TRUE if reverse DNS resolver success, otherwise FALSE
|
|
pDns - DNS name if fSt is TRUE
|
|
|
|
Return Value:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
{
|
|
m_fDnsResolved = TRUE;
|
|
|
|
if ( fSt )
|
|
{
|
|
strncpy( m_pszDnsName, pDns, DNS_MAX_NAME_LENGTH );
|
|
m_pszDnsName[ DNS_MAX_NAME_LENGTH ] = '\0';
|
|
|
|
if ( !m_Storage.GetAlloc() ||
|
|
(((PADDRESS_CHECK_LIST)m_Storage.GetAlloc())->dwFlags & RDNS_FLAG_DODNS2IPCHECK) )
|
|
{
|
|
if ( !m_fIpResolved )
|
|
{
|
|
BOOL fSync;
|
|
BOOL St;
|
|
|
|
// get IP addr
|
|
St = AsyncAddrByHost(
|
|
(PDNSFUNCDESC)&g_Dns2Ip,
|
|
(DNSARG)this,
|
|
&m_ResolvedAddr,
|
|
&fSync,
|
|
m_pszDnsName );
|
|
|
|
if ( St )
|
|
{
|
|
if ( !fSync )
|
|
{
|
|
return;
|
|
}
|
|
fSt = (!memcmp( (LPBYTE)(&((PSOCKADDR_IN)&m_ResolvedAddr)->sin_addr),
|
|
(LPBYTE)(&((PSOCKADDR_IN)m_pAddr)->sin_addr),
|
|
SIZEOF_IP_ADDRESS ) ||
|
|
(((PSOCKADDR_IN)m_pAddr)->sin_addr.s_addr == LOCALHOST_ADDRESS)) &&
|
|
CheckName( pDns );
|
|
}
|
|
else
|
|
{
|
|
m_dwErrorResolving = ERROR_INVALID_PARAMETER;
|
|
fSt = FALSE;
|
|
}
|
|
m_fIpResolved = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fSt = CheckName( pDns );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_dwErrorResolving = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
(m_HttpReqCallback)( m_HttpReqParam, fSt );
|
|
}
|
|
|
|
|
|
VOID
|
|
ADDRESS_CHECK::AddrCheckDnsCallBack2(
|
|
BOOL fSt,
|
|
struct sockaddr*pAddr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback routine from reverse DNS2 resolver
|
|
|
|
Arguments:
|
|
|
|
fSt - TRUE if reverse DNS resolver success, otherwise FALSE
|
|
pAddr - address if fSt is TRUE
|
|
|
|
Return Value:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
{
|
|
m_fIpResolved = TRUE;
|
|
|
|
memcpy( &m_ResolvedAddr, pAddr, sizeof(struct sockaddr*) );
|
|
|
|
if ( fSt )
|
|
{
|
|
fSt = (!memcmp( (LPBYTE)(&((PSOCKADDR_IN)pAddr)->sin_addr),
|
|
(LPBYTE)(&((PSOCKADDR_IN)m_pAddr)->sin_addr),
|
|
SIZEOF_IP_ADDRESS ) ||
|
|
(((PSOCKADDR_IN)m_pAddr)->sin_addr.s_addr == LOCALHOST_ADDRESS)) &&
|
|
CheckName( m_pszDnsName );
|
|
}
|
|
else
|
|
{
|
|
m_dwErrorResolving = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
(m_HttpReqCallback)( m_HttpReqParam, fSt );
|
|
}
|
|
|
|
|
|
VOID
|
|
ADDRESS_CHECK::AddrCheckDnsCallBack3(
|
|
BOOL fSt,
|
|
struct sockaddr*pAddr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback routine from reverse DNS3 resolver
|
|
|
|
Arguments:
|
|
|
|
fSt - TRUE if reverse DNS resolver success, otherwise FALSE
|
|
pAddr - address if fSt is TRUE
|
|
|
|
Return Value:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
{
|
|
m_fIpResolved = TRUE;
|
|
|
|
memcpy( &m_ResolvedAddr, pAddr, sizeof(struct sockaddr*) );
|
|
|
|
if ( fSt )
|
|
{
|
|
fSt = !memcmp( (LPBYTE)(&((PSOCKADDR_IN)pAddr)->sin_addr),
|
|
(LPBYTE)(&((PSOCKADDR_IN)m_pAddr)->sin_addr),
|
|
SIZEOF_IP_ADDRESS ) ||
|
|
(((PSOCKADDR_IN)m_pAddr)->sin_addr.s_addr == LOCALHOST_ADDRESS);
|
|
if ( !fSt )
|
|
{
|
|
m_pszDnsName[ 0 ] = '\0';
|
|
}
|
|
}
|
|
|
|
(m_HttpReqCallbackEx)( m_HttpReqParam, fSt, m_pszDnsName );
|
|
}
|
|
|
|
|
|
VOID
|
|
ADDRESS_CHECK::ResolveDnsCallBack(
|
|
BOOL fSt,
|
|
LPSTR pDns
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback routine from reverse DNS resolver
|
|
|
|
Arguments:
|
|
|
|
fSt - TRUE if reverse DNS resolver success, otherwise FALSE
|
|
pDns - DNS name if fSt is TRUE
|
|
|
|
Return Value:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
{
|
|
m_fDnsResolved = TRUE;
|
|
|
|
if ( fSt )
|
|
{
|
|
strncpy( m_pszDnsName, pDns, DNS_MAX_NAME_LENGTH );
|
|
m_pszDnsName[ DNS_MAX_NAME_LENGTH ] = '\0';
|
|
|
|
if ( !m_Storage.GetAlloc() ||
|
|
(((PADDRESS_CHECK_LIST)m_Storage.GetAlloc())->dwFlags & RDNS_FLAG_DODNS2IPCHECK) )
|
|
{
|
|
if ( !m_fIpResolved )
|
|
{
|
|
BOOL fSync;
|
|
BOOL St;
|
|
|
|
// get IP addr
|
|
St = AsyncAddrByHost(
|
|
(PDNSFUNCDESC)&g_ResolveDns2Ip,
|
|
(DNSARG)this,
|
|
&m_ResolvedAddr,
|
|
&fSync,
|
|
m_pszDnsName );
|
|
|
|
if ( St )
|
|
{
|
|
if ( !fSync )
|
|
{
|
|
return;
|
|
}
|
|
fSt = (!memcmp( (LPBYTE)(&((PSOCKADDR_IN)&m_ResolvedAddr)->sin_addr),
|
|
(LPBYTE)(&((PSOCKADDR_IN)m_pAddr)->sin_addr),
|
|
SIZEOF_IP_ADDRESS ) ||
|
|
(((PSOCKADDR_IN)m_pAddr)->sin_addr.s_addr == LOCALHOST_ADDRESS)) &&
|
|
CheckName( pDns );
|
|
}
|
|
else
|
|
{
|
|
fSt = FALSE;
|
|
}
|
|
m_fIpResolved = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
(m_HttpReqCallbackEx)( m_HttpReqParam, fSt, pDns );
|
|
}
|
|
|
|
|
|
AC_RESULT
|
|
ADDRESS_CHECK::CheckAccess(
|
|
LPBOOL pfSync,
|
|
ADDRCHECKFUNC pFunc,
|
|
ADDRCHECKARG pArg
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check that bound address has access to bound check list
|
|
validation can be either synchronous or asynchronous, caller
|
|
must handle both cases.
|
|
If async, caller must be prepared to handle completion notification
|
|
at any time after calling this function.
|
|
|
|
Arguments:
|
|
|
|
pfSync - updated with TRUE if validation was synchronous
|
|
( i.e. if return value reflect validation status )
|
|
pFunc - ptr to callback routine use if asynchronous validation
|
|
pArg - argument used when calling pFunc
|
|
|
|
Return Value:
|
|
|
|
If sync, TRUE if bound address validated, otherwise FALSE
|
|
If async, TRUE if request successfully queued, otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
BOOL St;
|
|
AC_RESULT fSt = CheckAddress( m_pAddr );
|
|
|
|
if ( fSt == AC_IN_DENY_LIST || fSt == AC_IN_GRANT_LIST )
|
|
{
|
|
*pfSync = TRUE;
|
|
return fSt;
|
|
}
|
|
|
|
if ( !GetNbName( TRUE ) && !GetNbName(FALSE) )
|
|
{
|
|
*pfSync = TRUE;
|
|
return fSt;
|
|
}
|
|
|
|
if ( !m_fDnsResolved )
|
|
{
|
|
if ( m_pszDnsName == NULL )
|
|
{
|
|
m_pszDnsName = (CHAR*) LocalAlloc( LPTR, DNS_MAX_NAME_LENGTH + 1 );
|
|
if ( m_pszDnsName == NULL )
|
|
{
|
|
*pfSync = TRUE;
|
|
return AC_NOT_CHECKED;
|
|
}
|
|
}
|
|
|
|
m_HttpReqCallback = pFunc;
|
|
m_HttpReqParam = pArg;
|
|
|
|
// get DNS name
|
|
St = AsyncHostByAddr(
|
|
(PDNSFUNCDESC)&g_Ip2Dns,
|
|
(DNSARG)this,
|
|
m_pAddr,
|
|
pfSync,
|
|
m_pszDnsName,
|
|
DNS_MAX_NAME_LENGTH
|
|
);
|
|
if ( !St || !*pfSync )
|
|
{
|
|
return AC_NOT_CHECKED;
|
|
}
|
|
m_fDnsResolved = TRUE;
|
|
}
|
|
else
|
|
{
|
|
*pfSync = TRUE;
|
|
}
|
|
|
|
if ( !m_Storage.GetAlloc() ||
|
|
(((PADDRESS_CHECK_LIST)m_Storage.GetAlloc())->dwFlags & RDNS_FLAG_DODNS2IPCHECK) )
|
|
{
|
|
if ( !m_fIpResolved )
|
|
{
|
|
// get IP addr
|
|
St = AsyncAddrByHost(
|
|
(PDNSFUNCDESC)&g_Dns2Ip,
|
|
(DNSARG)this,
|
|
&m_ResolvedAddr,
|
|
pfSync,
|
|
m_pszDnsName );
|
|
if ( !St || !*pfSync )
|
|
{
|
|
return AC_NOT_CHECKED;
|
|
}
|
|
m_fIpResolved = TRUE;
|
|
}
|
|
if ( memcmp( (LPBYTE)(&((PSOCKADDR_IN)&m_ResolvedAddr)->sin_addr),
|
|
(LPBYTE)(&((PSOCKADDR_IN)m_pAddr)->sin_addr),
|
|
SIZEOF_IP_ADDRESS ) &&
|
|
(((PSOCKADDR_IN)m_pAddr)->sin_addr.s_addr != LOCALHOST_ADDRESS))
|
|
{
|
|
return AC_IN_DENY_LIST;
|
|
}
|
|
}
|
|
|
|
return CheckName( m_pszDnsName );
|
|
}
|
|
|
|
|
|
AC_RESULT
|
|
ADDRESS_CHECK::CheckIpAccess(
|
|
LPBOOL pfNeedDns
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check that bound address has access to bound IP check list
|
|
|
|
Arguments:
|
|
|
|
pfNeedDns - updated with TRUE if DNS access check necessary
|
|
|
|
Return Value:
|
|
|
|
returns AC_RESULT
|
|
|
|
--*/
|
|
{
|
|
AC_RESULT ac = CheckAddress( m_pAddr );
|
|
|
|
if ( ac != AC_IN_DENY_LIST && ac != AC_IN_GRANT_LIST )
|
|
{
|
|
*pfNeedDns = (GetNbName( TRUE ) || GetNbName(FALSE));
|
|
}
|
|
else
|
|
{
|
|
*pfNeedDns = FALSE;
|
|
}
|
|
|
|
return ac;
|
|
}
|
|
|
|
#if 0
|
|
AC_RESULT
|
|
ADDRESS_CHECK::CheckDnsAccess(
|
|
LPBOOL pfGranted,
|
|
LPBOOL pfIsList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check that bound DNS name has access to bound DNS check list
|
|
|
|
Arguments:
|
|
|
|
pfGranted - updated with TRUE if access granted, otherwise FALSE
|
|
pfIsList- updated with TRUE if address found in deny/grant list
|
|
|
|
Return Value:
|
|
|
|
return TRUE if no error, otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
return CheckName( m_pszDnsName );
|
|
|
|
}
|
|
#endif
|
|
|
|
|
|
LPSTR
|
|
ADDRESS_CHECK::InitReverse(
|
|
LPSTR pR,
|
|
LPSTR pTarget,
|
|
LPBOOL pfAlloc
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Build a reversed DNS representation of supplied DNS name
|
|
|
|
Arguments:
|
|
|
|
pR - DNS name to reverse
|
|
pTarget - ptr to buffer to be used for reverse representation,
|
|
assumed to be SIZE_FAST_REVERSE_DNS byte wide
|
|
pfAlloc - updated with TRUE if memory allocation was necessary
|
|
to hold result. To be presented to TerminateReverse()
|
|
|
|
Return Value:
|
|
|
|
buffer holding reversed representation of DNS name, to be presented
|
|
to TerminateReverse()
|
|
|
|
--*/
|
|
{
|
|
UINT l = strlen( pR );
|
|
LPSTR p = pTarget;
|
|
if ( l > SIZE_FAST_REVERSE_DNS )
|
|
{
|
|
if ( (p = (LPSTR)LocalAlloc( LMEM_FIXED, l ))==NULL )
|
|
{
|
|
// BugFix: 47980, 47981, 47989 Whistler
|
|
// Prefix bug pfAlloc not being set.
|
|
// EBK 5/5/2000
|
|
*pfAlloc = FALSE;
|
|
return p;
|
|
}
|
|
*pfAlloc = TRUE;
|
|
}
|
|
else
|
|
{
|
|
*pfAlloc = FALSE;
|
|
}
|
|
|
|
// reverse pR to p
|
|
|
|
LPSTR pD;
|
|
UINT cS;
|
|
LPSTR pT = p + l;
|
|
|
|
*pT = '\0';
|
|
|
|
if ( *pR )
|
|
{
|
|
for ( ;; )
|
|
{
|
|
if ( pD = (LPSTR)memchr( pR, '.', l ) )
|
|
{
|
|
cS = DIFF(pD - pR);
|
|
}
|
|
else
|
|
{
|
|
cS = l;
|
|
}
|
|
|
|
memcpy( pT - cS, pR, cS );
|
|
|
|
if ( pR[cS++] )
|
|
{
|
|
pR += cS;
|
|
pT -= cS;
|
|
*pT = '.';
|
|
l -= cS;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
|
|
VOID
|
|
ADDRESS_CHECK::TerminateReverse(
|
|
LPSTR pAlloc,
|
|
BOOL fAlloc
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free resources used by InitReverse
|
|
|
|
Arguments:
|
|
|
|
pAlloc - buffer holding result of InitReverse()
|
|
fAlloc - flag updated by InitReverse()
|
|
|
|
Return Value:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
{
|
|
if ( fAlloc )
|
|
{
|
|
LocalFree( pAlloc );
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
ADDRESS_CHECK::CheckReversedName(
|
|
LPSTR pName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check if DNS name ( reversed format ) is in grant or deny list
|
|
|
|
Arguments:
|
|
|
|
pName - DNS name
|
|
|
|
Return Value:
|
|
|
|
TRUE if name is granted access, otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
CHAR achReversed[SIZE_FAST_REVERSE_DNS];
|
|
|
|
// BugFix: 117800, 117809, 117818, Whistler
|
|
// Prefix bug fAlloc not being set.
|
|
// Prefix did not like the fix to just make
|
|
// sure it was set in InitReverse, so now I
|
|
// am initializing it prior to the call. It's
|
|
// overkill, but should make prefix happy.
|
|
// EBK 5/15/2000
|
|
BOOL fAlloc = FALSE;
|
|
LPSTR pReversed;
|
|
BOOL fSt;
|
|
|
|
if ( pReversed = InitReverse( pName, achReversed, &fAlloc ) )
|
|
{
|
|
fSt = CheckReversedName( pReversed );
|
|
}
|
|
else
|
|
{
|
|
fSt = FALSE;
|
|
}
|
|
|
|
TerminateReverse( pReversed, fAlloc );
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
AC_RESULT
|
|
ADDRESS_CHECK::CheckName(
|
|
LPSTR pName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check if DNS name is in grant or deny list
|
|
|
|
Arguments:
|
|
|
|
pName - DNS name
|
|
|
|
Return Value:
|
|
|
|
TRUE if name is granted access, otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
// if name is empty, it cannot be checked
|
|
if (pName[0] == '\0')
|
|
{
|
|
return AC_NOT_CHECKED;
|
|
}
|
|
|
|
// if deny list non empty, check not in list
|
|
|
|
if ( GetNbName( FALSE ) )
|
|
{
|
|
if ( IsMatchName( FALSE, pName ) )
|
|
{
|
|
return AC_IN_DENY_LIST;
|
|
}
|
|
return AC_NOT_IN_DENY_LIST;
|
|
}
|
|
|
|
// if grant list non empty, check in list
|
|
|
|
if ( GetNbName( TRUE ) )
|
|
{
|
|
if ( IsMatchName( TRUE, pName ) )
|
|
{
|
|
return AC_IN_GRANT_LIST;
|
|
}
|
|
return AC_NOT_IN_GRANT_LIST;
|
|
}
|
|
|
|
return AC_NO_LIST;
|
|
}
|
|
|
|
|
|
UINT
|
|
ADDRESS_CHECK::GetNbComponent(
|
|
LPSTR pName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns number of components in DNS name
|
|
|
|
Arguments:
|
|
|
|
pName - DNS name
|
|
|
|
Return Value:
|
|
|
|
Number of components.
|
|
|
|
--*/
|
|
{
|
|
LPSTR pDot = pName;
|
|
UINT cComp;
|
|
|
|
for ( cComp = 1 ; pDot = strchr( pDot, '.') ; ++cComp )
|
|
{
|
|
++pDot;
|
|
}
|
|
|
|
return cComp;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ADDRESS_CHECK::AddReversedName(
|
|
BOOL fGrant,
|
|
LPSTR pName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add a name entry, reversing its DNS components
|
|
|
|
Arguments:
|
|
|
|
fGrant - TRUE to locate in grant list, FALSE for deny list
|
|
pName - ptr to DNS name
|
|
|
|
Return Value:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
CHAR achReversed[SIZE_FAST_REVERSE_DNS];
|
|
// BugFix: 117800, 117809, 117818, Whistler
|
|
// Prefix bug fAlloc not being set.
|
|
// Prefix did not like the fix to just make
|
|
// sure it was set in InitReverse, so now I
|
|
// am initializing it prior to the call. It's
|
|
// overkill, but should make prefix happy.
|
|
// EBK 5/15/2000
|
|
BOOL fAlloc = FALSE;
|
|
LPSTR pReversed;
|
|
BOOL fSt;
|
|
|
|
if ( pReversed = InitReverse( pName, achReversed, &fAlloc ) )
|
|
{
|
|
fSt = AddName( fGrant, pReversed );
|
|
}
|
|
else
|
|
{
|
|
fSt = FALSE;
|
|
}
|
|
|
|
TerminateReverse( pReversed, fAlloc );
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ADDRESS_CHECK::AddName(
|
|
BOOL fGrant,
|
|
LPSTR pName,
|
|
DWORD dwFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add a name entry
|
|
|
|
Arguments:
|
|
|
|
fGrant - TRUE to locate in grant list, FALSE for deny list
|
|
pName - ptr to DNS name
|
|
dwFlags - flags
|
|
|
|
Return Value:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
LPBYTE pStore = m_Storage.GetAlloc();
|
|
PADDRESS_CHECK_LIST pList;
|
|
PNAME_HEADER pHd;
|
|
UINT iL;
|
|
UINT cS = GetNbComponent( pName ) | ( dwFlags & DNSLIST_FLAG_NOSUBDOMAIN );
|
|
UINT cN = strlen( pName ) + 1;
|
|
LPBYTE pA;
|
|
LPBYTE pS;
|
|
PNAME_LIST_ENTRY pE;
|
|
UINT iS;
|
|
int cm;
|
|
|
|
if ( pStore )
|
|
{
|
|
pList = (PADDRESS_CHECK_LIST)pStore;
|
|
pHd = (PNAME_HEADER)MAKEPTR( pStore, fGrant ? pList->iGrantName : pList->iDenyName);
|
|
pE = (PNAME_LIST_ENTRY)((LPBYTE)pHd + sizeof(NAME_HEADER));
|
|
for ( iL = 0 ; iL < pHd->cEntries ; ++iL )
|
|
{
|
|
if ( pE->cComponents == cS )
|
|
{
|
|
// found matching family, mask
|
|
// find where to insert
|
|
DWORD i;
|
|
for ( i= 0 ; i < pE->cNames ; ++i )
|
|
{
|
|
pS = MAKEPTR(pStore, pE->iName[i] );
|
|
if ( !(cm = _stricmp( pName, (LPSTR)pS )) )
|
|
{
|
|
// already exist
|
|
return FALSE;
|
|
}
|
|
else if ( cm < 0 )
|
|
{
|
|
// insert @ i
|
|
insert_name:
|
|
UINT s = m_Storage.GetUsed();
|
|
iS = DIFF((LPBYTE)pE - pStore);
|
|
if ( m_Storage.Resize( sizeof(SELFREFINDEX)+cN ) )
|
|
{
|
|
int l;
|
|
// refresh ptrs
|
|
pStore = m_Storage.GetAlloc();
|
|
pList = (PADDRESS_CHECK_LIST)pStore;
|
|
pHd = (PNAME_HEADER)MAKEPTR( pStore, fGrant ? pList->iGrantName : pList->iDenyName);
|
|
pE = (PNAME_LIST_ENTRY)(pStore+iS);
|
|
|
|
pS = MAKEPTR(pStore, l=DIFF((LPBYTE)(pE->iName+i)-pStore) );
|
|
memmove( pS+sizeof(SELFREFINDEX), pS, s-l );
|
|
pList->cRefSize += sizeof(SELFREFINDEX);
|
|
AdjustRefs( pStore, l, sizeof(SELFREFINDEX) );
|
|
s+=sizeof(SELFREFINDEX);
|
|
pE->iName[i] = MAKEREF(s);
|
|
memcpy( MAKEPTR(pStore,s), pName, cN );
|
|
++pE->cNames;
|
|
++pHd->cNames;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
}
|
|
goto insert_name;
|
|
}
|
|
else if ( cS < pE->cComponents )
|
|
{
|
|
insert_at_current_pos:
|
|
// must insert new Entry @ pE
|
|
int i = m_Storage.GetUsed()+sizeof(NAME_LIST_ENTRY)+sizeof(SELFREFINDEX);
|
|
UINT iS = DIFF((LPBYTE)pE - pStore);
|
|
UINT cWasUsed = m_Storage.GetUsed();
|
|
if ( m_Storage.Resize( sizeof(NAME_LIST_ENTRY)+sizeof(SELFREFINDEX)+cN ) )
|
|
{
|
|
// refresh ptrs
|
|
pStore = m_Storage.GetAlloc();
|
|
pList = (PADDRESS_CHECK_LIST)pStore;
|
|
pHd = (PNAME_HEADER)MAKEPTR( pStore, fGrant ? pList->iGrantName : pList->iDenyName);
|
|
pE = (PNAME_LIST_ENTRY)(pStore +iS);
|
|
pList->cRefSize += sizeof(NAME_LIST_ENTRY)+sizeof(SELFREFINDEX);
|
|
|
|
// make room for entry
|
|
memmove( (LPBYTE)(pE+1) + sizeof(SELFREFINDEX),
|
|
pE,
|
|
cWasUsed - iS );
|
|
AdjustRefs( pStore, iS, sizeof(NAME_LIST_ENTRY)+sizeof(SELFREFINDEX) );
|
|
|
|
pE->cComponents = cS;
|
|
pE->cNames = 1;
|
|
pE->iName[0] = MAKEREF( i );
|
|
|
|
// copy name
|
|
pA = MAKEPTR( pStore, i );
|
|
memcpy( pA, pName, cN );
|
|
|
|
++pHd->cEntries;
|
|
++pHd->cNames;
|
|
return TRUE;
|
|
}
|
|
break;
|
|
}
|
|
pE = (PNAME_LIST_ENTRY)((LPBYTE)pE + sizeof(NAME_LIST_ENTRY) + pE->cNames * sizeof(SELFREFINDEX));
|
|
}
|
|
goto insert_at_current_pos;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ADDRESS_CHECK::DeleteName(
|
|
BOOL fGrant,
|
|
DWORD iIndex
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Delete a DNS name entry
|
|
|
|
Arguments:
|
|
|
|
fGrant - TRUE to locate in grant list, FALSE for deny list
|
|
iIndex - index in list (0-based )
|
|
|
|
Return Value:
|
|
|
|
TRUE if iIndex valid in array defined by fGrant, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
PNAME_LIST_ENTRY pE;
|
|
PNAME_HEADER pHd;
|
|
DWORD iIndexInHeader;
|
|
LPBYTE pStore = m_Storage.GetAlloc();
|
|
|
|
if ( LocateName( fGrant, iIndex, &pHd, &pE, &iIndexInHeader ) )
|
|
{
|
|
UINT iS = MAKEOFFSET( pE->iName[iIndexInHeader] );
|
|
LPBYTE pAddr = MAKEPTR(pStore, iS);
|
|
UINT cS = strlen( (LPSTR)pAddr ) + 1;
|
|
|
|
memmove( pAddr,
|
|
pAddr + cS,
|
|
m_Storage.GetUsed() - iS - cS );
|
|
AdjustRefs( pStore, iS, -(int)cS );
|
|
m_Storage.AdjustUsed( -(int)cS );
|
|
|
|
iS = DIFF((LPBYTE)(pE->iName+iIndexInHeader) - pStore);
|
|
memmove( pE->iName+iIndexInHeader,
|
|
pE->iName+iIndexInHeader+1,
|
|
m_Storage.GetUsed() - iS - sizeof(SELFREFINDEX) );
|
|
((PADDRESS_CHECK_LIST)pStore)->cRefSize -= sizeof(SELFREFINDEX);
|
|
AdjustRefs( pStore, DIFF((LPBYTE)pE - pStore), (DWORD)-(int)sizeof(SELFREFINDEX) );
|
|
m_Storage.AdjustUsed( -(int)sizeof(SELFREFINDEX) );
|
|
|
|
--pE->cNames;
|
|
--pHd->cNames;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ADDRESS_CHECK::GetReversedName(
|
|
BOOL fGrant,
|
|
DWORD iIndex,
|
|
LPSTR pName,
|
|
LPDWORD pdwSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get DNS name in specified list
|
|
|
|
Arguments:
|
|
|
|
fGrant - TRUE to locate in grant list, FALSE for deny list
|
|
iIndex - index (0-based) in specified list
|
|
pName - ptr to buffer to be used to hold result
|
|
pdwSize - in: specify buffer max length. out: result size
|
|
( including '\0' delimiter )
|
|
|
|
Return Value:
|
|
|
|
TRUE if iIndex valid in specified list and buffer wide enough
|
|
to hold result, FALSE otherwise ( can be ERROR_NOT_ENOUGH_MEMORY,
|
|
ERROR_INVALID_PARAMETER )
|
|
|
|
--*/
|
|
{
|
|
CHAR achReversed[SIZE_FAST_REVERSE_DNS];
|
|
|
|
// BugFix: 117800, 117809, 117818, Whistler
|
|
// Prefix bug fAlloc not being set.
|
|
// Prefix did not like the fix to just make
|
|
// sure it was set in InitReverse, so now I
|
|
// am initializing it prior to the call. It's
|
|
// overkill, but should make prefix happy.
|
|
// EBK 5/15/2000
|
|
BOOL fAlloc = FALSE;
|
|
LPSTR pReversed;
|
|
BOOL fSt = FALSE;
|
|
LPSTR pRName;
|
|
|
|
if ( GetName( fGrant, iIndex, &pRName ) )
|
|
{
|
|
if ( pReversed = InitReverse( pRName, achReversed, &fAlloc ) )
|
|
{
|
|
UINT l = strlen( pReversed ) + 1;
|
|
if ( l <= *pdwSize )
|
|
{
|
|
memcpy( pName, pReversed, l );
|
|
fSt = TRUE;
|
|
}
|
|
else
|
|
{
|
|
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
*pdwSize = l;
|
|
}
|
|
else
|
|
{
|
|
SetLastError( 0 );
|
|
*pdwSize = 0;
|
|
}
|
|
|
|
TerminateReverse( pReversed, fAlloc );
|
|
}
|
|
else
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
*pdwSize = 0;
|
|
}
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ADDRESS_CHECK::GetName(
|
|
BOOL fGrant,
|
|
DWORD iIndex,
|
|
LPSTR* ppName,
|
|
LPDWORD pdwFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get DNS name in specified list
|
|
|
|
Arguments:
|
|
|
|
fGrant - TRUE to locate in grant list, FALSE for deny list
|
|
iIndex - index (0-based) in specified list
|
|
ppName - updated with ptr to DNS name
|
|
pdwFlags - updated with DNS flags, can be NULL
|
|
|
|
Return Value:
|
|
|
|
TRUE if iIndex valid in specified list, otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
PNAME_LIST_ENTRY pHeader;
|
|
PNAME_HEADER pHd;
|
|
DWORD iIndexInHeader;
|
|
LPBYTE pStore = m_Storage.GetAlloc();
|
|
|
|
if ( LocateName( fGrant, iIndex, &pHd, &pHeader, &iIndexInHeader ) )
|
|
{
|
|
*ppName = (LPSTR)MAKEPTR(pStore, pHeader->iName[iIndexInHeader] );
|
|
if ( pdwFlags )
|
|
{
|
|
*pdwFlags = pHeader->cComponents & DNSLIST_FLAGS;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
DWORD
|
|
ADDRESS_CHECK::GetNbName(
|
|
BOOL fGrant
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get number of entries in list
|
|
|
|
Arguments:
|
|
|
|
fGrant - TRUE to locate in grant list, FALSE for deny list
|
|
|
|
Return Value:
|
|
|
|
Number of entries in list
|
|
|
|
--*/
|
|
{
|
|
LPBYTE pStore = m_Storage.GetAlloc();
|
|
PADDRESS_CHECK_LIST pList;
|
|
PNAME_HEADER pHd;
|
|
|
|
if ( pStore )
|
|
{
|
|
pList = (PADDRESS_CHECK_LIST)pStore;
|
|
pHd = (PNAME_HEADER)MAKEPTR( pStore, fGrant ? pList->iGrantName : pList->iDenyName);
|
|
return pHd->cNames;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ADDRESS_CHECK::LocateName(
|
|
BOOL fGrant,
|
|
DWORD iIndex,
|
|
PNAME_HEADER* ppHd,
|
|
PNAME_LIST_ENTRY* pHeader,
|
|
LPDWORD piIndexInHeader
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Locate a name in the specified list, returns ptr
|
|
to header & element in address list
|
|
|
|
Arguments:
|
|
|
|
fGrant - TRUE to locate in grant list, FALSE for deny list
|
|
iIndex - index in list ( 0-based )
|
|
ppHd - updated with ptr to name header
|
|
pHeader - updated with ptr to name list entry
|
|
piIndexInHeader - updated with index in array pHeader->iName
|
|
|
|
Return Value:
|
|
|
|
TRUE if iIndex valid in array defined by fGrant, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
LPBYTE pStore = m_Storage.GetAlloc();
|
|
PADDRESS_CHECK_LIST pList;
|
|
PNAME_HEADER pHd;
|
|
PNAME_LIST_ENTRY pE;
|
|
UINT iL;
|
|
|
|
if ( pStore )
|
|
{
|
|
pList = (PADDRESS_CHECK_LIST)pStore;
|
|
*ppHd = pHd = (PNAME_HEADER)MAKEPTR( pStore, fGrant ? pList->iGrantName : pList->iDenyName);
|
|
pE = (PNAME_LIST_ENTRY)((LPBYTE)pHd + sizeof(NAME_HEADER));
|
|
for ( iL = 0 ; iL < pHd->cEntries ; ++iL )
|
|
{
|
|
if ( iIndex < pE->cNames )
|
|
{
|
|
*pHeader = pE;
|
|
*piIndexInHeader = iIndex;
|
|
return TRUE;
|
|
}
|
|
iIndex -= pE->cNames;
|
|
pE = (PNAME_LIST_ENTRY)((LPBYTE)pE + sizeof(NAME_LIST_ENTRY) + pE->cNames * sizeof(SELFREFINDEX));
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ADDRESS_CHECK::DeleteAllName(
|
|
BOOL fGrant
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Delete all DNS name entries
|
|
|
|
Arguments:
|
|
|
|
fGrant - TRUE to delete in grant list, FALSE for deny list
|
|
|
|
Return Value:
|
|
|
|
TRUE if success, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
while ( DeleteName( fGrant, 0 ) )
|
|
{
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ADDRESS_CHECK::IsMatchName(
|
|
BOOL fGrant,
|
|
LPSTR pName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check if name in list
|
|
|
|
Arguments:
|
|
|
|
fGrant - TRUE to locate in grant list, FALSE for deny list
|
|
pName - ptr to DNS name
|
|
|
|
Return Value:
|
|
|
|
TRUE if name is in specified list, otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
LPBYTE pStore = m_Storage.GetAlloc();
|
|
PADDRESS_CHECK_LIST pList;
|
|
PNAME_HEADER pHd;
|
|
PNAME_LIST_ENTRY pE;
|
|
UINT iL;
|
|
UINT cS;
|
|
NAMECMPDESC ncd;
|
|
DWORD cbNameLength;
|
|
BOOL fTryAgain = FALSE;
|
|
CHAR achName[ DNS_MAX_NAME_LENGTH + 1 ];
|
|
|
|
ncd.pBase = pStore;
|
|
|
|
if ( pStore )
|
|
{
|
|
strncpy( achName, pName, DNS_MAX_NAME_LENGTH );
|
|
achName[ DNS_MAX_NAME_LENGTH ] = '\0';
|
|
|
|
cbNameLength = strlen( achName );
|
|
pName = achName;
|
|
|
|
// BugFix: 47983 Whistler
|
|
// Prefix bug pName not being valid.
|
|
// EBK 5/5/2000
|
|
DBG_ASSERT(cbNameLength >= 1);
|
|
|
|
if ( pName && pName[ cbNameLength - 1 ] == '.' )
|
|
{
|
|
// This is an FQDN (i.e. it has a period at the end).
|
|
// We need to be more careful with our handling of it, since we want
|
|
// to match against checks which didn't specify the trailing period.
|
|
|
|
fTryAgain = TRUE;
|
|
|
|
// Temporarily remove the trailing period
|
|
|
|
pName[ cbNameLength - 1 ] = '\0';
|
|
}
|
|
TryAgain:
|
|
/* INTRINSA suppress = uninitialized */
|
|
cS = GetNbComponent( pName );
|
|
|
|
pList = (PADDRESS_CHECK_LIST)pStore;
|
|
pHd = (PNAME_HEADER)MAKEPTR( pStore, fGrant ? pList->iGrantName : pList->iDenyName);
|
|
pE = (PNAME_LIST_ENTRY)((LPBYTE)pHd + sizeof(NAME_HEADER));
|
|
for ( iL = 0 ; iL < pHd->cEntries ; ++iL )
|
|
{
|
|
UINT cASComp = pE->cComponents & ~DNSLIST_FLAGS;
|
|
if ( cS == cASComp ||
|
|
((cS > cASComp) && !(pE->cComponents & DNSLIST_FLAG_NOSUBDOMAIN)) )
|
|
{
|
|
LPSTR p = pName;
|
|
BOOL fSt;
|
|
if ( cS > cASComp )
|
|
{
|
|
int i = cS - cASComp;
|
|
for ( ; i-- ; )
|
|
{
|
|
if ( p = strchr( p, '.' ) )
|
|
{
|
|
++p;
|
|
}
|
|
}
|
|
}
|
|
ncd.pName = (LPVOID)p;
|
|
|
|
fSt = BsearchEx( p,
|
|
pE->iName,
|
|
pE->cNames,
|
|
sizeof(SELFREFINDEX),
|
|
(CMPFUNC)NameCmp,
|
|
&ncd ) != NULL;
|
|
if ( fSt )
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
pE = (PNAME_LIST_ENTRY)((LPBYTE)pE + sizeof(NAME_LIST_ENTRY) + pE->cNames * sizeof(SELFREFINDEX));
|
|
}
|
|
|
|
if ( fTryAgain )
|
|
{
|
|
fTryAgain = FALSE;
|
|
|
|
pName[ cbNameLength - 1 ] = '.';
|
|
goto TryAgain;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
#if 0 // inlined now
|
|
|
|
BOOL
|
|
ADDRESS_CHECK::BindAddr(
|
|
struct sockaddr* pAddr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Bind an address to an ADDRESS_CHECK object
|
|
|
|
Arguments:
|
|
|
|
pAddr - ptr to address
|
|
|
|
Return Value:
|
|
|
|
TRUE if sucess, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
m_pAddr = pAddr;
|
|
m_fDnsResolved = FALSE;
|
|
m_fIpResolved = FALSE;
|
|
m_dwErrorResolving = 0;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
ADDRESS_CHECK::UnbindAddr(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Unbind an address to an ADDRESS_CHECK object
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
{
|
|
m_pAddr = NULL;
|
|
m_fDnsResolved = FALSE;
|
|
}
|
|
|
|
# endif // 0
|
|
|
|
BOOL
|
|
ADDRESS_CHECK::QueryDnsName(
|
|
LPBOOL pfSync,
|
|
ADDRCHECKFUNCEX pFunc,
|
|
ADDRCHECKARG pArg,
|
|
LPSTR * ppName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reverse resolve bound address to DNS name
|
|
|
|
Arguments:
|
|
|
|
pfSync - updated with TRUE if validation was synchronous
|
|
( i.e. if return value reflect validation status )
|
|
pFunc - ptr to callback routine use if asynchronous validation
|
|
pArg - argument used when calling pFunc
|
|
|
|
Return Value:
|
|
|
|
If sync, TRUE if bound address validated, otherwise FALSE
|
|
If async, TRUE if request successfully queued, otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
BOOL fSt;
|
|
|
|
if ( !m_pAddr )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if ( !m_fDnsResolved )
|
|
{
|
|
if ( m_pszDnsName == NULL )
|
|
{
|
|
m_pszDnsName = (CHAR*) LocalAlloc( LPTR, DNS_MAX_NAME_LENGTH + 1 );
|
|
if ( m_pszDnsName == NULL )
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
m_HttpReqCallbackEx = pFunc;
|
|
m_HttpReqParam = pArg;
|
|
|
|
// get DNS name
|
|
fSt = AsyncHostByAddr(
|
|
(PDNSFUNCDESC)(pFunc ? &g_ResolveDns : NULL),
|
|
(DNSARG)this,
|
|
m_pAddr,
|
|
pfSync,
|
|
m_pszDnsName,
|
|
DNS_MAX_NAME_LENGTH
|
|
);
|
|
if ( !fSt || !*pfSync )
|
|
{
|
|
return fSt;
|
|
}
|
|
m_fDnsResolved = TRUE;
|
|
|
|
if ( m_pszDnsName[ 0 ] == '\0' )
|
|
{
|
|
m_dwErrorResolving = ERROR_INVALID_PARAMETER;
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*pfSync = TRUE;
|
|
}
|
|
|
|
if ( !m_Storage.GetAlloc() ||
|
|
(((PADDRESS_CHECK_LIST)m_Storage.GetAlloc())->dwFlags & RDNS_FLAG_DODNS2IPCHECK) )
|
|
{
|
|
if ( !m_fIpResolved )
|
|
{
|
|
m_HttpReqCallbackEx = pFunc;
|
|
m_HttpReqParam = pArg;
|
|
|
|
// get IP addr
|
|
fSt = AsyncAddrByHost(
|
|
(PDNSFUNCDESC)(pFunc ? &g_ResolveDns2Ip : NULL),
|
|
(DNSARG)this,
|
|
&m_ResolvedAddr,
|
|
pfSync,
|
|
m_pszDnsName );
|
|
if ( !fSt || !*pfSync )
|
|
{
|
|
return fSt;
|
|
}
|
|
m_fIpResolved = TRUE;
|
|
if ( !memcmp( (LPBYTE)(&((PSOCKADDR_IN)&m_ResolvedAddr)->sin_addr),
|
|
(LPBYTE)NULL_IP_ADDR,
|
|
SIZEOF_IP_ADDRESS ) )
|
|
{
|
|
m_dwErrorResolving = ERROR_INVALID_PARAMETER;
|
|
return FALSE;
|
|
}
|
|
}
|
|
if ( memcmp( (LPBYTE)(&((PSOCKADDR_IN)&m_ResolvedAddr)->sin_addr),
|
|
(LPBYTE)(&((PSOCKADDR_IN)m_pAddr)->sin_addr),
|
|
SIZEOF_IP_ADDRESS ) &&
|
|
(((PSOCKADDR_IN)m_pAddr)->sin_addr.s_addr != LOCALHOST_ADDRESS ) )
|
|
{
|
|
m_pszDnsName[ 0 ] = '\0';
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
*ppName = m_pszDnsName;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CSidCache::Init(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize SID cache object
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
TRUE if success, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
INITIALIZE_CRITICAL_SECTION( &csLock );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
CSidCache::Terminate(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Terminate SID cache object
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
{
|
|
DeleteCriticalSection( &csLock );
|
|
}
|
|
|
|
|
|
BOOL
|
|
CSidCache::AddToCache(
|
|
PSID pSid,
|
|
DWORD dwTTL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add SID entry to cache
|
|
|
|
Arguments:
|
|
|
|
pSid - SID to add to cache
|
|
dwTTL - Time to Live ( in seconds ) in cache
|
|
|
|
Return Value:
|
|
|
|
TRUE if success, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
BOOL fSt = TRUE;
|
|
|
|
EnterCriticalSection( &csLock );
|
|
|
|
if ( !IsInCache( pSid ) )
|
|
{
|
|
DWORD dwL = GetLengthSid( pSid );
|
|
DWORD dwWas = xaStore.GetUsed();
|
|
if ( xaStore.Resize( sizeof(SID_CACHE_ENTRY) + dwL ) )
|
|
{
|
|
PSID_CACHE_ENTRY pB = (PSID_CACHE_ENTRY)(xaStore.GetAlloc()
|
|
+ dwWas );
|
|
pB->tExpire = (DWORD)(time(NULL) + dwTTL);
|
|
pB->dwSidLen = dwL;
|
|
memcpy( pB->Sid, pSid, dwL );
|
|
}
|
|
else
|
|
{
|
|
fSt = FALSE;
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection( &csLock );
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CSidCache::IsInCache(
|
|
PSID pSid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check if SID present and in cache
|
|
|
|
Arguments:
|
|
|
|
pSid - SID to add to cache
|
|
|
|
Return Value:
|
|
|
|
TRUE if found, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
return CheckPresentAndResetTtl( pSid, 0xffffffff );
|
|
}
|
|
|
|
|
|
BOOL
|
|
CSidCache::CheckPresentAndResetTtl(
|
|
PSID pSid,
|
|
DWORD dwTtl
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check if SID present and in cache and if found
|
|
update its TTL
|
|
|
|
Arguments:
|
|
|
|
pSid - SID to add to cache
|
|
dwTTL - Time to Live ( in seconds ) in cache
|
|
|
|
Return Value:
|
|
|
|
TRUE if found, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
// walk through xaStore,
|
|
BOOL fSt = FALSE;
|
|
|
|
EnterCriticalSection( &csLock );
|
|
|
|
PSID_CACHE_ENTRY pB = (PSID_CACHE_ENTRY)(xaStore.GetAlloc() );
|
|
PSID_CACHE_ENTRY pM = (PSID_CACHE_ENTRY)(xaStore.GetAlloc()
|
|
+ xaStore.GetUsed());
|
|
|
|
if ( pB )
|
|
{
|
|
while ( pB < pM )
|
|
{
|
|
if ( EqualSid( (PSID)(pB->Sid), pSid ) )
|
|
{
|
|
if ( dwTtl != 0xffffffff )
|
|
{
|
|
pB->tExpire = (DWORD)(time(NULL) + dwTtl);
|
|
}
|
|
fSt = TRUE;
|
|
break;
|
|
}
|
|
pB = (PSID_CACHE_ENTRY)( (LPBYTE)pB + pB->dwSidLen + sizeof(SID_CACHE_ENTRY) );
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection( &csLock );
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CSidCache::Scavenger(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Remove expired entries from cache based on TTL
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
TRUE if no error, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
// walk through xaStore,
|
|
BOOL fSt = TRUE;
|
|
|
|
EnterCriticalSection( &csLock );
|
|
|
|
PSID_CACHE_ENTRY pB = (PSID_CACHE_ENTRY)(xaStore.GetAlloc() );
|
|
PSID_CACHE_ENTRY pM = (PSID_CACHE_ENTRY)(xaStore.GetAlloc()
|
|
+ xaStore.GetUsed());
|
|
DWORD tNow = (DWORD)(time(NULL));
|
|
DWORD dwAdj = 0;
|
|
|
|
if ( pB )
|
|
{
|
|
while ( pB < pM )
|
|
{
|
|
DWORD dwL = pB->dwSidLen+sizeof(SID_CACHE_ENTRY);
|
|
if ( pB->tExpire <= tNow )
|
|
{
|
|
dwAdj += dwL;
|
|
}
|
|
else if ( dwAdj )
|
|
{
|
|
memmove( (LPBYTE)pB-dwAdj,
|
|
pB,
|
|
dwL );
|
|
}
|
|
pB = (PSID_CACHE_ENTRY)( (LPBYTE)pB + dwL );
|
|
}
|
|
xaStore.AdjustUsed( -(int)dwAdj );
|
|
}
|
|
|
|
LeaveCriticalSection( &csLock );
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
#if DBG
|
|
VOID
|
|
ADDRESS_CHECK::DumpAddr(
|
|
BOOL fGrant
|
|
)
|
|
{
|
|
UINT i = GetNbAddr( fGrant );
|
|
UINT x;
|
|
for ( x = 0 ; x < i ; ++x )
|
|
{
|
|
LPBYTE pM;
|
|
LPBYTE pA;
|
|
DWORD dwF;
|
|
GetAddr( fGrant, x, &dwF, &pM, &pA );
|
|
|
|
CHAR achE[80];
|
|
wsprintf( achE, "%d.%d.%d.%d %d.%d.%d.%d\r\n",
|
|
pM[0], pM[1], pM[2], pM[3],
|
|
pA[0], pA[1], pA[2], pA[3] );
|
|
OutputDebugString( achE );
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
ADDRESS_CHECK::DumpName(
|
|
BOOL fGrant
|
|
)
|
|
{
|
|
UINT i = GetNbName( fGrant );
|
|
UINT x;
|
|
for ( x = 0 ; x < i ; ++x )
|
|
{
|
|
//CHAR achN[80];
|
|
//DWORD dwN = sizeof(achN);
|
|
LPSTR pN;
|
|
GetName( fGrant, x, &pN ); //achN, &dwN );
|
|
OutputDebugString( pN );
|
|
OutputDebugString( "\r\n" );
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
ADDRESS_CHECK::DumpAddrAndName(
|
|
VOID
|
|
)
|
|
{
|
|
OutputDebugString( "Addr granted:\r\n" );
|
|
DumpAddr( TRUE );
|
|
OutputDebugString( "Addr denied:\r\n" );
|
|
DumpAddr( FALSE );
|
|
|
|
OutputDebugString( "Name granted:\r\n" );
|
|
DumpName( TRUE );
|
|
OutputDebugString( "Name denied:\r\n" );
|
|
DumpName( FALSE );
|
|
}
|
|
|
|
|
|
void CaBack( ADDRCHECKARG pArg, BOOL f )
|
|
{
|
|
CHAR achE[80];
|
|
wsprintf( achE, "pArg=%08x, BOOL = %d\r\n", pArg, f );
|
|
OutputDebugString( achE );
|
|
}
|
|
|
|
|
|
VOID TestAPI()
|
|
{
|
|
ADDRESS_CHECK *pac=new ADDRESS_CHECK;
|
|
|
|
pac->BindCheckList();
|
|
|
|
pac->AddAddr( TRUE, AF_INET, (LPBYTE)"\xff\xff\x0\x0", (LPBYTE)"\x55\x66\x77\x88" );
|
|
pac->AddAddr( TRUE, AF_INET, (LPBYTE)"\xff\xff\x0\x0", (LPBYTE)"\x44\x66\x77\x88" );
|
|
pac->AddAddr( TRUE, AF_INET, (LPBYTE)"\xff\xff\x0\x0", (LPBYTE)"\x55\x77\x77\x88" );
|
|
pac->AddAddr( TRUE, AF_INET, (LPBYTE)"\xff\xff\x0\x0", (LPBYTE)"\x55\x66\x77\x88" ); // should fail
|
|
pac->AddAddr( TRUE, AF_INET, (LPBYTE)"\xff\x00\x0\x0", (LPBYTE)"\x55\x66\x77\x88" );
|
|
pac->AddAddr( TRUE, AF_INET, (LPBYTE)"\xff\xff\xff\x0",(LPBYTE)"\x55\x66\x77\x88" );
|
|
|
|
UINT i = pac->GetNbAddr( TRUE );
|
|
UINT x;
|
|
for ( x = 0 ; x < i ; ++x )
|
|
{
|
|
LPBYTE pM;
|
|
LPBYTE pA;
|
|
DWORD dwF;
|
|
pac->GetAddr( TRUE, x, &dwF, &pM, &pA );
|
|
}
|
|
|
|
pac->DeleteAddr( TRUE, 1 );
|
|
pac->DeleteAddr( TRUE, 1 );
|
|
pac->DeleteAddr( TRUE, 1 );
|
|
pac->DeleteAddr( TRUE, 1 );
|
|
pac->DeleteAddr( TRUE, 1 ); // should fail
|
|
pac->DeleteAddr( TRUE, 0 );
|
|
pac->DeleteAddr( TRUE, 0 ); // should fail
|
|
|
|
// names
|
|
|
|
pac->AddName( TRUE, "msft.com" );
|
|
pac->AddName( TRUE, "msft.com" ); // should fail
|
|
pac->AddName( TRUE, "fr" );
|
|
pac->AddName( TRUE, "www.sunw.com" );
|
|
pac->AddName( TRUE, "ftp.sunw.com" );
|
|
pac->AddName( TRUE, "aapl.com" );
|
|
|
|
i = pac->GetNbName( TRUE );
|
|
x;
|
|
for ( x = 0 ; x < i ; ++x )
|
|
{
|
|
//CHAR achN[80];
|
|
//DWORD dwN = sizeof(achN);
|
|
LPSTR pN;
|
|
pac->GetName( TRUE, x, &pN ); //achN, &dwN );
|
|
}
|
|
|
|
pac->CheckName( "msft.com" );
|
|
|
|
sockaddr* psa = new sockaddr;
|
|
BOOL fInList;
|
|
psa->sa_family = AF_INET;
|
|
memcpy( (&((PSOCKADDR_IN)psa)->sin_addr), "\x44\x66\xaa\xbb", SIZEOF_IP_ADDRESS );
|
|
pac->CheckAddress( psa );
|
|
|
|
BOOL fSync;
|
|
psa->sa_family = AF_INET;
|
|
memcpy( (&((PSOCKADDR_IN)psa)->sin_addr), "\x9d\x37\x53\x48", SIZEOF_IP_ADDRESS ); // PHILLICH3
|
|
pac->BindAddr( psa );
|
|
pac->CheckAccess( &fSync, (ADDRCHECKFUNC)CaBack, (ADDRCHECKARG)NULL );
|
|
|
|
// pac->DeleteName( TRUE, 1 );
|
|
// pac->DeleteName( TRUE, 1 );
|
|
// pac->DeleteName( TRUE, 1 );
|
|
// pac->DeleteName( TRUE, 1 );
|
|
// pac->DeleteName( TRUE, 1 ); // should fail
|
|
// pac->DeleteName( TRUE, 0 );
|
|
// pac->DeleteName( TRUE, 0 ); // should fail
|
|
}
|
|
#endif
|