Leaked source code of windows server 2003
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.

370 lines
13 KiB

  1. /*++
  2. Copyright(c) 1998,99 Microsoft Corporation
  3. Module Name:
  4. tcpip.c
  5. Abstract:
  6. Windows Load Balancing Service (WLBS)
  7. Driver - IP/TCP/UDP support
  8. Author:
  9. kyrilf
  10. --*/
  11. #include <ndis.h>
  12. #include "tcpip.h"
  13. #include "wlbsip.h"
  14. #include "univ.h"
  15. #include "wlbsparm.h"
  16. #include "params.h"
  17. #include "main.h"
  18. #include "log.h"
  19. #include "tcpip.tmh"
  20. /* GLOBALS */
  21. static ULONG log_module_id = LOG_MODULE_TCPIP;
  22. static UCHAR nbt_encoded_shadow_name [NBT_ENCODED_NAME_LEN];
  23. /* PROCEDURES */
  24. BOOLEAN Tcpip_init (
  25. PTCPIP_CTXT ctxtp,
  26. PVOID parameters)
  27. {
  28. ULONG i, j;
  29. PCVY_PARAMS params = (PCVY_PARAMS) parameters;
  30. UNICODE_STRING UnicodeMachineName;
  31. ANSI_STRING AnsiMachineName;
  32. WCHAR pwcMachineName[NBT_NAME_LEN];
  33. UCHAR pucMachineName[NBT_NAME_LEN];
  34. /* extract cluster computer name from full internet name */
  35. j = 0;
  36. while ((params -> domain_name [j] != 0)
  37. && (params -> domain_name [j] != L'.'))
  38. {
  39. // Get only 15 characters since the maximum length of a Netbios machine name is 15.
  40. // It must be padded with a ' ', hence the definition on NBT_NAME_LEN to 16.
  41. if (j < (NBT_NAME_LEN - 1))
  42. {
  43. j ++;
  44. }
  45. else
  46. {
  47. TRACE_CRIT("%!FUNC! Cluster name in %ls longer than 15 characters. Truncating it to 15 characters.", params->domain_name);
  48. break;
  49. }
  50. }
  51. /* build encoded cluster computer name for checking against arriving NBT
  52. session requests */
  53. for (i = 0; i < NBT_NAME_LEN; i ++)
  54. {
  55. if (i >= j)
  56. {
  57. ctxtp -> nbt_encoded_cluster_name [2 * i] =
  58. NBT_ENCODE_FIRST (' ');
  59. ctxtp -> nbt_encoded_cluster_name [2 * i + 1] =
  60. NBT_ENCODE_SECOND (' ');
  61. }
  62. else
  63. {
  64. ctxtp -> nbt_encoded_cluster_name [2 * i] =
  65. NBT_ENCODE_FIRST (toupper ((UCHAR) (params -> domain_name [i])));
  66. ctxtp -> nbt_encoded_cluster_name [2 * i + 1] =
  67. NBT_ENCODE_SECOND (toupper ((UCHAR) (params -> domain_name [i])));
  68. }
  69. }
  70. /* Save away the machine name in Netbios format.
  71. Tcpip_nbt_handle overwrites NetBT Session request packets destined for the cluster name
  72. with this saved machine name.
  73. */
  74. nbt_encoded_shadow_name[0] = 0;
  75. if (params -> hostname[0] != 0)
  76. {
  77. /* extract computer name from FQDN */
  78. j = 0;
  79. while ((params -> hostname [j] != 0)
  80. && (params -> hostname [j] != L'.'))
  81. {
  82. // Get only 15 characters since the maximum length of a Netbios machine name is 15.
  83. // It must be padded with a ' ', hence the definition on NBT_NAME_LEN to 16.
  84. if (j < (NBT_NAME_LEN - 1))
  85. {
  86. pwcMachineName[j] = params -> hostname[j];
  87. j ++;
  88. }
  89. else
  90. {
  91. TRACE_CRIT("%!FUNC! Host name in %ls longer than 15 characters. Truncating it to 15 characters.", params->hostname);
  92. break;
  93. }
  94. }
  95. pwcMachineName[j] = 0;
  96. /* Convert unicode string to ansi string */
  97. UnicodeMachineName.Buffer = pwcMachineName;
  98. UnicodeMachineName.Length = (USHORT) (j * sizeof(WCHAR));
  99. UnicodeMachineName.MaximumLength = NBT_NAME_LEN * sizeof(WCHAR);
  100. pucMachineName[0] = 0;
  101. AnsiMachineName.Buffer = pucMachineName;
  102. AnsiMachineName.Length = 0;
  103. AnsiMachineName.MaximumLength = NBT_NAME_LEN;
  104. if (RtlUnicodeStringToAnsiString(&AnsiMachineName, &UnicodeMachineName, FALSE) == STATUS_SUCCESS)
  105. {
  106. for (i = 0; i < NBT_NAME_LEN; i ++)
  107. {
  108. if (i >= j)
  109. {
  110. nbt_encoded_shadow_name [2 * i] =
  111. NBT_ENCODE_FIRST (' ');
  112. nbt_encoded_shadow_name [2 * i + 1] =
  113. NBT_ENCODE_SECOND (' ');
  114. }
  115. else
  116. {
  117. nbt_encoded_shadow_name [2 * i] =
  118. NBT_ENCODE_FIRST (toupper (pucMachineName[i]));
  119. nbt_encoded_shadow_name [2 * i + 1] =
  120. NBT_ENCODE_SECOND (toupper (pucMachineName[i]));
  121. }
  122. }
  123. }
  124. else
  125. {
  126. TRACE_CRIT("%!FUNC! RtlUnicodeStringToAnsiString failed to convert %ls to Ansi", pwcMachineName);
  127. }
  128. }
  129. else // We donot have the machine's name, so, there will be no name to overwrite the NetBT packets with.
  130. {
  131. TRACE_CRIT("%!FUNC! Host name is not present. Unable to encode Netbios name.");
  132. }
  133. return TRUE;
  134. } /* Tcpip_init */
  135. VOID Tcpip_nbt_handle (
  136. PTCPIP_CTXT ctxtp,
  137. PMAIN_PACKET_INFO pPacketInfo
  138. )
  139. {
  140. PUCHAR called_name;
  141. ULONG i;
  142. PNBT_HDR nbt_hdrp = (PNBT_HDR)pPacketInfo->IP.TCP.Payload.pPayload;
  143. /* if this is an NBT session request packet, check to see if it's calling
  144. the cluster machine name, which should be replaced with the shadow name */
  145. // Do we have the machine name ?
  146. if (nbt_encoded_shadow_name[0] == 0)
  147. {
  148. TRACE_CRIT("%!FUNC! No host name present to replace the cluster name with");
  149. return;
  150. }
  151. if (NBT_GET_PKT_TYPE (nbt_hdrp) == NBT_SESSION_REQUEST)
  152. {
  153. /* pass the field length byte - assume all names are
  154. NBT_ENCODED_NAME_LEN bytes long */
  155. called_name = NBT_GET_CALLED_NAME (nbt_hdrp) + 1;
  156. /* match called name to cluster name */
  157. for (i = 0; i < NBT_ENCODED_NAME_LEN; i ++)
  158. {
  159. if (called_name [i] != ctxtp -> nbt_encoded_cluster_name [i])
  160. break;
  161. }
  162. /* replace cluster computer name with the shadom name */
  163. if (i >= NBT_ENCODED_NAME_LEN)
  164. {
  165. USHORT checksum;
  166. for (i = 0; i < NBT_ENCODED_NAME_LEN; i ++)
  167. called_name [i] = nbt_encoded_shadow_name [i];
  168. /* re-compute checksum */
  169. checksum = Tcpip_chksum(ctxtp, pPacketInfo, TCPIP_PROTOCOL_TCP);
  170. TCP_SET_CHKSUM (pPacketInfo->IP.TCP.pHeader, checksum);
  171. }
  172. }
  173. } /* end Tcpip_nbt_handle */
  174. USHORT Tcpip_chksum (
  175. PTCPIP_CTXT ctxtp,
  176. PMAIN_PACKET_INFO pPacketInfo,
  177. ULONG prot)
  178. {
  179. ULONG checksum = 0, i, len;
  180. PUCHAR ptr;
  181. USHORT original;
  182. USHORT usRet;
  183. /* Preserve original checksum. Note that Main_{send/recv}_frame_parse ensures
  184. that we can safely touch all of the protocol headers (not options, however). */
  185. if (prot == TCPIP_PROTOCOL_TCP)
  186. {
  187. /* Grab the checksum and zero out the checksum in the header; checksums
  188. over headers MUST be performed with zero in the checksum field. */
  189. original = TCP_GET_CHKSUM(pPacketInfo->IP.TCP.pHeader);
  190. TCP_SET_CHKSUM(pPacketInfo->IP.TCP.pHeader, 0);
  191. }
  192. else if (prot == TCPIP_PROTOCOL_UDP)
  193. {
  194. /* Grab the checksum and zero out the checksum in the header; checksums
  195. over headers MUST be performed with zero in the checksum field. */
  196. original = UDP_GET_CHKSUM(pPacketInfo->IP.UDP.pHeader);
  197. UDP_SET_CHKSUM(pPacketInfo->IP.UDP.pHeader, 0);
  198. }
  199. else
  200. {
  201. /* Grab the checksum and zero out the checksum in the header; checksums
  202. over headers MUST be performed with zero in the checksum field. */
  203. original = IP_GET_CHKSUM(pPacketInfo->IP.pHeader);
  204. IP_SET_CHKSUM(pPacketInfo->IP.pHeader, 0);
  205. }
  206. /* Computer appropriate checksum for specified protocol. */
  207. if (prot != TCPIP_PROTOCOL_IP)
  208. {
  209. /* Checksum is computed over the source IP address, destination IP address,
  210. protocol (6 for TCP), TCP segment length value and entire TCP segment.
  211. (setting checksum field within TCP header to 0). Code is taken from page
  212. 185 of "Internetworking with TCP/IP: Volume II" by Comer/Stevens, 1991. */
  213. ptr = (PUCHAR)IP_GET_SRC_ADDR_PTR(pPacketInfo->IP.pHeader);
  214. /* 2*IP_ADDR_LEN bytes = IP_ADDR_LEN shorts. */
  215. for (i = 0; i < IP_ADDR_LEN; i ++, ptr += 2)
  216. checksum += (ULONG)((ptr[0] << 8) | ptr[1]);
  217. }
  218. if (prot == TCPIP_PROTOCOL_TCP)
  219. {
  220. /* Calculate the IP datagram length (packet length minus the IP header). */
  221. len = IP_GET_PLEN(pPacketInfo->IP.pHeader) - IP_GET_HLEN(pPacketInfo->IP.pHeader) * sizeof(ULONG);
  222. /* Since we only have the indicated number of bytes that we can safely look
  223. at, if the calculated length happens to be larger, we cannot perform
  224. this checksum, so bail out now. */
  225. if (len > pPacketInfo->IP.TCP.Length)
  226. {
  227. UNIV_PRINT_CRIT(("Tcpip_chksum: Length of the TCP buffer (%u) is less than the calculated packet size (%u)", pPacketInfo->IP.TCP.Length, len));
  228. TRACE_CRIT("%!FUNC! Length of the TCP buffer (%u) is less than the calculated packet size (%u)", pPacketInfo->IP.TCP.Length, len);
  229. /* Return an invalid checksum. */
  230. return 0xffff;
  231. }
  232. checksum += TCPIP_PROTOCOL_TCP + len;
  233. ptr = (PUCHAR)pPacketInfo->IP.TCP.pHeader;
  234. }
  235. else if (prot == TCPIP_PROTOCOL_UDP)
  236. {
  237. /* Calculate the IP datagram length (packet length minus the IP header). */
  238. len = IP_GET_PLEN(pPacketInfo->IP.pHeader) - IP_GET_HLEN(pPacketInfo->IP.pHeader) * sizeof(ULONG);
  239. /* Since we only have the indicated number of bytes that we can safely look
  240. at, if the calculated length happens to be larger, we cannot perform
  241. this checksum, so bail out now. */
  242. if (len > pPacketInfo->IP.UDP.Length)
  243. {
  244. UNIV_PRINT_CRIT(("Tcpip_chksum: Length of the UDP buffer (%u) is less than the calculated packet size (%u)", pPacketInfo->IP.UDP.Length, len));
  245. TRACE_CRIT("%!FUNC! Length of the UDP buffer (%u) is less than the calculated packet size (%u)", pPacketInfo->IP.UDP.Length, len);
  246. /* Return an invalid checksum. */
  247. return 0xffff;
  248. }
  249. checksum += TCPIP_PROTOCOL_UDP + UDP_GET_LEN(pPacketInfo->IP.UDP.pHeader);
  250. ptr = (PUCHAR)pPacketInfo->IP.UDP.pHeader;
  251. }
  252. else
  253. {
  254. /* Calculate the IP header length. */
  255. len = IP_GET_HLEN(pPacketInfo->IP.pHeader) * sizeof(ULONG);
  256. /* Since we only have the indicated number of bytes that we can safely look
  257. at, if the calculated length happens to be larger, we cannot perform
  258. this checksum, so bail out now. */
  259. if (len > pPacketInfo->IP.Length)
  260. {
  261. UNIV_PRINT_CRIT(("Tcpip_chksum: Length of the IP buffer (%u) is less than the calculated packet size (%u)", pPacketInfo->IP.Length, len));
  262. TRACE_CRIT("%!FUNC! Length of the IP buffer (%u) is less than the calculated packet size (%u)", pPacketInfo->IP.Length, len);
  263. /* Return an invalid checksum. */
  264. return 0xffff;
  265. }
  266. ptr = (PUCHAR)pPacketInfo->IP.pHeader;
  267. }
  268. /* Loop through the entire packet by USHORTs and calculate the checksum. */
  269. for (i = 0; i < len / 2; i ++, ptr += 2)
  270. checksum += (ULONG)((ptr[0] << 8) | ptr[1]);
  271. /* If the length is odd, handle the last byte. Note that no current cases exist
  272. to test this odd-byte code. IP, TCP and UDP headers are ALWAYS a multiple of
  273. four bytes. Therefore, this will only execute when the UDP/TCP payload is an
  274. odd number of bytes. NLB calls this function to calculate checksums for NetBT,
  275. remote control and our outgoing IGMP messages. For NetBT, the payload of the
  276. packets we care about is ALWAYS 72 bytes. NLB remote control messages are
  277. ALWAYS 300 byte (in .Net, or 44 bytes in Win2k/NT) payloads. Only the IP header
  278. checksum is calculated for an IGMP message. Therefore, no case currently exists
  279. to test an odd length, but this is not magic we're doing here. */
  280. if (len % 2)
  281. checksum += (ULONG)(ptr[0] << 8);
  282. /* Add the two USHORTs the comprise the checksum together. */
  283. checksum = (checksum >> 16) + (checksum & 0xffff);
  284. /* Add the upper USHORT to the checksum. */
  285. checksum += (checksum >> 16);
  286. /* Restore original checksum. */
  287. if (prot == TCPIP_PROTOCOL_TCP)
  288. {
  289. TCP_SET_CHKSUM(pPacketInfo->IP.TCP.pHeader, original);
  290. }
  291. else if (prot == TCPIP_PROTOCOL_UDP)
  292. {
  293. UDP_SET_CHKSUM(pPacketInfo->IP.UDP.pHeader, original);
  294. }
  295. else
  296. {
  297. IP_SET_CHKSUM(pPacketInfo->IP.pHeader, original);
  298. }
  299. /* The final checksum is the two's compliment of the checksum. */
  300. usRet = (USHORT)(~checksum & 0xffff);
  301. return usRet;
  302. }