550 lines
13 KiB
C++
550 lines
13 KiB
C++
|
/*++
|
|||
|
|
|||
|
Copyright (C) Microsoft Corporation, 1997 - 1999
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
ipname.cxx
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
Miscellaneous helper routines to resolve names to IP Addresses.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Gopal Parupudi <GopalP>
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
a. Class IP_ADDRESS_RESOLVER cloned from RPC Runtime Transport sources
|
|||
|
(rpc\runtime\trans\winnt\common\wstrans.cxx).
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
GopalP 10/13/1997 Start.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
#include <precomp.hxx>
|
|||
|
|
|||
|
|
|||
|
#define BACKSLASH ((SENS_CHAR) '\\')
|
|||
|
#define HTTP_PREFIX1 (SENS_STRING("http://"))
|
|||
|
#define HTTP_PREFIX2 (SENS_STRING("http:\\\\"))
|
|||
|
#define HTTP_PREFIX_LEN 7
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
GetNetBIOSName(
|
|||
|
IN TCHAR *ActualName,
|
|||
|
IN OUT TCHAR *SanitizedName
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Sanitize the name of the destination to make it more suitable for
|
|||
|
name resolution.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ActualName - Original Name of the destination.
|
|||
|
|
|||
|
SanitizedName - On return, this contains the sanitized version of the
|
|||
|
Actual Name. Memory is allocated by the caller.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE, if successful.
|
|||
|
|
|||
|
FALSE, if the address if the address in invalid.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
TCHAR *pchTemp;
|
|||
|
|
|||
|
//
|
|||
|
// Remove the leading \\ characters, if present.
|
|||
|
//
|
|||
|
pchTemp = ActualName;
|
|||
|
if (*pchTemp == BACKSLASH)
|
|||
|
{
|
|||
|
// Check for another slash
|
|||
|
if (*++pchTemp == BACKSLASH)
|
|||
|
{
|
|||
|
if (NULL != _tcschr(++pchTemp, BACKSLASH))
|
|||
|
{
|
|||
|
// Found yet another slash!
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
_tcscpy(SanitizedName, pchTemp);
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Remove the "http://" prefix, if present.
|
|||
|
//
|
|||
|
pchTemp = ActualName;
|
|||
|
if ( (_tcsnicmp(HTTP_PREFIX1, ActualName, HTTP_PREFIX_LEN) == 0)
|
|||
|
|| (_tcsnicmp(HTTP_PREFIX2, ActualName, HTTP_PREFIX_LEN) == 0))
|
|||
|
{
|
|||
|
_tcscpy(SanitizedName, (pchTemp + HTTP_PREFIX_LEN));
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
_tcscpy(SanitizedName, pchTemp);
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
ResolveName(
|
|||
|
IN TCHAR *lpszDestination,
|
|||
|
OUT LPDWORD lpdwIpAddr
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Resolve the destination name to its IP Address.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
lpszDestination - Name of the destination of interest.
|
|||
|
|
|||
|
lpdwIpAddr - On success, this contains the IP Address of the destination.
|
|||
|
|
|||
|
Note:
|
|||
|
|
|||
|
Since this function depends on Winsock2 being loaded, there are 2 different
|
|||
|
implementations - one for Win9x and one for NT.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
ERROR_SUCCESS, if successful
|
|||
|
|
|||
|
Error code from GetLastError(), otherwise
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS status;
|
|||
|
TCHAR *lpszSanitizedName;
|
|||
|
DWORD dwReturnCode;
|
|||
|
DWORD bufsize;
|
|||
|
PVOID buf;
|
|||
|
BOOL bSuccess;
|
|||
|
|
|||
|
if ( (lpdwIpAddr == NULL)
|
|||
|
|| (lpszDestination == NULL))
|
|||
|
{
|
|||
|
return ERROR_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
*lpdwIpAddr = 0x0;
|
|||
|
lpszSanitizedName = NULL;
|
|||
|
dwReturnCode = ERROR_HOST_UNREACHABLE;
|
|||
|
bSuccess = FALSE;
|
|||
|
|
|||
|
lpszSanitizedName = (TCHAR*) new char[(sizeof(TCHAR) * (_tcslen(lpszDestination)+1))];
|
|||
|
if (!lpszSanitizedName)
|
|||
|
{
|
|||
|
return (ERROR_OUTOFMEMORY);
|
|||
|
}
|
|||
|
|
|||
|
bSuccess = GetNetBIOSName(lpszDestination, lpszSanitizedName);
|
|||
|
if (bSuccess == FALSE)
|
|||
|
{
|
|||
|
SensPrint(SENS_INFO, (SENS_STRING("Bad format for destination name - %s\n"), lpszDestination));
|
|||
|
delete lpszSanitizedName;
|
|||
|
return (ERROR_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
|
|||
|
SensPrint(SENS_INFO, (SENS_STRING("Actual Name - [%s]\n"), lpszDestination));
|
|||
|
SensPrint(SENS_INFO, (SENS_STRING("Sanitized Name - [%s]\n"), lpszSanitizedName));
|
|||
|
|
|||
|
#if !defined(SENS_CHICAGO)
|
|||
|
|
|||
|
bufsize = sizeof(WSAQUERYSET) + IP_BUFFER_SIZE;
|
|||
|
buf = (PVOID) new char[bufsize];
|
|||
|
if (NULL == buf)
|
|||
|
{
|
|||
|
delete lpszSanitizedName;
|
|||
|
return (ERROR_OUTOFMEMORY);
|
|||
|
}
|
|||
|
|
|||
|
IP_ADDRESS_RESOLVER resolver(lpszSanitizedName, bufsize, buf);
|
|||
|
|
|||
|
status = resolver.NextAddress(lpdwIpAddr);
|
|||
|
|
|||
|
switch (status)
|
|||
|
{
|
|||
|
case RPC_S_OK:
|
|||
|
dwReturnCode = ERROR_SUCCESS;
|
|||
|
break;
|
|||
|
|
|||
|
case RPC_S_OUT_OF_MEMORY:
|
|||
|
dwReturnCode = ERROR_OUTOFMEMORY;
|
|||
|
break;
|
|||
|
|
|||
|
case RPC_S_SERVER_UNAVAILABLE:
|
|||
|
default:
|
|||
|
//
|
|||
|
// Should we return HOST_NOT_FOUND in some cases depending
|
|||
|
// upon the WSAGetLastError() value? Maybe. But, the error
|
|||
|
// ERROR_HOST_UNREACHABLE is pretty close enough.
|
|||
|
//
|
|||
|
dwReturnCode = ERROR_HOST_UNREACHABLE;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Cleanup
|
|||
|
//
|
|||
|
if (NULL != lpszSanitizedName)
|
|||
|
{
|
|||
|
delete lpszSanitizedName;
|
|||
|
}
|
|||
|
if (NULL != buf)
|
|||
|
{
|
|||
|
delete buf;
|
|||
|
}
|
|||
|
|
|||
|
#else // SENS_CHICAGO
|
|||
|
|
|||
|
struct hostent *phostentry;
|
|||
|
unsigned long host_addr;
|
|||
|
|
|||
|
phostentry = NULL;
|
|||
|
host_addr = 0x0;
|
|||
|
|
|||
|
if (*lpszDestination == '\0')
|
|||
|
{
|
|||
|
//
|
|||
|
// An empty hostname means the local machine
|
|||
|
//
|
|||
|
host_addr = htonl(INADDR_LOOPBACK);
|
|||
|
dwReturnCode = ERROR_SUCCESS;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// First, assume a numeric address
|
|||
|
//
|
|||
|
host_addr = inet_addr(lpszDestination);
|
|||
|
if (host_addr == INADDR_NONE)
|
|||
|
{
|
|||
|
//
|
|||
|
// Not a numeric address. Try a friendly name
|
|||
|
//
|
|||
|
phostentry = gethostbyname(lpszDestination);
|
|||
|
|
|||
|
if (phostentry == (struct hostent *)NULL)
|
|||
|
{
|
|||
|
dwReturnCode = ERROR_HOST_UNREACHABLE;
|
|||
|
SensPrintA(SENS_INFO, ("gethostbyname(%s) failed with a "
|
|||
|
"WSAGetLastError() of %d!\n", lpszDestination,
|
|||
|
WSAGetLastError()));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
host_addr = *(unsigned long *)phostentry->h_addr;
|
|||
|
dwReturnCode = ERROR_SUCCESS;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// Destination is an IP address.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// NOTE:
|
|||
|
//
|
|||
|
// a. gethostbyaddr() sometimes fails to resolve valid IP
|
|||
|
// addresses. WSAGetLastError() returns WSANO_DATA. This
|
|||
|
// is a problem with Win9x name resolution.
|
|||
|
// b. gethostbyaddr() is visibly slow on Win9x platforms. In
|
|||
|
// SENS's case, is better to avoid this call.
|
|||
|
// c. We will just go ahead and use the host_addr returned
|
|||
|
// from inet_addr() and try to do a programmatic ping.
|
|||
|
//
|
|||
|
|
|||
|
dwReturnCode = ERROR_SUCCESS;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
*lpdwIpAddr = host_addr;
|
|||
|
|
|||
|
SensPrintA(SENS_INFO, ("Resolved IP Address - [0x%x], dwReturnCode - %d\n",
|
|||
|
*lpdwIpAddr, dwReturnCode));
|
|||
|
|
|||
|
#endif // SENS_CHICAGO
|
|||
|
|
|||
|
return (dwReturnCode);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#if !defined(SENS_CHICAGO)
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
IP_ADDRESS_RESOLVER::NextAddress(
|
|||
|
OUT LPDWORD lpdwIpAddr
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Returns the next IP address associated with the Name
|
|||
|
parameter to the constructor.
|
|||
|
|
|||
|
During the first call if check for loopback and for dotted numeric IP
|
|||
|
address formats. If these fail then it begins a complex lookup
|
|||
|
(WSALookupServiceBegin) and returns the first available address.
|
|||
|
|
|||
|
During successive calls in which a complex lookup was started
|
|||
|
it returns sucessive addressed returned by WSALookupServiceNext().
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
lpdwIpAddr - If successful, the member is set to an IP address.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - lpdwIpAddr points to a new IP address
|
|||
|
|
|||
|
RPC_S_SERVER_UNAVAILABLE - Unable to find any more addresses
|
|||
|
|
|||
|
RPC_S_OUT_OF_MEMORY - otherwise
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
int err;
|
|||
|
RPC_STATUS status;
|
|||
|
|
|||
|
*lpdwIpAddr = 0x0;
|
|||
|
|
|||
|
// If this is the first call, _Name will be non-NULL and
|
|||
|
// we need to start the lookup process.
|
|||
|
|
|||
|
if (_Name)
|
|||
|
{
|
|||
|
TCHAR *Name = _Name;
|
|||
|
_Name = 0;
|
|||
|
|
|||
|
// Check for loopback first.
|
|||
|
if (! *Name)
|
|||
|
{
|
|||
|
// Loopback - assign result of htonl(INADDR_LOOPBACK)
|
|||
|
// Little-endian dependence.
|
|||
|
*lpdwIpAddr = 0x0100007F;
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
// Assume dot address since this is faster to check.
|
|||
|
int size = sizeof(SOCKADDR_IN);
|
|||
|
SOCKADDR_IN addr;
|
|||
|
err = WSAStringToAddress(Name,
|
|||
|
AF_INET,
|
|||
|
0,
|
|||
|
(PSOCKADDR)&addr,
|
|||
|
&size);
|
|||
|
|
|||
|
if (err != SOCKET_ERROR)
|
|||
|
{
|
|||
|
*lpdwIpAddr = addr.sin_addr.s_addr;
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
ASSERT(GetLastError() == WSAEINVAL);
|
|||
|
|
|||
|
// Start a complex query operation
|
|||
|
|
|||
|
const static AFPROTOCOLS aIpProtocols[2] =
|
|||
|
{
|
|||
|
{AF_INET, IPPROTO_UDP},
|
|||
|
{AF_INET, IPPROTO_TCP}
|
|||
|
};
|
|||
|
|
|||
|
const static GUID guidHostAddressByName = SVCID_INET_HOSTADDRBYNAME;
|
|||
|
WSAQUERYSET wsqs;
|
|||
|
|
|||
|
memset(&wsqs, 0, sizeof(wsqs));
|
|||
|
wsqs.dwSize = sizeof(WSAQUERYSET);
|
|||
|
// wsqs.dwNameSpace = NS_ALL;
|
|||
|
ASSERT(NS_ALL == 0);
|
|||
|
wsqs.lpszServiceInstanceName = Name;
|
|||
|
wsqs.lpServiceClassId = (GUID *)&guidHostAddressByName;
|
|||
|
wsqs.dwNumberOfProtocols = 2;
|
|||
|
wsqs.lpafpProtocols = (PAFPROTOCOLS)&aIpProtocols[0];
|
|||
|
|
|||
|
err = WSALookupServiceBegin(&wsqs,
|
|||
|
LUP_RETURN_ADDR,
|
|||
|
&_hRnr);
|
|||
|
|
|||
|
if (err == SOCKET_ERROR)
|
|||
|
{
|
|||
|
SensPrintA(SENS_INFO, ("WSALookupServiceBegin() failed: %d\n", GetLastError()));
|
|||
|
return(RPC_S_SERVER_UNAVAILABLE);
|
|||
|
}
|
|||
|
|
|||
|
_index = 0;
|
|||
|
|
|||
|
if (_pwsqs)
|
|||
|
{
|
|||
|
_pwsqs->dwNumberOfCsAddrs = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (!_hRnr)
|
|||
|
{
|
|||
|
// First call finished but didn't start a complex query. Abort now.
|
|||
|
return(RPC_S_SERVER_UNAVAILABLE);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// A complex query has been started.
|
|||
|
|
|||
|
ASSERT(_hRnr);
|
|||
|
|
|||
|
// If the cached query structure is empty, call WSALookupNext to get
|
|||
|
// more addresses.
|
|||
|
|
|||
|
if (!_pwsqs || (_index >= _pwsqs->dwNumberOfCsAddrs))
|
|||
|
{
|
|||
|
|
|||
|
DWORD needed = _size;
|
|||
|
|
|||
|
// Loop needed to realloc a larger _pwsqs buffer.
|
|||
|
|
|||
|
for(;;)
|
|||
|
{
|
|||
|
err = WSALookupServiceNext(_hRnr,
|
|||
|
0, // flags
|
|||
|
&needed,
|
|||
|
_pwsqs);
|
|||
|
|
|||
|
// Success, break out of the loop.
|
|||
|
if (err != SOCKET_ERROR)
|
|||
|
{
|
|||
|
ASSERT(_pwsqs->dwNumberOfCsAddrs > 0);
|
|||
|
ASSERT(_pwsqs->lpcsaBuffer);
|
|||
|
|
|||
|
// Reset to start of new result set.
|
|||
|
_index = 0;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
status = GetLastError();
|
|||
|
|
|||
|
// WSAEFAULT means the buffer was too small.
|
|||
|
|
|||
|
if (status != WSAEFAULT)
|
|||
|
{
|
|||
|
// WSA_E_NO_MORE means all matching address have
|
|||
|
// already been returned.
|
|||
|
|
|||
|
VALIDATE(status)
|
|||
|
{
|
|||
|
WSA_E_NO_MORE,
|
|||
|
WSANO_DATA,
|
|||
|
WSASERVICE_NOT_FOUND,
|
|||
|
WSAHOST_NOT_FOUND,
|
|||
|
WSATRY_AGAIN,
|
|||
|
WSANO_RECOVERY,
|
|||
|
WSANO_DATA,
|
|||
|
WSAEINVAL // In response to out of resources scenarios.
|
|||
|
} END_VALIDATE;
|
|||
|
|
|||
|
SensPrintA(SENS_ERR, ("WSALookupServiceNext() failed: %d\n", status));
|
|||
|
|
|||
|
return(RPC_S_SERVER_UNAVAILABLE);
|
|||
|
}
|
|||
|
|
|||
|
// Allocate a larger buffer.
|
|||
|
|
|||
|
if (needed <= _size)
|
|||
|
{
|
|||
|
ASSERT(needed > _size);
|
|||
|
return(RPC_S_SERVER_UNAVAILABLE);
|
|||
|
}
|
|||
|
|
|||
|
if (_fFree)
|
|||
|
{
|
|||
|
delete _pwsqs;
|
|||
|
}
|
|||
|
|
|||
|
_pwsqs = (PWSAQUERYSET) new char[needed];
|
|||
|
//_pwsqs = new WSAQUERYSETW[(needed - sizeof(WSAQUERYSETW))];
|
|||
|
//_pwsqs = (PWSAQUERYSETW) new char(needed - sizeof(WSAQUERYSETW));
|
|||
|
if (!_pwsqs)
|
|||
|
{
|
|||
|
return(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
_fFree = TRUE;
|
|||
|
_pwsqs->dwNumberOfCsAddrs = 0;
|
|||
|
_size = needed;
|
|||
|
|
|||
|
#if DBG
|
|||
|
// On retail we start with enough space for two addresses during the
|
|||
|
// first call. If this debug print gets hit too much we can increase the
|
|||
|
// starting size (IP_BUFFER_SIZE).
|
|||
|
if (_size > sizeof(WSAQUERYSET) + IP_RETAIL_BUFFER_SIZE)
|
|||
|
{
|
|||
|
SensPrintA(SENS_ERR, ("WSALookupServerNext(): sizeof(WSAQUERYSETW) - %d\n"
|
|||
|
"WSALookupServerNext(): IP_RETAIL_BUFFER_SIZE - %d\n",
|
|||
|
sizeof(WSAQUERYSETW), IP_RETAIL_BUFFER_SIZE));
|
|||
|
SensPrintA(SENS_ERR, ("WSALookupServerNext() wants %d bytes. Make this the "
|
|||
|
"default?\n", _size));
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ASSERT(_pwsqs);
|
|||
|
ASSERT(_index < _pwsqs->dwNumberOfCsAddrs);
|
|||
|
|
|||
|
LPCSADDR_INFO pInfo = &_pwsqs->lpcsaBuffer[_index];
|
|||
|
_index++;
|
|||
|
|
|||
|
*lpdwIpAddr = ((SOCKADDR_IN *)pInfo->RemoteAddr.lpSockaddr)->sin_addr.s_addr;
|
|||
|
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
IP_ADDRESS_RESOLVER::~IP_ADDRESS_RESOLVER()
|
|||
|
{
|
|||
|
if (_hRnr)
|
|||
|
{
|
|||
|
WSALookupServiceEnd(_hRnr);
|
|||
|
}
|
|||
|
|
|||
|
if (_fFree)
|
|||
|
{
|
|||
|
delete _pwsqs;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#endif // SENS_CHICAGO
|