/* Receive a vector of pending packets from the UDP socket. The returned packets contain the source address and the channel they arrived on. If they did not arrive on a bound channel, the the channel will be set to -1. This function returns the number of packets read from the network, or -1 on error. This function does not block, so can return 0 packets pending. */ extern int SDLNet_UDP_RecvV(UDPsocket sock, UDPpacket **packets) { int numrecv, i, j; struct UDP_channel *binding; socklen_t sock_len; struct sockaddr_in sock_addr; if ( sock == NULL ) { return(0); } numrecv = 0; while ( packets[numrecv] && SocketReady(sock->channel) ) { UDPpacket *packet; packet = packets[numrecv]; sock_len = sizeof(sock_addr); packet->status = recvfrom(sock->channel, packet->data, packet->maxlen, 0, (struct sockaddr *)&sock_addr, &sock_len); if ( packet->status >= 0 ) { packet->len = packet->status; packet->address.host = sock_addr.sin_addr.s_addr; packet->address.port = sock_addr.sin_port; packet->channel = -1; for (i=(SDLNET_MAX_UDPCHANNELS-1); i>=0; --i ) { binding = &sock->binding[i]; for ( j=binding->numbound-1; j>=0; --j ) { if ( (packet->address.host == binding->address[j].host) && (packet->address.port == binding->address[j].port) ) { packet->channel = i; goto foundit; /* break twice */ } } } foundit: ++numrecv; } else { packet->len = 0; } } sock->ready = 0; return(numrecv); }
bool Connection::DoClientKeyExchange() { // Generate RC4 key unsigned int i = 0; unsigned char rc4key[RC4_KEY_SIZE]; unsigned char buffer[128]; memset(rc4key, 0, sizeof(rc4key)); SetRC4Key(rc4key); // Receive the pubic key packet Sleep(20); memset(buffer, 0, sizeof(buffer)); if ( !SocketReady() || (recv(m_Socket, (char *) buffer, 74, 0) != 74) ) { LogMessage("[%d] ERROR: DoClientKeyExchange recv\n", m_RecvThreadHandle); return false; } // Clear the buffer memset(buffer, 0, WWRSA_BLOCK_SIZE - RC4_KEY_SIZE + sizeof(long)); // Put the length in front of the buffer unsigned char *key = buffer + sizeof(long); *((unsigned long *) buffer) = ntohl(WWRSA_BLOCK_SIZE); // Copy the RC4 key to the bottom of the buffer unsigned char *dest = &key[WWRSA_BLOCK_SIZE - 1]; unsigned char *src = rc4key; for (i = 0; i < RC4_KEY_SIZE; i++) *dest-- = *src++; // Encrypt the RC4 key m_WestwoodRSA.Encrypt(key, WWRSA_BLOCK_SIZE, key); // Send the encrypted RC4 key to the server int length = WWRSA_BLOCK_SIZE + sizeof(long); // Returns true if not socket error or timeout and buffer was completely sent return bool( SocketReady() && (send(m_Socket, (char *) buffer, length, 0) == length) ); }
/* Receive a vector of pending packets from the UDP socket. The returned packets contain the source address and the channel they arrived on. If they did not arrive on a bound channel, the the channel will be set to -1. This function returns the number of packets read from the network, or -1 on error. This function does not block, so can return 0 packets pending. */ extern int SDLNet_UDP_RecvV(UDPsocket sock, UDPpacket **packets) { int numrecv, i, j; struct UDP_channel *binding; #ifdef MACOS_OPENTRANSPORT TUnitData OTpacket; OTFlags flags; InetAddress address; #else int sock_len; struct sockaddr_in sock_addr; #endif numrecv = 0; while ( packets[numrecv] && SocketReady(sock->channel) ) { UDPpacket *packet; packet = packets[numrecv]; #ifdef MACOS_OPENTRANSPORT memset(&OTpacket, 0, sizeof(OTpacket)); OTpacket.addr.buf = (Uint8 *)&address; OTpacket.addr.maxlen = (sizeof address); OTpacket.udata.buf = packet->data; OTpacket.udata.maxlen = packet->maxlen; packet->status = OTRcvUData(sock->channel, &OTpacket, &flags); #ifdef DEBUG_NET printf("Packet status: %d\n", packet->status); #endif AsyncUDPPopEvent(sock); if (packet->status == noErr) { packet->len = OTpacket.udata.len; packet->address.host = address.fHost; packet->address.port = address.fPort; #ifdef DEBUG_NET printf("Packet address: 0x%8.8x:%d, length = %d\n", packet->address.host, packet->address.port, packet->len); #endif } #else sock_len = sizeof(sock_addr); packet->status = recvfrom(sock->channel, packet->data, packet->maxlen, 0, (struct sockaddr *)&sock_addr, #ifdef USE_GUSI_SOCKETS (unsigned int *)&sock_len); #else &sock_len); #endif if ( packet->status >= 0 ) { packet->len = packet->status; packet->address.host = sock_addr.sin_addr.s_addr; packet->address.port = sock_addr.sin_port; } #endif if (packet->status >= 0) { packet->channel = -1; for (i=(SDLNET_MAX_UDPCHANNELS-1); i>=0; --i ) { binding = &sock->binding[i]; for ( j=binding->numbound-1; j>=0; --j ) { if ( (packet->address.host == binding->address[j].host) && (packet->address.port == binding->address[j].port) ) { packet->channel = i; goto foundit; /* break twice */ } } } foundit: ++numrecv; } else { packet->len = 0; } } sock->ready = 0; return(numrecv); }
void Connection::RunRecvThread() { bool isSocketReady = false; // Used for checking Socket state int numretries = 0; int received; unsigned short bytes; short opcode; EnbTcpHeader header; char *ptr_hdr = (char*)&header; memset(&header, 0, sizeof(header)); while (!g_ServerShutdown && !m_TcpThreadTerminated) { while (m_TcpThreadRunning) { // Do the key exchange if it hasn't been done yet if (!m_KeysExchanged) { if (!RunKeyExchange()) { // Key Exchange failed. KillConnection(); break; } else { m_KeysExchanged = true; } } // Main Loop isSocketReady = SocketReady(1); // One Second Timeout if ( isSocketReady && (recv(m_Socket, ptr_hdr, 4, 0) == 4) ) { m_InactivityTimer = 0; if (m_PacketLoggingEnabled) { LogMessage("[%d] Received 4 byte header (encrypted):\n", m_RecvThreadHandle); DumpBuffer((unsigned char *) &header, 4); } if (m_ServerType != CONNECTION_TYPE_SECTOR_SERVER_TO_PROXY && m_ServerType != CONNECTION_TYPE_GLOBAL_PROXY_TO_SERVER) { m_CryptIn.RC4((unsigned char *) &header, 4); } if (m_PacketLoggingEnabled) { LogMessage("[%d] Received 4 byte header (decrypted):\n", m_RecvThreadHandle); DumpBuffer((unsigned char *) &header, 4); } bytes = header.size - sizeof(EnbTcpHeader); // Bytes to fetch opcode = header.opcode; // Opcode for this packet // This buffer check MUST be in place if ( (bytes > MAX_BUFFER) ) { LogMessage("[%d] Received packet with incorrect payload length: opcode = 0x%02x, length = %d. Aborting.\n", m_RecvThreadHandle, opcode, bytes); KillConnection(); // We're not permitting a 2nd chance. break; } //LogMessage("Received packet: opcode = 0x%02x, length = %d\n", opcode, bytes); received = recv(m_Socket, (char *) m_RecvBuffer, bytes, 0); numretries = 0; while ( received != bytes && // Did we fetch everything? SocketReady() && // Can we still get more? numretries < MAX_RETRIES && // Can we still retry to get more? m_TcpThreadRunning ) // And we haven't been told to stop? { int rcv = recv(m_Socket, (char *) (m_RecvBuffer + received), bytes - received, 0); if (rcv > 0) { received += rcv; } else break; numretries++; // Prevent an infinite loop } if ( received == bytes && m_TcpThreadRunning ) // We got the whole package and we haven't been told top stop { if (m_ServerType != CONNECTION_TYPE_SECTOR_SERVER_TO_PROXY && m_ServerType != CONNECTION_TYPE_GLOBAL_PROXY_TO_SERVER) { m_CryptIn.RC4(m_RecvBuffer, bytes); } if (m_PacketLoggingEnabled) { LogMessage("[%d] Received %d byte packet\n", m_RecvThreadHandle, received); DumpBuffer(m_RecvBuffer,bytes); } switch (m_ServerType) { case CONNECTION_TYPE_CLIENT_TO_GLOBAL_SERVER : ProcessGlobalServerOpcode(opcode, bytes); break; case CONNECTION_TYPE_CLIENT_TO_MASTER_SERVER : ProcessMasterServerOpcode(opcode, bytes); break; case CONNECTION_TYPE_CLIENT_TO_SECTOR_SERVER : //ProcessSectorServerOpcode(opcode, bytes); LogMessage("[%d] ERROR!!: Sector Server opcode received!\n", m_RecvThreadHandle); break; case CONNECTION_TYPE_MASTER_SERVER_TO_SECTOR_SERVER : ProcessMasterServerToSectorServerOpcode(opcode, bytes); break; case CONNECTION_TYPE_SECTOR_SERVER_TO_SECTOR_SERVER : ProcessSectorServerToSectorServerOpcode(opcode, bytes); break; case CONNECTION_TYPE_SECTOR_SERVER_TO_PROXY: ProcessProxyClientOpcode(opcode, bytes); break; case CONNECTION_TYPE_GLOBAL_PROXY_TO_SERVER: ProcessProxyGlobalOpcode(opcode, bytes); break; default: LogMessage("[%d] ERROR: Unknown type of connection.\n", m_RecvThreadHandle); m_TcpThreadRunning = false; // Shouldn't happen (but was able to with a buffer overflow). break; } } else { // Error Stage if (m_TcpThreadRunning) // We weren't told to stop, but never got our whole packet { LogMessage("[%d] Error receiving TCP packet on port %d, got %d bytes, expecting %d -- aborting!\n", m_RecvThreadHandle,m_TcpPort, received, bytes); if (received > 0 && g_Debug && received < 10000) DumpBuffer(m_RecvBuffer, received); } m_TcpThreadRunning = false; } } else { // Check Connection Status DWORD error = WSAGetLastError(); if ( !isSocketReady && error == 0 ) { m_InactivityTimer++; if ( (m_MaxInactivityTime > 0) && (m_InactivityTimer > m_MaxInactivityTime) ) { LogMessage("[%d] TCP connection on port %d exceeded maximum inactivity. Aborting.\n", m_RecvThreadHandle, m_TcpPort); m_TcpThreadRunning = false; } } else { switch (error) { case 0: LogMessage("[%d] TCP connection on port %d gracefully closed\n", m_RecvThreadHandle, m_TcpPort); break; case WSAECONNRESET: LogMessage("[%d] TCP connection on port %d was reset\n", m_RecvThreadHandle, m_TcpPort); break; default: LogMessage("[%d] TCP error on port %d (Error %d). Aborting.\n", m_RecvThreadHandle, m_TcpPort, error); break; } m_TcpThreadRunning = false; } } } KillConnection(); // m_TcpThreadRunning was set to false. Go to sleep... #ifdef WIN32 SuspendThread(m_RecvThreadHandle); #else pthread_cond_wait(&m_RecvThreadCond, &m_RecvThreadMtx); #endif } m_TcpThreadTerminated = true; }
bool Connection::DoKeyExchange() { unsigned char buffer[128]; unsigned char *p = buffer; int length; // Send the RSA Public Key to the client length = m_WestwoodRSA.GetModulus(&p); length += m_WestwoodRSA.GetPublicExponent(&p); if ( (send(m_Socket, (char *) buffer, length, 0) != length) || // Did send fail? !SocketReady() || // Did the socket timeout? (recv(m_Socket, (char *) buffer, 4, 0) != 4) ) // Never got a 4-byte header? { return false; } long key_length = (long) ntohl((*((unsigned long *) buffer))); if ( (key_length < WWRSA_BLOCK_SIZE) || (key_length > (WWRSA_BLOCK_SIZE + 1)) ) { LogMessage("[%d] ERROR: DoKeyExchange key_length = %d\n", m_RecvThreadHandle, key_length); return false; } // Get the encrypted RC4 Session Key response from the client length = recv(m_Socket, (char *) buffer, key_length, 0); if (length != key_length) { LogMessage("[%d] ERROR: DoKeyExchange key_length = %d, recv_length = %d\n", m_RecvThreadHandle, key_length, length); return false; } // Ignore leading 0 if present p = buffer; if ( (key_length == WWRSA_BLOCK_SIZE + 1) && (*p == 0) ) { key_length--; p++; } // Decrypt the RC4 Session Key unsigned char rc4key[WWRSA_BLOCK_SIZE]; if (!m_WestwoodRSA.Decrypt(p, WWRSA_BLOCK_SIZE, rc4key)) { LogMessage("[%d] ERROR: DoKeyExchange m_WestwoodRSA.Decrypt failed\n", m_RecvThreadHandle); return false; } unsigned char rc4_key_buffer[RC4_KEY_SIZE]; // Reverse the order of the decrypted RC4 Session Key rc4_key_buffer[0] = rc4key[0x3f]; rc4_key_buffer[1] = rc4key[0x3e]; rc4_key_buffer[2] = rc4key[0x3d]; rc4_key_buffer[3] = rc4key[0x3c]; rc4_key_buffer[4] = rc4key[0x3b]; rc4_key_buffer[5] = rc4key[0x3a]; rc4_key_buffer[6] = rc4key[0x39]; rc4_key_buffer[7] = rc4key[0x38]; SetRC4Key(rc4_key_buffer); return true; }