NAT.cpp 138 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690
  1. /*
  2. ** Command & Conquer Renegade(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. *** 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 ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Command & Conquer *
  23. * *
  24. * $Archive:: /Commando/Code/Commando/NAT.cpp $*
  25. * *
  26. * $Author:: Steve_t $*
  27. * *
  28. * $Modtime:: 3/26/02 3:04p $*
  29. * *
  30. * $Revision:: 37 $*
  31. * *
  32. * *
  33. *---------------------------------------------------------------------------------------------*
  34. * *
  35. * *
  36. *---------------------------------------------------------------------------------------------*
  37. * *
  38. * Functions: *
  39. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  40. /*
  41. ** Disable warning about exception handling not being enabled.
  42. */
  43. #pragma warning(disable : 4530)
  44. #include "always.h"
  45. #include <windows.h>
  46. #include "systimer.h"
  47. #include <snmp.h>
  48. #include <stddef.h>
  49. #include <process.h>
  50. #include "crandom.h"
  51. #include "except.h"
  52. #include "nat.h"
  53. #include "natsock.h"
  54. #include "nataddr.h"
  55. #include "slavemaster.h"
  56. #include "gamedata.h"
  57. /*
  58. ** Set this flag in the debugger to cause the client to fail to connect.
  59. */
  60. //bool CrapFlag = false;
  61. /*
  62. ** Single instance of firewall helper class.
  63. */
  64. FirewallHelperClass FirewallHelper;
  65. /***********************************************************************************************
  66. * FirewallHelperClass::FirewallHelperClass -- Constructor *
  67. * *
  68. * *
  69. * *
  70. * INPUT: Nothing *
  71. * *
  72. * OUTPUT: Nothing *
  73. * *
  74. * WARNINGS: None *
  75. * *
  76. * HISTORY: *
  77. * 3/15/01 5:03PM ST : Created *
  78. *=============================================================================================*/
  79. FirewallHelperClass::FirewallHelperClass(void)
  80. {
  81. Behavior = FIREWALL_TYPE_UNKNOWN;
  82. LastBehavior = FIREWALL_TYPE_UNKNOWN;
  83. SourcePortAllocationDelta = 0;
  84. LastSourcePortAllocationDelta = 0;
  85. NumManglerServers = 0;
  86. CurrentManglerServer = -1;
  87. SourcePortPool = 0;
  88. ThreadActive = false;
  89. ThreadState = THREAD_IDLE;
  90. ThreadEvent = INVALID_HANDLE_VALUE;
  91. NATThreadMutex = CreateMutex(NULL, false, NULL);
  92. NATDataMutex = CreateMutex(NULL, false, NULL);
  93. ThreadHandle = INVALID_HANDLE_VALUE;
  94. QueueNotifyPtr = NULL;
  95. SuccessFlagPtr = NULL;
  96. CancelPlayer[0] = 0;
  97. SendDelay = false;
  98. Confidence = 0;
  99. }
  100. /***********************************************************************************************
  101. * FirewallHelperClass::Startup -- Start up the firewall thread *
  102. * *
  103. * *
  104. * *
  105. * INPUT: Nothing *
  106. * *
  107. * OUTPUT: Nothing *
  108. * *
  109. * WARNINGS: None *
  110. * *
  111. * HISTORY: *
  112. * 8/31/2001 12:35PM ST : Created *
  113. *=============================================================================================*/
  114. void FirewallHelperClass::Startup(void)
  115. {
  116. /*
  117. ** Start the firewall thread.
  118. */
  119. WWDEBUG_SAY(("FirewallHelper: Starting firewall thread\n"));
  120. ThreadState = THREAD_IDLE;
  121. ThreadEvent = INVALID_HANDLE_VALUE;
  122. ThreadActive = true;
  123. //ThreadHandle = CreateThread(NULL, 128*1024, &NAT_Thread_Start, this, 0, &ThreadID);
  124. ThreadHandle = (HANDLE)_beginthreadex(NULL, 128*1024, &NAT_Thread_Start, this, 0, (unsigned int*)&ThreadID);
  125. fw_assert(ThreadHandle != NULL);
  126. }
  127. /***********************************************************************************************
  128. * FirewallHelperClass::Shutdown -- Shut down the firewall thread *
  129. * *
  130. * *
  131. * *
  132. * INPUT: Nothing *
  133. * *
  134. * OUTPUT: Nothing *
  135. * *
  136. * WARNINGS: None *
  137. * *
  138. * HISTORY: *
  139. * 8/31/2001 12:35PM ST : Created *
  140. *=============================================================================================*/
  141. void FirewallHelperClass::Shutdown(void)
  142. {
  143. if (ThreadActive) {
  144. WWDEBUG_SAY(("FirewallHelper: Stopping firewall thread\n"));
  145. /*
  146. ** Signal the thread to go away.
  147. */
  148. ThreadActive = false;
  149. /*
  150. ** Wait for the thread to go away.
  151. */
  152. int deadlock = WaitForSingleObject(NATThreadMutex, 5 * 1000);
  153. if (deadlock == WAIT_TIMEOUT) {
  154. WWDEBUG_SAY(("FirewallHelperClass - Timeout waiting for firewall thread mutex\n"));
  155. fw_assert(deadlock != WAIT_TIMEOUT);
  156. } else {
  157. ReleaseMutex(NATThreadMutex);
  158. }
  159. }
  160. // Release the thread
  161. if (INVALID_HANDLE_VALUE != ThreadHandle) {
  162. CloseHandle(ThreadHandle);
  163. ThreadHandle = INVALID_HANDLE_VALUE;
  164. }
  165. }
  166. /***********************************************************************************************
  167. * FirewallHelperClass::Set_Firewall_Info -- Set firewall info from the game *
  168. * *
  169. * *
  170. * *
  171. * INPUT: last_behavior - how the firewall behaved last time we tried it *
  172. * last_delta - the firewalls last known good port delta *
  173. * port_pool - base port number to use when allocating temporary ports *
  174. * send_delay - value of send delay flag used for netgear firewalls. *
  175. * *
  176. * OUTPUT: Nothing *
  177. * *
  178. * WARNINGS: None *
  179. * *
  180. * HISTORY: *
  181. * 8/20/2001 12:16PM ST : Created *
  182. *=============================================================================================*/
  183. void FirewallHelperClass::Set_Firewall_Info(unsigned long last_behavior, int last_delta, unsigned short port_pool, bool send_delay, int confidence)
  184. {
  185. if (port_pool) {
  186. SourcePortPool = port_pool;
  187. } else {
  188. if (SourcePortPool == 0) {
  189. SourcePortPool = PORT_POOL_MIN + FreeRandom.Get_Int(0, 32768);
  190. }
  191. }
  192. LastBehavior = (FirewallBehaviorType) last_behavior;
  193. LastSourcePortAllocationDelta = last_delta;
  194. SendDelay = send_delay;
  195. Confidence = confidence;
  196. }
  197. /***********************************************************************************************
  198. * FirewallHelperClass::Set_Firewall_Info -- Set firewall info from the game *
  199. * *
  200. * *
  201. * *
  202. * INPUT: last_behavior - how the firewall behaved last time we tried it *
  203. * last_delta - the firewalls last known good port delta *
  204. * port_pool - base port number to use when allocating temporary ports *
  205. * send_delay - value of send delay flag used for netgear firewalls. *
  206. * *
  207. * OUTPUT: Nothing *
  208. * *
  209. * WARNINGS: None *
  210. * *
  211. * HISTORY: *
  212. * 8/20/2001 12:16PM ST : Created *
  213. *=============================================================================================*/
  214. void FirewallHelperClass::Get_Firewall_Info(unsigned long &last_behavior, int &last_delta, unsigned short &port_pool, bool &send_delay, int &confidence) const
  215. {
  216. port_pool = SourcePortPool;
  217. last_behavior = (unsigned long) LastBehavior;
  218. last_delta = LastSourcePortAllocationDelta;
  219. send_delay = SendDelay;
  220. confidence = Confidence;
  221. }
  222. /***********************************************************************************************
  223. * *
  224. * *
  225. * *
  226. * *
  227. * INPUT: Nothing *
  228. * *
  229. * OUTPUT: Nothing *
  230. * *
  231. * WARNINGS: None *
  232. * *
  233. * HISTORY: *
  234. * 8/7/2001 2:15PM ST : Created *
  235. *=============================================================================================*/
  236. FirewallHelperClass::~FirewallHelperClass(void)
  237. {
  238. Shutdown();
  239. CloseHandle(NATThreadMutex);
  240. CloseHandle(NATDataMutex);
  241. }
  242. /***********************************************************************************************
  243. * FirewallHelperClass::NAT_Thread_Start -- Thread start for NAT thread *
  244. * *
  245. * *
  246. * *
  247. * INPUT: This ptr *
  248. * *
  249. * OUTPUT: Undefined *
  250. * *
  251. * WARNINGS: None *
  252. * *
  253. * HISTORY: *
  254. * 8/7/2001 2:39PM ST : Created *
  255. *=============================================================================================*/
  256. unsigned int __stdcall FirewallHelperClass::NAT_Thread_Start(void *thisptr)
  257. {
  258. unsigned int thread_exit_code = 0;
  259. Register_Thread_ID(GetCurrentThreadId(), "Firewall thread");
  260. __try {
  261. thread_exit_code = ((FirewallHelperClass*)thisptr)->NAT_Thread_Main_Loop();
  262. } __except(Exception_Handler(GetExceptionCode(), GetExceptionInformation())) {};
  263. Unregister_Thread_ID(GetCurrentThreadId(), "Firewall thread");
  264. return(thread_exit_code);
  265. }
  266. /***********************************************************************************************
  267. * FirewallHelperClass::NAT_Thread_Main_Loop -- Main loop for NAT thread *
  268. * *
  269. * *
  270. * *
  271. * INPUT: Nothing *
  272. * *
  273. * OUTPUT: Nothing *
  274. * *
  275. * WARNINGS: None *
  276. * *
  277. * HISTORY: *
  278. * 8/7/2001 2:42PM ST : Created *
  279. *=============================================================================================*/
  280. unsigned long FirewallHelperClass::NAT_Thread_Main_Loop(void)
  281. {
  282. /*
  283. ** Take ownership of the thread mutex.
  284. */
  285. int deadlock = WaitForSingleObject(NATThreadMutex, 10 * 1000);
  286. if (deadlock == WAIT_TIMEOUT) {
  287. WWDEBUG_SAY(("FirewallHelperClass - Timeout waiting for thread mutex\n"));
  288. fw_assert(deadlock != WAIT_TIMEOUT);
  289. }
  290. /*
  291. ** Thread main loop.
  292. */
  293. while (ThreadActive) {
  294. /*
  295. ** Always do some sleeping here since this thread is a relatively low priority compared to stuff like running the
  296. ** game engine.
  297. ** If we are not doing anything much then sleep for longer.
  298. */
  299. if (ThreadState == THREAD_IDLE && ThreadQueue.Count() == 0) {
  300. Sleep(50);
  301. } else {
  302. Sleep(0);
  303. }
  304. /*
  305. ** Check for incoming private game options packets.
  306. */
  307. Process_Game_Options();
  308. /*
  309. ** Lock data access while we process each loop.
  310. */
  311. ThreadLockClass locker(this);
  312. switch (ThreadState) {
  313. /*
  314. ** Idle state, no activity required.
  315. */
  316. case THREAD_IDLE:
  317. /*
  318. ** See if there is a pending thread action to execute.
  319. */
  320. if (ThreadQueue.Count()) {
  321. ThreadState = ThreadQueue[0].ThreadAction;
  322. ThreadEvent = ThreadQueue[0].ThreadEvent;
  323. //delete ThreadQueue[0];
  324. ThreadQueue.Delete(0);
  325. } else {
  326. if (WOLNATInterface.Am_I_Server()) {
  327. if (ClientQueue.Count()) {
  328. WWDEBUG_SAY(("Client with no thread action!\n"));
  329. Add_Thread_Action(THREAD_CONNECT_FIREWALL, INVALID_HANDLE_VALUE);
  330. }
  331. }
  332. }
  333. break;
  334. /*
  335. ** Time to connect to another player.
  336. */
  337. case THREAD_CONNECT_FIREWALL:
  338. {
  339. int connected = Negotiate_Port();
  340. if (connected == FW_RESULT_SUCCEEDED && !WOLNATInterface.Am_I_Server()) {
  341. WOLNATInterface.Set_Server_Negotiated_Address(&PlayersFirewallAddress);
  342. }
  343. Set_Client_Success(connected);
  344. ThreadState = THREAD_CONNECT_FIREWALL_DONE;
  345. break;
  346. }
  347. /*
  348. ** Connection done, signal as required.
  349. */
  350. case THREAD_CONNECT_FIREWALL_DONE:
  351. Set_Thread_Event();
  352. Send_Queue_States();
  353. ThreadState = THREAD_IDLE;
  354. break;
  355. /*
  356. ** Detect the firewall settings.
  357. */
  358. case THREAD_DETECT_FIREWALL:
  359. Behavior = Detect_Firewall_Behavior();
  360. WWDEBUG_SAY(("FirewallHelper: Behavior is = %08x\n", (unsigned long)Behavior));
  361. ThreadState = THREAD_DETECT_FIREWALL_DONE;
  362. Set_Thread_Event();
  363. break;
  364. /*
  365. ** Detection done, signal as required.
  366. */
  367. case THREAD_DETECT_FIREWALL_DONE:
  368. Set_Thread_Event();
  369. ThreadState = THREAD_IDLE;
  370. break;
  371. /*
  372. ** Get the local chat connection address.
  373. */
  374. case THREAD_GET_LOCAL_ADDRESS:
  375. Get_Local_Chat_Connection_Address();
  376. ThreadState = THREAD_IDLE;
  377. break;
  378. /*
  379. ** We finished getting the local chat connection address.
  380. */
  381. case THREAD_GET_LOCAL_ADDRESS_DONE:
  382. ThreadState = THREAD_IDLE;
  383. Set_Thread_Event();
  384. break;
  385. default:
  386. fw_assert(false);
  387. break;
  388. }
  389. }
  390. ReleaseMutex(NATThreadMutex);
  391. return(0);
  392. }
  393. /***********************************************************************************************
  394. * FirewallHelperClass::Reset -- Causes a re-detect of the firewall *
  395. * *
  396. * *
  397. * *
  398. * INPUT: Nothing *
  399. * *
  400. * OUTPUT: Nothing *
  401. * *
  402. * WARNINGS: None *
  403. * *
  404. * HISTORY: *
  405. * 3/29/01 1:04AM ST : Created *
  406. *=============================================================================================*/
  407. void FirewallHelperClass::Reset(void)
  408. {
  409. ThreadLockClass locker(this);
  410. Behavior = FIREWALL_TYPE_UNKNOWN;
  411. }
  412. /***********************************************************************************************
  413. * FirewallHelperClass::Reset_Server -- Reset server side variables *
  414. * *
  415. * *
  416. * *
  417. * INPUT: Nothing *
  418. * *
  419. * OUTPUT: Nothing *
  420. * *
  421. * WARNINGS: None *
  422. * *
  423. * HISTORY: *
  424. * 8/10/2001 3:23PM ST : Created *
  425. *=============================================================================================*/
  426. void FirewallHelperClass::Reset_Server(void)
  427. {
  428. ConnectionHistory.Delete_All();
  429. MangledPortHistory.Delete_All();
  430. }
  431. /***********************************************************************************************
  432. * FirewallHelperClass::Detect_Firewall -- See what our firewall is up to *
  433. * *
  434. * *
  435. * *
  436. * INPUT: Nothing *
  437. * *
  438. * OUTPUT: Nothing *
  439. * *
  440. * WARNINGS: None *
  441. * *
  442. * HISTORY: *
  443. * 3/15/01 6:47PM ST : Created *
  444. *=============================================================================================*/
  445. void FirewallHelperClass::Detect_Firewall(HANDLE event)
  446. {
  447. ThreadLockClass locker(this);
  448. if (Behavior == FIREWALL_TYPE_UNKNOWN) {
  449. Add_Thread_Action(THREAD_DETECT_FIREWALL, event);
  450. } else {
  451. SetEvent(event);
  452. }
  453. }
  454. /***********************************************************************************************
  455. * FirewallHelperClass::Connected_To_WWOnline_Server *
  456. * *
  457. * *
  458. * *
  459. * INPUT: Nothing *
  460. * *
  461. * OUTPUT: Nothing *
  462. * *
  463. * WARNINGS: None *
  464. * *
  465. * HISTORY: *
  466. * 8/7/2001 10:02PM ST : Created *
  467. *=============================================================================================*/
  468. void FirewallHelperClass::Connected_To_WWOnline_Server(void)
  469. {
  470. /*
  471. ** Don't need to go through this again if we already got the local chat connection address.
  472. */
  473. if (!LocalChatConnectionAddress.Is_Valid()) {
  474. /*
  475. ** Get the local chat connection address.
  476. */
  477. ThreadLockClass locker(this);
  478. Add_Thread_Action(THREAD_GET_LOCAL_ADDRESS, INVALID_HANDLE_VALUE);
  479. }
  480. }
  481. /***********************************************************************************************
  482. * FHC::Get_Next_Temporary_Source_Port -- Get a throwaway source port for temporary use *
  483. * *
  484. * *
  485. * *
  486. * INPUT: number of ports in sequence to skip *
  487. * *
  488. * OUTPUT: port number *
  489. * *
  490. * WARNINGS: None *
  491. * *
  492. * HISTORY: *
  493. * 3/15/01 12:06PM ST : Created *
  494. *=============================================================================================*/
  495. unsigned short FirewallHelperClass::Get_Next_Temporary_Source_Port(int skip)
  496. {
  497. unsigned short return_port = (unsigned short) SourcePortPool;
  498. /*
  499. ** Try max 256 ports until we find one we can bind to a socket.
  500. */
  501. int tries = 256;
  502. if (skip == 0) {
  503. skip = 1;
  504. }
  505. while (tries--) {
  506. SourcePortPool += skip;
  507. return_port = (unsigned short) SourcePortPool;
  508. if (SourcePortPool > PORT_POOL_MAX) {
  509. SourcePortPool = PORT_POOL_MIN;
  510. }
  511. /*
  512. ** Validate the port by trying to bind it to a socket.
  513. */
  514. SocketHandlerClass *temp = new SocketHandlerClass;
  515. bool result = temp->Open(return_port, 0);
  516. delete temp;
  517. if (result) {
  518. return(return_port);
  519. }
  520. }
  521. return(return_port);
  522. }
  523. /***********************************************************************************************
  524. * FHC::Send_To_Mangler -- Send to the mangler from the specified socket handler *
  525. * *
  526. * *
  527. * *
  528. * INPUT: Address of mangler server *
  529. * Socket handler to use when sending *
  530. * ID to insert into the packet *
  531. * blitzme flag (obsolete, must be false) *
  532. * *
  533. * OUTPUT: True if sent OK *
  534. * *
  535. * WARNINGS: None *
  536. * *
  537. * HISTORY: *
  538. * 3/15/01 12:47PM ST : Created *
  539. *=============================================================================================*/
  540. bool FirewallHelperClass::Send_To_Mangler(IPAddressClass *address, SocketHandlerClass *socket_handler, unsigned long packet_id, bool blitzme)
  541. {
  542. /*
  543. ** Build the packet to send out.
  544. */
  545. unsigned char packet_buf[512];
  546. int packet_size = Build_Mangler_Packet(packet_buf, socket_handler->Get_Incoming_Port(), packet_id, blitzme);
  547. WWDEBUG_SAY(("FirewallHelper: Sending from port %d to %s\n", (unsigned int)(socket_handler->Get_Incoming_Port()), address->As_String()));
  548. /*
  549. ** Send it.
  550. */
  551. socket_handler->Write(packet_buf, packet_size, address, address->Get_Port());
  552. return(true);
  553. }
  554. /***********************************************************************************************
  555. * FHC::Get_Mangler_Response -- Get the manglers response to a specific query *
  556. * *
  557. * *
  558. * *
  559. * INPUT: Packet id of packet we are looking for *
  560. * Ptr to socket handler class to query for packets *
  561. * Timeout, 0=default *
  562. * service_all - true if all sockets should be serviced *
  563. * *
  564. * OUTPUT: Port the mangler saw this packet come from. *
  565. * *
  566. * WARNINGS: None *
  567. * *
  568. * HISTORY: *
  569. * 3/15/01 12:51PM ST : Created *
  570. *=============================================================================================*/
  571. unsigned short FirewallHelperClass::Get_Mangler_Response(unsigned long packet_id, SocketHandlerClass *socket_handler, int time, bool all_service)
  572. {
  573. /*
  574. ** Locals.
  575. */
  576. int peek_packet = 0;
  577. CnCPacketType *packet;
  578. unsigned char packet_buf[1024];
  579. int packet_size = sizeof(packet_buf);
  580. IPAddressClass address;
  581. unsigned long id;
  582. unsigned long timeout = TIMEGETTIME();
  583. unsigned char temp_address[4];
  584. unsigned short temp_port;
  585. /*
  586. ** Asserts.
  587. */
  588. fw_assert(socket_handler != NULL);
  589. if (time) {
  590. timeout += (unsigned long) time;
  591. } else {
  592. timeout += (unsigned long) TIMER_SECOND;
  593. }
  594. while (timeout > TIMEGETTIME()) {
  595. if (all_service) {
  596. SocketHandlerClass::Service_All();
  597. } else {
  598. socket_handler->Service();
  599. }
  600. /*
  601. ** Get a copy of the global packet we want to examine. This doesn't remove it from the queue.
  602. */
  603. int result = socket_handler->Peek(packet_buf, packet_size, &temp_address, &temp_port, peek_packet);
  604. /*
  605. ** Check if we got a packet from the mangler.
  606. */
  607. if (result) {
  608. packet = (CnCPacketType*)packet_buf;
  609. if (packet->Packet.Command == NET_MANGLER_RESPONSE) {
  610. WWDEBUG_SAY(("FirewallHelper: Got NET_MANGLER_RESPONSE packet\n"));
  611. /*
  612. ** We got a mangler packet, see if it's the one we are looking for.
  613. */
  614. #ifdef WWDEBUG
  615. int original_port = packet->Packet.ManglerData.OriginalPortNumber;
  616. #endif //WWDEBUG
  617. id = packet->GHeader.Header.PacketID;
  618. if (packet_id == id) {
  619. /*
  620. ** Looks good, lets get the mangled port number out.
  621. */
  622. unsigned short mangled_port = packet->Packet.ManglerData.MangledPortNumber;
  623. WWDEBUG_SAY(("FirewallHelper: Mangler is seeing packets from port %d as coming from port %d\n", (unsigned int)original_port, (unsigned int)mangled_port));
  624. /*
  625. ** Now the mangled address. This should never change.
  626. */
  627. ExternalAddress.Set_Address(packet->Packet.ManglerData.MangledAddress);
  628. WWDEBUG_SAY(("FirewallHelper: Mangler is seeing our packets coming from address %s\n", ExternalAddress.As_String()));
  629. /*
  630. ** Remove the packet from the queue.
  631. */
  632. result = socket_handler->Read(packet_buf, packet_size, &temp_address, &temp_port, peek_packet);
  633. fw_assert(result != NULL);
  634. return(mangled_port);
  635. }
  636. }
  637. peek_packet++;
  638. } else {
  639. peek_packet = 0;
  640. }
  641. Sleep(0);
  642. }
  643. return(0);
  644. }
  645. /***********************************************************************************************
  646. * FHC::Detect_Firewall_Behavior -- What is that wacky firewall doing to our packet headers? *
  647. * *
  648. * *
  649. * *
  650. * INPUT: Nothing *
  651. * *
  652. * OUTPUT: Firewall behavior *
  653. * *
  654. * WARNINGS: None *
  655. * *
  656. * HISTORY: *
  657. * 3/15/01 12:30PM ST : Created *
  658. *=============================================================================================*/
  659. FirewallHelperClass::FirewallBehaviorType FirewallHelperClass::Detect_Firewall_Behavior(void)
  660. {
  661. unsigned short mangler_port = 4321;
  662. char temp_mangler_name[128];
  663. unsigned long packet_id = 0x7f000000;
  664. /*
  665. ** Well, we are going to need some manglers.
  666. */
  667. static char _manglername[5][80] = {
  668. "mangler1.westwood.com",
  669. "mangler2.westwood.com",
  670. "mangler3.westwood.com",
  671. "mangler.westwood.com",
  672. ""
  673. };
  674. unsigned char mangler_addresses[4][4];
  675. int num_mangler_addresses = 0;
  676. FirewallBehaviorType behavior = FIREWALL_TYPE_SIMPLE;
  677. IPAddressClass manglers[4];
  678. unsigned long timeout;
  679. int mangler_index_offset = 0;
  680. unsigned short source_ports[NUM_TEST_PORTS];
  681. unsigned short mangled_ports[NUM_TEST_PORTS];
  682. SocketHandlerClass *port_sockets[NUM_TEST_PORTS];
  683. int delta = 0;
  684. bool save_firewall_type = true;
  685. bool looks_good = true;
  686. /*
  687. ** Figure out which mangler to use this time. Pick randomly from the available manglers.
  688. */
  689. NumManglerServers = WOLNATInterface.Get_Num_Mangler_Servers();
  690. if (CurrentManglerServer == -1) {
  691. CurrentManglerServer = FreeRandom.Get_Int(0, NumManglerServers-1);
  692. WWDEBUG_SAY(("FirewallHelper - Using mangler server %d\n", CurrentManglerServer));
  693. }
  694. /*
  695. ** If the user specified a particular port to use then we act as if there is no firewall.
  696. */
  697. if (WOLNATInterface.Get_Force_Port()) {
  698. behavior = FIREWALL_TYPE_SIMPLE;
  699. WWDEBUG_SAY(("FirewallHelper: Source port %d specified by user\n", WOLNATInterface.Get_Force_Port()));
  700. if (SendDelay) {
  701. unsigned long addbehavior = FIREWALL_TYPE_NETGEAR_BUG;
  702. addbehavior |= (unsigned long)behavior;
  703. behavior = (FirewallBehaviorType) addbehavior;
  704. WWDEBUG_SAY(("FirewallHelper: Netgear bug specified by command line or SendDelay flag\n"));
  705. }
  706. return(behavior);
  707. }
  708. /*
  709. ** Slave servers inherit their firewall info from the master server.
  710. */
  711. if (SlaveMaster.Am_I_Slave()) {
  712. behavior = LastBehavior;
  713. SourcePortAllocationDelta = LastSourcePortAllocationDelta;
  714. ExternalAddress.Set_Address(WOLNATInterface.Get_Reg_External_IP(), WOLNATInterface.Get_Reg_External_Port());
  715. return(behavior);
  716. }
  717. timeout = TIMEGETTIME() + (5*TIMER_SECOND);
  718. WWDEBUG_SAY(("FirewallHelper: About to call gethostbyname for the mangler address\n"));
  719. int namenum = 0;
  720. /*
  721. ** Convert the list of mangler servers to numeric IP addresses.
  722. **
  723. */
  724. do {
  725. char *mangler_name_ptr = &_manglername[namenum][0];
  726. /*
  727. ** Use the wolapi supplied mangler info if available.
  728. */
  729. bool got_name = WOLNATInterface.Get_Mangler_Name_By_Index(namenum, temp_mangler_name);
  730. if (got_name) {
  731. mangler_name_ptr = temp_mangler_name;
  732. unsigned short servserv_port = WOLNATInterface.Get_Mangler_Port_By_Index(namenum);
  733. fw_assert(servserv_port != 0);
  734. if (servserv_port) {
  735. mangler_port = servserv_port;
  736. }
  737. WWDEBUG_SAY(("FirewallHelper - Using mangler server from servserv - address is %s ; %d\n", mangler_name_ptr, mangler_port));
  738. } else {
  739. WWDEBUG_SAY(("FirewallHelper - Using default mangler name for mangler %d\n", namenum));
  740. }
  741. namenum++;
  742. if (strlen(mangler_name_ptr) == 0) {
  743. break;
  744. }
  745. /*
  746. ** Do the lookup.
  747. */
  748. char temp_name[256];
  749. strcpy(temp_name, mangler_name_ptr);
  750. struct hostent *host_info = gethostbyname(temp_name);
  751. if (!host_info) {
  752. WWDEBUG_SAY(("FirewallHelper: gethostbyname failed! Error code %d\n", WSAGetLastError()));
  753. break;
  754. }
  755. /*
  756. ** See if we already have that address in the list.
  757. */
  758. bool found = false;
  759. for (int i=0 ; i<num_mangler_addresses ; i++) {
  760. if (memcmp(mangler_addresses[i], &host_info->h_addr_list[0][0], 4) == 0) {
  761. found = true;
  762. break;
  763. }
  764. }
  765. /*
  766. ** Add the address in if we didn't find it.
  767. */
  768. if (!found) {
  769. int m = num_mangler_addresses++;
  770. memcpy(&mangler_addresses[m][0], &host_info->h_addr_list[0][0], 4);
  771. WWDEBUG_SAY(("FirewallHelper: 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]));
  772. }
  773. } while (num_mangler_addresses < 4 && TIMEGETTIME() < timeout);
  774. /*
  775. ** We need a certain number of manglers to be able to do the detection.
  776. */
  777. fw_assert(num_mangler_addresses > 2);
  778. if (num_mangler_addresses < 3) {
  779. WWDEBUG_SAY(("FirewallHelper: Not enough manglers - returning default behavior\n"));
  780. if (Confidence > 0) {
  781. behavior = LastBehavior;
  782. SourcePortAllocationDelta = LastSourcePortAllocationDelta;
  783. }
  784. return(behavior);
  785. }
  786. /*
  787. ** Convert the mangler addresses to IPAddressClass format.
  788. */
  789. for (int i=0 ; i<num_mangler_addresses ; i++) {
  790. unsigned char addr[4];
  791. memcpy(addr, &mangler_addresses[i][0], 4);
  792. manglers[i].Set_Address(addr, mangler_port);
  793. }
  794. /*
  795. ** OK, we have our manglers.
  796. **
  797. ** First test, see if there is any port mangling at all.
  798. **
  799. **
  800. **
  801. */
  802. /*
  803. ** Get a spare port number and create a new socket to bind it to.
  804. */
  805. unsigned short port = Get_Next_Temporary_Source_Port(0);
  806. SocketHandlerClass socket;
  807. if (!socket.Open(port, 4321)) {
  808. WWDEBUG_SAY(("FirewallHelper: Unable to open temp source port - returning default behavior\n"));
  809. return(behavior);
  810. }
  811. /*
  812. ** Send to the mangler from this port until we get a response.
  813. */
  814. timeout = TIMEGETTIME() + TIMER_SECOND * 6;
  815. unsigned short mangled_port = 0;
  816. while (TIMEGETTIME() < timeout && mangled_port == 0) {
  817. Send_To_Mangler(&manglers[0], &socket, packet_id);
  818. mangled_port = Get_Mangler_Response(packet_id, &socket);
  819. }
  820. if (mangled_port == 0) {
  821. /*
  822. ** No response from mangler 0. That's bad. I guess we could try the other manglers.
  823. ** We already tried the first one so skip that. Don't use the last one either since that will be needed later to detect
  824. ** port per ip behavior.
  825. */
  826. for (int m=1 ; m<num_mangler_addresses - 1 ; m++) {
  827. mangler_index_offset = m;
  828. timeout = TIMEGETTIME() + TIMER_SECOND * 3;
  829. while (TIMEGETTIME() < timeout && mangled_port == 0) {
  830. Send_To_Mangler(&manglers[mangler_index_offset], &socket, packet_id);
  831. mangled_port = Get_Mangler_Response(packet_id, &socket);
  832. }
  833. }
  834. }
  835. /*
  836. ** See if we got no response or a non-mangled response.
  837. */
  838. if (mangled_port == 0 || mangled_port == port) {
  839. if (mangled_port == port) {
  840. SourcePortAllocationDelta = 0;
  841. LastSourcePortAllocationDelta = 0;
  842. LastBehavior = FIREWALL_TYPE_SIMPLE;
  843. Confidence = 0;
  844. } else {
  845. WWASSERT(mangled_port == 0);
  846. if (Confidence) {
  847. SourcePortAllocationDelta = LastSourcePortAllocationDelta;
  848. return(LastBehavior);
  849. }
  850. }
  851. return(FIREWALL_TYPE_SIMPLE);
  852. }
  853. /*
  854. **
  855. ** Second test. See if the ports are mangled differently for different destination IPs.
  856. **
  857. ** We can use the spare socket from the last test and send to a different mangler.
  858. **
  859. */
  860. /*
  861. ** Send to the mangler from this port until we get a response.
  862. */
  863. timeout = TIMEGETTIME() + (TIMER_SECOND * 6);
  864. unsigned short second_ip_mangled_port = 0;
  865. while (TIMEGETTIME() < timeout && second_ip_mangled_port == 0) {
  866. Send_To_Mangler(&manglers[mangler_index_offset + 1], &socket, packet_id+1);
  867. second_ip_mangled_port = Get_Mangler_Response(packet_id+1, &socket);
  868. };
  869. /*
  870. ** We are done with this socket/port
  871. */
  872. socket.Close();
  873. /*
  874. ** See if we got no response or a non-mangled response.
  875. */
  876. if (second_ip_mangled_port == 0 || second_ip_mangled_port == port) {
  877. WWDEBUG_SAY(("FirewallHelper: No response or response is unmangled - returning simple firewall behavior\n"));
  878. return(FIREWALL_TYPE_SIMPLE);
  879. }
  880. /*
  881. ** Got a mangled port. Is it the same as the last one (mangles the same regardless of destination IP).
  882. */
  883. if (mangled_port == second_ip_mangled_port) {
  884. behavior = FIREWALL_TYPE_DUMB_MANGLING;
  885. WWDEBUG_SAY(("FirewallHelper: Source ports mangled the same way regardless of destination IP\n"));
  886. } else {
  887. behavior = FIREWALL_TYPE_SMART_MANGLING;
  888. WWDEBUG_SAY(("FirewallHelper: Source ports mangled differently per destination IP\n"));
  889. }
  890. /*
  891. ** Third test.
  892. **
  893. ** This test tries to detect a pattern in the ports allocated by the NAT.
  894. ** We use several source ports for this one.
  895. **
  896. */
  897. /*
  898. ** Try this whole thing a max of 3 times.
  899. */
  900. int try_again;
  901. for (try_again = 0 ; try_again < 3 ; try_again++) {
  902. memset(source_ports, 0, sizeof(source_ports));
  903. memset(mangled_ports, 0, sizeof(source_ports));
  904. memset(port_sockets, 0, sizeof(port_sockets));
  905. /*
  906. ** Open a socket for each source port.
  907. ** We should use a non-linear set of source ports so we can detect the NAT32 relative offset
  908. ** case.
  909. */
  910. bool port_open_failed = false;
  911. for (i=0 ; i<NUM_TEST_PORTS ; i++) {
  912. source_ports[i] = Get_Next_Temporary_Source_Port(i);
  913. port_sockets[i] = new SocketHandlerClass;
  914. if (!port_sockets[i]->Open(source_ports[i], 4321)) {
  915. port_open_failed = true;
  916. /*
  917. ** Close any spare ports we allocated already before we bail.
  918. */
  919. for (int j=0 ; j<i ; j++) {
  920. if (port_sockets[j]) {
  921. delete port_sockets[j];
  922. port_sockets[j] = NULL;
  923. }
  924. }
  925. WWDEBUG_SAY(("FirewallHelper: Unable to open all source ports for allocation pattern test - returning default behavior\n"));
  926. break; //return(behavior);
  927. }
  928. }
  929. if (port_open_failed) {
  930. continue;
  931. }
  932. /*
  933. ** OK, lets get some numbers from the mangler.
  934. **
  935. ** Keep sending from each port until we get a response to all the sends. There's a implied
  936. ** delay between initial sends due to the timeout in Get_Mangler_Response.
  937. */
  938. int num_responses = 0;
  939. packet_id = packet_id + 10;
  940. timeout = TIMEGETTIME() + (TIMER_SECOND * 12);
  941. while (TIMEGETTIME() < timeout && num_responses < NUM_TEST_PORTS) {
  942. for (i=0 ; i<NUM_TEST_PORTS ; i++) {
  943. if (mangled_ports[i] == 0) {
  944. Send_To_Mangler(&manglers[mangler_index_offset], port_sockets[i], packet_id+i);
  945. mangled_ports[i] = Get_Mangler_Response(packet_id+i, port_sockets[i], 0, true);
  946. if (mangled_ports[i] != 0) {
  947. num_responses++;
  948. }
  949. }
  950. }
  951. }
  952. /*
  953. ** Close down those sockets - we are finished with them.
  954. */
  955. for (int j=0 ; j<i ; j++) {
  956. if (port_sockets[j]) {
  957. delete port_sockets[j];
  958. port_sockets[j] = NULL;
  959. }
  960. }
  961. /*
  962. ** We need at least 4 responses to be sure of the port allocation scheme.
  963. */
  964. if (num_responses < 4) {
  965. if (LastSourcePortAllocationDelta != 0 && (int)LastBehavior > (int)FIREWALL_TYPE_SIMPLE) {
  966. /*
  967. ** If the delta we got last time we played looks good then use that.
  968. */
  969. SourcePortAllocationDelta = LastSourcePortAllocationDelta;
  970. WWDEBUG_SAY(("FirewallHelper: Unable to verify responses from 4 mangler servers - returning default behavior\n"));
  971. return(behavior);
  972. }
  973. /*
  974. ** Try again.
  975. */
  976. continue;
  977. }
  978. bool relative_delta = false;
  979. delta = Get_NAT_Port_Allocation_Scheme(num_responses, source_ports, mangled_ports, relative_delta, looks_good);
  980. if (delta) {
  981. /*
  982. ** Hey, we got it!
  983. */
  984. unsigned long addbehavior = 0;
  985. if (relative_delta) {
  986. addbehavior = (unsigned long)FIREWALL_TYPE_RELATIVE_PORT_ALLOCATION;
  987. } else {
  988. addbehavior = (unsigned long)FIREWALL_TYPE_SIMPLE_PORT_ALLOCATION;
  989. }
  990. addbehavior |= (unsigned long)behavior;
  991. behavior = (FirewallBehaviorType) addbehavior;
  992. SourcePortAllocationDelta = delta;
  993. if (!looks_good) {
  994. save_firewall_type = false;
  995. }
  996. break;
  997. } else {
  998. if (LastSourcePortAllocationDelta != 0 && (int)LastBehavior > (int)FIREWALL_TYPE_SIMPLE) {
  999. /*
  1000. ** If the delta we got last time we played looks good then use that.
  1001. */
  1002. SourcePortAllocationDelta = LastSourcePortAllocationDelta;
  1003. behavior = LastBehavior;
  1004. save_firewall_type = false;
  1005. break;
  1006. }
  1007. }
  1008. }
  1009. /*
  1010. ** See if we screwed up.
  1011. */
  1012. if (try_again == 3) {
  1013. /*
  1014. ** We know it mangles differently per IP but we don't know how. Make something up.
  1015. */
  1016. SourcePortAllocationDelta = 1;
  1017. save_firewall_type = false;
  1018. }
  1019. /*
  1020. ** Test to see if the NAT mangles differently per destination port at the same IP.
  1021. **
  1022. **
  1023. */
  1024. if ((behavior & FIREWALL_TYPE_SMART_MANGLING) != 0) {
  1025. if ((behavior & FIREWALL_TYPE_SIMPLE_PORT_ALLOCATION) != 0) {
  1026. WWDEBUG_SAY(("FirewallHelper: Testing to see if the NAT mangles differently per destination port at the same IP\n"));
  1027. /*
  1028. ** We need 2 source ports for this.
  1029. */
  1030. unsigned short port1 = Get_Next_Temporary_Source_Port(0);
  1031. SocketHandlerClass socket1;
  1032. if (!socket1.Open(port1, 4321)) {
  1033. return(behavior);
  1034. }
  1035. unsigned short port2 = Get_Next_Temporary_Source_Port(0);
  1036. SocketHandlerClass socket2;
  1037. if (!socket2.Open(port2, 4321)) {
  1038. return(behavior);
  1039. }
  1040. /*
  1041. ** Get a reference port.
  1042. */
  1043. timeout = TIMEGETTIME() + (TIMER_SECOND * 4);
  1044. mangled_port = 0;
  1045. packet_id = packet_id + 10;
  1046. /*
  1047. ** Wait for a response.
  1048. */
  1049. while (TIMEGETTIME() < timeout && mangled_port == 0) {
  1050. Send_To_Mangler(&manglers[mangler_index_offset], &socket1, packet_id);
  1051. mangled_port = Get_Mangler_Response(packet_id, &socket1);
  1052. }
  1053. if (mangled_port == 0) {
  1054. return(behavior);
  1055. }
  1056. /*
  1057. ** Send out to a different port at that IP.
  1058. ** We won't get a response for this.
  1059. */
  1060. IPAddressClass addr = manglers[mangler_index_offset];
  1061. addr.Set_Port(addr.Get_Port() + 1);
  1062. Send_To_Mangler(&addr, &socket1, packet_id);
  1063. Send_To_Mangler(&addr, &socket1, packet_id);
  1064. Send_To_Mangler(&addr, &socket1, packet_id);
  1065. /*
  1066. ** We can't get a response from a different destination port so the only way to detect
  1067. ** this behavior is to check the next mangled port allocation to see if it's double
  1068. ** what we would normally expect.
  1069. */
  1070. packet_id++;
  1071. unsigned short new_mangled_port = 0;
  1072. timeout = TIMEGETTIME() + (TIMER_SECOND * 4);
  1073. while (TIMEGETTIME() < timeout && new_mangled_port == 0) {
  1074. Send_To_Mangler(&manglers[mangler_index_offset], &socket2, packet_id);
  1075. new_mangled_port = Get_Mangler_Response(packet_id, &socket2);
  1076. }
  1077. if (new_mangled_port != 0) {
  1078. if (new_mangled_port != mangled_port + SourcePortAllocationDelta) {
  1079. WWDEBUG_SAY(("FirewallHelper: NAT uses different source ports for different destination ports\n"));
  1080. unsigned long addbehavior = 0;
  1081. addbehavior = (unsigned long)FIREWALL_TYPE_DESTINATION_PORT_DELTA;
  1082. addbehavior |= (unsigned long)behavior;
  1083. behavior = (FirewallBehaviorType) addbehavior;
  1084. } else {
  1085. fw_assert(new_mangled_port == mangled_port + SourcePortAllocationDelta);
  1086. if (new_mangled_port == mangled_port + SourcePortAllocationDelta) {
  1087. WWDEBUG_SAY(("FirewallHelper: NAT uses the same source port for different destination ports\n"));
  1088. } else {
  1089. WWDEBUG_SAY(("FirewallHelper: Unable to complete destination port mangling test\n"));
  1090. fw_assert(false);
  1091. }
  1092. }
  1093. }
  1094. } else {
  1095. /*
  1096. ** NAT32 uses different mangled source ports for different destination ports.
  1097. */
  1098. unsigned long addbehavior = 0;
  1099. addbehavior = (unsigned long)FIREWALL_TYPE_DESTINATION_PORT_DELTA;
  1100. addbehavior |= (unsigned long)behavior;
  1101. behavior = (FirewallBehaviorType) addbehavior;
  1102. }
  1103. }
  1104. /*
  1105. ** See if the user specified a netgear firewall - that will save us the trouble of detecting it.
  1106. */
  1107. if (SendDelay) {
  1108. unsigned long addbehavior = FIREWALL_TYPE_NETGEAR_BUG;
  1109. addbehavior |= (unsigned long)behavior;
  1110. behavior = (FirewallBehaviorType) addbehavior;
  1111. WWDEBUG_SAY(("FirewallHelper: Netgear bug specified by command line or SendDelay flag\n"));
  1112. }
  1113. /*
  1114. ** Remember this firewall type for next time.
  1115. */
  1116. if (save_firewall_type) {
  1117. LastBehavior = behavior;
  1118. LastSourcePortAllocationDelta = SourcePortAllocationDelta;
  1119. Confidence = 0;
  1120. } else {
  1121. /*
  1122. ** If we have high confidence in the last settings we detected then we might want to use those in preference.
  1123. */
  1124. if (LastBehavior == behavior && LastSourcePortAllocationDelta != SourcePortAllocationDelta) {
  1125. if (Confidence > 0) {
  1126. /*
  1127. ** Only do this max 3 times before accepting the new delta.
  1128. */
  1129. Confidence = (Confidence / 3) - 1;
  1130. SourcePortAllocationDelta = LastSourcePortAllocationDelta;
  1131. }
  1132. }
  1133. }
  1134. return(behavior);
  1135. }
  1136. /***********************************************************************************************
  1137. * FHC::Get_NAT_Port_Allocation_Scheme -- Find out how a NAT is allocating ports *
  1138. * *
  1139. * *
  1140. * *
  1141. * INPUT: Number of ports we should analyze *
  1142. * List of original port numbers *
  1143. * List of mangled port numbers *
  1144. * relative_delta (out) Is the delta relative to the original port number? *
  1145. * looks_good (out) Do all the values point to the same delta? *
  1146. * *
  1147. * OUTPUT: Port allocation delta *
  1148. * *
  1149. * WARNINGS: None *
  1150. * *
  1151. * HISTORY: *
  1152. * 3/15/01 4:45PM ST : Created *
  1153. *=============================================================================================*/
  1154. int FirewallHelperClass::Get_NAT_Port_Allocation_Scheme(int num_ports, unsigned short *original_ports, unsigned short *mangled_ports, bool &relative_delta, bool &looks_good)
  1155. {
  1156. fw_assert(num_ports > 3);
  1157. WWDEBUG_SAY(("FirewallHelper: Looking for port allocation pattern in original_ports %d, %d, %d, %d\n", original_ports[0], original_ports[1], original_ports[2], original_ports[3]));
  1158. /*
  1159. ** Sort the mangled ports into order - should be easier to detect patterns.
  1160. ** Stupid bubble sort will do. original_ports may be out of oder after the sort.
  1161. */
  1162. for (int x=0 ; x<num_ports ; x++) {
  1163. for (int y=0 ; y<num_ports-1 ; y++) {
  1164. if (mangled_ports[y] > mangled_ports[y+1]) {
  1165. int temp = mangled_ports[y];
  1166. mangled_ports[y] = mangled_ports[y+1];
  1167. mangled_ports[y+1] = temp;
  1168. temp = original_ports[y];
  1169. original_ports[y] = original_ports[y+1];
  1170. original_ports[y+1] = temp;
  1171. }
  1172. }
  1173. }
  1174. /*
  1175. ** Now start looking for patterns in the port numbers. Possible patterns include.
  1176. **
  1177. ** Incremental. Port numbers are allocated incrementally.
  1178. ** Every 'n' ports. NAT adds 'n' port numbers when allocating ports.
  1179. **
  1180. ** Also, schemes may be absolute or relative to the original port number.
  1181. */
  1182. /*
  1183. ** 1. Check for absolute sequential allocation.
  1184. */
  1185. if (mangled_ports[1] - mangled_ports[0] == 1) {
  1186. if (mangled_ports[2] - mangled_ports[1] == 1) {
  1187. if (mangled_ports[3] - mangled_ports[2] == 1) {
  1188. WWDEBUG_SAY(("FirewallHelper: Incremental port allocation detected\n"));
  1189. relative_delta = false;
  1190. looks_good = true;
  1191. return(1);
  1192. }
  1193. }
  1194. }
  1195. /*
  1196. ** 2. Check for semi sequential.
  1197. */
  1198. if (mangled_ports[1] - mangled_ports[0] == 2) {
  1199. if (mangled_ports[2] - mangled_ports[1] == 2) {
  1200. if (mangled_ports[3] - mangled_ports[2] == 2) {
  1201. WWDEBUG_SAY(("FirewallHelper: Semi-incremental port allocation detected\n"));
  1202. relative_delta = false;
  1203. looks_good = true;
  1204. return(2);
  1205. }
  1206. }
  1207. }
  1208. int diff1 = mangled_ports[1] - mangled_ports[0];
  1209. int diff2 = mangled_ports[2] - mangled_ports[1];
  1210. int diff3 = mangled_ports[3] - mangled_ports[2];
  1211. /*
  1212. ** 3. Check for absolute scheme skipping 'n' ports.
  1213. */
  1214. if (diff1 == diff2 && diff2 == diff3) {
  1215. WWDEBUG_SAY(("FirewallHelper: Looks good for absolute allocation sequence delta of %d\n", diff1));
  1216. relative_delta = false;
  1217. looks_good = true;
  1218. return(diff1);
  1219. }
  1220. if (diff1 == diff2) {
  1221. WWDEBUG_SAY(("FirewallHelper: Probable absolute allocation sequence delta of %d\n", diff1));
  1222. relative_delta = false;
  1223. looks_good = false;
  1224. return(diff1);
  1225. }
  1226. if (diff2 == diff3) {
  1227. WWDEBUG_SAY(("FirewallHelper: Probable absolute allocation sequence delta of %d\n", diff2));
  1228. relative_delta = false;
  1229. looks_good = false;
  1230. return(diff2);
  1231. }
  1232. /*
  1233. ** Insert more tests here if we can think of any!!!!!
  1234. */
  1235. /*
  1236. ** 4. Check for relative scheme skipping 'n' ports. NAT32 behaves this way, it skips 100 ports
  1237. ** each time.
  1238. */
  1239. for (int i=0 ; i<num_ports ; i++) {
  1240. mangled_ports[i] -= original_ports[i];
  1241. }
  1242. diff1 = mangled_ports[1] - mangled_ports[0];
  1243. diff2 = mangled_ports[2] - mangled_ports[1];
  1244. diff3 = mangled_ports[3] - mangled_ports[2];
  1245. /*
  1246. ** Look for a linear pattern.
  1247. */
  1248. if (diff1 == diff2 && diff2 == diff3) {
  1249. /*
  1250. ** Return a -ve result to indicate that port mangling is relative.
  1251. */
  1252. WWDEBUG_SAY(("FirewallHelper: Looks good for a relative port range delta of %d\n", diff1));
  1253. relative_delta = true;
  1254. looks_good = true;
  1255. return(diff1);
  1256. }
  1257. /*
  1258. ** Look for a broken pattern. Maybe the NAT skipped a whole range.
  1259. */
  1260. if (diff1 == diff2 || diff1 == diff3) {
  1261. WWDEBUG_SAY(("FirewallHelper: Detected probable broken relative port range delta of %d\n", diff1));
  1262. relative_delta = true;
  1263. looks_good = false;
  1264. return(diff1);
  1265. }
  1266. if (diff2 == diff3) {
  1267. WWDEBUG_SAY(("FirewallHelper: Detected probable broken relative port range delta of %d\n", diff2));
  1268. relative_delta = true;
  1269. looks_good = false;
  1270. return(diff2);
  1271. }
  1272. /*
  1273. ** Aw hell, I don't know what it is.
  1274. */
  1275. looks_good = false;
  1276. relative_delta = false;
  1277. return(0);
  1278. }
  1279. /***********************************************************************************************
  1280. * FHC::Get_Firewall_Hardness -- How hard is it to connect to this firewall *
  1281. * *
  1282. * *
  1283. * *
  1284. * INPUT: Firewall behavior *
  1285. * *
  1286. * OUTPUT: Hardness *
  1287. * *
  1288. * WARNINGS: None *
  1289. * *
  1290. * HISTORY: *
  1291. * 3/16/01 11:43AM ST : Created *
  1292. *=============================================================================================*/
  1293. int FirewallHelperClass::Get_Firewall_Hardness(FirewallBehaviorType behavior)
  1294. {
  1295. int hardness = 0;
  1296. unsigned long fw = (unsigned long) behavior;
  1297. if (((unsigned long)FIREWALL_TYPE_SIMPLE & fw) != 0) {
  1298. hardness++;
  1299. }
  1300. if (((unsigned long)FIREWALL_TYPE_DUMB_MANGLING & fw) != 0) {
  1301. hardness += 2;
  1302. }
  1303. if (((unsigned long)FIREWALL_TYPE_SMART_MANGLING & fw) != 0) {
  1304. hardness += 3;
  1305. }
  1306. if (((unsigned long)FIREWALL_TYPE_NETGEAR_BUG & fw) != 0) {
  1307. hardness += 10;
  1308. }
  1309. if (((unsigned long)FIREWALL_TYPE_SIMPLE_PORT_ALLOCATION & fw) != 0) {
  1310. hardness += 1;
  1311. }
  1312. if (((unsigned long)FIREWALL_TYPE_RELATIVE_PORT_ALLOCATION & fw) != 0) {
  1313. hardness += 2;
  1314. }
  1315. return(hardness);
  1316. }
  1317. /***********************************************************************************************
  1318. * FHC::Get_Firewall_Retries -- How many retries is it likely to take before we connect? *
  1319. * *
  1320. * *
  1321. * *
  1322. * INPUT: Firewall behavior *
  1323. * *
  1324. * OUTPUT: Hardness *
  1325. * *
  1326. * WARNINGS: None *
  1327. * *
  1328. * HISTORY: *
  1329. * 3/16/01 11:43AM ST : Created *
  1330. *=============================================================================================*/
  1331. int FirewallHelperClass::Get_Firewall_Retries(FirewallBehaviorType behavior)
  1332. {
  1333. int retries = 2;
  1334. unsigned long fw = (unsigned long) behavior;
  1335. if (((unsigned long)FIREWALL_TYPE_SIMPLE & fw) != 0) {
  1336. retries++;
  1337. }
  1338. if (((unsigned long)FIREWALL_TYPE_DUMB_MANGLING & fw) != 0) {
  1339. retries += 1;
  1340. }
  1341. if (((unsigned long)FIREWALL_TYPE_SMART_MANGLING & fw) != 0) {
  1342. retries += 1;
  1343. }
  1344. if (((unsigned long)FIREWALL_TYPE_NETGEAR_BUG & fw) != 0) {
  1345. //retries += 10;
  1346. }
  1347. if (((unsigned long)FIREWALL_TYPE_SIMPLE_PORT_ALLOCATION & fw) != 0) {
  1348. //retries += 1;
  1349. }
  1350. if (((unsigned long)FIREWALL_TYPE_RELATIVE_PORT_ALLOCATION & fw) != 0) {
  1351. retries += 5;
  1352. }
  1353. return(retries);
  1354. }
  1355. /***********************************************************************************************
  1356. * FHC::Get_Next_Mangled_Source_Port -- How will the firewall mangle our next source port *
  1357. * *
  1358. * *
  1359. * *
  1360. * INPUT: Source port that we will use *
  1361. * *
  1362. * OUTPUT: Nothing *
  1363. * *
  1364. * WARNINGS: None *
  1365. * *
  1366. * HISTORY: *
  1367. * 3/16/01 3:30PM ST : Created *
  1368. *=============================================================================================*/
  1369. unsigned short FirewallHelperClass::Get_Next_Mangled_Source_Port(unsigned short source_port)
  1370. {
  1371. /*
  1372. ** Locals.
  1373. */
  1374. static unsigned long _packet_id = 0x7f100000;
  1375. unsigned long timeout;
  1376. int return_port = source_port;
  1377. SocketHandlerClass socket;
  1378. /*
  1379. ** If our firewall is stupid then just return the source port.
  1380. */
  1381. unsigned long fw = (unsigned long) Behavior;
  1382. if (fw == 0) {
  1383. return(source_port);
  1384. }
  1385. if (((unsigned long)FIREWALL_TYPE_SIMPLE & fw) != 0) {
  1386. return(source_port);
  1387. }
  1388. /*
  1389. ** If our NAT uses the same mangled source port regardless of the dest IP then we can use any previous connection to a different IP.
  1390. */
  1391. if (WOLNATInterface.Am_I_Server() && ((unsigned long)FIREWALL_TYPE_DUMB_MANGLING & fw) != 0) {
  1392. for (int h=0 ; h<ConnectionHistory.Count() ; h++) {
  1393. /*
  1394. ** Make sure it isn't my address (should never be, even with players from behind the same firewall).
  1395. */
  1396. if (!ConnectionHistory[h].Is_IP_Equal(ExternalAddress)) {
  1397. WWDEBUG_SAY(("FirewallHelper - same port regardless of dest ip - using port %d from connection to %s ; %d\n", (unsigned long) MangledPortHistory[h], ConnectionHistory[h].As_String()));
  1398. return(MangledPortHistory[h]);
  1399. }
  1400. }
  1401. }
  1402. /*
  1403. ** Get the address of a mangler server.
  1404. */
  1405. unsigned short mangler_port = 4321;
  1406. char mangler_name[256];
  1407. strcpy(mangler_name, "mangler2.westwood.com");
  1408. unsigned char maddress[4];
  1409. if (NumManglerServers > 0) {
  1410. fw_assert(CurrentManglerServer >= 0 && CurrentManglerServer < NumManglerServers);
  1411. bool got_name = WOLNATInterface.Get_Mangler_Name_By_Index(CurrentManglerServer, mangler_name);
  1412. if (got_name) {
  1413. unsigned short servserv_port = WOLNATInterface.Get_Mangler_Port_By_Index(CurrentManglerServer);
  1414. fw_assert(servserv_port != 0);
  1415. if (servserv_port) {
  1416. mangler_port = servserv_port;
  1417. }
  1418. WWDEBUG_SAY(("FirewallHelper - Using mangler server from servserv - address is %s ; %d\n", mangler_name, mangler_port));
  1419. } else {
  1420. WWDEBUG_SAY(("FirewallHelper - Using default mangler name for mangler %d\n", CurrentManglerServer));
  1421. }
  1422. }
  1423. /*
  1424. ** Get the address to send the packets to.
  1425. */
  1426. //WWDEBUG_SAY (("Firewall helper - About to call gethostbyname for %s\n", mangler_name));
  1427. struct hostent *host_info = gethostbyname(mangler_name);
  1428. if (!host_info) {
  1429. WWDEBUG_SAY(("FirewallHelper - gethostbyname failed! Error code %d\n", WSAGetLastError()));
  1430. return(source_port);
  1431. }
  1432. memcpy(maddress, &host_info->h_addr_list[0][0], 4);
  1433. //WWDEBUG_SAY(("FirewallHelper: Mangler address is %d.%d.%d.%d ; %d\n", maddress[0], maddress[1], maddress[2], maddress[3], (int)mangler_port));
  1434. IPAddressClass mangler_address;
  1435. mangler_address.Set_Address(maddress, mangler_port);
  1436. //WWDEBUG_SAY(("FirewallHelper: Mangler address is %s\n", mangler_address.As_String()));
  1437. //WWDEBUG_SAY(("FirewallHelper: fw = %08x\n", fw));
  1438. /*
  1439. ** Send to the mangler to establish a reference port.
  1440. */
  1441. unsigned short port = Get_Next_Temporary_Source_Port(0);
  1442. fw_assert(port != source_port);
  1443. if (!socket.Open(port, 4321)) {
  1444. return(source_port);
  1445. }
  1446. WWDEBUG_SAY(("FirewallHelper - Getting mangling for temp source port %d\n", (int)port));
  1447. /*
  1448. ** Send to the mangler from this port until we get a response.
  1449. */
  1450. timeout = TIMEGETTIME() + (TIMER_SECOND * 3);
  1451. unsigned short mangled_port = 0;
  1452. while (TIMEGETTIME() < timeout && mangled_port == 0) {
  1453. Send_To_Mangler(&mangler_address, &socket, _packet_id);
  1454. mangled_port = Get_Mangler_Response(_packet_id, &socket, TIMER_SECOND / 2);
  1455. if (mangled_port != 0) {
  1456. WWDEBUG_SAY(("FirewallHelper - Mangled port = %d\n", (int)mangled_port));
  1457. }
  1458. }
  1459. _packet_id++;
  1460. fw_assert(mangled_port != 0 && mangled_port != source_port);
  1461. if (mangled_port == 0) {
  1462. /*
  1463. ** We failed to get a response from the mangler, try a different one next retry.
  1464. */
  1465. CurrentManglerServer++;
  1466. if (CurrentManglerServer >= NumManglerServers) {
  1467. CurrentManglerServer = 0;
  1468. }
  1469. WWDEBUG_SAY(("FirewallHelper: Couldn't find mangled port, returning source port\n"));
  1470. return(source_port);
  1471. }
  1472. /*
  1473. ** Our new reference port is 'mangled port'. If we don't care about IP then we are done.
  1474. */
  1475. if (((unsigned long)FIREWALL_TYPE_DUMB_MANGLING & fw) != 0) {
  1476. WWDEBUG_SAY(("FirewallHelper - Dumb firewall, returning next mangled port as %d\n", mangled_port));
  1477. return(mangled_port);
  1478. }
  1479. /*
  1480. ** Apply our known delta to the mangled port.
  1481. */
  1482. if (((unsigned long)FIREWALL_TYPE_SIMPLE_PORT_ALLOCATION & fw) != 0) {
  1483. /*
  1484. ** Simple port allocation.
  1485. */
  1486. return_port = (int)mangled_port + SourcePortAllocationDelta;
  1487. } else {
  1488. /*
  1489. ** Rats. It's a relative mangler. This is much harder. Damn NAT32 guy.
  1490. */
  1491. if (SourcePortAllocationDelta == 100) {
  1492. /*
  1493. ** Special NAT32 section.
  1494. **
  1495. ** NAT32 mangles source UDP port by adding 1700 + 100 * internal table index
  1496. **
  1497. ** To get the current index we need to take the mangled port and subtract 1700 and the source port
  1498. */
  1499. return_port = mangled_port - port;
  1500. return_port -= 1700;
  1501. return_port += SourcePortAllocationDelta;
  1502. return_port += source_port;
  1503. return_port += 1700;
  1504. } else {
  1505. WWASSERT(SourcePortAllocationDelta != 0);
  1506. if (SourcePortAllocationDelta == 0) {
  1507. /*
  1508. ** This should never happen....
  1509. */
  1510. return_port = mangled_port;
  1511. } else {
  1512. return_port = mangled_port / SourcePortAllocationDelta;
  1513. return_port = return_port * SourcePortAllocationDelta;
  1514. return_port += (source_port % SourcePortAllocationDelta);
  1515. return_port += SourcePortAllocationDelta;
  1516. }
  1517. }
  1518. }
  1519. /*
  1520. ** This bit is probably doomed.
  1521. */
  1522. if (return_port > 65535) {
  1523. return_port -= 65535;
  1524. }
  1525. if (return_port < 1024) {
  1526. return_port += 1024;
  1527. }
  1528. WWDEBUG_SAY(("FirewallHelper - Returning next mangled port as %d\n", return_port));
  1529. return(unsigned short(return_port));
  1530. }
  1531. /***********************************************************************************************
  1532. * NatterClass::Build_Mangler_Packet -- Build a packet to send to the mangler. *
  1533. * *
  1534. * *
  1535. * *
  1536. * INPUT: Buffer to build packet in *
  1537. * Port to set into the packets Port area *
  1538. * Packet ID. *
  1539. * Blitzme flag (shouldn't be used) *
  1540. * *
  1541. * OUTPUT: Nothing *
  1542. * *
  1543. * WARNINGS: None *
  1544. * *
  1545. * HISTORY: *
  1546. * 8/6/2001 1:11PM ST : Created *
  1547. *=============================================================================================*/
  1548. int FirewallHelperClass::Build_Mangler_Packet(unsigned char *buffer, unsigned short port, unsigned long packet_id, bool blitzme)
  1549. {
  1550. /*
  1551. ** Asserts.
  1552. */
  1553. fw_assert(buffer != NULL);
  1554. fw_assert(blitzme == false);
  1555. /*
  1556. ** Need the buffer to exist.
  1557. */
  1558. if (buffer == NULL) {
  1559. return(0);
  1560. }
  1561. /*
  1562. ** Cast the buffer to a CnCPacketType.
  1563. */
  1564. CnCPacketType *packet = (CnCPacketType*)buffer;
  1565. /*
  1566. ** Clear out the buffer prior to setting fields.
  1567. */
  1568. memset(packet, 0, sizeof(CnCPacketType));
  1569. /*
  1570. ** Set the required Global Header firelds.
  1571. */
  1572. packet->GHeader.Header.MagicNumber = GLOBAL_MAGICNUM;
  1573. packet->GHeader.Header.Code = PACKET_DATA_NOACK;
  1574. packet->GHeader.Header.ForwardTo = 0;
  1575. packet->GHeader.Header.PacketID = packet_id;
  1576. packet->GHeader.ProductID = COMMAND_AND_CONQUER_RA2;
  1577. /*
  1578. ** Set the Global Packet fields.
  1579. */
  1580. packet->Packet.Command = NET_MANGLER_REQUEST;
  1581. strcpy(packet->Packet.Name, "ren");
  1582. packet->Packet.ManglerData.MangledPortNumber = port;
  1583. packet->Packet.ManglerData.OriginalPortNumber = port;
  1584. packet->Packet.ManglerData.BlitzMe = 0;
  1585. /*
  1586. ** Blitzme field is obsolete and should never be used.
  1587. */
  1588. if (blitzme) {
  1589. packet->Packet.ManglerData.BlitzMe = 1;
  1590. }
  1591. /*
  1592. ** Return success.
  1593. */
  1594. return(sizeof(CnCPacketType));
  1595. }
  1596. /***********************************************************************************************
  1597. * FirewallHelperClass::Add_Thread_Action -- Add a new action to the thread control FIFO *
  1598. * *
  1599. * *
  1600. * *
  1601. * INPUT: Thread action *
  1602. * Notification event *
  1603. * *
  1604. * OUTPUT: Nothing *
  1605. * *
  1606. * WARNINGS: None *
  1607. * *
  1608. * HISTORY: *
  1609. * 8/9/2001 9:06PM ST : Created *
  1610. *=============================================================================================*/
  1611. void FirewallHelperClass::Add_Thread_Action(int thread_action, HANDLE thread_event)
  1612. {
  1613. ThreadLockClass locker(this);
  1614. ThreadActionClass thread;
  1615. thread.ThreadAction = thread_action;
  1616. thread.ThreadEvent = thread_event;
  1617. ThreadQueue.Add(thread);
  1618. }
  1619. /***********************************************************************************************
  1620. * FirewallHelperClass::Set_Thread_Event -- Set the event associated with action completion *
  1621. * *
  1622. * *
  1623. * *
  1624. * INPUT: Nothing *
  1625. * *
  1626. * OUTPUT: Nothing *
  1627. * *
  1628. * WARNINGS: None *
  1629. * *
  1630. * HISTORY: *
  1631. * 8/9/2001 9:09PM ST : Created *
  1632. *=============================================================================================*/
  1633. void FirewallHelperClass::Set_Thread_Event(void)
  1634. {
  1635. ThreadLockClass locker(this);
  1636. if (ThreadEvent != INVALID_HANDLE_VALUE) {
  1637. SetEvent(ThreadEvent);
  1638. ThreadEvent = INVALID_HANDLE_VALUE;
  1639. }
  1640. }
  1641. /***********************************************************************************************
  1642. * FirewallHelperClass::Talk_To_New_Player -- A new player wants to negotiate a NAT port *
  1643. * *
  1644. * *
  1645. * *
  1646. * INPUT: User struct for player *
  1647. * *
  1648. * OUTPUT: Nothing *
  1649. * *
  1650. * WARNINGS: None *
  1651. * *
  1652. * HISTORY: *
  1653. * 8/7/2001 8:31PM ST : Created *
  1654. *=============================================================================================*/
  1655. void FirewallHelperClass::Talk_To_New_Player(WOL::User *user)
  1656. {
  1657. /*
  1658. ** We are only reading here - no need to get exclusive access.
  1659. */
  1660. //ThreadLockClass locker(this);
  1661. WWASSERT(PTheGameData != NULL);
  1662. /*
  1663. ** Fill in an invitation options packet to send to the guest.
  1664. */
  1665. WOLNATInterfaceClass::PrivateGameOptionsStruct options;
  1666. strcpy(options.NATOptionsPrefix, "NAT:");
  1667. options.Option = WOLNATInterfaceClass::OPTION_INVITE_PORT_NEGOTIATION;
  1668. sprintf(options.OptionData.Invitation.LocalIP, "%08x,", (unsigned long) LocalChatConnectionAddress.Get_Address());
  1669. sprintf(options.OptionData.Invitation.LocalPort, "%04x,", The_Game()->Get_Port());
  1670. sprintf(options.OptionData.Invitation.ExternalIP, "%08x,", (unsigned long) ExternalAddress.Get_Address());
  1671. sprintf(options.OptionData.Invitation.FirewallType, "%08x,", Get_Raw_Firewall_Behavior());
  1672. sprintf(options.OptionData.Invitation.Queued, "%04x", ClientQueue.Count());
  1673. /*
  1674. ** Send it.
  1675. */
  1676. WOLNATInterface.Send_Private_Game_Options(user, (char*)&options);
  1677. }
  1678. /***********************************************************************************************
  1679. * FirewallHelperClass::Process_Game_Options -- Process private game options packets *
  1680. * *
  1681. * *
  1682. * *
  1683. * INPUT: Nothing *
  1684. * *
  1685. * OUTPUT: Nothing *
  1686. * *
  1687. * WARNINGS: None *
  1688. * *
  1689. * HISTORY: *
  1690. * 8/9/2001 10:01PM ST : Created *
  1691. *=============================================================================================*/
  1692. void FirewallHelperClass::Process_Game_Options(void)
  1693. {
  1694. /*
  1695. ** Locals.
  1696. */
  1697. WOL::User user;
  1698. char options_buffer[OPTIONS_STAGING_BUFFER_SIZE];
  1699. unsigned long addr_ip = 0;
  1700. unsigned short addr_port = 0;
  1701. unsigned long firewall = 0;
  1702. ThreadLockClass locker(this);
  1703. /*
  1704. ** See if there are any pending game options packets.
  1705. */
  1706. if (WOLNATInterface.Get_Private_Game_Options(&user, options_buffer, OPTIONS_STAGING_BUFFER_SIZE)) {
  1707. /*
  1708. ** Cast the options buffer to a more manageable type.
  1709. */
  1710. WOLNATInterfaceClass::PrivateGameOptionsStruct *options = (WOLNATInterfaceClass::PrivateGameOptionsStruct*) options_buffer;
  1711. /*
  1712. ** Get the option type.
  1713. */
  1714. switch (options->Option) {
  1715. /*
  1716. ** This option represents a game server inviting us to negotiate a connection through firewalls. It will contain his
  1717. ** local IP and port. This is a client side message only.
  1718. */
  1719. case WOLNATInterfaceClass::OPTION_INVITE_PORT_NEGOTIATION:
  1720. WWDEBUG_SAY(("FirewallHelper - Got OPTION_INVITE_PORT_NEGOTIATION\n"));
  1721. fw_assert(!WOLNATInterface.Am_I_Server());
  1722. if (!WOLNATInterface.Am_I_Server()) {
  1723. /*
  1724. ** Pull out the players info from the packet.
  1725. */
  1726. sscanf(options->OptionData.Invitation.LocalIP, "%08x", &addr_ip);
  1727. sscanf(options->OptionData.Invitation.LocalPort, "%04hx", &addr_port);
  1728. PlayersLocalAddress.Set_Address(addr_ip, addr_port);
  1729. sscanf(options->OptionData.Invitation.ExternalIP, "%08x", &addr_ip);
  1730. PlayersExternalAddress.Set_Address(addr_ip, addr_port);
  1731. sscanf(options->OptionData.Invitation.FirewallType, "%08x", (unsigned long*)(&PlayersFirewallType));
  1732. sscanf(options->OptionData.Invitation.Queued, "%04x", &QueuedPlayers);
  1733. strcpy(PlayersName, (char*)user.name);
  1734. PlayerAsUser = user;
  1735. if (QueueNotifyPtr) {
  1736. *QueueNotifyPtr = QueuedPlayers;
  1737. }
  1738. WWDEBUG_SAY(("FirewallHelper - Received port negotiation invitation. %d players in the queue ahead of me\n", QueuedPlayers));
  1739. WWDEBUG_SAY(("FirewallHelper - Server is %s. Local addr = %s, ", PlayersName, PlayersLocalAddress.As_String()));
  1740. WWDEBUG_SAY(("external addr = %s, firewall = %08x\n", PlayersExternalAddress.As_String(), (unsigned long) PlayersFirewallType));
  1741. /*
  1742. ** Wait for queue notification.
  1743. */
  1744. if (QueuedPlayers == 0) {
  1745. QueuedPlayers = -1;
  1746. }
  1747. /*
  1748. ** Respond to the server with my info.
  1749. */
  1750. ClientPort = WOLNATInterface.Get_Next_Client_Port();
  1751. WOLNATInterfaceClass::PrivateGameOptionsStruct send_options;
  1752. strcpy(send_options.NATOptionsPrefix, "NAT:");
  1753. send_options.Option = WOLNATInterfaceClass::OPTION_ACCEPT_PORT_NEGOTIATION_INVITATION;
  1754. sprintf(send_options.OptionData.Accept.LocalIP, "%08x,", (unsigned long) LocalChatConnectionAddress.Get_Address());
  1755. sprintf(send_options.OptionData.Accept.LocalPort, "%04x,", ClientPort);
  1756. sprintf(send_options.OptionData.Accept.ExternalIP, "%08x,", (unsigned long) ExternalAddress.Get_Address());
  1757. sprintf(send_options.OptionData.Accept.FirewallType, "%08x", Get_Raw_Firewall_Behavior());
  1758. /*
  1759. ** Send it.
  1760. */
  1761. WOLNATInterface.Send_Private_Game_Options(&user, (char*)&send_options);
  1762. /*
  1763. ** Go into connect mode.
  1764. ** Don't do this until we get a confirmation of our queue position.
  1765. */
  1766. Add_Thread_Action(THREAD_CONNECT_FIREWALL, INVALID_HANDLE_VALUE);
  1767. }
  1768. break;
  1769. /*
  1770. ** This option represents a game client accepting our invitation to negotiate a connection through firewalls. It
  1771. ** will contain his local IP and port. This is a server side message only.
  1772. */
  1773. case WOLNATInterfaceClass::OPTION_ACCEPT_PORT_NEGOTIATION_INVITATION:
  1774. WWDEBUG_SAY(("FirewallHelper - Got OPTION_ACCEPT_PORT_NEGOTIATION_INVITATION\n"));
  1775. fw_assert(WOLNATInterface.Am_I_Server());
  1776. if (WOLNATInterface.Am_I_Server()) {
  1777. /*
  1778. ** Pull out the players info from the packet.
  1779. */
  1780. unsigned long ext_ip = 0;
  1781. sscanf(options->OptionData.Accept.LocalIP, "%08x", &addr_ip);
  1782. sscanf(options->OptionData.Accept.LocalPort, "%04hx", &addr_port);
  1783. sscanf(options->OptionData.Accept.ExternalIP, "%08x", &ext_ip);
  1784. sscanf(options->OptionData.Accept.FirewallType, "%08x", &firewall);
  1785. /*
  1786. ** Create a queue entry for the player.
  1787. */
  1788. ClientStruct *client = new ClientStruct;
  1789. strcpy(client->Name, (char*)user.name);
  1790. client->LocalAddress.Set_Address(addr_ip, addr_port);
  1791. client->ExternalAddress.Set_Address(ext_ip, addr_port);
  1792. client->FirewallType = (FirewallBehaviorType) firewall;
  1793. client->User = user;
  1794. /*
  1795. ** Make sure this client isn't in the client list already (Should never happen but...)
  1796. */
  1797. if (Remove_Player_From_Negotiation_Queue(client->Name)) {
  1798. WWDEBUG_SAY(("FirewallHelper OPTION_ACCEPT_PORT_NEGOTIATION_INVITATION - Removed %s from ClientQueue\n", client->Name));
  1799. }
  1800. /*
  1801. ** Add this player to the negotiation queue.
  1802. */
  1803. ClientQueue.Add(client);
  1804. WWDEBUG_SAY(("FirewallHelper - Got client accept from %s. Local addr = %s,", client->Name, client->LocalAddress.As_String()));
  1805. WWDEBUG_SAY((" external addr = %s, firewall = %08x\n", client->ExternalAddress.As_String(), (unsigned long) firewall));
  1806. Add_Thread_Action(THREAD_CONNECT_FIREWALL, INVALID_HANDLE_VALUE);
  1807. }
  1808. break;
  1809. /*
  1810. ** Handle connection result message.
  1811. **
  1812. */
  1813. case WOLNATInterfaceClass::OPTION_CONNECTION_RESULT:
  1814. {
  1815. int result = options->OptionData.ConnectionResult.Result[0] - 'a';
  1816. WWDEBUG_SAY(("FirewallHelper - Got OPTION_CONNECTION_RESULT %d from %s\n", result, options->OptionData.ConnectionResult.Name));
  1817. if (stricmp(PlayersName, options->OptionData.ConnectionResult.Name) == 0) {
  1818. PlayersConnectionResult = result;
  1819. unsigned long port;
  1820. sscanf(options->OptionData.ConnectionResult.Port, "%04x", &port);
  1821. PlayersConnectionResultPort = (unsigned short) port;
  1822. if (WOLNATInterface.Am_I_Server()) {
  1823. LastOptionsFromClient = TIMEGETTIME();
  1824. }
  1825. }
  1826. break;
  1827. }
  1828. /*
  1829. ** Other player is telling us what port to use when talking to him.
  1830. */
  1831. case WOLNATInterfaceClass::OPTION_PORT_NOTIFICATION:
  1832. {
  1833. WWDEBUG_SAY(("FirewallHelper - Got OPTION_PORT_NOTIFICATION from %s\n", options->OptionData.Port.Name));
  1834. unsigned long port;
  1835. sscanf(options->OptionData.Port.MangledPort, "%04x", &port);
  1836. WWDEBUG_SAY(("FirewallHelper - Port is %d\n", port));
  1837. //fw_assert(port >= 1024 && port < 65536);
  1838. //if (port >= 1024 && port < 65536) {
  1839. if (stricmp(PlayersName, options->OptionData.Port.Name) == 0) {
  1840. PlayersMangledPort = (unsigned short) port;
  1841. if (WOLNATInterface.Am_I_Server()) {
  1842. LastOptionsFromClient = TIMEGETTIME();
  1843. }
  1844. }
  1845. //}
  1846. break;
  1847. }
  1848. /*
  1849. ** Server is telling us how close to the front of the queue we are.
  1850. */
  1851. case WOLNATInterfaceClass::OPTION_QUEUE_STATE:
  1852. {
  1853. WWDEBUG_SAY(("FirewallHelper - Got OPTION_QUEUE_STATE\n"));
  1854. int queue;
  1855. sscanf(options->OptionData.QueueState.Position, "%02x", &queue);
  1856. WWDEBUG_SAY(("FirewallHelper - Queue position is %d\n", queue));
  1857. QueuedPlayers = queue;
  1858. if (QueueNotifyPtr) {
  1859. *QueueNotifyPtr = queue;
  1860. }
  1861. //if (QueuedPlayers == 0) {
  1862. // if (ThreadState != THREAD_DETECT_FIREWALL) {
  1863. // Add_Thread_Action(THREAD_CONNECT_FIREWALL, INVALID_HANDLE_VALUE);
  1864. // }
  1865. //}
  1866. break;
  1867. }
  1868. /*
  1869. ** Client has cancelled out of the game channel.
  1870. */
  1871. case WOLNATInterfaceClass::OPTION_ABORT_NEGOTIATION:
  1872. WWDEBUG_SAY(("FirewallHelper - Got OPTION_ABORT_NEGOTIATION from %s\n", (char*)user.name));
  1873. {
  1874. ThreadLockClass locker(this);
  1875. if (WOLNATInterface.Am_I_Server()) {
  1876. if (stricmp((char*)user.name, PlayersName) == 0) {
  1877. strcpy(CancelPlayer, (char*)user.name);
  1878. }
  1879. }
  1880. /*
  1881. ** Remove this player from the client queue if he is in there.
  1882. */
  1883. if (Remove_Player_From_Negotiation_Queue((char*)user.name)) {
  1884. WWDEBUG_SAY(("FirewallHelper OPTION_ABORT_NEGOTIATION - Removed %s from ClientQueue\n", (char*)user.name));
  1885. }
  1886. break;
  1887. }
  1888. /*
  1889. ** Client has joined a channel and is available for negotiation.
  1890. */
  1891. case WOLNATInterfaceClass::OPTION_CLIENT_IN_CHANNEL:
  1892. WWDEBUG_SAY(("FirewallHelper - Got OPTION_CLIENT_IN_CHANNEL from %s\n", (char*)user.name));
  1893. if (WOLNATInterface.Am_I_Server()) {
  1894. Talk_To_New_Player(&user);
  1895. }
  1896. break;
  1897. default:
  1898. fw_assert(false);
  1899. break;
  1900. }
  1901. }
  1902. }
  1903. /***********************************************************************************************
  1904. * FirewallHelperClass::Cleanup_Client_Queue -- Remove pending entries from client queue *
  1905. * *
  1906. * *
  1907. * *
  1908. * INPUT: Nothing *
  1909. * *
  1910. * OUTPUT: Nothing *
  1911. * *
  1912. * WARNINGS: ONLY CALL THIS FROM THE MAIN THREAD *
  1913. * *
  1914. * HISTORY: *
  1915. * 3/22/2002 4:09PM ST : Created *
  1916. *=============================================================================================*/
  1917. void FirewallHelperClass::Cleanup_Client_Queue(void)
  1918. {
  1919. /*
  1920. ** This is the main thread removing entries from the client queue that it wasn't able to remove before due to thread
  1921. ** contention.
  1922. */
  1923. fw_assert(Get_Main_Thread_ID() == GetCurrentThreadId());
  1924. while (ClientQueueRemoveList.Count()) {
  1925. if (Remove_Player_From_Negotiation_Queue_If_Mutex_Available(ClientQueueRemoveList[0]->Name)) {
  1926. delete ClientQueueRemoveList[0];
  1927. ClientQueueRemoveList.Delete(0);
  1928. } else {
  1929. break;
  1930. }
  1931. }
  1932. }
  1933. /***********************************************************************************************
  1934. * FirewallHelperClass::Remove_Player_From_Negotiation_Queue_If_Mutex_Available - What it says *
  1935. * *
  1936. * *
  1937. * *
  1938. * *
  1939. * INPUT: Player name *
  1940. * *
  1941. * OUTPUT: True if mutex was available *
  1942. * *
  1943. * WARNINGS: None *
  1944. * *
  1945. * HISTORY: *
  1946. * 3/22/2002 3:41PM ST : Created *
  1947. *=============================================================================================*/
  1948. bool FirewallHelperClass::Remove_Player_From_Negotiation_Queue_If_Mutex_Available(char *player_name)
  1949. {
  1950. ThreadLockClass locker(this, 0);
  1951. /*
  1952. ** If we can grab the mutex then remove the item immediately, otherwise add it to a list and return.
  1953. */
  1954. if (locker.WaitResult == WAIT_OBJECT_0) {
  1955. Remove_Player_From_Negotiation_Queue(player_name);
  1956. return(true);
  1957. } else {
  1958. /*
  1959. ** Just add the name to a list that will be checked later when it's safe to remove stuff from the client queue.
  1960. ** This list must only ever be accessed from the main thread.
  1961. */
  1962. fw_assert(Get_Main_Thread_ID() == GetCurrentThreadId());
  1963. for (int i=0 ; i<ClientQueueRemoveList.Count() ; i++) {
  1964. if (stricmp(ClientQueueRemoveList[i]->Name, player_name) == 0) {
  1965. return(false);
  1966. }
  1967. }
  1968. ClientStruct *clientptr = new ClientStruct;
  1969. strcpy(clientptr->Name, player_name);
  1970. ClientQueueRemoveList.Add(clientptr);
  1971. }
  1972. return(false);
  1973. }
  1974. /***********************************************************************************************
  1975. * FirewallHelperClass::Remove_Player_From_Negotiation_Queue - What it says *
  1976. * *
  1977. * *
  1978. * *
  1979. * INPUT: Player name *
  1980. * *
  1981. * OUTPUT: True if player was in queue *
  1982. * *
  1983. * WARNINGS: None *
  1984. * *
  1985. * HISTORY: *
  1986. * 3/3/2002 10:20PM ST : Created *
  1987. *=============================================================================================*/
  1988. bool FirewallHelperClass::Remove_Player_From_Negotiation_Queue(char *player_name)
  1989. {
  1990. fw_assert(WOLNATInterface.Am_I_Server());
  1991. if (ClientQueue.Count() == 0) {
  1992. return(false);
  1993. }
  1994. ThreadLockClass locker(this);
  1995. ClientStruct *clientptr = NULL;
  1996. bool retcode = false;
  1997. for (int i=0 ; i<ClientQueue.Count() ; i++) {
  1998. clientptr = ClientQueue[i];
  1999. if (stricmp(clientptr->Name, player_name) == 0) {
  2000. WWDEBUG_SAY(("FirewallHelper - Removed %s from ClientQueue\n", clientptr->Name));
  2001. delete clientptr;
  2002. ClientQueue.Delete(i);
  2003. i--;
  2004. retcode = true;
  2005. }
  2006. }
  2007. return(retcode);
  2008. }
  2009. /***********************************************************************************************
  2010. * FirewallHelperClass::Send_My_Port -- Send my mangled port number to the other guy *
  2011. * *
  2012. * *
  2013. * *
  2014. * INPUT: Port *
  2015. * *
  2016. * OUTPUT: Nothing *
  2017. * *
  2018. * WARNINGS: None *
  2019. * *
  2020. * HISTORY: *
  2021. * 8/13/2001 11:37AM ST : Created *
  2022. *=============================================================================================*/
  2023. void FirewallHelperClass::Send_My_Port(unsigned short port)
  2024. {
  2025. ThreadLockClass locker(this);
  2026. WWDEBUG_SAY(("FirewallHelper - Sending my port number (%d) to %s\n", (unsigned int)port, PlayersName));
  2027. /*
  2028. ** Fill in an port notification options packet to send to the guest.
  2029. */
  2030. WOLNATInterfaceClass::PrivateGameOptionsStruct options;
  2031. strcpy(options.NATOptionsPrefix, "NAT:");
  2032. options.Option = WOLNATInterfaceClass::OPTION_PORT_NOTIFICATION;
  2033. sprintf(options.OptionData.Port.MangledPort, "%04x,", port);
  2034. char my_name[64];
  2035. WOLNATInterface.Get_My_Name(my_name);
  2036. strcpy(options.OptionData.Port.Name, my_name);
  2037. /*
  2038. ** Send it.
  2039. */
  2040. WOLNATInterface.Send_Private_Game_Options(&PlayerAsUser, (char*)&options);
  2041. }
  2042. /***********************************************************************************************
  2043. * FirewallHelperClass::Send_Connection_Result -- Send connection result game option *
  2044. * *
  2045. * *
  2046. * *
  2047. * INPUT: Result enum *
  2048. * *
  2049. * OUTPUT: Nothing *
  2050. * *
  2051. * WARNINGS: None *
  2052. * *
  2053. * HISTORY: *
  2054. * 8/13/2001 2:17PM ST : Created *
  2055. *=============================================================================================*/
  2056. void FirewallHelperClass::Send_Connection_Result(int result, unsigned short port)
  2057. {
  2058. ThreadLockClass locker(this);
  2059. /*
  2060. ** Fill in a connection result options packet to send to the other player.
  2061. */
  2062. WOLNATInterfaceClass::PrivateGameOptionsStruct options;
  2063. strcpy(options.NATOptionsPrefix, "NAT:");
  2064. options.Option = WOLNATInterfaceClass::OPTION_CONNECTION_RESULT;
  2065. options.OptionData.ConnectionResult.Result[0] = 'a' + result;
  2066. options.OptionData.ConnectionResult.Result[1] = ',';
  2067. sprintf(options.OptionData.ConnectionResult.Port, "%04x,", (unsigned long) port);
  2068. char my_name[64];
  2069. WOLNATInterface.Get_My_Name(my_name);
  2070. strcpy(options.OptionData.ConnectionResult.Name, my_name);
  2071. /*
  2072. ** Send it.
  2073. */
  2074. WOLNATInterface.Send_Private_Game_Options(&PlayerAsUser, (char*)&options);
  2075. }
  2076. /***********************************************************************************************
  2077. * FirewallHelperClass::Send_Connection_Result -- Send connection result game option *
  2078. * *
  2079. * *
  2080. * *
  2081. * INPUT: Result enum *
  2082. * *
  2083. * OUTPUT: Nothing *
  2084. * *
  2085. * WARNINGS: None *
  2086. * *
  2087. * HISTORY: *
  2088. * 8/13/2001 2:17PM ST : Created *
  2089. *=============================================================================================*/
  2090. void FirewallHelperClass::Send_Queue_States(void)
  2091. {
  2092. if (WOLNATInterface.Am_I_Server()) {
  2093. if (ClientQueue.Count()) {
  2094. ThreadLockClass locker(this);
  2095. /*
  2096. ** Fill in a queue state options packet to send to the other players.
  2097. */
  2098. WOLNATInterfaceClass::PrivateGameOptionsStruct options;
  2099. strcpy(options.NATOptionsPrefix, "NAT:");
  2100. options.Option = WOLNATInterfaceClass::OPTION_QUEUE_STATE;
  2101. char my_name[64];
  2102. WOLNATInterface.Get_My_Name(my_name);
  2103. strcpy(options.OptionData.ConnectionResult.Name, my_name);
  2104. /*
  2105. ** Send updates to all queued players.
  2106. */
  2107. for (int i=0 ; i<ClientQueue.Count() ; i++) {
  2108. sprintf(options.OptionData.QueueState.Position, "%02x", i);
  2109. ClientStruct *client = ClientQueue[i];
  2110. fw_assert(client != NULL);
  2111. if (client) {
  2112. /*
  2113. ** Send it.
  2114. */
  2115. WOLNATInterface.Send_Private_Game_Options(&client->User, (char*)&options);
  2116. }
  2117. }
  2118. }
  2119. }
  2120. }
  2121. /***********************************************************************************************
  2122. * FirewallHelperClass::Set_Client_Connect_Event -- Set client event completion info *
  2123. * *
  2124. * *
  2125. * *
  2126. * INPUT: Event *
  2127. * Ptr to success flag *
  2128. * *
  2129. * OUTPUT: Nothing *
  2130. * *
  2131. * WARNINGS: None *
  2132. * *
  2133. * HISTORY: *
  2134. * 8/14/2001 10:56PM ST : Created *
  2135. *=============================================================================================*/
  2136. void FirewallHelperClass::Set_Client_Connect_Event(HANDLE thread_event, HANDLE cancel_event, int *flag_ptr, int *queue_ptr)
  2137. {
  2138. ThreadLockClass locker(this);
  2139. fw_assert(!WOLNATInterface.Am_I_Server());
  2140. if (!WOLNATInterface.Am_I_Server()) {
  2141. SuccessFlagPtr = flag_ptr;
  2142. ClientConnectEvent = thread_event;
  2143. ClientCancelEvent = cancel_event;
  2144. QueueNotifyPtr = queue_ptr;
  2145. }
  2146. }
  2147. /***********************************************************************************************
  2148. * FirewallHelperClass::Set_Client_Success -- Set the client connect return status *
  2149. * *
  2150. * *
  2151. * *
  2152. * INPUT: Success - Did the client get a good port and IP for the server *
  2153. * *
  2154. * OUTPUT: Nothing *
  2155. * *
  2156. * WARNINGS: None *
  2157. * *
  2158. * HISTORY: *
  2159. * 8/14/2001 10:59PM ST : Created *
  2160. *=============================================================================================*/
  2161. void FirewallHelperClass::Set_Client_Success(int success)
  2162. {
  2163. if (!WOLNATInterface.Am_I_Server()) {
  2164. if (SuccessFlagPtr) {
  2165. *SuccessFlagPtr = success;
  2166. }
  2167. SuccessFlagPtr = NULL;
  2168. if (QueueNotifyPtr) {
  2169. *QueueNotifyPtr = 0;
  2170. }
  2171. QueueNotifyPtr = NULL;
  2172. if (ClientConnectEvent != INVALID_HANDLE_VALUE) {
  2173. SetEvent(ClientConnectEvent);
  2174. }
  2175. ClientConnectEvent = INVALID_HANDLE_VALUE;
  2176. ClientCancelEvent = INVALID_HANDLE_VALUE;
  2177. }
  2178. }
  2179. /***********************************************************************************************
  2180. * FirewallHelperClass::Client_Cancelled -- Checks to see if the player hit cancel. *
  2181. * *
  2182. * *
  2183. * *
  2184. * INPUT: Nothing *
  2185. * *
  2186. * OUTPUT: True if player cancelled *
  2187. * *
  2188. * WARNINGS: None *
  2189. * *
  2190. * HISTORY: *
  2191. * 8/17/2001 12:04PM ST : Created *
  2192. *=============================================================================================*/
  2193. bool FirewallHelperClass::Client_Cancelled(void)
  2194. {
  2195. if (!WOLNATInterface.Am_I_Server()) {
  2196. ThreadLockClass locker(this);
  2197. if (ClientCancelEvent != INVALID_HANDLE_VALUE) {
  2198. int result = WaitForSingleObject(ClientCancelEvent, 0);
  2199. if (result == WAIT_OBJECT_0) {
  2200. WWDEBUG_SAY(("FirewallHelper - Client cancelled\n"));
  2201. return(true);
  2202. }
  2203. }
  2204. }
  2205. return(false);
  2206. }
  2207. /***********************************************************************************************
  2208. * FirewallHelperClass::Remote_Client_Cancelled -- Did the remote client hit cancel? *
  2209. * *
  2210. * *
  2211. * *
  2212. * INPUT: True if our client cancelled *
  2213. * *
  2214. * OUTPUT: Nothing *
  2215. * *
  2216. * WARNINGS: Requres PlayersName variable to be correctly set up *
  2217. * Will only return true once for each cancellation *
  2218. * *
  2219. * HISTORY: *
  2220. * 8/19/2001 9:26PM ST : Created *
  2221. *=============================================================================================*/
  2222. bool FirewallHelperClass::Remote_Client_Cancelled(void)
  2223. {
  2224. ThreadLockClass locker(this);
  2225. if (WOLNATInterface.Am_I_Server() && CancelPlayer[0] != 0) {
  2226. if (stricmp(CancelPlayer, PlayersName) == 0) {
  2227. CancelPlayer[0] = 0;
  2228. return(true);
  2229. }
  2230. }
  2231. return(false);
  2232. }
  2233. /***********************************************************************************************
  2234. * FirewallHelperClass::Send_Cancel_Notification -- Send abort to host *
  2235. * *
  2236. * *
  2237. * *
  2238. * INPUT: Nothing *
  2239. * *
  2240. * OUTPUT: Nothing *
  2241. * *
  2242. * WARNINGS: None *
  2243. * *
  2244. * HISTORY: *
  2245. * 8/19/2001 9:32PM ST : Created *
  2246. *=============================================================================================*/
  2247. void FirewallHelperClass::Send_Cancel_Notification(void)
  2248. {
  2249. fw_assert(!WOLNATInterface.Am_I_Server());
  2250. if (!WOLNATInterface.Am_I_Server()) {
  2251. ThreadLockClass locker(this);
  2252. WWDEBUG_SAY(("FirewallHelper - Sending my cancellation notice to the server\n"));
  2253. /*
  2254. ** Fill in an abort notification options packet to send to the host.
  2255. */
  2256. WOLNATInterfaceClass::PrivateGameOptionsStruct options;
  2257. strcpy(options.NATOptionsPrefix, "NAT:");
  2258. options.Option = WOLNATInterfaceClass::OPTION_ABORT_NEGOTIATION;
  2259. options.OptionData.QuitTalking.Nothing = 0;
  2260. /*
  2261. ** Send it.
  2262. */
  2263. WOLNATInterface.Send_Private_Game_Options(&PlayerAsUser, (char*)&options);
  2264. }
  2265. }
  2266. /***********************************************************************************************
  2267. * FirewallHelperClass::Negotiate_Port -- Option communications with one other player *
  2268. * *
  2269. * *
  2270. * *
  2271. * INPUT: Nothing *
  2272. * *
  2273. * OUTPUT: True if we heard from the other player directly *
  2274. * *
  2275. * WARNINGS: None *
  2276. * *
  2277. * HISTORY: *
  2278. * 8/7/2001 8:54PM ST : Created *
  2279. *=============================================================================================*/
  2280. int FirewallHelperClass::Negotiate_Port(void)
  2281. {
  2282. int retries = 5;
  2283. unsigned long timeout;
  2284. unsigned long resend_timer;
  2285. bool mangling = true;
  2286. bool sharing_a_nat = false;
  2287. int result;
  2288. IPAddressClass address;
  2289. bool gotit = false;
  2290. SocketHandlerClass *socket = NULL;
  2291. char receive_packet[512];
  2292. char my_name[256];
  2293. my_name[0] = 0;
  2294. bool server = WOLNATInterface.Am_I_Server();
  2295. bool got_name = WOLNATInterface.Get_My_Name(my_name);
  2296. fw_assert(got_name);
  2297. if (!got_name) {
  2298. WWDEBUG_SAY(("FirewallHelper - Failed to get user log on name\n"));
  2299. return(FW_RESULT_FAILED);
  2300. }
  2301. PlayersMangledPort = 0;
  2302. PlayersConnectionResult = -1;
  2303. PlayersConnectionResultPort = 0;
  2304. /*
  2305. ** On the server side, we need to find out who we are supposed to be connecting to.
  2306. ** We will use the game comms to send and receive on the server side since we already have a socket bound to the port
  2307. ** we want to use.
  2308. */
  2309. if (server) {
  2310. if (ClientQueue.Count() == 0) {
  2311. return(FW_RESULT_FAILED);
  2312. }
  2313. /*
  2314. ** Update everyones queue state.
  2315. */
  2316. Send_Queue_States();
  2317. ClientStruct *client = ClientQueue[0];
  2318. PlayersLocalAddress = client->LocalAddress;
  2319. PlayersExternalAddress = client->ExternalAddress;
  2320. PlayersFirewallType = client->FirewallType;
  2321. PlayerAsUser = client->User;
  2322. strcpy(PlayersName, client->Name);
  2323. LastOptionsFromClient = TIMEGETTIME();
  2324. delete client;
  2325. ClientQueue.Delete(0);
  2326. WWDEBUG_SAY(("FirewallHelper - Removed next player %s from client queue\n", PlayersName));
  2327. if (Remote_Client_Cancelled()) {
  2328. return(FW_RESULT_FAILED);
  2329. }
  2330. CancelPlayer[0] = 0;
  2331. } else {
  2332. /*
  2333. ** On the client side, we need to open a new socket using the client side port number. Use any port number for the
  2334. ** second parameter since it's the default send port and will always be overridden when we send anyway.
  2335. */
  2336. socket = new SocketHandlerClass;
  2337. socket->Service_Never();
  2338. if (!socket->Open(ClientPort, PlayersLocalAddress.Get_Port())) {
  2339. WWDEBUG_SAY(("FirewallHelperClass: Failed to open socket for client\n"));
  2340. fw_assert(false);
  2341. delete socket;
  2342. return(FW_RESULT_FAILED);
  2343. }
  2344. WOLNATInterface.Set_Service_Socket_Handler(socket);
  2345. /*
  2346. ** If we aren't sure of the queue size then wait until we are.
  2347. */
  2348. if (QueuedPlayers == -1) {
  2349. timeout = TIMEGETTIME() + (8 * TIMER_SECOND);
  2350. while (TIMEGETTIME() < timeout && QueuedPlayers == -1) {
  2351. Process_Game_Options();
  2352. Sleep(5);
  2353. /*
  2354. ** See if the user cancelled.
  2355. */
  2356. if (Client_Cancelled()) {
  2357. Send_Cancel_Notification();
  2358. WOLNATInterface.Set_Service_Socket_Handler(NULL);
  2359. delete socket;
  2360. return(FW_RESULT_CANCELLED);
  2361. }
  2362. }
  2363. }
  2364. if (QueuedPlayers == -1) {
  2365. /*
  2366. ** This should never happen right....?
  2367. */
  2368. if (socket) {
  2369. WOLNATInterface.Set_Service_Socket_Handler(NULL);
  2370. delete socket;
  2371. }
  2372. return(FW_RESULT_FAILED);
  2373. }
  2374. /*
  2375. ** If there are players queued ahead of us, wait til we get to the front of the queue.
  2376. */
  2377. timeout = TIMEGETTIME() + (QueuedPlayers * 32 * TIMER_SECOND);
  2378. while (TIMEGETTIME() < timeout && QueuedPlayers != 0) {
  2379. Process_Game_Options();
  2380. Sleep(5);
  2381. /*
  2382. ** See if the user cancelled.
  2383. */
  2384. if (Client_Cancelled()) {
  2385. Send_Cancel_Notification();
  2386. WOLNATInterface.Set_Service_Socket_Handler(NULL);
  2387. delete socket;
  2388. return(FW_RESULT_CANCELLED);
  2389. }
  2390. }
  2391. }
  2392. PlayersFirewallAddress = PlayersExternalAddress;
  2393. PlayersFirewallAddress.Set_Port(PlayersLocalAddress.Get_Port());
  2394. WWDEBUG_SAY(("FirewallHelper - Negotiating port with player %s, local address = %s,", PlayersName, PlayersLocalAddress.As_String()));
  2395. WWDEBUG_SAY((" ext address = %s, firewall = %08x\n", PlayersExternalAddress.As_String(), PlayersFirewallType));
  2396. /*
  2397. ** What will our mangled port be if we try to talk to this player?
  2398. **
  2399. ** If they are behind the same firewall then there will be no mangling.
  2400. **
  2401. */
  2402. if (PlayersExternalAddress.Is_IP_Equal(ExternalAddress)) {
  2403. mangling = false;
  2404. sharing_a_nat = true;
  2405. PlayersFirewallAddress = PlayersLocalAddress;
  2406. WWDEBUG_SAY(("Both external IPs match - we are behind the same firewall\n"));
  2407. }
  2408. /*
  2409. ** Maybe neither of our firewalls use port mangling. If so, then we can use the default port number.
  2410. */
  2411. if (mangling) {
  2412. if (Behavior == 0 || (Behavior & FIREWALL_TYPE_SIMPLE) != 0) {
  2413. if (PlayersFirewallType == 0 || (PlayersFirewallType & FIREWALL_TYPE_SIMPLE) != 0) {
  2414. /*
  2415. ** Ok, we both have crap firewalls or modems or somesuch. Anyway, this should be easy.
  2416. */
  2417. mangling = false;
  2418. }
  2419. }
  2420. }
  2421. int trying = 0;
  2422. unsigned short last_send_port = 0;
  2423. unsigned short my_last_mangled_port = 0;
  2424. unsigned short verified_mangled_port = 0;
  2425. bool used_old_port = false;
  2426. do {
  2427. Sleep(0);
  2428. /*
  2429. ** See if the user cancelled.
  2430. */
  2431. if (Client_Cancelled()) {
  2432. Send_Cancel_Notification();
  2433. WOLNATInterface.Set_Service_Socket_Handler(NULL);
  2434. delete socket;
  2435. return(FW_RESULT_CANCELLED);
  2436. }
  2437. if (Remote_Client_Cancelled()) {
  2438. return(FW_RESULT_FAILED);
  2439. }
  2440. /*
  2441. ** If we haven't got any kind of options at all from the client for 10 seconds then give up.
  2442. */
  2443. if (trying > 0 && server && (TIMEGETTIME() - LastOptionsFromClient > TIMER_SECOND * 10)) {
  2444. break;
  2445. }
  2446. if (!mangling) {
  2447. /*
  2448. ** Use their unmangled port number. Nothing fancy needed here.
  2449. */
  2450. PlayersMangledPort = PlayersLocalAddress.Get_Port();
  2451. } else {
  2452. unsigned short mangled_port = 0;
  2453. /*
  2454. ** If our firewall uses the same source port regardless of destination port and we have
  2455. ** already connected to someone at this address (two players behind the same NAT) then
  2456. ** we have to try the same source port we are already talking to the other guy on.
  2457. **
  2458. ** If that's not working out then try a different port after two attempts.
  2459. */
  2460. if (server && trying < 2) {
  2461. if ((Behavior & FirewallHelperClass::FIREWALL_TYPE_DESTINATION_PORT_DELTA) == 0) {
  2462. WWDEBUG_SAY(("FirewallHelper: No destination port delta - looking for earlier connections at the same address\n"));
  2463. for (int r = 0 ; r < ConnectionHistory.Count() ; r++) {
  2464. if (ConnectionHistory[r].Is_IP_Equal(PlayersExternalAddress)) {
  2465. mangled_port = MangledPortHistory[r];
  2466. used_old_port = true;
  2467. WWDEBUG_SAY(("FirewallHelper - Found old connection port number to use - port number %d\n", mangled_port));
  2468. break;
  2469. }
  2470. }
  2471. }
  2472. }
  2473. /*
  2474. ** If this isn't the first try then we might already know what the port will be since it can't change between tries.
  2475. */
  2476. if (mangled_port == 0) {
  2477. if ((Behavior & FirewallHelperClass::FIREWALL_TYPE_DESTINATION_PORT_DELTA) == 0) {
  2478. if (trying > 0) {
  2479. if (!used_old_port) {
  2480. mangled_port = my_last_mangled_port;
  2481. WWDEBUG_SAY(("FirewallHelper - No dest port delta - using last port number %d\n", mangled_port));
  2482. } else {
  2483. used_old_port = false;
  2484. }
  2485. }
  2486. }
  2487. }
  2488. if (mangled_port == 0) {
  2489. /*
  2490. ** Work out what my port will be.
  2491. */
  2492. unsigned short base_port = 0;
  2493. if (server) {
  2494. base_port = WOLNATInterface.Get_Port_As_Server();
  2495. } else {
  2496. /*
  2497. ** Client only. Roll onto the next port and try that.
  2498. */
  2499. if (trying > 0) {
  2500. WOLNATInterface.Set_Service_Socket_Handler(NULL);
  2501. Sleep(100);
  2502. socket->Close();
  2503. for (int cp=0 ; cp < 2048 ; cp++) {
  2504. ClientPort = WOLNATInterface.Get_Next_Client_Port();
  2505. if (socket->Open(ClientPort, PlayersLocalAddress.Get_Port())) {
  2506. break;
  2507. } else {
  2508. socket->Close();
  2509. ClientPort = 0;
  2510. }
  2511. }
  2512. fw_assert(ClientPort != 0);
  2513. WOLNATInterface.Set_Service_Socket_Handler(socket);
  2514. }
  2515. if (ClientPort != 0) {
  2516. base_port = ClientPort;
  2517. }
  2518. }
  2519. /*
  2520. ** Get my mangled port. This can take up to 4 seconds.
  2521. */
  2522. mangled_port = FirewallHelper.Get_Next_Mangled_Source_Port(base_port);
  2523. }
  2524. /*
  2525. ** Send my mangled port to the other chap.
  2526. */
  2527. fw_assert(mangled_port != 0);
  2528. Send_My_Port(mangled_port);
  2529. my_last_mangled_port = mangled_port;
  2530. }
  2531. /*
  2532. ** Wait until we know what port to send to. Allow plenty of time for slow chat server response.
  2533. ** Players are more likely to be in 'sync' with each other after the first try.
  2534. */
  2535. timeout = TIMEGETTIME() + (6 * TIMER_SECOND);
  2536. if (trying > 0) {
  2537. timeout = timeout - (3*TIMER_SECOND);
  2538. }
  2539. while (TIMEGETTIME() < timeout && ((mangling == true && PlayersMangledPort == last_send_port) || (mangling == false && PlayersMangledPort == 0))) {
  2540. Process_Game_Options();
  2541. Sleep(5);
  2542. /*
  2543. ** See if the user cancelled.
  2544. */
  2545. if (Client_Cancelled()) {
  2546. Send_Cancel_Notification();
  2547. WOLNATInterface.Set_Service_Socket_Handler(NULL);
  2548. delete socket;
  2549. return(FW_RESULT_CANCELLED);
  2550. }
  2551. if (Remote_Client_Cancelled()) {
  2552. return(FW_RESULT_FAILED);
  2553. }
  2554. }
  2555. if (verified_mangled_port != 0) {
  2556. PlayersMangledPort = verified_mangled_port;
  2557. }
  2558. last_send_port = PlayersMangledPort;
  2559. PlayersFirewallAddress.Set_Port(PlayersMangledPort);
  2560. if (PlayersMangledPort == 0) {
  2561. WWDEBUG_SAY(("FirewallHelper: PlayersMangledPort = 0 - skipping packet send\n"));
  2562. }
  2563. if (PlayersMangledPort != 0) {
  2564. /*
  2565. ** OK, we know what port to send to. Let dooooo it.
  2566. */
  2567. /*
  2568. ** Build the port probe packet to send.
  2569. */
  2570. char packet[256];
  2571. strcpy(packet, my_name);
  2572. /*
  2573. ** If we are a netgear and talking to a non netgear then pause before sending.
  2574. **
  2575. ** This is needed when playing a netgear against a linksys. If the netgear sends first
  2576. ** then the linksys can respond with a ICMP port unreachable message in the case that
  2577. ** it already has an open port table mapping with a pre-existing player.
  2578. **
  2579. ** When it gets an ICMP port unreachable, the netgear invalidates any existing port mappings.
  2580. **
  2581. ** The delay has to be long enough for our port number to be passed through the chat server
  2582. ** to the other guy and for him to start sending.
  2583. */
  2584. if (Is_Netgear() && !Is_Netgear(PlayersFirewallType)) {
  2585. WWDEBUG_SAY(("FirewallHelper: Doing the netgear sleep thing\n"));
  2586. Sleep(TIMER_SECOND * 4);
  2587. }
  2588. /*
  2589. ** Send the packet to the other player. If a NAT mangles an outgoing port number then it will be noted
  2590. ** as the packet comes in.
  2591. */
  2592. WWDEBUG_SAY(("FirewallHelper: Sending PACKETTYPE_FIREWALL_PROBE packet to %s at port %d\n", PlayersName, PlayersMangledPort));
  2593. timeout = TIMEGETTIME() + (TIMER_SECOND * 6);
  2594. resend_timer = 0;
  2595. do {
  2596. if (resend_timer < TIMEGETTIME()) {
  2597. //if (!CrapFlag)
  2598. WOLNATInterface.Send_Game_Format_Packet_To(&PlayersFirewallAddress, packet, strlen(packet)+1, socket);
  2599. resend_timer = TIMEGETTIME() + (TIMER_SECOND / 2);
  2600. }
  2601. Sleep(5);
  2602. Process_Game_Options();
  2603. /*
  2604. ** See if the user cancelled.
  2605. */
  2606. if (Client_Cancelled()) {
  2607. Send_Cancel_Notification();
  2608. WOLNATInterface.Set_Service_Socket_Handler(NULL);
  2609. delete socket;
  2610. return(FW_RESULT_CANCELLED);
  2611. }
  2612. if (Remote_Client_Cancelled()) {
  2613. return(FW_RESULT_FAILED);
  2614. }
  2615. //if (!gotit) {
  2616. /*
  2617. ** See if a port probe came in from this player.
  2618. */
  2619. IPAddressClass receive_address;
  2620. result = WOLNATInterface.Get_Packet(receive_packet, sizeof(receive_packet), receive_address);
  2621. /*
  2622. ** Check if we got a packet from this game.
  2623. */
  2624. if (result) {
  2625. WWDEBUG_SAY(("FirewallHelper: Got a packet from player %s at address %s\n", receive_packet, receive_address.As_String()));
  2626. /*
  2627. ** Is it from the guy we are trying to talk to?
  2628. */
  2629. if (stricmp(receive_packet, PlayersName) == 0) {
  2630. WWDEBUG_SAY(("FirewallHelper: Packet is from other guy\n"));
  2631. /*
  2632. ** Send a connection result game option.
  2633. */
  2634. Send_Connection_Result(CONNRESULT_CONNECTED, receive_address.Get_Port());
  2635. /*
  2636. ** Note the address the packet came in on.
  2637. */
  2638. PlayersFirewallAddress = receive_address;
  2639. verified_mangled_port = receive_address.Get_Port();
  2640. /*
  2641. ** Got it.
  2642. */
  2643. gotit = true;
  2644. }
  2645. }
  2646. //}
  2647. /*
  2648. ** If the other player got our packet and we got theirs then we are finished.
  2649. */
  2650. if (gotit && PlayersConnectionResult == CONNRESULT_CONNECTED) {
  2651. WWDEBUG_SAY(("FirewallHelper: Got connection result - my packet must have got through\n"));
  2652. break;
  2653. }
  2654. /*
  2655. ** If the other guy has started re-trying then we might as well do that too.
  2656. */
  2657. if (PlayersConnectionResult >= CONNRESULT_TRY1 && PlayersConnectionResult < CONNRESULT_CONNECTED) {
  2658. int their_try = PlayersConnectionResult - CONNRESULT_TRY1;
  2659. if (their_try > trying) {
  2660. WWDEBUG_SAY(("FirewallHelper: Other player is trying again - their_try = %d\n", their_try));
  2661. trying = their_try - 1;
  2662. break;
  2663. }
  2664. }
  2665. } while(TIMEGETTIME() < timeout);
  2666. }
  2667. if (gotit && PlayersConnectionResult == CONNRESULT_CONNECTED) {
  2668. break;
  2669. }
  2670. if (trying >= retries) {
  2671. break;
  2672. }
  2673. /*
  2674. ** Well, that didn't go too well, let's try again.
  2675. */
  2676. trying++;
  2677. Send_Connection_Result(CONNRESULT_TRY1 + trying, 0);
  2678. WWDEBUG_SAY(("FirewallHelper: Trying again - trying = %d\n", trying));
  2679. } while(true);
  2680. if (socket) {
  2681. WOLNATInterface.Set_Service_Socket_Handler(NULL);
  2682. delete socket;
  2683. }
  2684. if (gotit && PlayersConnectionResult == CONNRESULT_CONNECTED) {
  2685. WWDEBUG_SAY(("FirewallHelper: Port negotiation successful! Correct address is %s\n", PlayersFirewallAddress.As_String()));
  2686. WWDEBUG_SAY(("Player saw our port as %d\n", (unsigned long)PlayersConnectionResultPort));
  2687. /*
  2688. ** Well it worked so we have more confidence in our firewall settings.
  2689. */
  2690. Confidence++;
  2691. /*
  2692. ** Save the port number in case we have to connect to this guy again.
  2693. */
  2694. if (server) {
  2695. unsigned short history_port = PlayersConnectionResultPort;
  2696. if (history_port == 0) {
  2697. history_port = my_last_mangled_port;
  2698. }
  2699. bool found_history = false;
  2700. for (int h=0 ; h<ConnectionHistory.Count() ; h++) {
  2701. if (ConnectionHistory[h].Is_IP_Equal(PlayersExternalAddress)) {
  2702. MangledPortHistory[h] = history_port;
  2703. found_history = true;
  2704. break;
  2705. }
  2706. }
  2707. if (!found_history) {
  2708. ConnectionHistory.Add(PlayersExternalAddress);
  2709. MangledPortHistory.Add(history_port);
  2710. }
  2711. fw_assert(ConnectionHistory.Count() == MangledPortHistory.Count());
  2712. }
  2713. return(FW_RESULT_SUCCEEDED);
  2714. } else {
  2715. WWDEBUG_SAY(("FirewallHelper: *** Port negotiation failed! ***\n"));
  2716. Confidence--;
  2717. if (Confidence < 0) {
  2718. Confidence = 0;
  2719. }
  2720. }
  2721. return(FW_RESULT_FAILED);
  2722. }
  2723. /*
  2724. ** Function definitions for the MIB-II entry points.
  2725. */
  2726. BOOL (__stdcall *SnmpExtensionInitPtr)(IN DWORD dwUpTimeReference, OUT HANDLE *phSubagentTrapEvent, OUT AsnObjectIdentifier *pFirstSupportedRegion);
  2727. BOOL (__stdcall *SnmpExtensionQueryPtr)(IN BYTE bPduType, IN OUT RFC1157VarBindList *pVarBindList, OUT AsnInteger32 *pErrorStatus, OUT AsnInteger32 *pErrorIndex);
  2728. LPVOID (__stdcall *SnmpUtilMemAllocPtr)(IN DWORD bytes);
  2729. VOID (__stdcall *SnmpUtilMemFreePtr)(IN LPVOID pMem);
  2730. typedef struct tConnInfoStruct {
  2731. unsigned int State;
  2732. unsigned long LocalIP;
  2733. unsigned short LocalPort;
  2734. unsigned long RemoteIP;
  2735. unsigned short RemotePort;
  2736. } ConnInfoStruct;
  2737. /***********************************************************************************************
  2738. * Get_Local_Chat_Connection_Address -- Which address are we using to talk to the chat server? *
  2739. * *
  2740. * *
  2741. * *
  2742. * INPUT: Ptr to address to return local address * *
  2743. * *
  2744. * OUTPUT: True if success *
  2745. * *
  2746. * WARNINGS: None *
  2747. * *
  2748. * HISTORY: *
  2749. * 10/27/00 3:24PM ST : Created *
  2750. *=============================================================================================*/
  2751. bool FirewallHelperClass::Get_Local_Chat_Connection_Address(void)
  2752. {
  2753. /*
  2754. ** Local defines.
  2755. */
  2756. enum {
  2757. CLOSED = 1,
  2758. LISTENING,
  2759. SYN_SENT,
  2760. SEN_RECEIVED,
  2761. ESTABLISHED,
  2762. FIN_WAIT,
  2763. FIN_WAIT2,
  2764. CLOSE_WAIT,
  2765. LAST_ACK,
  2766. CLOSING,
  2767. TIME_WAIT,
  2768. DELETE_TCB
  2769. };
  2770. enum {
  2771. tcpConnState = 1,
  2772. tcpConnLocalAddress,
  2773. tcpConnLocalPort,
  2774. tcpConnRemAddress,
  2775. tcpConnRemPort
  2776. };
  2777. /*
  2778. ** Locals.
  2779. */
  2780. char server_name[128];
  2781. unsigned char server_address[4];
  2782. unsigned char remote_address[4];
  2783. HANDLE trap_handle;
  2784. AsnObjectIdentifier first_supported_region;
  2785. DynamicVectorClass<ConnInfoStruct*> connection_list;
  2786. int last_field;
  2787. int index;
  2788. AsnInteger error_status;
  2789. AsnInteger error_index;
  2790. int conn_entry_type_index;
  2791. int conn_entry_type;
  2792. bool found;
  2793. unsigned int server_port = 0;
  2794. IPAddressClass my_address;
  2795. /*
  2796. ** Statics.
  2797. */
  2798. static char _conn_state[][32] = {
  2799. "?",
  2800. "CLOSED",
  2801. "LISTENING",
  2802. "SYN_SENT",
  2803. "SEN_RECEIVED",
  2804. "ESTABLISHED",
  2805. "FIN_WAIT",
  2806. "FIN_WAIT2",
  2807. "CLOSE_WAIT",
  2808. "LAST_ACK",
  2809. "CLOSING",
  2810. "TIME_WAIT",
  2811. "DELETE_TCB"
  2812. };
  2813. /*
  2814. ** If we already did this then there's no need to do it again.
  2815. */
  2816. if (LocalChatConnectionAddress.Is_Valid()) {
  2817. return(true);
  2818. }
  2819. WWDEBUG_SAY(("FirewallHelper - Finding local address used to talk to the chat server\n"));
  2820. /*
  2821. ** Get the name of the current server.
  2822. */
  2823. WOLNATInterface.Get_Current_Server_ConnData(server_name, sizeof(server_name));
  2824. if (strlen(server_name) == 0) {
  2825. return(false);
  2826. }
  2827. /*
  2828. ** the conndata field will look something like
  2829. **
  2830. ** TCP;ra2chat.westwood.com;7000
  2831. */
  2832. fw_assert(strnicmp((char*)server_name, "TCP;", 4) == 0);
  2833. char *server_name_ptr = &server_name[4];
  2834. char *semi_colon_ptr = strchr(server_name_ptr, ';');
  2835. if (semi_colon_ptr) {
  2836. *semi_colon_ptr = 0;
  2837. sscanf(semi_colon_ptr+1, "%d", &server_port);
  2838. } else {
  2839. WWDEBUG_SAY(("FirewallHelper - Failed to parse server name\n"));
  2840. return(false);
  2841. }
  2842. WWDEBUG_SAY(("FirewallHelper - Current chat server name is %s\n", server_name_ptr));
  2843. WWDEBUG_SAY(("FirewallHelper - Chat server port is %d\n", server_port));
  2844. /*
  2845. ** Get the address of the chat server.
  2846. */
  2847. WWDEBUG_SAY(("FirewallHelper - About to call gethostbyname\n"));
  2848. struct hostent *host_info = gethostbyname(server_name_ptr);
  2849. if (!host_info) {
  2850. WWDEBUG_SAY(("FirewallHelper - gethostbyname failed! Error code %d\n", WSAGetLastError()));
  2851. return(false);
  2852. }
  2853. memcpy(server_address, &host_info->h_addr_list[0][0], 4);
  2854. unsigned long temp = *((unsigned long*)(&server_address[0]));
  2855. temp = ntohl(temp);
  2856. *((unsigned long*)(&server_address[0])) = temp;
  2857. WWDEBUG_SAY(("FirewallHelper - Host address is %d.%d.%d.%d\n", server_address[3], server_address[2], server_address[1], server_address[0]));
  2858. /*
  2859. ** Load the MIB-II SNMP DLL.
  2860. */
  2861. WWDEBUG_SAY(("FirewallHelper - About to load INETMIB1.DLL\n"));
  2862. HINSTANCE mib_ii_dll = LoadLibrary("inetmib1.dll");
  2863. if (mib_ii_dll == NULL) {
  2864. WWDEBUG_SAY(("FirewallHelper - Failed to load INETMIB1.DLL\n"));
  2865. return(false);
  2866. }
  2867. WWDEBUG_SAY(("FirewallHelper - About to load SNMPAPI.DLL\n"));
  2868. HINSTANCE snmpapi_dll = LoadLibrary("snmpapi.dll");
  2869. if (snmpapi_dll == NULL) {
  2870. WWDEBUG_SAY(("FirewallHelper - Failed to load SNMPAPI.DLL\n"));
  2871. FreeLibrary(mib_ii_dll);
  2872. return(false);
  2873. }
  2874. /*
  2875. ** Get the function pointers into the .dll
  2876. */
  2877. SnmpExtensionInitPtr = (int (__stdcall *)(unsigned long,void ** ,AsnObjectIdentifier *)) GetProcAddress(mib_ii_dll, "SnmpExtensionInit");
  2878. SnmpExtensionQueryPtr = (int (__stdcall *)(unsigned char,SnmpVarBindList *,long *,long *)) GetProcAddress(mib_ii_dll, "SnmpExtensionQuery");
  2879. SnmpUtilMemAllocPtr = (void *(__stdcall *)(unsigned long)) GetProcAddress(snmpapi_dll, "SnmpUtilMemAlloc");
  2880. SnmpUtilMemFreePtr = (void (__stdcall *)(void *)) GetProcAddress(snmpapi_dll, "SnmpUtilMemFree");
  2881. if (SnmpExtensionInitPtr == NULL || SnmpExtensionQueryPtr == NULL || SnmpUtilMemAllocPtr == NULL || SnmpUtilMemFreePtr == NULL) {
  2882. WWDEBUG_SAY(("FirewallHelper - Failed to get proc addresses for linked functions\n"));
  2883. FreeLibrary(snmpapi_dll);
  2884. FreeLibrary(mib_ii_dll);
  2885. return(false);
  2886. }
  2887. RFC1157VarBindList *bind_list_ptr = (RFC1157VarBindList *) SnmpUtilMemAllocPtr(sizeof(RFC1157VarBindList) + 8192);
  2888. RFC1157VarBind *bind_ptr = (RFC1157VarBind *) SnmpUtilMemAllocPtr(sizeof(RFC1157VarBind) + 128);
  2889. /*
  2890. ** OK, here we go. Try to initialise the .dll
  2891. */
  2892. WWDEBUG_SAY(("FirewallHelper - About to init INETMIB1.DLL\n"));
  2893. int ok = SnmpExtensionInitPtr(GetCurrentTime(), &trap_handle, &first_supported_region);
  2894. if (!ok) {
  2895. /*
  2896. ** Aw crap.
  2897. */
  2898. WWDEBUG_SAY(("FirewallHelper - Failed to init the .dll\n"));
  2899. SnmpUtilMemFreePtr(bind_list_ptr);
  2900. SnmpUtilMemFreePtr(bind_ptr);
  2901. FreeLibrary(snmpapi_dll);
  2902. FreeLibrary(mib_ii_dll);
  2903. return(false);
  2904. }
  2905. /*
  2906. ** Name of mib_ii object we want to query. See RFC 1213.
  2907. **
  2908. ** iso.org.dod.internet.mgmt.mib-2.tcp.tcpConnTable.TcpConnEntry.tcpConnState
  2909. ** 1 3 6 1 2 1 6 13 1 1
  2910. */
  2911. unsigned int mib_ii_name[] = {1,3,6,1,2,1,6,13,1,1};
  2912. unsigned int *mib_ii_name_ptr = (unsigned int *) SnmpUtilMemAllocPtr(sizeof(mib_ii_name) + 1024);
  2913. memcpy(mib_ii_name_ptr, mib_ii_name, sizeof(mib_ii_name));
  2914. /*
  2915. ** Get the index of the conn entry data.
  2916. */
  2917. conn_entry_type_index = ARRAY_SIZE(mib_ii_name) - 1;
  2918. /*
  2919. ** Set up the bind list.
  2920. */
  2921. bind_ptr->name.idLength = ARRAY_SIZE(mib_ii_name);
  2922. bind_ptr->name.ids = mib_ii_name_ptr;
  2923. bind_list_ptr->list = bind_ptr;
  2924. bind_list_ptr->len = 1;
  2925. /*
  2926. ** We start with the tcpConnLocalAddress field.
  2927. */
  2928. last_field = 1;
  2929. /*
  2930. ** First connection.
  2931. */
  2932. index = 0;
  2933. /*
  2934. ** Suck out that tcp connection info....
  2935. */
  2936. while (true) {
  2937. if (!SnmpExtensionQueryPtr(ASN_RFC1157_GETNEXTREQUEST, bind_list_ptr, &error_status, &error_index)) {
  2938. WWDEBUG_SAY(("FirewallHelper - SnmpExtensionQuery returned false\n"));
  2939. SnmpUtilMemFreePtr(bind_list_ptr);
  2940. SnmpUtilMemFreePtr(bind_ptr);
  2941. FreeLibrary(snmpapi_dll);
  2942. FreeLibrary(mib_ii_dll);
  2943. return(false);
  2944. }
  2945. /*
  2946. ** If this is something new we aren't looking for then we are done.
  2947. */
  2948. if (bind_ptr->name.idLength < ARRAY_SIZE(mib_ii_name)) {
  2949. break;
  2950. }
  2951. /*
  2952. ** Get the type of info we are looking at. See RFC1213.
  2953. **
  2954. ** 1 = tcpConnState
  2955. ** 2 = tcpConnLocalAddress
  2956. ** 3 = tcpConnLocalPort
  2957. ** 4 = tcpConnRemAddress
  2958. ** 5 = tcpConnRemPort
  2959. **
  2960. ** tcpConnState is one of the following...
  2961. **
  2962. ** 1 closed
  2963. ** 2 listen
  2964. ** 3 synSent
  2965. ** 4 synReceived
  2966. ** 5 established
  2967. ** 6 finWait1
  2968. ** 7 finWait2
  2969. ** 8 closeWait
  2970. ** 9 lastAck
  2971. ** 10 closing
  2972. ** 11 timeWait
  2973. ** 12 deleteTCB
  2974. */
  2975. conn_entry_type = bind_ptr->name.ids[conn_entry_type_index];
  2976. if (last_field != conn_entry_type) {
  2977. index = 0;
  2978. last_field = conn_entry_type;
  2979. }
  2980. switch (conn_entry_type) {
  2981. /*
  2982. ** 1. First field in the entry. Need to create a new connection info struct
  2983. ** here to store this connection in.
  2984. */
  2985. case tcpConnState:
  2986. {
  2987. ConnInfoStruct *new_conn = new ConnInfoStruct;
  2988. new_conn->State = bind_ptr->value.asnValue.number;
  2989. connection_list.Add(new_conn);
  2990. break;
  2991. }
  2992. /*
  2993. ** 2. Local address field.
  2994. */
  2995. case tcpConnLocalAddress:
  2996. fw_assert(index < connection_list.Count());
  2997. connection_list[index]->LocalIP = *((unsigned long*)bind_ptr->value.asnValue.address.stream);
  2998. index++;
  2999. break;
  3000. /*
  3001. ** 3. Local port field.
  3002. */
  3003. case tcpConnLocalPort:
  3004. fw_assert(index < connection_list.Count());
  3005. connection_list[index]->LocalPort = bind_ptr->value.asnValue.number;
  3006. index++;
  3007. break;
  3008. /*
  3009. ** 4. Remote address field.
  3010. */
  3011. case tcpConnRemAddress:
  3012. fw_assert(index < connection_list.Count());
  3013. connection_list[index]->RemoteIP = *((unsigned long*)bind_ptr->value.asnValue.address.stream);
  3014. index++;
  3015. break;
  3016. /*
  3017. ** 5. Remote port field.
  3018. */
  3019. case tcpConnRemPort:
  3020. fw_assert(index < connection_list.Count());
  3021. connection_list[index]->RemotePort = bind_ptr->value.asnValue.number;
  3022. index++;
  3023. break;
  3024. }
  3025. }
  3026. SnmpUtilMemFreePtr(bind_list_ptr);
  3027. SnmpUtilMemFreePtr(bind_ptr);
  3028. //SnmpUtilMemFreePtr(mib_ii_name_ptr); // Don't free this - the SnmpExtensionQueryPtr call frees it apparently
  3029. WWDEBUG_SAY(("FirewallHelper - Got %d connections in list, parsing...\n", connection_list.Count()));
  3030. /*
  3031. ** Right, we got the lot. Lets see if any of them have the same address as the chat
  3032. ** server we think we are talking to.
  3033. */
  3034. found = false;
  3035. while (connection_list.Count()) {
  3036. ConnInfoStruct *connection = connection_list[0];
  3037. temp = ntohl(connection->RemoteIP);
  3038. memcpy(remote_address, (unsigned char*)&temp, 4);
  3039. /*
  3040. ** See if this connection has the same address as our server.
  3041. */
  3042. if (!found && memcmp(remote_address, server_address, 4) == 0) {
  3043. WWDEBUG_SAY(("FirewallHelper - Found connection with same remote address as server\n"));
  3044. if (server_port == 0 || server_port == (unsigned int)connection->RemotePort) {
  3045. WWDEBUG_SAY(("FirewallHelper - Connection has same port\n"));
  3046. /*
  3047. ** Make sure the connection is current.
  3048. */
  3049. if (connection->State == ESTABLISHED) {
  3050. WWDEBUG_SAY(("FirewallHelper - Connection is ESTABLISHED\n"));
  3051. my_address.Set_Address((unsigned char*)&connection->LocalIP, connection->LocalPort);
  3052. found = true;
  3053. } else {
  3054. WWDEBUG_SAY(("FirewallHelper - Connection is not ESTABLISHED - skipping\n"));
  3055. }
  3056. } else {
  3057. WWDEBUG_SAY(("FirewallHelper - Connection has different port. Port is %d, looking for %d\n", connection->RemotePort, server_port));
  3058. }
  3059. }
  3060. /*
  3061. ** Free the memory.
  3062. */
  3063. delete connection_list[0];
  3064. connection_list.Delete(0);
  3065. }
  3066. if (found) {
  3067. WWDEBUG_SAY(("FirewallHelper - Using address %s to talk to chat server\n", my_address.As_String()));
  3068. LocalChatConnectionAddress = my_address;
  3069. }
  3070. FreeLibrary(snmpapi_dll);
  3071. FreeLibrary(mib_ii_dll);
  3072. ThreadLockClass locker(this);
  3073. ThreadState = THREAD_GET_LOCAL_ADDRESS_DONE;
  3074. return(found);
  3075. }
  3076. /***********************************************************************************************
  3077. * FirewallHelperClass::Get_Local_Address -- Get local chat address ip as a long *
  3078. * *
  3079. * *
  3080. * *
  3081. * INPUT: Nothing *
  3082. * *
  3083. * OUTPUT: Local IP - 0 if unknown *
  3084. * *
  3085. * WARNINGS: None *
  3086. * *
  3087. * HISTORY: *
  3088. * 10/11/2001 4:30PM ST : Created *
  3089. *=============================================================================================*/
  3090. unsigned long FirewallHelperClass::Get_Local_Address(void)
  3091. {
  3092. unsigned long ip = 0;
  3093. if (LocalChatConnectionAddress.Is_Valid()) {
  3094. ip = LocalChatConnectionAddress.Get_Address();
  3095. ip = htonl(ip);
  3096. }
  3097. return(ip);
  3098. }
  3099. /***********************************************************************************************
  3100. * FirewallHelperClass::Get_Raw_Firewall_Behavior -- Get firewall behavior bits *
  3101. * *
  3102. * *
  3103. * *
  3104. * INPUT: Nothing *
  3105. * *
  3106. * OUTPUT: Firewall behavior *
  3107. * *
  3108. * WARNINGS: None *
  3109. * *
  3110. * HISTORY: *
  3111. * 11/3/2001 8:50PM ST : Created *
  3112. *=============================================================================================*/
  3113. unsigned short FirewallHelperClass::Get_Raw_Firewall_Behavior(void)
  3114. {
  3115. unsigned short behave = (unsigned short)Behavior;
  3116. /*
  3117. ** If we are forcing a particular port to be used then set the behavior type to be as if there was no firewall there at all.
  3118. */
  3119. if (WOLNATInterface.Get_Force_Port() != 0) {
  3120. behave = (unsigned short) FIREWALL_TYPE_SIMPLE;
  3121. }
  3122. return(behave);
  3123. }