summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--inc/shared/game.h1
-rw-r--r--src/server/ac.c2
-rw-r--r--src/server/main.c60
-rw-r--r--src/server/mvd.c12
4 files changed, 56 insertions, 19 deletions
diff --git a/inc/shared/game.h b/inc/shared/game.h
index c7cef58..5e5c779 100644
--- a/inc/shared/game.h
+++ b/inc/shared/game.h
@@ -52,6 +52,7 @@ typedef enum {
#define GMF_ENHANCED_SAVEGAMES 0x00000400
#define GMF_VARIABLE_FPS 0x00000800
#define GMF_EXTRA_USERINFO 0x00001000
+#define GMF_IPV6_ADDRESS_AWARE 0x00002000
//===============================================================
diff --git a/src/server/ac.c b/src/server/ac.c
index c50edb1..8bc6425 100644
--- a/src/server/ac.c
+++ b/src/server/ac.c
@@ -1112,7 +1112,7 @@ char *AC_ClientConnect(client_t *cl)
}
}
- if (ac.ready) {
+ if (ac.ready && net_from.type == NA_IP) {
MSG_WriteShort(15);
MSG_WriteByte(ACC_REQUESTCHALLENGE);
MSG_WriteData(net_from.ip.u8, 4);
diff --git a/src/server/main.c b/src/server/main.c
index aaf2321..468cd39 100644
--- a/src/server/main.c
+++ b/src/server/main.c
@@ -688,21 +688,34 @@ static qboolean permit_connection(conn_params_t *p)
if (sv_locked->integer)
return reject("Server is locked.\n");
- // limit number of connections from single IP
+ // link-local IPv6 addresses are permitted without sv_iplimit check
+ if (net_from.type == NA_IP6 && NET_IsLanAddress(&net_from))
+ return qtrue;
+
+ // limit number of connections from single IPv4 address or /48 IPv6 network
if (sv_iplimit->integer > 0) {
count = 0;
FOR_EACH_CLIENT(cl) {
- if (NET_IsEqualBaseAdr(&net_from, &cl->netchan->remote_address)) {
- if (cl->state == cs_zombie) {
- count++;
- } else {
- count += 2;
- }
- }
+ netadr_t *adr = &cl->netchan->remote_address;
+
+ if (net_from.type != adr->type)
+ continue;
+ if (net_from.type == NA_IP && net_from.ip.u32[0] != adr->ip.u32[0])
+ continue;
+ if (net_from.type == NA_IP6 && memcmp(net_from.ip.u8, adr->ip.u8, 48 / CHAR_BIT))
+ continue;
+
+ if (cl->state == cs_zombie)
+ count += 1;
+ else
+ count += 2;
+ }
+ if (count / 2 >= sv_iplimit->integer) {
+ if (net_from.type == NA_IP6)
+ return reject("Too many connections from your IPv6 network.\n");
+ else
+ return reject("Too many connections from your IP address.\n");
}
- count >>= 1;
- if (count >= sv_iplimit->integer)
- return reject("Too many connections from your IP address.\n");
}
return qtrue;
@@ -794,6 +807,26 @@ static qboolean parse_enhanced_params(conn_params_t *p)
return qtrue;
}
+static char *userinfo_ip_string(void)
+{
+ static char s[MAX_QPATH];
+
+ // fake up reserved IPv4 address to prevent IPv6 unaware mods from exploding
+ if (net_from.type == NA_IP6 && !(g_features->integer & GMF_IPV6_ADDRESS_AWARE)) {
+ uint8_t res = 0;
+ int i;
+
+ // stuff /48 network part into the last byte
+ for (i = 0; i < 48 / CHAR_BIT; i++)
+ res ^= net_from.ip.u8[i];
+
+ Q_snprintf(s, sizeof(s), "198.51.100.%u:%u", res, BigShort(net_from.port));
+ return s;
+ }
+
+ return NET_AdrToString(&net_from);
+}
+
static qboolean parse_userinfo(conn_params_t *params, char *userinfo)
{
char *info, *s;
@@ -848,8 +881,7 @@ static qboolean parse_userinfo(conn_params_t *params, char *userinfo)
}
// force the IP key/value pair so the game can filter based on ip
- s = NET_AdrToString(&net_from);
- if (!Info_SetValueForKey(userinfo, "ip", s))
+ if (!Info_SetValueForKey(userinfo, "ip", userinfo_ip_string()))
return reject("Oversize userinfo string.\n");
}
@@ -1005,7 +1037,7 @@ static void append_extra_userinfo(conn_params_t *params, char *userinfo)
"\\challenge\\%d\\ip\\%s"
"\\major\\%d\\minor\\%d\\netchan\\%d"
"\\packetlen\\%d\\qport\\%d\\zlib\\%d",
- params->challenge, NET_AdrToString(&net_from),
+ params->challenge, userinfo_ip_string(),
params->protocol, params->version, params->nctype,
params->maxlength, params->qport, params->has_zlib);
}
diff --git a/src/server/mvd.c b/src/server/mvd.c
index da0ecee..1e7d973 100644
--- a/src/server/mvd.c
+++ b/src/server/mvd.c
@@ -1730,14 +1730,18 @@ static void accept_client(netstream_t *stream)
gtv_client_t *client;
netstream_t *s;
- // limit number of connections from single IP
+ // limit number of connections from single IPv4 address or /48 IPv6 network
if (sv_iplimit->integer > 0) {
int count = 0;
FOR_EACH_GTV(client) {
- if (NET_IsEqualBaseAdr(&client->stream.address, &stream->address)) {
- count++;
- }
+ if (stream->address.type != client->stream.address.type)
+ continue;
+ if (stream->address.type == NA_IP && stream->address.ip.u32[0] != client->stream.address.ip.u32[0])
+ continue;
+ if (stream->address.type == NA_IP6 && memcmp(stream->address.ip.u8, client->stream.address.ip.u8, 48 / CHAR_BIT))
+ continue;
+ count++;
}
if (count >= sv_iplimit->integer) {
Com_Printf("TCP client [%s] rejected: too many connections\n",