123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501 |
- #include "StdAfx.h"
- #include "Network.h"
- #include "Client.h"
- #include "World.h"
- // Database access
- #include "Database.h"
- #include "AccountDatabase.h"
- #include "CharacterDatabase.h"
- // Network access
- #include "crc.h"
- #include "BinaryWriter.h"
- #include "BinaryReader.h"
- #include "PacketController.h"
- // NOTES:
- // 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
- CNetwork::CNetwork(SOCKET *sockets, int socketCount)
- {
- m_sockets = sockets;
- m_socketCount = socketCount;
- //
- m_wID = 0x0B; // 0x005;
- //
- m_freeslot = 1;
- m_slotrange = 0;
- //
- memset(m_clients, 0, sizeof(m_clients));
- }
- CNetwork::~CNetwork()
- {
- for (int i = 0; i < 400; i++)
- {
- SafeDelete(m_clients[i]);
- }
- }
- WORD CNetwork::GetServerID(void)
- {
- return m_wID;
- }
- void CNetwork::SendConnectlessBlob(SOCKADDR_IN *peer, BlobPacket_s *blob,
- DWORD dwFlags, DWORD dwSequence = 0, WORD wTime = 0)
- {
- BlobHeader_s *header = &blob->header;
- header->dwSequence = dwSequence;
- header->dwFlags = dwFlags;
- header->dwCRC = 0;
- header->wRecID = GetServerID();
- header->wTime = wTime;
- header->wTable = 0x01;
- GenericCRC(blob);
- SendPacket(peer, blob, BLOBLEN(blob));
- }
- void CNetwork::SendPacket(SOCKADDR_IN *peer, void *data, DWORD len)
- {
- SOCKET socket = m_sockets[0];
- if (socket == INVALID_SOCKET) return;
- #ifdef _DEBUG
- LOG(Network, Verbose, "Sent:\n");
- LOG_BYTES(Network, Verbose, data, len);
- #endif
- sendto(socket, (char *)data, len, 0, (sockaddr *)peer, sizeof(SOCKADDR_IN));
- g_pGlobals->PacketSent(len);
- }
- void CNetwork::ThinkSocket(SOCKET socket)
- {
- if (socket == INVALID_SOCKET) return;
- static BYTE buffer[0x1E4];
- static int bloblen;
- static int clientaddrlen = { sizeof(sockaddr_in) };
- static sockaddr_in clientaddr;
- while (TRUE)
- {
- // Doing it similar to AC..
- int bloblen = recvfrom(socket, (char *)buffer, 0x1E4, NULL, (sockaddr *)&clientaddr, &clientaddrlen);
- if (bloblen == SOCKET_ERROR)
- {
- DWORD dwCode = WSAGetLastError();
- if (dwCode != 10035)
- LOG(Temp, Normal, "Winsock Error %lu\n", dwCode);
- break;
- }
- else if (!bloblen)
- break;
- else if (bloblen < sizeof(BlobHeader_s))
- continue;
- g_pGlobals->PacketRecv(bloblen);
- BlobPacket_s *blob = reinterpret_cast<BlobPacket_s*>(buffer);
- bloblen -= sizeof(BlobHeader_s);
- WORD wSize = blob->header.wSize;
- WORD wRecID = blob->header.wRecID;
- if (bloblen != wSize)
- continue;
- blob->header.dwCRC -= CalcTransportCRC((DWORD *)blob);
- #ifdef _DEBUG
- SOCKADDR_IN addr;
- memset(&addr, 0, sizeof(addr));
- int namelen = sizeof(addr);
- getsockname(socket, (sockaddr *)&addr, &namelen);
- LOG(Network, Verbose, "Received on port %d:\n", ntohs(addr.sin_port));
- LOG_BYTES(Network, Verbose, &blob->header, blob->header.wSize + sizeof(blob->header));
- #endif
- if (!wRecID)
- {
- ProcessConnectionless(&clientaddr, blob);
- }
- else
- {
- CClient *client = ValidateClient(wRecID, &clientaddr);
- if (client)
- client->IncomingBlob(blob);
- }
- }
- }
- void CNetwork::Think()
- {
- for (int i = 0; i < m_socketCount; i++)
- ThinkSocket(m_sockets[i]);
- if (m_slotrange >= 400)
- m_slotrange = 399;
- for (WORD index = 1; index <= m_slotrange; index++)
- {
- CClient *client = m_clients[index];
- if (client)
- {
- client->Think();
- if (!client->IsAlive())
- KillClient(index);
- }
- }
- }
- CClient* CNetwork::GetClient(WORD index)
- {
- if (!index || index >= 400)
- return NULL;
- return m_clients[index];
- }
- void CNetwork::KickClient(CClient *pClient)
- {
- if (!pClient)
- return;
- LOG(Temp, Normal, "Client #%u (%s) is being kicked.\n", pClient->GetIndex(), pClient->GetAccount());
- BinaryWriter KC;
- KC.WriteLong(0xF7DC);
- KC.WriteLong(0);
- pClient->SendNetMessage(KC.GetData(), KC.GetSize(), PRIVATE_MSG);
- pClient->ThinkOutbound();
- pClient->Kill(NULL, NULL);
- }
- void CNetwork::KickClient(WORD index)
- {
- KickClient(GetClient(index));
- }
- CClient* CNetwork::ValidateClient(WORD index, sockaddr_in *peer)
- {
- CClient* pClient = GetClient(index);
- if (!pClient)
- return NULL;
- if (!pClient->CheckAddress(peer))
- return NULL;
- return pClient;
- }
- void CNetwork::KillClient(WORD index)
- {
- CClient *pClient = GetClient(index);
- if (!pClient)
- return;
- LOG(Temp, Normal, "Client(%s, %s) disconnected. (%s)\n", pClient->GetAccount(), inet_ntoa(pClient->GetHostAddress()->sin_addr), timestamp());
- delete pClient;
- m_clients[index] = NULL;
- if (index == m_slotrange) m_slotrange--;
- if (index < m_freeslot) m_freeslot = index;
- UpdateClientsHUD(m_clients, m_slotrange);
- }
- CClient* CNetwork::FindClientByAccount(const char* account)
- {
- for (WORD index = 1; index <= m_slotrange; index++)
- {
- CClient *client = m_clients[index];
- if (client)
- {
- if (client->CheckAccount(account))
- return client;
- }
- }
- return NULL;
- }
- void CNetwork::ConnectionRequest(sockaddr_in *addr, BlobPacket_s *p)
- {
- BinaryReader cr(p->data, p->header.wSize);
- char *szVersion = cr.ReadString(); //client version stamp
- cr.ReadDWORD(); // 0x20 ?
- enum eAuthMethod {
- ePhatAC = 1,
- eUnk = 2,
- eLiveAC = 3
- };
- DWORD dwAuthMethod = cr.ReadDWORD();
- cr.ReadDWORD(); // 0x0 ?
- DWORD dwUnixTime = cr.ReadDWORD(); //client unix timestamp
- char AC2DLove[20];
- char *szAccount;
- switch (dwAuthMethod)
- {
- case ePhatAC:
- szAccount = cr.ReadString();
- break;
- case eLiveAC:
- {
- DWORD dwTicketLength = cr.ReadDWORD();
- if (dwTicketLength >= 256)
- return;
- cr.ReadArray(dwTicketLength);
- strcpy(AC2DLove, "actwod:love");
- szAccount = AC2DLove;
- }
- break;
- default:
- return;
- }
- DWORD dwPortalStamp = cr.ReadDWORD();
- DWORD dwCellStamp = cr.ReadDWORD();
- if (cr.GetLastError()) return;
- char *szPassword = strstr(szAccount, ":");
- if (!szPassword) return;
- *(szPassword) = '\0';
- szPassword++;
- int accessLevel;
- std::string actualAccount;
- if (!g_pDB->AccountDB()->CheckAccount(szAccount, szPassword, &accessLevel, actualAccount))
- {
- szAccount = (char *)actualAccount.c_str();
- //Bad login.
- CREATEBLOB(BadLogin, sizeof(DWORD));
- *((DWORD *)BadLogin->data) = 0x00000000;
- SendConnectlessBlob(addr, BadLogin, BT_ERROR, NULL);
- DELETEBLOB(BadLogin);
- LOG(Temp, Normal, "Invalid login from %s, used %s:%s\n", inet_ntoa(addr->sin_addr), szAccount, szPassword);
- }
- else
- {
- szAccount = (char *)actualAccount.c_str();
- CClient *pExistingClient = FindClientByAccount(szAccount);
- if (pExistingClient)
- {
- if (_stricmp(pExistingClient->GetAccount(), " admin"))
- {
- KickClient(pExistingClient);
- // TODO don't allow this player to login for a few seconds while the world handles the other player
- }
- else
- {
- return;
- }
- }
- WORD index = GetClientSlot();
- if (index == NULL)
- {
- //Server unavailable.
- CREATEBLOB(ServerFull, sizeof(DWORD));
- *((DWORD *)ServerFull->data) = 0x00000005;
- SendConnectlessBlob(addr, ServerFull, BT_ERROR, NULL);
- DELETEBLOB(ServerFull);
- }
- LOG(Temp, Normal, "Client(%s, %s) connected on slot #%u (%s)\n", szAccount, inet_ntoa(addr->sin_addr), index, timestamp());
- CClient *client = m_clients[index] = new CClient(addr, index, szAccount, accessLevel);
- client->SetLoginData(dwUnixTime, dwPortalStamp, dwCellStamp);
- if (index > m_slotrange) m_slotrange = index;
- if (index == m_freeslot) m_freeslot++;
- //Add the client to the HUD
- UpdateClientsHUD(m_clients, m_slotrange);
- BinaryWriter AcceptConnect;
- //Some server variables.
- AcceptConnect.WriteDouble(g_pGlobals->Time());
- /*
- AcceptConnect.WriteDWORD( 0 );
- AcceptConnect.WriteDWORD( 0 );
- AcceptConnect.WriteWORD( index );
- //Mock the client's version.
- DWORD dwVersionLen = (DWORD)strlen( szVersion );
- AcceptConnect.WriteDWORD( dwVersionLen );
- AcceptConnect.AppendData( szVersion, dwVersionLen );
- */
- /*
- AcceptConnect.WriteDWORD(0x587335ff);
- AcceptConnect.WriteDWORD(0xbd1ab10b);
- AcceptConnect.WriteWORD(0);
- AcceptConnect.WriteWORD(0);
- */
- /*
- //Now for the CRC information
- AcceptConnect.WriteDWORD(0x20002000);
- //This CRC information could be expanded, but it would be useless to do so.
- static DWORD CRCData[] =
- {
- //The seeds will be 'AC2D' =)
- 0x33667788,
- 0x00000008,
- 0x08C563FB, 0x3180C716, 0xFEE543FF,
- 0x69E3F38A, 0x82F8CF23, 0x8059C4B9,
- 0x08B63099, 0xDD80C2E5, 0xADCDADBB,
- 0x00000003,
- //AC2D:
- 0x8E3E7E34, 0x8E3E7E34, 0x8E3E7E34
- //ACE:
- //0x74EFCAF8, 0x4BFC9E54, 0xBBDF4885
- };
- AcceptConnect.WriteDWORD( sizeof(CRCData) );
- AcceptConnect.AppendData( CRCData, sizeof(CRCData) );
- */
- /*
- AcceptConnect.WriteDWORD(0xAC2DAC2D);
- AcceptConnect.WriteDWORD(0xAC2DAC2D);
- */
- /*
- AcceptConnect.WriteDWORD(0);
- AcceptConnect.WriteDWORD(0);
- AcceptConnect.WriteDWORD(0x587335ff);
- AcceptConnect.WriteDWORD(0xbd1ab10b);
- AcceptConnect.WriteWORD(0);
- AcceptConnect.WriteWORD(0);
- AcceptConnect.WriteDWORD(0x45EBD7CD);
- AcceptConnect.WriteDWORD(0x6D54AF60);
- AcceptConnect.WriteDWORD(0);
- */
- BYTE canned[] = {
- 0xbe, 0xc8, 0x8a, 0x58, 0x0b, 0x1e, 0x99, 0x43
- };
- AcceptConnect.WriteData(canned, sizeof(canned));
- /*
- BYTE canned[] = {
- 0x13, 0x24, 0x46, 0x80, 0x96, 0x03, 0xc4, 0x41,
- 0xbe, 0xc8, 0x8a, 0x58, 0x0b, 0x1e, 0x99, 0x43,
- 0x2c, 0x00, 0x00, 0x00, 0x5e, 0x77, 0xb2, 0x33,
- 0x0c, 0x76, 0x08, 0x76, 0x02, 0x00, 0x00, 0x00
- };
- AcceptConnect.WriteData(canned, sizeof(canned));
- */
- AcceptConnect.WriteDWORD(index);
- AcceptConnect.WriteDWORD(0xAC2DAC2D);
- AcceptConnect.WriteDWORD(0xAC2DAC2D);
- AcceptConnect.WriteDWORD(2);
- DWORD dwLength = AcceptConnect.GetSize();
- if (dwLength <= 0x1D0)
- {
- CREATEBLOB(Woot, (WORD)dwLength);
- memcpy(Woot->data, AcceptConnect.GetData(), dwLength);
- SendConnectlessBlob(addr, Woot, BT_LOGINREPLY, 0x00000000);
- DELETEBLOB(Woot);
- }
- else
- {
- LOG(Temp, Normal, "AcceptConnect.GetSize() > 0x1D0");
- }
- }
- }
- WORD CNetwork::GetClientSlot()
- {
- //Find an available slot for a connecting client.
- WORD index = m_freeslot;
- while (index < 400)
- {
- if (!m_clients[index])
- return index;
- index++;
- }
- return NULL;
- }
- void CNetwork::ProcessConnectionless(sockaddr_in *peer, BlobPacket_s *blob)
- {
- DWORD dwFlags = blob->header.dwFlags;
- if (dwFlags == BT_LOGIN)
- {
- //if (blob->header.dwSequence != 1)
- // LOG(Temp, Normal, "Client connecting with bad sequence?\n");
- if (!IsBannedIP(peer->sin_addr))
- {
- ConnectionRequest(peer, blob);
- }
- return;
- }
- LOG(Network, Verbose, "Unhandled connectionless packet received: 0x%08X Look into this\n", dwFlags);
- }
- BOOL CNetwork::IsBannedIP(in_addr ip)
- {
- return FALSE;
- }
|