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 #ifdef NQPROT
if ((contype & 2) && !connectinfo.clogged) if ((contype & 2) && !connectinfo.clogged)
{ {
char *e;
int pwd;
sizebuf_t sb; sizebuf_t sb;
memset(&sb, 0, sizeof(sb)); memset(&sb, 0, sizeof(sb));
sb.data = data; 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 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 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, 1); /*'mod'*/
MSG_WriteByte(&sb, 34); /*'mod' version*/ MSG_WriteByte(&sb, 34); /*'mod' version*/
MSG_WriteByte(&sb, 0); /*flags*/ 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*/ /*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) if (contype & 1)
@ -4370,31 +4379,36 @@ void CLNQ_ConnectionlessPacket(void)
} }
else else
{ {
port = htons((unsigned short)MSG_ReadLong()); port = htons((unsigned short)MSG_ReadLong()); //this is the port that we're meant to respond to...
//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.proquake_angles_hack = false;
cls.protocol_nq = CPNQ_ID; cls.protocol_nq = CPNQ_ID;
if (MSG_ReadByte() == 1) //a proquake server adds a little extra info if (MSG_ReadByte() == 1) //a proquake server adds a little extra info
{ {
int ver = MSG_ReadByte(); int ver = MSG_ReadByte();
int flags = MSG_ReadByte();
Con_DPrintf("ProQuake server %i.%i\n", ver/10, ver%10); Con_DPrintf("ProQuake server %i.%i\n", ver/10, ver%10);
// if (ver >= 34) // if (ver >= 34)
cls.proquake_angles_hack = true; cls.proquake_angles_hack = true;
if (MSG_ReadByte() == 1) if (flags & 1)
{ {
//its a 'pure' server. //its a 'pure' server.
Con_Printf("pure ProQuake server\n"); Con_Printf("pure ProQuake server\n");
return; 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); char *SV_BannedReason (netadr_t *a);
void SV_EvaluatePenalties(client_t *cl); void SV_EvaluatePenalties(client_t *cl);
void SV_AutoAddPenalty (client_t *cl, unsigned int banflag, int duration, char *reason); 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. //note: not all penalties are actually penalties, but they can still expire.
#define BAN_BAN (1u<<0) //user is banned from the server #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_AddBanEntry(&proto, reason);
SV_EvaluatePenalties(cl); 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) static void SV_WriteIP_f (void)
{ {

View File

@ -2668,15 +2668,33 @@ void SV_DoDirectConnect(svconnectinfo_t *fte_restrict info)
} }
else else
{ {
s = Info_ValueForKey (info->userinfo, "password"); if (!password.string[0] ||
if (password.string[0] && !stricmp(password.string, "none") ||
stricmp(password.string, "none") && NET_IsLoopBackAddress(&info->adr))
strcmp(password.string, s) && ; //don't care, doesn't matter.
!NET_IsLoopBackAddress(&info->adr)) 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)); s = Info_ValueForKey (info->userinfo, "password");
SV_RejectMessage (info->protocol, "server requires a password\n\n"); if (strcmp(password.string, s))
return; {
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; spectator = false;
Info_RemoveKey (info->userinfo, "password"); // remove passwd Info_RemoveKey (info->userinfo, "password"); // remove passwd
@ -4594,12 +4612,21 @@ qboolean SVNQ_ConnectionlessPacket(void)
) )
{ {
if (password.string[0] && if (password.string[0] &&
stricmp(password.string, "none") && stricmp(password.string, "none"))
strcmp(password.string, va("%i", passwd)) )
{ //make sure we don't get crippled because of being unable to specify the actual password with proquake's stuff. { //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)); char *e;
SV_RejectMessage (SCP_NETQUAKE, "server requires a password\n\n"); intmax_t svpass = strtoll(password.string, &e, 0);
return true; 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); SZ_Clear(&sb);