FirewallHelper.cpp 60 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585
  1. /*
  2. ** Command & Conquer Generals Zero Hour(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. /***********************************************************************************************
  24. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  25. ***********************************************************************************************
  26. * *
  27. * Project Name : Command & Conquer *
  28. * *
  29. * $Archive:: /RedAlert2/NAT.CPP $*
  30. * *
  31. * $Author:: Steve_t $*
  32. * *
  33. * $Modtime:: 3/15/01 12:00PM $*
  34. * *
  35. * $Revision:: 1 $*
  36. * *
  37. * *
  38. *---------------------------------------------------------------------------------------------*
  39. * *
  40. * *
  41. *---------------------------------------------------------------------------------------------*
  42. * *
  43. * Functions: *
  44. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  45. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  46. #include "Common/crc.h"
  47. #include "Common/UserPreferences.h"
  48. #include "GameNetwork/FirewallHelper.h"
  49. #include "GameNetwork/NAT.h"
  50. #include "GameNetwork/udp.h"
  51. #include "GameNetwork/NetworkDefs.h"
  52. #include "GameNetwork/GameSpy/GSConfig.h"
  53. #ifdef _INTERNAL
  54. // for occasional debugging...
  55. //#pragma optimize("", off)
  56. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  57. #endif
  58. FirewallHelperClass *TheFirewallHelper = NULL;
  59. FirewallHelperClass * createFirewallHelper()
  60. {
  61. return NEW FirewallHelperClass();
  62. }
  63. /***********************************************************************************************
  64. * FirewallHelperClass::FirewallHelperClass -- Constructor *
  65. * *
  66. * *
  67. * *
  68. * INPUT: Nothing *
  69. * *
  70. * OUTPUT: Nothing *
  71. * *
  72. * WARNINGS: None *
  73. * *
  74. * HISTORY: *
  75. * 3/15/01 5:03PM ST : Created *
  76. *=============================================================================================*/
  77. /* static */ Int FirewallHelperClass::m_sourcePortPool = 4096;
  78. FirewallHelperClass::FirewallHelperClass(void)
  79. {
  80. //Added Sadullah Nader
  81. //Initializations missing and needed
  82. m_currentTry = 0;
  83. m_numManglers = 0;
  84. m_numResponses = 0;
  85. m_packetID = 0;
  86. m_timeoutLength = 0;
  87. m_timeoutStart = 0;
  88. //
  89. m_behavior = FIREWALL_TYPE_UNKNOWN;
  90. m_lastBehavior = FIREWALL_TYPE_UNKNOWN;
  91. m_sourcePortAllocationDelta = 0;
  92. m_lastSourcePortAllocationDelta = 0;
  93. for (Int i = 0; i < MAX_SPARE_SOCKETS; ++i) {
  94. m_spareSockets[i].port = 0;
  95. m_messages[i].length = 0;
  96. m_mangledPorts[i] = 0;
  97. m_sparePorts[i] = 0;
  98. }
  99. for (i = 0; i < MAX_NUM_MANGLERS; i++)
  100. {
  101. m_manglers[i] = 0;
  102. }
  103. m_currentState = DETECTIONSTATE_IDLE;
  104. m_sourcePortPool = 4096 + ((timeGetTime() / 1000) % 1000); // do this to make sure we don't use the same source
  105. // port before a previous connection has had a chance
  106. // to time out.
  107. }
  108. /***********************************************************************************************
  109. * FirewallHelperClass::~FirewallHelperClass -- Destructor *
  110. * *
  111. * *
  112. * *
  113. * INPUT: Nothing *
  114. * *
  115. * OUTPUT: Nothing *
  116. * *
  117. * WARNINGS: None *
  118. * *
  119. * HISTORY: *
  120. * 4/16/02 BGC : Created *
  121. *=============================================================================================*/
  122. FirewallHelperClass::~FirewallHelperClass()
  123. {
  124. reset();
  125. }
  126. /***********************************************************************************************
  127. * FirewallHelperClass::Reset -- Cleans out the object *
  128. * *
  129. * *
  130. * *
  131. * INPUT: Nothing *
  132. * *
  133. * OUTPUT: Nothing *
  134. * *
  135. * WARNINGS: None *
  136. * *
  137. * HISTORY: *
  138. * 3/29/01 1:04AM ST : Created *
  139. *=============================================================================================*/
  140. void FirewallHelperClass::reset(void)
  141. {
  142. closeAllSpareSockets();
  143. m_currentState = DETECTIONSTATE_IDLE;
  144. for (Int i = 0; i < MAX_SPARE_SOCKETS; ++i) {
  145. m_messages[i].length = 0;
  146. }
  147. }
  148. /***********************************************************************************************
  149. * FirewallHelperClass::Detect_Firewall -- See what our firewall is up to *
  150. * *
  151. * *
  152. * *
  153. * INPUT: Nothing *
  154. * *
  155. * OUTPUT: Nothing *
  156. * *
  157. * WARNINGS: None *
  158. * *
  159. * HISTORY: *
  160. * 3/15/01 6:47PM ST : Created *
  161. *=============================================================================================*/
  162. Bool FirewallHelperClass::detectFirewall(void)
  163. {
  164. OptionPreferences pref;
  165. OptionPreferences::const_iterator it = pref.find("FirewallNeedToRefresh");
  166. if (it != pref.end()) {
  167. AsciiString str = it->second;
  168. if (str.compareNoCase("TRUE") == 0) {
  169. TheWritableGlobalData->m_firewallBehavior = FIREWALL_TYPE_UNKNOWN;
  170. }
  171. }
  172. if (TheWritableGlobalData->m_firewallBehavior == FIREWALL_TYPE_UNKNOWN) {
  173. detectFirewallBehavior();
  174. return FALSE;
  175. } else {
  176. DEBUG_LOG(("FirewallHelperClass::detectFirewall - firewall behavior already specified as %d, port allocation delta is %d, skipping detection.\n", TheWritableGlobalData->m_firewallBehavior, TheWritableGlobalData->m_firewallPortAllocationDelta));
  177. }
  178. return TRUE;
  179. }
  180. Bool FirewallHelperClass::behaviorDetectionUpdate()
  181. {
  182. if (m_currentState == DETECTIONSTATE_IDLE) {
  183. return FALSE;
  184. }
  185. if (m_currentState == DETECTIONSTATE_DONE) {
  186. return TRUE;
  187. }
  188. if (m_currentState == DETECTIONSTATE_BEGIN) {
  189. return detectionBeginUpdate();
  190. }
  191. if (m_currentState == DETECTIONSTATE_TEST1) {
  192. return detectionTest1Update();
  193. }
  194. if (m_currentState == DETECTIONSTATE_TEST2) {
  195. return detectionTest2Update();
  196. }
  197. if (m_currentState == DETECTIONSTATE_TEST3) {
  198. return detectionTest3Update();
  199. }
  200. if (m_currentState == DETECTIONSTATE_TEST3_WAITFORRESPONSES) {
  201. return detectionTest3WaitForResponsesUpdate();
  202. }
  203. if (m_currentState == DETECTIONSTATE_TEST4_1) {
  204. return detectionTest4Stage1Update();
  205. }
  206. if (m_currentState == DETECTIONSTATE_TEST4_2) {
  207. return detectionTest4Stage2Update();
  208. }
  209. if (m_currentState == DETECTIONSTATE_TEST5) {
  210. return detectionTest5Update();
  211. }
  212. return TRUE;
  213. }
  214. /***********************************************************************************************
  215. * FHC::getNextTemporarySourcePort -- Get a throwaway source port for temporary use *
  216. * *
  217. * *
  218. * *
  219. * INPUT: number of ports in sequence to skip *
  220. * *
  221. * OUTPUT: port number *
  222. * *
  223. * WARNINGS: None *
  224. * *
  225. * HISTORY: *
  226. * 3/15/01 12:06PM ST : Created *
  227. *=============================================================================================*/
  228. UnsignedShort FirewallHelperClass::getNextTemporarySourcePort(Int skip)
  229. {
  230. UnsignedShort return_port = (UnsignedShort) m_sourcePortPool;
  231. /*
  232. ** Try max 256 ports until we find one we can bind to a socket.
  233. */
  234. Int tries = 256;
  235. if (skip == 0) {
  236. skip = 1;
  237. }
  238. while (tries--) {
  239. m_sourcePortPool += skip;
  240. return_port = (UnsignedShort) m_sourcePortPool;
  241. if (m_sourcePortPool > 65535) {
  242. m_sourcePortPool = 2048;
  243. }
  244. /*
  245. ** Validate the port by trying to bind it to a socket.
  246. */
  247. Bool result = openSpareSocket(return_port);
  248. if (result) {
  249. closeSpareSocket(return_port);
  250. return(return_port);
  251. } else {
  252. DEBUG_LOG(("FirewallHelperClass::getNextTemporarySourcePort - failed to open socket on port %d\n"));
  253. }
  254. }
  255. return(return_port);
  256. }
  257. /***********************************************************************************************
  258. * FHC::sendToManglerFromPort -- Send to the mangler from the specified port *
  259. * *
  260. * *
  261. * *
  262. * INPUT: Address of mangler server *
  263. * Source port to send *from* *
  264. * *
  265. * OUTPUT: True if sent OK *
  266. * *
  267. * WARNINGS: None *
  268. * *
  269. * HISTORY: *
  270. * 3/15/01 12:47PM ST : Created *
  271. *=============================================================================================*/
  272. Bool FirewallHelperClass::sendToManglerFromPort(UnsignedInt address, UnsignedShort port, UnsignedShort packetID, Bool blitzme)
  273. {
  274. DEBUG_LOG(("sizeof(ManglerMessage) == %d, sizeof(ManglerData) == %d\n",
  275. sizeof(ManglerMessage), sizeof(ManglerData)));
  276. /*
  277. ** Build the packet to send out.
  278. */
  279. ManglerMessage packet;
  280. memset(&(packet.data),0x44, sizeof(ManglerData));
  281. packet.data.NetCommandType = 12; // mangler request.
  282. packet.data.PacketID = packetID;
  283. if (blitzme) {
  284. packet.data.BlitzMe = 1;
  285. } else {
  286. packet.data.BlitzMe = 0;
  287. }
  288. packet.data.magic = GENERALS_MAGIC_NUMBER;
  289. packet.data.OriginalPortNumber = port;
  290. /*
  291. DEBUG_LOG(("Pre-Adjust Buffer = "));
  292. for (Int i = 0; i < sizeof(ManglerData); ++i) {
  293. DEBUG_LOG(("%02x", *(((unsigned char *)(&(packet.data))) + i)));
  294. }
  295. DEBUG_LOG(("\n"));
  296. */
  297. byteAdjust(&(packet.data));
  298. /*
  299. DEBUG_LOG(("Pre-CRC Buffer = "));
  300. for (i = 0; i < sizeof(ManglerData); ++i) {
  301. DEBUG_LOG(("%02x", *(((unsigned char *)(&(packet.data))) + i)));
  302. }
  303. DEBUG_LOG(("\n"));
  304. */
  305. CRC crc;
  306. crc.computeCRC((unsigned char *)(&(packet.data.magic)), sizeof(ManglerData) - sizeof(unsigned int));
  307. packet.data.CRC = htonl(crc.get());
  308. packet.length = sizeof(ManglerData);
  309. DEBUG_LOG(("FirewallHelperClass::sendToManglerFromPort - Sending from port %d to %d.%d.%d.%d:%d\n", (UnsignedInt)port,
  310. (address & 0xFF000000) >> 24,
  311. (address & 0xFF0000) >> 16,
  312. (address & 0xFF00) >> 8,
  313. (address & 0xFF), MANGLER_PORT));
  314. /*
  315. DEBUG_LOG(("Buffer = "));
  316. for (i = 0; i < sizeof(ManglerData); ++i) {
  317. DEBUG_LOG(("%02x", *(((unsigned char *)(&(packet.data))) + i)));
  318. }
  319. DEBUG_LOG(("\n"));
  320. */
  321. SpareSocketStruct *spareSocket = findSpareSocketByPort(port);
  322. // DEBUG_LOG(("PacketID = %u\n", packetID));
  323. // DEBUG_LOG(("OriginalPortNumber = %u\n", port));
  324. if (spareSocket == NULL) {
  325. DEBUG_ASSERTCRASH(spareSocket != NULL, ("Could not find spare socket for send."));
  326. DEBUG_LOG(("FirewallHelperClass::sendToManglerFromPort - failed to find the spare socket for port %d\n", port));
  327. return FALSE;
  328. }
  329. spareSocket->udp->Write((UnsignedByte *) &packet, sizeof(ManglerData), address, MANGLER_PORT);
  330. return(TRUE);
  331. }
  332. SpareSocketStruct * FirewallHelperClass::findSpareSocketByPort(UnsignedShort port) {
  333. DEBUG_LOG(("FirewallHelperClass::findSpareSocketByPort - trying to find spare socket with port %d\n", port));
  334. for (Int i = 0; i < MAX_SPARE_SOCKETS; ++i) {
  335. if (m_spareSockets[i].port == port) {
  336. DEBUG_LOG(("FirewallHelperClass::findSpareSocketByPort - found it!\n"));
  337. return &(m_spareSockets[i]);
  338. }
  339. }
  340. DEBUG_LOG(("FirewallHelperClass::findSpareSocketByPort - didn't find it\n"));
  341. return NULL;
  342. }
  343. ManglerMessage * FirewallHelperClass::findEmptyMessage() {
  344. for (Int i = 0; i < MAX_SPARE_SOCKETS; ++i) {
  345. if (m_messages[i].length == 0) {
  346. return &(m_messages[i]);
  347. }
  348. }
  349. return NULL;
  350. }
  351. void FirewallHelperClass::byteAdjust(ManglerData *data) {
  352. // for (Int i = 0; i < len/4; ++i) {
  353. // *buf = htonl(*buf);
  354. // ++buf;
  355. // }
  356. data->CRC = htonl(data->CRC);
  357. data->magic = htons(data->magic);
  358. data->MyMangledPortNumber = htons(data->MyMangledPortNumber);
  359. data->OriginalPortNumber = htons(data->OriginalPortNumber);
  360. data->PacketID = htons(data->PacketID);
  361. }
  362. /***********************************************************************************************
  363. * FHC::Get_Mangler_Response_On_Port -- Get the manglers response to a specific query *
  364. * *
  365. * *
  366. * *
  367. * INPUT: Packet id of packet we are looking for *
  368. * *
  369. * OUTPUT: Port the mangler saw this packet come from. *
  370. * *
  371. * WARNINGS: None *
  372. * *
  373. * HISTORY: *
  374. * 3/15/01 12:51PM ST : Created *
  375. *=============================================================================================*/
  376. UnsignedShort FirewallHelperClass::getManglerResponse(UnsignedShort packetID, Int time)
  377. {
  378. ManglerMessage *msg = NULL;
  379. // SpareSocketStruct *spareSocket = NULL;
  380. sockaddr_in addr;
  381. for (Int i = 0; i < MAX_SPARE_SOCKETS; ++i) {
  382. if (m_spareSockets[i].udp != NULL) {
  383. ManglerMessage *message = findEmptyMessage();
  384. if (message == NULL) {
  385. break;
  386. }
  387. Int retval = m_spareSockets[i].udp->Read((unsigned char *)message, sizeof(ManglerData), &addr);
  388. if (retval > 0) {
  389. CRC crc;
  390. crc.computeCRC((unsigned char *)(&(message->data.magic)), sizeof(ManglerData) - sizeof(unsigned int));
  391. if (crc.get() != htonl(message->data.CRC)) {
  392. DEBUG_LOG(("FirewallHelperClass::getManglerResponse - Saw message, CRC mismatch. Expected CRC %u, computed CRC %u\n", message->data.CRC, crc.get()));
  393. continue;
  394. }
  395. byteAdjust(&(message->data));
  396. message->length = retval;
  397. DEBUG_LOG(("FirewallHelperClass::getManglerResponse - Saw message of %d bytes from mangler %d on port %u\n", retval, i, m_spareSockets[i].port));
  398. DEBUG_LOG(("FirewallHelperClass::getManglerResponse - Message has packet ID %d 0x%08X, looking for packet id %d 0x%08X\n", message->data.PacketID, message->data.PacketID, packetID, packetID));
  399. if (message->data.PacketID == packetID) {
  400. DEBUG_LOG(("FirewallHelperClass::getManglerResponse - packet ID's match, returning message\n"));
  401. msg = message;
  402. message->length = 0;
  403. }
  404. if (ntohs(message->data.PacketID) == packetID) {
  405. DEBUG_LOG(("FirewallHelperClass::getManglerResponse - NETWORK BYTE ORDER packet ID's match, returning message\n"));
  406. msg = message;
  407. message->length = 0;
  408. }
  409. }
  410. }
  411. }
  412. // See if we have already received it and saved it.
  413. if (msg == NULL) {
  414. for (i = 0; i < MAX_SPARE_SOCKETS; ++i) {
  415. if ((m_messages[i].length != 0) && (m_messages[i].data.PacketID == packetID)) {
  416. msg = &(m_messages[i]);
  417. msg->length = 0;
  418. }
  419. }
  420. }
  421. if (msg == NULL) {
  422. return 0;
  423. }
  424. UnsignedShort mangled_port = msg->data.MyMangledPortNumber;
  425. DEBUG_LOG(("Mangler is seeing packets from port %d as coming from port %d\n", (UnsignedInt)msg->data.OriginalPortNumber, (UnsignedInt)mangled_port));
  426. return mangled_port;
  427. }
  428. /***********************************************************************************************
  429. * FirewallHelperClass::Write_Firewall_Settings -- Save out firewall settings. *
  430. * *
  431. * *
  432. * *
  433. * INPUT: Nothing *
  434. * *
  435. * OUTPUT: Nothing *
  436. * *
  437. * WARNINGS: None *
  438. * *
  439. * HISTORY: *
  440. * 3/22/01 10:23PM ST : Created *
  441. *=============================================================================================*/
  442. void FirewallHelperClass::writeFirewallBehavior(void)
  443. {
  444. OptionPreferences pref;
  445. char num[16];
  446. num[0] = 0;
  447. itoa(TheGlobalData->m_firewallBehavior, num, 10);
  448. AsciiString numstr;
  449. numstr = num;
  450. (pref)["FirewallBehavior"] = numstr;
  451. TheWritableGlobalData->m_firewallPortAllocationDelta = TheFirewallHelper->getSourcePortAllocationDelta();
  452. num[0] = 0;
  453. itoa(TheGlobalData->m_firewallPortAllocationDelta, num, 10);
  454. numstr = num;
  455. (pref)["FirewallPortAllocationDelta"] = numstr;
  456. pref.write();
  457. }
  458. /***********************************************************************************************
  459. * FirewallHelperClass::flagNeedToRefresh -- Flag that the next time we log in we need to *
  460. * refresh our firewall settings. *
  461. * *
  462. * *
  463. * *
  464. * INPUT: flag - whether or not to refresh...munkee *
  465. * *
  466. * OUTPUT: Nothing *
  467. * *
  468. * WARNINGS: None *
  469. * *
  470. * HISTORY: *
  471. * 2/19/03 4:30PM BGC : Created *
  472. *=============================================================================================*/
  473. void FirewallHelperClass::flagNeedToRefresh(Bool flag)
  474. {
  475. OptionPreferences pref;
  476. (pref)["FirewallNeedToRefresh"] = flag ? AsciiString("TRUE") : AsciiString("FALSE");
  477. pref.write();
  478. }
  479. /***********************************************************************************************
  480. * FirewallHelperClass::Read_Firewall_Behavior -- Read in old firewall settings *
  481. * *
  482. * *
  483. * *
  484. * INPUT: Nothing *
  485. * *
  486. * OUTPUT: Nothing *
  487. * *
  488. * WARNINGS: None *
  489. * *
  490. * HISTORY: *
  491. * 3/22/01 10:25PM ST : Created *
  492. *=============================================================================================*/
  493. void FirewallHelperClass::readFirewallBehavior(void)
  494. {
  495. #if (0)
  496. m_lastBehavior = (FirewallBehaviorType) ConfigINI.Get_Int("MultiPlayer", "FirewallSettings", FIREWALL_UNKNOWN);
  497. m_lastSourcePortAllocationDelta = ConfigINI.Get_Int("MultiPlayer", "FirewallDelta", 1);
  498. #endif //(0)
  499. }
  500. /***********************************************************************************************
  501. * FHC::detectFirewallBehavior -- What is that wacky firewall doing to our packet headers? *
  502. * *
  503. * *
  504. * *
  505. * INPUT: Nothing *
  506. * *
  507. * OUTPUT: Firewall behavior *
  508. * *
  509. * WARNINGS: None *
  510. * *
  511. * HISTORY: *
  512. * 3/15/01 12:30PM ST : Created *
  513. *=============================================================================================*/
  514. void FirewallHelperClass::detectFirewallBehavior(/*Bool &canRecord*/)
  515. {
  516. m_behavior = FIREWALL_TYPE_SIMPLE;
  517. m_currentState = DETECTIONSTATE_BEGIN;
  518. }
  519. FirewallHelperClass::FirewallBehaviorType FirewallHelperClass::getFirewallBehavior() {
  520. m_currentState = DETECTIONSTATE_IDLE;
  521. return m_behavior;
  522. }
  523. Short FirewallHelperClass::getSourcePortAllocationDelta() {
  524. return m_sourcePortAllocationDelta;
  525. }
  526. /* static */ void FirewallHelperClass::getManglerName(Int manglerIndex, Char *nameBuf)
  527. {
  528. AsciiString host;
  529. UnsignedShort port;
  530. TheGameSpyConfig->getManglerLocation(manglerIndex, host, port);
  531. strcpy(nameBuf, host.str());
  532. }
  533. Bool FirewallHelperClass::detectionBeginUpdate() {
  534. // UnsignedShort mangler_port = MANGLER_PORT;
  535. m_packetID = 0x7f00;
  536. //int current_mangler = 0;
  537. /*
  538. ** Well, we are going to need some manglers.
  539. */
  540. UnsignedByte mangler_addresses[4][4];
  541. // Int delta = 0;
  542. /*
  543. ** If the user specified a particular port to use then we act as if there is no firewall.
  544. */
  545. if (TheWritableGlobalData->m_firewallPortOverride != 0) {
  546. m_behavior = FIREWALL_TYPE_SIMPLE;
  547. DEBUG_LOG(("Source port %d specified by user\n", TheGlobalData->m_firewallPortOverride));
  548. if (TheGlobalData->m_firewallSendDelay) {
  549. UnsignedInt addbehavior = FIREWALL_TYPE_NETGEAR_BUG;
  550. addbehavior |= (UnsignedInt)m_behavior;
  551. m_behavior = (FirewallBehaviorType) addbehavior;
  552. DEBUG_LOG(("Netgear bug specified by command line or SendDelay flag\n"));
  553. }
  554. m_currentState = DETECTIONSTATE_DONE;
  555. return TRUE;
  556. }
  557. m_timeoutStart = timeGetTime();
  558. m_timeoutLength = 5000;
  559. DEBUG_LOG(("About to call gethostbyname for the mangler address\n"));
  560. int namenum = 0;
  561. do {
  562. AsciiString host;
  563. UnsignedShort port;
  564. TheGameSpyConfig->getManglerLocation(namenum, host, port);
  565. const char *mangler_name_ptr = host.str();
  566. DEBUG_LOG(("Looking at %s:%d", host.str(), port));
  567. /*
  568. ** Use the wolapi supplied mangler info if available.
  569. */
  570. // if (NumManglerServers > namenum) {
  571. // mangler_name_ptr = &ManglerServerAddress[namenum][0];
  572. // mangler_port = ManglerServerPort[namenum];
  573. //current_mangler = CurrentManglerServer;
  574. // DEBUG_LOG(("Using mangler from servserv\n"));
  575. // }
  576. namenum++;
  577. if (strlen(mangler_name_ptr) == 0) {
  578. break;
  579. }
  580. /*
  581. ** Do the lookup.
  582. */
  583. char temp_name[256];
  584. strcpy(temp_name, mangler_name_ptr);
  585. struct hostent *host_info = gethostbyname(temp_name);
  586. if (!host_info) {
  587. DEBUG_LOG(("gethostbyname failed! Error code %d\n", WSAGetLastError()));
  588. break;
  589. }
  590. /*
  591. ** See if we already have that address in the list.
  592. */
  593. Bool found = FALSE;
  594. for (Int i=0 ; i<m_numManglers; i++) {
  595. if (memcmp(mangler_addresses[i], &host_info->h_addr_list[0][0], 4) == 0) {
  596. found = TRUE;
  597. break;
  598. }
  599. }
  600. /*
  601. ** Add the address in if we didn't find it.
  602. */
  603. if (!found) {
  604. Int m = m_numManglers++;
  605. memcpy(&mangler_addresses[m][0], &host_info->h_addr_list[0][0], 4);
  606. ntohl((UnsignedInt)mangler_addresses[m]);
  607. DEBUG_LOG(("Found mangler address at %d.%d.%d.%d\n", mangler_addresses[m][0], mangler_addresses[m][1], mangler_addresses[m][2], mangler_addresses[m][3]));
  608. }
  609. } while ((m_numManglers < MAX_NUM_MANGLERS) && ((timeGetTime() - m_timeoutStart) < m_timeoutLength));
  610. DEBUG_ASSERTCRASH(m_numManglers > 2, ("not enough mangler addresses found."));
  611. if (m_numManglers < 3) {
  612. m_currentState = DETECTIONSTATE_DONE;
  613. return TRUE;
  614. }
  615. for (Int i=0 ; i<m_numManglers ; i++) {
  616. UnsignedInt temp = 0;
  617. temp = mangler_addresses[i][3];
  618. temp += mangler_addresses[i][2] << 8;
  619. temp += mangler_addresses[i][1] << 16;
  620. temp += mangler_addresses[i][0] << 24;
  621. m_manglers[i] = temp;
  622. // memcpy(&(m_manglers[i]), &mangler_addresses[i][0], 4);
  623. }
  624. DEBUG_LOG(("FirewallHelperClass::detectionBeginUpdate - Testing for Netgear bug\n"));
  625. /*
  626. ** See if the user specified a netgear firewall - that will save us the trouble.
  627. */
  628. if (TheGlobalData->m_firewallSendDelay) {
  629. UnsignedInt addbehavior = FIREWALL_TYPE_NETGEAR_BUG;
  630. addbehavior |= (UnsignedInt)m_behavior;
  631. m_behavior = (FirewallBehaviorType) addbehavior;
  632. DEBUG_LOG(("FirewallHelperClass::detectionBeginUpdate - Netgear bug specified by command line or SendDelay flag\n"));
  633. } else {
  634. DEBUG_LOG(("FirewallHelperClass::detectionBeginUpdate - Netgear bug not specified\n"));
  635. }
  636. /*
  637. ** OK, we have our manglers.
  638. **
  639. ** First test, see if there is any port mangling at all.
  640. **
  641. **
  642. **
  643. */
  644. DEBUG_LOG(("About to start mangler test 1\n"));
  645. /*
  646. ** Get a spare port number and create a new socket to bind it to.
  647. */
  648. m_sparePorts[0] = getNextTemporarySourcePort(0);
  649. if (!openSpareSocket(m_sparePorts[0])) {
  650. m_currentState = DETECTIONSTATE_DONE;
  651. return TRUE;
  652. }
  653. /*
  654. ** Send to the mangler from this port until we get a response.
  655. */
  656. m_timeoutStart = timeGetTime();
  657. m_timeoutLength = 6000;
  658. sendToManglerFromPort(m_manglers[0], m_sparePorts[0], m_packetID);
  659. m_currentState = DETECTIONSTATE_TEST1;
  660. return FALSE;
  661. }
  662. Bool FirewallHelperClass::detectionTest1Update() {
  663. m_mangledPorts[0] = getManglerResponse(m_packetID);
  664. /*
  665. ** See if we got no response or a non-mangled response.
  666. */
  667. if (m_mangledPorts[0] == 0 || m_mangledPorts[0] == m_sparePorts[0]) {
  668. if (m_mangledPorts[0] == m_sparePorts[0]) {
  669. m_sourcePortAllocationDelta = 0;
  670. DEBUG_LOG(("FirewallHelperClass::detectionTest1Update - Non-mangled response from mangler, quitting test.\n"));
  671. }
  672. if ((m_mangledPorts[0] == 0) && ((timeGetTime() - m_timeoutStart) < m_timeoutLength)) {
  673. // we are still waiting for a response and haven't timed out yet.
  674. DEBUG_LOG(("FirewallHelperClass::detectionTest1Update - waiting for response from mangler.\n"));
  675. return FALSE;
  676. }
  677. if ((m_mangledPorts[0] == 0) && ((timeGetTime() - m_timeoutStart) >= m_timeoutLength)) {
  678. // we are still waiting for a response and we timed out.
  679. DEBUG_LOG(("FirewallHelperClass::detectionTest1Update - timed out waiting for response from mangler.\n"));
  680. }
  681. // either we have received a non-mangled response or we timed out waiting for a response.
  682. closeSpareSocket(m_sparePorts[0]);
  683. m_currentState = DETECTIONSTATE_DONE;
  684. return TRUE;
  685. }
  686. DEBUG_LOG(("FirewallHelperClass::detectionTest1Update - test 1 complete\n"));
  687. /*
  688. ** Test one completed, time to start up the second test.
  689. **
  690. ** Second test. See if the ports are mangled differently for different destination IPs.
  691. **
  692. ** We can use the spare socket from the last test and send to a different mangler.
  693. **
  694. */
  695. /*
  696. ** Send to the mangler from this port until we get a response.
  697. */
  698. m_timeoutStart = timeGetTime();
  699. m_timeoutLength = 6000;
  700. m_mangledPorts[1] = 0;
  701. sendToManglerFromPort(m_manglers[1], m_sparePorts[0], m_packetID+1);
  702. m_currentState = DETECTIONSTATE_TEST2;
  703. return FALSE;
  704. }
  705. Bool FirewallHelperClass::detectionTest2Update() {
  706. m_mangledPorts[1] = getManglerResponse(m_packetID+1);
  707. if (m_mangledPorts[1] == 0) {
  708. if ((timeGetTime() - m_timeoutStart) <= m_timeoutLength) {
  709. return FALSE;
  710. }
  711. DEBUG_LOG(("FirewallHelperClass::detectionTest2Update - timed out waiting for mangler response\n"));
  712. m_currentState = DETECTIONSTATE_DONE;
  713. return TRUE;
  714. }
  715. /*
  716. ** We are done with this socket/port
  717. */
  718. closeSpareSocket(m_sparePorts[0]);
  719. /*
  720. ** See if we got no response or a non-mangled response.
  721. */
  722. if (m_mangledPorts[1] == 0 || m_mangledPorts[1] == m_sparePorts[0]) {
  723. m_currentState = DETECTIONSTATE_DONE;
  724. UnsignedInt addBehavior = (UnsignedInt)FIREWALL_TYPE_SIMPLE;
  725. addBehavior |= (UnsignedInt)m_behavior;
  726. m_behavior = (FirewallBehaviorType)addBehavior;
  727. if (m_mangledPorts[1] == 0) {
  728. DEBUG_LOG(("FirewallHelperClass::detectionTest2Update - got no response from mangler\n"));
  729. } else {
  730. DEBUG_LOG(("FirewallHelperClass::detectionTest2Update - got a mangler response, no port mangling\n"));
  731. }
  732. DEBUG_LOG(("FirewallHelperClass::detectionTest2Update - Setting behavior to SIMPLE, done testing\n"));
  733. return TRUE;
  734. }
  735. if (m_mangledPorts[0] == m_mangledPorts[1]) {
  736. DEBUG_LOG(("FirewallHelperClass::detectionTest2Update - port mangling doesn't depend on destination IP, setting to DUMB_MANGLING\n"));
  737. UnsignedInt addBehavior = (UnsignedInt)FIREWALL_TYPE_DUMB_MANGLING;
  738. addBehavior |= (UnsignedInt)m_behavior;
  739. m_behavior = (FirewallBehaviorType)addBehavior;
  740. } else {
  741. DEBUG_LOG(("FirewallHelperClass::detectionTest2Update - port mangling depends on destination IP, setting to SMART_MANGLING\n"));
  742. UnsignedInt addBehavior = (UnsignedInt)FIREWALL_TYPE_SMART_MANGLING;
  743. addBehavior |= (UnsignedInt)m_behavior;
  744. m_behavior = (FirewallBehaviorType)addBehavior;
  745. }
  746. /*
  747. ** Third test.
  748. **
  749. ** This test tries to detect a pattern in the ports allocated by the NAT.
  750. ** We use several source ports for this one.
  751. **
  752. */
  753. m_currentTry = 0;
  754. m_packetID = m_packetID + 10;
  755. DEBUG_LOG(("FirewallHelperClass::detectionTest2Update - moving on to 3rd test\n"));
  756. m_currentState = DETECTIONSTATE_TEST3;
  757. return FALSE;
  758. }
  759. Bool FirewallHelperClass::detectionTest3Update() {
  760. /*
  761. ** Try this whole thing a max of 3 times.
  762. */
  763. if (m_currentTry < 3) {
  764. memset(m_sparePorts, 0, sizeof(m_sparePorts));
  765. memset(m_mangledPorts, 0, sizeof(m_mangledPorts));
  766. /*
  767. ** Open a socket for each source port.
  768. ** We should use a non-linear set of source ports so we can detect the NAT32 relative offset
  769. ** case.
  770. */
  771. for (Int i=0 ; i<NUM_TEST_PORTS ; i++) {
  772. m_sparePorts[i] = getNextTemporarySourcePort(i);
  773. if (!openSpareSocket(m_sparePorts[i])) {
  774. /*
  775. ** Close any spare ports we allocated already before we bail.
  776. */
  777. for (Int j=0 ; j<i ; j++) {
  778. if (m_sparePorts[j]) {
  779. closeSpareSocket(m_sparePorts[j]);
  780. }
  781. }
  782. DEBUG_LOG(("FirewallHelperClass::detectionTest3Update - Failed to open all the spare sockets, bailing test\n"));
  783. m_currentState = DETECTIONSTATE_DONE;
  784. return TRUE;
  785. }
  786. }
  787. /*
  788. ** OK, lets get some numbers from the mangler.
  789. **
  790. ** Keep sending from each port until we get a response to all the sends. There's a implied
  791. ** delay between initial sends due to the timeout in Get_Mangler_Response.
  792. */
  793. m_timeoutStart = timeGetTime();
  794. m_timeoutLength = 12000;
  795. DEBUG_LOG(("FirewallHelperClass::detectionTest3Update - Sending to %d manglers\n", NUM_TEST_PORTS));
  796. for (i=0 ; i<NUM_TEST_PORTS ; i++) {
  797. if (m_mangledPorts[i] == 0) {
  798. sendToManglerFromPort(m_manglers[0], m_sparePorts[i], m_packetID+i);
  799. }
  800. }
  801. m_numResponses = 0;
  802. m_currentState = DETECTIONSTATE_TEST3_WAITFORRESPONSES;
  803. DEBUG_LOG(("FirewallHelperClass::detectionTest3Update - Waiting for mangler responses\n"));
  804. return FALSE;
  805. }
  806. DEBUG_LOG(("FirewallHelperClass::detectionTest3Update - Failed to complete test, quitting\n"));
  807. m_currentState = DETECTIONSTATE_DONE;
  808. return TRUE;
  809. }
  810. Bool FirewallHelperClass::detectionTest3WaitForResponsesUpdate() {
  811. for (Int i = 0; i < NUM_TEST_PORTS; ++i) {
  812. if (m_mangledPorts[i] == 0) {
  813. m_mangledPorts[i] = getManglerResponse(m_packetID + i);
  814. if (m_mangledPorts[i] != 0) {
  815. ++m_numResponses;
  816. }
  817. }
  818. }
  819. if (m_numResponses < NUM_TEST_PORTS) {
  820. if ((timeGetTime() - m_timeoutStart) > m_timeoutLength) {
  821. /*
  822. ** Close down those sockets - we are finished with them.
  823. */
  824. for (Int j=0 ; j<i ; j++) {
  825. if (m_spareSockets[j].port != 0) {
  826. closeSpareSocket(m_spareSockets[j].port);
  827. }
  828. }
  829. DEBUG_LOG(("FirewallHelperClass::detectionTest3WaitForResponsesUpdate - timed out waiting, bailing test\n"));
  830. m_currentState = DETECTIONSTATE_DONE;
  831. return TRUE;
  832. }
  833. return FALSE;
  834. }
  835. /*
  836. ** Close down those sockets - we are finished with them.
  837. */
  838. for (Int j=0 ; j<i ; j++) {
  839. if (m_spareSockets[j].port != 0) {
  840. closeSpareSocket(m_spareSockets[j].port);
  841. }
  842. }
  843. /*
  844. ** We need at least 4 responses to be sure of the port allocation scheme.
  845. */
  846. if (m_numResponses < 4) {
  847. if (m_lastSourcePortAllocationDelta != 0 && (int)m_lastBehavior > (int)FIREWALL_TYPE_SIMPLE) {
  848. /*
  849. ** If the delta we got last time we played looks good then use that.
  850. */
  851. m_sourcePortAllocationDelta = m_lastSourcePortAllocationDelta;
  852. }
  853. DEBUG_LOG(("FirewallHelperClass::detectionTest3WaitForResponsesUpdate - didn't get enough responses, using %d as the source port allocation delta, finished test\n"));
  854. m_currentState = DETECTIONSTATE_DONE;
  855. return TRUE;
  856. }
  857. Bool relative_delta = FALSE;
  858. Bool looks_good = FALSE;
  859. Int delta = getNATPortAllocationScheme(m_numResponses, m_sparePorts, m_mangledPorts, relative_delta, looks_good);
  860. DEBUG_LOG(("FirewallHelperClass::detectionTest3WaitForResponsesUpdate - getNATPortAllocationScheme returned %d\n", delta));
  861. if (delta) {
  862. /*
  863. ** Hey, we got it!
  864. */
  865. UnsignedInt addbehavior = 0;
  866. if (relative_delta) {
  867. DEBUG_LOG(("FirewallHelperClass::detectionTest3WaitForResponsesUpdate - detected RELATIVE PORT ALLOCATION\n"));
  868. addbehavior = (UnsignedInt)FIREWALL_TYPE_RELATIVE_PORT_ALLOCATION;
  869. } else {
  870. DEBUG_LOG(("FirewallHelperClass::detectionTest3WaitForResponsesUpdate - detected SIMPLE PORT ALLOCATION\n"));
  871. addbehavior = (UnsignedInt)FIREWALL_TYPE_SIMPLE_PORT_ALLOCATION;
  872. }
  873. addbehavior |= (UnsignedInt)m_behavior;
  874. m_behavior = (FirewallBehaviorType) addbehavior;
  875. m_sourcePortAllocationDelta = delta;
  876. DEBUG_LOG(("FirewallHelperClass::detectionTest3WaitForResponsesUpdate - setting source port delta to %d\n", delta));
  877. } else {
  878. DEBUG_LOG(("FirewallHelperClass::detectionTest3WaitForResponsesUpdate - didn't get a delta value\n"));
  879. if (m_lastSourcePortAllocationDelta != 0 && (Int)m_lastBehavior > (Int)FIREWALL_TYPE_SIMPLE) {
  880. /*
  881. ** If the delta we got last time we played looks good then use that.
  882. */
  883. DEBUG_LOG(("FirewallHelperClass::detectionTest3WaitForResponsesUpdate - using the port allocation delta we have from before which is %d\n", m_lastSourcePortAllocationDelta));
  884. m_sourcePortAllocationDelta = m_lastSourcePortAllocationDelta;
  885. }
  886. ++m_currentTry;
  887. m_currentState = DETECTIONSTATE_TEST3;
  888. return FALSE;
  889. }
  890. DEBUG_LOG(("FirewallHelperClass::detectionTest3WaitForRepsonsesUpdate - starting 4th test\n"));
  891. /*
  892. ** Fourth test.
  893. **
  894. ** Test to see if the NAT mangles differently per destination port at the same IP.
  895. */
  896. if ((m_behavior & FIREWALL_TYPE_SMART_MANGLING) != 0) {
  897. if ((m_behavior & FIREWALL_TYPE_SIMPLE_PORT_ALLOCATION) != 0) {
  898. DEBUG_LOG(("FirewallHelperClass::detectionTest3WaitForRepsonsesUpdate - simple port allocation, Testing to see if the NAT mangles differently per destination port at the same IP\n"));
  899. /*
  900. ** We need 2 source ports for this.
  901. */
  902. m_sparePorts[0] = getNextTemporarySourcePort(0);
  903. if (!openSpareSocket(m_sparePorts[0])) {
  904. m_currentState = DETECTIONSTATE_DONE;
  905. DEBUG_LOG(("FirewallHelperClass::detectionTest3WaitForRepsonsesUpdate - Failed to open first spare port, bailing\n"));
  906. return TRUE;
  907. }
  908. m_sparePorts[1] = getNextTemporarySourcePort(0);
  909. if (!openSpareSocket(m_sparePorts[1])) {
  910. closeSpareSocket(m_sparePorts[0]);
  911. m_currentState = DETECTIONSTATE_DONE;
  912. DEBUG_LOG(("FirewallHelperClass::detectionTest3WaitForRepsonsesUpdate - Failed to open second spare port, bailing\n"));
  913. return TRUE;
  914. }
  915. /*
  916. ** Get a reference port.
  917. */
  918. m_timeoutStart = timeGetTime();
  919. m_timeoutLength = 4000;
  920. m_mangledPorts[0] = 0;
  921. m_packetID += 10;
  922. /*
  923. ** Wait for a response.
  924. */
  925. sendToManglerFromPort(m_manglers[0], m_sparePorts[0], m_packetID);
  926. m_currentState = DETECTIONSTATE_TEST4_1;
  927. return FALSE;
  928. } else {
  929. /*
  930. ** NAT32 uses different mangled source ports for different destination ports.
  931. */
  932. DEBUG_LOG(("FirewallHelperClass::detectionTest3WaitForRepsonsesUpdate - relative port allocation, NAT32 right?\n"));
  933. UnsignedInt addbehavior = 0;
  934. addbehavior = (UnsignedInt)FIREWALL_TYPE_DESTINATION_PORT_DELTA;
  935. DEBUG_LOG(("FirewallHelperClass::detectionTest3WaitForRepsonsesUpdate - adding DESTINATION PORT DELTA to behavior\n"));
  936. addbehavior |= (UnsignedInt)m_behavior;
  937. m_behavior = (FirewallBehaviorType) addbehavior;
  938. }
  939. } else {
  940. DEBUG_LOG(("FirewallHelperClass::detectionTest3WaitForResponsesUpdate - We don't have smart mangling, skipping test 4, entering test 5\n"));
  941. }
  942. DEBUG_LOG(("FirewallHelperClass::detectionTest3WaitForRepsonsesUpdate - entering test 5\n"));
  943. m_currentState = DETECTIONSTATE_TEST5;
  944. return FALSE;
  945. }
  946. Bool FirewallHelperClass::detectionTest4Stage1Update() {
  947. m_mangledPorts[0] = getManglerResponse(m_packetID);
  948. if (m_mangledPorts[0] == 0) {
  949. if ((timeGetTime() - m_timeoutStart) > m_timeoutLength) {
  950. closeSpareSocket(m_sparePorts[0]);
  951. closeSpareSocket(m_sparePorts[1]);
  952. m_currentState = DETECTIONSTATE_DONE;
  953. DEBUG_LOG(("FirewallHelperClass::detectionTest4Stage1Update - timed out waiting for mangler response, quitting\n"));
  954. return TRUE;
  955. }
  956. return FALSE;
  957. }
  958. /*
  959. ** Send out to a different port at that IP.
  960. ** We won't get a response for this.
  961. */
  962. UnsignedInt addr = m_manglers[0];
  963. UnsignedShort port1 = m_sparePorts[0] + 1;
  964. sendToManglerFromPort(addr, port1, m_packetID);
  965. sendToManglerFromPort(addr, port1, m_packetID);
  966. sendToManglerFromPort(addr, port1, m_packetID);
  967. /*
  968. ** We can't get a response from a different destination port so the only way to detect
  969. ** this behavior is to check the next mangled port allocation to see if it's double
  970. ** what we would normally expect.
  971. */
  972. m_packetID++;
  973. m_timeoutStart = timeGetTime();
  974. m_timeoutLength = 4000;
  975. sendToManglerFromPort(m_manglers[0], m_sparePorts[1], m_packetID);
  976. m_currentState = DETECTIONSTATE_TEST4_2;
  977. return FALSE;
  978. }
  979. Bool FirewallHelperClass::detectionTest4Stage2Update() {
  980. m_mangledPorts[1] = getManglerResponse(m_packetID);
  981. if (m_mangledPorts[1] == 0) {
  982. if ((timeGetTime() - m_timeoutStart) > m_timeoutLength) {
  983. closeSpareSocket(m_sparePorts[0]);
  984. closeSpareSocket(m_sparePorts[1]);
  985. m_currentState = DETECTIONSTATE_DONE;
  986. DEBUG_LOG(("FirewallHelperClass::detectionTest4Stage2Update - timed out waiting for the second mangler response, quitting\n"));
  987. return TRUE;
  988. }
  989. return FALSE;
  990. }
  991. if (m_mangledPorts[1] != m_mangledPorts[0] + m_sourcePortAllocationDelta) {
  992. DEBUG_LOG(("FirewallHelperClass::detectionTest4Stage2Update - NAT uses different source ports for different destination ports\n"));
  993. UnsignedInt addbehavior = 0;
  994. addbehavior = (UnsignedInt)FIREWALL_TYPE_DESTINATION_PORT_DELTA;
  995. addbehavior |= (UnsignedInt)m_behavior;
  996. m_behavior = (FirewallBehaviorType) addbehavior;
  997. } else {
  998. DEBUG_ASSERTCRASH(m_mangledPorts[1] == m_mangledPorts[0] + m_sourcePortAllocationDelta, ("Problem getting the source port deltas."));
  999. if (m_mangledPorts[1] == m_mangledPorts[0] + m_sourcePortAllocationDelta) {
  1000. DEBUG_LOG(("FirewallHelperClass::detectionTest4Stage2Update - NAT uses the same source port for different destination ports\n"));
  1001. } else {
  1002. DEBUG_LOG(("FirewallHelperClass::detectionTest4Stage2Update - Unable to complete destination port mangling test\n"));
  1003. DEBUG_CRASH(("Unable to complete destination port mangling test\n"));
  1004. }
  1005. }
  1006. m_currentState = DETECTIONSTATE_TEST5;
  1007. return detectionTest5Update();
  1008. }
  1009. Bool FirewallHelperClass::detectionTest5Update() {
  1010. /*
  1011. ** We have done all the tests we *have* to. There's other info that it would be nice to know though.
  1012. **
  1013. ** Test for the netgear bug behavior.
  1014. */
  1015. #if (0)
  1016. // moved to before test 1. Moved because this flag could be specified for another firewall
  1017. // for testing purposes and never get this far because it has behavior that doesn't require
  1018. // all the tests to be performed.
  1019. // BGC 10/1/02
  1020. DEBUG_LOG(("FirewallHelperClass::detectionTest5Update - Testing for Netgear bug\n"));
  1021. /*
  1022. ** See if the user specified a netgear firewall - that will save us the trouble.
  1023. */
  1024. if (TheGlobalData->m_firewallSendDelay) {
  1025. UnsignedInt addbehavior = FIREWALL_TYPE_NETGEAR_BUG;
  1026. addbehavior |= (UnsignedInt)m_behavior;
  1027. m_behavior = (FirewallBehaviorType) addbehavior;
  1028. DEBUG_LOG(("FirewallHelperClass::detectionTest5Update - Netgear bug specified by command line or SendDelay flag\n"));
  1029. } else {
  1030. DEBUG_LOG(("FirewallHelperClass::detectionTest5Update - Netgear bug not specified\n"));
  1031. }
  1032. #endif // #if (0)
  1033. DEBUG_LOG(("FirewallHelperClass::detectionTest5Update - All done, behavior is: "));
  1034. if ((m_behavior & FIREWALL_TYPE_SIMPLE) != 0) {
  1035. DEBUG_LOG((" FIREWALL_TYPE_SIMPLE "));
  1036. }
  1037. if ((m_behavior & FIREWALL_TYPE_DUMB_MANGLING) != 0) {
  1038. DEBUG_LOG((" FIREWALL_TYPE_DUMB_MANGLING "));
  1039. }
  1040. if ((m_behavior & FIREWALL_TYPE_SMART_MANGLING) != 0) {
  1041. DEBUG_LOG((" FIREWALL_TYPE_SMART_MANGLING "));
  1042. }
  1043. if ((m_behavior & FIREWALL_TYPE_NETGEAR_BUG) != 0) {
  1044. DEBUG_LOG((" FIREWALL_TYPE_NETGEAR_BUG "));
  1045. }
  1046. if ((m_behavior & FIREWALL_TYPE_SIMPLE_PORT_ALLOCATION) != 0) {
  1047. DEBUG_LOG((" FIREWALL_TYPE_SIMPLE_PORT_ALLOCATION "));
  1048. }
  1049. if ((m_behavior & FIREWALL_TYPE_RELATIVE_PORT_ALLOCATION) != 0) {
  1050. DEBUG_LOG((" FIREWALL_TYPE_RELATIVE_PORT_ALLOCATION "));
  1051. }
  1052. if ((m_behavior & FIREWALL_TYPE_DESTINATION_PORT_DELTA) != 0) {
  1053. DEBUG_LOG((" FIREWALL_TYPE_DESTINATION_PORT_DELTA "));
  1054. }
  1055. DEBUG_LOG(("\n"));
  1056. m_currentState = DETECTIONSTATE_DONE;
  1057. return TRUE;
  1058. }
  1059. /***********************************************************************************************
  1060. * FHC::Get_NAT_Port_Allocation_Scheme -- Find out how a NAT is allocating ports *
  1061. * *
  1062. * *
  1063. * *
  1064. * INPUT: Number of ports we should analyze *
  1065. * List of original port numbers *
  1066. * List of mangled port numbers *
  1067. * relative_delta (out) Is the delta relative to the original port number? *
  1068. * looks_good (out) Do all the values point to the same delta? *
  1069. * *
  1070. * OUTPUT: Port allocation delta *
  1071. * *
  1072. * WARNINGS: None *
  1073. * *
  1074. * HISTORY: *
  1075. * 3/15/01 4:45PM ST : Created *
  1076. *=============================================================================================*/
  1077. Int FirewallHelperClass::getNATPortAllocationScheme(Int numPorts, UnsignedShort *originalPorts, UnsignedShort *mangledPorts, Bool &relativeDelta, Bool &looksGood)
  1078. {
  1079. DEBUG_ASSERTCRASH(numPorts > 3, ("numPorts too small"));
  1080. DEBUG_LOG(("Looking for port allocation pattern in originalPorts %d, %d, %d, %d\n", originalPorts[0], originalPorts[1], originalPorts[2], originalPorts[3]));
  1081. /*
  1082. ** Sort the mangled ports into order - should be easier to detect patterns.
  1083. ** Stupid bubble sort will do. original_ports may be out of oder after the sort.
  1084. */
  1085. for (Int x=0 ; x<numPorts ; x++) {
  1086. for (Int y=0 ; y<numPorts-1 ; y++) {
  1087. if (mangledPorts[y] > mangledPorts[y+1]) {
  1088. Int temp = mangledPorts[y];
  1089. mangledPorts[y] = mangledPorts[y+1];
  1090. mangledPorts[y+1] = temp;
  1091. temp = originalPorts[y];
  1092. originalPorts[y] = originalPorts[y+1];
  1093. originalPorts[y+1] = temp;
  1094. }
  1095. }
  1096. }
  1097. /*
  1098. ** Now start looking for patterns in the port numbers. Possible patterns include.
  1099. **
  1100. ** Incremental. Port numbers are allocated incrementally.
  1101. ** Every 'n' ports. NAT adds 'n' port numbers when allocating ports.
  1102. **
  1103. ** Also, schemes may be absolute or relative to the original port number.
  1104. */
  1105. /*
  1106. ** 1. Check for absolute sequential allocation.
  1107. */
  1108. if (mangledPorts[1] - mangledPorts[0] == 1) {
  1109. if (mangledPorts[2] - mangledPorts[1] == 1) {
  1110. if (mangledPorts[3] - mangledPorts[2] == 1) {
  1111. DEBUG_LOG(("Incremental port allocation detected\n"));
  1112. relativeDelta = FALSE;
  1113. looksGood = TRUE;
  1114. return(1);
  1115. }
  1116. }
  1117. }
  1118. /*
  1119. ** 2. Check for semi sequential.
  1120. */
  1121. if (mangledPorts[1] - mangledPorts[0] == 2) {
  1122. if (mangledPorts[2] - mangledPorts[1] == 2) {
  1123. if (mangledPorts[3] - mangledPorts[2] == 2) {
  1124. DEBUG_LOG(("Semi-incremental port allocation detected\n"));
  1125. relativeDelta = FALSE;
  1126. looksGood = TRUE;
  1127. return(2);
  1128. }
  1129. }
  1130. }
  1131. Int diff1 = mangledPorts[1] - mangledPorts[0];
  1132. Int diff2 = mangledPorts[2] - mangledPorts[1];
  1133. Int diff3 = mangledPorts[3] - mangledPorts[2];
  1134. /*
  1135. ** 3. Check for absolute scheme skipping 'n' ports.
  1136. */
  1137. if (diff1 == diff2 && diff2 == diff3) {
  1138. DEBUG_LOG(("Looks good for absolute allocation sequence delta of %d\n", diff1));
  1139. relativeDelta = FALSE;
  1140. looksGood = TRUE;
  1141. return(diff1);
  1142. }
  1143. if (diff1 == diff2) {
  1144. DEBUG_LOG(("Probable absolute allocation sequence delta of %d\n", diff1));
  1145. relativeDelta = FALSE;
  1146. looksGood = FALSE;
  1147. return(diff1);
  1148. }
  1149. if (diff2 == diff3) {
  1150. DEBUG_LOG(("Probable absolute allocation sequence delta of %d\n", diff2));
  1151. relativeDelta = FALSE;
  1152. looksGood = FALSE;
  1153. return(diff2);
  1154. }
  1155. /*
  1156. ** Insert more tests here if we can think of any!!!!!
  1157. */
  1158. /*
  1159. ** 4. Check for relative scheme skipping 'n' ports. NAT32 behaves this way, it skips 100 ports
  1160. ** each time.
  1161. */
  1162. for (Int i=0 ; i<numPorts ; i++) {
  1163. mangledPorts[i] -= originalPorts[i];
  1164. }
  1165. diff1 = mangledPorts[1] - mangledPorts[0];
  1166. diff2 = mangledPorts[2] - mangledPorts[1];
  1167. diff3 = mangledPorts[3] - mangledPorts[2];
  1168. /*
  1169. ** Look for a linear pattern.
  1170. */
  1171. if (diff1 == diff2 && diff2 == diff3) {
  1172. /*
  1173. ** Return a -ve result to indicate that port mangling is relative.
  1174. */
  1175. DEBUG_LOG(("Looks good for a relative port range delta of %d\n", diff1));
  1176. relativeDelta = TRUE;
  1177. looksGood = TRUE;
  1178. return(diff1);
  1179. }
  1180. /*
  1181. ** Look for a broken pattern. Maybe the NAT skipped a whole range.
  1182. */
  1183. if (diff1 == diff2 || diff1 == diff3) {
  1184. DEBUG_LOG(("Detected probable broken relative port range delta of %d\n", diff1));
  1185. relativeDelta = TRUE;
  1186. looksGood = FALSE;
  1187. return(diff1);
  1188. }
  1189. if (diff2 == diff3) {
  1190. DEBUG_LOG(("Detected probable broken relative port range delta of %d\n", diff2));
  1191. relativeDelta = TRUE;
  1192. looksGood = FALSE;
  1193. return(diff2);
  1194. }
  1195. /*
  1196. ** Aw hell, I don't know what it is.
  1197. */
  1198. looksGood = FALSE;
  1199. relativeDelta = FALSE;
  1200. return(0);
  1201. }
  1202. /***********************************************************************************************
  1203. * FHC::Get_Firewall_Hardness -- How hard is it to connect to this firewall *
  1204. * *
  1205. * *
  1206. * *
  1207. * INPUT: Firewall behavior *
  1208. * *
  1209. * OUTPUT: Hardness *
  1210. * *
  1211. * WARNINGS: None *
  1212. * *
  1213. * HISTORY: *
  1214. * 3/16/01 11:43AM ST : Created *
  1215. *=============================================================================================*/
  1216. Int FirewallHelperClass::getFirewallHardness(FirewallBehaviorType behavior)
  1217. {
  1218. Int hardness = 0;
  1219. UnsignedInt fw = (UnsignedInt) behavior;
  1220. if (((UnsignedInt)FIREWALL_TYPE_SIMPLE & fw) != 0) {
  1221. hardness++;
  1222. }
  1223. if (((UnsignedInt)FIREWALL_TYPE_DUMB_MANGLING & fw) != 0) {
  1224. hardness += 2;
  1225. }
  1226. if (((UnsignedInt)FIREWALL_TYPE_SMART_MANGLING & fw) != 0) {
  1227. hardness += 3;
  1228. }
  1229. if (((UnsignedInt)FIREWALL_TYPE_NETGEAR_BUG & fw) != 0) {
  1230. hardness += 10;
  1231. }
  1232. if (((UnsignedInt)FIREWALL_TYPE_SIMPLE_PORT_ALLOCATION & fw) != 0) {
  1233. hardness += 1;
  1234. }
  1235. if (((UnsignedInt)FIREWALL_TYPE_RELATIVE_PORT_ALLOCATION & fw) != 0) {
  1236. hardness += 2;
  1237. }
  1238. return(hardness);
  1239. }
  1240. /***********************************************************************************************
  1241. * FHC::Get_Firewall_Retries -- How many retries is it likely to take before we connect? *
  1242. * *
  1243. * *
  1244. * *
  1245. * INPUT: Firewall behavior *
  1246. * *
  1247. * OUTPUT: Hardness *
  1248. * *
  1249. * WARNINGS: None *
  1250. * *
  1251. * HISTORY: *
  1252. * 3/16/01 11:43AM ST : Created *
  1253. *=============================================================================================*/
  1254. Int FirewallHelperClass::getFirewallRetries(FirewallBehaviorType behavior)
  1255. {
  1256. Int retries = 2;
  1257. UnsignedInt fw = (UnsignedInt) behavior;
  1258. if (((UnsignedInt)FIREWALL_TYPE_SIMPLE & fw) != 0) {
  1259. retries++;
  1260. }
  1261. if (((UnsignedInt)FIREWALL_TYPE_DUMB_MANGLING & fw) != 0) {
  1262. retries += 1;
  1263. }
  1264. if (((UnsignedInt)FIREWALL_TYPE_SMART_MANGLING & fw) != 0) {
  1265. retries += 1;
  1266. }
  1267. if (((UnsignedInt)FIREWALL_TYPE_NETGEAR_BUG & fw) != 0) {
  1268. //retries += 10;
  1269. }
  1270. if (((UnsignedInt)FIREWALL_TYPE_SIMPLE_PORT_ALLOCATION & fw) != 0) {
  1271. //retries += 1;
  1272. }
  1273. if (((UnsignedInt)FIREWALL_TYPE_RELATIVE_PORT_ALLOCATION & fw) != 0) {
  1274. retries += 5;
  1275. }
  1276. return(retries);
  1277. }
  1278. /*
  1279. * openSpareSocket - opens a socket for communication on a specified port.
  1280. * returns TRUE if successful, FALSE otherwise.
  1281. */
  1282. Bool FirewallHelperClass::openSpareSocket(UnsignedShort port) {
  1283. for (Int i = 0; i < MAX_SPARE_SOCKETS; ++i) {
  1284. if (m_spareSockets[i].port == 0) {
  1285. break;
  1286. }
  1287. }
  1288. // don't have room for any more spare sockets. Fail.
  1289. if (i == MAX_SPARE_SOCKETS) {
  1290. DEBUG_ASSERTCRASH(i < MAX_SPARE_SOCKETS, ("Ran out of spare sockets."));
  1291. return FALSE;
  1292. }
  1293. m_spareSockets[i].udp = NEW UDP();
  1294. if (m_spareSockets[i].udp == NULL) {
  1295. DEBUG_LOG(("FirewallHelperClass::openSpareSocket - failed to create UDP object\n"));
  1296. return FALSE;
  1297. }
  1298. if (m_spareSockets[i].udp->Bind((UnsignedInt)0, port) != 0) {
  1299. DEBUG_CRASH(("FirewallHelperClass::openSpareSocket - Failed to init spare socket"));
  1300. return FALSE;
  1301. }
  1302. m_spareSockets[i].port = port;
  1303. DEBUG_LOG(("FirewallHelperClass::openSpareSocket - port %d is open for send\n", port));
  1304. return TRUE;
  1305. }
  1306. /*
  1307. * closeSpareSocket - closes a socket at a specific port.
  1308. */
  1309. void FirewallHelperClass::closeSpareSocket(UnsignedShort port) {
  1310. for (Int i = 0; i < MAX_SPARE_SOCKETS; ++i) {
  1311. if (m_spareSockets[i].port == port) {
  1312. if (m_spareSockets[i].udp != NULL) {
  1313. delete m_spareSockets[i].udp;
  1314. m_spareSockets[i].udp = NULL;
  1315. }
  1316. m_spareSockets[i].port = 0;
  1317. break;
  1318. }
  1319. }
  1320. }
  1321. /*
  1322. * closeAllSpareSockets - closes all spare sockets, duh.
  1323. */
  1324. void FirewallHelperClass::closeAllSpareSockets() {
  1325. for (Int i = 0; i < MAX_SPARE_SOCKETS; ++i) {
  1326. if (m_spareSockets[i].port != 0) {
  1327. m_spareSockets[i].port = 0;
  1328. }
  1329. if (m_spareSockets[i].udp != NULL) {
  1330. delete (m_spareSockets[i].udp);
  1331. m_spareSockets[i].udp = NULL;
  1332. }
  1333. }
  1334. }