diff options
author | Andrey Nazarov <skuller@skuller.net> | 2014-01-02 17:34:35 +0400 |
---|---|---|
committer | Andrey Nazarov <skuller@skuller.net> | 2014-12-01 23:03:15 +0300 |
commit | f0ec1cdcae487fa6d3d4154a18ed47f0edb34d61 (patch) | |
tree | f88cf7556598a8040f32f1459f4fe2167ed2eed4 | |
parent | 98888c2720e87cb7ce8cd738b9f806ee7c922d2d (diff) |
Prepare address matching code for IPv6.
-rw-r--r-- | inc/common/net/net.h | 63 | ||||
-rw-r--r-- | src/common/net/net.c | 4 | ||||
-rw-r--r-- | src/server/commands.c | 97 | ||||
-rw-r--r-- | src/server/main.c | 2 | ||||
-rw-r--r-- | src/server/server.h | 4 |
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]; |