NQ: Try to improve compat with proxies/port-forwarding and proquake's numeric-only passwords.

This commit is contained in:
Shpoike 2023-08-08 19:28:53 +01:00
parent bb9f7eb51a
commit 11a5b27689
4 changed files with 79 additions and 24 deletions

View file

@ -1347,6 +1347,8 @@ void CL_CheckForResend (void)
#ifdef NQPROT
if ((contype & 2) && !connectinfo.clogged)
{
char *e;
int pwd;
sizebuf_t sb;
memset(&sb, 0, sizeof(sb));
sb.data = data;
@ -1366,11 +1368,18 @@ void CL_CheckForResend (void)
which means it corrects for our public port if our nat uses different public ports for different remote ports
thus all nq engines claim to be proquake
*/
if (!*password.string || !strcmp(password.string, "none"))
pwd = 0;
else
{
pwd = strtol(password.string, &e, 0);
if (*e)
pwd = CalcHashInt(&hash_md4, password.string, strlen(password.string));
}
MSG_WriteByte(&sb, 1); /*'mod'*/
MSG_WriteByte(&sb, 34); /*'mod' version*/
MSG_WriteByte(&sb, 0); /*flags*/
MSG_WriteLong(&sb, strtoul(password.string, NULL, 0)); /*password*/
MSG_WriteLong(&sb, pwd); /*password*/
/*FTE servers will detect this string and treat it as a qw challenge instead (if it allows qw clients), so protocol choice is deterministic*/
if (contype & 1)
@ -4370,31 +4379,36 @@ void CLNQ_ConnectionlessPacket(void)
}
else
{
port = htons((unsigned short)MSG_ReadLong());
//this is the port that we're meant to respond to.
port = htons((unsigned short)MSG_ReadLong()); //this is the port that we're meant to respond to...
if (msg_badread) //qe has no port specified. and that's fine when its over dtls anyway.
port = 0;
if (port && !msg_badread)
{
char buf[256];
net_from.port = port;
Con_DPrintf("redirecting to port %s\n", NET_AdrToString(buf, sizeof(buf), &net_from));
}
cls.proquake_angles_hack = false;
cls.protocol_nq = CPNQ_ID;
if (MSG_ReadByte() == 1) //a proquake server adds a little extra info
{
int ver = MSG_ReadByte();
int flags = MSG_ReadByte();
Con_DPrintf("ProQuake server %i.%i\n", ver/10, ver%10);
// if (ver >= 34)
cls.proquake_angles_hack = true;
if (MSG_ReadByte() == 1)
if (flags & 1)
{
//its a 'pure' server.
Con_Printf("pure ProQuake server\n");
return;
}
if (flags & 0x80)
port = 0; //don't force the port.
}
if (port && port != net_from.port)
{
char buf[256];
net_from.port = port;
Con_Printf("redirecting to port %s\n", NET_AdrToString(buf, sizeof(buf), &net_from));
}
}

View file

@ -1129,6 +1129,7 @@ const char *SV_CheckRejectConnection(netadr_t *adr, const char *uinfo, unsigned
char *SV_BannedReason (netadr_t *a);
void SV_EvaluatePenalties(client_t *cl);
void SV_AutoAddPenalty (client_t *cl, unsigned int banflag, int duration, char *reason);
void SV_AutoBanSender (int duration, char *reason); //bans net_from
//note: not all penalties are actually penalties, but they can still expire.
#define BAN_BAN (1u<<0) //user is banned from the server

View file

@ -1916,6 +1916,19 @@ void SV_AutoAddPenalty (client_t *cl, unsigned int banflag, int duration, char *
SV_AddBanEntry(&proto, reason);
SV_EvaluatePenalties(cl);
}
void SV_AutoBanSender (int duration, char *reason)
{
bannedips_t proto;
proto.banflags = BAN_BAN;
proto.expiretime = SV_BanTime() + duration;
memset(&proto.adrmask.address, 0xff, sizeof(proto.adrmask.address));
proto.adr = net_from;
proto.adr.port = 0;
proto.adrmask.type = proto.adr.type;
SV_AddBanEntry(&proto, reason);
}
static void SV_WriteIP_f (void)
{

View file

@ -2668,15 +2668,33 @@ void SV_DoDirectConnect(svconnectinfo_t *fte_restrict info)
}
else
{
s = Info_ValueForKey (info->userinfo, "password");
if (password.string[0] &&
stricmp(password.string, "none") &&
strcmp(password.string, s) &&
!NET_IsLoopBackAddress(&info->adr))
if (!password.string[0] ||
!stricmp(password.string, "none") ||
NET_IsLoopBackAddress(&info->adr))
; //don't care, doesn't matter.
else if (info->protocol == SCP_NETQUAKE)
{ //if its a proquake client then use numeric passwords, which take a bit of processing
char *e;
int got = strtol(Info_ValueForKey (info->userinfo, "password"), NULL, 0);
int need = strtol(password.string, &e, 0);
if (*e)
need = CalcHashInt(&hash_md4, password.string, strlen(password.string));
if (got != need)
{
Con_TPrintf ("%s:password failed\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &info->adr));
SV_RejectMessage (info->protocol, "server requires a password\n\n");
return;
}
}
else
{
Con_TPrintf ("%s:password failed\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &info->adr));
SV_RejectMessage (info->protocol, "server requires a password\n\n");
return;
s = Info_ValueForKey (info->userinfo, "password");
if (strcmp(password.string, s))
{
Con_TPrintf ("%s:password failed\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &info->adr));
SV_RejectMessage (info->protocol, "server requires a password\n\n");
return;
}
}
spectator = false;
Info_RemoveKey (info->userinfo, "password"); // remove passwd
@ -4594,12 +4612,21 @@ qboolean SVNQ_ConnectionlessPacket(void)
)
{
if (password.string[0] &&
stricmp(password.string, "none") &&
strcmp(password.string, va("%i", passwd)) )
stricmp(password.string, "none"))
{ //make sure we don't get crippled because of being unable to specify the actual password with proquake's stuff.
Con_TPrintf ("%s:password failed (nq)\n", NET_AdrToString (buffer2, sizeof(buffer2), &net_from));
SV_RejectMessage (SCP_NETQUAKE, "server requires a password\n\n");
return true;
char *e;
intmax_t svpass = strtoll(password.string, &e, 0);
if (*e) //something ain't numeric... hash it so they have a chance of getting it right...
svpass = CalcHashInt(&hash_md4, password.string, strlen(password.string));
if (passwd != svpass)
{
Con_TPrintf ("%s:password failed (nq)\n", NET_AdrToString (buffer2, sizeof(buffer2), &net_from));
SV_RejectMessage (SCP_NETQUAKE, "\x01this server requires a password\n\n");
//and prevent them from spamming attempts. botnets might still get through fast though.
SV_AutoBanSender(15, "password cooldown");
return true;
}
}
SZ_Clear(&sb);