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