Source code of Windows XP (NT5)
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.

549 lines
13 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1997 - 1999
  3. Module Name:
  4. ipname.cxx
  5. Abstract:
  6. Miscellaneous helper routines to resolve names to IP Addresses.
  7. Author:
  8. Gopal Parupudi <GopalP>
  9. Notes:
  10. a. Class IP_ADDRESS_RESOLVER cloned from RPC Runtime Transport sources
  11. (rpc\runtime\trans\winnt\common\wstrans.cxx).
  12. Revision History:
  13. GopalP 10/13/1997 Start.
  14. --*/
  15. #include <precomp.hxx>
  16. #define BACKSLASH ((SENS_CHAR) '\\')
  17. #define HTTP_PREFIX1 (SENS_STRING("http://"))
  18. #define HTTP_PREFIX2 (SENS_STRING("http:\\\\"))
  19. #define HTTP_PREFIX_LEN 7
  20. BOOL
  21. GetNetBIOSName(
  22. IN TCHAR *ActualName,
  23. IN OUT TCHAR *SanitizedName
  24. )
  25. /*++
  26. Routine Description:
  27. Sanitize the name of the destination to make it more suitable for
  28. name resolution.
  29. Arguments:
  30. ActualName - Original Name of the destination.
  31. SanitizedName - On return, this contains the sanitized version of the
  32. Actual Name. Memory is allocated by the caller.
  33. Return Value:
  34. TRUE, if successful.
  35. FALSE, if the address if the address in invalid.
  36. --*/
  37. {
  38. TCHAR *pchTemp;
  39. //
  40. // Remove the leading \\ characters, if present.
  41. //
  42. pchTemp = ActualName;
  43. if (*pchTemp == BACKSLASH)
  44. {
  45. // Check for another slash
  46. if (*++pchTemp == BACKSLASH)
  47. {
  48. if (NULL != _tcschr(++pchTemp, BACKSLASH))
  49. {
  50. // Found yet another slash!
  51. return FALSE;
  52. }
  53. _tcscpy(SanitizedName, pchTemp);
  54. return TRUE;
  55. }
  56. else
  57. {
  58. return FALSE;
  59. }
  60. }
  61. //
  62. // Remove the "http://" prefix, if present.
  63. //
  64. pchTemp = ActualName;
  65. if ( (_tcsnicmp(HTTP_PREFIX1, ActualName, HTTP_PREFIX_LEN) == 0)
  66. || (_tcsnicmp(HTTP_PREFIX2, ActualName, HTTP_PREFIX_LEN) == 0))
  67. {
  68. _tcscpy(SanitizedName, (pchTemp + HTTP_PREFIX_LEN));
  69. return TRUE;
  70. }
  71. _tcscpy(SanitizedName, pchTemp);
  72. return TRUE;
  73. }
  74. DWORD
  75. ResolveName(
  76. IN TCHAR *lpszDestination,
  77. OUT LPDWORD lpdwIpAddr
  78. )
  79. /*++
  80. Routine Description:
  81. Resolve the destination name to its IP Address.
  82. Arguments:
  83. lpszDestination - Name of the destination of interest.
  84. lpdwIpAddr - On success, this contains the IP Address of the destination.
  85. Note:
  86. Since this function depends on Winsock2 being loaded, there are 2 different
  87. implementations - one for Win9x and one for NT.
  88. Return Value:
  89. ERROR_SUCCESS, if successful
  90. Error code from GetLastError(), otherwise
  91. --*/
  92. {
  93. RPC_STATUS status;
  94. TCHAR *lpszSanitizedName;
  95. DWORD dwReturnCode;
  96. DWORD bufsize;
  97. PVOID buf;
  98. BOOL bSuccess;
  99. if ( (lpdwIpAddr == NULL)
  100. || (lpszDestination == NULL))
  101. {
  102. return ERROR_INVALID_PARAMETER;
  103. }
  104. *lpdwIpAddr = 0x0;
  105. lpszSanitizedName = NULL;
  106. dwReturnCode = ERROR_HOST_UNREACHABLE;
  107. bSuccess = FALSE;
  108. lpszSanitizedName = (TCHAR*) new char[(sizeof(TCHAR) * (_tcslen(lpszDestination)+1))];
  109. if (!lpszSanitizedName)
  110. {
  111. return (ERROR_OUTOFMEMORY);
  112. }
  113. bSuccess = GetNetBIOSName(lpszDestination, lpszSanitizedName);
  114. if (bSuccess == FALSE)
  115. {
  116. SensPrint(SENS_INFO, (SENS_STRING("Bad format for destination name - %s\n"), lpszDestination));
  117. delete lpszSanitizedName;
  118. return (ERROR_INVALID_PARAMETER);
  119. }
  120. SensPrint(SENS_INFO, (SENS_STRING("Actual Name - [%s]\n"), lpszDestination));
  121. SensPrint(SENS_INFO, (SENS_STRING("Sanitized Name - [%s]\n"), lpszSanitizedName));
  122. #if !defined(SENS_CHICAGO)
  123. bufsize = sizeof(WSAQUERYSET) + IP_BUFFER_SIZE;
  124. buf = (PVOID) new char[bufsize];
  125. if (NULL == buf)
  126. {
  127. delete lpszSanitizedName;
  128. return (ERROR_OUTOFMEMORY);
  129. }
  130. IP_ADDRESS_RESOLVER resolver(lpszSanitizedName, bufsize, buf);
  131. status = resolver.NextAddress(lpdwIpAddr);
  132. switch (status)
  133. {
  134. case RPC_S_OK:
  135. dwReturnCode = ERROR_SUCCESS;
  136. break;
  137. case RPC_S_OUT_OF_MEMORY:
  138. dwReturnCode = ERROR_OUTOFMEMORY;
  139. break;
  140. case RPC_S_SERVER_UNAVAILABLE:
  141. default:
  142. //
  143. // Should we return HOST_NOT_FOUND in some cases depending
  144. // upon the WSAGetLastError() value? Maybe. But, the error
  145. // ERROR_HOST_UNREACHABLE is pretty close enough.
  146. //
  147. dwReturnCode = ERROR_HOST_UNREACHABLE;
  148. break;
  149. }
  150. //
  151. // Cleanup
  152. //
  153. if (NULL != lpszSanitizedName)
  154. {
  155. delete lpszSanitizedName;
  156. }
  157. if (NULL != buf)
  158. {
  159. delete buf;
  160. }
  161. #else // SENS_CHICAGO
  162. struct hostent *phostentry;
  163. unsigned long host_addr;
  164. phostentry = NULL;
  165. host_addr = 0x0;
  166. if (*lpszDestination == '\0')
  167. {
  168. //
  169. // An empty hostname means the local machine
  170. //
  171. host_addr = htonl(INADDR_LOOPBACK);
  172. dwReturnCode = ERROR_SUCCESS;
  173. }
  174. else
  175. {
  176. //
  177. // First, assume a numeric address
  178. //
  179. host_addr = inet_addr(lpszDestination);
  180. if (host_addr == INADDR_NONE)
  181. {
  182. //
  183. // Not a numeric address. Try a friendly name
  184. //
  185. phostentry = gethostbyname(lpszDestination);
  186. if (phostentry == (struct hostent *)NULL)
  187. {
  188. dwReturnCode = ERROR_HOST_UNREACHABLE;
  189. SensPrintA(SENS_INFO, ("gethostbyname(%s) failed with a "
  190. "WSAGetLastError() of %d!\n", lpszDestination,
  191. WSAGetLastError()));
  192. }
  193. else
  194. {
  195. host_addr = *(unsigned long *)phostentry->h_addr;
  196. dwReturnCode = ERROR_SUCCESS;
  197. }
  198. }
  199. else
  200. {
  201. //
  202. // Destination is an IP address.
  203. //
  204. //
  205. // NOTE:
  206. //
  207. // a. gethostbyaddr() sometimes fails to resolve valid IP
  208. // addresses. WSAGetLastError() returns WSANO_DATA. This
  209. // is a problem with Win9x name resolution.
  210. // b. gethostbyaddr() is visibly slow on Win9x platforms. In
  211. // SENS's case, is better to avoid this call.
  212. // c. We will just go ahead and use the host_addr returned
  213. // from inet_addr() and try to do a programmatic ping.
  214. //
  215. dwReturnCode = ERROR_SUCCESS;
  216. }
  217. }
  218. *lpdwIpAddr = host_addr;
  219. SensPrintA(SENS_INFO, ("Resolved IP Address - [0x%x], dwReturnCode - %d\n",
  220. *lpdwIpAddr, dwReturnCode));
  221. #endif // SENS_CHICAGO
  222. return (dwReturnCode);
  223. }
  224. #if !defined(SENS_CHICAGO)
  225. RPC_STATUS
  226. IP_ADDRESS_RESOLVER::NextAddress(
  227. OUT LPDWORD lpdwIpAddr
  228. )
  229. /*++
  230. Routine Description:
  231. Returns the next IP address associated with the Name
  232. parameter to the constructor.
  233. During the first call if check for loopback and for dotted numeric IP
  234. address formats. If these fail then it begins a complex lookup
  235. (WSALookupServiceBegin) and returns the first available address.
  236. During successive calls in which a complex lookup was started
  237. it returns sucessive addressed returned by WSALookupServiceNext().
  238. Arguments:
  239. lpdwIpAddr - If successful, the member is set to an IP address.
  240. Return Value:
  241. RPC_S_OK - lpdwIpAddr points to a new IP address
  242. RPC_S_SERVER_UNAVAILABLE - Unable to find any more addresses
  243. RPC_S_OUT_OF_MEMORY - otherwise
  244. --*/
  245. {
  246. int err;
  247. RPC_STATUS status;
  248. *lpdwIpAddr = 0x0;
  249. // If this is the first call, _Name will be non-NULL and
  250. // we need to start the lookup process.
  251. if (_Name)
  252. {
  253. TCHAR *Name = _Name;
  254. _Name = 0;
  255. // Check for loopback first.
  256. if (! *Name)
  257. {
  258. // Loopback - assign result of htonl(INADDR_LOOPBACK)
  259. // Little-endian dependence.
  260. *lpdwIpAddr = 0x0100007F;
  261. return(RPC_S_OK);
  262. }
  263. // Assume dot address since this is faster to check.
  264. int size = sizeof(SOCKADDR_IN);
  265. SOCKADDR_IN addr;
  266. err = WSAStringToAddress(Name,
  267. AF_INET,
  268. 0,
  269. (PSOCKADDR)&addr,
  270. &size);
  271. if (err != SOCKET_ERROR)
  272. {
  273. *lpdwIpAddr = addr.sin_addr.s_addr;
  274. return(RPC_S_OK);
  275. }
  276. ASSERT(GetLastError() == WSAEINVAL);
  277. // Start a complex query operation
  278. const static AFPROTOCOLS aIpProtocols[2] =
  279. {
  280. {AF_INET, IPPROTO_UDP},
  281. {AF_INET, IPPROTO_TCP}
  282. };
  283. const static GUID guidHostAddressByName = SVCID_INET_HOSTADDRBYNAME;
  284. WSAQUERYSET wsqs;
  285. memset(&wsqs, 0, sizeof(wsqs));
  286. wsqs.dwSize = sizeof(WSAQUERYSET);
  287. // wsqs.dwNameSpace = NS_ALL;
  288. ASSERT(NS_ALL == 0);
  289. wsqs.lpszServiceInstanceName = Name;
  290. wsqs.lpServiceClassId = (GUID *)&guidHostAddressByName;
  291. wsqs.dwNumberOfProtocols = 2;
  292. wsqs.lpafpProtocols = (PAFPROTOCOLS)&aIpProtocols[0];
  293. err = WSALookupServiceBegin(&wsqs,
  294. LUP_RETURN_ADDR,
  295. &_hRnr);
  296. if (err == SOCKET_ERROR)
  297. {
  298. SensPrintA(SENS_INFO, ("WSALookupServiceBegin() failed: %d\n", GetLastError()));
  299. return(RPC_S_SERVER_UNAVAILABLE);
  300. }
  301. _index = 0;
  302. if (_pwsqs)
  303. {
  304. _pwsqs->dwNumberOfCsAddrs = 0;
  305. }
  306. }
  307. else
  308. {
  309. if (!_hRnr)
  310. {
  311. // First call finished but didn't start a complex query. Abort now.
  312. return(RPC_S_SERVER_UNAVAILABLE);
  313. }
  314. }
  315. // A complex query has been started.
  316. ASSERT(_hRnr);
  317. // If the cached query structure is empty, call WSALookupNext to get
  318. // more addresses.
  319. if (!_pwsqs || (_index >= _pwsqs->dwNumberOfCsAddrs))
  320. {
  321. DWORD needed = _size;
  322. // Loop needed to realloc a larger _pwsqs buffer.
  323. for(;;)
  324. {
  325. err = WSALookupServiceNext(_hRnr,
  326. 0, // flags
  327. &needed,
  328. _pwsqs);
  329. // Success, break out of the loop.
  330. if (err != SOCKET_ERROR)
  331. {
  332. ASSERT(_pwsqs->dwNumberOfCsAddrs > 0);
  333. ASSERT(_pwsqs->lpcsaBuffer);
  334. // Reset to start of new result set.
  335. _index = 0;
  336. break;
  337. }
  338. status = GetLastError();
  339. // WSAEFAULT means the buffer was too small.
  340. if (status != WSAEFAULT)
  341. {
  342. // WSA_E_NO_MORE means all matching address have
  343. // already been returned.
  344. VALIDATE(status)
  345. {
  346. WSA_E_NO_MORE,
  347. WSANO_DATA,
  348. WSASERVICE_NOT_FOUND,
  349. WSAHOST_NOT_FOUND,
  350. WSATRY_AGAIN,
  351. WSANO_RECOVERY,
  352. WSANO_DATA,
  353. WSAEINVAL // In response to out of resources scenarios.
  354. } END_VALIDATE;
  355. SensPrintA(SENS_ERR, ("WSALookupServiceNext() failed: %d\n", status));
  356. return(RPC_S_SERVER_UNAVAILABLE);
  357. }
  358. // Allocate a larger buffer.
  359. if (needed <= _size)
  360. {
  361. ASSERT(needed > _size);
  362. return(RPC_S_SERVER_UNAVAILABLE);
  363. }
  364. if (_fFree)
  365. {
  366. delete _pwsqs;
  367. }
  368. _pwsqs = (PWSAQUERYSET) new char[needed];
  369. //_pwsqs = new WSAQUERYSETW[(needed - sizeof(WSAQUERYSETW))];
  370. //_pwsqs = (PWSAQUERYSETW) new char(needed - sizeof(WSAQUERYSETW));
  371. if (!_pwsqs)
  372. {
  373. return(RPC_S_OUT_OF_MEMORY);
  374. }
  375. _fFree = TRUE;
  376. _pwsqs->dwNumberOfCsAddrs = 0;
  377. _size = needed;
  378. #if DBG
  379. // On retail we start with enough space for two addresses during the
  380. // first call. If this debug print gets hit too much we can increase the
  381. // starting size (IP_BUFFER_SIZE).
  382. if (_size > sizeof(WSAQUERYSET) + IP_RETAIL_BUFFER_SIZE)
  383. {
  384. SensPrintA(SENS_ERR, ("WSALookupServerNext(): sizeof(WSAQUERYSETW) - %d\n"
  385. "WSALookupServerNext(): IP_RETAIL_BUFFER_SIZE - %d\n",
  386. sizeof(WSAQUERYSETW), IP_RETAIL_BUFFER_SIZE));
  387. SensPrintA(SENS_ERR, ("WSALookupServerNext() wants %d bytes. Make this the "
  388. "default?\n", _size));
  389. }
  390. #endif
  391. }
  392. }
  393. ASSERT(_pwsqs);
  394. ASSERT(_index < _pwsqs->dwNumberOfCsAddrs);
  395. LPCSADDR_INFO pInfo = &_pwsqs->lpcsaBuffer[_index];
  396. _index++;
  397. *lpdwIpAddr = ((SOCKADDR_IN *)pInfo->RemoteAddr.lpSockaddr)->sin_addr.s_addr;
  398. return(RPC_S_OK);
  399. }
  400. IP_ADDRESS_RESOLVER::~IP_ADDRESS_RESOLVER()
  401. {
  402. if (_hRnr)
  403. {
  404. WSALookupServiceEnd(_hRnr);
  405. }
  406. if (_fFree)
  407. {
  408. delete _pwsqs;
  409. }
  410. }
  411. #endif // SENS_CHICAGO