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.

729 lines
18 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. tcpcfg.c
  5. Abstract:
  6. TCP/IP translation routines
  7. Author:
  8. Mike Massa (mikemas) July 15, 1997
  9. Revision History:
  10. Who When What
  11. -------- -------- ----------------------------------------------
  12. mikemas 07-15-97 created
  13. --*/
  14. #include "clusrtlp.h"
  15. #include <tdi.h>
  16. #include <tdiinfo.h>
  17. #include <ipinfo.h>
  18. #include <llinfo.h>
  19. #include <ntddtcp.h>
  20. #include <winsock2.h>
  21. #include <wchar.h>
  22. //
  23. // Private Constants
  24. //
  25. #define MAX_ADDRESS_STRING_LENGTH 15
  26. #define MAX_ENDPOINT_STRING_LENGTH 5
  27. VOID
  28. ClRtlQueryTcpipInformation(
  29. OUT LPDWORD MaxAddressStringLength,
  30. OUT LPDWORD MaxEndpointStringLength,
  31. OUT LPDWORD TdiAddressInfoLength
  32. )
  33. /*++
  34. Routine Description:
  35. Returns information about the TCP/IP protocol.
  36. Arguments:
  37. MaxAddressStringLength - A pointer to a variable into which to place
  38. the maximum length, in characters, of a TCP/IP
  39. network address value in string format, including
  40. the terminating NULL. If this parameter is NUL,
  41. it will be skipped.
  42. MaxEndpointStringLength - A pointer to a variable into which to place
  43. the maximum length, in characters, of a TCP/IP
  44. transport endpoint value in string format,
  45. including the terminating NUL. If this parameter
  46. is NULL, it will be skipped.
  47. Return Value:
  48. None.
  49. --*/
  50. {
  51. if (MaxAddressStringLength != NULL) {
  52. *MaxAddressStringLength = MAX_ADDRESS_STRING_LENGTH;
  53. }
  54. if (MaxEndpointStringLength != NULL) {
  55. *MaxEndpointStringLength = MAX_ENDPOINT_STRING_LENGTH;
  56. }
  57. if (TdiAddressInfoLength != NULL) {
  58. *TdiAddressInfoLength = sizeof(TDI_ADDRESS_INFO) -
  59. sizeof(TRANSPORT_ADDRESS) +
  60. sizeof(TA_IP_ADDRESS);
  61. }
  62. return;
  63. } // ClRtlQueryTcpipInformation
  64. DWORD
  65. ClRtlTcpipAddressToString(
  66. ULONG AddressValue,
  67. LPWSTR * AddressString
  68. )
  69. /*++
  70. Routine Description:
  71. Converts a binary representation of a TCP/IP network address,
  72. in network byte order, into a string representation.
  73. Arguments:
  74. AddressValue - The binary value, in network byte order, to convert.
  75. AddressString - A pointer to a pointer to a unicode string buffer into
  76. which to place the converted value. If this parameter
  77. is NULL, the string buffer will be allocated and
  78. must be freed by the caller.
  79. Return Value:
  80. ERROR_SUCCESS if the operation was successful.
  81. A Windows error code otherwise.
  82. --*/
  83. {
  84. DWORD status;
  85. NTSTATUS ntStatus;
  86. UNICODE_STRING unicodeString;
  87. ANSI_STRING ansiString;
  88. LPSTR ansiBuffer;
  89. LPWSTR addressString;
  90. BOOLEAN allocatedStringBuffer = FALSE;
  91. USHORT maxStringLength = (MAX_ADDRESS_STRING_LENGTH + 1) *
  92. sizeof(WCHAR);
  93. if (*AddressString == NULL) {
  94. addressString = LocalAlloc(LMEM_FIXED, maxStringLength);
  95. if (addressString == NULL) {
  96. return(ERROR_NOT_ENOUGH_MEMORY);
  97. }
  98. allocatedStringBuffer = TRUE;
  99. }
  100. else {
  101. addressString = *AddressString;
  102. }
  103. ansiBuffer = inet_ntoa(*((struct in_addr *) &AddressValue));
  104. if (ansiBuffer == NULL) {
  105. status = ERROR_INVALID_PARAMETER;
  106. goto error_exit;
  107. }
  108. RtlInitAnsiString(&ansiString, ansiBuffer);
  109. unicodeString.Buffer = addressString;
  110. unicodeString.Length = 0;
  111. unicodeString.MaximumLength = maxStringLength;
  112. ntStatus = RtlAnsiStringToUnicodeString(
  113. &unicodeString,
  114. &ansiString,
  115. FALSE
  116. );
  117. if (ntStatus != STATUS_SUCCESS) {
  118. status = RtlNtStatusToDosError(ntStatus);
  119. goto error_exit;
  120. }
  121. *AddressString = addressString;
  122. return(ERROR_SUCCESS);
  123. error_exit:
  124. if (allocatedStringBuffer) {
  125. LocalFree(addressString);
  126. }
  127. return(status);
  128. } // ClRtlTcpipAddressToString
  129. DWORD
  130. ClRtlTcpipStringToAddress(
  131. LPCWSTR AddressString,
  132. PULONG AddressValue
  133. )
  134. /*++
  135. Routine Description:
  136. Converts a string representation of a TCP/IP network address
  137. into a binary representation in network byte order. The string must
  138. be formatted in the canonical IP Address form (xxx.xxx.xxx.xxx).
  139. Leading zeros are optional.
  140. Arguments:
  141. AddressString - A pointer to the string to convert.
  142. AddressValue - A pointer to a variable into which to place the converted
  143. binary value. The value will be in network byte order.
  144. Return Value:
  145. ERROR_SUCCESS if the operation was successful.
  146. A Windows error code otherwise.
  147. --*/
  148. {
  149. NTSTATUS status;
  150. UNICODE_STRING unicodeString;
  151. STRING ansiString;
  152. ULONG address;
  153. //
  154. // Make sure the string is formatted correctly.
  155. //
  156. {
  157. DWORD periodCount = 0;
  158. DWORD digitCount = 0;
  159. BOOLEAN isValid = TRUE;
  160. LPCWSTR addressString = AddressString;
  161. LPCWSTR digitString = AddressString;
  162. while (*addressString != L'\0') {
  163. if (*addressString == L'.') {
  164. // Character is a period. There must be exactly
  165. // three periods. There must be at least one
  166. // digit before each period.
  167. periodCount++;
  168. if ((digitCount == 0) || (periodCount > 3)) {
  169. isValid = FALSE;
  170. } else if (wcstoul(digitString, NULL, 10) > 255) {
  171. isValid = FALSE;
  172. } else {
  173. digitCount = 0;
  174. digitString = addressString + 1;
  175. }
  176. } else if (iswdigit(*addressString)) {
  177. // Character is a digit. There can be up to three
  178. // decimal digits before each period, and the value
  179. // can not exceed 255.
  180. digitCount++;
  181. if (digitCount > 3) {
  182. isValid = FALSE;
  183. }
  184. }
  185. else {
  186. // Character is not a digit.
  187. isValid = FALSE;
  188. }
  189. if (!isValid)
  190. break;
  191. addressString++;
  192. }
  193. if ((periodCount != 3) ||
  194. (digitCount == 0) ||
  195. (wcstoul(digitString, NULL, 10) > 255)) {
  196. isValid = FALSE;
  197. }
  198. if (!isValid)
  199. return(ERROR_INVALID_PARAMETER);
  200. }
  201. RtlInitUnicodeString(&unicodeString, AddressString);
  202. status = RtlUnicodeStringToAnsiString(
  203. &ansiString,
  204. &unicodeString,
  205. TRUE
  206. );
  207. if (status == STATUS_SUCCESS) {
  208. address = inet_addr(ansiString.Buffer);
  209. RtlFreeAnsiString(&ansiString);
  210. if (address == INADDR_NONE) {
  211. if (lstrcmpW(AddressString, L"255.255.255.255") != 0) {
  212. return(ERROR_INVALID_PARAMETER);
  213. }
  214. }
  215. *AddressValue = address;
  216. return(ERROR_SUCCESS);
  217. }
  218. return(status);
  219. } // ClRtlTcpipStringToAddress
  220. DWORD
  221. ClRtlTcpipEndpointToString(
  222. USHORT EndpointValue,
  223. LPWSTR * EndpointString
  224. )
  225. /*++
  226. Routine Description:
  227. Converts a binary representation of a TCP/IP transport endpoint,
  228. in network byte order, into a string representation.
  229. Arguments:
  230. EndpointValue - The binary value, in network byte order, to convert.
  231. EndpointString - A pointer to a pointer to a unicode string buffer into
  232. which to place the converted value. If this parameter
  233. is NULL, the string buffer will be allocated and
  234. must be freed by the caller.
  235. Return Value:
  236. ERROR_SUCCESS if the operation was successful.
  237. A Windows error code otherwise.
  238. --*/
  239. {
  240. DWORD status;
  241. NTSTATUS ntStatus;
  242. ULONG endpointValue;
  243. LPWSTR endpointString;
  244. USHORT maxStringLength = (MAX_ENDPOINT_STRING_LENGTH + 1) *
  245. sizeof(WCHAR);
  246. if (*EndpointString == NULL) {
  247. endpointString = LocalAlloc(LMEM_FIXED, maxStringLength);
  248. if (endpointString == NULL) {
  249. return(ERROR_NOT_ENOUGH_MEMORY);
  250. }
  251. *EndpointString = endpointString;
  252. }
  253. else {
  254. endpointString = *EndpointString;
  255. }
  256. endpointValue = 0;
  257. endpointValue = ntohs(EndpointValue);
  258. _ultow( endpointValue, endpointString, 10);
  259. return(ERROR_SUCCESS);
  260. } // ClRtlTcpipEndpointToString
  261. DWORD
  262. ClRtlTcpipStringToEndpoint(
  263. LPCWSTR EndpointString,
  264. PUSHORT EndpointValue
  265. )
  266. /*++
  267. Routine Description:
  268. Converts a string representation of a TCP/IP transport endpoint
  269. into a binary representation in network byte order.
  270. Arguments:
  271. EndpointString - A pointer to the string to convert.
  272. EndpointValue - A pointer to a variable into which to place the converted
  273. binary value. The value will be in network byte order.
  274. Return Value:
  275. ERROR_SUCCESS if the operation was successful.
  276. A Windows error code otherwise.
  277. --*/
  278. {
  279. ULONG endpoint;
  280. DWORD length = lstrlenW(EndpointString);
  281. if ( (length == 0) || (length > MAX_ENDPOINT_STRING_LENGTH) ) {
  282. return(ERROR_INCORRECT_ADDRESS);
  283. }
  284. endpoint = wcstoul(EndpointString, NULL, 10);
  285. if (endpoint > 0xFFFF) {
  286. return(ERROR_INCORRECT_ADDRESS);
  287. }
  288. *EndpointValue = (USHORT) htons( ((USHORT) endpoint) );
  289. return(ERROR_SUCCESS);
  290. } // ClRtlTcpipStringToEndpoint
  291. BOOL
  292. ClRtlIsValidTcpipAddress(
  293. IN ULONG Address
  294. )
  295. {
  296. //
  297. // Convert to little-endian format, since that is what the broken
  298. // winsock macros require.
  299. //
  300. Address = ntohl(Address);
  301. if ( (Address == 0) ||
  302. (!IN_CLASSA(Address) && !IN_CLASSB(Address) && !IN_CLASSC(Address))
  303. )
  304. {
  305. return(FALSE);
  306. }
  307. return(TRUE);
  308. } // ClRtlIsValidTcpipAddress
  309. BOOL
  310. ClRtlIsValidTcpipSubnetMask(
  311. IN ULONG SubnetMask
  312. )
  313. {
  314. if ( (SubnetMask == 0xffffffff) || (SubnetMask == 0)) {
  315. return(FALSE);
  316. }
  317. return(TRUE);
  318. } // ClRtlIsValidTcpipSubnetMask
  319. BOOL
  320. ClRtlIsValidTcpipAddressAndSubnetMask(
  321. IN ULONG Address,
  322. IN ULONG SubnetMask
  323. )
  324. {
  325. ULONG NetOnly = Address & SubnetMask;
  326. ULONG HostOnly = Address & ~SubnetMask;
  327. //
  328. // make sure the address/subnet combination makes sense.
  329. // This assumes that the address has already been validated
  330. // by a call to ClRtlIsValidTcpipAddress
  331. //
  332. return !( NetOnly == 0 ||
  333. NetOnly == SubnetMask ||
  334. HostOnly == 0 ||
  335. HostOnly == ~SubnetMask
  336. );
  337. } // ClRtlIsValidTcpipAddressAndSubnetMask
  338. DWORD
  339. ClRtlBuildTcpipTdiAddress(
  340. IN LPWSTR NetworkAddress,
  341. IN LPWSTR TransportEndpoint,
  342. OUT LPVOID * TdiAddress,
  343. OUT LPDWORD TdiAddressLength
  344. )
  345. /*++
  346. Routine Description:
  347. Builds a TDI Transport Address structure containing the specified
  348. NetworkAddress and TransportEndpoint. The memory for the TDI address
  349. is allocated by this routine and must be freed by the caller.
  350. Arguments:
  351. NetworkAddress - A pointer to a unicode string containing the
  352. network address to encode.
  353. TransportEndpoint - A pointer to a unicode string containing the
  354. transport endpoint to encode.
  355. TdiAddress - On output, contains the address of the TDI Transport
  356. Address structure.
  357. TdiAddressLength - On output, contains the length of the TDI Transport
  358. address structure.
  359. Return Value:
  360. ERROR_SUCCESS if the operation was successful.
  361. A Windows error code otherwise.
  362. --*/
  363. {
  364. DWORD status;
  365. PTA_IP_ADDRESS taIpAddress;
  366. ULONG ipAddress;
  367. USHORT udpPort;
  368. status = ClRtlTcpipStringToAddress(NetworkAddress, &ipAddress);
  369. if (status != ERROR_SUCCESS) {
  370. return(status);
  371. }
  372. status = ClRtlTcpipStringToEndpoint(TransportEndpoint, &udpPort);
  373. if (lstrlenW(TransportEndpoint) > MAX_ENDPOINT_STRING_LENGTH) {
  374. return(ERROR_INCORRECT_ADDRESS);
  375. }
  376. if (status != ERROR_SUCCESS) {
  377. return(status);
  378. }
  379. taIpAddress = LocalAlloc(LMEM_FIXED, sizeof(TA_IP_ADDRESS));
  380. if (taIpAddress == NULL) {
  381. return(ERROR_NOT_ENOUGH_MEMORY);
  382. }
  383. ZeroMemory(taIpAddress, sizeof(TA_IP_ADDRESS));
  384. taIpAddress->TAAddressCount = 1;
  385. taIpAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_IP);
  386. taIpAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
  387. taIpAddress->Address[0].Address[0].in_addr = ipAddress;
  388. taIpAddress->Address[0].Address[0].sin_port = udpPort;
  389. *TdiAddress = taIpAddress;
  390. *TdiAddressLength = sizeof(TA_IP_ADDRESS);
  391. return(ERROR_SUCCESS);
  392. } // ClRtlBuildTcpipTdiAddress
  393. DWORD
  394. ClRtlBuildLocalTcpipTdiAddress(
  395. IN LPWSTR NetworkAddress,
  396. OUT LPVOID TdiAddress,
  397. OUT LPDWORD TdiAddressLength
  398. )
  399. /*++
  400. Routine Description:
  401. Builds a TDI Transport Address structure which can be used to open
  402. a local TDI Address Object. The TransportEndpoint is chosen by the
  403. transport. The memory for the TDI address is allocated by this
  404. routine and must be freed by the caller.
  405. Arguments:
  406. NetworkAddress - A pointer to a unicode string containing the
  407. network address to encode.
  408. TdiAddress - On output, contains the address of the TDI Transport
  409. Address structure.
  410. TdiAddressLength - On output, contains the length of the TDI Transport
  411. address structure.
  412. Return Value:
  413. ERROR_SUCCESS if the operation was successful.
  414. A Windows error code otherwise.
  415. --*/
  416. {
  417. return(ClRtlBuildTcpipTdiAddress(
  418. NetworkAddress,
  419. L"0",
  420. TdiAddress,
  421. TdiAddressLength
  422. ));
  423. } // ClRtlBuildLocalTcpipTdiAddress
  424. DWORD
  425. ClRtlParseTcpipTdiAddress(
  426. IN LPVOID TdiAddress,
  427. OUT LPWSTR * NetworkAddress,
  428. OUT LPWSTR * TransportEndpoint
  429. )
  430. /*++
  431. Routine Description:
  432. Extracts the NetworkAddress and TransportEndpoint values from
  433. a TDI address.
  434. Arguments:
  435. TdiAddress - A pointer to the TDI TRANSPORT_ADDRESS structure to parse.
  436. NetworkAddress - A pointer to a pointer to a unicode string into which
  437. the parsed network address will be placed. If this
  438. parameter is NULL, the target string buffer will be
  439. allocated and must be freed by the caller.
  440. TransportEndpoint - A pointer to a pointer to a unicode string into
  441. which the parsed transport endpoint will be placed.
  442. If this parameter is NULL, the target string buffer
  443. will be allocated and must be freed by the caller.
  444. Return Value:
  445. ERROR_SUCCESS if the operation was successful.
  446. A Windows error code otherwise.
  447. --*/
  448. {
  449. LONG i;
  450. TA_ADDRESS * currentAddr;
  451. TDI_ADDRESS_IP UNALIGNED * validAddr = NULL;
  452. PTRANSPORT_ADDRESS addrList = TdiAddress;
  453. DWORD status;
  454. BOOLEAN allocatedAddressString = FALSE;
  455. currentAddr = (TA_ADDRESS *)addrList->Address;
  456. for (i = 0; i < addrList->TAAddressCount; i++) {
  457. if (currentAddr->AddressType == TDI_ADDRESS_TYPE_IP) {
  458. if (currentAddr->AddressLength >= TDI_ADDRESS_LENGTH_IP) {
  459. validAddr = (TDI_ADDRESS_IP UNALIGNED *) currentAddr->Address;
  460. break;
  461. }
  462. } else {
  463. currentAddr = (TA_ADDRESS *)(currentAddr->Address +
  464. currentAddr->AddressLength);
  465. }
  466. }
  467. if (validAddr == NULL) {
  468. return(ERROR_INCORRECT_ADDRESS);
  469. }
  470. if (NetworkAddress == NULL) {
  471. allocatedAddressString = TRUE;
  472. }
  473. status = ClRtlTcpipAddressToString(
  474. validAddr->in_addr,
  475. NetworkAddress
  476. );
  477. if (status != ERROR_SUCCESS) {
  478. return(status);
  479. }
  480. status = ClRtlTcpipEndpointToString(
  481. validAddr->sin_port,
  482. TransportEndpoint
  483. );
  484. if (status != ERROR_SUCCESS) {
  485. if (allocatedAddressString) {
  486. LocalFree(*NetworkAddress);
  487. *NetworkAddress = NULL;
  488. }
  489. return(status);
  490. }
  491. return(ERROR_SUCCESS);
  492. } // ClRtlParseTcpipTdiAddress
  493. DWORD
  494. ClRtlParseTcpipTdiAddressInfo(
  495. IN LPVOID TdiAddressInfo,
  496. OUT LPWSTR * NetworkAddress,
  497. OUT LPWSTR * TransportEndpoint
  498. )
  499. /*++
  500. Routine Description:
  501. Extracts the NetworkAddress and TransportEndpoint values from
  502. a TDI_ADDRESS_INFO structure.
  503. Arguments:
  504. TdiAddressInfo - A pointer to the TDI_ADDRESS_INFO structure to parse.
  505. NetworkAddress - A pointer to a pointer to a unicode string into which
  506. the parsed network address will be placed. If this
  507. parameter is NULL, the target string buffer will be
  508. allocated and must be freed by the caller.
  509. TransportEndpoint - A pointer to a pointer to a unicode string into
  510. which the parsed transport endpoint will be placed.
  511. If this parameter is NULL, the target string buffer
  512. will be allocated and must be freed by the caller.
  513. Return Value:
  514. ERROR_SUCCESS if the operation was successful.
  515. A Windows error code otherwise.
  516. --*/
  517. {
  518. DWORD status;
  519. PTDI_ADDRESS_INFO addressInfo = TdiAddressInfo;
  520. status = ClRtlParseTcpipTdiAddress(
  521. &(addressInfo->Address),
  522. NetworkAddress,
  523. TransportEndpoint
  524. );
  525. return(status);
  526. } // ClRtlParseTcpipTdiAddressInfo