nat.h 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708
  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.h $*
  25. * *
  26. * $Author:: Steve_t $*
  27. * *
  28. * $Modtime:: 3/26/02 12:16p $*
  29. * *
  30. * $Revision:: 19 $*
  31. * *
  32. * *
  33. *---------------------------------------------------------------------------------------------*
  34. * *
  35. * *
  36. *---------------------------------------------------------------------------------------------*
  37. * *
  38. * Functions: *
  39. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  40. #pragma once
  41. #ifndef NAT_H
  42. #define NAT_H
  43. #include "always.h"
  44. #include "win.h"
  45. #ifdef WWASSERT
  46. #ifndef fw_assert
  47. #define fw_assert WWASSERT
  48. #endif //fw_assert
  49. #else //WWASSERT
  50. #define fw_assert assert
  51. #endif //WWASSERT
  52. #include "nataddr.h"
  53. #include "natter.h"
  54. #include "wolapi.h"
  55. /*
  56. ** Number of ports to use when testing port mangling sequences.
  57. */
  58. #define NUM_TEST_PORTS 4
  59. #ifndef IPAddressClass
  60. class IPAddressClass;
  61. #endif //IPAddressClass
  62. #ifndef SocketHandlerClass
  63. class SocketHandlerClass;
  64. #endif //SocketHandlerClass
  65. /*
  66. **
  67. ** Class to help in dealing with firewalls.
  68. **
  69. ** Basically detects firewall type and behavior.
  70. **
  71. ** In Renegade it also does the firewall port negotiation between server and client.
  72. */
  73. class FirewallHelperClass {
  74. public:
  75. /*
  76. ** Enumeration of firewall behaviors we can detect.
  77. **
  78. ** It is assumed that all port mangling firewalls change the mangled source port in response to
  79. ** an application source port change.
  80. */
  81. typedef enum tFirewallBehaviorType {
  82. /*
  83. ** Just used as an initialiser.
  84. */
  85. FIREWALL_TYPE_UNKNOWN = 0,
  86. /*
  87. ** This is a simple, non-port translating firewall, or there is no firewall at all.
  88. */
  89. FIREWALL_TYPE_SIMPLE = 1,
  90. /*
  91. ** This is a firewall/NAT with port mangling but it's pretty dumb - it uses the same mangled
  92. ** source port regardless of the destination address.
  93. */
  94. FIREWALL_TYPE_DUMB_MANGLING = 2,
  95. /*
  96. ** This is a smarter firewall/NAT with port mangling that uses different mangled source ports
  97. ** for different destination IPs.
  98. */
  99. FIREWALL_TYPE_SMART_MANGLING = 4,
  100. /*
  101. ** This is a firewall that exhibits the bug as seen in the Netgear firewalls. A previously good
  102. ** source port mapping will change in response to unsolicited traffic from a known IP.
  103. */
  104. FIREWALL_TYPE_NETGEAR_BUG = 8,
  105. /*
  106. ** This firewall has a simple absolute offset port allocation scheme.
  107. */
  108. FIREWALL_TYPE_SIMPLE_PORT_ALLOCATION = 16,
  109. /*
  110. ** This firewall has a relative offset port allocation scheme. For these firewalls, we have to
  111. ** subtract the actual source port from the mangled source port to discover the allocation scheme.
  112. ** The mangled port number is based in part on the original source port number.
  113. */
  114. FIREWALL_TYPE_RELATIVE_PORT_ALLOCATION = 32,
  115. /*
  116. ** This firewall mangles source ports differently depending on the destination port.
  117. */
  118. FIREWALL_TYPE_DESTINATION_PORT_DELTA = 64
  119. } FirewallBehaviorType;
  120. /*
  121. ** Constructor, destructor.
  122. */
  123. FirewallHelperClass(void);
  124. ~FirewallHelperClass(void);
  125. /*
  126. ** Startup, shutdown.
  127. */
  128. void Startup(void);
  129. void Shutdown(void);
  130. /*
  131. ** Detection.
  132. */
  133. void Detect_Firewall(HANDLE event = INVALID_HANDLE_VALUE);
  134. unsigned short Get_Raw_Firewall_Behavior(void); // {return((unsigned short)Behavior);};
  135. short Get_Source_Port_Allocation_Delta(void) {return(SourcePortAllocationDelta);}
  136. /*
  137. ** Query class for behavior.
  138. */
  139. unsigned short Get_Next_Mangled_Source_Port(unsigned short source_port);
  140. int Get_Firewall_Hardness(FirewallBehaviorType behavior);
  141. int Get_Firewall_Retries(FirewallBehaviorType behavior);
  142. void Set_Source_Port_Pool_Start(int port) {SourcePortPool = port;};
  143. int Get_Source_Port_Pool(void) {return(SourcePortPool);};
  144. /*
  145. ** Talking to the manglers.
  146. */
  147. int Build_Mangler_Packet(unsigned char *buffer, unsigned short port, unsigned long packet_id = 0, bool blitzme = false);
  148. /*
  149. ** Port management.
  150. */
  151. unsigned short Get_Next_Temporary_Source_Port(int skip);
  152. bool Get_Reference_Port(void);
  153. void Reset_Server(void);
  154. unsigned short Get_Client_Bind_Port(void) {return(ClientPort);}; //PlayersFirewallAddress.Get_Port());};
  155. /*
  156. ** Firewall info import and export.
  157. */
  158. void Set_Firewall_Info(unsigned long last_behavior, int last_delta, unsigned short port_pool, bool send_delay, int confidence);
  159. void Get_Firewall_Info(unsigned long &last_behavior, int &last_delta, unsigned short &port_pool, bool &send_delay, int &confidence) const;
  160. void Set_Send_Delay(bool send_delay) {SendDelay = send_delay;};
  161. bool Get_Send_Delay(void) {return(SendDelay);};
  162. /*
  163. ** Communications functions.
  164. */
  165. bool Send_To_Mangler(IPAddressClass *address, SocketHandlerClass *socket_handler, unsigned long packet_id, bool blitzme = false);
  166. unsigned short Get_Mangler_Response(unsigned long packet_id, SocketHandlerClass *socket_handler, int time = 0, bool all_service = false);
  167. /*
  168. ** Server connection negotiation functions.
  169. */
  170. void Connected_To_WWOnline_Server(void);
  171. void Talk_To_New_Player(WOL::User *user);
  172. void Send_My_Port(unsigned short port);
  173. void Set_Client_Connect_Event(HANDLE thread_event, HANDLE cancel_event, int *flag_ptr, int *queue_ptr);
  174. bool Remove_Player_From_Negotiation_Queue(char *player_name);
  175. bool Remove_Player_From_Negotiation_Queue_If_Mutex_Available(char *player_name);
  176. void Cleanup_Client_Queue(void);
  177. /*
  178. ** Get the local chat connection address.
  179. */
  180. bool Get_Local_Chat_Connection_Address(void);
  181. unsigned long Get_Local_Address(void);
  182. IPAddressClass &Get_External_Address(void) {return(ExternalAddress);}
  183. void Set_External_Address(IPAddressClass &addr) {ExternalAddress = addr;}
  184. /*
  185. ** Reset.
  186. */
  187. void Reset(void);
  188. /*
  189. ** Query.
  190. */
  191. bool Is_Busy(void) {return((ThreadState != THREAD_IDLE) ? true : false);}
  192. /*
  193. ** Inline behavior query functions.
  194. */
  195. inline bool Is_NAT(void) {
  196. if (Behavior == FIREWALL_TYPE_UNKNOWN || (Behavior & FIREWALL_TYPE_SIMPLE) != 0) {
  197. return(false);
  198. }
  199. return(true);
  200. };
  201. inline bool Is_NAT(FirewallBehaviorType behavior) {
  202. if (behavior == FIREWALL_TYPE_UNKNOWN || (behavior & FIREWALL_TYPE_SIMPLE) != 0) {
  203. return(false);
  204. }
  205. return(true);
  206. };
  207. inline bool Is_Netgear(FirewallBehaviorType behavior) {
  208. if ((behavior & FIREWALL_TYPE_NETGEAR_BUG) != 0) {
  209. return(true);
  210. }
  211. return(false);
  212. };
  213. inline bool Is_Netgear(void) {
  214. if ((Behavior & FIREWALL_TYPE_NETGEAR_BUG) != 0) {
  215. return(true);
  216. }
  217. return(false);
  218. };
  219. /*
  220. ** Exposing the thread ID for the exception handler.
  221. */
  222. unsigned long Get_Thread_ID(void) {return(ThreadID);};
  223. /*
  224. ** Connection results reported back to the dialog wait object.
  225. */
  226. enum {
  227. FW_RESULT_UNKNOWN,
  228. FW_RESULT_FAILED,
  229. FW_RESULT_SUCCEEDED,
  230. FW_RESULT_CANCELLED
  231. };
  232. private:
  233. /************************************************************************************************************************
  234. **
  235. ** Private functions.
  236. **
  237. */
  238. /*
  239. ** Detection.
  240. */
  241. FirewallBehaviorType Detect_Firewall_Behavior(void);
  242. int Get_NAT_Port_Allocation_Scheme(int num_ports, unsigned short *original_ports, unsigned short *mangled_ports, bool &relative_delta, bool &looks_good);
  243. /*
  244. ** Server connection negotiation functions.
  245. */
  246. int Negotiate_Port(void);
  247. void Send_Connection_Result(int result, unsigned short port);
  248. void Set_Client_Success(int success);
  249. void Send_Queue_States(void);
  250. bool Client_Cancelled(void);
  251. bool Remote_Client_Cancelled(void);
  252. void Send_Cancel_Notification(void);
  253. /*
  254. ** Threading.
  255. */
  256. static unsigned int __stdcall NAT_Thread_Start(void *param);
  257. unsigned long NAT_Thread_Main_Loop(void);
  258. void Add_Thread_Action(int thread_action, HANDLE thread_event);
  259. void Set_Thread_Event(void);
  260. /*
  261. ** Game options processing.
  262. */
  263. void Process_Game_Options(void);
  264. /************************************************************************************************************************
  265. **
  266. ** Private data.
  267. **
  268. */
  269. /*
  270. ** How does our firewall behave?
  271. */
  272. FirewallBehaviorType Behavior;
  273. /*
  274. ** How did the firewall behave the last time we ran the game.
  275. */
  276. FirewallBehaviorType LastBehavior;
  277. /*
  278. ** What is the delta in our firewalls NAT port allocation scheme.
  279. */
  280. int SourcePortAllocationDelta;
  281. /*
  282. ** What was the delta the last time we ran?
  283. */
  284. int LastSourcePortAllocationDelta;
  285. /*
  286. ** Source ports used only to discover port allocation patterns.
  287. */
  288. int SourcePortPool;
  289. /*
  290. ** Should we delay before sending (for Netgear bug)?
  291. */
  292. bool SendDelay;
  293. /*
  294. ** How well do the remembered settings work.
  295. */
  296. int Confidence;
  297. /*
  298. ** Mangler server info.
  299. */
  300. int NumManglerServers;
  301. char ManglerServerAddress[64][128];
  302. int ManglerServerPort[64];
  303. int CurrentManglerServer;
  304. /*
  305. ** Local chat connection address.
  306. */
  307. IPAddressClass LocalChatConnectionAddress;
  308. /*
  309. ** Our address as far as chat knows.
  310. */
  311. IPAddressClass ExternalAddress;
  312. /************************************************************************************************************************
  313. **
  314. ** Server/Client connection related private data.
  315. **
  316. **
  317. */
  318. /*
  319. ** Who we are currently trying to talk to.
  320. */
  321. char PlayersName[64];
  322. /*
  323. ** Local address of the player we are trying to talk to.
  324. */
  325. IPAddressClass PlayersLocalAddress;
  326. /*
  327. ** External (mangler view) address of the player we are trying to talk to.
  328. */
  329. IPAddressClass PlayersExternalAddress;
  330. /*
  331. ** Type of firewall that the other player has.
  332. */
  333. FirewallBehaviorType PlayersFirewallType;
  334. /*
  335. ** Teacks what we expect the other player to have his port number mangled to.
  336. */
  337. unsigned short PlayersMangledPort;
  338. /*
  339. ** Other players in WOL::User struct form.
  340. */
  341. WOL::User PlayerAsUser;
  342. /*
  343. ** Our current best guess at the combined mangled port/ip of the other player.
  344. */
  345. IPAddressClass PlayersFirewallAddress;
  346. /*
  347. ** Connection result reported by other player. Used to find out if our packet got through. See enum below.
  348. */
  349. int PlayersConnectionResult;
  350. /*
  351. ** Port that the other player saw our packet actually come from.
  352. */
  353. unsigned short PlayersConnectionResultPort;
  354. /*
  355. ** Enum for connection results.
  356. */
  357. enum {
  358. CONNRESULT_UNTRIED = -1,
  359. CONNRESULT_FAILED = 0,
  360. CONNRESULT_TRY1,
  361. CONNRESULT_TRY2,
  362. CONNRESULT_TRY3,
  363. CONNRESULT_TRY4,
  364. CONNRESULT_TRY5,
  365. CONNRESULT_TRY6,
  366. CONNRESULT_TRY7,
  367. CONNRESULT_TRY8,
  368. CONNRESULT_TRY9,
  369. CONNRESULT_TRY10,
  370. CONNRESULT_CONNECTED
  371. };
  372. /************************************************************************************************************************
  373. **
  374. ** Server side only data.
  375. **
  376. */
  377. /*
  378. ** Client queue (for server only). This is a list of clients waiting to negotiate a port.
  379. */
  380. typedef struct tClientStruct {
  381. char Name[64];
  382. IPAddressClass LocalAddress;
  383. IPAddressClass ExternalAddress;
  384. FirewallBehaviorType FirewallType;
  385. WOL::User User;
  386. } ClientStruct;
  387. DynamicVectorClass<ClientStruct*> ClientQueue;
  388. /*
  389. ** List if names waiting to be removed from the client queue.
  390. */
  391. DynamicVectorClass<ClientStruct*> ClientQueueRemoveList;
  392. /*
  393. ** Connections we have made so far in this game. This includes people who were in the game and left.
  394. */
  395. DynamicVectorClass<IPAddressClass> ConnectionHistory;
  396. DynamicVectorClass<unsigned short> MangledPortHistory;
  397. /*
  398. ** When we last heard from the client.
  399. */
  400. unsigned long LastOptionsFromClient;
  401. /*
  402. ** Name of player who has cancelled out of our game channel before connecting.
  403. */
  404. char CancelPlayer[64];
  405. /************************************************************************************************************************
  406. **
  407. ** Client side only data.
  408. **
  409. */
  410. /*
  411. ** Number of players in the servers queue ahead of us.
  412. */
  413. int QueuedPlayers;
  414. /*
  415. ** Port that the client will use as a basis for negotiation.
  416. */
  417. unsigned short ClientPort;
  418. /*
  419. ** Client connect event notification.
  420. */
  421. int *SuccessFlagPtr;
  422. HANDLE ClientConnectEvent;
  423. HANDLE ClientCancelEvent;
  424. int *QueueNotifyPtr;
  425. /************************************************************************************************************************
  426. **
  427. ** Threading.
  428. **
  429. ** This class runs in it's own thread so that firewall negotiation doesn't stall the server when a new client joins.
  430. ** It also means that the clients join dialog is serviced while connecting, allowing him to cancel at any time.
  431. **
  432. */
  433. HANDLE ThreadHandle;
  434. unsigned long ThreadID;
  435. HANDLE NATThreadMutex;
  436. HANDLE NATDataMutex;
  437. bool ThreadActive;
  438. /*
  439. ** Thread actions.
  440. */
  441. enum {
  442. THREAD_IDLE,
  443. THREAD_DETECT_FIREWALL,
  444. THREAD_DETECT_FIREWALL_DONE,
  445. THREAD_CONNECT_FIREWALL,
  446. THREAD_CONNECT_FIREWALL_DONE,
  447. THREAD_GET_LOCAL_ADDRESS,
  448. THREAD_GET_LOCAL_ADDRESS_DONE
  449. };
  450. /*
  451. ** Thread state i.e. what it's doing.
  452. */
  453. int ThreadState;
  454. /*
  455. ** Event to be signalled when the current thread action completes.
  456. */
  457. HANDLE ThreadEvent;
  458. /*
  459. ** Thread action FIFO
  460. */
  461. class ThreadActionClass {
  462. public:
  463. inline bool operator == (ThreadActionClass const &data) {
  464. return(memcmp((void*)this, &data, sizeof(*this)) == 0);
  465. };
  466. inline bool operator != (ThreadActionClass const &data) {
  467. return(memcmp((void*)this, &data, sizeof(*this)) != 0);
  468. };
  469. int ThreadAction;
  470. HANDLE ThreadEvent;
  471. };
  472. DynamicVectorClass<ThreadActionClass> ThreadQueue;
  473. /*
  474. ** Thread safety.
  475. */
  476. class ThreadLockClass
  477. {
  478. public:
  479. /*
  480. ** Constructor. Grabs the mutex.
  481. */
  482. inline ThreadLockClass(FirewallHelperClass *fwptr, unsigned long timeout = 10 * 1000) {
  483. FWPtr = fwptr;
  484. /*
  485. ** Just test the mutex if timeout is 0.
  486. */
  487. WaitResult = WaitForSingleObject(fwptr->NATDataMutex, timeout);
  488. if (timeout != 0 && WaitResult == WAIT_TIMEOUT) {
  489. WWDEBUG_SAY(("FirewallHelper - Timeout waiting for firewall helper data mutex\n"));
  490. fw_assert(WaitResult != WAIT_TIMEOUT);
  491. }
  492. };
  493. FirewallHelperClass *FWPtr;
  494. int WaitResult;
  495. /*
  496. ** Destructor, releases the mutex.
  497. */
  498. inline ~ThreadLockClass(void) {
  499. ReleaseMutex(FWPtr->NATDataMutex);
  500. };
  501. };
  502. friend ThreadLockClass;
  503. /*****************************************************************************************************************
  504. **
  505. **
  506. ** C&C Packet format as expected by the mangler. Copied from various places in the RA2 code.
  507. **
  508. */
  509. public:
  510. /*
  511. ** One byte alignment.
  512. */
  513. #pragma pack(push, 1)
  514. /*
  515. ** Misc C&C packet defines.
  516. */
  517. #define GLOBAL_MAGICNUM 0x1236
  518. #define PACKET_DATA_NOACK 1
  519. #define COMMAND_AND_CONQUER_RA2 0xaa03
  520. #define NET_MANGLER_REQUEST 43
  521. #define NET_MANGLER_RESPONSE 44
  522. #define MPLAYER_NAME_MAX 20
  523. #define SERIAL_MAX 23
  524. /*
  525. ** CommHeaderType - Low level packet wrapper.
  526. */
  527. struct CommHeaderType {
  528. unsigned short MagicNumber; // in, out = GLOBAL_MAGICNUM = 0x1236. Just preserve the incoming value.
  529. char Code; // in, out = PACKET_DATA_NOACK = 1
  530. union {
  531. unsigned char ForwardTo; // = 0
  532. unsigned char ForwardFrom;
  533. };
  534. unsigned long PacketID; // Dont care.
  535. unsigned char ForwardAddress[4];
  536. unsigned short ForwardPort;
  537. };
  538. /*
  539. ** GlobalHeaderType - Low level packet wrapper for global channel packets.
  540. */
  541. struct GlobalHeaderType {
  542. CommHeaderType Header; // See above
  543. unsigned short ProductID; // in, out = COMMAND_AND_CONQUER_RA2 = 0xaa03. Just return the value from the received packet
  544. };
  545. /*
  546. ** GlobalPacketType - Payload of global channel packet.
  547. */
  548. struct GlobalPacketType {
  549. int Command; // in = NET_MANGLER_REQUEST = 43 , out = NET_MANGLER_RESPONSE = 44
  550. char Name[MPLAYER_NAME_MAX]; // in, out = Player name (8 bit) - return same name
  551. char Serial[SERIAL_MAX]; // Not used.
  552. union
  553. {
  554. struct {
  555. unsigned short MangledPortNumber;
  556. unsigned char MangledAddress[4];
  557. unsigned short OriginalPortNumber;
  558. unsigned char BlitzMe;
  559. } ManglerData;
  560. };
  561. };
  562. /*
  563. ** CnCPacketType - Header and payload in one structure.
  564. */
  565. typedef struct tCnCPacketType {
  566. GlobalHeaderType GHeader;
  567. GlobalPacketType Packet;
  568. } CnCPacketType;
  569. #pragma pack(pop)
  570. /*
  571. ** End C&C packet format.
  572. ****************************************************************************************************************
  573. */
  574. };
  575. /*
  576. ** Single instance of FirewallHelperClass
  577. */
  578. extern FirewallHelperClass FirewallHelper;
  579. #endif //NAT_H