|
|
/*++
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
//
|