/*++ Copyright (c) 2001-2001 Microsoft Corporation Module Name: iphelp.c Abstract: IP help API routines. Author: Jim Gilroy (jamesg) January 2001 Revision History: --*/ #include "local.h" BOOL IpHelp_Initialize( VOID ) /*++ Routine Description: Startup IP Help API Arguments: None Return Value: TRUE if started successfully. FALSE on error. --*/ { return TRUE; } VOID IpHelp_Cleanup( VOID ) /*++ Routine Description: Cleanup IP Help API Arguments: None Return Value: None --*/ { } DNS_STATUS IpHelp_GetAdaptersInfo( OUT PIP_ADAPTER_INFO * ppAdapterInfo ) /*++ Routine Description: Call IP Help GetAdaptersInfo() Arguments: ppAdapterInfo -- addr to receive pointer to adapter info retrieved Return Value: None --*/ { DNS_STATUS status = NO_ERROR; DWORD bufferSize; INT fretry; PIP_ADAPTER_INFO pbuf; DNSDBG( TRACE, ( "GetAdaptersInfo( %p )\n", ppAdapterInfo )); // // init IP Help (no-op) if already done // *ppAdapterInfo = NULL; // // call down to get buffer size // // start with reasonable alloc, then bump up if too small // fretry = 0; bufferSize = 1000; while ( fretry < 2 ) { pbuf = (PIP_ADAPTER_INFO) ALLOCATE_HEAP( bufferSize ); if ( !pbuf ) { status = DNS_ERROR_NO_MEMORY; goto Unlock; } status = (DNS_STATUS) GetAdaptersInfo( pbuf, &bufferSize ); if ( status == NO_ERROR ) { break; } FREE_HEAP( pbuf ); pbuf = NULL; // if buf too small on first try, // continue to retry with suggested buffer size if ( status == ERROR_BUFFER_OVERFLOW || status == ERROR_INSUFFICIENT_BUFFER ) { fretry++; continue; } // any other error is terminal DNSDBG( ANY, ( "ERROR: GetAdapterInfo() failed with error %d\n", status )); status = DNS_ERROR_NO_DNS_SERVERS; break; } DNS_ASSERT( !pbuf || status==NO_ERROR ); if ( status == NO_ERROR ) { *ppAdapterInfo = pbuf; } Unlock: DNSDBG( TRACE, ( "Leave GetAdaptersInfo() => %d\n", status )); return status; } DNS_STATUS IpHelp_GetPerAdapterInfo( IN DWORD AdapterIndex, OUT PIP_PER_ADAPTER_INFO * ppPerAdapterInfo ) /*++ Routine Description: Call IP Help GetPerAdapterInfo() Arguments: AdapterIndex -- index of adapter to get info for ppPerAdapterInfo -- addr to receive pointer to per adapter info Return Value: None --*/ { DNS_STATUS status = NO_ERROR; DWORD bufferSize; INT fretry; PIP_PER_ADAPTER_INFO pbuf; DNSDBG( TRACE, ( "GetPerAdapterInfo( %d, %p )\n", AdapterIndex, ppPerAdapterInfo )); // // init IP Help (no-op) if already done // *ppPerAdapterInfo = NULL; // // call down to get buffer size // // start with reasonable alloc, then bump up if too small // fretry = 0; bufferSize = 1000; while ( fretry < 2 ) { pbuf = (PIP_PER_ADAPTER_INFO) ALLOCATE_HEAP( bufferSize ); if ( !pbuf ) { status = DNS_ERROR_NO_MEMORY; goto Unlock; } status = (DNS_STATUS) GetPerAdapterInfo( AdapterIndex, pbuf, &bufferSize ); if ( status == NO_ERROR ) { break; } FREE_HEAP( pbuf ); pbuf = NULL; // if buf too small on first try, // continue to retry with suggested buffer size if ( status == ERROR_BUFFER_OVERFLOW || status == ERROR_INSUFFICIENT_BUFFER ) { fretry++; continue; } // any other error is terminal DNSDBG( ANY, ( "ERROR: GetAdapterInfo() failed with error %d\n", status )); status = DNS_ERROR_NO_DNS_SERVERS; break; } DNS_ASSERT( !pbuf || status==NO_ERROR ); if ( status == NO_ERROR ) { *ppPerAdapterInfo = pbuf; } Unlock: DNSDBG( TRACE, ( "Leave GetPerAdapterInfo() => %d\n", status )); return status; } DNS_STATUS IpHelp_GetBestInterface( IN IP4_ADDRESS Ip4Addr, OUT PDWORD pdwInterfaceIndex ) /*++ Routine Description: Call IP Help GetBestInterface() Arguments: Ip4Addr -- IP address to check pdwInterfaceIndex -- addr to recv interface index Return Value: ERROR_SUCCESS if successful. ErrorCode on failure. --*/ { DNS_STATUS status; DNSDBG( TRACE, ( "GetBestInterface( %08x, %p )\n", Ip4Addr, pdwInterfaceIndex )); // // init IP Help (no-op) if already done // status = (DNS_STATUS) GetBestInterface( Ip4Addr, pdwInterfaceIndex ); DNSDBG( TRACE, ( "Leave GetBestInterface() => %d\n" "\tip = %s\n" "\tinterface = %d\n", status, IP4_STRING( Ip4Addr ), *pdwInterfaceIndex )); return status; } DNS_STATUS IpHelp_ParseIpAddressString( IN OUT PIP4_ARRAY pIpArray, IN PIP_ADDR_STRING pIpAddrString, IN BOOL fGetSubnetMask, IN BOOL fReverse ) /*++ Routine Description: Build IP array from IP help IP_ADDR_STRING structure. Arguments: pIpArray -- IP array of DNS servers pIpAddrString -- pointer to address info with address data fGetSubnetMask -- get subnet masks fReverse -- reverse the IP array Return Value: ERROR_SUCCESS if successful. DNS_ERROR_NO_DNS_SERVERS if nothing parsed. --*/ { PIP_ADDR_STRING pipBlob = pIpAddrString; IP4_ADDRESS ip; DWORD countServers = pIpArray->AddrCount; DNSDBG( TRACE, ( "IpHelp_ParseIpAddressString()\n" "\tout IP array = %p\n" "\tIP string = %p\n" "\tsubnet? = %d\n" "\treverse? = %d\n", pIpArray, pIpAddrString, fGetSubnetMask, fReverse )); // // loop reading IP or subnet // // DCR_FIX0: address and subnet will be misaligned if read separately // // DCR: move to count\allocate model and if getting subnets get together // while ( pipBlob && countServers < DNS_MAX_IP_INTERFACE_COUNT ) { if ( fGetSubnetMask ) { ip = inet_addr( pipBlob->IpMask.String ); if ( ip != INADDR_ANY ) { pIpArray->AddrArray[ countServers ] = ip; countServers++; } } else { ip = inet_addr( pipBlob->IpAddress.String ); if ( ip != INADDR_ANY && ip != INADDR_NONE ) { pIpArray->AddrArray[ countServers ] = ip; countServers++; } } pipBlob = pipBlob->Next; } // reset IP count pIpArray->AddrCount = countServers; // reverse array if desired if ( fReverse ) { Dns_ReverseOrderOfIpArray( pIpArray ); } DNSDBG( NETINFO, ( "Leave IpHelp_ParseIpAddressString()\n" "\tcount = %d\n" "\tfirst IP = %s\n", countServers, countServers ? IP_STRING( pIpArray->AddrArray[0] ) : "" )); return ( pIpArray->AddrCount ) ? ERROR_SUCCESS : DNS_ERROR_NO_DNS_SERVERS; } PIP_ADAPTER_ADDRESSES IpHelp_GetAdaptersAddresses( IN ULONG Family, IN DWORD Flags ) /*++ Routine Description: Call IP Help GetAdaptersAddresses Arguments: Family -- address family Flags -- flags Return Value: None --*/ { DNS_STATUS status = NO_ERROR; INT retry; PIP_ADAPTER_ADDRESSES pbuf = NULL; DWORD bufSize = 0x1000; // start with 4K HMODULE hlib = NULL; FARPROC proc; DNSDBG( TRACE, ( "GetAdaptersAddresses()\n" "\tFamily = %d\n" "\tFlags = %08x\n", Family, Flags )); // // init IP Help (no-op) if already done // hlib = LoadLibrary( L"iphlpapi.dll" ); if ( !hlib ) { goto Failed; } proc = GetProcAddress( hlib, "GetAdaptersAddresses" ); if ( !proc ) { goto Failed; } // // call down in loop to allow one buffer resizing // retry = 0; while ( 1 ) { // allocate a buffer to hold results if ( pbuf ) { FREE_HEAP( pbuf ); } pbuf = ALLOCATE_HEAP( bufSize ); if ( !pbuf ) { goto Failed; } // call down status = (DNS_STATUS) (*proc)( Family, Flags, NULL, // no reserved, pbuf, & bufSize ); if ( status == NO_ERROR ) { break; } else if ( status != ERROR_BUFFER_OVERFLOW ) { goto Failed; } DNSDBG( NETINFO, ( "Retrying GetAdaptersAddresses() with buffer length %d\n", bufSize )); if ( retry != 0 ) { DNS_ASSERT( FALSE ); goto Failed; } continue; } // success DNSDBG( TRACE, ( "Leave GetAdaptersAddresses() = %p\n", pbuf )); IF_DNSDBG( NETINFO ) { DnsDbg_IpAdapterList( "IP Help Adapter List", pbuf, TRUE, // print addrs TRUE // print list ); } return pbuf; Failed: FREE_HEAP( pbuf ); if ( status == NO_ERROR ) { status = GetLastError(); } DNSDBG( ANY, ( "Failed GetAdaptersAddresses() => %d\n", status )); SetLastError( status ); return( NULL ); } DNS_STATUS IpHelp_ReadAddrsFromList( IN PVOID pAddrList, IN BOOL fUnicast, IN DWORD ScreenMask, OPTIONAL IN DWORD ScreenFlags, OPTIONAL OUT PDNS_ADDR_ARRAY * ppComboArray, OPTIONAL OUT PDNS_ADDR_ARRAY * pp6OnlyArray, OPTIONAL OUT PDNS_ADDR_ARRAY * pp4OnlyArray, OPTIONAL OUT PDWORD pCount6, OPTIONAL OUT PDWORD pCount4 OPTIONAL ) /*++ Routine Description: Read IP addres from IP help IP_ADAPTER_XXX_ADDRESS list. Arguments: pAddrList -- any IP address list PIP_ADAPTER_UNICAST_ADDRESS PIP_ADAPTER_ANYCAST_ADDRESS PIP_ADAPTER_MULTICAST_ADDRESS PIP_ADAPTER_DNS_SERVER_ADDRESS fUnicast -- this is unicast address list ScreenMask -- mask of address flags we care about example: IP_ADAPTER_ADDRESS_DNS_ELIGIBLE | IP_ADAPTER_ADDRESS_TRANSIENT ScreenFlags -- required state of flags within mask example: IP_ADAPTER_ADDRESS_DNS_ELIGIBLE this (with above mask) would screen for eligible non-cluster addresses Return Value: NO_ERROR if successful. ErrorCode on failure. --*/ { PIP_ADAPTER_UNICAST_ADDRESS pnextAddr; PIP_ADAPTER_UNICAST_ADDRESS paddr; DNS_STATUS status = NO_ERROR; DWORD count4 = 0; DWORD count6 = 0; DWORD countAll = 0; PADDR_ARRAY parrayCombo = NULL; PADDR_ARRAY parray6 = NULL; PADDR_ARRAY parray4 = NULL; DNS_ADDR dnsAddr; DNSDBG( TRACE, ( "IpHelp_ReadAddrsFromList( %p )\n", pAddrList )); // // count // pnextAddr = (PIP_ADAPTER_UNICAST_ADDRESS) pAddrList; while ( paddr = pnextAddr ) { PSOCKADDR psa; pnextAddr = paddr->Next; if ( ScreenMask && (ScreenMask & paddr->Flags) != ScreenFlags ) { continue; } // screen off expired, invalid, bogus if ( fUnicast && paddr->DadState != IpDadStatePreferred ) { continue; } psa = paddr->Address.lpSockaddr; if ( !psa ) { DNS_ASSERT( FALSE ); continue; } #if 0 // DCR: temphack -- screen link-local if ( SOCKADDR_IS_IP6(psa) ) { if ( IP6_IS_ADDR_LINKLOCAL( (PIP6_ADDRESS)&((PSOCKADDR_IN6)psa)->sin6_addr ) ) { continue; } } #endif if ( fUnicast && SOCKADDR_IS_LOOPBACK(psa) ) { continue; } else if ( SOCKADDR_IS_IP6(psa) ) { count6++; countAll++; } else if ( SOCKADDR_IS_IP4(psa) ) { count4++; countAll++; } ELSE_ASSERT_FALSE; } // // alloc arrays // status = DNS_ERROR_NO_MEMORY; if ( ppComboArray ) { if ( countAll ) { parrayCombo = DnsAddrArray_Create( countAll ); } *ppComboArray = parrayCombo; if ( !parrayCombo && (countAll) ) { goto Failed; } } if ( pp6OnlyArray ) { if ( count6 ) { parray6 = DnsAddrArray_Create( count6 ); } *pp6OnlyArray = parray6; if ( !parray6 && count6 ) { goto Failed; } } if ( pp4OnlyArray ) { if ( count4 ) { parray4 = DnsAddrArray_Create( count4 ); } *pp4OnlyArray = parray4; if ( !parray4 && count4 ) { goto Failed; } } // // read addrs into array // pnextAddr = (PIP_ADAPTER_UNICAST_ADDRESS) pAddrList; while ( paddr = pnextAddr ) { PSOCKADDR psa; DWORD flags = 0; DWORD subnetLen = 0; pnextAddr = paddr->Next; if ( ScreenMask && (ScreenMask & paddr->Flags) != ScreenFlags ) { continue; } // screen off expired, invalid, bogus if ( fUnicast && paddr->DadState != IpDadStatePreferred ) { continue; } psa = paddr->Address.lpSockaddr; if ( !psa ) { DNS_ASSERT( FALSE ); continue; } #if 0 // DCR: temphack -- screen link local if ( SOCKADDR_IS_IP6(psa) && IP6_IS_ADDR_LINKLOCAL( (PIP6_ADDRESS)&((PSOCKADDR_IN6)psa)->sin6_addr ) ) { continue; } #endif // screen off loopback if ( fUnicast && SOCKADDR_IS_LOOPBACK(psa) ) { continue; } // // build DNS_ADDR // // DCR: FIX6: fix subnet length once DaveThaler is in // if ( fUnicast ) { flags = paddr->Flags; subnetLen = 0; #if 0 // TEST HACK: make transients if ( g_DnsTestMode ) { flags |= IP_ADAPTER_ADDRESS_TRANSIENT; } #endif } if ( !DnsAddr_Build( & dnsAddr, psa, 0, // any family subnetLen, flags ) ) { DNS_ASSERT( FALSE ); continue; } // // AddrArray_AddSockaddrEx() with flag to choose types to add // // DCR: not sure we want local IP6 array as DNS_ADDR -- // maybe just plain IP6 // if ( parrayCombo ) { DnsAddrArray_AddAddr( parrayCombo, & dnsAddr, 0, // any family 0 // no dup screen ); } if ( parray6 ) { DnsAddrArray_AddAddr( parray6, & dnsAddr, AF_INET6, // any family 0 // no dup screen ); } if ( parray4 ) { DnsAddrArray_AddAddr( parray4, & dnsAddr, AF_INET, // any family 0 // no dup screen ); } } // // set counts // if ( pCount6 ) { *pCount6 = count6; } if ( pCount4 ) { *pCount4 = count4; } return NO_ERROR; Failed: // // cleanup any partial allocs // DnsAddrArray_Free( parrayCombo ); DnsAddrArray_Free( parray6 ); Dns_Free( parray4 ); DNS_ASSERT( status != NO_ERROR ); return status; } // // End iphelp.c //