Leaked source code of windows server 2003
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.
 
 
 
 
 
 

3354 lines
61 KiB

/*++
Copyright (c) 2001-2002 Microsoft Corporation
Module Name:
dnsaddr.c
Abstract:
Domain Name System (DNS) Library
DNS_ADDR routines.
Author:
Jim Gilroy (jamesg) November 2001
Revision History:
--*/
#include "local.h"
//
// DNS_ADDR routines
//
WORD
DnsAddr_DnsType(
IN PDNS_ADDR pAddr
)
/*++
Routine Description:
Get DNS type corresponding to DNS_ADDR.
DCR: DnsAddr_DnsType could be a macro
currently a function simply because Family_X
are in lower-pri header file; once determine
if Family_X available everywhere we want DNS_ADDR
routines, then can macroize
Arguments:
pAddr -- first addr
Return Value:
TRUE if loopback.
FALSE otherwise.
--*/
{
return Family_DnsType( DnsAddr_Family(pAddr) );
}
BOOL
DnsAddr_IsEqual(
IN PDNS_ADDR pAddr1,
IN PDNS_ADDR pAddr2,
IN DWORD MatchFlag
)
/*++
Routine Description:
Test if DNS_ADDRs are equal.
Arguments:
pAddr1 -- first addr
pAddr2 -- second addr
MatchFlag -- level of match
Return Value:
TRUE if loopback.
FALSE otherwise.
--*/
{
if ( MatchFlag == 0 ||
MatchFlag == DNSADDR_MATCH_ALL )
{
return RtlEqualMemory(
pAddr1,
pAddr2,
sizeof(*pAddr1) );
}
else if ( MatchFlag == DNSADDR_MATCH_SOCKADDR )
{
return RtlEqualMemory(
pAddr1,
pAddr2,
DNS_ADDR_MAX_SOCKADDR_LENGTH );
}
//
// DCR: currently no separate match to include scope
// could dispatch to separate match routines for AF
// compare families, then dispatch
//
else if ( MatchFlag & DNSADDR_MATCH_IP )
// else if ( MatchFlag == DNSADDR_MATCH_IP )
{
if ( DnsAddr_IsIp4( pAddr1 ) )
{
return( DnsAddr_IsIp4( pAddr2 )
&&
DnsAddr_GetIp4(pAddr1) == DnsAddr_GetIp4(pAddr2) );
}
else if ( DnsAddr_IsIp6( pAddr1 ) )
{
return( DnsAddr_IsIp6( pAddr2 )
&&
IP6_ARE_ADDRS_EQUAL(
DnsAddr_GetIp6Ptr(pAddr1),
DnsAddr_GetIp6Ptr(pAddr2) ) );
}
return FALSE;
}
ELSE_ASSERT_FALSE;
return RtlEqualMemory(
pAddr1,
pAddr2,
DNS_ADDR_MAX_SOCKADDR_LENGTH );
}
BOOL
DnsAddr_MatchesIp4(
IN PDNS_ADDR pAddr,
IN IP4_ADDRESS Ip4
)
/*++
Routine Description:
Test if DNS_ADDR is a given IP4.
Arguments:
pAddr -- first addr
Ip4 -- IP4 address
Return Value:
TRUE if loopback.
FALSE otherwise.
--*/
{
return ( DnsAddr_IsIp4( pAddr )
&&
Ip4 == DnsAddr_GetIp4(pAddr) );
}
BOOL
DnsAddr_MatchesIp6(
IN PDNS_ADDR pAddr,
IN PIP6_ADDRESS pIp6
)
/*++
Routine Description:
Test if DNS_ADDR is a given IP6.
Arguments:
pAddr -- first addr
pIp6 -- IP6 address
Return Value:
TRUE if loopback.
FALSE otherwise.
--*/
{
return ( DnsAddr_IsIp6( pAddr )
&&
IP6_ARE_ADDRS_EQUAL(
DnsAddr_GetIp6Ptr(pAddr),
pIp6 ) );
}
BOOL
DnsAddr_IsLoopback(
IN PDNS_ADDR pAddr,
IN DWORD Family
)
/*++
Routine Description:
Test if DNS_ADDR is loopback.
Arguments:
pAddr -- addr to set with IP6 address
Family --
AF_INET6 to only accept if 6
AF_INET4 to only accept if 4
0 to extract always
Return Value:
TRUE if loopback.
FALSE otherwise.
--*/
{
DWORD addrFam = DnsAddr_Family(pAddr);
if ( Family == 0 ||
Family == addrFam )
{
if ( addrFam == AF_INET6 )
{
return IP6_IS_ADDR_LOOPBACK(
(PIP6_ADDRESS)&pAddr->SockaddrIn6.sin6_addr );
}
else if ( addrFam == AF_INET )
{
return (pAddr->SockaddrIn.sin_addr.s_addr == DNS_NET_ORDER_LOOPBACK);
}
}
return FALSE;
}
BOOL
DnsAddr_IsUnspec(
IN PDNS_ADDR pAddr,
IN DWORD Family
)
/*++
Routine Description:
Test if DNS_ADDR is unspecied.
Arguments:
pAddr -- addr to test
Family --
AF_INET6 to only accept if 6
AF_INET4 to only accept if 4
0 to extract always
Return Value:
TRUE if unspecified.
FALSE otherwise.
--*/
{
DWORD family = DnsAddr_Family(pAddr);
if ( Family == 0 ||
Family == family )
{
if ( family == AF_INET6 )
{
return IP6_IS_ADDR_ZERO( (PIP6_ADDRESS)&pAddr->SockaddrIn6.sin6_addr );
}
else if ( family == AF_INET )
{
return (pAddr->SockaddrIn.sin_addr.s_addr == 0);
}
}
return FALSE;
}
BOOL
DnsAddr_IsClear(
IN PDNS_ADDR pAddr
)
/*++
Routine Description:
Test if DNS_ADDR is clear. This is similar to unspecified but includes
invalid addresses (where family is zero) also.
Arguments:
pAddr -- addr test
Return Value:
TRUE if clear.
FALSE otherwise.
--*/
{
DWORD family = DnsAddr_Family( pAddr );
if ( family == AF_INET6 )
{
return IP6_IS_ADDR_ZERO( (PIP6_ADDRESS)&pAddr->SockaddrIn6.sin6_addr );
}
else if ( family == AF_INET )
{
return pAddr->SockaddrIn.sin_addr.s_addr == 0;
}
else if ( family == 0 )
{
return TRUE;
}
ASSERT( FALSE ); // Family is invalid - not good.
return FALSE;
}
BOOL
DnsAddr_IsIp6DefaultDns(
IN PDNS_ADDR pAddr
)
/*++
Routine Description:
Test if DNS_ADDR is IP6 default DNS addr.
Arguments:
pAddr -- addr to check
Return Value:
TRUE if IP6 default DNS.
FALSE otherwise.
--*/
{
if ( !DnsAddr_IsIp6( pAddr ) )
{
return FALSE;
}
return IP6_IS_ADDR_DEFAULT_DNS( (PIP6_ADDRESS)&pAddr->SockaddrIn6.sin6_addr );
}
//
// DNS_ADDR to other types
//
DWORD
DnsAddr_WriteSockaddr(
OUT PSOCKADDR pSockaddr,
IN DWORD SockaddrLength,
IN PDNS_ADDR pAddr
)
/*++
Routine Description:
Write sockaddr with IP6 or IP4 address.
Arguments:
pSockaddr -- ptr to sockaddr
pSockaddrLength -- ptr to DWORD
input: holds length of pSockaddr buffer
output: set to sockaddr length
pAddr -- addr
Return Value:
Sockaddr length written.
Zero if unable to write (bad sockaddr or inadequate length.
--*/
{
DWORD length;
DNSDBG( SOCKET, (
"DnsAddr_WriteSockaddr( %p, %u, %p )\n",
pSockaddr,
SockaddrLength,
pAddr ));
// out length
length = pAddr->SockaddrLength;
// zero
RtlZeroMemory( pSockaddr, SockaddrLength );
//
// fill in sockaddr for IP4 or IP6
//
if ( SockaddrLength >= length )
{
RtlCopyMemory(
pSockaddr,
& pAddr->Sockaddr,
length );
}
else
{
length = 0;
}
return length;
}
BOOL
DnsAddr_WriteIp6(
OUT PIP6_ADDRESS pIp,
IN PDNS_ADDR pAddr
)
/*++
Routine Description:
Write IP6 address.
Arguments:
pIp -- addr to write IP6 to
pAddr -- DNS addr
Return Value:
TRUE if successful.
FALSE on bad DNS_ADDR for IP6 write.
--*/
{
WORD family;
DWORD len;
DNSDBG( SOCKET, (
"DnsAddr_WriteIp6Addr( %p, %p )\n",
pIp,
pAddr ));
//
// check family
//
if ( DnsAddr_IsIp6(pAddr) )
{
IP6_ADDR_COPY(
pIp,
(PIP6_ADDRESS) &pAddr->SockaddrIn6.sin6_addr );
return TRUE;
}
return FALSE;
}
IP4_ADDRESS
DnsAddr_GetIp4(
IN PDNS_ADDR pAddr
)
/*++
Routine Description:
Write IP4 address.
Arguments:
pAddr -- DNS addr
Return Value:
IP4 address if successful.
INADDR_NONE if not valid IP4
--*/
{
//
// check family
//
if ( DnsAddr_IsIp4(pAddr) )
{
return (IP4_ADDRESS) pAddr->SockaddrIn.sin_addr.s_addr;
}
return INADDR_NONE;
}
//
// Build DNS_ADDRs
//
BOOL
DnsAddr_Build(
OUT PDNS_ADDR pAddr,
IN PSOCKADDR pSockaddr,
IN DWORD Family, OPTIONAL
IN DWORD SubnetLength,
IN DWORD Flags
)
/*++
Routine Description:
Build from sockaddr
Arguments:
pAddr -- addr to set with IP6 address
pSockaddr -- ptr to sockaddr
Family --
AF_INET6 to only extract if 6
AF_INET4 to only extract if 4
0 to extract always
SubnetLength -- length to set subnet
Return Value:
TRUE if successful.
FALSE on bad sockaddr.
--*/
{
WORD family;
DWORD len;
IP4_ADDRESS ip4;
DNSDBG( TRACE, (
"DnsAddr_Build( %p, %p, %u, %u, 08x )\n",
pAddr,
pSockaddr,
Family,
SubnetLength,
Flags ));
// zero
RtlZeroMemory(
pAddr,
sizeof(*pAddr) );
//
// verify adequate length
// verify family match (if desired)
//
len = Sockaddr_Length( pSockaddr );
if ( len > DNS_ADDR_MAX_SOCKADDR_LENGTH )
{
return FALSE;
}
if ( Family && Family != pSockaddr->sa_family )
{
return FALSE;
}
//
// write sockaddr
// write length fields
//
RtlCopyMemory(
& pAddr->Sockaddr,
pSockaddr,
len );
pAddr->SockaddrLength = len;
//
// extra fields
//
pAddr->SubnetLength = SubnetLength;
pAddr->Flags = Flags;
return TRUE;
}
VOID
DnsAddr_BuildFromIp4(
OUT PDNS_ADDR pAddr,
IN IP4_ADDRESS Ip4,
IN WORD Port
)
/*++
Routine Description:
Build from IP4
Arguments:
pAddr -- addr to set with IP6 address
Ip4 -- IP4 to build
Return Value:
None
--*/
{
SOCKADDR_IN sockaddr;
DNSDBG( TRACE, (
"DnsAddr_BuildFromIp4( %p, %s, %u )\n",
pAddr,
IP4_STRING( Ip4 ),
Port ));
// zero
RtlZeroMemory(
pAddr,
sizeof(*pAddr) );
//
// fill in for IP4
//
pAddr->SockaddrIn.sin_family = AF_INET;
pAddr->SockaddrIn.sin_port = Port;
pAddr->SockaddrIn.sin_addr.s_addr = Ip4;
pAddr->SockaddrLength = sizeof(SOCKADDR_IN);
}
VOID
DnsAddr_BuildFromIp6(
OUT PDNS_ADDR pAddr,
IN PIP6_ADDRESS pIp6,
IN DWORD ScopeId,
IN WORD Port
)
/*++
Routine Description:
Build from IP6
Arguments:
pAddr -- addr to set with IP6 address
pIp6 -- IP6
ScopeId -- scope id
Port -- port
Return Value:
None
--*/
{
DNSDBG( TRACE, (
"DnsAddr_BuildFromIp6( %p, %s, %u, %u )\n",
pAddr,
IPADDR_STRING( pIp6 ),
ScopeId,
Port ));
//
// DCR: IP6 with V4 mapped
// could use build sockaddr from IP6, then
// call generic build
//
// zero
RtlZeroMemory(
pAddr,
sizeof(*pAddr) );
//
// fill in for IP4
//
pAddr->SockaddrIn6.sin6_family = AF_INET6;
pAddr->SockaddrIn6.sin6_port = Port;
pAddr->SockaddrIn6.sin6_scope_id = ScopeId;
IP6_ADDR_COPY(
(PIP6_ADDRESS) &pAddr->SockaddrIn6.sin6_addr,
pIp6 );
pAddr->SockaddrLength = sizeof(SOCKADDR_IN6);
}
VOID
DnsAddr_BuildFromAtm(
OUT PDNS_ADDR pAddr,
IN DWORD AtmType,
IN PCHAR pAtmAddr
)
/*++
Routine Description:
Build from ATM address.
Note, this is not a full SOCKADDR_ATM, see note below.
This is a useful hack for bringing ATMA record info into
DNS_ADDR format for transfer from DNS to RnR.
Arguments:
pAddr -- addr to set with IP6 address
AtmType -- ATM address type
pAtmAddr -- ATM address; ATM_ADDR_SIZE (20) bytes in length
Return Value:
None
--*/
{
ATM_ADDRESS atmAddr;
DNSDBG( TRACE, (
"DnsAddr_BuildFromAtm( %p, %d, %p )\n",
pAddr,
AtmType,
pAtmAddr ));
//
// clear
//
RtlZeroMemory(
pAddr,
sizeof(*pAddr) );
//
// fill in address
//
// note: we are simply using DNS_ADDR sockaddr portion as a
// blob to hold ATM_ADDRESS; this is NOT a full
// SOCKADDR_ATM structure which contains additional fields
// and is larger than what we support in DNS_ADDR
//
// DCR: functionalize ATMA to ATM conversion
// not sure this num of digits is correct
// may have to actually parse address
//
// DCR: not filling satm_blli and satm_bhil fields
// see RnR CSADDR builder for possible default values
//
pAddr->Sockaddr.sa_family = AF_ATM;
pAddr->SockaddrLength = sizeof(ATM_ADDRESS);
atmAddr.AddressType = AtmType;
atmAddr.NumofDigits = ATM_ADDR_SIZE;
RtlCopyMemory(
& atmAddr.Addr,
pAtmAddr,
ATM_ADDR_SIZE );
RtlCopyMemory(
& ((PSOCKADDR_ATM)pAddr)->satm_number,
& atmAddr,
sizeof(ATM_ADDRESS) );
}
BOOL
DnsAddr_BuildFromDnsRecord(
OUT PDNS_ADDR pAddr,
IN PDNS_RECORD pRR
)
/*++
Routine Description:
Build from DNS_RECORD
Arguments:
pAddr -- addr to set with IP6 address
pRR -- DNS record to use
Return Value:
TRUE if successful.
FALSE if unknown family.
--*/
{
BOOL retval = TRUE;
switch ( pRR->wType )
{
case DNS_TYPE_A:
DnsAddr_BuildFromIp4(
pAddr,
pRR->Data.A.IpAddress,
0 );
break;
case DNS_TYPE_AAAA:
DnsAddr_BuildFromIp6(
pAddr,
&pRR->Data.AAAA.Ip6Address,
pRR->dwReserved,
0 );
break;
case DNS_TYPE_ATMA:
DnsAddr_BuildFromAtm(
pAddr,
pRR->Data.ATMA.AddressType,
pRR->Data.ATMA.Address );
break;
default:
retval = FALSE;
break;
}
return retval;
}
BOOL
DnsAddr_BuildFromFlatAddr(
OUT PDNS_ADDR pAddr,
IN DWORD Family,
IN PCHAR pFlatAddr,
IN WORD Port
)
/*++
Routine Description:
Build from IP4
Arguments:
pAddr -- addr to set with IP6 address
Family -- address family
pFlatAddr -- ptr to flat IP4 or IP6 address
Port -- port
Return Value:
TRUE if successful.
FALSE if unknown family.
--*/
{
//
// check IP4
//
if ( Family == AF_INET )
{
DnsAddr_BuildFromIp4(
pAddr,
* (PIP4_ADDRESS) pFlatAddr,
Port );
}
else if ( Family == AF_INET6 )
{
DnsAddr_BuildFromIp6(
pAddr,
(PIP6_ADDRESS) pFlatAddr,
0, // scope less
Port );
}
else
{
return FALSE;
}
return TRUE;
}
BOOL
DnsAddr_BuildMcast(
OUT PDNS_ADDR pAddr,
IN DWORD Family,
IN PWSTR pName
)
/*++
Routine Description:
Build from sockaddr
Arguments:
pAddr -- addr to set with IP6 address
Family --
AF_INET6 for IP6 mcast
AF_INET for IP4 mcast
pName -- published record name; required for IP6 only
Return Value:
TRUE if successful.
FALSE on bad sockaddr.
--*/
{
WORD family;
DWORD len;
IP4_ADDRESS ip4;
DNSDBG( TRACE, (
"DnsAddr_BuildMcast( %p, %d, %s )\n",
pAddr,
Family,
pName ));
//
// zero
RtlZeroMemory(
pAddr,
sizeof(*pAddr) );
//
// IP4 has single mcast address
//
if ( Family == AF_INET )
{
DnsAddr_BuildFromIp4(
pAddr,
MCAST_IP4_ADDRESS,
MCAST_PORT_NET_ORDER );
}
//
// IP6 address includes name hash
//
else if ( Family == AF_INET6 )
{
IP6_ADDRESS mcastAddr;
Ip6_McastCreate(
& mcastAddr,
pName );
DnsAddr_BuildFromIp6(
pAddr,
& mcastAddr,
0, // no scope
MCAST_PORT_NET_ORDER );
#if 0
CHAR label[ DNS_MAX_LABEL_BUFFER_LENGTH ];
CHAR downLabel[ DNS_MAX_LABEL_BUFFER_LENGTH ];
CHAR md5Hash[ 16 ]; // 128bit hash
// hash of downcased label
Dns_CopyNameLabel(
label,
pName );
Dns_DowncaseNameLabel(
downLabel,
label,
0, // null terminated
0 // no flags
);
Dns_Md5Hash(
md5Hash,
downLabel );
// mcast addr
// - first 12 bytes are fixed
// - last 4 bytes are first 32bits of hash
IP6_ADDR_COPY(
& mcastAddr,
& g_Ip6McastBaseAddr );
RtlCopyMemory(
& mcastAddr[12],
& md5Hash,
sizeof(DWORD) );
#endif
}
return TRUE;
}
//
// Printing\string conversion
//
PCHAR
DnsAddr_WriteIpString_A(
OUT PCHAR pBuffer,
IN PDNS_ADDR pAddr
)
/*++
Routine Description:
Write DNS_ADDR IP address to string.
Note: Does NOT write entire DNS_ADDR or sockaddr.
Arguments:
pBuffer -- buffer to write to
pAddr -- addr to write
Return Value:
Ptr to next char in buffer (ie the terminating NULL)
NULL on invalid address. However, invalid address message is
written to the buffer and it's length can be determined.
--*/
{
if ( DnsAddr_IsIp4(pAddr) )
{
pBuffer += sprintf(
pBuffer,
"%s",
inet_ntoa( pAddr->SockaddrIn.sin_addr ) );
}
else if ( DnsAddr_IsIp6(pAddr) )
{
pBuffer = Dns_Ip6AddressToString_A(
pBuffer,
(PIP6_ADDRESS) &pAddr->SockaddrIn6.sin6_addr );
}
else
{
sprintf(
pBuffer,
"Invalid DNS_ADDR at %p",
pAddr );
pBuffer = NULL;
}
return pBuffer;
}
PCHAR
DnsAddr_Ntoa(
IN PDNS_ADDR pAddr
)
/*++
Routine Description:
Get IP address string for DNS_ADDR.
Note: Does NOT write entire DNS_ADDR or sockaddr.
Arguments:
pAddr -- addr to convert
Return Value:
Ptr to TLS blob with address string.
--*/
{
if ( !pAddr )
{
return "Null Address";
}
else if ( DnsAddr_IsIp4(pAddr) )
{
return inet_ntoa( pAddr->SockaddrIn.sin_addr );
}
else if ( DnsAddr_IsIp6(pAddr) )
{
return Ip6_TempNtoa( (PIP6_ADDRESS)&pAddr->SockaddrIn6.sin6_addr );
}
else
{
return NULL;
}
}
PSTR
DnsAddr_WriteStructString_A(
OUT PCHAR pBuffer,
IN PDNS_ADDR pAddr
)
/*++
Routine Description:
Write DNS_ADDR as string.
Arguments:
pAddr -- ptr to IP to get string for
Return Value:
Ptr to next char in buffer (terminating NULL).
--*/
{
CHAR ipBuffer[ DNS_ADDR_STRING_BUFFER_LENGTH ];
//BOOL finValid;
// write address portion
//finValid = !DnsAddr_WriteIpString_A(
DnsAddr_WriteIpString_A(
ipBuffer,
pAddr );
//
// write struct including address
//
pBuffer += sprintf(
pBuffer,
"af=%d, salen=%d, [sub=%d, flag=%08x] p=%u, addr=%s",
pAddr->Sockaddr.sa_family,
pAddr->SockaddrLength,
pAddr->SubnetLength,
pAddr->Flags,
pAddr->SockaddrIn.sin_port,
ipBuffer );
return pBuffer;
}
//
// DNS_ADDR_ARRAY routines
//
DWORD
DnsAddrArray_Sizeof(
IN PDNS_ADDR_ARRAY pArray
)
/*++
Routine Description:
Get size in bytes of address array.
Arguments:
pArray -- address array to find size of
Return Value:
Size in bytes of IP array.
--*/
{
if ( ! pArray )
{
return 0;
}
return (pArray->AddrCount * sizeof(DNS_ADDR)) + sizeof(DNS_ADDR_ARRAY) - sizeof(DNS_ADDR);
}
#if 0
BOOL
DnsAddrArray_Probe(
IN PDNS_ADDR_ARRAY pArray
)
/*++
Routine Description:
Touch all entries in IP array to insure valid memory.
Arguments:
pArray -- ptr to address array
Return Value:
TRUE if successful.
FALSE otherwise
--*/
{
DWORD i;
BOOL result;
if ( ! pArray )
{
return( TRUE );
}
for ( i=0; i<pArray->AddrCount; i++ )
{
result = IP6_IS_ADDR_LOOPBACK( &pArray->AddrArray[i] );
}
return( TRUE );
}
#endif
#if 0
BOOL
DnsAddrArray_ValidateSizeOf(
IN PDNS_ADDR_ARRAY pArray,
IN DWORD dwMemoryLength
)
/*++
Routine Description:
Check that size of IP array, corresponds to length of memory.
Arguments:
pArray -- ptr to address array
dwMemoryLength -- length of IP array memory
Return Value:
TRUE if IP array size matches memory length
FALSE otherwise
--*/
{
return( DnsAddrArray_SizeOf(pArray) == dwMemoryLength );
}
#endif
VOID
DnsAddrArray_Init(
IN OUT PDNS_ADDR_ARRAY pArray,
IN DWORD MaxCount
)
/*++
Routine Description:
Init memory as DNS_ADDR_ARRAY array.
Arguments:
pArray -- array to init
MaxCount -- count of addresses
Return Value:
None
--*/
{
pArray->MaxCount = MaxCount;
pArray->AddrCount = 0;
}
VOID
DnsAddrArray_Free(
IN PDNS_ADDR_ARRAY pArray
)
/*++
Routine Description:
Free IP array.
Only for arrays created through create routines below.
Arguments:
pArray -- IP array to free.
Return Value:
None
--*/
{
FREE_HEAP( pArray );
}
PDNS_ADDR_ARRAY
DnsAddrArray_Create(
IN DWORD MaxCount
)
/*++
Routine Description:
Create uninitialized address array.
Arguments:
AddrCount -- count of addresses array will hold
Return Value:
Ptr to uninitialized address array, if successful
NULL on failure.
--*/
{
PDNS_ADDR_ARRAY parray;
DNSDBG( IPARRAY, ( "DnsAddrArray_Create() of count %d\n", MaxCount ));
parray = (PDNS_ADDR_ARRAY) ALLOCATE_HEAP_ZERO(
(MaxCount * sizeof(DNS_ADDR)) +
sizeof(DNS_ADDR_ARRAY) - sizeof(DNS_ADDR) );
if ( ! parray )
{
return( NULL );
}
//
// initialize IP count
//
parray->MaxCount = MaxCount;
DNSDBG( IPARRAY, (
"DnsAddrArray_Create() new array (count %d) at %p\n",
MaxCount,
parray ));
return( parray );
}
PDNS_ADDR_ARRAY
DnsAddrArray_CreateFromIp4Array(
IN PIP4_ARRAY pArray4
)
/*++
Routine Description:
Create DNS_ADDR_ARRAY from IP4 array.
Arguments:
pAddr4Array -- IP4 array
Return Value:
Ptr to uninitialized address array, if successful
NULL on failure.
--*/
{
PDNS_ADDR_ARRAY parray;
DWORD i;
DNSDBG( IPARRAY, (
"DnsAddrArray_CreateFromIp4Array( %p )\n",
pArray4 ));
if ( ! pArray4 )
{
return( NULL );
}
//
// allocate the array
//
parray = DnsAddrArray_Create( pArray4->AddrCount );
if ( !parray )
{
return NULL;
}
//
// fill the array
//
for ( i=0; i<pArray4->AddrCount; i++ )
{
DnsAddrArray_AddIp4(
parray,
pArray4->AddrArray[i],
0 // no duplicate screen
);
}
DNSDBG( IPARRAY, (
"Leave DnsAddrArray_CreateFromIp4Array() new array (count %d) at %p\n",
parray->AddrCount,
parray ));
return( parray );
}
PDNS_ADDR_ARRAY
DnsAddrArray_CopyAndExpand(
IN PDNS_ADDR_ARRAY pArray,
IN DWORD ExpandCount,
IN BOOL fDeleteExisting
)
/*++
Routine Description:
Create expanded copy of address array.
Arguments:
pArray -- address array to copy
ExpandCount -- number of IP to expand array size by
fDeleteExisting -- TRUE to delete existing array;
this is useful when function is used to grow existing
IP array in place; note that locking must be done
by caller
note, that if new array creation FAILS -- then old array
is NOT deleted
Return Value:
Ptr to IP array copy, if successful
NULL on failure.
--*/
{
PDNS_ADDR_ARRAY pnewArray;
DWORD newCount;
//
// no existing array -- just create desired size
//
if ( ! pArray )
{
if ( ExpandCount )
{
return DnsAddrArray_Create( ExpandCount );
}
return( NULL );
}
//
// create IP array of desired size
// then copy any existing addresses
//
pnewArray = DnsAddrArray_Create( pArray->AddrCount + ExpandCount );
if ( ! pnewArray )
{
return( NULL );
}
newCount = pnewArray->MaxCount;
RtlCopyMemory(
(PBYTE) pnewArray,
(PBYTE) pArray,
DnsAddrArray_Sizeof(pArray) );
pnewArray->MaxCount = newCount;
//
// delete existing -- for "grow mode"
//
if ( fDeleteExisting )
{
FREE_HEAP( pArray );
}
return( pnewArray );
}
PDNS_ADDR_ARRAY
DnsAddrArray_CreateCopy(
IN PDNS_ADDR_ARRAY pArray
)
/*++
Routine Description:
Create copy of address array.
Arguments:
pArray -- address array to copy
Return Value:
Ptr to address array copy, if successful
NULL on failure.
--*/
{
//
// call essentially "CopyEx" function
//
// note, not macroing this because this may well become
// a DLL entry point
//
return DnsAddrArray_CopyAndExpand(
pArray,
0, // no expansion
0 // don't delete existing array
);
}
//
// Tests
//
DWORD
DnsAddrArray_GetFamilyCount(
IN PDNS_ADDR_ARRAY pArray,
IN DWORD Family
)
/*++
Routine Description:
Get count of addrs of a particular family.
Arguments:
pArray -- address array
Family -- family to count
Return Value:
Count of addrs of a particular family.
--*/
{
DWORD i;
DWORD count;
WORD arrayFamily;
if ( !pArray )
{
return 0;
}
// no family specified -- all addrs count
if ( Family == 0 )
{
return pArray->AddrCount;
}
//
// array family is specified -- so either all or none
//
if ( arrayFamily = pArray->Family )
{
if ( arrayFamily == Family )
{
return pArray->AddrCount;
}
else
{
return 0;
}
}
//
// family specified and array family unspecified -- must count
//
count = 0;
for (i=0; i<pArray->AddrCount; i++)
{
if ( DnsAddr_Family( &pArray->AddrArray[i] ) == Family )
{
count++;
}
}
return( count );
}
BOOL
DnsAddrArray_ContainsAddr(
IN PDNS_ADDR_ARRAY pArray,
IN PDNS_ADDR pAddr,
IN DWORD MatchFlag
)
/*++
Routine Description:
Check if IP array contains desired address.
Arguments:
pArray -- address array to copy
pAddr -- IP to check for
MatchFlag -- level of match required
Return Value:
TRUE if address in array.
Ptr to address array copy, if successful
NULL on failure.
--*/
{
DWORD i;
if ( ! pArray )
{
return( FALSE );
}
for (i=0; i<pArray->AddrCount; i++)
{
if ( DnsAddr_IsEqual(
pAddr,
&pArray->AddrArray[i],
MatchFlag ) )
{
return( TRUE );
}
}
return( FALSE );
}
BOOL
DnsAddrArray_ContainsAddrEx(
IN PDNS_ADDR_ARRAY pArray,
IN PDNS_ADDR pAddr,
IN DWORD MatchFlag, OPTIONAL
IN DNSADDR_SCREEN_FUNC pScreenFunc, OPTIONAL
IN PDNS_ADDR pScreenAddr OPTIONAL
)
/*++
Routine Description:
Check if IP array contains desired address.
Arguments:
pArray -- address array to copy
pAddr -- IP to check for
MatchFlag -- match level for screening dups; zero for no dup screening
pScreenFunc -- screen function (see header def for explanation)
pScreenAddr -- screening addr param to screen function
Return Value:
TRUE if address in array.
Ptr to address array copy, if successful
NULL on failure.
--*/
{
DWORD i;
DNSDBG( IPARRAY, (
"DnsAddrArray_ContainsAddrEx( %p, %p, %08x, %p, %p )\n",
pArray,
pAddr,
MatchFlag,
pScreenFunc,
pScreenAddr ));
if ( ! pArray )
{
return( FALSE );
}
for (i=0; i<pArray->AddrCount; i++)
{
if ( DnsAddr_IsEqual(
pAddr,
&pArray->AddrArray[i],
MatchFlag ) )
{
//
// do advanced screening here -- if any
//
if ( !pScreenFunc ||
pScreenFunc(
&pArray->AddrArray[i],
pScreenAddr ) )
{
return TRUE;
}
}
}
return( FALSE );
}
BOOL
DnsAddrArray_ContainsIp4(
IN PDNS_ADDR_ARRAY pArray,
IN IP4_ADDRESS Ip4
)
{
DNS_ADDR addr;
// read IP into addr
DnsAddr_BuildFromIp4(
& addr,
Ip4,
0 );
// with only IP, only match IP
return DnsAddrArray_ContainsAddr(
pArray,
& addr,
DNSADDR_MATCH_IP );
}
BOOL
DnsAddrArray_ContainsIp6(
IN PDNS_ADDR_ARRAY pArray,
IN PIP6_ADDRESS pIp6
)
{
DNS_ADDR addr;
// read IP into addr
DnsAddr_BuildFromIp6(
& addr,
pIp6,
0, // no scope
0 );
// with only IP, only match IP
return DnsAddrArray_ContainsAddr(
pArray,
& addr,
DNSADDR_MATCH_IP );
}
//
// Add \ Delete operations
//
BOOL
DnsAddrArray_AddAddr(
IN OUT PDNS_ADDR_ARRAY pArray,
IN PDNS_ADDR pAddr,
IN DWORD Family,
IN DWORD MatchFlag OPTIONAL
)
/*++
Routine Description:
Add IP address to IP array.
Allowable "slot" in array, is any zero IP address.
Arguments:
pArray -- address array to add to
pAddr -- IP address to add to array
Family -- optional, only add if match this family
MatchFlag -- flags for matching if screening dups
Return Value:
TRUE if successful.
FALSE if array full.
--*/
{
DWORD count;
//
// screen for existence
//
// this check makes it easy to write code that does
// Add\Full?=>Expand loop without having to write
// startup existence\create code
//
if ( !pArray )
{
return FALSE;
}
//
// check family match
//
// DCR: error codes on DnsAddrArray_AddAddrEx()?
// - then can have found dup and bad family
// errors
//
if ( Family &&
DnsAddr_Family(pAddr) != Family )
{
return TRUE;
}
//
// check for duplicates
//
if ( MatchFlag )
{
if ( DnsAddrArray_ContainsAddr( pArray, pAddr, MatchFlag ) )
{
return TRUE;
}
}
count = pArray->AddrCount;
if ( count >= pArray->MaxCount )
{
return FALSE;
}
DnsAddr_Copy(
&pArray->AddrArray[ count ],
pAddr );
pArray->AddrCount = ++count;
return TRUE;
}
BOOL
DnsAddrArray_AddSockaddr(
IN OUT PDNS_ADDR_ARRAY pArray,
IN PSOCKADDR pSockaddr,
IN DWORD Family,
IN DWORD MatchFlag
)
/*++
Routine Description:
Add IP address to IP array.
Allowable "slot" in array, is any zero IP address.
Arguments:
pArray -- address array to add to
pAddIp -- IP address to add to array
Family -- required family to do add; 0 for add always
MatchFlag -- match flags if screening duplicates
Return Value:
TRUE if successful.
FALSE if array full.
--*/
{
DNS_ADDR addr;
if ( !DnsAddr_Build(
& addr,
pSockaddr,
Family,
0, // no subnet length info
0 // no flags
) )
{
return FALSE;
}
return DnsAddrArray_AddAddr(
pArray,
&addr,
0, // family screen done in build routine
MatchFlag );
}
BOOL
DnsAddrArray_AddIp4(
IN OUT PDNS_ADDR_ARRAY pArray,
IN IP4_ADDRESS Ip4,
IN DWORD MatchFlag
)
/*++
Routine Description:
Add IP4 address to IP array.
Arguments:
pArray -- address array to add to
Ip4 -- IP4 address to add to array
MatchFlag -- match flags if screening duplicates
Return Value:
TRUE if successful.
FALSE if array full.
--*/
{
DNS_ADDR addr;
DnsAddr_BuildFromIp4(
&addr,
Ip4,
0 );
return DnsAddrArray_AddAddr(
pArray,
&addr,
0, // no family screen
MatchFlag );
}
BOOL
DnsAddrArray_AddIp6(
IN OUT PDNS_ADDR_ARRAY pArray,
IN PIP6_ADDRESS pIp6,
IN DWORD ScopeId,
IN DWORD MatchFlag
)
/*++
Routine Description:
Add IP4 address to IP array.
Arguments:
pArray -- address array to add to
pIp6 -- IP6 address to add to array
MatchFlag -- match flags if screening duplicates
Return Value:
TRUE if successful.
FALSE if array full.
--*/
{
DNS_ADDR addr;
DnsAddr_BuildFromIp6(
&addr,
pIp6,
ScopeId, // no scope
0 );
return DnsAddrArray_AddAddr(
pArray,
&addr,
0, // no family screen
MatchFlag );
}
DWORD
DnsAddrArray_DeleteAddr(
IN OUT PDNS_ADDR_ARRAY pArray,
IN PDNS_ADDR pAddrDelete,
IN DWORD MatchFlag
)
/*++
Routine Description:
Delete IP address from IP array.
Arguments:
pArray -- address array to add to
pAddrDelete -- IP address to delete from array
Return Value:
Count of instances of IpDelete found in array.
--*/
{
DWORD found = 0;
INT i;
INT currentLast;
i = currentLast = pArray->AddrCount-1;
//
// check each IP for match to delete IP
// - go backwards through array
// - swap in last IP in array
//
while ( i >= 0 )
{
if ( DnsAddr_IsEqual(
&pArray->AddrArray[i],
pAddrDelete,
MatchFlag ) )
{
DnsAddr_Copy(
& pArray->AddrArray[i],
& pArray->AddrArray[ currentLast ] );
DnsAddr_Clear( &pArray->AddrArray[ currentLast ] );
currentLast--;
found++;
}
i--;
}
pArray->AddrCount = currentLast + 1;
return( found );
}
DWORD
DnsAddrArray_DeleteIp4(
IN OUT PDNS_ADDR_ARRAY pArray,
IN IP4_ADDRESS Ip4
)
{
DNS_ADDR addr;
// read IP into addr
DnsAddr_BuildFromIp4(
& addr,
Ip4,
0 );
// with only IP, only match IP
return DnsAddrArray_DeleteAddr(
pArray,
& addr,
DNSADDR_MATCH_IP );
}
DWORD
DnsAddrArray_DeleteIp6(
IN OUT PDNS_ADDR_ARRAY pArray,
IN PIP6_ADDRESS Ip6
)
{
DNS_ADDR addr;
// read IP into addr
DnsAddr_BuildFromIp6(
& addr,
Ip6,
0, // no scope
0 );
// with only IP, only match IP
return DnsAddrArray_DeleteAddr(
pArray,
& addr,
DNSADDR_MATCH_IP );
}
//
// Array operations
//
VOID
DnsAddrArray_Clear(
IN OUT PDNS_ADDR_ARRAY pArray
)
/*++
Routine Description:
Clear memory in IP array.
Arguments:
pArray -- address array to clear
Return Value:
None.
--*/
{
// clear just the address list, leaving count intact
RtlZeroMemory(
pArray->AddrArray,
pArray->AddrCount * sizeof(DNS_ADDR) );
}
VOID
DnsAddrArray_Reverse(
IN OUT PDNS_ADDR_ARRAY pArray
)
/*++
Routine Description:
Reorder the list of IPs in reverse.
Arguments:
pArray -- address array to reorder
Return Value:
None.
--*/
{
DNS_ADDR tempAddr;
DWORD i;
DWORD j;
//
// swap IPs working from ends to the middle
//
if ( pArray &&
pArray->AddrCount )
{
for ( i = 0, j = pArray->AddrCount - 1;
i < j;
i++, j-- )
{
DnsAddr_Copy(
& tempAddr,
& pArray->AddrArray[i] );
DnsAddr_Copy(
& pArray->AddrArray[i],
& pArray->AddrArray[j] );
DnsAddr_Copy(
& pArray->AddrArray[j],
& tempAddr );
}
}
}
DNS_STATUS
DnsAddrArray_AppendArrayEx(
IN OUT PDNS_ADDR_ARRAY pArray,
IN PDNS_ADDR_ARRAY pAppendArray,
IN DWORD AppendCount,
IN DWORD Family, OPTIONAL
IN DWORD MatchFlag, OPTIONAL
IN DNSADDR_SCREEN_FUNC pScreenFunc, OPTIONAL
IN PDNS_ADDR pScreenAddr OPTIONAL
)
/*++
Routine Description:
Append entries from another array.
Arguments:
pArray -- existing array
pAppendArray -- array to append
AppendCount -- number of addrs to append; MAXDWORD for entire array
Family -- family, if screening family; zero for no screening
MatchFlag -- match level for screening dups; zero for no dup screening
pScreenFunc -- screen function (see header def for explanation)
pScreenAddr -- screening addr param to screen function
Return Value:
NO_ERROR if successful.
ERROR_MORE_DATA -- inadequate space in target array
--*/
{
DWORD i;
DNS_STATUS status = NO_ERROR;
DNSDBG( IPARRAY, (
"DnsAddrArray_AppendArrayEx( %p, %p, %d, %d, %08x, %p, %p )\n",
pArray,
pAppendArray,
AppendCount,
Family,
MatchFlag,
pScreenFunc,
pScreenAddr ));
if ( ! pAppendArray )
{
return( NO_ERROR );
}
//
// read from append array
//
for ( i=0; i<pAppendArray->AddrCount; i++ )
{
PDNS_ADDR paddr = &pAppendArray->AddrArray[i];
//
// do advanced screening here -- if any
//
if ( pScreenAddr )
{
if ( !pScreenFunc(
paddr,
pScreenAddr ) )
{
continue;
}
}
//
// attempt the add
//
if ( DnsAddrArray_AddAddr(
pArray,
paddr,
Family,
MatchFlag
) )
{
if ( --AppendCount > 0 )
{
continue;
}
break;
}
else
{
//
// add failed
// - break if array is full
//
// DCR: should really only ERROR_MORE_DATA if there is more data
// separate error codes on _AddAddr would fix this
//
if ( pArray->AddrCount == pArray->MaxCount )
{
status = ERROR_MORE_DATA;
break;
}
}
}
return( status );
}
DNS_STATUS
DnsAddrArray_AppendArray(
IN OUT PDNS_ADDR_ARRAY pArray,
IN PDNS_ADDR_ARRAY pAppendArray
)
/*++
Routine Description:
Create DNS_ADDR_ARRAY from IP4 array.
Arguments:
pArray -- existing array
pAppendArray -- array to append
Return Value:
NO_ERROR if successful.
ERROR_MORE_DATA -- inadequate space in target array
--*/
{
//
// append with Ex version
//
// note, if EX is expensive, could do simple
// check\RtlCopyMemory type append
//
return DnsAddrArray_AppendArrayEx(
pArray,
pAppendArray,
MAXDWORD, // append entire array
0, // no family screen
0, // no dup detection
NULL, // no screen func
NULL // no screen addr
);
}
//
// Set operations
//
DNS_STATUS
DnsAddrArray_Diff(
IN PDNS_ADDR_ARRAY pArray1,
IN PDNS_ADDR_ARRAY pArray2,
IN DWORD MatchFlag, OPTIONAL
OUT PDNS_ADDR_ARRAY* ppOnlyIn1,
OUT PDNS_ADDR_ARRAY* ppOnlyIn2,
OUT PDNS_ADDR_ARRAY* ppIntersect
)
/*++
Routine Description:
Computes differences and intersection of two IP arrays.
Out arrays are allocated with DnsAddrArray_Alloc(), caller must free with DnsAddrArray_Free()
Arguments:
pArray1 -- IP array
pArray2 -- IP array
MatchFlag -- flags for determining match
ppOnlyIn1 -- addr to recv IP array of addresses only in array 1 (not in array2)
ppOnlyIn2 -- addr to recv IP array of addresses only in array 2 (not in array1)
ppIntersect -- addr to recv IP array of intersection addresses
Return Value:
ERROR_SUCCESS if successful.
DNS_ERROR_NO_MEMORY if unable to allocate memory for IP arrays.
--*/
{
DWORD j;
PDNS_ADDR paddr;
PDNS_ADDR_ARRAY intersectArray = NULL;
PDNS_ADDR_ARRAY only1Array = NULL;
PDNS_ADDR_ARRAY only2Array = NULL;
//
// create result IP arrays
//
if ( ppIntersect )
{
intersectArray = DnsAddrArray_CreateCopy( pArray1 );
if ( !intersectArray )
{
goto NoMem;
}
*ppIntersect = intersectArray;
}
if ( ppOnlyIn1 )
{
only1Array = DnsAddrArray_CreateCopy( pArray1 );
if ( !only1Array )
{
goto NoMem;
}
*ppOnlyIn1 = only1Array;
}
if ( ppOnlyIn2 )
{
only2Array = DnsAddrArray_CreateCopy( pArray2 );
if ( !only2Array )
{
goto NoMem;
}
*ppOnlyIn2 = only2Array;
}
//
// clean the arrays
//
for ( j=0; j< pArray1->AddrCount; j++ )
{
paddr = &pArray1->AddrArray[j];
// if IP in both arrays, delete from "only" arrays
if ( DnsAddrArray_ContainsAddr( pArray2, paddr, MatchFlag ) )
{
if ( only1Array )
{
DnsAddrArray_DeleteAddr( only1Array, paddr, MatchFlag );
}
if ( only2Array )
{
DnsAddrArray_DeleteAddr( only2Array, paddr, MatchFlag );
}
}
// if IP not in both arrays, delete from intersection
// note intersection started as IpArray1
else if ( intersectArray )
{
DnsAddrArray_DeleteAddr(
intersectArray,
paddr,
MatchFlag );
}
}
return( ERROR_SUCCESS );
NoMem:
if ( intersectArray )
{
FREE_HEAP( intersectArray );
}
if ( only1Array )
{
FREE_HEAP( only1Array );
}
if ( only2Array )
{
FREE_HEAP( only2Array );
}
if ( ppIntersect )
{
*ppIntersect = NULL;
}
if ( ppOnlyIn1 )
{
*ppOnlyIn1 = NULL;
}
if ( ppOnlyIn2 )
{
*ppOnlyIn2 = NULL;
}
return( DNS_ERROR_NO_MEMORY );
}
BOOL
DnsAddrArray_IsIntersection(
IN PDNS_ADDR_ARRAY pArray1,
IN PDNS_ADDR_ARRAY pArray2,
IN DWORD MatchFlag OPTIONAL
)
/*++
Routine Description:
Determine if there's intersection of two IP arrays.
Arguments:
pArray1 -- IP array
pArray2 -- IP array
MatchFlag -- flags for determining match
Return Value:
TRUE if intersection.
FALSE if no intersection or empty or NULL array.
--*/
{
DWORD count;
DWORD j;
//
// protect against NULL
// this is called from the server on potentially changing (reconfigurable)
// IP array pointers; this provides cheaper protection than
// worrying about locking
//
if ( !pArray1 || !pArray2 )
{
return( FALSE );
}
//
// same array
//
if ( pArray1 == pArray2 )
{
return( TRUE );
}
//
// test that at least one IP in array 1 is in array 2
//
count = pArray1->AddrCount;
for ( j=0; j < count; j++ )
{
if ( DnsAddrArray_ContainsAddr(
pArray2,
&pArray1->AddrArray[j],
MatchFlag ) )
{
return( TRUE );
}
}
// no intersection
return( FALSE );
}
BOOL
DnsAddrArray_IsEqual(
IN PDNS_ADDR_ARRAY pArray1,
IN PDNS_ADDR_ARRAY pArray2,
IN DWORD MatchFlag
)
/*++
Routine Description:
Determines if IP arrays are equal.
Arguments:
pArray1 -- IP array
pArray2 -- IP array
MatchFlag -- level of match
Return Value:
TRUE if arrays equal.
FALSE otherwise.
--*/
{
DWORD j;
DWORD count;
//
// same array? or missing array?
//
if ( pArray1 == pArray2 )
{
return( TRUE );
}
if ( !pArray1 || !pArray2 )
{
return( FALSE );
}
//
// arrays the same length?
//
count = pArray1->AddrCount;
if ( count != pArray2->AddrCount )
{
return( FALSE );
}
//
// test that each IP in array 1 is in array 2
//
// test that each IP in array 2 is in array 1
// - do second test in case of duplicates
// that fool equal-lengths check
//
for ( j=0; j < count; j++ )
{
if ( !DnsAddrArray_ContainsAddr(
pArray2,
&pArray1->AddrArray[j],
MatchFlag ) )
{
return( FALSE );
}
}
for ( j=0; j < count; j++ )
{
if ( !DnsAddrArray_ContainsAddr(
pArray1,
&pArray2->AddrArray[j],
MatchFlag ) )
{
return( FALSE );
}
}
// equal arrays
return( TRUE );
}
DNS_STATUS
DnsAddrArray_Union(
IN PDNS_ADDR_ARRAY pArray1,
IN PDNS_ADDR_ARRAY pArray2,
OUT PDNS_ADDR_ARRAY* ppUnion
)
/*++
Routine Description:
Computes the union of two IP arrays.
Out array is allocated with DnsAddrArray_Alloc(), caller must free with DnsAddrArray_Free()
Arguments:
pArray1 -- IP array
pArray2 -- IP array
ppUnion -- addr to recv IP array of addresses in array 1 and in array2
Return Value:
ERROR_SUCCESS if successful.
DNS_ERROR_NO_MEMORY if unable to allocate memory for IP array.
--*/
{
PDNS_ADDR_ARRAY punionArray = NULL;
DWORD j;
//
// create result IP arrays
//
if ( !ppUnion )
{
return( ERROR_INVALID_PARAMETER );
}
punionArray = DnsAddrArray_Create(
pArray1->AddrCount +
pArray2->AddrCount );
if ( !punionArray )
{
goto NoMem;
}
*ppUnion = punionArray;
//
// create union from arrays
//
for ( j = 0; j < pArray1->AddrCount; j++ )
{
DnsAddrArray_AddAddr(
punionArray,
& pArray1->AddrArray[j],
0, // no family screen
DNSADDR_MATCH_ALL // screen out dups
);
}
for ( j = 0; j < pArray2->AddrCount; j++ )
{
DnsAddrArray_AddAddr(
punionArray,
& pArray2->AddrArray[j],
0, // no family screen
DNSADDR_MATCH_ALL // screen out dups
);
}
return( ERROR_SUCCESS );
NoMem:
if ( punionArray )
{
FREE_HEAP( punionArray );
*ppUnion = NULL;
}
return( DNS_ERROR_NO_MEMORY );
}
BOOL
DnsAddrArray_CheckAndMakeSubset(
IN OUT PDNS_ADDR_ARRAY pArraySub,
IN PDNS_ADDR_ARRAY pArraySuper
)
/*++
Routine Description:
Clear entries from IP array until it is subset of another IP array.
Arguments:
pArraySub -- addr array to make into subset
pArraySuper -- addr array superset
Return Value:
TRUE if pArraySub is already subset.
FALSE if needed to nix entries to make IP array a subset.
--*/
{
DWORD i;
DWORD newCount;
//
// check each entry in subset IP array,
// if not in superset IP array, eliminate it
//
newCount = pArraySub->AddrCount;
for (i=0; i < newCount; i++)
{
if ( ! DnsAddrArray_ContainsAddr(
pArraySuper,
& pArraySub->AddrArray[i],
DNSADDR_MATCH_ALL ) )
{
// remove this IP entry and replace with
// last IP entry in array
newCount--;
if ( i >= newCount )
{
break;
}
DnsAddr_Copy(
& pArraySub->AddrArray[i],
& pArraySub->AddrArray[newCount] );
}
}
// if eliminated entries, reset array count
if ( newCount < pArraySub->AddrCount )
{
pArraySub->AddrCount = newCount;
return( FALSE );
}
return( TRUE );
}
//
// Special case initializations
//
VOID
DnsAddrArray_InitSingleWithAddr(
IN OUT PDNS_ADDR_ARRAY pArray,
IN PDNS_ADDR pAddr
)
/*++
Routine Description:
Init array to contain single address.
This is for single address passing in array -- usually stack array.
Note, that this assumes uninitialized array unlike DnsAddrArray_AddIp()
and creates single IP array.
Arguments:
pArray -- array, at least of length 1
pAddr -- ptr to DNS address
Return Value:
None
--*/
{
pArray->AddrCount = 1;
pArray->MaxCount = 1;
DnsAddr_Copy(
&pArray->AddrArray[0],
pAddr );
}
VOID
DnsAddrArray_InitSingleWithIp6(
IN OUT PDNS_ADDR_ARRAY pArray,
IN PIP6_ADDRESS pIp6
)
/*++
Routine Description:
Init array to contain single IP6 address.
This is for single address passing in array -- usually stack array.
Note, that this assumes uninitialized array unlike DnsAddrArray_AddIp()
and creates single IP array.
Arguments:
pArray -- array, at least of length 1
pIp6 -- IP6 address
Return Value:
None
--*/
{
pArray->AddrCount = 1;
pArray->MaxCount = 1;
DnsAddr_BuildFromIp6(
&pArray->AddrArray[0],
pIp6,
0, // no scope
0 // no port info
);
}
VOID
DnsAddrArray_InitSingleWithIp4(
IN OUT PDNS_ADDR_ARRAY pArray,
IN IP4_ADDRESS Ip4Addr
)
/*++
Routine Description:
Init IP array to contain single IP4 address.
This is for single address passing in array -- usually stack array.
Note, that this assumes uninitialized array unlike DnsAddrArray_AddIp()
and creates single IP array.
Arguments:
pArray -- DNS_ADDR_ARRAY, at least of length 1
Ip4Addr -- IP4 address
Return Value:
None
--*/
{
pArray->AddrCount = 1;
pArray->MaxCount = 1;
DnsAddr_BuildFromIp4(
&pArray->AddrArray[0],
Ip4Addr,
0 // no port info
);
}
DWORD
DnsAddrArray_InitSingleWithSockaddr(
IN OUT PDNS_ADDR_ARRAY pArray,
IN PSOCKADDR pSockAddr
)
/*++
Routine Description:
Init IP array to contain single address.
This is for single address passing in array -- usually stack array.
Note, that this assumes uninitialized array unlike DnsAddrArray_AddIp()
and creates single IP array.
Arguments:
pArray -- DNS_ADDR_ARRAY, at least of length 1
pSockaddr -- ptr to sockaddr
Return Value:
Family of sockaddr (AF_INET or AF_INET6) if successful.
Zero on error.
--*/
{
pArray->AddrCount = 1;
pArray->MaxCount = 1;
return DnsAddr_Build(
&pArray->AddrArray[0],
pSockAddr,
0, // any family
0, // no subnet length info
0 // no flags
);
}
//
// Write other types
//
PIP4_ARRAY
DnsAddrArray_CreateIp4Array(
IN PDNS_ADDR_ARRAY pArray
)
/*++
Routine Description:
Create IP4 array from address array.
Arguments:
pArray -- array to make into IP4 array.
Return Value:
Ptr to IP4_ARRAY with all IP4 addrs in input array.
NULL if no IP4 in array.
NULL on failure.
--*/
{
PIP4_ARRAY parray4 = NULL;
DWORD i;
DWORD count4 = 0;
DNSDBG( IPARRAY, (
"DnsAddrArray_CreateIp4Array( %p )\n",
pArray ));
if ( ! pArray )
{
goto Done;
}
//
// count IP4
//
count4 = DnsAddrArray_GetFamilyCount( pArray, AF_INET );
//
// allocate the array
//
parray4 = Dns_CreateIpArray( count4 );
if ( !parray4 )
{
goto Done;
}
//
// fill the array
//
for ( i=0; i<pArray->AddrCount; i++ )
{
IP4_ADDRESS ip4;
ip4 = DnsAddr_GetIp4( &pArray->AddrArray[i] );
if ( ip4 != BAD_IP4_ADDR )
{
Dns_AddIpToIpArray(
parray4,
ip4 );
}
}
//
// reset to eliminate zero's which may be left by duplicate entries
//
// note, this does whack zeros, but that happens in Dns_AddIpToIpArray()
// above also, as zero's are taken to be "empty slots" in array;
// this is an artifact of the IP4_ARRAY being used both as a fixed
// object (where any value would be ok) and dynamically (where the
// zeros are treated as empty, because we don't have independent size
// and length fields)
//
Dns_CleanIpArray( parray4, DNS_IPARRAY_CLEAN_ZERO );
Done:
DNSDBG( IPARRAY, (
"Leave DnsAddrArray_CreateIp4Array() => %p\n"
"\tIP4 count %d\n"
"\tnew array count %d\n",
parray4,
parray4 ? parray4->AddrCount : 0,
count4 ));
return( parray4 );
}
DWORD
DnsAddrArray_NetworkMatchIp4(
IN PDNS_ADDR_ARRAY pArray,
IN IP4_ADDRESS IpAddr,
OUT PDNS_ADDR * ppAddr
)
/*++
Routine Description:
Check through array for best network match.
Arguments:
pArray -- existing array
IpAddr -- IP4 addr to check
ppAddr -- addr to receive ptr to best match element
Return Value:
DNSADDR_NETMATCH_NONE
DNSADDR_NETMATCH_CLASSA
DNSADDR_NETMATCH_CLASSB
DNSADDR_NETMATCH_CLASSC
DNSADDR_NETMATCH_SUBNET
--*/
{
DWORD i;
IP4_ADDRESS classMask;
DWORD fmatch = DNSADDR_NETMATCH_NONE;
PDNS_ADDR paddrMatch = NULL;
DNSDBG( IPARRAY, (
"DnsAddrArray_NetworkMatchIp( %p, %s, %p )\n",
pArray,
IP4_STRING( IpAddr ),
ppAddr ));
if ( ! pArray )
{
goto Done;
}
//
// DCR: subnet matching improvements
// - use length throughout
// - return bits matched
// - 32 for identical addrs
// - 31 for subnet match
// - 0 no match in class
//
// separate matching function with optional
// IN param of class subnet length of IP
//
//
// get class subnet mask
//
classMask = Dns_GetNetworkMask( IpAddr );
//
// check each element in array
//
for ( i=0; i<pArray->AddrCount; i++ )
{
DWORD classMatchLevel;
IP4_ADDRESS subnet;
IP4_ADDRESS ip;
PDNS_ADDR paddr = &pArray->AddrArray[i];
ip = DnsAddr_GetIp4( paddr );
if ( ip == BAD_IP4_ADDR )
{
continue;
}
// xor to nix any common network bits
ip = ip ^ IpAddr;
// check subnet match (if subnet given)
// note shift bits up, as in network order
subnet = (IP4_ADDRESS)(-1);
if ( paddr->SubnetLength )
{
subnet >>= (32 - paddr->SubnetLength);
if ( (ip & subnet) == 0 )
{
fmatch = DNSADDR_NETMATCH_SUBNET;
paddrMatch = paddr;
break;
}
}
//
// try class match
// - stop if have previous match at this level
// - otherwise always do class C
// - stop if reach class subnet for IpAddr
// example, we do NOT return NETMATCH_CLASSB for
// a class C address -- it's meaningless
//
classMatchLevel = DNSADDR_NETMATCH_CLASSC;
subnet = SUBNET_MASK_CLASSC;
while ( fmatch < classMatchLevel )
{
if ( (ip & subnet) == 0 )
{
fmatch = classMatchLevel;
paddrMatch = paddr;
break;
}
classMatchLevel--;
subnet >>= 8;
if ( classMask > subnet )
{
break;
}
}
}
Done:
//
// set return addr
//
if ( ppAddr )
{
*ppAddr = paddrMatch;
}
DNSDBG( IPARRAY, (
"Leave DnsAddrArray_NetworkMatchIp( %p, %s, %p )\n"
"\tMatch Level = %d\n"
"\tMatch Addr = %s (subnet len %d)\n",
pArray,
IP4_STRING( IpAddr ),
ppAddr,
paddrMatch ? DNSADDR_STRING(paddrMatch) : NULL,
paddrMatch ? paddrMatch->SubnetLength : 0 ));
return( fmatch );
}
//
// End dnsaddr.c
//