Created
April 20, 2013 21:19
-
-
Save Elizafox/5427473 to your computer and use it in GitHub Desktop.
Does what it says on the tin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From e3136a0f48c41d5d884735694a306dc08b95e303 Mon Sep 17 00:00:00 2001 | |
From: Elizabeth Myers <elizabeth@interlinked.me> | |
Date: Sat, 20 Apr 2013 16:17:29 -0500 | |
Subject: [PATCH] Add support for multiple forms of blacklist queries using | |
matches. | |
It supports both literal and last octet matches from the dnsbl. | |
--- | |
include/blacklist.h | 15 ++++++- | |
src/blacklist.c | 83 +++++++++++++++++++++++++++++++----- | |
src/newconf.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++++--- | |
3 files changed, 199 insertions(+), 19 deletions(-) | |
diff --git a/include/blacklist.h b/include/blacklist.h | |
index c277da9..79eec92 100644 | |
--- a/include/blacklist.h | |
+++ b/include/blacklist.h | |
@@ -24,6 +24,11 @@ | |
#ifndef _BLACKLIST_H_ | |
#define _BLACKLIST_H_ | |
+#include "stdinc.h" | |
+ | |
+#define BLACKLIST_FILTER_ALL 1 | |
+#define BLACKLIST_FILTER_LAST 2 | |
+ | |
/* A configured DNSBL */ | |
struct Blacklist { | |
unsigned int status; /* If CONF_ILLEGAL, delete when no clients */ | |
@@ -31,6 +36,7 @@ struct Blacklist { | |
int ipv4; /* Does this blacklist support IPv4 lookups? */ | |
int ipv6; /* Does this blacklist support IPv6 lookups? */ | |
char host[IRCD_RES_HOSTLEN + 1]; | |
+ rb_dlink_list filters; /* Filters for queries */ | |
char reject_reason[IRCD_BUFSIZE]; | |
unsigned int hits; | |
time_t lastwarning; | |
@@ -44,8 +50,15 @@ struct BlacklistClient { | |
rb_dlink_node node; | |
}; | |
+/* A blacklist filter */ | |
+struct BlacklistFilter { | |
+ int type; /* Type of filter */ | |
+ char filterstr[HOSTIPLEN]; /* The filter itself */ | |
+ rb_dlink_node node; | |
+}; | |
+ | |
/* public interfaces */ | |
-struct Blacklist *new_blacklist(char *host, char *reject_reason, int ipv4, int ipv6); | |
+struct Blacklist *new_blacklist(char *host, char *reject_reason, int ipv4, int ipv6, rb_dlink_list *filters); | |
void lookup_blacklists(struct Client *client_p); | |
void abort_blacklist_queries(struct Client *client_p); | |
void unref_blacklist(struct Blacklist *blptr); | |
diff --git a/src/blacklist.c b/src/blacklist.c | |
index 85a5545..8f4f09a 100644 | |
--- a/src/blacklist.c | |
+++ b/src/blacklist.c | |
@@ -59,6 +59,64 @@ static struct Blacklist *find_blacklist(char *name) | |
return NULL; | |
} | |
+static inline int blacklist_check_reply(struct BlacklistClient *blcptr, struct rb_sockaddr_storage *addr) | |
+{ | |
+ struct Blacklist *blptr = blcptr->blacklist; | |
+ char ipaddr[HOSTIPLEN]; | |
+ char *lastoctet; | |
+ rb_dlink_node *ptr; | |
+ | |
+ /* XXX the below two checks might want to change at some point | |
+ * e.g. if IPv6 blacklists don't use 127.x.y.z or A records anymore | |
+ * --Elizabeth | |
+ */ | |
+ if (addr->ss_family != AF_INET || | |
+ memcmp(&((struct sockaddr_in *)addr)->sin_addr, "\177", 1)) | |
+ goto blwarn; | |
+ | |
+ /* No filters and entry found - thus positive match */ | |
+ if (!rb_dlink_list_length(&blptr->filters)) | |
+ return 1; | |
+ | |
+ rb_inet_ntop_sock((struct sockaddr *)addr, ipaddr, sizeof(ipaddr)); | |
+ | |
+ /* Below will prolly have to change too if the above changes */ | |
+ if ((lastoctet = strrchr(ipaddr, '.')) == NULL || *(++lastoctet) == '\0') | |
+ goto blwarn; | |
+ | |
+ RB_DLINK_FOREACH(ptr, blcptr->blacklist->filters.head) | |
+ { | |
+ struct BlacklistFilter *filter = ptr->data; | |
+ char *cmpstr; | |
+ | |
+ if (filter->type == BLACKLIST_FILTER_ALL) | |
+ cmpstr = ipaddr; | |
+ else if (filter->type == BLACKLIST_FILTER_LAST) | |
+ cmpstr = lastoctet; | |
+ else | |
+ { | |
+ sendto_realops_snomask(SNO_GENERAL, L_ALL, | |
+ "blacklist_check_reply(): Unknown filtertype (BUG!)"); | |
+ continue; | |
+ } | |
+ | |
+ if (strcmp(cmpstr, filter->filterstr) == 0) | |
+ /* Match! */ | |
+ return 1; | |
+ } | |
+ | |
+ return 0; | |
+blwarn: | |
+ if (blcptr->blacklist->lastwarning + 3600 < rb_current_time()) | |
+ { | |
+ sendto_realops_snomask(SNO_GENERAL, L_ALL, | |
+ "Garbage reply from blacklist %s", | |
+ blcptr->blacklist->host); | |
+ blcptr->blacklist->lastwarning = rb_current_time(); | |
+ } | |
+ return 0; | |
+} | |
+ | |
static void blacklist_dns_callback(void *vptr, struct DNSReply *reply) | |
{ | |
struct BlacklistClient *blcptr = (struct BlacklistClient *) vptr; | |
@@ -77,17 +135,8 @@ static void blacklist_dns_callback(void *vptr, struct DNSReply *reply) | |
if (reply != NULL) | |
{ | |
- /* only accept 127.x.y.z as a listing */ | |
- if (reply->addr.ss_family == AF_INET && | |
- !memcmp(&((struct sockaddr_in *)&reply->addr)->sin_addr, "\177", 1)) | |
+ if (blacklist_check_reply(blcptr, &reply->addr)) | |
listed = TRUE; | |
- else if (blcptr->blacklist->lastwarning + 3600 < rb_current_time()) | |
- { | |
- sendto_realops_snomask(SNO_GENERAL, L_ALL, | |
- "Garbage reply from blacklist %s", | |
- blcptr->blacklist->host); | |
- blcptr->blacklist->lastwarning = rb_current_time(); | |
- } | |
} | |
/* they have a blacklist entry for this client */ | |
@@ -180,7 +229,7 @@ static void initiate_blacklist_dnsquery(struct Blacklist *blptr, struct Client * | |
} | |
/* public interfaces */ | |
-struct Blacklist *new_blacklist(char *name, char *reject_reason, int ipv4, int ipv6) | |
+struct Blacklist *new_blacklist(char *name, char *reject_reason, int ipv4, int ipv6, rb_dlink_list *filters) | |
{ | |
struct Blacklist *blptr; | |
@@ -195,10 +244,14 @@ struct Blacklist *new_blacklist(char *name, char *reject_reason, int ipv4, int i | |
} | |
else | |
blptr->status &= ~CONF_ILLEGAL; | |
+ | |
rb_strlcpy(blptr->host, name, IRCD_RES_HOSTLEN + 1); | |
rb_strlcpy(blptr->reject_reason, reject_reason, IRCD_BUFSIZE); | |
blptr->ipv4 = ipv4; | |
blptr->ipv6 = ipv6; | |
+ | |
+ rb_dlinkMoveList(filters, &blptr->filters); | |
+ | |
blptr->lastwarning = 0; | |
return blptr; | |
@@ -206,9 +259,17 @@ struct Blacklist *new_blacklist(char *name, char *reject_reason, int ipv4, int i | |
void unref_blacklist(struct Blacklist *blptr) | |
{ | |
+ rb_dlink_node *ptr, *next_ptr; | |
+ | |
blptr->refcount--; | |
if (blptr->status & CONF_ILLEGAL && blptr->refcount <= 0) | |
{ | |
+ RB_DLINK_FOREACH_SAFE(ptr, next_ptr, blptr->filters.head) | |
+ { | |
+ rb_free(ptr); | |
+ rb_dlinkDelete(ptr, &blptr->filters); | |
+ } | |
+ | |
rb_dlinkFindDestroy(blptr, &blacklist_list); | |
rb_free(blptr); | |
} | |
diff --git a/src/newconf.c b/src/newconf.c | |
index afa06e3..b593471 100644 | |
--- a/src/newconf.c | |
+++ b/src/newconf.c | |
@@ -58,6 +58,7 @@ static char *yy_blacklist_host = NULL; | |
static char *yy_blacklist_reason = NULL; | |
static int yy_blacklist_ipv4 = 1; | |
static int yy_blacklist_ipv6 = 0; | |
+static rb_dlink_list yy_blacklist_filters; | |
static char *yy_privset_extends = NULL; | |
@@ -1779,9 +1780,24 @@ conf_set_alias_target(void *data) | |
yy_alias->target = rb_strdup(data); | |
} | |
+/* XXX for below */ | |
+static void conf_set_blacklist_reason(void *data); | |
+ | |
static void | |
conf_set_blacklist_host(void *data) | |
{ | |
+ if (yy_blacklist_host) | |
+ { | |
+ conf_report_error("blacklist::host %s overlaps existing host %s", | |
+ (char *)data, yy_blacklist_host); | |
+ | |
+ /* Cleanup */ | |
+ conf_set_blacklist_reason(NULL); | |
+ return; | |
+ } | |
+ | |
+ yy_blacklist_ipv4 = 1; | |
+ yy_blacklist_ipv6 = 0; | |
yy_blacklist_host = rb_strdup(data); | |
} | |
@@ -1814,9 +1830,89 @@ conf_set_blacklist_type(void *data) | |
} | |
static void | |
+conf_set_blacklist_matches(void *data) | |
+{ | |
+ conf_parm_t *args = data; | |
+ | |
+ for (; args; args = args->next) | |
+ { | |
+ struct BlacklistFilter *filter; | |
+ char *str = args->v.string; | |
+ char *p; | |
+ int type = BLACKLIST_FILTER_LAST; | |
+ | |
+ if (CF_TYPE(args->type) != CF_QSTRING) | |
+ { | |
+ conf_report_error("blacklist::matches -- must be quoted string"); | |
+ continue; | |
+ } | |
+ | |
+ if (str == NULL) | |
+ { | |
+ conf_report_error("blacklist::matches -- invalid entry"); | |
+ continue; | |
+ } | |
+ | |
+ if (strlen(str) > HOSTIPLEN) | |
+ { | |
+ conf_report_error("blacklist::matches has an entry too long: %s", | |
+ str); | |
+ continue; | |
+ } | |
+ | |
+ for (p = str; *p != '\0'; p++) | |
+ { | |
+ /* Check for validity */ | |
+ if (*p == '.') | |
+ type = BLACKLIST_FILTER_ALL; | |
+ else if (!isalnum(*p)) | |
+ { | |
+ conf_report_error("blacklist::matches has invalid IP match entry %s", | |
+ str); | |
+ type = 0; | |
+ break; | |
+ } | |
+ } | |
+ | |
+ if (type == BLACKLIST_FILTER_ALL) | |
+ { | |
+ /* Basic IP sanity check */ | |
+ struct rb_sockaddr_storage tmp; | |
+ if (rb_inet_pton(AF_INET, str, &tmp) <= 0) | |
+ { | |
+ conf_report_error("blacklist::matches has invalid IP match entry %s", | |
+ str); | |
+ continue; | |
+ } | |
+ } | |
+ else if (type == BLACKLIST_FILTER_LAST) | |
+ { | |
+ /* Verify it's the correct length */ | |
+ if (strlen(str) > 3) | |
+ { | |
+ conf_report_error("blacklist::matches has invalid octet match entry %s", | |
+ str); | |
+ continue; | |
+ } | |
+ } | |
+ else | |
+ { | |
+ continue; /* Invalid entry */ | |
+ } | |
+ | |
+ filter = rb_malloc(sizeof(struct BlacklistFilter)); | |
+ filter->type = type; | |
+ rb_strlcpy(filter->filterstr, str, sizeof(filter->filterstr)); | |
+ | |
+ rb_dlinkAdd(filter, &filter->node, &yy_blacklist_filters); | |
+ } | |
+} | |
+ | |
+static void | |
conf_set_blacklist_reason(void *data) | |
{ | |
yy_blacklist_reason = rb_strdup(data); | |
+ rb_dlink_node *ptr, *nptr; | |
if (yy_blacklist_host && yy_blacklist_reason) | |
{ | |
@@ -1842,16 +1938,25 @@ conf_set_blacklist_reason(void *data) | |
} | |
} | |
- new_blacklist(yy_blacklist_host, yy_blacklist_reason, yy_blacklist_ipv4, yy_blacklist_ipv6); | |
+ new_blacklist(yy_blacklist_host, yy_blacklist_reason, yy_blacklist_ipv4, yy_blacklist_ipv6, | |
+ &yy_blacklist_filters); | |
+ } | |
cleanup_bl: | |
- rb_free(yy_blacklist_host); | |
- rb_free(yy_blacklist_reason); | |
- yy_blacklist_host = NULL; | |
- yy_blacklist_reason = NULL; | |
- yy_blacklist_ipv4 = 1; | |
- yy_blacklist_ipv6 = 0; | |
+ RB_DLINK_FOREACH_SAFE(ptr, nptr, yy_blacklist_filters.head) | |
+ { | |
+ if (data == NULL) | |
+ rb_free(ptr); | |
+ | |
+ rb_dlinkDelete(ptr, &yy_blacklist_filters); | |
} | |
+ | |
+ rb_free(yy_blacklist_host); | |
+ rb_free(yy_blacklist_reason); | |
+ yy_blacklist_host = NULL; | |
+ yy_blacklist_reason = NULL; | |
+ yy_blacklist_ipv4 = 1; | |
+ yy_blacklist_ipv6 = 0; | |
} | |
/* public functions */ | |
@@ -2354,5 +2459,6 @@ newconf_init() | |
add_top_conf("blacklist", NULL, NULL, NULL); | |
add_conf_item("blacklist", "host", CF_QSTRING, conf_set_blacklist_host); | |
add_conf_item("blacklist", "type", CF_STRING | CF_FLIST, conf_set_blacklist_type); | |
+ add_conf_item("blacklist", "matches", CF_QSTRING | CF_FLIST, conf_set_blacklist_matches); | |
add_conf_item("blacklist", "reject_reason", CF_QSTRING, conf_set_blacklist_reason); | |
} | |
-- | |
1.8.1.5 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment