1
votes

I'm trying to do a stress test in case attackers try to attempt a lot of TCP connections to my C++ game server at once.

I made a simple program that connects 1000 times via the TCP port to my game server. Here is where my server accepts connections:

bool serverIsOn = true;
double listen = tcplisten(12345, 30000, 1);
setnagle(listen, true);

...

while(serverIsOn){
    double playerSocket = tcpaccept(listen, 1);
    if(playerSocket > -1){
        cout << "Got a new connection, socket ID: " << playerSocket << endl;

        std::string ip = tcpip(playerSocket);
        if(ipIsBanned(ip))
            closesocket(playerSocket);
    }
}

Here are the definitions of tcplisten and tcpaccept:

double tcplisten(double port, double max, double mode)
{
    CSocket* sock = new CSocket();
    if(sock->tcplisten((int)port, (int)max,(int)mode))
        return AddSocket(sock);
    delete sock;
    return -1;
}

double tcpaccept(double sockid, double mode)
{
    CSocket*sock = (CSocket*)sockets.item((int)sockid);
    if(sock == NULL)return -1;
    CSocket*sock2 = sock->tcpaccept((int)mode);
    if(sock2 != NULL)return AddSocket(sock2);
    return -1;
}

The problem: The server stops accepting connections after my test program has ended. For example, if I connect on my game after (which only requests one connection as opposed to my test-attack program which requests 1000 connections), the game can not even connect. I also do not see any connections via console output on my server anymore. The last connection made was from the attack program. It's as if it can't accept anymore and something has crashed but I can't figure out what, no exceptions or errors.

This is a huge problem for my server as anyone can easily just crash the server and force it to have to restart to start accepting new connections again.

What can I do to combat this? I mean I tried even setting the max number of connections at once to 30,000 but that didn't work. Even if it did work, someone could just try to connect more than 30,000 times making that useless.

EDIT:

More in-depth definitions of tcplisten and tcpaccept functions above:

bool CSocket::tcplisten(int port, int max, int mode)
{
    if((sockid = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) return false;
    SOCKADDR_IN addr;
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(port);
    if(mode)setsync(1);
    if(bind(sockid, (LPSOCKADDR)&addr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
    {
        closesocket(sockid);
        return false;
    }
    if(listen(sockid, max) == SOCKET_ERROR)
    {
        closesocket(sockid);
        //TEMP ADD
        sockid = INVALID_SOCKET;
        return false;
    }
    return true;
}


CSocket* CSocket::tcpaccept(int mode)
{
    //TEMP REMOVE: if(sockid<0)return NULL;
    if(sockid == INVALID_SOCKET) return NULL;
    SOCKET sock2;
    if((sock2 = accept(sockid, (SOCKADDR *)&SenderAddr, &SenderAddrSize)) != INVALID_SOCKET)
    {
        CSocket*sockit = new CSocket(sock2);
        if(mode >=1)sockit->setsync(1);
        return sockit;
    }

    return NULL;
}

EDIT 2: Here is the definition of AddSocket:

int AddSocket(CSocket*b)
{
    for(int i = 0; i < sockets.count; i ++)
    {
        if(sockets[i] == NULL)
        {
            sockets.set(i, b);
            return i;
        }
    }
    sockets.Add(b);
    return sockets.count-1;
}
1
When you call closesocket(sockid), make sure to also set sockid = INVALID_SOCKET afterwards. And sockid<0 should be sockid == INVALID_SOCKET. And why are you using double to represent sockets instead of using SOCKET or at least int? SOCKET handles are not floating-point values. An what does AddSocket() actually return? You are passing that value directly to closesocket() if the IP is banned. Why are you not cleaning up your CSocket object for that client? - Remy Lebeau
And the max value you pass to listen() does not control how many clients can be connected at a time, it controls how many clients can be pending in the socket's backlog waiting for accept() to accept them. You have to use your own logic to control the number of max clients connected at a time. If accept() returns an accepted client, and you have exceeded your max limit, close the socket immediately. Or use WSAAccept() instead of accept() so you can use a callback function that rejects pending clients when your max limit has been reached. - Remy Lebeau
Your situation sounds like either your while(serverIsOn) loop has stopped running, or accept() is blocked waiting for new clients that never arrive. But you have no output when socket functions fail, or any output after your loop ends. Add those messages and then see what happens. - Remy Lebeau
Amazing! I use that port number on my luggage! - user4581301
Port numbers are not doubles either, they are 16-bit integers. This is very strange code. - user207421

1 Answers

0
votes

If you're on Linux, you can use the tcp_tw_reuse sysctl.