Index | Thread | Search

From:
Kirill A. Korinsky <kirill@korins.ky>
Subject:
Re: unwind: support wildcard in blacklist
To:
tech@openbsd.org
Date:
Tue, 29 Oct 2024 22:51:30 +0100

Download raw body.

Thread
On Sat, 14 Sep 2024 20:18:14 +0200,
Florian Obser <florian@openbsd.org> wrote:
> 
> I had hopped I'd find the time to review this, but it's been two weeks
> and it didn't happen. It's getting too close to release so it won't make
> it for 7.6.
> I put it on my todo list to look at it mid October at the earliest. Feel
> free to prod me if it doesn't happen then.
>

as asked here the friendly ping which includes the diff.

ok? thougths?

Index: frontend.c
===================================================================
RCS file: /cvs/src/sbin/unwind/frontend.c,v
diff -u -p -r1.83 frontend.c
--- frontend.c	5 Sep 2024 08:22:46 -0000	1.83
+++ frontend.c	29 Oct 2024 21:50:47 -0000
@@ -118,6 +118,8 @@ TAILQ_HEAD(, pending_query)	 pending_que
 struct bl_node {
 	RB_ENTRY(bl_node)	 entry;
 	char			*domain;
+	int			 len;
+	int			 wildcard;
 };
 
 __dead void		 frontend_shutdown(void);
@@ -171,6 +173,19 @@ RB_GENERATE(bl_tree, bl_node, entry, bl_
 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)
 {
@@ -734,7 +749,7 @@ handle_query(struct pending_query *pq)
 {
 	struct query_imsg	 query_imsg;
 	struct bl_node		 find;
-	int			 rcode;
+	int			 rcode, matched;
 	char			*str;
 	char			 dname[LDNS_MAX_DOMAINLEN + 1];
 	char			 qclass_buf[16];
@@ -791,8 +806,13 @@ 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) {
+	matched = (RB_FIND(bl_tree, &bl_head, &find) != NULL);
+	reverse(dname, dname + find.len);
+	if (matched) {
 		if (frontend_conf->blocklist_log)
 			log_info("blocking %s", dname);
 		error_answer(pq, LDNS_RCODE_REFUSED);
@@ -1542,14 +1562,20 @@ parse_blocklist(int fd)
 			if (linelen >= 2 && line[linelen - 2] != '.')
 				line[linelen - 1] = '.';
 			else
-				line[linelen - 1] = '\0';
+				line[linelen-- - 1] = '\0';
 		}
 
+		if (line[0] == '#')
+		    continue;
+
 		bl_node = malloc(sizeof *bl_node);
 		if (bl_node == NULL)
 			fatal("%s: malloc", __func__);
 		if ((bl_node->domain = strdup(line)) == NULL)
 			fatal("%s: strdup", __func__);
+		reverse(bl_node->domain, bl_node->domain + linelen);
+		bl_node->len = linelen;
+		bl_node->wildcard = line[0] == '.';
 		if (RB_INSERT(bl_tree, &bl_head, bl_node) != NULL) {
 			log_warnx("duplicate blocked domain \"%s\"", line);
 			free(bl_node->domain);
@@ -1564,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
Index: unwind.conf.5
===================================================================
RCS file: /cvs/src/sbin/unwind/unwind.conf.5,v
diff -u -p -r1.34 unwind.conf.5
--- unwind.conf.5	30 Jun 2024 16:10:26 -0000	1.34
+++ unwind.conf.5	29 Oct 2024 21:50:48 -0000
@@ -69,9 +69,10 @@ If a domain from this list is queried,
 .Nm unwind
 answers with a return code of
 .Dv REFUSED .
-With
 .Cm log
-blocked queries are logged.
+blocked queries are logged. The list supports limited wildcard
+syntax: domains starting with . (dot) are treated as any subdomains
+on that zone.
 .It Ic forwarder Brq Ar address Oo Ic port Ar number Oc Oo Oo Ic authentication name Ar name Oc Ic DoT Oc ...
 A list of addresses of DNS name servers to forward queries to.
 .Ic port


-- 
wbr, Kirill