diff --git a/qw/source/sv_ccmds.c b/qw/source/sv_ccmds.c index de8ac6751..745dbb603 100644 --- a/qw/source/sv_ccmds.c +++ b/qw/source/sv_ccmds.c @@ -738,7 +738,7 @@ SV_Ban_f (void) continue; if (cl->userid == uid) { SV_BroadcastPrintf (PRINT_HIGH, "Admin Banned user %s %s\n", - cl->name, mins ? va("for %.1f minutes",mins) + cl->name, mins ? va("for %.1f minutes", mins) : "permanently"); SV_DropClient (cl); Cmd_ExecuteString ( diff --git a/qw/source/sv_main.c b/qw/source/sv_main.c index 79a74ff69..e4e01ee2d 100644 --- a/qw/source/sv_main.c +++ b/qw/source/sv_main.c @@ -35,6 +35,9 @@ #ifdef HAVE_STRINGS_H # include #endif +#ifdef HAVE_ARPA_INET_H +# include +#endif #include #include @@ -1073,9 +1076,14 @@ SV_ConnectionlessPacket (void) */ typedef struct { - unsigned int mask; - unsigned int compare; - double time; + int mask; +#ifdef HAVE_IPV6 + byte ip[16]; +#else + byte ip[4]; +#endif + double time; + filtertype_t type; } ipfilter_t; #define MAX_IPFILTERS 1024 @@ -1083,63 +1091,216 @@ typedef struct { cvar_t *filterban; int numipfilters; ipfilter_t ipfilters[MAX_IPFILTERS]; -filtertype_t filttypes[MAX_IPFILTERS]; +unsigned int ipmasks[33]; // network byte order -qboolean -StringToFilter (const char *s, ipfilter_t * f) +void +SV_GenerateIPMasks (void) { - byte b[4], m[4]; - char num[128]; - int i, j; + int i; + unsigned long int j = 0xFFFFFFFF; - for (i = 0; i < 4; i++) { - b[i] = 0; - m[i] = 0; + for (i = 32; i >= 0; i--) { + ipmasks[i] = htonl (j); + j = j << 1; } +} - for (i = 0; i < 4; i++) { - if (*s < '0' || *s > '9') { - SV_Printf ("Bad filter address: %s\n", s); +static inline void +SV_MaskIPTrim (byte *ip, int mask) +{ + int i; +#ifdef HAVE_IPV6 + int intcount = 4; +#else + int intcount = 1; +#endif + + for (i = 0; i < intcount; i++) { + ((unsigned int *)ip)[i] &= ipmasks[mask > 32 ? 32 : mask]; + if ((mask -= 32) < 0) + mask = 0; + } +} + +// assumes b has already been masked +static inline qboolean +SV_MaskIPCompare (byte *a, byte *b, int mask) +{ + int i; +#ifdef HAVE_IPV6 + int intcount = 4; +#else + int intcount = 1; +#endif + + for (i = 0; i < intcount; i++) { + if ((((unsigned int *)a)[i] & ipmasks[mask > 32 ? 32 : mask]) != ((unsigned int *)b)[i]) return false; - } - - j = 0; - while (*s >= '0' && *s <= '9') { - num[j++] = *s++; - } - num[j] = 0; - b[i] = atoi (num); - if (b[i] != 0) - m[i] = 255; - - if (!*s) - break; - s++; + if ((mask -= 32) < 0) + mask = 0; } - f->mask = *(unsigned int *) m; - f->compare = *(unsigned int *) b; - return true; } -void -CleanIPlist (void) +static inline qboolean +SV_IPCompare (byte *a, byte *b) { - int i, j; + int i; +#ifdef HAVE_IPV6 + int intcount = 4; +#else + int intcount = 1; +#endif - for (i=0 ; i= '9') { + Con_Printf ("a\n"); + goto bad_address; + } + if (strchr (slash, '/')) { + Con_Printf ("b\n"); + goto bad_address; + } + mask = strtol (slash, &endptr, 10); + if (!*slash || *endptr) { + Con_Printf ("c '%s' %c %c\n", slash, *slash, *endptr); + goto bad_address; + } + } else + mask = -1; + +#ifdef HAVE_IPV6 + // FIXME: we *must* fill in the extra bytes here if we're doing ipv6 +#error Prefix bytes not set for parsing ipv4 addresses +#endif + i = inet_pton (AF_INET, s, b); + if (i == 1) { + if (mask == -1) { + if (!b[3]) { // FIXME: should check a cvar + if (!b[2]) { + if (!b[1]) { + if (!b[0]) { + mask = 0; + } else + mask = 8; + } else + mask = 16; + } else + mask = 24; + } else + mask = 32; + } + } else { +#ifdef HAVE_IPV6 + i = inet_pton (AF_INET6, s, b); +#endif + } + if (i != 1) + goto bad_address; + +#ifdef HAVE_IPV6 + if (mask > 128) +#else + if (mask > 32) +#endif + goto bad_address; + + SV_MaskIPTrim (b, mask); + f->mask = mask; + SV_IPCopy (f->ip, b); + + free (s); + return true; + +bad_address: + SV_Printf ("Bad filter address: %s\n", address); + free (s); + return false; +} + +void +SV_RemoveIPFilter (int i) +{ + for (; i + 1 < numipfilters; i++) + ipfilters[i] = ipfilters[i + 1]; + + numipfilters--; +} + + +void +SV_CleanIPList (void) +{ + // FIXME: some of this is duplicated from listip + int i; + char *type; + + for (i = 0; i < numipfilters;) { + if (ipfilters[i].time && (ipfilters[i].time < realtime)) { +#ifdef HAVE_IPV6 + char buf[INET6_ADDRSTRLEN]; + if (!inet_ntop (AF_INET6, ipfilters[i].ip, buf, INET6_ADDRSTRLEN)) + Sys_Error ("SV_CleanIPList: inet_ntop failed. wtf?\n"); +#else + char buf[INET_ADDRSTRLEN]; + if (!inet_ntop (AF_INET, ipfilters[i].ip, buf, INET_ADDRSTRLEN)) + Sys_Error ("SV_CleanIPList: inet_ntop_failed. wtf?\n"); +#endif + switch (ipfilters[i].type) { + case ft_ban: type = "Ban"; break; + case ft_mute: type = "Mute"; break; + case ft_cuff: type = "Cuff"; break; + default: Sys_Error ("SV_CleanIPList: invalid filter type"); + } + SV_Printf ("SV_CleanIPList: %s for %s/%d removed\n", + type, buf, ipfilters[i].mask); + SV_RemoveIPFilter (i); + } else + i++; } } @@ -1147,35 +1308,94 @@ void SV_AddIP_f (void) { int i; + double bantime; + filtertype_t type; - for (i = 0; i < numipfilters; i++) - if (ipfilters[i].compare == 0xffffffff) - break; // free spot - if (i == numipfilters) { - if (numipfilters == MAX_IPFILTERS) { - SV_Printf ("IP filter list is full\n"); + if (Cmd_Argc () < 2 || Cmd_Argc () > 4) { + SV_Printf ("Usage: addip / [