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.
 
 
 
 
 
 

2426 lines
44 KiB

/*++
Copyright (c) 1995-2001 Microsoft Corporation
Module Name:
ip6.c
Abstract:
Domain Name System (DNS) Library
IP6 address array routines.
Author:
Jim Gilroy (jamesg) October 2001
Revision History:
--*/
#include "local.h"
//
// Max IP count when doing IP array to\from string conversions
//
#define MAX_PARSE_IP (1000)
//
// For IP6 debug string writing.
//
CHAR g_Ip6StringBuffer[ IP6_ADDRESS_STRING_BUFFER_LENGTH ];
//
// IP6 Mcast address base
// FF02:0:0:0:0:2::/96 base plus 32bits of hash
//
// IP6_ADDRESS g_Ip6McastBaseAddr = {0xFF,2, 0,0, 0,0, 0,0, 0,0, 0,2, 0,0, 0,0};
//
// General IP6 routines.
//
VOID
Dns_Md5Hash(
OUT PBYTE pHash,
IN PSTR pName
)
/*++
Routine Description:
Create MD5 hash of name.
Arguments:
pHash -- 128bit (16 byte) buffer to recv hash
pName -- name to hash
Return Value:
None
--*/
{
DNSDBG( TRACE, (
"Dns_Md5Hash( %p, %s )\n",
pHash,
pName ));
//
// DCR: FIX0: need real MD5 hash -- ask Lars, Scott
//
{
DWORD sum = 0;
RtlZeroMemory(
pHash,
16 );
while ( *pName )
{
sum += *pName++;
}
* (PDWORD)pHash = sum;
}
}
BOOL
Ip6_McastCreate(
OUT PIP6_ADDRESS pIp,
IN PWSTR pName
)
/*++
Routine Description:
Create mcast IP6 address.
Arguments:
pIp -- address to set with mcast address
pName -- DNS name mcast address is for
Return Value:
TRUE if made mcast address for name.
FALSE on error.
--*/
{
WCHAR label[ DNS_MAX_LABEL_BUFFER_LENGTH ];
WCHAR downLabel[ DNS_MAX_LABEL_BUFFER_LENGTH ];
CHAR utf8Label[ DNS_MAX_LABEL_BUFFER_LENGTH ];
CHAR md5Hash[ 16 ]; // 128bit hash
IP6_ADDRESS mcastAddr;
DWORD bufLength;
DNSDBG( TRACE, (
"Ip6_McastCreate( %p, %S )\n",
pIp,
pName ));
//
// hash of downcased label
//
Dns_CopyNameLabelW(
label,
pName );
Dns_MakeCanonicalNameW(
downLabel,
DNS_MAX_LABEL_BUFFER_LENGTH,
label,
0 // null terminated
);
bufLength = DNS_MAX_LABEL_BUFFER_LENGTH;
if ( !Dns_StringCopy(
utf8Label,
& bufLength,
(PCHAR) downLabel,
0, // null terminated
DnsCharSetUnicode,
DnsCharSetUtf8 ) )
{
DNS_ASSERT( FALSE );
return FALSE;
}
//
// hash
//
Dns_Md5Hash(
md5Hash,
utf8Label );
// mcast addr
// - first 12 bytes are fixed
// - last 4 bytes are first 32bits of hash
#if 0
IP6_ADDR_COPY(
pIp,
& g_Ip6McastBaseAddr );
#else
RtlZeroMemory(
pIp,
sizeof(IP6_ADDRESS) );
pIp->IP6Byte[0] = 0xff;
pIp->IP6Byte[1] = 2;
pIp->IP6Byte[11] = 2;
#endif
RtlCopyMemory(
& pIp->IP6Dword[3],
md5Hash,
sizeof(DWORD) );
return TRUE;
}
DWORD
Ip6_CopyFromSockaddr(
OUT PIP6_ADDRESS pIp,
IN PSOCKADDR pSockAddr,
IN INT Family
)
/*++
Routine Description:
Extract IP from sockaddr.
Arguments:
pIp -- 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
Return Value:
Family extracted (AF_INET) or (AF_INET6) if successful.
Zero on bad sockaddr family.
--*/
{
DWORD saFamily = pSockAddr->sa_family;
if ( Family &&
saFamily != Family )
{
return 0;
}
if ( saFamily == AF_INET6 )
{
IP6_ADDR_COPY(
pIp,
(PIP6_ADDRESS) &((PSOCKADDR_IN6)pSockAddr)->sin6_addr );
}
else if ( saFamily == AF_INET )
{
IP6_SET_ADDR_V4MAPPED(
pIp,
((PSOCKADDR_IN)pSockAddr)->sin_addr.s_addr );
}
else
{
saFamily = 0;
}
return saFamily;
}
INT
Ip6_Family(
IN PIP6_ADDRESS pIp
)
/*++
Routine Description:
Get IP6 family
AF_INET if V4MAPPED
AF_INET6 otherwise
Arguments:
pIp -- addr
Return Value:
AF_INET if address is V4MAPPED
AF_INET6 otherwise
--*/
{
return IP6_IS_ADDR_V4MAPPED(pIp) ? AF_INET : AF_INET6;
}
INT
Ip6_WriteSockaddr(
OUT PSOCKADDR pSockaddr,
OUT PDWORD pSockaddrLength, OPTIONAL
IN PIP6_ADDRESS pIp,
IN WORD Port OPTIONAL
)
/*++
Routine Description:
Write sockaddr with IP6 or IP4 address.
Arguments:
pSockaddr -- ptr to sockaddr, must be at least SOCKADDR_IN6 size
pSockaddrLength -- ptr to DWORD to set be with sockaddr length
pIp -- addr to set with IP6 address
Port -- port to write
Return Value:
Family written (AF_INET) or (AF_INET6) if successful.
Zero on bad sockaddr family.
--*/
{
WORD family;
DWORD length;
IP4_ADDRESS ip4;
DNSDBG( SOCKET, (
"Ip6_WriteSockaddr( %p, %p, %p, %d )\n",
pSockaddr,
pSockaddrLength,
pIp,
Port ));
// zero
RtlZeroMemory(
pSockaddr,
sizeof( SOCKADDR_IN6 ) );
//
// fill in sockaddr for IP4 or IP6
//
ip4 = IP6_GET_V4_ADDR_IF_MAPPED( pIp );
if ( ip4 != BAD_IP4_ADDR )
{
family = AF_INET;
length = sizeof(SOCKADDR_IN);
((PSOCKADDR_IN)pSockaddr)->sin_addr.s_addr = ip4;
}
else
{
family = AF_INET6;
length = sizeof(SOCKADDR_IN6);
RtlCopyMemory(
(PIP6_ADDRESS) &((PSOCKADDR_IN6)pSockaddr)->sin6_addr,
pIp,
sizeof(IP6_ADDRESS) );
}
// fill family and port -- same position for both type
pSockaddr->sa_family = family;
((PSOCKADDR_IN)pSockaddr)->sin_port = Port;
// return length if requested
if ( pSockaddrLength )
{
*pSockaddrLength = length;
}
return family;
}
INT
Ip6_WriteDnsAddr(
OUT PDNS_ADDR pDnsAddr,
IN PIP6_ADDRESS pIp,
IN WORD Port OPTIONAL
)
/*++
Routine Description:
Write DNS_ADDR with IP6 or IP4 address.
Arguments:
pSockaddr -- ptr to sockaddr blob
pIp -- addr to set with IP6 address
Port -- port to write
Return Value:
Family written (AF_INET) or (AF_INET6) if successful.
Zero on bad sockaddr family.
--*/
{
return Ip6_WriteSockaddr(
& pDnsAddr->Sockaddr,
& pDnsAddr->SockaddrLength,
pIp,
Port );
}
PSTR
Ip6_TempNtoa(
IN PIP6_ADDRESS pIp
)
/*++
Routine Description:
Get string for IP6 address.
This is temp inet6_ntoa() until i get that built.
This will work for all IP4 addresses and will (we presume)
only rarely collide on IP6.
Arguments:
pIp -- ptr to IP to get string for
Return Value:
Address string.
--*/
{
// make life simple
if ( !pIp )
{
return NULL;
}
// if IP4, use existing inet_ntoa()
if ( IP6_IS_ADDR_V4MAPPED( pIp ) )
{
return inet_ntoa( *(IN_ADDR *) &pIp->IP6Dword[3] );
}
// if IP6 write into global buffer
// - until inet6_ntoa() which will use existing TLS block
g_Ip6StringBuffer[0] = 0;
RtlIpv6AddressToStringA(
(PIN6_ADDR) pIp,
g_Ip6StringBuffer );
return g_Ip6StringBuffer;
}
PSTR
Ip6_AddrStringForSockaddr(
IN PSOCKADDR pSockaddr
)
/*++
Routine Description:
Get string for sockaddr.
Arguments:
pSockaddr -- ptr to sockaddr
Return Value:
Address string.
--*/
{
IP6_ADDRESS ip6;
if ( ! pSockaddr ||
! Ip6_CopyFromSockaddr(
& ip6,
pSockaddr,
0 ) )
{
return NULL;
}
return Ip6_TempNtoa( &ip6 );
}
//
// Routines to handle actual array of IP addresses.
//
PIP6_ADDRESS
Ip6_FlatArrayCopy(
IN PIP6_ADDRESS AddrArray,
IN DWORD Count
)
/*++
Routine Description:
Create copy of IP address array.
Arguments:
AddrArray -- array of IP addresses
Count -- count of IP addresses
Return Value:
Ptr to IP address array copy, if successful
NULL on failure.
--*/
{
PIP6_ADDRESS parray;
// validate
if ( ! AddrArray || Count == 0 )
{
return( NULL );
}
// allocate memory and copy
parray = (PIP6_ADDRESS) ALLOCATE_HEAP( Count*sizeof(IP6_ADDRESS) );
if ( ! parray )
{
return( NULL );
}
memcpy(
parray,
AddrArray,
Count*sizeof(IP6_ADDRESS) );
return( parray );
}
#if 0
BOOL
Dns_ValidateIp6Array(
IN PIP6_ADDRESS AddrArray,
IN DWORD Count,
IN DWORD dwFlag
)
/*++
Routine Description:
Validate IP address array.
Current checks:
- existence
- non-broadcast
- non-lookback
Arguments:
AddrArray -- array of IP addresses
Count -- count of IP addresses
dwFlag -- validity tests to do; currently unused
Return Value:
TRUE if valid IP addresses.
FALSE if invalid address found.
--*/
{
DWORD i;
//
// protect against bad parameters
//
if ( Count && ! AddrArray )
{
return( FALSE );
}
//
// check each IP address
//
for ( i=0; i < Count; i++)
{
// DCR: need IP6 validations
if( AddrArray[i] == INADDR_ANY
||
AddrArray[i] == INADDR_BROADCAST
||
AddrArray[i] == INADDR_LOOPBACK )
{
return( FALSE );
}
}
return( TRUE );
}
#endif
//
// IP6_ARRAY routines
//
DWORD
Ip6Array_Sizeof(
IN PIP6_ARRAY pIpArray
)
/*++
Routine Description:
Get size in bytes of IP address array.
Arguments:
pIpArray -- IP address array to find size of
Return Value:
Size in bytes of IP array.
--*/
{
if ( ! pIpArray )
{
return 0;
}
return (pIpArray->AddrCount * sizeof(IP6_ADDRESS)) + 2*sizeof(DWORD);
}
BOOL
Ip6Array_Probe(
IN PIP6_ARRAY pIpArray
)
/*++
Routine Description:
Touch all entries in IP array to insure valid memory.
Arguments:
pIpArray -- ptr to IP address array
Return Value:
TRUE if successful.
FALSE otherwise
--*/
{
DWORD i;
BOOL result;
if ( ! pIpArray )
{
return( TRUE );
}
for ( i=0; i<pIpArray->AddrCount; i++ )
{
result = IP6_IS_ADDR_LOOPBACK( &pIpArray->AddrArray[i] );
}
return( TRUE );
}
#if 0
BOOL
Ip6Array_ValidateSizeOf(
IN PIP6_ARRAY pIpArray,
IN DWORD dwMemoryLength
)
/*++
Routine Description:
Check that size of IP array, corresponds to length of memory.
Arguments:
pIpArray -- ptr to IP address array
dwMemoryLength -- length of IP array memory
Return Value:
TRUE if IP array size matches memory length
FALSE otherwise
--*/
{
return( Ip6Array_SizeOf(pIpArray) == dwMemoryLength );
}
#endif
VOID
Ip6Array_Init(
IN OUT PIP6_ARRAY pIpArray,
IN DWORD MaxCount
)
/*++
Routine Description:
Init memory as IP6 array.
Arguments:
pArray -- array to init
MaxCount -- count of addresses
Return Value:
None
--*/
{
pIpArray->MaxCount = MaxCount;
pIpArray->AddrCount = 0;
}
VOID
Ip6Array_Free(
IN PIP6_ARRAY pIpArray
)
/*++
Routine Description:
Free IP array.
Only for arrays created through create routines below.
Arguments:
pIpArray -- IP array to free.
Return Value:
None
--*/
{
FREE_HEAP( pIpArray );
}
PIP6_ARRAY
Ip6Array_Create(
IN DWORD MaxCount
)
/*++
Routine Description:
Create uninitialized IP address array.
Arguments:
AddrCount -- count of addresses array will hold
Return Value:
Ptr to uninitialized IP address array, if successful
NULL on failure.
--*/
{
PIP6_ARRAY parray;
DNSDBG( IPARRAY, ( "Ip6Array_Create() of count %d\n", MaxCount ));
parray = (PIP6_ARRAY) ALLOCATE_HEAP_ZERO(
(MaxCount * sizeof(IP6_ADDRESS)) +
sizeof(IP6_ARRAY) - sizeof(IP6_ADDRESS) );
if ( ! parray )
{
return( NULL );
}
//
// initialize IP count
//
parray->MaxCount = MaxCount;
DNSDBG( IPARRAY, (
"Ip6Array_Create() new array (count %d) at %p\n",
MaxCount,
parray ));
return( parray );
}
PIP6_ARRAY
Ip6Array_CreateFromIp4Array(
IN PIP4_ARRAY pIp4Array
)
/*++
Routine Description:
Create IP6 array from IP4 array.
Arguments:
pIp4Array -- IP4 array
Return Value:
Ptr to uninitialized IP address array, if successful
NULL on failure.
--*/
{
PIP6_ARRAY parray;
DWORD i;
DNSDBG( IPARRAY, (
"Ip6Array_CreateFromIp4Array( %p )\n",
pIp4Array ));
if ( ! pIp4Array )
{
return( NULL );
}
//
// allocate the array
//
parray = Ip6Array_Create( pIp4Array->AddrCount );
if ( !parray )
{
return NULL;
}
//
// fill the array
//
for ( i=0; i<pIp4Array->AddrCount; i++ )
{
Ip6Array_AddIp4(
parray,
pIp4Array->AddrArray[i],
FALSE // no duplicate screen
);
}
DNSDBG( IPARRAY, (
"Leave Ip6Array_CreateFromIp4Array() new array (count %d) at %p\n",
parray->AddrCount,
parray ));
return( parray );
}
PIP6_ARRAY
Ip6Array_CreateFromFlatArray(
IN DWORD AddrCount,
IN PIP6_ADDRESS pipAddrs
)
/*++
Routine Description:
Create IP address array structure from existing array of IP addresses.
Arguments:
AddrCount -- count of addresses in array
pipAddrs -- IP address array
Return Value:
Ptr to IP address array.
NULL on failure.
--*/
{
PIP6_ARRAY parray;
if ( ! pipAddrs || ! AddrCount )
{
return( NULL );
}
// create IP array of desired size
// then copy incoming array of addresses
parray = Ip6Array_Create( AddrCount );
if ( ! parray )
{
return( NULL );
}
memcpy(
parray->AddrArray,
pipAddrs,
AddrCount * sizeof(IP6_ADDRESS) );
parray->AddrCount = AddrCount;
return( parray );
}
PIP6_ARRAY
Ip6Array_CopyAndExpand(
IN PIP6_ARRAY pIpArray,
IN DWORD ExpandCount,
IN BOOL fDeleteExisting
)
/*++
Routine Description:
Create expanded copy of IP address array.
Arguments:
pIpArray -- IP 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.
--*/
{
PIP6_ARRAY pnewArray;
DWORD newCount;
//
// no existing array -- just create desired size
//
if ( ! pIpArray )
{
if ( ExpandCount )
{
return Ip6Array_Create( ExpandCount );
}
return( NULL );
}
//
// create IP array of desired size
// then copy any existing addresses
//
pnewArray = Ip6Array_Create( pIpArray->AddrCount + ExpandCount );
if ( ! pnewArray )
{
return( NULL );
}
RtlCopyMemory(
(PBYTE) pnewArray->AddrArray,
(PBYTE) pIpArray->AddrArray,
pIpArray->AddrCount * sizeof(IP6_ADDRESS) );
//
// delete existing -- for "grow mode"
//
if ( fDeleteExisting )
{
FREE_HEAP( pIpArray );
}
return( pnewArray );
}
PIP6_ARRAY
Ip6Array_CreateCopy(
IN PIP6_ARRAY pIpArray
)
/*++
Routine Description:
Create copy of IP address array.
Arguments:
pIpArray -- IP address array to copy
Return Value:
Ptr to IP address array copy, if successful
NULL on failure.
--*/
{
#if 0
PIP6_ARRAY pIpArrayCopy;
if ( ! pIpArray )
{
return( NULL );
}
// create IP array of desired size
// then copy entire structure
pIpArrayCopy = Ip6Array_Create( pIpArray->AddrCount );
if ( ! pIpArrayCopy )
{
return( NULL );
}
memcpy(
pIpArrayCopy,
pIpArray,
Ip6Array_Sizeof(pIpArray) );
return( pIpArrayCopy );
#endif
//
// call essentially "CopyEx" function
//
// note, not macroing this because this may well become
// a DLL entry point
//
return Ip6Array_CopyAndExpand(
pIpArray,
0, // no expansion
0 // don't delete existing array
);
}
BOOL
Ip6Array_ContainsIp(
IN PIP6_ARRAY pIpArray,
IN PIP6_ADDRESS pIp
)
/*++
Routine Description:
Check if IP array contains desired address.
Arguments:
pIpArray -- IP address array to copy
pIp -- IP to check for
Return Value:
TRUE if address in array.
Ptr to IP address array copy, if successful
NULL on failure.
--*/
{
DWORD i;
if ( ! pIpArray )
{
return( FALSE );
}
for (i=0; i<pIpArray->AddrCount; i++)
{
if ( IP6_ADDR_EQUAL( pIp, &pIpArray->AddrArray[i] ) )
{
return( TRUE );
}
}
return( FALSE );
}
BOOL
Ip6Array_AddIp(
IN OUT PIP6_ARRAY pIpArray,
IN PIP6_ADDRESS pAddIp,
IN BOOL fScreenDups
)
/*++
Routine Description:
Add IP address to IP array.
Allowable "slot" in array, is any zero IP address.
Arguments:
pIpArray -- IP address array to add to
pAddIp -- IP address to add to array
fScreenDups -- screen out duplicates
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 ( !pIpArray )
{
return FALSE;
}
//
// check for duplicates
//
if ( fScreenDups )
{
if ( Ip6Array_ContainsIp( pIpArray, pAddIp ) )
{
return TRUE;
}
}
count = pIpArray->AddrCount;
if ( count >= pIpArray->MaxCount )
{
return FALSE;
}
IP6_ADDR_COPY(
&pIpArray->AddrArray[ count ],
pAddIp );
pIpArray->AddrCount = ++count;
return TRUE;
}
BOOL
Ip6Array_AddSockaddr(
IN OUT PIP6_ARRAY pIpArray,
IN PSOCKADDR pSockaddr,
IN DWORD Family,
IN BOOL fScreenDups
)
/*++
Routine Description:
Add IP address to IP array.
Allowable "slot" in array, is any zero IP address.
Arguments:
pIpArray -- IP address array to add to
pAddIp -- IP address to add to array
Family -- required family to do add; 0 for add always
fScreenDups -- screen out duplicates
Return Value:
TRUE if successful.
FALSE if array full.
--*/
{
IP6_ADDRESS ip6;
if ( !Ip6_CopyFromSockaddr(
& ip6,
pSockaddr,
Family ) )
{
return FALSE;
}
return Ip6Array_AddIp(
pIpArray,
&ip6,
fScreenDups );
}
BOOL
Ip6Array_AddIp4(
IN OUT PIP6_ARRAY pIpArray,
IN IP4_ADDRESS Ip4,
IN BOOL fScreenDups
)
/*++
Routine Description:
Add IP4 address to IP array.
Arguments:
pIpArray -- IP address array to add to
Ip4 -- IP4 address to add to array
fScreenDups -- screen out duplicates
Return Value:
TRUE if successful.
FALSE if array full.
--*/
{
IP6_ADDRESS ip6;
IP6_SET_ADDR_V4MAPPED(
&ip6,
Ip4 );
return Ip6Array_AddIp(
pIpArray,
&ip6,
fScreenDups );
}
VOID
Ip6Array_Clear(
IN OUT PIP6_ARRAY pIpArray
)
/*++
Routine Description:
Clear memory in IP array.
Arguments:
pIpArray -- IP address array to clear
Return Value:
None.
--*/
{
// clear just the address list, leaving count intact
RtlZeroMemory(
pIpArray->AddrArray,
pIpArray->AddrCount * sizeof(IP6_ADDRESS) );
}
VOID
Ip6Array_Reverse(
IN OUT PIP6_ARRAY pIpArray
)
/*++
Routine Description:
Reorder the list of IPs in reverse.
Arguments:
pIpArray -- IP address array to reorder
Return Value:
None.
--*/
{
IP6_ADDRESS tempIp;
DWORD i;
DWORD j;
//
// swap IPs working from ends to the middle
//
if ( pIpArray &&
pIpArray->AddrCount )
{
for ( i = 0, j = pIpArray->AddrCount - 1;
i < j;
i++, j-- )
{
IP6_ADDR_COPY(
& tempIp,
& pIpArray->AddrArray[i] );
IP6_ADDR_COPY(
& pIpArray->AddrArray[i],
& pIpArray->AddrArray[j] );
IP6_ADDR_COPY(
& pIpArray->AddrArray[j],
& tempIp );
}
}
}
BOOL
Ip6Array_CheckAndMakeIpArraySubset(
IN OUT PIP6_ARRAY pIpArraySub,
IN PIP6_ARRAY pIpArraySuper
)
/*++
Routine Description:
Clear entries from IP array until it is subset of another IP array.
Arguments:
pIpArraySub -- IP array to make into subset
pIpArraySuper -- IP array superset
Return Value:
TRUE if pIpArraySub 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 = pIpArraySub->AddrCount;
for (i=0; i < newCount; i++)
{
if ( ! Ip6Array_ContainsIp(
pIpArraySuper,
& pIpArraySub->AddrArray[i] ) )
{
// remove this IP entry and replace with
// last IP entry in array
newCount--;
if ( i >= newCount )
{
break;
}
IP6_ADDR_COPY(
& pIpArraySub->AddrArray[i],
& pIpArraySub->AddrArray[ newCount ] );
}
}
// if eliminated entries, reset array count
if ( newCount < pIpArraySub->AddrCount )
{
pIpArraySub->AddrCount = newCount;
return( FALSE );
}
return( TRUE );
}
DWORD
WINAPI
Ip6Array_DeleteIp(
IN OUT PIP6_ARRAY pIpArray,
IN PIP6_ADDRESS pIpDelete
)
/*++
Routine Description:
Delete IP address from IP array.
Arguments:
pIpArray -- IP address array to add to
pIpDelete -- 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 = pIpArray->AddrCount-1;
//
// check each IP for match to delete IP
// - go backwards through array
// - swap in last IP in array
//
while ( i >= 0 )
{
if ( IP6_ADDR_EQUAL( &pIpArray->AddrArray[i], pIpDelete ) )
{
IP6_ADDR_COPY(
& pIpArray->AddrArray[i],
& pIpArray->AddrArray[ currentLast ] );
IP6_SET_ADDR_ANY( &pIpArray->AddrArray[ currentLast ] );
currentLast--;
found++;
}
i--;
}
pIpArray->AddrCount = currentLast + 1;
return( found );
}
#if 0
INT
WINAPI
Ip6Array_Clean(
IN OUT PIP6_ARRAY pIpArray,
IN DWORD Flag
)
/*++
Routine Description:
Clean IP array.
Remove bogus stuff from IP Array:
-- Zeros
-- Loopback
-- AutoNet
Arguments:
pIpArray -- IP address array to add to
Flag -- which cleanups to make
Return Value:
Count of instances cleaned from array.
--*/
{
DWORD found = 0;
INT i;
INT currentLast;
IP6_ADDRESS ip;
i = currentLast = pIpArray->AddrCount-1;
while ( i >= 0 )
{
ip = pIpArray->AddrArray[i];
if (
( (Flag & DNS_IPARRAY_CLEAN_LOOPBACK) && ip == DNS_NET_ORDER_LOOPBACK )
||
( (Flag & DNS_IPARRAY_CLEAN_ZERO) && ip == 0 )
||
( (Flag & DNS_IPARRAY_CLEAN_AUTONET) && DNS_IS_AUTONET_IP(ip) ) )
{
// remove IP from array
pIpArray->AddrArray[i] = pIpArray->AddrArray[ currentLast ];
currentLast--;
found++;
}
i--;
}
pIpArray->AddrCount -= found;
return( found );
}
#endif
DNS_STATUS
WINAPI
Ip6Array_Diff(
IN PIP6_ARRAY pIpArray1,
IN PIP6_ARRAY pIpArray2,
OUT PIP6_ARRAY* ppOnlyIn1,
OUT PIP6_ARRAY* ppOnlyIn2,
OUT PIP6_ARRAY* ppIntersect
)
/*++
Routine Description:
Computes differences and intersection of two IP arrays.
Out arrays are allocated with Ip6Array_Alloc(), caller must free with Ip6Array_Free()
Arguments:
pIpArray1 -- IP array
pIpArray2 -- IP array
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;
PIP6_ADDRESS pip;
PIP6_ARRAY intersectArray = NULL;
PIP6_ARRAY only1Array = NULL;
PIP6_ARRAY only2Array = NULL;
//
// create result IP arrays
//
if ( ppIntersect )
{
intersectArray = Ip6Array_CreateCopy( pIpArray1 );
if ( !intersectArray )
{
goto NoMem;
}
*ppIntersect = intersectArray;
}
if ( ppOnlyIn1 )
{
only1Array = Ip6Array_CreateCopy( pIpArray1 );
if ( !only1Array )
{
goto NoMem;
}
*ppOnlyIn1 = only1Array;
}
if ( ppOnlyIn2 )
{
only2Array = Ip6Array_CreateCopy( pIpArray2 );
if ( !only2Array )
{
goto NoMem;
}
*ppOnlyIn2 = only2Array;
}
//
// clean the arrays
//
for ( j=0; j< pIpArray1->AddrCount; j++ )
{
pip = &pIpArray1->AddrArray[j];
// if IP in both arrays, delete from "only" arrays
if ( Ip6Array_ContainsIp( pIpArray2, pip ) )
{
if ( only1Array )
{
Ip6Array_DeleteIp( only1Array, pip );
}
if ( only2Array )
{
Ip6Array_DeleteIp( only2Array, pip );
}
}
// if IP not in both arrays, delete from intersection
// note intersection started as IpArray1
else if ( intersectArray )
{
Ip6Array_DeleteIp( intersectArray, pip );
}
}
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
WINAPI
Ip6Array_IsIntersection(
IN PIP6_ARRAY pIpArray1,
IN PIP6_ARRAY pIpArray2
)
/*++
Routine Description:
Determine if there's intersection of two IP arrays.
Arguments:
pIpArray1 -- IP array
pIpArray2 -- IP array
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 ( !pIpArray1 || !pIpArray2 )
{
return( FALSE );
}
//
// same array
//
if ( pIpArray1 == pIpArray2 )
{
return( TRUE );
}
//
// test that at least one IP in array 1 is in array 2
//
count = pIpArray1->AddrCount;
for ( j=0; j < count; j++ )
{
if ( Ip6Array_ContainsIp( pIpArray2, &pIpArray1->AddrArray[j] ) )
{
return( TRUE );
}
}
// no intersection
return( FALSE );
}
BOOL
WINAPI
Ip6Array_IsEqual(
IN PIP6_ARRAY pIpArray1,
IN PIP6_ARRAY pIpArray2
)
/*++
Routine Description:
Determines if IP arrays are equal.
Arguments:
pIpArray1 -- IP array
pIpArray2 -- IP array
Return Value:
TRUE if arrays equal.
FALSE otherwise.
--*/
{
DWORD j;
DWORD count;
//
// same array? or missing array?
//
if ( pIpArray1 == pIpArray2 )
{
return( TRUE );
}
if ( !pIpArray1 || !pIpArray2 )
{
return( FALSE );
}
//
// arrays the same length?
//
count = pIpArray1->AddrCount;
if ( count != pIpArray2->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 ( !Ip6Array_ContainsIp( pIpArray2, &pIpArray1->AddrArray[j] ) )
{
return( FALSE );
}
}
for ( j=0; j < count; j++ )
{
if ( !Ip6Array_ContainsIp( pIpArray1, &pIpArray2->AddrArray[j] ) )
{
return( FALSE );
}
}
// equal arrays
return( TRUE );
}
DNS_STATUS
WINAPI
Ip6Array_Union(
IN PIP6_ARRAY pIpArray1,
IN PIP6_ARRAY pIpArray2,
OUT PIP6_ARRAY* ppUnion
)
/*++
Routine Description:
Computes the union of two IP arrays.
Out array is allocated with Ip6Array_Alloc(), caller must free with Ip6Array_Free()
Arguments:
pIpArray1 -- IP array
pIpArray2 -- 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.
--*/
{
DWORD j;
PIP6_ARRAY punionArray = NULL;
//
// create result IP arrays
//
if ( !ppUnion )
{
return( ERROR_INVALID_PARAMETER );
}
punionArray = Ip6Array_Create( pIpArray1->AddrCount +
pIpArray2->AddrCount );
if ( !punionArray )
{
goto NoMem;
}
*ppUnion = punionArray;
//
// create union from arrays
//
for ( j = 0; j < pIpArray1->AddrCount; j++ )
{
Ip6Array_AddIp(
punionArray,
& pIpArray1->AddrArray[j],
TRUE // screen out dups
);
}
for ( j = 0; j < pIpArray2->AddrCount; j++ )
{
Ip6Array_AddIp(
punionArray,
& pIpArray2->AddrArray[j],
TRUE // screen out dups
);
}
return( ERROR_SUCCESS );
NoMem:
if ( punionArray )
{
FREE_HEAP( punionArray );
*ppUnion = NULL;
}
return( DNS_ERROR_NO_MEMORY );
}
#if 0
DNS_STATUS
Ip6Array_CreateIpArrayFromMultiIpString(
IN PSTR pszMultiIpString,
OUT PIP6_ARRAY* ppIpArray
)
/*++
Routine Description:
Create IP array out of multi-IP string.
Arguments:
pszMultiIpString -- string containing IP addresses;
separator is whitespace or comma
ppIpArray -- addr to receive ptr to allocated IP array
Return Value:
ERROR_SUCCESS if one or more valid IP addresses in string.
DNS_ERROR_INVALID_IP6_ADDRESS if parsing error.
DNS_ERROR_NO_MEMORY if can not create IP array.
--*/
{
PCHAR pch;
CHAR ch;
PCHAR pbuf;
PCHAR pbufStop;
DNS_STATUS status = ERROR_SUCCESS;
DWORD countIp = 0;
IP6_ADDRESS ip;
CHAR buffer[ IP6_ADDRESS_STRING_LENGTH+2 ];
IP6_ADDRESS arrayIp[ MAX_PARSE_IP ];
// stop byte for IP string buffer
// - note we put extra byte pad in buffer above
// this allows us to write ON stop byte and use
// that to detect invalid-long IP string
//
pbufStop = buffer + IP6_ADDRESS_STRING_LENGTH;
//
// DCR: use IP array builder for local IP address
// then need Ip6Array_CreateIpArrayFromMultiIpString()
// to use count\alloc method when buffer overflows
// to do this we'd need to do parsing in loop
// and skip conversion when count overflow, but set
// flag to go back in again with allocated buffer
//
// safer would be to tokenize-count, alloc, build from tokens
//
//
// loop until reach end of string
//
pch = pszMultiIpString;
while ( countIp < MAX_PARSE_IP )
{
// skip whitespace
while ( ch = *pch++ )
{
if ( ch == ' ' || ch == '\t' || ch == ',' )
{
continue;
}
break;
}
if ( !ch )
{
break;
}
//
// copy next IP string into buffer
// - stop copy at whitespace or NULL
// - on invalid-long IP string, stop copying
// but continue parsing, so can still get any following IPs
// note, we actually write ON the buffer stop byte as our
// "invalid-long" detection mechanism
//
pbuf = buffer;
do
{
if ( pbuf <= pbufStop )
{
*pbuf++ = ch;
}
ch = *pch++;
}
while ( ch && ch != ' ' && ch != ',' && ch != '\t' );
//
// convert buffer into IP address
// - insure was valid length string
// - null terminate
//
if ( pbuf <= pbufStop )
{
*pbuf = 0;
ip = inet_addr( buffer );
if ( ip == INADDR_BROADCAST )
{
status = DNS_ERROR_INVALID_IP6_ADDRESS ;
}
else
{
arrayIp[ countIp++ ] = ip;
}
}
else
{
status = DNS_ERROR_INVALID_IP6_ADDRESS ;
}
// quit if at end of string
if ( !ch )
{
break;
}
}
//
// if successfully parsed IP addresses, create IP array
// note, we'll return what we have even if some addresses are
// bogus, status code will indicate the parsing problem
//
// note, if explicitly passed empty string, then create
// empty IP array, don't error
//
if ( countIp == 0 && *pszMultiIpString != 0 )
{
*ppIpArray = NULL;
status = DNS_ERROR_INVALID_IP6_ADDRESS ;
}
else
{
*ppIpArray = Ip6Array_CreateFromFlatArray(
countIp,
arrayIp );
if ( !*ppIpArray )
{
status = DNS_ERROR_NO_MEMORY;
}
IF_DNSDBG( IPARRAY )
{
DnsDbg_IpArray(
"New Parsed IP array",
NULL, // no name
*ppIpArray );
}
}
return( status );
}
LPSTR
Ip6Array_CreateMultiIpStringFrom(
IN PIP6_ARRAY pIpArray,
IN CHAR chSeparator OPTIONAL
)
/*++
Routine Description:
Create IP array out of multi-IP string.
Arguments:
pIpArray -- IP array to generate string for
chSeparator -- separating character between strings;
OPTIONAL, if not given, blank is used
Return Value:
Ptr to string representation of IP array.
Caller must free.
--*/
{
PCHAR pch;
DWORD i;
PCHAR pszip;
DWORD length;
PCHAR pchstop;
CHAR buffer[ IP6_ADDRESS _STRING_LENGTH*MAX_PARSE_IP + 1 ];
//
// if no IP array, return NULL string
// this allows this function to simply indicate when registry
// delete rather than write is indicated
//
if ( !pIpArray )
{
return( NULL );
}
// if no separator, use blank
if ( !chSeparator )
{
chSeparator = ' ';
}
//
// loop through all IPs in array, appending each
//
pch = buffer;
pchstop = pch + ( IP6_ADDRESS _STRING_LENGTH * (MAX_PARSE_IP-1) );
*pch = 0;
for ( i=0; i < pIpArray->AddrCount; i++ )
{
if ( pch >= pchstop )
{
break;
}
pszip = IP4_STRING( pIpArray->AddrArray[i] );
if ( pszip )
{
length = strlen( pszip );
memcpy(
pch,
pszip,
length );
pch += length;
*pch++ = chSeparator;
}
}
// if wrote any strings, then write terminator over last separator
if ( pch != buffer )
{
*--pch = 0;
}
// create copy of buffer as return
length = (DWORD)(pch - buffer) + 1;
pch = ALLOCATE_HEAP( length );
if ( !pch )
{
return( NULL );
}
memcpy(
pch,
buffer,
length );
DNSDBG( IPARRAY, (
"String representation %s of IP array at %p\n",
pch,
pIpArray ));
return( pch );
}
#endif
VOID
Ip6Array_InitSingleWithIp(
IN OUT PIP6_ARRAY pArray,
IN PIP6_ADDRESS pIp
)
/*++
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 Ip6Array_AddIp()
and creates single IP array.
Arguments:
pArray -- IP6 array, at least of length 1
pIp -- ptr to IP6 address
Return Value:
None
--*/
{
pArray->AddrCount = 1;
pArray->MaxCount = 1;
IP6_ADDR_COPY(
&pArray->AddrArray[0],
pIp );
}
VOID
Ip6Array_InitSingleWithIp4(
IN OUT PIP6_ARRAY pArray,
IN IP4_ADDRESS Ip4Addr
)
/*++
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 Ip6Array_AddIp()
and creates single IP array.
Arguments:
pArray -- IP6 array, at least of length 1
Ip4Addr -- IP4 address
Return Value:
None
--*/
{
pArray->AddrCount = 1;
pArray->MaxCount = 1;
IP6_SET_ADDR_V4MAPPED(
&pArray->AddrArray[0],
Ip4Addr );
}
DWORD
Ip6Array_InitSingleWithSockaddr(
IN OUT PIP6_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 Ip6Array_AddIp()
and creates single IP array.
Arguments:
pArray -- IP6 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 Ip6_CopyFromSockaddr(
&pArray->AddrArray[0],
pSockAddr,
0 );
}
PIP4_ARRAY
Ip4Array_CreateFromIp6Array(
IN PIP6_ARRAY pIp6Array,
OUT PDWORD pCount6
)
/*++
Routine Description:
Create IP4 array from IP6 array.
Arguments:
pIp6Array -- IP6 array
pCount6 -- addr to receive count of IP6 addresses dropped
Return Value:
Ptr to uninitialized IP address array, if successful
NULL on failure.
--*/
{
PIP4_ARRAY parray = NULL;
DWORD i;
DWORD count6 = 0;
DNSDBG( IPARRAY, (
"Ip4Array_CreateFromIp6Array( %p, %p )\n",
pIp6Array,
pCount6 ));
if ( ! pIp6Array )
{
goto Done;
}
//
// allocate the array
//
parray = Dns_CreateIpArray( pIp6Array->AddrCount );
if ( !parray )
{
goto Done;
}
//
// fill the array
//
for ( i=0; i<pIp6Array->AddrCount; i++ )
{
IP4_ADDRESS ip4;
ip4 = IP6_GET_V4_ADDR_IF_MAPPED( &pIp6Array->AddrArray[i] );
if ( ip4 != BAD_IP4_ADDR )
{
Dns_AddIpToIpArray(
parray,
ip4 );
}
else
{
count6++;
}
}
Done:
// set dropped IP6 count
if ( pCount6 )
{
*pCount6 = count6;
}
DNSDBG( IPARRAY, (
"Leave Ip4Array_CreateFromIp6Array()\n"
"\tnew array (count %d) at %p\n"
"\tdropped IP6 count %d\n",
parray ? parray->AddrCount : 0,
parray,
count6 ));
return( parray );
}
//
// End ip6.c
//