Clone of PhatAC @ https://github.com/floaterxk/PhatAC

Network.cpp 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  1. #include "StdAfx.h"
  2. #include "Network.h"
  3. #include "Client.h"
  4. #include "World.h"
  5. // Database access
  6. #include "Database.h"
  7. #include "AccountDatabase.h"
  8. #include "CharacterDatabase.h"
  9. // Network access
  10. #include "crc.h"
  11. #include "BinaryWriter.h"
  12. #include "BinaryReader.h"
  13. #include "PacketController.h"
  14. // NOTES:
  15. // A client can easily perform denial of service attacks by issuing a large number of connection requests if there ever comes a time this matters to fix
  16. CNetwork::CNetwork(SOCKET *sockets, int socketCount)
  17. {
  18. m_sockets = sockets;
  19. m_socketCount = socketCount;
  20. //
  21. m_wID = 0x0B; // 0x005;
  22. //
  23. m_freeslot = 1;
  24. m_slotrange = 0;
  25. //
  26. memset(m_clients, 0, sizeof(m_clients));
  27. }
  28. CNetwork::~CNetwork()
  29. {
  30. for (int i = 0; i < 400; i++)
  31. {
  32. SafeDelete(m_clients[i]);
  33. }
  34. }
  35. WORD CNetwork::GetServerID(void)
  36. {
  37. return m_wID;
  38. }
  39. void CNetwork::SendConnectlessBlob(SOCKADDR_IN *peer, BlobPacket_s *blob,
  40. DWORD dwFlags, DWORD dwSequence = 0, WORD wTime = 0)
  41. {
  42. BlobHeader_s *header = &blob->header;
  43. header->dwSequence = dwSequence;
  44. header->dwFlags = dwFlags;
  45. header->dwCRC = 0;
  46. header->wRecID = GetServerID();
  47. header->wTime = wTime;
  48. header->wTable = 0x01;
  49. GenericCRC(blob);
  50. SendPacket(peer, blob, BLOBLEN(blob));
  51. }
  52. void CNetwork::SendPacket(SOCKADDR_IN *peer, void *data, DWORD len)
  53. {
  54. SOCKET socket = m_sockets[0];
  55. if (socket == INVALID_SOCKET) return;
  56. #ifdef _DEBUG
  57. LOG(Network, Verbose, "Sent:\n");
  58. LOG_BYTES(Network, Verbose, data, len);
  59. #endif
  60. sendto(socket, (char *)data, len, 0, (sockaddr *)peer, sizeof(SOCKADDR_IN));
  61. g_pGlobals->PacketSent(len);
  62. }
  63. void CNetwork::ThinkSocket(SOCKET socket)
  64. {
  65. if (socket == INVALID_SOCKET) return;
  66. static BYTE buffer[0x1E4];
  67. static int bloblen;
  68. static int clientaddrlen = { sizeof(sockaddr_in) };
  69. static sockaddr_in clientaddr;
  70. while (TRUE)
  71. {
  72. // Doing it similar to AC..
  73. int bloblen = recvfrom(socket, (char *)buffer, 0x1E4, NULL, (sockaddr *)&clientaddr, &clientaddrlen);
  74. if (bloblen == SOCKET_ERROR)
  75. {
  76. DWORD dwCode = WSAGetLastError();
  77. if (dwCode != 10035)
  78. LOG(Temp, Normal, "Winsock Error %lu\n", dwCode);
  79. break;
  80. }
  81. else if (!bloblen)
  82. break;
  83. else if (bloblen < sizeof(BlobHeader_s))
  84. continue;
  85. g_pGlobals->PacketRecv(bloblen);
  86. BlobPacket_s *blob = reinterpret_cast<BlobPacket_s*>(buffer);
  87. bloblen -= sizeof(BlobHeader_s);
  88. WORD wSize = blob->header.wSize;
  89. WORD wRecID = blob->header.wRecID;
  90. if (bloblen != wSize)
  91. continue;
  92. blob->header.dwCRC -= CalcTransportCRC((DWORD *)blob);
  93. #ifdef _DEBUG
  94. SOCKADDR_IN addr;
  95. memset(&addr, 0, sizeof(addr));
  96. int namelen = sizeof(addr);
  97. getsockname(socket, (sockaddr *)&addr, &namelen);
  98. LOG(Network, Verbose, "Received on port %d:\n", ntohs(addr.sin_port));
  99. LOG_BYTES(Network, Verbose, &blob->header, blob->header.wSize + sizeof(blob->header));
  100. #endif
  101. if (!wRecID)
  102. {
  103. ProcessConnectionless(&clientaddr, blob);
  104. }
  105. else
  106. {
  107. CClient *client = ValidateClient(wRecID, &clientaddr);
  108. if (client)
  109. client->IncomingBlob(blob);
  110. }
  111. }
  112. }
  113. void CNetwork::Think()
  114. {
  115. for (int i = 0; i < m_socketCount; i++)
  116. ThinkSocket(m_sockets[i]);
  117. if (m_slotrange >= 400)
  118. m_slotrange = 399;
  119. for (WORD index = 1; index <= m_slotrange; index++)
  120. {
  121. CClient *client = m_clients[index];
  122. if (client)
  123. {
  124. client->Think();
  125. if (!client->IsAlive())
  126. KillClient(index);
  127. }
  128. }
  129. }
  130. CClient* CNetwork::GetClient(WORD index)
  131. {
  132. if (!index || index >= 400)
  133. return NULL;
  134. return m_clients[index];
  135. }
  136. void CNetwork::KickClient(CClient *pClient)
  137. {
  138. if (!pClient)
  139. return;
  140. LOG(Temp, Normal, "Client #%u (%s) is being kicked.\n", pClient->GetIndex(), pClient->GetAccount());
  141. BinaryWriter KC;
  142. KC.WriteLong(0xF7DC);
  143. KC.WriteLong(0);
  144. pClient->SendNetMessage(KC.GetData(), KC.GetSize(), PRIVATE_MSG);
  145. pClient->ThinkOutbound();
  146. pClient->Kill(NULL, NULL);
  147. }
  148. void CNetwork::KickClient(WORD index)
  149. {
  150. KickClient(GetClient(index));
  151. }
  152. CClient* CNetwork::ValidateClient(WORD index, sockaddr_in *peer)
  153. {
  154. CClient* pClient = GetClient(index);
  155. if (!pClient)
  156. return NULL;
  157. if (!pClient->CheckAddress(peer))
  158. return NULL;
  159. return pClient;
  160. }
  161. void CNetwork::KillClient(WORD index)
  162. {
  163. CClient *pClient = GetClient(index);
  164. if (!pClient)
  165. return;
  166. LOG(Temp, Normal, "Client(%s, %s) disconnected. (%s)\n", pClient->GetAccount(), inet_ntoa(pClient->GetHostAddress()->sin_addr), timestamp());
  167. delete pClient;
  168. m_clients[index] = NULL;
  169. if (index == m_slotrange) m_slotrange--;
  170. if (index < m_freeslot) m_freeslot = index;
  171. UpdateClientsHUD(m_clients, m_slotrange);
  172. }
  173. CClient* CNetwork::FindClientByAccount(const char* account)
  174. {
  175. for (WORD index = 1; index <= m_slotrange; index++)
  176. {
  177. CClient *client = m_clients[index];
  178. if (client)
  179. {
  180. if (client->CheckAccount(account))
  181. return client;
  182. }
  183. }
  184. return NULL;
  185. }
  186. void CNetwork::ConnectionRequest(sockaddr_in *addr, BlobPacket_s *p)
  187. {
  188. BinaryReader cr(p->data, p->header.wSize);
  189. char *szVersion = cr.ReadString(); //client version stamp
  190. cr.ReadDWORD(); // 0x20 ?
  191. enum eAuthMethod {
  192. ePhatAC = 1,
  193. eUnk = 2,
  194. eLiveAC = 3
  195. };
  196. DWORD dwAuthMethod = cr.ReadDWORD();
  197. cr.ReadDWORD(); // 0x0 ?
  198. DWORD dwUnixTime = cr.ReadDWORD(); //client unix timestamp
  199. char AC2DLove[20];
  200. char *szAccount;
  201. switch (dwAuthMethod)
  202. {
  203. case ePhatAC:
  204. szAccount = cr.ReadString();
  205. break;
  206. case eLiveAC:
  207. {
  208. DWORD dwTicketLength = cr.ReadDWORD();
  209. if (dwTicketLength >= 256)
  210. return;
  211. cr.ReadArray(dwTicketLength);
  212. strcpy(AC2DLove, "actwod:love");
  213. szAccount = AC2DLove;
  214. }
  215. break;
  216. default:
  217. return;
  218. }
  219. DWORD dwPortalStamp = cr.ReadDWORD();
  220. DWORD dwCellStamp = cr.ReadDWORD();
  221. if (cr.GetLastError()) return;
  222. char *szPassword = strstr(szAccount, ":");
  223. if (!szPassword) return;
  224. *(szPassword) = '\0';
  225. szPassword++;
  226. int accessLevel;
  227. std::string actualAccount;
  228. if (!g_pDB->AccountDB()->CheckAccount(szAccount, szPassword, &accessLevel, actualAccount))
  229. {
  230. szAccount = (char *)actualAccount.c_str();
  231. //Bad login.
  232. CREATEBLOB(BadLogin, sizeof(DWORD));
  233. *((DWORD *)BadLogin->data) = 0x00000000;
  234. SendConnectlessBlob(addr, BadLogin, BT_ERROR, NULL);
  235. DELETEBLOB(BadLogin);
  236. LOG(Temp, Normal, "Invalid login from %s, used %s:%s\n", inet_ntoa(addr->sin_addr), szAccount, szPassword);
  237. }
  238. else
  239. {
  240. szAccount = (char *)actualAccount.c_str();
  241. CClient *pExistingClient = FindClientByAccount(szAccount);
  242. if (pExistingClient)
  243. {
  244. if (_stricmp(pExistingClient->GetAccount(), " admin"))
  245. {
  246. KickClient(pExistingClient);
  247. // TODO don't allow this player to login for a few seconds while the world handles the other player
  248. }
  249. else
  250. {
  251. return;
  252. }
  253. }
  254. WORD index = GetClientSlot();
  255. if (index == NULL)
  256. {
  257. //Server unavailable.
  258. CREATEBLOB(ServerFull, sizeof(DWORD));
  259. *((DWORD *)ServerFull->data) = 0x00000005;
  260. SendConnectlessBlob(addr, ServerFull, BT_ERROR, NULL);
  261. DELETEBLOB(ServerFull);
  262. }
  263. LOG(Temp, Normal, "Client(%s, %s) connected on slot #%u (%s)\n", szAccount, inet_ntoa(addr->sin_addr), index, timestamp());
  264. CClient *client = m_clients[index] = new CClient(addr, index, szAccount, accessLevel);
  265. client->SetLoginData(dwUnixTime, dwPortalStamp, dwCellStamp);
  266. if (index > m_slotrange) m_slotrange = index;
  267. if (index == m_freeslot) m_freeslot++;
  268. //Add the client to the HUD
  269. UpdateClientsHUD(m_clients, m_slotrange);
  270. BinaryWriter AcceptConnect;
  271. //Some server variables.
  272. AcceptConnect.WriteDouble(g_pGlobals->Time());
  273. /*
  274. AcceptConnect.WriteDWORD( 0 );
  275. AcceptConnect.WriteDWORD( 0 );
  276. AcceptConnect.WriteWORD( index );
  277. //Mock the client's version.
  278. DWORD dwVersionLen = (DWORD)strlen( szVersion );
  279. AcceptConnect.WriteDWORD( dwVersionLen );
  280. AcceptConnect.AppendData( szVersion, dwVersionLen );
  281. */
  282. /*
  283. AcceptConnect.WriteDWORD(0x587335ff);
  284. AcceptConnect.WriteDWORD(0xbd1ab10b);
  285. AcceptConnect.WriteWORD(0);
  286. AcceptConnect.WriteWORD(0);
  287. */
  288. /*
  289. //Now for the CRC information
  290. AcceptConnect.WriteDWORD(0x20002000);
  291. //This CRC information could be expanded, but it would be useless to do so.
  292. static DWORD CRCData[] =
  293. {
  294. //The seeds will be 'AC2D' =)
  295. 0x33667788,
  296. 0x00000008,
  297. 0x08C563FB, 0x3180C716, 0xFEE543FF,
  298. 0x69E3F38A, 0x82F8CF23, 0x8059C4B9,
  299. 0x08B63099, 0xDD80C2E5, 0xADCDADBB,
  300. 0x00000003,
  301. //AC2D:
  302. 0x8E3E7E34, 0x8E3E7E34, 0x8E3E7E34
  303. //ACE:
  304. //0x74EFCAF8, 0x4BFC9E54, 0xBBDF4885
  305. };
  306. AcceptConnect.WriteDWORD( sizeof(CRCData) );
  307. AcceptConnect.AppendData( CRCData, sizeof(CRCData) );
  308. */
  309. /*
  310. AcceptConnect.WriteDWORD(0xAC2DAC2D);
  311. AcceptConnect.WriteDWORD(0xAC2DAC2D);
  312. */
  313. /*
  314. AcceptConnect.WriteDWORD(0);
  315. AcceptConnect.WriteDWORD(0);
  316. AcceptConnect.WriteDWORD(0x587335ff);
  317. AcceptConnect.WriteDWORD(0xbd1ab10b);
  318. AcceptConnect.WriteWORD(0);
  319. AcceptConnect.WriteWORD(0);
  320. AcceptConnect.WriteDWORD(0x45EBD7CD);
  321. AcceptConnect.WriteDWORD(0x6D54AF60);
  322. AcceptConnect.WriteDWORD(0);
  323. */
  324. BYTE canned[] = {
  325. 0xbe, 0xc8, 0x8a, 0x58, 0x0b, 0x1e, 0x99, 0x43
  326. };
  327. AcceptConnect.WriteData(canned, sizeof(canned));
  328. /*
  329. BYTE canned[] = {
  330. 0x13, 0x24, 0x46, 0x80, 0x96, 0x03, 0xc4, 0x41,
  331. 0xbe, 0xc8, 0x8a, 0x58, 0x0b, 0x1e, 0x99, 0x43,
  332. 0x2c, 0x00, 0x00, 0x00, 0x5e, 0x77, 0xb2, 0x33,
  333. 0x0c, 0x76, 0x08, 0x76, 0x02, 0x00, 0x00, 0x00
  334. };
  335. AcceptConnect.WriteData(canned, sizeof(canned));
  336. */
  337. AcceptConnect.WriteDWORD(index);
  338. AcceptConnect.WriteDWORD(0xAC2DAC2D);
  339. AcceptConnect.WriteDWORD(0xAC2DAC2D);
  340. AcceptConnect.WriteDWORD(2);
  341. DWORD dwLength = AcceptConnect.GetSize();
  342. if (dwLength <= 0x1D0)
  343. {
  344. CREATEBLOB(Woot, (WORD)dwLength);
  345. memcpy(Woot->data, AcceptConnect.GetData(), dwLength);
  346. SendConnectlessBlob(addr, Woot, BT_LOGINREPLY, 0x00000000);
  347. DELETEBLOB(Woot);
  348. }
  349. else
  350. {
  351. LOG(Temp, Normal, "AcceptConnect.GetSize() > 0x1D0");
  352. }
  353. }
  354. }
  355. WORD CNetwork::GetClientSlot()
  356. {
  357. //Find an available slot for a connecting client.
  358. WORD index = m_freeslot;
  359. while (index < 400)
  360. {
  361. if (!m_clients[index])
  362. return index;
  363. index++;
  364. }
  365. return NULL;
  366. }
  367. void CNetwork::ProcessConnectionless(sockaddr_in *peer, BlobPacket_s *blob)
  368. {
  369. DWORD dwFlags = blob->header.dwFlags;
  370. if (dwFlags == BT_LOGIN)
  371. {
  372. //if (blob->header.dwSequence != 1)
  373. // LOG(Temp, Normal, "Client connecting with bad sequence?\n");
  374. if (!IsBannedIP(peer->sin_addr))
  375. {
  376. ConnectionRequest(peer, blob);
  377. }
  378. return;
  379. }
  380. LOG(Network, Verbose, "Unhandled connectionless packet received: 0x%08X Look into this\n", dwFlags);
  381. }
  382. BOOL CNetwork::IsBannedIP(in_addr ip)
  383. {
  384. return FALSE;
  385. }