Source: http://www.licq.org/changeset/6146 Reason: DoS via large number of connections, bug #219708 --- a/trunk/licq/include/licq_socket.h +++ b/trunk/licq/include/licq_socket.h @@ -251,4 +251,5 @@ fd_set SocketSet() { return m_sSockets.SocketSet(); } int LargestSocket() { return m_sSockets.Largest(); } + unsigned short Num() { return m_sSockets.Num(); } protected: --- a/trunk/licq/src/socket.cpp +++ b/trunk/licq/src/socket.cpp @@ -818,6 +818,24 @@ socklen_t sizeofSockaddr = sizeof(struct sockaddr_in); - newSocket.m_nDescriptor = accept(m_nDescriptor, (struct sockaddr *)&newSocket.m_sRemoteAddr, &sizeofSockaddr); - newSocket.SetLocalAddress(); + // Make sure we stay under FD_SETSIZE + // See: + // * http://www.securityfocus.com/archive/1/490711 + // * http://securityvulns.com/docs7669.html + // for more details + // This probably has no affect, since we are using multiple threads, but keep it here + // to be used as a sanity check. + int newDesc = accept(m_nDescriptor, (struct sockaddr *)&newSocket.m_sRemoteAddr, &sizeofSockaddr); + if (newDesc < FD_SETSIZE) + { + newSocket.m_nDescriptor = newDesc; + newSocket.SetLocalAddress(); + } + else + { + gLog.Error(tr("%sCannot accept new connection, too many descriptors in use.\n"), L_ERRORxSTR); + close(newDesc); + + // TODO throw an exception, or do something to tell the caller it failed + } } --- a/trunk/licq/src/icqd-threads.cpp +++ b/trunk/licq/src/icqd-threads.cpp @@ -24,4 +24,5 @@ #include "gettext.h" +#define MAX_CONNECTS 256 #define DEBUG_THREADS(x) //#define DEBUG_THREADS(x) gLog.Info(x) @@ -781,6 +782,19 @@ tcp->RecvConnection(*newSocket); gSocketManager.DropSocket(tcp); - gSocketManager.AddSocket(newSocket); - gSocketManager.DropSocket(newSocket); + + // Make sure we can handle another socket before accepting it + if (gSocketManager.Num() > MAX_CONNECTS) + { + // Too many sockets, drop this one + char remoteIp[32]; + gLog.Warn(tr("%sToo many connected sockets, rejecting connection from %s.\n"), + L_WARNxSTR, newSocket->RemoteIpStr(remoteIp)); + delete newSocket; + } + else + { + gSocketManager.AddSocket(newSocket); + gSocketManager.DropSocket(newSocket); + } } } --- a/trunk/licq/src/icqd-chat.cpp +++ b/trunk/licq/src/icqd-chat.cpp @@ -24,4 +24,5 @@ #include "gettext.h" +#define MAX_CONNECTS 256 #define DEBUG_THREADS(x) @@ -2384,14 +2385,22 @@ else if (nCurrentSocket == chatman->chatServer.Descriptor()) { - CChatUser *u = new CChatUser; - u->m_pClient = new CChatClient; - - chatman->chatServer.RecvConnection(u->sock); - chatman->sockman.AddSocket(&u->sock); - chatman->sockman.DropSocket(&u->sock); - - u->state = CHAT_STATE_HANDSHAKE; - chatman->chatUsers.push_back(u); - gLog.Info(tr("%sChat: Received connection.\n"), L_TCPxSTR); + if (chatman->sockman.Num() >= MAX_CONNECTS) + { + // Too many sockets, drop this one + gLog.Warn(tr("%sToo many connected clients, rejecting new connection.\n"), L_WARNxSTR); + } + else + { + CChatUser *u = new CChatUser; + u->m_pClient = new CChatClient; + + chatman->chatServer.RecvConnection(u->sock); + chatman->sockman.AddSocket(&u->sock); + chatman->sockman.DropSocket(&u->sock); + + u->state = CHAT_STATE_HANDSHAKE; + chatman->chatUsers.push_back(u); + gLog.Info(tr("%sChat: Received connection.\n"), L_TCPxSTR); + } }