Index | Thread | Search

From:
Kirill A. Korinsky <kirill@korins.ky>
Subject:
unwind: support wildcard in blacklist
To:
OpenBSD tech <tech@openbsd.org>, florian@openbsd.org
Date:
Mon, 24 Jun 2024 22:55:23 +0100

Download raw body.

Thread
Florian, tech@,

Here a diff which introduced support of wildcard inside unwind's domain
blacklist. Wildcard supported only at begining and as '*' which should be
followed by '.'.

So, after that this two lines:

google.com
*.google.com

blocks any requests to google.com and all its subdomains.

The diff:

diff --git sbin/unwind/frontend.c sbin/unwind/frontend.c
index ccbc977eb73..32a83b56468 100644
--- sbin/unwind/frontend.c
+++ sbin/unwind/frontend.c
@@ -118,6 +118,8 @@ TAILQ_HEAD(, pending_query)	 pending_queries;
 struct bl_node {
 	RB_ENTRY(bl_node)	 entry;
 	char			*domain;
+	int			 len;
+	int			 wildcard;
 };
 
 __dead void		 frontend_shutdown(void);
@@ -171,6 +173,18 @@ RB_GENERATE(bl_tree, bl_node, entry, bl_cmp)
 struct dns64_prefix	*dns64_prefixes;
 int			 dns64_prefix_count;
 
+static void
+reverse(char* begin, char* end)
+{
+	char t;
+	while (begin < --end) {
+		t = *begin;
+		*begin = *end;
+		*end = t;
+		++begin;
+	}
+}
+
 void
 frontend_sig_handler(int sig, short event, void *bula)
 {
@@ -790,6 +804,9 @@ handle_query(struct pending_query *pq)
 	log_debug("%s: %s %s %s ?", ip_port((struct sockaddr *)&pq->from),
 	    dname, qclass_buf, qtype_buf);
 
+	find.len = strlen(dname);
+	find.wildcard = 0;
+	reverse(dname, dname + find.len);
 	find.domain = dname;
 	if (RB_FIND(bl_tree, &bl_head, &find) != NULL) {
 		if (frontend_conf->blocklist_log)
@@ -797,6 +814,7 @@ handle_query(struct pending_query *pq)
 		error_answer(pq, LDNS_RCODE_REFUSED);
 		goto send_answer;
 	}
+	reverse(dname, dname + find.len);
 
 	if (pq->qinfo.qtype == LDNS_RR_TYPE_AXFR || pq->qinfo.qtype ==
 	    LDNS_RR_TYPE_IXFR) {
@@ -1541,7 +1559,7 @@ parse_blocklist(int fd)
 			if (linelen >= 2 && line[linelen - 2] != '.')
 				line[linelen - 1] = '.';
 			else
-				line[linelen - 1] = '\0';
+				line[linelen-- - 1] = '\0';
 		}
 
 		bl_node = malloc(sizeof *bl_node);
@@ -1549,6 +1567,15 @@ parse_blocklist(int fd)
 			fatal("%s: malloc", __func__);
 		if ((bl_node->domain = strdup(line)) == NULL)
 			fatal("%s: strdup", __func__);
+		reverse(bl_node->domain, bl_node->domain + linelen);
+		if (linelen > 2 && line[0] == '*' && line[1] == '.') {
+			bl_node->wildcard = 1;
+			bl_node->domain[linelen - 1] = '\0';
+			bl_node->len = linelen - 1;
+		} else {
+			bl_node->wildcard = 0;
+			bl_node->len = linelen;
+		}
 		if (RB_INSERT(bl_tree, &bl_head, bl_node) != NULL) {
 			log_warnx("duplicate blocked domain \"%s\"", line);
 			free(bl_node->domain);
@@ -1563,7 +1590,12 @@ parse_blocklist(int fd)
 
 int
 bl_cmp(struct bl_node *e1, struct bl_node *e2) {
-	return (strcasecmp(e1->domain, e2->domain));
+	if (e1->wildcard == e2->wildcard)
+		return (strcasecmp(e1->domain, e2->domain));
+	else if (e1->wildcard)
+		return (strncasecmp(e1->domain, e2->domain, e1->len));
+	else /* e2->wildcard */
+		return (strncasecmp(e1->domain, e2->domain, e2->len));
 }
 
 void


-- 
wbr, Kirill