Index | Thread | Search

From:
Otto Moerbeek <otto@drijf.net>
Subject:
Re: unwind: support wildcard in blacklist
To:
"Kirill A. Korinsky" <kirill@korins.ky>
Cc:
OpenBSD tech <tech@openbsd.org>, florian@openbsd.org
Date:
Tue, 25 Jun 2024 07:20:26 +0200

Download raw body.

Thread
On Mon, Jun 24, 2024 at 10:55:23PM +0100, Kirill A. Korinsky wrote:

> 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.

Please be aware that in DNS wildcards are already used and have a
somehat different than expected interpretation.

https://en.wikipedia.org/wiki/Wildcard_DNS_record

This means that this should be docuemnted extra carefully, or a
different syntax should be used that does not confuse DNS people.

	-Otto

> 
> 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
>