summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Nazarov <skuller@skuller.net>2014-01-02 17:34:35 +0400
committerAndrey Nazarov <skuller@skuller.net>2014-12-01 23:03:15 +0300
commitf0ec1cdcae487fa6d3d4154a18ed47f0edb34d61 (patch)
treef88cf7556598a8040f32f1459f4fe2167ed2eed4
parent98888c2720e87cb7ce8cd738b9f806ee7c922d2d (diff)
Prepare address matching code for IPv6.
-rw-r--r--inc/common/net/net.h63
-rw-r--r--src/common/net/net.c4
-rw-r--r--src/server/commands.c97
-rw-r--r--src/server/main.c2
-rw-r--r--src/server/server.h4
5 files changed, 123 insertions, 47 deletions
diff --git a/inc/common/net/net.h b/inc/common/net/net.h
index 187487b..d687120 100644
--- a/inc/common/net/net.h
+++ b/inc/common/net/net.h
@@ -65,7 +65,8 @@ typedef enum {
NA_BAD,
NA_LOOPBACK,
NA_BROADCAST,
- NA_IP
+ NA_IP,
+ NA_IP6
} netadrtype_t;
typedef enum {
@@ -81,9 +82,10 @@ typedef enum {
} netflag_t;
typedef union {
- uint8_t u8[4];
- uint16_t u16[2];
- uint32_t u32;
+ uint8_t u8[16];
+ uint16_t u16[8];
+ uint32_t u32[4];
+ uint64_t u64[2];
} netadrip_t;
typedef struct netadr_s {
@@ -119,10 +121,15 @@ static inline qboolean NET_IsEqualAdr(const netadr_t *a, const netadr_t *b)
return qtrue;
case NA_IP:
case NA_BROADCAST:
- if (a->ip.u32 == b->ip.u32 && a->port == b->port) {
+ if (a->ip.u32[0] == b->ip.u32[0] && a->port == b->port) {
return qtrue;
}
- // fall through
+ return qfalse;
+ case NA_IP6:
+ if (memcmp(a->ip.u8, b->ip.u8, 16) == 0 && a->port == b->port) {
+ return qtrue;
+ }
+ return qfalse;
default:
break;
}
@@ -141,10 +148,43 @@ static inline qboolean NET_IsEqualBaseAdr(const netadr_t *a, const netadr_t *b)
return qtrue;
case NA_IP:
case NA_BROADCAST:
- if (a->ip.u32 == b->ip.u32) {
+ if (a->ip.u32[0] == b->ip.u32[0]) {
+ return qtrue;
+ }
+ return qfalse;
+ case NA_IP6:
+ if (memcmp(a->ip.u8, b->ip.u8, 16) == 0) {
return qtrue;
}
- // fall through
+ return qfalse;
+ default:
+ break;
+ }
+
+ return qfalse;
+}
+
+static inline qboolean NET_IsEqualBaseAdrMask(const netadr_t *a,
+ const netadr_t *b,
+ const netadr_t *m)
+{
+ if (a->type != b->type) {
+ return qfalse;
+ }
+
+ switch (a->type) {
+ case NA_IP:
+ return !((a->ip.u32[0] ^ b->ip.u32[0]) & m->ip.u32[0]);
+ case NA_IP6:
+#if (defined __amd64__) || (defined _M_AMD64)
+ return !(((a->ip.u64[0] ^ b->ip.u64[0]) & m->ip.u64[0]) |
+ ((a->ip.u64[1] ^ b->ip.u64[1]) & m->ip.u64[1]));
+#else
+ return !(((a->ip.u32[0] ^ b->ip.u32[0]) & m->ip.u32[0]) |
+ ((a->ip.u32[1] ^ b->ip.u32[1]) & m->ip.u32[1]) |
+ ((a->ip.u32[2] ^ b->ip.u32[2]) & m->ip.u32[2]) |
+ ((a->ip.u32[3] ^ b->ip.u32[3]) & m->ip.u32[3]));
+#endif
default:
break;
}
@@ -166,7 +206,12 @@ static inline qboolean NET_IsLanAddress(const netadr_t *adr)
adr->ip.u16[0] == MakeRawShort(172, 16)) {
return qtrue;
}
- // fall through
+ return qfalse;
+ case NA_IP6:
+ if (adr->ip.u8[0] == 0xfe && (adr->ip.u8[1] & 0xc0) == 0x80) {
+ return qtrue;
+ }
+ return qfalse;
default:
break;
}
diff --git a/src/common/net/net.c b/src/common/net/net.c
index 10e3763..a0b1746 100644
--- a/src/common/net/net.c
+++ b/src/common/net/net.c
@@ -148,7 +148,7 @@ static void NET_NetadrToSockadr(const netadr_t *a, struct sockaddr_in *s)
break;
case NA_IP:
s->sin_family = AF_INET;
- s->sin_addr.s_addr = a->ip.u32;
+ s->sin_addr.s_addr = a->ip.u32[0];
s->sin_port = a->port;
break;
default:
@@ -162,7 +162,7 @@ static void NET_SockadrToNetadr(const struct sockaddr_in *s, netadr_t *a)
memset(a, 0, sizeof(*a));
a->type = NA_IP;
- a->ip.u32 = s->sin_addr.s_addr;
+ a->ip.u32[0] = s->sin_addr.s_addr;
a->port = s->sin_port;
}
diff --git a/src/server/commands.c b/src/server/commands.c
index 457f5b5..09a7990 100644
--- a/src/server/commands.c
+++ b/src/server/commands.c
@@ -452,6 +452,8 @@ static void SV_DumpEnts_f(void)
//===============================================================
+static void make_mask(netadr_t *mask, netadrtype_t type, int bits);
+
/*
==================
SV_Kick_f
@@ -480,10 +482,10 @@ static void SV_Kick_f(void)
// optionally ban their IP address
if (!strcmp(Cmd_Argv(0), "kickban")) {
netadr_t *addr = &sv_client->netchan->remote_address;
- if (addr->type == NA_IP) {
+ if (addr->type == NA_IP || addr->type == NA_IP6) {
addrmatch_t *match = Z_Malloc(sizeof(*match));
- match->addr.u32 = addr->ip.u32;
- match->mask = 0xffffffffU;
+ match->addr = *addr;
+ make_mask(&match->mask, addr->type, addr->type == NA_IP6 ? 128 : 32);
match->hits = 0;
match->time = 0;
match->comment[0] = 0;
@@ -988,15 +990,20 @@ static void SV_ServerCommand_f(void)
ge->ServerCommand();
}
-// (ip & mask) == (addr & mask)
-// bits = 32 --> mask = 255.255.255.255
-// bits = 24 --> mask = 255.255.255.0
+static void make_mask(netadr_t *mask, netadrtype_t type, int bits)
+{
+ memset(mask, 0, sizeof(*mask));
+ mask->type = type;
+ memset(mask->ip.u8, 0xff, bits >> 3);
+ if (bits & 7) {
+ mask->ip.u8[bits >> 3] = ~((1 << (8 - (bits & 7))) - 1);
+ }
+}
-static qboolean parse_mask(const char *s, uint32_t *addr, uint32_t *mask)
+static qboolean parse_mask(char *s, netadr_t *addr, netadr_t *mask)
{
- netadr_t address;
+ int bits, size;
char *p;
- int bits;
p = strchr(s, '/');
if (p) {
@@ -1006,45 +1013,67 @@ static qboolean parse_mask(const char *s, uint32_t *addr, uint32_t *mask)
return qfalse;
}
bits = atoi(p);
- if (bits < 1 || bits > 32) {
- Com_Printf("Bad mask: %d bits\n", bits);
- return qfalse;
- }
} else {
- bits = 32;
+ bits = -1;
}
- if (!NET_StringToAdr(s, &address, 0)) {
+ if (!NET_StringToBaseAdr(s, addr)) {
Com_Printf("Bad address: %s\n", s);
return qfalse;
}
- *addr = address.ip.u32;
- *mask = BigLong(~((1 << (32 - bits)) - 1));
+ size = (addr->type == NA_IP6) ? 128 : 32;
+
+ if (bits == -1) {
+ bits = size;
+ }
+
+ if (bits < 1 || bits > size) {
+ Com_Printf("Bad mask: %d bits\n", bits);
+ return qfalse;
+ }
+
+ make_mask(mask, addr->type, bits);
return qtrue;
}
-static size_t format_mask(addrmatch_t *match, char *buf, size_t size)
+static size_t format_mask(addrmatch_t *match, char *buf, size_t buf_size)
{
- uint8_t *ip = match->addr.u8;
- uint32_t mask = BigLong(match->mask);
- int i;
+ int i, j, bits, size;
+
+ size = (match->mask.type == NA_IP6) ? 128 : 32;
+ bits = 0;
+
+ for (i = 0; i < size >> 3; i++) {
+ int c = match->mask.ip.u8[i];
+
+ if (c == 0xff) {
+ bits += 8;
+ continue;
+ }
- for (i = 0; i < 32; i++) {
- if (mask & (1 << i)) {
+ if (c == 0) {
break;
}
+
+ for (j = 0; j < 8; j++) {
+ if (!(c & (1 << (7 - j)))) {
+ break;
+ }
+ }
+
+ bits += j;
+ break;
}
- return Q_snprintf(buf, size, "%d.%d.%d.%d/%d",
- ip[0], ip[1], ip[2], ip[3], 32 - i);
+ return Q_snprintf(buf, buf_size, "%s/%d", NET_BaseAdrToString(&match->addr), bits);
}
void SV_AddMatch_f(list_t *list)
{
- char *s, buf[32];
+ char *s, buf[MAX_QPATH];
addrmatch_t *match;
- uint32_t addr, mask;
+ netadr_t addr, mask;
size_t len;
if (Cmd_Argc() < 2) {
@@ -1058,7 +1087,8 @@ void SV_AddMatch_f(list_t *list)
}
LIST_FOR_EACH(addrmatch_t, match, list, entry) {
- if (match->addr.u32 == addr && match->mask == mask) {
+ if (NET_IsEqualBaseAdr(&match->addr, &addr) &&
+ NET_IsEqualBaseAdr(&match->mask, &mask)) {
format_mask(match, buf, sizeof(buf));
Com_Printf("Entry %s already exists.\n", buf);
return;
@@ -1068,7 +1098,7 @@ void SV_AddMatch_f(list_t *list)
s = Cmd_ArgsFrom(2);
len = strlen(s);
match = Z_Malloc(sizeof(*match) + len);
- match->addr.u32 = addr;
+ match->addr = addr;
match->mask = mask;
match->hits = 0;
match->time = 0;
@@ -1080,7 +1110,7 @@ void SV_DelMatch_f(list_t *list)
{
char *s;
addrmatch_t *match, *next;
- uint32_t addr, mask;
+ netadr_t addr, mask;
int i;
if (Cmd_Argc() < 2) {
@@ -1122,7 +1152,8 @@ void SV_DelMatch_f(list_t *list)
}
LIST_FOR_EACH(addrmatch_t, match, list, entry) {
- if (match->addr.u32 == addr && match->mask == mask) {
+ if (NET_IsEqualBaseAdr(&match->addr, &addr) &&
+ NET_IsEqualBaseAdr(&match->mask, &mask)) {
remove:
List_Remove(&match->entry);
Z_Free(match);
@@ -1135,8 +1166,8 @@ remove:
void SV_ListMatches_f(list_t *list)
{
addrmatch_t *match;
- char last[32];
- char addr[32];
+ char last[MAX_QPATH];
+ char addr[MAX_QPATH];
int count;
if (LIST_EMPTY(list)) {
diff --git a/src/server/main.c b/src/server/main.c
index 0383779..aaf2321 100644
--- a/src/server/main.c
+++ b/src/server/main.c
@@ -366,7 +366,7 @@ addrmatch_t *SV_MatchAddress(list_t *list, netadr_t *addr)
addrmatch_t *match;
LIST_FOR_EACH(addrmatch_t, match, list, entry) {
- if ((addr->ip.u32 & match->mask) == (match->addr.u32 & match->mask)) {
+ if (NET_IsEqualBaseAdrMask(addr, &match->addr, &match->mask)) {
match->hits++;
match->time = time(NULL);
return match;
diff --git a/src/server/server.h b/src/server/server.h
index 1f9535d..0919e07 100644
--- a/src/server/server.h
+++ b/src/server/server.h
@@ -393,8 +393,8 @@ typedef struct {
typedef struct {
list_t entry;
- netadrip_t addr;
- uint32_t mask;
+ netadr_t addr;
+ netadr_t mask;
unsigned hits;
time_t time; // time of the last hit
char comment[1];