NQ: Try to improve compat with proxies/port-forwarding and proquake's numeric-only passwords.
This commit is contained in:
parent
bb9f7eb51a
commit
11a5b27689
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue