summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Changes1
-rw-r--r--include/extern.h14
-rw-r--r--include/services.h38
-rw-r--r--src/Makefile7
-rw-r--r--src/userban.c472
-rw-r--r--version.log6
6 files changed, 534 insertions, 4 deletions
diff --git a/Changes b/Changes
index 03796070b..6dca9d149 100644
--- a/Changes
+++ b/Changes
@@ -1,6 +1,7 @@
Anope Version S V N
--------------------
Provided by Anope Dev. <dev@anope.org> - 2005
+06/05 A New bansystem which is faster and supports CIDR bans. [ #00]
06/03 A Protocol files can now fill mod_current_buffer with custom code. [#389]
06/04 F Register script now works again. [#394]
06/04 F Finishing sync for Ultimate3 was not done correctly. [#398]
diff --git a/include/extern.h b/include/extern.h
index 433d6bb96..56e2ff4ca 100644
--- a/include/extern.h
+++ b/include/extern.h
@@ -1055,6 +1055,20 @@ E int sockprintf(ano_socket_t s, char *fmt, ...);
E int conn(const char *host, int port, const char *lhost, int lport);
E void disconn(ano_socket_t s);
+/**** userban.c ****/
+
+E uint32 cidr_to_netmask(uint16 cidr);
+E uint16 netmask_to_cidr(uint32 mask);
+E BanInfo *ban_create(char *mask, uint32 id);
+E int ban_match(BanInfo *ban, char *user, char *host, uint32 ip);
+E int ban_match_mask(BanInfo *ban, char *mask, uint32 ip);
+E int ban_add(BanList *bl, char *mask);
+E void ban_del(BanList *bl, BanInfo *ban);
+E BanList *banlist_create(int hashed);
+E int banlist_match(BanList *bl, char *user, char *host, uint32 ip);
+E int banlist_match_mask(BanList *bl, char *mask, uint32 ip);
+E BanInfo *banlist_lookup_id(BanList *bl, uint32 id);
+
/**** users.c ****/
E User *userlist[1024];
diff --git a/include/services.h b/include/services.h
index e0017256e..31684577c 100644
--- a/include/services.h
+++ b/include/services.h
@@ -1317,6 +1317,44 @@ typedef struct ircd_modes_ {
/*************************************************************************/
+/* UserBan support structures */
+
+typedef struct baninfo_ BanInfo;
+typedef struct banlist_ BanList;
+
+struct baninfo_ {
+ uint32 id; /* Ban ID, can be used to look it up */
+ uint16 type; /* See BANTYPE_ below */
+
+ uint32 cidr_mask; /* Netmask for CIDR matching */
+ uint32 cidr_ip; /* IP mask for CIDR matching */
+ char *user; /* User value, NULL when not matched */
+ char *host; /* Host value, NULL when not matched */
+
+ char *mask; /* String version of the ban mask, for displaying */
+
+ BanInfo *next;
+ BanInfo *prev;
+};
+
+struct banlist_ {
+ uint16 flags; /* See BANLIST_ below */
+ BanInfo **bans; /* Ban data lists */
+ uint32 next_id; /* Next ID to use for a ban */
+};
+
+#define BANTYPE_NONE 0x0000
+#define BANTYPE_CIDR4 0x0001
+#define BANTYPE_USER 0x0002
+#define BANTYPE_USER_WILD 0x0004
+#define BANTYPE_HOST 0x0008
+#define BANTYPE_HOST_WILD 0x0010
+
+#define BANLIST_NONE 0x0000
+#define BANLIST_HASHED 0x0001
+
+/*************************************************************************/
+
#include "extern.h"
/*************************************************************************/
diff --git a/src/Makefile b/src/Makefile
index a467256fd..65c1cc3fc 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -3,12 +3,12 @@ RDB_OBJ = $(RDB:.c=.o)
OBJS = actions.o base64.o botserv.o channels.o chanserv.o commands.o compat.o \
config.o datafiles.o encrypt.o events.o helpserv.o hostserv.o init.o ircd.o language.o list.o log.o mail.o main.o \
memory.o memoserv.o messages.o misc.o modules.o news.o nickserv.o operserv.o \
- process.o send.o servers.o sessions.o slist.o sockutil.o timeout.o users.o \
+ process.o send.o servers.o sessions.o slist.o sockutil.o timeout.o userban.o users.o \
$(VSNPRINTF_O) $(RDB_OBJ) $(MYSQL_OBJ)
SRCS = actions.c base64.c botserv.c channels.c chanserv.c commands.c compat.c \
config.c datafiles.c encrypt.c events.c helpserv.c hostserv.c init.c ircd.c language.c list.c log.c mail.c main.c \
memory.c memoserv.c messages.c misc.c modules.c news.c nickserv.c operserv.c \
- process.c send.c servers.c sessions.c slist.c sockutil.c timeout.c users.c \
+ process.c send.c servers.c sessions.c slist.c sockutil.c timeout.c userban.c users.c \
$(VSNPRINTF_C) $(RDB) $(MYSQL)
INCLUDES = ../include/commands.h ../include/defs.h ../include/language.h \
@@ -48,7 +48,7 @@ datafiles.o: datafiles.c $(INCLUDES)
encrypt.o: encrypt.c $(INCLUDES)
events.o: events.c $(INCLUDES)
init.o: init.c $(INCLUDES)
-ircd.o: ircd.c $(INCLUDES)
+ircd.o: ircd.c $(INCLUDES)
helpserv.o: helpserv.c $(INCLUDES)
hostserv.o: hostserv.c $(INCLUDES)
language.o: language.c $(INCLUDES)
@@ -71,6 +71,7 @@ sessions.o: sessions.c $(INCLUDES)
slist.o: slist.c $(INCLUDES)
sockutil.o: sockutil.c $(INCLUDES)
timeout.o: timeout.c $(INCLUDES)
+userban.o: userban.c $(INCLUDES)
users.o: users.c $(INCLUDES)
vsnprintf.o: vsnprintf.c $(INCLUDES)
mysql.o: mysql.c $(INCLUDES)
diff --git a/src/userban.c b/src/userban.c
new file mode 100644
index 000000000..1ef883516
--- /dev/null
+++ b/src/userban.c
@@ -0,0 +1,472 @@
+/* Host and IP (incl. CIDR) banning routines
+ *
+ * (C) 2003-2005 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Please read COPYING and README for further details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ *
+ * $Id$
+ *
+ */
+
+#include "services.h"
+
+/*************************************************************************/
+
+#define BANHOSTHASH(x) (*(x) & 0x1F)
+#define BANINFOHASH(x) ((((x)->type & BANTYPE_CIDR4) || (*((x)->host) == '*') || (*((x)->host) == '?')) ? 32 : BANHOSTHASH((x)->host))
+
+/*************************************************************************/
+
+/**
+ * Turn a cidr value into a netmask
+ * @param cidr CIDR value
+ * @return Netmask value
+ */
+uint32 cidr_to_netmask(uint16 cidr)
+{
+ if (cidr == 0)
+ return 0;
+
+ return (0xFFFFFFFF - (1 << (32 - cidr)) + 1);
+}
+
+/**
+ * Turn a netmask into a cidr value
+ * @param mask Netmask
+ * @return CIDR value
+ */
+uint16 netmask_to_cidr(uint32 mask)
+{
+ int tmp = 0;
+
+ while (!(mask & (1 << tmp)) && (tmp < 32))
+ tmp++;
+
+ return (32 - tmp);
+}
+
+/*************************************************************************/
+
+/**
+ * Check if the given string is some sort of wildcard
+ * @param str String to check
+ * @return 1 for wildcard, 0 for anything else
+ */
+int str_is_wildcard(const char *str)
+{
+ while (*str) {
+ if ((*str == '*') || (*str == '?'))
+ return 1;
+ str++;
+ }
+
+ return 0;
+}
+
+/**
+ * Check if the given string is a pure wildcard
+ * @param str String to check
+ * @return 1 for pure wildcard, 0 for anything else
+ */
+int str_is_pure_wildcard(const char *str)
+{
+ while (*str) {
+ if (*str != '*')
+ return 0;
+ str++;
+ }
+
+ return 1;
+}
+
+/*************************************************************************/
+
+/**
+ * Check if the given string is an IP or CIDR mask, and fill the given
+ * ip/cidr params if so.
+ * @param str String to check
+ * @param ip The ipmask to fill when a CIDR is found
+ * @param mask The CIDR mask to fill when a CIDR is found
+ * @param host Displayed host
+ * @return 1 for IP/CIDR, 0 for anything else
+ */
+int str_is_cidr(char *str, uint32 * ip, uint32 * mask, char **host)
+{
+ int i;
+ int octets[4] = { -1, -1, -1, -1 };
+ char *s = str;
+ char buf[512];
+ uint16 cidr;
+
+ for (i = 0; i < 4; i++) {
+ octets[i] = strtol(s, &s, 10);
+ /* Bail out if the octet is invalid or wrongly terminated */
+ if ((octets[i] < 0) || (octets[i] > 255)
+ || ((i < 3) && (*s != '.')))
+ return 0;
+ if (i < 3)
+ s++;
+ }
+
+ /* Fill the IP - the dirty way */
+ *ip = octets[3];
+ *ip += octets[2] * 256;
+ *ip += octets[1] * 65536;
+ *ip += octets[0] * 16777216;
+
+ if (*s == '/') {
+ s++;
+ /* There's a CIDR mask here! */
+ cidr = strtol(s, &s, 10);
+ /* Bail out if the CIDR is invalid or the string isn't done yet */
+ if ((cidr > 32) || (*s))
+ return 0;
+ } else {
+ /* No CIDR mask here - use 32 so the whole ip will be matched */
+ cidr = 32;
+ }
+
+ *mask = cidr_to_netmask(cidr);
+ /* Apply the mask to avoid 255.255.255.255/8 bans */
+ *ip &= *mask;
+
+ /* Refill the octets to fill the host */
+ octets[0] = (*ip & 0xFF000000) / 16777216;
+ octets[1] = (*ip & 0x00FF0000) / 65536;
+ octets[2] = (*ip & 0x0000FF00) / 256;
+ octets[3] = (*ip & 0x000000FF);
+
+ if (cidr == 32)
+ snprintf(buf, 512, "%d.%d.%d.%d", octets[0], octets[1], octets[2],
+ octets[3]);
+ else
+ snprintf(buf, 512, "%d.%d.%d.%d/%d", octets[0], octets[1],
+ octets[2], octets[3], cidr);
+
+ *host = sstrdup(buf);
+
+ return 1;
+}
+
+/*************************************************************************/
+
+/**
+ * Create a BanInfo for the given mask. This function destroys the given
+ * mask as a side effect.
+ * @param mask Host/IP/CIDR mask to parse
+ * @param id Ban ID to use for this ban
+ * @return BanInfo struct for the given mask, NULL if creation failed
+ */
+BanInfo *ban_create(char *mask, uint32 id)
+{
+ char *user, *host, *cidrhost;
+ char buf[BUFSIZE];
+ BanInfo *ban;
+ uint32 ip;
+ uint32 cidr;
+
+ ban = scalloc(1, sizeof(BanInfo));
+ ban->id = id;
+ ban->type = BANTYPE_NONE;
+
+ host = strchr(mask, '@');
+ if (host) {
+ *host++ = '\0';
+ /* If the user is purely a wildcard, ignore it */
+ if (str_is_pure_wildcard(mask))
+ user = NULL;
+ else
+ user = mask;
+ } else {
+ /* If there's no user in the mask, assume a pure wildcard */
+ user = NULL;
+ host = mask;
+ }
+
+ if (user) {
+ ban->user = sstrdup(user);
+ /* Check if we have a wildcard user */
+ if (str_is_wildcard(user))
+ ban->type |= BANTYPE_USER_WILD;
+ else
+ ban->type |= BANTYPE_USER;
+ }
+ /* Only check the host if it's not a pure wildcard */
+ if (*host && !str_is_pure_wildcard(host)) {
+ if (ircd->nickip && str_is_cidr(host, &ip, &cidr, &cidrhost)) {
+ ban->cidr_ip = ip;
+ ban->cidr_mask = cidr;
+ ban->type |= BANTYPE_CIDR4;
+ host = cidrhost;
+ } else if (strchr(host, '/')) {
+ /* If we still have a CIDR we're fucked (scientific term) */
+ return NULL;
+ } else {
+ ban->host = sstrdup(host);
+ if (str_is_wildcard(host))
+ ban->type |= BANTYPE_HOST_WILD;
+ else
+ ban->type |= BANTYPE_HOST;
+ }
+ }
+
+ if (!user)
+ user = "*";
+ if (!host)
+ host = "*";
+ snprintf(buf, BUFSIZE, "%s@%s", user, host);
+ ban->mask = sstrdup(buf);
+
+ return ban;
+}
+
+/*************************************************************************/
+
+/**
+ * Match the given BanInfo to the given user/host and optional IP addy
+ * @param ban BanInfo struct to match against
+ * @param user User to match against
+ * @param host Host to match against
+ * @param ip IP to match against, set to 0 to not match this
+ * @return 1 for a match, 0 for no match
+ */
+int ban_match(BanInfo * ban, char *user, char *host, uint32 ip)
+{
+ if ((ban->type & BANTYPE_CIDR4) && ip
+ && ((ip & ban->cidr_mask) != ban->cidr_ip))
+ return 0;
+ if ((ban->type & BANTYPE_USER) && (stricmp(ban->user, user) != 0))
+ return 0;
+ if ((ban->type & BANTYPE_HOST) && (stricmp(ban->host, host) != 0))
+ return 0;
+ if ((ban->type & BANTYPE_USER_WILD)
+ && !match_wild_nocase(ban->user, user))
+ return 0;
+ if ((ban->type & BANTYPE_HOST_WILD)
+ && !match_wild_nocase(ban->host, host))
+ return 0;
+
+ return 1;
+}
+
+/**
+ * Match the given BanInfo to the given hostmask and optional IP addy
+ * @param ban BanInfo struct to match against
+ * @param mask Hostmask to match against
+ * @param ip IP to match against, set to 0 to not match this
+ * @return 1 for a match, 0 for no match
+ */
+int ban_match_mask(BanInfo * ban, char *mask, uint32 ip)
+{
+ char *user;
+ char *host;
+
+ if (ban->type & (BANTYPE_USER | BANTYPE_USER_WILD)) {
+ host = strchr(mask, '@');
+ if (host) {
+ *host++ = '\0';
+ user = mask;
+ } else {
+ user = NULL;
+ }
+ }
+ if (ban->type & (BANTYPE_HOST | BANTYPE_HOST_WILD)) {
+ if (ban->type & (BANTYPE_USER | BANTYPE_USER_WILD)) {
+ if (!user)
+ host = mask;
+ } else {
+ host = strchr(mask, '@');
+ if (host)
+ host++;
+ else
+ host = mask;
+ }
+ }
+
+ return ban_match(ban, user, host, ip);
+}
+
+/*************************************************************************/
+
+/**
+ * Create and initialize a new ban list
+ * @param hashed Should the list be hashed or not?
+ * @return Pointer to the created BanList object
+ */
+BanList *banlist_create(int hashed)
+{
+ BanList *bl;
+
+ bl = scalloc(1, sizeof(BanList));
+ bl->flags = BANLIST_NONE;
+
+ if (hashed) {
+ bl->flags |= BANLIST_HASHED;
+ bl->bans = scalloc(33, sizeof(BanInfo));
+ } else {
+ bl->bans = scalloc(1, sizeof(BanInfo));
+ }
+
+ bl->next_id = 1;
+
+ return bl;
+}
+
+/*************************************************************************/
+
+/**
+ * Create a ban and add it to the given banlist
+ * @param bl BanList object the banmask should be added to
+ * @param mask The mask to parse and add to the banlist
+ * @return 1 for success, 0 for failure
+ */
+int ban_add(BanList * bl, char *mask)
+{
+ int hash;
+ char *hostmask;
+ BanInfo *ban;
+
+ hostmask = sstrdup(mask);
+ ban = ban_create(hostmask, bl->next_id);
+ free(hostmask);
+ if (!ban)
+ return 0;
+
+ bl->next_id++;
+
+ if (bl->flags & BANLIST_HASHED) {
+ hash = BANINFOHASH(ban);
+ ban->next = bl->bans[hash];
+ ban->prev = NULL;
+ if (bl->bans[hash])
+ bl->bans[hash]->prev = ban;
+ bl->bans[hash] = ban;
+ } else {
+ ban->next = *(bl->bans);
+ ban->prev = NULL;
+ if (*(bl->bans))
+ (*(bl->bans))->prev = ban;
+ *(bl->bans) = ban;
+ }
+
+ return 1;
+}
+
+/*************************************************************************/
+
+/**
+ * Delete the given ban from the given banlist
+ * @param bl BanList object the banmask should be deleted from
+ * @param ban The ban to be deleted, has to be in the given banlist
+ */
+void ban_del(BanList * bl, BanInfo * ban)
+{
+ if (ban->next)
+ ban->next->prev = ban->prev;
+ if (ban->prev)
+ ban->prev->next = ban->next;
+ else if (bl->flags & BANLIST_HASHED)
+ bl->bans[BANINFOHASH(ban)] = ban->next;
+ else
+ *(bl->bans) = ban->next;
+
+ if (ban->user)
+ free(ban->user);
+ if (ban->host)
+ free(ban->host);
+ free(ban->mask);
+
+ free(ban);
+}
+
+/*************************************************************************/
+
+/**
+ * Match a user, host, and ip to a banlist
+ * @param bl BanList that should be matched against
+ * @param user The user to match
+ * @param host The host to match
+ * @param ip The ip to match
+ * @return 1 for match, 0 for no match
+ */
+int banlist_match(BanList * bl, char *user, char *host, uint32 ip)
+{
+ BanInfo *ban;
+
+ if (bl->flags & BANLIST_HASHED) {
+ for (ban = bl->bans[BANHOSTHASH(host)]; ban; ban = ban->next) {
+ if (ban_match(ban, user, host, ip))
+ return 1;
+ }
+ /* Now check for all wildcard-qualified bans */
+ for (ban = bl->bans[32]; ban; ban = ban->next) {
+ if (ban_match(ban, user, host, ip))
+ return 1;
+ }
+ } else {
+ for (ban = *(bl->bans); ban; ban = ban->next) {
+ if (ban_match(ban, user, host, ip))
+ return 1;
+ }
+ }
+
+ /* We matched none, yay */
+ return 0;
+}
+
+/**
+ * Match a mask and ip to a banlist
+ * @param bl BanList that should be matched against
+ * @param mask The user@host mask to match
+ * @return 1 for match, 0 for no match
+ */
+int banlist_match_mask(BanList * bl, char *mask, uint32 ip)
+{
+ char *user;
+ char *host;
+
+ host = strchr(mask, '@');
+ if (host) {
+ *host++ = '\0';
+ user = mask;
+ } else {
+ user = NULL;
+ host = mask;
+ }
+
+ return banlist_match(bl, user, host, ip);
+}
+
+/*************************************************************************/
+
+/**
+ * Lookup a ban id in a banlist
+ * @param bl BanList to search in
+ * @param id Ban id to lookup
+ * @return Pointer to BanInfo for the given id, or NULL if not found
+ */
+BanInfo *banlist_lookup_id(BanList * bl, uint32 id)
+{
+ int i;
+ BanInfo *ban;
+
+ if (bl->flags & BANLIST_HASHED) {
+ for (i = 0; i < 33; i++) {
+ for (ban = bl->bans[i]; ban; ban = ban->next) {
+ if (ban->id == id)
+ return ban;
+ }
+ }
+ } else {
+ for (ban = *(bl->bans); ban; ban = ban->next) {
+ if (ban->id == id)
+ return ban;
+ }
+ }
+}
+
+/* EOF */
diff --git a/version.log b/version.log
index bd006953e..038cb36ff 100644
--- a/version.log
+++ b/version.log
@@ -8,10 +8,14 @@
VERSION_MAJOR="1"
VERSION_MINOR="7"
VERSION_PATCH="10"
-VERSION_BUILD="827"
+VERSION_BUILD="828"
# $Log$
#
+# BUILD : 1.7.10 (828)
+# BUGS :
+# NOTES : Added a new ban system which should be faster than what we have now and also supports CIDR bans -- not yet in use, but will be used for akills andeventually channel bans -- hashing and cidr bans are not tested yet
+#
# BUILD : 1.7.10 (827)
# BUGS : 394
# NOTES : Fixed /src/bin/register