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.

374 lines
15 KiB

  1. #include <windows.h>
  2. #include <tchar.h>
  3. #include <winsock2.h>
  4. #include <stdio.h>
  5. #include "debug.h"
  6. #include "wlbsconfig.h"
  7. #include "wlbsparm.h"
  8. #define MAXIPSTRLEN 20
  9. //+----------------------------------------------------------------------------
  10. //
  11. // Function: IpAddressFromAbcdWsz
  12. //
  13. // Synopsis:Converts caller's a.b.c.d IP address string to a network byte order IP
  14. // address. 0 if formatted incorrectly.
  15. //
  16. // Arguments: IN const WCHAR* wszIpAddress - ip address in a.b.c.d unicode string
  17. //
  18. // Returns: DWORD - IPAddr, return INADDR_NONE on failure
  19. //
  20. // History: fengsun Created Header 12/8/98
  21. // chrisdar COPIED FROM \nt\net\config\netcfg\wlbscfg\utils.cpp BECAUSE COULDN'T RESOLVE RtlAssert WHEN COMPILING THIS FILE INTO PROJECT
  22. //
  23. //+----------------------------------------------------------------------------
  24. DWORD WINAPI IpAddressFromAbcdWsz(IN const WCHAR* wszIpAddress)
  25. {
  26. CHAR szIpAddress[MAXIPSTRLEN + 1];
  27. DWORD nboIpAddr;
  28. ASSERT(lstrlen(wszIpAddress) < MAXIPSTRLEN);
  29. WideCharToMultiByte(CP_ACP, 0, wszIpAddress, -1,
  30. szIpAddress, sizeof(szIpAddress), NULL, NULL);
  31. nboIpAddr = inet_addr(szIpAddress);
  32. return(nboIpAddr);
  33. }
  34. bool ValidateVipInRule(const PWCHAR pwszRuleString, const WCHAR pwToken, DWORD& dwVipLen)
  35. {
  36. ASSERT(NULL != pwszRuleString);
  37. bool ret = false;
  38. dwVipLen = 0;
  39. // Find the first occurence of the token string, which will denote the end of
  40. // the VIP part of the rule
  41. PWCHAR pwcAtSeparator = wcschr(pwszRuleString, pwToken);
  42. if (NULL == pwcAtSeparator) { return ret; }
  43. // Found the token string. Copy out the VIP and validate it.
  44. WCHAR wszIP[WLBS_MAX_CL_IP_ADDR + 1];
  45. DWORD dwStrLen = min((UINT)(pwcAtSeparator - pwszRuleString),
  46. WLBS_MAX_CL_IP_ADDR);
  47. wcsncpy(wszIP, pwszRuleString, dwStrLen);
  48. wszIP[dwStrLen] = '\0';
  49. ASSERT(dwStrLen == wcslen(wszIP));
  50. dwVipLen = dwStrLen;
  51. // IpAddressFromAbcdWsz calls inet_addr to check the format of the IP address, but the
  52. // allowed formats are very flexible. For our port rule definition of a VIP we require
  53. // a rigid a.b.c.d format. To ensure that we only say the IP address is valid for IPs
  54. // specified in this manner, ensure that there are 3 and only 3 '.' in the string.
  55. DWORD dwTmpCount = 0;
  56. PWCHAR pwszTmp = pwszRuleString;
  57. while (pwszTmp < pwcAtSeparator)
  58. {
  59. if (*pwszTmp++ == L'.') { dwTmpCount++; }
  60. }
  61. if (dwTmpCount == 3 && INADDR_NONE != IpAddressFromAbcdWsz(wszIP)) { ret = true; }
  62. return ret;
  63. }
  64. DWORD testRule(PWCHAR ptr)
  65. {
  66. WLBS_REG_PARAMS* paramp = new WLBS_REG_PARAMS;
  67. DWORD ret = 0;
  68. PWLBS_PORT_RULE rp, rulep;
  69. /* distinct rule elements for parsing */
  70. typedef enum
  71. {
  72. vip,
  73. start,
  74. end,
  75. protocol,
  76. mode,
  77. affinity,
  78. load,
  79. priority
  80. }
  81. CVY_RULE_ELEMENT;
  82. CVY_RULE_ELEMENT elem = vip;
  83. DWORD count = 0;
  84. DWORD i;
  85. DWORD dwVipLen = 0;
  86. const DWORD dwVipAllNameLen = sizeof(CVY_NAME_PORTRULE_VIPALL)/sizeof(WCHAR) - 1; // Used below in a loop. Set it here since it is a constant.
  87. WCHAR wszTraceOutputTmp[WLBS_MAX_CL_IP_ADDR + 1];
  88. bool bFallThrough = false; // Used in 'vip' case statement below.
  89. rulep = paramp->i_port_rules;
  90. while (ptr != NULL) {
  91. switch (elem) {
  92. case vip:
  93. // DO NOT MOVE THIS CASE STATEMENT. IT MUST ALWAYS COME BEFORE THE 'start' CASE STATEMENT. See FALLTHROUGH comment below.
  94. bFallThrough = false;
  95. dwVipLen = 0;
  96. if (ValidateVipInRule(ptr, L',', dwVipLen))
  97. {
  98. ASSERT(dwVipLen <= WLBS_MAX_CL_IP_ADDR);
  99. // rulep->virtual_ip_addr is a TCHAR and ptr is a WCHAR.
  100. // Data is moved from the latter to the former so ASSERT TCHAR is WCHAR.
  101. ASSERT(sizeof(TCHAR) == sizeof(WCHAR));
  102. // This is a rule for a specific VIP
  103. _tcsncpy(rulep->virtual_ip_addr, ptr, dwVipLen);
  104. (rulep->virtual_ip_addr)[dwVipLen] = '\0';
  105. }
  106. else
  107. {
  108. // This is either an 'all' rule, a VIP-less rule or a malformed rule. We can't distinguish a malformed rule
  109. // from a VIP-less rule, so we will assume the rule is either an 'all' rule or a VIP-less rule. In both cases
  110. // set the VIP component of the rule to be the default or 'all' value.
  111. // Copy the 'all' IP into the rule.
  112. _tcscpy(rulep->virtual_ip_addr, CVY_DEF_ALL_VIP);
  113. if (dwVipAllNameLen != dwVipLen || (_tcsnicmp(ptr, CVY_NAME_PORTRULE_VIPALL, dwVipAllNameLen) != 0))
  114. {
  115. // The rule is either VIP-less or it is malformed. We assume it is VIP-less and let the 'start'
  116. // case handle the current token as a start_port property by falling through to the next case clause
  117. // rather than breaking.
  118. bFallThrough = true;
  119. // wprintf(L"doing fallthrough...%d, %d\n", dwVipAllNameLen, dwVipLen);
  120. _tcsncpy(wszTraceOutputTmp, ptr, dwVipLen);
  121. wszTraceOutputTmp[dwVipLen] = '\0';
  122. // TraceMsg(L"-----\n#### VIP element of port rule is invalid = %s\n", wszTraceOutputTmp);
  123. }
  124. }
  125. // TraceMsg(L"-----\n#### Port rule vip = %s\n", rulep->virtual_ip_addr);
  126. elem = start;
  127. // !!!!!!!!!!!!!!!!!!!!
  128. // FALLTHROUGH
  129. // !!!!!!!!!!!!!!!!!!!!
  130. // When we have a VIP-less port rule, we will fall through this case statement into the 'start' case statement
  131. // below so that the current token can be used as the start_port for a port rule.
  132. if (!bFallThrough)
  133. {
  134. // We have a VIP in the port rule. We do a "break;" as std operating procedure.
  135. // TraceMsg(L"-----\n#### Fallthrough case statement from port rule vip to start\n");
  136. break;
  137. }
  138. // NO AUTOMATIC "break;" STATEMENT HERE. Above, we conditionally flow to the 'start' case...
  139. case start:
  140. // DO NOT MOVE THIS CASE STATEMENT. IT MUST ALWAYS COME AFTER THE 'vip' CASE STATEMENT.
  141. // See comments (FALLTHROUGH) inside the 'vip' case statement.
  142. rulep->start_port = _wtoi(ptr);
  143. // CVY_CHECK_MIN (rulep->start_port, CVY_MIN_PORT);
  144. CVY_CHECK_MAX (rulep->start_port, CVY_MAX_PORT);
  145. // TraceMsg(L"-----\n#### Start port = %d\n", rulep->start_port);
  146. elem = end;
  147. break;
  148. case end:
  149. rulep->end_port = _wtoi(ptr);
  150. // CVY_CHECK_MIN (rulep->end_port, CVY_MIN_PORT);
  151. CVY_CHECK_MAX (rulep->end_port, CVY_MAX_PORT);
  152. // TraceMsg(L"#### End port = %d\n", rulep->end_port);
  153. elem = protocol;
  154. break;
  155. case protocol:
  156. switch (ptr [0]) {
  157. case L'T':
  158. case L't':
  159. rulep->protocol = CVY_TCP;
  160. // TraceMsg(L"#### Protocol = TCP\n");
  161. break;
  162. case L'U':
  163. case L'u':
  164. rulep->protocol = CVY_UDP;
  165. // TraceMsg(L"#### Protocol = UDP\n");
  166. break;
  167. default:
  168. rulep->protocol = CVY_TCP_UDP;
  169. // TraceMsg(L"#### Protocol = Both\n");
  170. break;
  171. }
  172. elem = mode;
  173. break;
  174. case mode:
  175. switch (ptr [0]) {
  176. case L'D':
  177. case L'd':
  178. rulep->mode = CVY_NEVER;
  179. // TraceMsg(L"#### Mode = Disabled\n");
  180. goto end_rule;
  181. case L'S':
  182. case L's':
  183. rulep->mode = CVY_SINGLE;
  184. // TraceMsg(L"#### Mode = Single\n");
  185. elem = priority;
  186. break;
  187. default:
  188. rulep->mode = CVY_MULTI;
  189. // TraceMsg(L"#### Mode = Multiple\n");
  190. elem = affinity;
  191. break;
  192. }
  193. break;
  194. case affinity:
  195. switch (ptr [0]) {
  196. case L'C':
  197. case L'c':
  198. rulep->mode_data.multi.affinity = CVY_AFFINITY_CLASSC;
  199. // TraceMsg(L"#### Affinity = Class C\n");
  200. break;
  201. case L'N':
  202. case L'n':
  203. rulep->mode_data.multi.affinity = CVY_AFFINITY_NONE;
  204. // TraceMsg(L"#### Affinity = None\n");
  205. break;
  206. default:
  207. rulep->mode_data.multi.affinity = CVY_AFFINITY_SINGLE;
  208. // TraceMsg(L"#### Affinity = Single\n");
  209. break;
  210. }
  211. elem = load;
  212. break;
  213. case load:
  214. if (ptr [0] == L'E' || ptr [0] == L'e') {
  215. rulep->mode_data.multi.equal_load = TRUE;
  216. rulep->mode_data.multi.load = CVY_DEF_LOAD;
  217. // TraceMsg(L"#### Load = Equal\n");
  218. } else {
  219. rulep->mode_data.multi.equal_load = FALSE;
  220. rulep->mode_data.multi.load = _wtoi(ptr);
  221. // CVY_CHECK_MIN (rulep->mode_data.multi.load, CVY_MIN_LOAD);
  222. CVY_CHECK_MAX (rulep->mode_data.multi.load, CVY_MAX_LOAD);
  223. // TraceMsg(L"#### Load = %d\n", rulep->mode_data.multi.load);
  224. }
  225. goto end_rule;
  226. case priority:
  227. rulep->mode_data.single.priority = _wtoi(ptr);
  228. CVY_CHECK_MIN (rulep->mode_data.single.priority, CVY_MIN_PRIORITY);
  229. CVY_CHECK_MAX (rulep->mode_data.single.priority, CVY_MAX_PRIORITY);
  230. // TraceMsg(L"#### Priority = %d\n", rulep->mode_data.single.priority);
  231. goto end_rule;
  232. default:
  233. // TraceMsg(L"#### Bad rule element %d\n", elem);
  234. break;
  235. }
  236. next_field:
  237. ptr = wcschr(ptr, L',');
  238. if (ptr != NULL) {
  239. ptr ++;
  240. continue;
  241. } else break;
  242. end_rule:
  243. elem = vip;
  244. for (i = 0; i < count; i ++) {
  245. rp = paramp->i_port_rules + i;
  246. if ((rulep -> start_port < rp -> start_port &&
  247. rulep -> end_port >= rp -> start_port) ||
  248. (rulep -> start_port >= rp -> start_port &&
  249. rulep -> start_port <= rp -> end_port)) {
  250. // TraceMsg(L"#### Rule %d (%d - %d) overlaps with rule %d (%d - %d)\n", i, rp -> start_port, rp -> end_port, count, rulep -> start_port, rulep -> end_port);
  251. break;
  252. }
  253. }
  254. wprintf(L"vip = %s, start = %d, end = %d, protocol = %d\n", rulep->virtual_ip_addr, rulep->start_port, rulep->end_port, rulep->protocol);
  255. wprintf(L"mode = %d, affinity = %d, load = %d, %d\n", rulep->mode, rulep->mode_data.multi.affinity, rulep->mode_data.multi.equal_load, rulep->mode_data.multi.load);
  256. wprintf(L"priority = %d\n\n\n", rulep->mode_data.single.priority);
  257. rulep -> valid = TRUE;
  258. CVY_RULE_CODE_SET (rulep);
  259. if (i >= count) {
  260. count++;
  261. rulep++;
  262. if (count >= CVY_MAX_RULES) break;
  263. }
  264. goto next_field;
  265. }
  266. delete paramp;
  267. return ret;
  268. }
  269. int __cdecl wmain(int argc, wchar_t * argv[])
  270. {
  271. DWORD result = 0;
  272. // Good Vip = gv
  273. // No Vip = nv
  274. // Bad Vip = bv
  275. PWCHAR ppGoodRuleStrings[] = {
  276. L"1.2.3.4,20,21,Both,Multiple,Single,Equal\n", // gv
  277. L"1018,1019,UDP,Multiple,None,Equal\n", // nv
  278. L"1.2.3.4,20,21,Both,Multiple,Single,Equal,1018,1019,UDP,Multiple,None,Equal\n", // gv nv
  279. L"1018,1019,UDP,Multiple,None,Equal,1.2.3.4,20,21,Both,Multiple,Single,Equal\n", // nv gv
  280. L"1.2.3.4,20,21,Both,Multiple,Single,Equal,5.6.7.8,20,21,Both,Multiple,Single,Equal\n", // gv gv
  281. L"1018,1019,UDP,Multiple,None,Equal,4018,4019,UDP,Multiple,None,Equal\n", // nv nv
  282. L"1.2.3.4,20,21,Both,Multiple,Single,Equal,1018,1019,UDP,Multiple,None,Equal,4018,4019,UDP,Multiple,None,Equal\n", // gv nv nv
  283. L"1018,1019,UDP,Multiple,None,Equal,1.2.3.4,20,21,Both,Multiple,Single,Equal,4018,4019,UDP,Multiple,None,Equal\n", // nv gv nv
  284. L"1018,1019,UDP,Multiple,None,Equal,4018,4019,UDP,Multiple,None,Equal,1.2.3.4,20,21,Both,Multiple,Single,Equal\n", // nv nv gv
  285. L"1.2.3.4,20,21,Both,Multiple,Single,Equal,5.6.7.8,20,21,Both,Multiple,Single,Equal,1018,1019,UDP,Multiple,None,Equal\n", // gv gv nv
  286. L"1.2.3.4,20,21,Both,Multiple,Single,Equal,1018,1019,UDP,Multiple,None,Equal,5.6.7.8,20,21,Both,Multiple,Single,Equal\n", // gv nv gv
  287. L"1018,1019,UDP,Multiple,None,Equal,1.2.3.4,20,21,Both,Multiple,Single,Equal,5.6.7.8,20,21,Both,Multiple,Single,Equal\n", // nv gv gv
  288. L"all,0,19,Both,Multiple,None,Equal,1.2.3.4,20,21,Both,Multiple,Single,Equal,254.254.254.254,22,138,Both,Multiple,None,Equal,207.46.148.249,139,139,Both,Multiple,Single,Equal,157.54.55.192,140,442,Both,Multiple,None,Equal,443,443,Both,Multiple,Single,Equal\n",
  289. L"111.222.222.111,1018,1018,TCP,Multiple,None,Equal,\n",
  290. NULL
  291. };
  292. PWCHAR ppBadRuleStrings[] = {
  293. L"",
  294. L"\n",
  295. L"111.222.333.111,1018,1018,TCP,Multiple,None,Equal,\n",
  296. L"443,1000,1001,Both,Multiple,Single,Equal\n",
  297. L"1,1000,1001,Both,Multiple,Single,Equal\n",
  298. L"1.1,1000,1001,Both,Multiple,Single,Equal\n",
  299. L"1.1.1,1000,1001,Both,Multiple,Single,Equal\n",
  300. L"allinthefamily,1000,1001,Both,Multiple,Single,Equal\n",
  301. NULL
  302. };
  303. PWCHAR* ptr = ppGoodRuleStrings;
  304. wprintf(L"These rules are valid and should be read properly.\n\n");
  305. while(*ptr != NULL)
  306. {
  307. wprintf(L"Input rule string is = %s", *ptr);
  308. result = testRule(*ptr);
  309. wprintf(L"\n\n\n");
  310. ptr++;
  311. }
  312. wprintf(L"These rules will fail, but should not cause AV, etc.\n\n");
  313. ptr = ppBadRuleStrings;
  314. while(*ptr != NULL)
  315. {
  316. wprintf(L"Input rule string is = %s", *ptr);
  317. result = testRule(*ptr);
  318. wprintf(L"\n\n\n");
  319. ptr++;
  320. }
  321. return 0;
  322. }