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 [] =
{
{0, "sv_qwmasterextra2", "asgaard.morphos-team.net:27000", "Global master server. (admin: unknown)"},
{0, "sv_qwmasterextra3", "qwmaster.ocrana.de:27000", "German master server. (admin: unknown)"},
{0, "sv_qwmasterextra4", "masterserver.exhale.de:27000", "German master server. (admin: unknown)"},
- {0, "sv_qwmasterextra5", "kubus.rulez.pl:27000", "Poland master server. (admin: unknown)"},
+ {0, "sv_qwmasterextra5", "qwmaster.fodquake.net:27000", "Global master server. (admin: unknown)"},
{0, NULL, NULL, NULL}
};
!(
gameversion_min.integer >= 0 // min/max range set by user/mod?
&& gameversion_max.integer >= 0
- && gameversion_min.integer >= entry->info.gameversion // version of server in min/max range?
- && gameversion_max.integer <= entry->info.gameversion
+ && gameversion_min.integer <= entry->info.gameversion // version of server in min/max range?
+ && gameversion_max.integer >= entry->info.gameversion
)
)
return;
!(
gameversion_min.integer >= 0 // min/max range set by user/mod?
&& gameversion_max.integer >= 0
- && gameversion_min.integer >= info->gameversion // version of server in min/max range?
- && gameversion_max.integer <= info->gameversion
+ && gameversion_min.integer <= info->gameversion // version of server in min/max range?
+ && gameversion_max.integer >= info->gameversion
)
) ? '1' : '4',
info->mod, info->map);
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);
int length;
char teambuf[3];
const char *crypto_idstring;
+ const char *str;
SV_VM_Begin();
}
*qcstatus = 0;
- if(prog->globaloffsets.worldstatus >= 0)
+ str = PRVM_GetString(PRVM_serverglobalstring(worldstatus));
+ if(str && *str)
{
- const char *str = PRVM_G_STRING(prog->globaloffsets.worldstatus);
- if(str && *str)
- {
- char *p;
- const char *q;
- p = qcstatus;
- for(q = str; *q && p - qcstatus < (ptrdiff_t)(sizeof(qcstatus)) - 1; ++q)
- if(*q != '\\' && *q != '\n')
- *p++ = *q;
- *p = 0;
- }
+ char *p;
+ const char *q;
+ p = qcstatus;
+ for(q = str; *q && (size_t)(p - qcstatus) < (sizeof(qcstatus) - 1); ++q)
+ if(*q != '\\' && *q != '\n')
+ *p++ = *q;
+ *p = 0;
}
/// \TODO: we should add more information for the full status string
int nameind, cleanind, pingvalue;
char curchar;
char cleanname [sizeof(cl->name)];
+ const char *str;
+ prvm_edict_t *ed;
// Remove all characters '"' and '\' in the player name
nameind = 0;
pingvalue = 0;
*qcstatus = 0;
- if(prog->fieldoffsets.clientstatus >= 0)
+ ed = PRVM_EDICT_NUM(i + 1);
+ str = PRVM_GetString(PRVM_serveredictstring(ed, clientstatus));
+ if(str && *str)
{
- const char *str = PRVM_E_STRING(PRVM_EDICT_NUM(i + 1), prog->fieldoffsets.clientstatus);
- if(str && *str)
- {
- char *p;
- const char *q;
- p = qcstatus;
- for(q = str; *q && p != qcstatus + sizeof(qcstatus) - 1; ++q)
- if(*q != '\\' && *q != '"' && !ISWHITESPACE(*q))
- *p++ = *q;
- *p = 0;
- }
+ char *p;
+ const char *q;
+ p = qcstatus;
+ for(q = str; *q && p != qcstatus + sizeof(qcstatus) - 1; ++q)
+ if(*q != '\\' && *q != '"' && !ISWHITESPACE(*q))
+ *p++ = *q;
+ *p = 0;
}
if ((gamemode == GAME_NEXUIZ || gamemode == GAME_XONOTIC) && (teamplay.integer > 0))
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;
}