FirewallHelper.h 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. /***********************************************************************************************
  24. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  25. ***********************************************************************************************
  26. * *
  27. * Project Name : Command & Conquer *
  28. * *
  29. * $Archive:: /RedAlert2/NAT.CPP $*
  30. * *
  31. * $Author:: Steve_t $*
  32. * *
  33. * $Modtime:: 3/15/01 12:00PM $*
  34. * *
  35. * $Revision:: 1 $*
  36. * *
  37. * *
  38. *---------------------------------------------------------------------------------------------*
  39. * *
  40. * *
  41. *---------------------------------------------------------------------------------------------*
  42. * *
  43. * Functions: *
  44. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  45. #pragma once
  46. #ifndef __FIREWALLHELPER_H
  47. #define __FIREWALLHELPER_H
  48. class UDP;
  49. #define NUM_TEST_PORTS 4
  50. #define MAX_SPARE_SOCKETS 8
  51. /*
  52. **
  53. ** Class to help in dealing with firewalls.
  54. **
  55. **
  56. **
  57. */
  58. struct SpareSocketStruct {
  59. UDP *udp;
  60. UnsignedShort port;
  61. };
  62. enum FirewallDetectionState {
  63. DETECTIONSTATE_IDLE,
  64. DETECTIONSTATE_BEGIN,
  65. DETECTIONSTATE_TEST1,
  66. DETECTIONSTATE_TEST2,
  67. DETECTIONSTATE_TEST3,
  68. DETECTIONSTATE_TEST3_WAITFORRESPONSES,
  69. DETECTIONSTATE_TEST4_1,
  70. DETECTIONSTATE_TEST4_2,
  71. DETECTIONSTATE_TEST5,
  72. DETECTIONSTATE_DONE
  73. };
  74. #pragma pack(push, 1)
  75. // size = 16 bytes
  76. struct ManglerData {
  77. unsigned int CRC;
  78. unsigned short magic;
  79. unsigned short PacketID;
  80. unsigned short MyMangledPortNumber;
  81. unsigned short OriginalPortNumber;
  82. unsigned char MyMangledAddress[4];
  83. unsigned char NetCommandType;
  84. unsigned char BlitzMe;
  85. unsigned short Padding;
  86. };
  87. // size = TransportMessageHeader + ManglerData + 10 bytes = 26 bytes
  88. struct ManglerMessage {
  89. ManglerData data;
  90. int length;
  91. unsigned int ip;
  92. unsigned short port;
  93. };
  94. #pragma pack(pop)
  95. static const Int MAX_NUM_MANGLERS = 4;
  96. static const UnsignedShort MANGLER_PORT = 4321;
  97. class FirewallHelperClass {
  98. public:
  99. /*
  100. ** Enumeration of firewall behaviors we can detect.
  101. **
  102. ** It is assumed that all port mangling firewalls change the mangled source port in response to
  103. ** an application source port change.
  104. */
  105. typedef enum tFirewallBehaviorType {
  106. FIREWALL_MIN = 0,
  107. /*
  108. ** Just used as an initialiser.
  109. */
  110. FIREWALL_TYPE_UNKNOWN = 0,
  111. /*
  112. ** This is a simple, non-port translating firewall, or there is no firewall at all.
  113. */
  114. FIREWALL_TYPE_SIMPLE = 1,
  115. /*
  116. ** This is a firewall/NAT with port mangling but it's pretty dumb - it uses the same mangled
  117. ** source port regardless of the destination address.
  118. */
  119. FIREWALL_TYPE_DUMB_MANGLING = 2,
  120. /*
  121. ** This is a smarter firewall/NAT with port mangling that uses different mangled source ports
  122. ** for different destination IPs.
  123. */
  124. FIREWALL_TYPE_SMART_MANGLING = 4,
  125. /*
  126. ** This is a firewall that exhibits the bug as seen in the Netgear firewalls. A previously good
  127. ** source port mapping will change in response to unsolicited traffic from a known IP.
  128. */
  129. FIREWALL_TYPE_NETGEAR_BUG = 8,
  130. /*
  131. ** This firewall has a simple absolute offset port allocation scheme.
  132. */
  133. FIREWALL_TYPE_SIMPLE_PORT_ALLOCATION = 16,
  134. /*
  135. ** This firewall has a relative offset port allocation scheme. For these firewalls, we have to
  136. ** subtract the actual source port from the mangled source port to discover the allocation scheme.
  137. ** The mangled port number is based in part on the original source port number.
  138. */
  139. FIREWALL_TYPE_RELATIVE_PORT_ALLOCATION = 32,
  140. /*
  141. ** This firewall mangles source ports differently depending on the destination port.
  142. */
  143. FIREWALL_TYPE_DESTINATION_PORT_DELTA = 64,
  144. FIREWALL_MAX = 128
  145. } FirewallBehaviorType;
  146. FirewallHelperClass(void);
  147. virtual ~FirewallHelperClass(void);
  148. Bool detectFirewall(void);
  149. UnsignedShort getRawFirewallBehavior(void) {return((UnsignedShort)m_behavior);}
  150. Short getSourcePortAllocationDelta(void);
  151. Int getFirewallHardness(FirewallBehaviorType behavior);
  152. Int getFirewallRetries(FirewallBehaviorType behavior);
  153. void setSourcePortPoolStart(Int port) {m_sourcePortPool = port;};
  154. Int getSourcePortPool(void) {return(m_sourcePortPool);};
  155. void readFirewallBehavior(void);
  156. void reset(void);
  157. Bool behaviorDetectionUpdate(void);
  158. FirewallBehaviorType getFirewallBehavior(void);
  159. void writeFirewallBehavior(void);
  160. void flagNeedToRefresh(Bool flag);
  161. static void getManglerName(Int manglerIndex, Char *nameBuf);
  162. Bool sendToManglerFromPort(UnsignedInt address, UnsignedShort port, UnsignedShort packetID, Bool blitzme = FALSE);
  163. UnsignedShort getManglerResponse(UnsignedShort packetID, Int time = 0);
  164. Bool openSpareSocket(UnsignedShort port);
  165. void closeSpareSocket(UnsignedShort port);
  166. void closeAllSpareSockets();
  167. UnsignedShort getNextTemporarySourcePort(Int skip);
  168. Bool detectionBeginUpdate(void);
  169. Bool detectionTest1Update(void);
  170. Bool detectionTest2Update(void);
  171. Bool detectionTest3Update(void);
  172. Bool detectionTest3WaitForResponsesUpdate(void);
  173. Bool detectionTest4Stage1Update(void);
  174. Bool detectionTest4Stage2Update(void);
  175. Bool detectionTest5Update(void);
  176. /*
  177. ** Behavior query functions.
  178. */
  179. inline Bool isNAT(void) {
  180. if (m_behavior == FIREWALL_TYPE_UNKNOWN || (m_behavior & FIREWALL_TYPE_SIMPLE) != 0) {
  181. return(FALSE);
  182. }
  183. return(TRUE);
  184. };
  185. inline Bool isNAT(FirewallBehaviorType behavior) {
  186. if (behavior == FIREWALL_TYPE_UNKNOWN || (behavior & FIREWALL_TYPE_SIMPLE) != 0) {
  187. return(FALSE);
  188. }
  189. return(TRUE);
  190. };
  191. inline Bool isNetgear(FirewallBehaviorType behavior) {
  192. if ((behavior & FIREWALL_TYPE_NETGEAR_BUG) != 0) {
  193. return(TRUE);
  194. }
  195. return(FALSE);
  196. };
  197. inline Bool isNetgear(void) {
  198. if ((m_behavior & FIREWALL_TYPE_NETGEAR_BUG) != 0) {
  199. return(TRUE);
  200. }
  201. return(FALSE);
  202. };
  203. private:
  204. Int getNATPortAllocationScheme(Int numPorts, UnsignedShort *originalPorts, UnsignedShort *mangledPorts, Bool &relativeDelta, Bool &looksGood);
  205. void detectFirewallBehavior(/*Bool &canRecord*/);
  206. Bool getReferencePort(void);
  207. SpareSocketStruct * findSpareSocketByPort(UnsignedShort port);
  208. ManglerMessage * findEmptyMessage();
  209. void byteAdjust(ManglerData *data);
  210. /*
  211. ** How does our firewall behave?
  212. */
  213. FirewallBehaviorType m_behavior;
  214. /*
  215. ** How did the firewall behave the last time we ran the game.
  216. */
  217. FirewallBehaviorType m_lastBehavior;
  218. /*
  219. ** What is the delta in our firewalls NAT port allocation scheme.
  220. */
  221. Int m_sourcePortAllocationDelta;
  222. /*
  223. ** What was the delta the last time we ran?
  224. */
  225. Int m_lastSourcePortAllocationDelta;
  226. /*
  227. ** Source ports used only to discover port allocation patterns.
  228. ** Needs to be static so that previous communications with the manglers
  229. ** don't affect the current one.
  230. */
  231. static Int m_sourcePortPool;
  232. /*
  233. ** Spare sockets used for detecting mangling and such.
  234. */
  235. SpareSocketStruct m_spareSockets[MAX_SPARE_SOCKETS];
  236. UnsignedInt m_manglers[MAX_NUM_MANGLERS];
  237. Int m_numManglers;
  238. UnsignedShort m_sparePorts[MAX_SPARE_SOCKETS];
  239. UnsignedShort m_mangledPorts[MAX_SPARE_SOCKETS];
  240. UnsignedShort m_packetID;
  241. ManglerMessage m_messages[MAX_SPARE_SOCKETS];
  242. FirewallDetectionState m_currentState;
  243. time_t m_timeoutStart;
  244. time_t m_timeoutLength;
  245. Int m_numResponses;
  246. Int m_currentTry;
  247. };
  248. extern FirewallHelperClass *TheFirewallHelper;
  249. FirewallHelperClass * createFirewallHelper();
  250. #endif // __FIREWALLHELPER_H