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)"};
+extern cvar_t sv_status_privacy;
static cvar_t sv_masters [] =
{
lhnetaddress_t clientportaddress;
clientportaddress = *peeraddress;
LHNETADDRESS_SetPort(&clientportaddress, MSG_ReadLong());
+ // extra ProQuake stuff
+ if (length >= 6)
+ cls.proquake_servermod = MSG_ReadByte(); // MOD_PROQUAKE
+ else
+ cls.proquake_servermod = 0;
+ if (length >= 7)
+ cls.proquake_serverversion = MSG_ReadByte(); // version * 10
+ else
+ cls.proquake_serverversion = 0;
+ if (length >= 8)
+ cls.proquake_serverflags = MSG_ReadByte(); // flags (mainly PQF_CHEATFREE)
+ else
+ cls.proquake_serverflags = 0;
+ if (cls.proquake_servermod == 1)
+ Con_Printf("Connected to ProQuake %.1f server, enabling precise aim\n", cls.proquake_serverversion / 10.0f);
// 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);
M_Update_Return_Reason("Accepted");
MSG_WriteByte(&net_message, CCREQ_CONNECT);
MSG_WriteString(&net_message, "QUAKE");
MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
+ // extended proquake stuff
+ MSG_WriteByte(&net_message, 1); // mod = MOD_PROQUAKE
+ // this version matches ProQuake 3.40, the first version to support
+ // the NAT fix, and it only supports the NAT fix for ProQuake 3.40 or
+ // higher clients, so we pretend we are that version...
+ MSG_WriteByte(&net_message, 34); // version * 10
+ MSG_WriteByte(&net_message, 0); // flags
+ MSG_WriteLong(&net_message, 0); // password
+ // write the packetsize now...
StoreBigLong(net_message.data, NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
NetConn_Write(cls.connect_mysocket, net_message.data, net_message.cursize, &cls.connect_address);
SZ_Clear(&net_message);
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)
+void RCon_Execute(lhnetsocket_t *mysocket, lhnetaddress_t *peeraddress, const char *addressstring2, const char *userlevel, const char *s, const char *endpos, qboolean proquakeprotocol)
{
if(userlevel)
{
Con_Printf("\n");
if (!host_client || !host_client->netconnection || LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) != LHNETADDRESSTYPE_LOOP)
- Con_Rcon_Redirect_Init(mysocket, peeraddress);
+ Con_Rcon_Redirect_Init(mysocket, peeraddress, proquakeprotocol);
while(s != endpos)
{
size_t l = strlen(s);
++s;
userlevel = RCon_Authenticate(peeraddress, password, s, endpos, hmac_mdfour_time_matching, timeval, endpos - timeval - 1); // not including the appended \0 into the HMAC
- RCon_Execute(mysocket, peeraddress, addressstring2, userlevel, s, endpos);
+ RCon_Execute(mysocket, peeraddress, addressstring2, userlevel, s, endpos, false);
return true;
}
if (length >= 42 && !memcmp(string, "srcon HMAC-MD4 CHALLENGE ", 25))
++s;
userlevel = RCon_Authenticate(peeraddress, password, s, endpos, hmac_mdfour_challenge_matching, challenge, endpos - challenge - 1); // not including the appended \0 into the HMAC
- RCon_Execute(mysocket, peeraddress, addressstring2, userlevel, s, endpos);
+ RCon_Execute(mysocket, peeraddress, addressstring2, userlevel, s, endpos, false);
return true;
}
if (length >= 5 && !memcmp(string, "rcon ", 5))
if (!ISWHITESPACE(password[0]))
{
const char *userlevel = RCon_Authenticate(peeraddress, password, s, endpos, plaintext_matching, NULL, 0);
- RCon_Execute(mysocket, peeraddress, addressstring2, userlevel, s, endpos);
+ RCon_Execute(mysocket, peeraddress, addressstring2, userlevel, s, endpos, false);
}
return true;
}
MSG_WriteLong(&net_message, client->colors);
MSG_WriteLong(&net_message, client->frags);
MSG_WriteLong(&net_message, (int)(realtime - client->connecttime));
- MSG_WriteString(&net_message, client->netconnection ? client->netconnection->address : "botclient");
+ if(sv_status_privacy.integer)
+ MSG_WriteString(&net_message, client->netconnection ? "hidden" : "botclient");
+ else
+ MSG_WriteString(&net_message, client->netconnection ? client->netconnection->address : "botclient");
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);
SZ_Clear(&net_message);
}
break;
+ case CCREQ_RCON:
+ if (developer_extra.integer)
+ Con_DPrintf("Datagram_ParseConnectionless: received CCREQ_RCON from %s.\n", addressstring2);
+ if (sv.active && !rcon_secure.integer)
+ {
+ char password[2048];
+ char cmd[2048];
+ char *s;
+ char *endpos;
+ const char *userlevel;
+ strlcpy(password, MSG_ReadString(), sizeof(password));
+ strlcpy(cmd, MSG_ReadString(), sizeof(cmd));
+ s = cmd;
+ endpos = cmd + strlen(cmd) + 1; // one behind the NUL, so adding strlen+1 will eventually reach it
+ userlevel = RCon_Authenticate(peeraddress, password, s, endpos, plaintext_matching, NULL, 0);
+ RCon_Execute(mysocket, peeraddress, addressstring2, userlevel, s, endpos, true);
+ return true;
+ }
+ break;
default:
break;
}