]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - netconn.c
New rate burst handling; cvars: cl_rate_burstsize, net_usesizelimit, net_burstreserve
[xonotic/darkplaces.git] / netconn.c
index f01c3e05264a13b0016737ae1abcad01e3dec9d0..abc3501e0a23960f8f2171899f81dc98b65347d6 100755 (executable)
--- a/netconn.c
+++ b/netconn.c
@@ -48,7 +48,7 @@ static cvar_t sv_masters [] =
        {0, "sv_masterextra2", "64.22.107.125", "dpmaster.deathmask.net - default master server 2 (admin: Willis)"}, // admin: Willis
        {0, "sv_masterextra3", "92.62.40.73", "dpmaster.tchr.no - default master server 3 (admin: tChr)"}, // admin: tChr
 #ifdef SUPPORTIPV6
-       {0, "sv_masterextra4", "[2001:41d0:2:1628::4450]:27950", "dpmaster.div0.qc.to - default master server 4 (admin: divVerent)"}, // admin: divVerent
+       {0, "sv_masterextra4", "[2a03:4000:2:225::51:334d]:27950", "dpmaster.sudo.rm-f.org - default master server 4 (admin: divVerent)"}, // admin: divVerent
 #endif
        {0, NULL, NULL, NULL}
 };
@@ -76,9 +76,14 @@ static unsigned char sv_message_buf[NET_MAXMESSAGE];
 char cl_readstring[MAX_INPUTLINE];
 char sv_readstring[MAX_INPUTLINE];
 
+cvar_t net_test = {0, "net_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
+cvar_t net_usesizelimit = {0, "net_usesizelimit", "2", "use packet size limiting (0: never, 1: in non-CSQC mode, 2: always)"};
+cvar_t net_burstreserve = {0, "net_burstreserve", "0.3", "how much of the burst time to reserve for packet size spikes"};
 cvar_t net_messagetimeout = {0, "net_messagetimeout","300", "drops players who have not sent any packets for this many seconds"};
 cvar_t net_connecttimeout = {0, "net_connecttimeout","15", "after requesting a connection, the client must reply within this many seconds or be dropped (cuts down on connect floods). Must be above 10 seconds."};
-cvar_t net_connectfloodblockingtimeout = {0, "net_connectfloodblockingtimeout", "5", "when a connection packet is received, it will block all future connect packets from that IP address for this many seconds (cuts down on connect floods)"};
+cvar_t net_connectfloodblockingtimeout = {0, "net_connectfloodblockingtimeout", "5", "when a connection packet is received, it will block all future connect packets from that IP address for this many seconds (cuts down on connect floods). Note that this does not include retries from the same IP; these are handled earlier and let in."};
+cvar_t net_challengefloodblockingtimeout = {0, "net_challengefloodblockingtimeout", "0.5", "when a challenge packet is received, it will block all future challenge packets from that IP address for this many seconds (cuts down on challenge floods). DarkPlaces clients retry once per second, so this should be <= 1. Failure here may lead to connect attempts failing."};
+cvar_t net_getstatusfloodblockingtimeout = {0, "net_getstatusfloodblockingtimeout", "1", "when a getstatus packet is received, it will block all future getstatus packets from that IP address for this many seconds (cuts down on getstatus floods). DarkPlaces retries every 4 seconds, and qstat retries once per second, so this should be <= 1. Failure here may lead to server not showing up in the server list."};
 cvar_t hostname = {CVAR_SAVE, "hostname", "UNNAMED", "server message to show in server browser"};
 cvar_t developer_networking = {0, "developer_networking", "0", "prints all received and sent packets (recommended only for debugging)"};
 
@@ -91,6 +96,7 @@ static cvar_t net_slist_timeout = {0, "net_slist_timeout", "4", "how long to lis
 static cvar_t net_slist_pause = {0, "net_slist_pause", "0", "when set to 1, the server list won't update until it is set back to 0"};
 static cvar_t net_slist_maxtries = {0, "net_slist_maxtries", "3", "how many times to ask the same server for information (more times gives better ping reports but takes longer)"};
 static cvar_t net_slist_favorites = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "net_slist_favorites", "", "contains a list of IP addresses and ports to always query explicitly"};
+static cvar_t net_tos_dscp = {CVAR_SAVE, "net_tos_dscp", "32", "DiffServ Codepoint for network sockets (may need game restart to apply)"};
 static cvar_t gameversion = {0, "gameversion", "0", "version of game data (mod-specific) to be sent to querying clients"};
 static cvar_t gameversion_min = {0, "gameversion_min", "-1", "minimum version of game data (mod-specific), when client and server gameversion mismatch in the server browser the server is shown as incompatible; if -1, gameversion is used alone"};
 static cvar_t gameversion_max = {0, "gameversion_max", "-1", "maximum version of game data (mod-specific), when client and server gameversion mismatch in the server browser the server is shown as incompatible; if -1, gameversion is used alone"};
@@ -652,6 +658,7 @@ qboolean NetConn_CanSend(netconn_t *conn)
        conn->outgoing_netgraph[conn->outgoing_packetcounter].unreliablebytes = NETGRAPH_NOPACKET;
        conn->outgoing_netgraph[conn->outgoing_packetcounter].reliablebytes   = NETGRAPH_NOPACKET;
        conn->outgoing_netgraph[conn->outgoing_packetcounter].ackbytes        = NETGRAPH_NOPACKET;
+       conn->outgoing_netgraph[conn->outgoing_packetcounter].cleartime       = conn->cleartime;
        if (realtime > conn->cleartime)
                return true;
        else
@@ -661,7 +668,24 @@ qboolean NetConn_CanSend(netconn_t *conn)
        }
 }
 
-int NetConn_SendUnreliableMessage(netconn_t *conn, sizebuf_t *data, protocolversion_t protocol, int rate, qboolean quakesignon_suppressreliables)
+void NetConn_UpdateCleartime(double *cleartime, int rate, int burstsize, int len)
+{
+       double bursttime = burstsize / (double)rate;
+
+       // delay later packets to obey rate limit
+       if (*cleartime < realtime - bursttime)
+               *cleartime = realtime - bursttime;
+       *cleartime = *cleartime + len / (double)rate;
+
+       // limit bursts to one packet in size ("dialup mode" emulating old behaviour)
+       if (net_test.integer)
+       {
+               if (*cleartime < realtime)
+                       *cleartime = realtime;
+       }
+}
+
+int NetConn_SendUnreliableMessage(netconn_t *conn, sizebuf_t *data, protocolversion_t protocol, int rate, int burstsize, qboolean quakesignon_suppressreliables)
 {
        int totallen = 0;
        unsigned char sendbuffer[NET_HEADERSIZE+NET_MAXMESSAGE];
@@ -673,6 +697,8 @@ int NetConn_SendUnreliableMessage(netconn_t *conn, sizebuf_t *data, protocolvers
        if (conn->outgoing_netgraph[conn->outgoing_packetcounter].unreliablebytes == NETGRAPH_CHOKEDPACKET)
                conn->outgoing_netgraph[conn->outgoing_packetcounter].unreliablebytes = NETGRAPH_NOPACKET;
 
+       conn->outgoing_netgraph[conn->outgoing_packetcounter].cleartime = conn->cleartime;
+
        if (protocol == PROTOCOL_QUAKEWORLD)
        {
                int packetLen;
@@ -862,12 +888,7 @@ int NetConn_SendUnreliableMessage(netconn_t *conn, sizebuf_t *data, protocolvers
                }
        }
 
-       // delay later packets to obey rate limit
-       if (conn->cleartime < realtime - 0.1)
-               conn->cleartime = realtime - 0.1;
-       conn->cleartime = conn->cleartime + (double)totallen / (double)rate;
-       if (conn->cleartime < realtime)
-               conn->cleartime = realtime;
+       NetConn_UpdateCleartime(&conn->cleartime, cl_rate.integer, cl_rate_burstsize.integer, totallen);
 
        return 0;
 }
@@ -1056,14 +1077,14 @@ netconn_t *NetConn_Open(lhnetsocket_t *mysocket, lhnetaddress_t *peeraddress)
        return conn;
 }
 
-void NetConn_ClearConnectFlood(lhnetaddress_t *peeraddress);
+void NetConn_ClearFlood(lhnetaddress_t *peeraddress, server_floodaddress_t *floodlist, size_t floodlength);
 void NetConn_Close(netconn_t *conn)
 {
        netconn_t *c;
        // remove connection from list
 
        // allow the client to reconnect immediately
-       NetConn_ClearConnectFlood(&(conn->peeraddress));
+       NetConn_ClearFlood(&(conn->peeraddress), sv.connectfloodaddresses, sizeof(sv.connectfloodaddresses) / sizeof(sv.connectfloodaddresses[0]));
 
        if (conn == netconn_list)
                netconn_list = conn->next;
@@ -1092,6 +1113,9 @@ void NetConn_UpdateSockets(void)
 {
        int i, j;
 
+       // TODO add logic to automatically close sockets if needed
+       LHNET_DefaultDSCP(net_tos_dscp.integer);
+
        if (cls.state != ca_dedicated)
        {
                if (clientport2 != cl_netport.integer)
@@ -1185,6 +1209,7 @@ static int NetConn_ReceivedMessage(netconn_t *conn, const unsigned char *data, s
                        {
                                conn->incoming_packetcounter = (conn->incoming_packetcounter + 1) % NETGRAPH_PACKETS;
                                conn->incoming_netgraph[conn->incoming_packetcounter].time            = realtime;
+                               conn->incoming_netgraph[conn->incoming_packetcounter].cleartime       = conn->incoming_cleartime;
                                conn->incoming_netgraph[conn->incoming_packetcounter].unreliablebytes = NETGRAPH_LOSTPACKET;
                                conn->incoming_netgraph[conn->incoming_packetcounter].reliablebytes   = NETGRAPH_NOPACKET;
                                conn->incoming_netgraph[conn->incoming_packetcounter].ackbytes        = NETGRAPH_NOPACKET;
@@ -1192,9 +1217,19 @@ static int NetConn_ReceivedMessage(netconn_t *conn, const unsigned char *data, s
                }
                conn->incoming_packetcounter = (conn->incoming_packetcounter + 1) % NETGRAPH_PACKETS;
                conn->incoming_netgraph[conn->incoming_packetcounter].time            = realtime;
+               conn->incoming_netgraph[conn->incoming_packetcounter].cleartime       = conn->incoming_cleartime;
                conn->incoming_netgraph[conn->incoming_packetcounter].unreliablebytes = originallength + 28;
                conn->incoming_netgraph[conn->incoming_packetcounter].reliablebytes   = NETGRAPH_NOPACKET;
                conn->incoming_netgraph[conn->incoming_packetcounter].ackbytes        = NETGRAPH_NOPACKET;
+               NetConn_UpdateCleartime(&conn->incoming_cleartime, cl_rate.integer, cl_rate_burstsize.integer, originallength + 28);
+
+               // limit bursts to one packet in size ("dialup mode" emulating old behaviour)
+               if (net_test.integer)
+               {
+                       if (conn->cleartime < realtime)
+                               conn->cleartime = realtime;
+               }
+
                if (reliable_ack == conn->qw.reliable_sequence)
                {
                        // received, now we will be able to send another reliable message
@@ -1264,6 +1299,7 @@ static int NetConn_ReceivedMessage(netconn_t *conn, const unsigned char *data, s
                                                {
                                                        conn->incoming_packetcounter = (conn->incoming_packetcounter + 1) % NETGRAPH_PACKETS;
                                                        conn->incoming_netgraph[conn->incoming_packetcounter].time            = realtime;
+                                                       conn->incoming_netgraph[conn->incoming_packetcounter].cleartime       = conn->incoming_cleartime;
                                                        conn->incoming_netgraph[conn->incoming_packetcounter].unreliablebytes = NETGRAPH_LOSTPACKET;
                                                        conn->incoming_netgraph[conn->incoming_packetcounter].reliablebytes   = NETGRAPH_NOPACKET;
                                                        conn->incoming_netgraph[conn->incoming_packetcounter].ackbytes        = NETGRAPH_NOPACKET;
@@ -1271,9 +1307,12 @@ static int NetConn_ReceivedMessage(netconn_t *conn, const unsigned char *data, s
                                        }
                                        conn->incoming_packetcounter = (conn->incoming_packetcounter + 1) % NETGRAPH_PACKETS;
                                        conn->incoming_netgraph[conn->incoming_packetcounter].time            = realtime;
+                                       conn->incoming_netgraph[conn->incoming_packetcounter].cleartime       = conn->incoming_cleartime;
                                        conn->incoming_netgraph[conn->incoming_packetcounter].unreliablebytes = originallength + 28;
                                        conn->incoming_netgraph[conn->incoming_packetcounter].reliablebytes   = NETGRAPH_NOPACKET;
                                        conn->incoming_netgraph[conn->incoming_packetcounter].ackbytes        = NETGRAPH_NOPACKET;
+                                       NetConn_UpdateCleartime(&conn->incoming_cleartime, cl_rate.integer, cl_rate_burstsize.integer, originallength + 28);
+
                                        conn->nq.unreliableReceiveSequence = sequence + 1;
                                        conn->lastMessageTime = realtime;
                                        conn->timeout = realtime + newtimeout;
@@ -1302,6 +1341,8 @@ static int NetConn_ReceivedMessage(netconn_t *conn, const unsigned char *data, s
                        else if (flags & NETFLAG_ACK)
                        {
                                conn->incoming_netgraph[conn->incoming_packetcounter].ackbytes += originallength + 28;
+                               NetConn_UpdateCleartime(&conn->incoming_cleartime, cl_rate.integer, cl_rate_burstsize.integer, originallength + 28);
+
                                if (sequence == (conn->nq.sendSequence - 1))
                                {
                                        if (sequence == conn->nq.ackSequence)
@@ -1360,7 +1401,10 @@ static int NetConn_ReceivedMessage(netconn_t *conn, const unsigned char *data, s
                        {
                                unsigned char temppacket[8];
                                conn->incoming_netgraph[conn->incoming_packetcounter].reliablebytes   += originallength + 28;
+                               NetConn_UpdateCleartime(&conn->incoming_cleartime, cl_rate.integer, cl_rate_burstsize.integer, originallength + 28);
+
                                conn->outgoing_netgraph[conn->outgoing_packetcounter].ackbytes        += 8 + 28;
+
                                StoreBigLong(temppacket, 8 | NETFLAG_ACK);
                                StoreBigLong(temppacket + 4, sequence);
                                sendme = Crypto_EncryptPacket(&conn->crypto, temppacket, 8, &cryptosendbuffer, &sendmelen, sizeof(cryptosendbuffer));
@@ -1462,7 +1506,7 @@ static void NetConn_ConnectionEstablished(lhnetsocket_t *mysocket, lhnetaddress_
                msg.data = buf;
                msg.maxsize = sizeof(buf);
                MSG_WriteChar(&msg, clc_nop);
-               NetConn_SendUnreliableMessage(cls.netcon, &msg, cls.protocol, 10000, false);
+               NetConn_SendUnreliableMessage(cls.netcon, &msg, cls.protocol, 10000, 0, false);
        }
 }
 
@@ -1588,7 +1632,7 @@ static qboolean NetConn_ClientParsePacket_ServerList_PrepareQuery( int protocol,
 
        entry = &serverlist_cache[n];
 
-       memset(entry, 0, sizeof(entry));
+       memset(entry, 0, sizeof(*entry));
        entry->protocol =       protocol;
        //      store   the data        the engine cares about (address and     ping)
        strlcpy (entry->info.cname, ipstring, sizeof(entry->info.cname));
@@ -2496,31 +2540,34 @@ bad:
        return false;
 }
 
-static qboolean NetConn_PreventConnectFlood(lhnetaddress_t *peeraddress)
+static qboolean NetConn_PreventFlood(lhnetaddress_t *peeraddress, server_floodaddress_t *floodlist, size_t floodlength, double floodtime, qboolean renew)
 {
-       int floodslotnum, bestfloodslotnum;
+       size_t floodslotnum, bestfloodslotnum;
        double bestfloodtime;
        lhnetaddress_t noportpeeraddress;
        // see if this is a connect flood
        noportpeeraddress = *peeraddress;
        LHNETADDRESS_SetPort(&noportpeeraddress, 0);
        bestfloodslotnum = 0;
-       bestfloodtime = sv.connectfloodaddresses[bestfloodslotnum].lasttime;
-       for (floodslotnum = 0;floodslotnum < MAX_CONNECTFLOODADDRESSES;floodslotnum++)
+       bestfloodtime = floodlist[bestfloodslotnum].lasttime;
+       for (floodslotnum = 0;floodslotnum < floodlength;floodslotnum++)
        {
-               if (bestfloodtime >= sv.connectfloodaddresses[floodslotnum].lasttime)
+               if (bestfloodtime >= floodlist[floodslotnum].lasttime)
                {
-                       bestfloodtime = sv.connectfloodaddresses[floodslotnum].lasttime;
+                       bestfloodtime = floodlist[floodslotnum].lasttime;
                        bestfloodslotnum = floodslotnum;
                }
-               if (sv.connectfloodaddresses[floodslotnum].lasttime && LHNETADDRESS_Compare(&noportpeeraddress, &sv.connectfloodaddresses[floodslotnum].address) == 0)
+               if (floodlist[floodslotnum].lasttime && LHNETADDRESS_Compare(&noportpeeraddress, &floodlist[floodslotnum].address) == 0)
                {
                        // this address matches an ongoing flood address
-                       if (realtime < sv.connectfloodaddresses[floodslotnum].lasttime + net_connectfloodblockingtimeout.value)
+                       if (realtime < floodlist[floodslotnum].lasttime + floodtime)
                        {
-                               // renew the ban on this address so it does not expire
-                               // until the flood has subsided
-                               sv.connectfloodaddresses[floodslotnum].lasttime = realtime;
+                               if(renew)
+                               {
+                                       // renew the ban on this address so it does not expire
+                                       // until the flood has subsided
+                                       floodlist[floodslotnum].lasttime = realtime;
+                               }
                                //Con_Printf("Flood detected!\n");
                                return true;
                        }
@@ -2530,27 +2577,27 @@ static qboolean NetConn_PreventConnectFlood(lhnetaddress_t *peeraddress)
                }
        }
        // begin a new timeout on this address
-       sv.connectfloodaddresses[bestfloodslotnum].address = noportpeeraddress;
-       sv.connectfloodaddresses[bestfloodslotnum].lasttime = realtime;
+       floodlist[bestfloodslotnum].address = noportpeeraddress;
+       floodlist[bestfloodslotnum].lasttime = realtime;
        //Con_Printf("Flood detection initiated!\n");
        return false;
 }
 
-void NetConn_ClearConnectFlood(lhnetaddress_t *peeraddress)
+void NetConn_ClearFlood(lhnetaddress_t *peeraddress, server_floodaddress_t *floodlist, size_t floodlength)
 {
-       int floodslotnum;
+       size_t floodslotnum;
        lhnetaddress_t noportpeeraddress;
        // see if this is a connect flood
        noportpeeraddress = *peeraddress;
        LHNETADDRESS_SetPort(&noportpeeraddress, 0);
-       for (floodslotnum = 0;floodslotnum < MAX_CONNECTFLOODADDRESSES;floodslotnum++)
+       for (floodslotnum = 0;floodslotnum < floodlength;floodslotnum++)
        {
-               if (sv.connectfloodaddresses[floodslotnum].lasttime && LHNETADDRESS_Compare(&noportpeeraddress, &sv.connectfloodaddresses[floodslotnum].address) == 0)
+               if (floodlist[floodslotnum].lasttime && LHNETADDRESS_Compare(&noportpeeraddress, &floodlist[floodslotnum].address) == 0)
                {
                        // this address matches an ongoing flood address
                        // remove the ban
-                       sv.connectfloodaddresses[floodslotnum].address.addresstype = LHNETADDRESSTYPE_NONE;
-                       sv.connectfloodaddresses[floodslotnum].lasttime = 0;
+                       floodlist[floodslotnum].address.addresstype = LHNETADDRESSTYPE_NONE;
+                       floodlist[floodslotnum].lasttime = 0;
                        //Con_Printf("Flood cleared!\n");
                }
        }
@@ -2835,6 +2882,12 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                                challenge[i].address = *peeraddress;
                                NetConn_BuildChallengeString(challenge[i].string, sizeof(challenge[i].string));
                        }
+                       else
+                       {
+                               // flood control: drop if requesting challenge too often
+                               if(challenge[i].time > realtime - net_challengefloodblockingtimeout.value)
+                                       return true;
+                       }
                        challenge[i].time = realtime;
                        // send the challenge
                        dpsnprintf(response, sizeof(response), "\377\377\377\377challenge %s", challenge[i].string);
@@ -2939,7 +2992,7 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                                                        return true;
                                                }
                                        }
-                                       if (client->spawned)
+                                       if (client->begun)
                                        {
                                                // client crashed and is coming back,
                                                // keep their stuff intact
@@ -2964,7 +3017,7 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                                }
                        }
 
-                       if (NetConn_PreventConnectFlood(peeraddress))
+                       if (NetConn_PreventFlood(peeraddress, sv.connectfloodaddresses, sizeof(sv.connectfloodaddresses) / sizeof(sv.connectfloodaddresses[0]), net_connectfloodblockingtimeout.value, true))
                                return true;
 
                        // find an empty client slot for this new client
@@ -2997,6 +3050,9 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                {
                        const char *challenge = NULL;
 
+                       if (NetConn_PreventFlood(peeraddress, sv.getstatusfloodaddresses, sizeof(sv.getstatusfloodaddresses) / sizeof(sv.getstatusfloodaddresses[0]), net_getstatusfloodblockingtimeout.value, false))
+                               return true;
+
                        // If there was a challenge in the getinfo message
                        if (length > 8 && string[7] == ' ')
                                challenge = string + 8;
@@ -3013,6 +3069,9 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                {
                        const char *challenge = NULL;
 
+                       if (NetConn_PreventFlood(peeraddress, sv.getstatusfloodaddresses, sizeof(sv.getstatusfloodaddresses) / sizeof(sv.getstatusfloodaddresses[0]), net_getstatusfloodblockingtimeout.value, false))
+                               return true;
+
                        // If there was a challenge in the getinfo message
                        if (length > 10 && string[9] == ' ')
                                challenge = string + 10;
@@ -3166,6 +3225,22 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                                        // or coming back from a timeout
                                        // (if so, keep their stuff intact)
 
+                                       crypto_t *crypto = Crypto_ServerGetInstance(peeraddress);
+                                       if((crypto && crypto->authenticated) || client->netconnection->crypto.authenticated)
+                                       {
+                                               if (developer_extra.integer)
+                                                       Con_Printf("Datagram_ParseConnectionless: sending CCREP_REJECT \"Attempt to downgrade crypto.\" to %s.\n", addressstring2);
+                                               SZ_Clear(&sv_message);
+                                               // save space for the header, filled in later
+                                               MSG_WriteLong(&sv_message, 0);
+                                               MSG_WriteByte(&sv_message, CCREP_REJECT);
+                                               MSG_WriteString(&sv_message, "Attempt to downgrade crypto.\n");
+                                               StoreBigLong(sv_message.data, NETFLAG_CTL | (sv_message.cursize & NETFLAG_LENGTH_MASK));
+                                               NetConn_Write(mysocket, sv_message.data, sv_message.cursize, peeraddress);
+                                               SZ_Clear(&sv_message);
+                                               return true;
+                                       }
+
                                        // send a reply
                                        if (developer_extra.integer)
                                                Con_DPrintf("Datagram_ParseConnectionless: sending duplicate CCREP_ACCEPT to %s.\n", addressstring2);
@@ -3180,14 +3255,14 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
 
                                        // if client is already spawned, re-send the
                                        // serverinfo message as they'll need it to play
-                                       if (client->spawned)
+                                       if (client->begun)
                                                SV_SendServerinfo(client);
                                        return true;
                                }
                        }
 
                        // this is a new client, check for connection flood
-                       if (NetConn_PreventConnectFlood(peeraddress))
+                       if (NetConn_PreventFlood(peeraddress, sv.connectfloodaddresses, sizeof(sv.connectfloodaddresses) / sizeof(sv.connectfloodaddresses[0]), net_connectfloodblockingtimeout.value, true))
                                break;
 
                        // find a slot for the new client
@@ -3234,6 +3309,10 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                                Con_DPrintf("Datagram_ParseConnectionless: received CCREQ_SERVER_INFO from %s.\n", addressstring2);
                        if(!(islocal || sv_public.integer > -1))
                                break;
+
+                       if (NetConn_PreventFlood(peeraddress, sv.getstatusfloodaddresses, sizeof(sv.getstatusfloodaddresses) / sizeof(sv.getstatusfloodaddresses[0]), net_getstatusfloodblockingtimeout.value, false))
+                               break;
+
                        if (sv.active && !strcmp(MSG_ReadString(&sv_message, sv_readstring, sizeof(sv_readstring)), "QUAKE"))
                        {
                                int numclients;
@@ -3265,6 +3344,10 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                                Con_DPrintf("Datagram_ParseConnectionless: received CCREQ_PLAYER_INFO from %s.\n", addressstring2);
                        if(!(islocal || sv_public.integer > -1))
                                break;
+
+                       if (NetConn_PreventFlood(peeraddress, sv.getstatusfloodaddresses, sizeof(sv.getstatusfloodaddresses) / sizeof(sv.getstatusfloodaddresses[0]), net_getstatusfloodblockingtimeout.value, false))
+                               break;
+
                        if (sv.active)
                        {
                                int playerNumber, activeNumber, clientNumber;
@@ -3301,6 +3384,9 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                                Con_DPrintf("Datagram_ParseConnectionless: received CCREQ_RULE_INFO from %s.\n", addressstring2);
                        if(!(islocal || sv_public.integer > -1))
                                break;
+
+                       // no flood check here, as it only returns one cvar for one cvar and clients may iterate quickly
+
                        if (sv.active)
                        {
                                char *prevCvarName;
@@ -3354,7 +3440,7 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
        }
        if (host_client)
        {
-               if ((ret = NetConn_ReceivedMessage(host_client->netconnection, data, length, sv.protocol, host_client->spawned ? net_messagetimeout.value : net_connecttimeout.value)) == 2)
+               if ((ret = NetConn_ReceivedMessage(host_client->netconnection, data, length, sv.protocol, host_client->begun ? net_messagetimeout.value : net_connecttimeout.value)) == 2)
                {
                        SV_ReadClientMessage();
                        return ret;
@@ -3633,6 +3719,9 @@ void NetConn_Init(void)
        Cmd_AddCommand("net_slistqw", Net_SlistQW_f, "query qw master servers and print all server information");
        Cmd_AddCommand("net_refresh", Net_Refresh_f, "query dp master servers and refresh all server information");
        Cmd_AddCommand("heartbeat", Net_Heartbeat_f, "send a heartbeat to the master server (updates your server information)");
+       Cvar_RegisterVariable(&net_test);
+       Cvar_RegisterVariable(&net_usesizelimit);
+       Cvar_RegisterVariable(&net_burstreserve);
        Cvar_RegisterVariable(&rcon_restricted_password);
        Cvar_RegisterVariable(&rcon_restricted_commands);
        Cvar_RegisterVariable(&rcon_secure_maxdiff);
@@ -3642,9 +3731,13 @@ void NetConn_Init(void)
        Cvar_RegisterVariable(&net_slist_maxtries);
        Cvar_RegisterVariable(&net_slist_favorites);
        Cvar_RegisterVariable(&net_slist_pause);
+       if(LHNET_DefaultDSCP(-1) >= 0) // register cvar only if supported
+               Cvar_RegisterVariable(&net_tos_dscp);
        Cvar_RegisterVariable(&net_messagetimeout);
        Cvar_RegisterVariable(&net_connecttimeout);
        Cvar_RegisterVariable(&net_connectfloodblockingtimeout);
+       Cvar_RegisterVariable(&net_challengefloodblockingtimeout);
+       Cvar_RegisterVariable(&net_getstatusfloodblockingtimeout);
        Cvar_RegisterVariable(&cl_netlocalping);
        Cvar_RegisterVariable(&cl_netpacketloss_send);
        Cvar_RegisterVariable(&cl_netpacketloss_receive);