]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - netconn.c
make IPv6 addresses actually work in server queries
[xonotic/darkplaces.git] / netconn.c
index 9da54c77f1c2e4980d833d8b5032f645047330a9..f6e5a6f3d8124b2b8c4673318f78f32e5cf2c79a 100755 (executable)
--- a/netconn.c
+++ b/netconn.c
@@ -32,7 +32,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #define DPMASTER_PORT 27950
 
 // note this defaults on for dedicated servers, off for listen servers
-cvar_t sv_public = {0, "sv_public", "0", "1: advertises this server on the master server (so that players can find it in the server browser); 0: allow direct queries only; -1: do not respond to direct queries; -2: do not allow anyone to connect"};
+cvar_t sv_public = {0, "sv_public", "0", "1: advertises this server on the master server (so that players can find it in the server browser); 0: allow direct queries only; -1: do not respond to direct queries; -2: do not allow anyone to connect; -3: already block at getchallenge level"};
+cvar_t sv_public_rejectreason = {0, "sv_public_rejectreason", "The server is closing.", "Rejection reason for connects when sv_public is -2"};
 static cvar_t sv_heartbeatperiod = {CVAR_SAVE, "sv_heartbeatperiod", "120", "how often to send heartbeat in seconds (only used if sv_public is 1)"};
 
 static cvar_t sv_masters [] =
@@ -148,7 +149,7 @@ serverlist_infofield_t serverlist_sortbyfield;
 int serverlist_sortflags;
 
 int serverlist_viewcount = 0;
-serverlist_entry_t *serverlist_viewlist[SERVERLIST_VIEWLISTSIZE];
+unsigned short serverlist_viewlist[SERVERLIST_VIEWLISTSIZE];
 
 int serverlist_maxcachecount = 0;
 int serverlist_cachecount = 0;
@@ -157,7 +158,7 @@ serverlist_entry_t *serverlist_cache = NULL;
 qboolean serverlist_consoleoutput;
 
 static int nFavorites = 0;
-static lhnetaddress_t favorites[256];
+static lhnetaddress_t favorites[MAX_FAVORITESERVERS];
 
 void NetConn_UpdateFavorites(void)
 {
@@ -185,7 +186,7 @@ static void _ServerList_ViewList_Helper_InsertBefore( int index, serverlist_entr
        for( ; i > index ; i-- )
                serverlist_viewlist[ i ] = serverlist_viewlist[ i - 1 ];
 
-       serverlist_viewlist[index] = entry;
+       serverlist_viewlist[index] = (int)(entry - serverlist_cache);
 }
 
 /// we suppose serverlist_viewcount to be valid, ie > 0
@@ -431,11 +432,11 @@ static void ServerList_ViewList_Insert( serverlist_entry_t *entry )
 
        // two special cases
        // check whether to insert it as new first item
-       if( _ServerList_Entry_Compare( entry, serverlist_viewlist[0] ) ) {
+       if( _ServerList_Entry_Compare( entry, ServerList_GetViewEntry(0) ) ) {
                _ServerList_ViewList_Helper_InsertBefore( 0, entry );
                return;
        } // check whether to insert it as new last item
-       else if( !_ServerList_Entry_Compare( entry, serverlist_viewlist[serverlist_viewcount - 1] ) ) {
+       else if( !_ServerList_Entry_Compare( entry, ServerList_GetViewEntry(serverlist_viewcount - 1) ) ) {
                _ServerList_ViewList_Helper_InsertBefore( serverlist_viewcount, entry );
                return;
        }
@@ -445,7 +446,7 @@ static void ServerList_ViewList_Insert( serverlist_entry_t *entry )
        {
                mid = (start + end) / 2;
                // test the item that lies in the middle between start and end
-               if( _ServerList_Entry_Compare( entry, serverlist_viewlist[mid] ) )
+               if( _ServerList_Entry_Compare( entry, ServerList_GetViewEntry(mid) ) )
                        // the item has to be in the upper half
                        end = mid;
                else
@@ -460,7 +461,7 @@ static void ServerList_ViewList_Remove( serverlist_entry_t *entry )
        int i;
        for( i = 0; i < serverlist_viewcount; i++ )
        {
-               if (serverlist_viewlist[i] == entry)
+               if (ServerList_GetViewEntry(i) == entry)
                {
                        _ServerList_ViewList_Helper_Remove(i);
                        break;
@@ -1094,7 +1095,7 @@ static int NetConn_ReceivedMessage(netconn_t *conn, unsigned char *data, int len
                int sequence, sequence_ack;
                int reliable_ack, reliable_message;
                int count;
-               int qport;
+               //int qport;
 
                sequence = LittleLong(*((int *)(data + 0)));
                sequence_ack = LittleLong(*((int *)(data + 4)));
@@ -1107,7 +1108,7 @@ static int NetConn_ReceivedMessage(netconn_t *conn, unsigned char *data, int len
                        if (length < 2)
                                return 0;
                        // TODO: use qport to identify that this client really is who they say they are?  (and elsewhere in the code to identify the connection without a port match?)
-                       qport = LittleShort(*((int *)(data + 8)));
+                       //qport = LittleShort(*((int *)(data + 8)));
                        data += 2;
                        length -= 2;
                }
@@ -1530,16 +1531,16 @@ static void NetConn_ClientParsePacket_ServerList_ParseDPList(lhnetaddress_t *sen
                                ifname = LHNETADDRESS_GetInterfaceName(senderaddress);
                                if (ifname != NULL)
                                {
-                                       dpsnprintf (ipstring, sizeof (ipstring), "[%x%02x:%x%02x:%x%02x:%x%02x:%x%02x:%x%02x:%x%02x:%x%02x%%%s]:%hu",
-                                                               data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8],
-                                                               data[9], data[10], data[11], data[12], data[13], data[14], data[15], data[16],
+                                       dpsnprintf (ipstring, sizeof (ipstring), "[%x:%x:%x:%x:%x:%x:%x:%x%%%s]:%hu",
+                                                               (data[1] << 8) | data[2], (data[3] << 8) | data[4], (data[5] << 8) | data[6], (data[7] << 8) | data[8],
+                                                               (data[9] << 8) | data[10], (data[11] << 8) | data[12], (data[13] << 8) | data[14], (data[15] << 8) | data[16],
                                                                ifname, port);
                                }
                                else
                                {
-                                       dpsnprintf (ipstring, sizeof (ipstring), "[%x%02x:%x%02x:%x%02x:%x%02x:%x%02x:%x%02x:%x%02x:%x%02x]:%hu",
-                                                               data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8],
-                                                               data[9], data[10], data[11], data[12], data[13], data[14], data[15], data[16],
+                                       dpsnprintf (ipstring, sizeof (ipstring), "[%x:%x:%x:%x:%x:%x:%x:%x]:%hu",
+                                                               (data[1] << 8) | data[2], (data[3] << 8) | data[4], (data[5] << 8) | data[6], (data[7] << 8) | data[8],
+                                                               (data[9] << 8) | data[10], (data[11] << 8) | data[12], (data[13] << 8) | data[14], (data[15] << 8) | data[16],
                                                                port);
                                }
                        }
@@ -1601,9 +1602,10 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
 
                if (length > 10 && !memcmp(string, "challenge ", 10) && cls.rcon_trying)
                {
-                       int i, j;
+                       int i = 0, j;
                        for (j = 0;j < MAX_RCONS;j++)
                        {
+                               // note: this value from i is used outside the loop too...
                                i = (cls.rcon_ringpos + j) % MAX_RCONS;
                                if(cls.rcon_commands[i][0])
                                        if (!LHNETADDRESS_Compare(peeraddress, &cls.rcon_addresses[i]))
@@ -1623,24 +1625,26 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
 
                                if(HMAC_MDFOUR_16BYTES((unsigned char *) (buf + 29), (unsigned char *) argbuf, strlen(argbuf), (unsigned char *) rcon_password.string, n))
                                {
+                                       int k;
                                        buf[45] = ' ';
                                        strlcpy(buf + 46, argbuf, sizeof(buf) - 46);
                                        NetConn_Write(mysocket, buf, 46 + strlen(buf + 46), peeraddress);
                                        cls.rcon_commands[i][0] = 0;
                                        --cls.rcon_trying;
 
-                                       for (i = 0;i < MAX_RCONS;i++)
-                                               if(cls.rcon_commands[i][0])
-                                                       if (!LHNETADDRESS_Compare(peeraddress, &cls.rcon_addresses[i]))
+                                       for (k = 0;k < MAX_RCONS;k++)
+                                               if(cls.rcon_commands[k][0])
+                                                       if (!LHNETADDRESS_Compare(peeraddress, &cls.rcon_addresses[k]))
                                                                break;
-                                       if(i < MAX_RCONS)
+                                       if(k < MAX_RCONS)
                                        {
+                                               int l;
                                                NetConn_WriteString(mysocket, "\377\377\377\377getchallenge", peeraddress);
                                                // extend the timeout on other requests as we asked for a challenge
-                                               for (i = 0;i < MAX_RCONS;i++)
-                                                       if(cls.rcon_commands[i][0])
-                                                               if (!LHNETADDRESS_Compare(peeraddress, &cls.rcon_addresses[i]))
-                                                                       cls.rcon_timeout[i] = realtime + rcon_secure_challengetimeout.value;
+                                               for (l = 0;l < MAX_RCONS;l++)
+                                                       if(cls.rcon_commands[l][0])
+                                                               if (!LHNETADDRESS_Compare(peeraddress, &cls.rcon_addresses[l]))
+                                                                       cls.rcon_timeout[l] = realtime + rcon_secure_challengetimeout.value;
                                        }
 
                                        return true; // we used up the challenge, so we can't use this oen for connecting now anyway
@@ -1657,7 +1661,7 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                        // update the server IP in the userinfo (QW servers expect this, and it is used by the reconnect command)
                        InfoString_SetValue(cls.userinfo, sizeof(cls.userinfo), "*ip", addressstring2);
                        // TODO: add userinfo stuff here instead of using NQ commands?
-                       NetConn_WriteString(mysocket, va("\377\377\377\377connect\\protocol\\darkplaces 3\\protocols\\%s\\challenge\\%s", protocolnames, string + 10), peeraddress);
+                       NetConn_WriteString(mysocket, va("\377\377\377\377connect\\protocol\\darkplaces 3\\protocols\\%s%s\\challenge\\%s", protocolnames, cls.connect_userinfo, string + 10), peeraddress);
                        return true;
                }
                if (length == 6 && !memcmp(string, "accept", 6) && cls.connect_trying)
@@ -1841,7 +1845,7 @@ static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                        cls.qw_qport = qport.integer;
                        // update the server IP in the userinfo (QW servers expect this, and it is used by the reconnect command)
                        InfoString_SetValue(cls.userinfo, sizeof(cls.userinfo), "*ip", addressstring2);
-                       NetConn_WriteString(mysocket, va("\377\377\377\377connect %i %i %i \"%s\"\n", 28, cls.qw_qport, atoi(string + 1), cls.userinfo), peeraddress);
+                       NetConn_WriteString(mysocket, va("\377\377\377\377connect %i %i %i \"%s%s\"\n", 28, cls.qw_qport, atoi(string + 1), cls.userinfo, cls.connect_userinfo), peeraddress);
                        return true;
                }
                if (length >= 1 && string[0] == 'j' && cls.connect_trying)
@@ -2122,8 +2126,14 @@ void NetConn_ClientFrame(void)
                SZ_Clear(&net_message);
        }
        for (i = 0;i < cl_numsockets;i++)
+       {
                while (cl_sockets[i] && (length = NetConn_Read(cl_sockets[i], readbuffer, sizeof(readbuffer), &peeraddress)) > 0)
+               {
+//                     R_TimeReport("clientreadnetwork");
                        NetConn_ClientParsePacket(cl_sockets[i], readbuffer, length, &peeraddress);
+//                     R_TimeReport("clientparsepacket");
+               }
+       }
        NetConn_QueryQueueFrame();
        if (cls.netcon && realtime > cls.netcon->timeout && !sv.active)
        {
@@ -2204,7 +2214,7 @@ static qboolean NetConn_BuildStatusResponse(const char* challenge, char* out_msg
                                                "%s",
                                                fullstatus ? "statusResponse" : "infoResponse",
                                                gamename, com_modname, gameversion.integer, svs.maxclients,
-                                               nb_clients, nb_bots, sv.name, hostname.string, NET_PROTOCOL_VERSION,
+                                               nb_clients, nb_bots, sv.worldbasename, hostname.string, NET_PROTOCOL_VERSION,
                                                *qcstatus ? "\\qcstatus\\" : "", qcstatus,
                                                challenge ? "\\challenge\\" : "", challenge ? challenge : "",
                                                fullstatus ? "\n" : "");
@@ -2270,7 +2280,7 @@ static qboolean NetConn_BuildStatusResponse(const char* challenge, char* out_msg
                                        }
                                }
 
-                               if ((gamemode == GAME_NEXUIZ) && (teamplay.integer > 0))
+                               if ((gamemode == GAME_NEXUIZ || gamemode == GAME_XONOTIC) && (teamplay.integer > 0))
                                {
                                        if(cl->frags == -666) // spectator
                                                strlcpy(teambuf, " 0", sizeof(teambuf));
@@ -2441,7 +2451,7 @@ qboolean plaintext_matching(lhnetaddress_t *peeraddress, const char *password, c
 const char *RCon_Authenticate(lhnetaddress_t *peeraddress, const char *password, const char *s, const char *endpos, rcon_matchfunc_t comparator, const char *cs, int cslen)
 {
        const char *text, *userpass_start, *userpass_end, *userpass_startpass;
-       char buf[MAX_INPUTLINE];
+       static char buf[MAX_INPUTLINE];
        qboolean hasquotes;
        qboolean restricted = false;
        qboolean have_usernames = false;
@@ -2531,10 +2541,8 @@ allow:
        userpass_startpass = strchr(userpass_start, ':');
        if(have_usernames && userpass_startpass && userpass_startpass < userpass_end)
                return va("%srcon (username %.*s)", restricted ? "restricted " : "", (int)(userpass_startpass-userpass_start), userpass_start);
-       else
-               return va("%srcon", restricted ? "restricted " : "");
 
-       return "restricted rcon";
+       return va("%srcon", restricted ? "restricted " : "");
 }
 
 void RCon_Execute(lhnetsocket_t *mysocket, lhnetaddress_t *peeraddress, const char *addressstring2, const char *userlevel, const char *s, const char *endpos)
@@ -2581,7 +2589,8 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
        int i, ret, clientnum, best;
        double besttime;
        client_t *client;
-       char *s, *string, response[1400], addressstring2[128], stringbuf[16384];
+       char *s, *string, response[1400], addressstring2[128];
+       static char stringbuf[16384];
        qboolean islocal = (LHNETADDRESS_GetAddressType(peeraddress) == LHNETADDRESSTYPE_LOOP);
 
        if (!sv.active)
@@ -2616,7 +2625,7 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                        Com_HexDumpToConsole(data, length);
                }
 
-               if (length >= 12 && !memcmp(string, "getchallenge", 12) && (islocal || sv_public.integer > -2))
+               if (length >= 12 && !memcmp(string, "getchallenge", 12) && (islocal || sv_public.integer > -3))
                {
                        for (i = 0, best = 0, besttime = realtime;i < MAX_CHALLENGES;i++)
                        {
@@ -2639,7 +2648,7 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                        NetConn_WriteString(mysocket, va("\377\377\377\377challenge %s", challenge[i].string), peeraddress);
                        return true;
                }
-               if (length > 8 && !memcmp(string, "connect\\", 8) && (islocal || sv_public.integer > -2))
+               if (length > 8 && !memcmp(string, "connect\\", 8))
                {
                        string += 7;
                        length -= 7;
@@ -2655,6 +2664,14 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                        if (i == MAX_CHALLENGES)
                                return true;
 
+                       if(!(islocal || sv_public.integer > -2))
+                       {
+                               if (developer_extra.integer)
+                                       Con_Printf("Datagram_ParseConnectionless: sending \"reject %s\" to %s.\n", sv_public_rejectreason.string, addressstring2);
+                               NetConn_WriteString(mysocket, va("\377\377\377\377reject %s", sv_public_rejectreason.string), peeraddress);
+                               return true;
+                       }
+
                        // check engine protocol
                        if(!(s = SearchInfostring(string, "protocol")) || strcmp(s, "darkplaces 3"))
                        {
@@ -2855,8 +2872,20 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                case CCREQ_CONNECT:
                        if (developer_extra.integer)
                                Con_DPrintf("Datagram_ParseConnectionless: received CCREQ_CONNECT from %s.\n", addressstring2);
-                       if(!islocal && sv_public.integer <= -2)
+                       if(!(islocal || sv_public.integer > -2))
+                       {
+                               if (developer_extra.integer)
+                                       Con_DPrintf("Datagram_ParseConnectionless: sending CCREP_REJECT \"%s\" to %s.\n", sv_public_rejectreason.string, addressstring2);
+                               SZ_Clear(&net_message);
+                               // save space for the header, filled in later
+                               MSG_WriteLong(&net_message, 0);
+                               MSG_WriteByte(&net_message, CCREP_REJECT);
+                               MSG_WriteString(&net_message, va("%s\n", sv_public_rejectreason.string));
+                               StoreBigLong(net_message.data, NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
+                               NetConn_Write(mysocket, net_message.data, net_message.cursize, peeraddress);
+                               SZ_Clear(&net_message);
                                break;
+                       }
 
                        protocolname = MSG_ReadString();
                        protocolnumber = MSG_ReadByte();
@@ -2956,7 +2985,7 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                case CCREQ_SERVER_INFO:
                        if (developer_extra.integer)
                                Con_DPrintf("Datagram_ParseConnectionless: received CCREQ_SERVER_INFO from %s.\n", addressstring2);
-                       if(!islocal && sv_public.integer <= -1)
+                       if(!(islocal || sv_public.integer > -1))
                                break;
                        if (sv.active && !strcmp(MSG_ReadString(), "QUAKE"))
                        {
@@ -2987,7 +3016,7 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                case CCREQ_PLAYER_INFO:
                        if (developer_extra.integer)
                                Con_DPrintf("Datagram_ParseConnectionless: received CCREQ_PLAYER_INFO from %s.\n", addressstring2);
-                       if(!islocal && sv_public.integer <= -1)
+                       if(!(islocal || sv_public.integer > -1))
                                break;
                        if (sv.active)
                        {
@@ -3020,7 +3049,7 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                case CCREQ_RULE_INFO:
                        if (developer_extra.integer)
                                Con_DPrintf("Datagram_ParseConnectionless: received CCREQ_RULE_INFO from %s.\n", addressstring2);
-                       if(!islocal && sv_public.integer <= -1)
+                       if(!(islocal || sv_public.integer > -1))
                                break;
                        if (sv.active)
                        {
@@ -3360,6 +3389,7 @@ void NetConn_Init(void)
        Cvar_RegisterVariable(&net_address);
        Cvar_RegisterVariable(&net_address_ipv6);
        Cvar_RegisterVariable(&sv_public);
+       Cvar_RegisterVariable(&sv_public_rejectreason);
        Cvar_RegisterVariable(&sv_heartbeatperiod);
        for (i = 0;sv_masters[i].name;i++)
                Cvar_RegisterVariable(&sv_masters[i]);