summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorflorian <florian@openbsd.org>2019-05-10 14:10:38 +0000
committerflorian <florian@openbsd.org>2019-05-10 14:10:38 +0000
commit2d98827609ed0018da2c8b5885071d117d02abdc (patch)
tree4d39c96226b9cfe298f7f0111c57703f53590b4e
parentWhen calculating how much payload ospf6d can put into DD and LSREQ packets (diff)
downloadwireguard-openbsd-2d98827609ed0018da2c8b5885071d117d02abdc.tar.xz
wireguard-openbsd-2d98827609ed0018da2c8b5885071d117d02abdc.zip
Implement DNS block lists. If unwind is queried for a domain
in the block list it answers with rcode REFUSED.
-rw-r--r--sbin/unwind/captiveportal.c9
-rw-r--r--sbin/unwind/frontend.c102
-rw-r--r--sbin/unwind/parse.y21
-rw-r--r--sbin/unwind/printconf.c5
-rw-r--r--sbin/unwind/resolver.c9
-rw-r--r--sbin/unwind/unwind.c30
-rw-r--r--sbin/unwind/unwind.conf.510
-rw-r--r--sbin/unwind/unwind.h5
8 files changed, 181 insertions, 10 deletions
diff --git a/sbin/unwind/captiveportal.c b/sbin/unwind/captiveportal.c
index cbca055a055..bacc49877ea 100644
--- a/sbin/unwind/captiveportal.c
+++ b/sbin/unwind/captiveportal.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: captiveportal.c,v 1.10 2019/03/15 16:48:37 florian Exp $ */
+/* $OpenBSD: captiveportal.c,v 1.11 2019/05/10 14:10:38 florian Exp $ */
/*
* Copyright (c) 2018 Florian Obser <florian@openbsd.org>
@@ -342,6 +342,13 @@ captiveportal_dispatch_main(int fd, short event, void *bula)
strdup(imsg.data)) == NULL)
fatal("%s: strdup", __func__);
break;
+ case IMSG_RECONF_BLOCKLIST_FILE:
+ /* make sure this is a string */
+ ((char *)imsg.data)[IMSG_DATA_SIZE(imsg) - 1] = '\0';
+ if ((nconf->blocklist_file = strdup(imsg.data)) ==
+ NULL)
+ fatal("%s: strdup", __func__);
+ break;
case IMSG_RECONF_FORWARDER:
if (IMSG_DATA_SIZE(imsg) != sizeof(struct uw_forwarder))
fatalx("%s: IMSG_RECONF_FORWARDER wrong length:"
diff --git a/sbin/unwind/frontend.c b/sbin/unwind/frontend.c
index 4ed4bf77c65..36ef983a6a8 100644
--- a/sbin/unwind/frontend.c
+++ b/sbin/unwind/frontend.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: frontend.c,v 1.19 2019/05/08 21:59:13 florian Exp $ */
+/* $OpenBSD: frontend.c,v 1.20 2019/05/10 14:10:38 florian Exp $ */
/*
* Copyright (c) 2018 Florian Obser <florian@openbsd.org>
@@ -23,6 +23,7 @@
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/syslog.h>
+#include <sys/tree.h>
#include <sys/uio.h>
#include <netinet/in.h>
@@ -71,10 +72,16 @@ struct pending_query {
uint64_t imsg_id;
int fd;
int bogus;
+ int rcode_override;
};
TAILQ_HEAD(, pending_query) pending_queries;
+struct bl_node {
+ RB_ENTRY(bl_node) entry;
+ char *domain;
+};
+
__dead void frontend_shutdown(void);
void frontend_sig_handler(int, short, void *);
void frontend_startup(void);
@@ -92,6 +99,9 @@ void parse_dhcp_lease(int);
void parse_trust_anchor(struct trust_anchor_head *, int);
void send_trust_anchors(struct trust_anchor_head *);
void write_trust_anchors(struct trust_anchor_head *, int);
+void parse_blocklist(int);
+int bl_cmp(struct bl_node *, struct bl_node *);
+void free_bl(void);
struct uw_conf *frontend_conf;
struct imsgev *iev_main;
@@ -103,6 +113,10 @@ int ta_fd = -1;
static struct trust_anchor_head trust_anchors, new_trust_anchors;
+RB_HEAD(bl_tree, bl_node) bl_head = RB_INITIALIZER(&bl_head);
+RB_PROTOTYPE(bl_tree, bl_node, entry, bl_cmp)
+RB_GENERATE(bl_tree, bl_node, entry, bl_cmp)
+
void
frontend_sig_handler(int sig, short event, void *bula)
{
@@ -386,6 +400,13 @@ frontend_dispatch_main(int fd, short event, void *bula)
strdup(imsg.data)) == NULL)
fatal("%s: strdup", __func__);
break;
+ case IMSG_RECONF_BLOCKLIST_FILE:
+ /* make sure this is a string */
+ ((char *)imsg.data)[IMSG_DATA_SIZE(imsg) - 1] = '\0';
+ if ((nconf->blocklist_file = strdup(imsg.data)) ==
+ NULL)
+ fatal("%s: strdup", __func__);
+ break;
case IMSG_RECONF_FORWARDER:
if (IMSG_DATA_SIZE(imsg) != sizeof(struct uw_forwarder))
fatalx("%s: IMSG_RECONF_FORWARDER wrong length:"
@@ -416,6 +437,8 @@ frontend_dispatch_main(int fd, short event, void *bula)
fatalx("%s: IMSG_RECONF_END without "
"IMSG_RECONF_CONF", __func__);
merge_config(frontend_conf, nconf);
+ if (frontend_conf->blocklist_file == NULL)
+ free_bl();
nconf = NULL;
break;
case IMSG_UDP6SOCK:
@@ -479,6 +502,12 @@ frontend_dispatch_main(int fd, short event, void *bula)
if (!TAILQ_EMPTY(&trust_anchors))
send_trust_anchors(&trust_anchors);
break;
+ case IMSG_BLFD:
+ if ((fd = imsg.fd) == -1)
+ fatalx("%s: expected to receive imsg block "
+ "list fd but didn't receive any", __func__);
+ parse_blocklist(fd);
+ break;
default:
log_debug("%s: error handling imsg %d", __func__,
imsg.hdr.type);
@@ -674,6 +703,7 @@ udp_receive(int fd, short events, void *arg)
struct udp_ev *udpev = (struct udp_ev *)arg;
struct pending_query *pq;
struct query_imsg *query_imsg;
+ struct bl_node find;
ssize_t len, rem_len, buf_len;
uint16_t qdcount, ancount, nscount, arcount, t, c;
uint8_t *queryp;
@@ -736,6 +766,8 @@ udp_receive(int fd, short events, void *arg)
return;
}
+ pq->rcode_override = LDNS_RCODE_NOERROR;
+
if ((pq->query = malloc(len)) == NULL) {
log_warn(NULL);
free(pq);
@@ -751,6 +783,14 @@ udp_receive(int fd, short events, void *arg)
pq->from = udpev->from;
pq->fd = fd;
+ find.domain = buf;
+ if (RB_FIND(bl_tree, &bl_head, &find) != NULL) {
+ pq->rcode_override = LDNS_RCODE_REFUSED;
+ TAILQ_INSERT_TAIL(&pending_queries, pq, entry);
+ send_answer(pq, NULL, 0);
+ return;
+ }
+
if ((query_imsg = calloc(1, sizeof(*query_imsg))) == NULL) {
log_warn(NULL);
return;
@@ -791,7 +831,10 @@ send_answer(struct pending_query *pq, uint8_t *answer, ssize_t len)
LDNS_QR_SET(answer);
LDNS_RA_SET(answer);
- LDNS_RCODE_SET(answer, LDNS_RCODE_SERVFAIL);
+ if (pq->rcode_override != LDNS_RCODE_NOERROR)
+ LDNS_RCODE_SET(answer, pq->rcode_override);
+ else
+ LDNS_RCODE_SET(answer, LDNS_RCODE_SERVFAIL);
} else {
if (pq->bogus) {
if(LDNS_CD_WIRE(pq->query)) {
@@ -1237,3 +1280,58 @@ out:
ftruncate(fd, len);
fsync(fd);
}
+
+void
+parse_blocklist(int fd)
+{
+ FILE *f;
+ struct bl_node *bl_node;
+ char *line = NULL;
+ size_t linesize = 0;
+ ssize_t linelen;
+
+ if((f = fdopen(fd, "r")) == NULL) {
+ log_warn("cannot read block list");
+ close(fd);
+ return;
+ }
+
+ free_bl();
+
+ while ((linelen = getline(&line, &linesize, f)) != -1) {
+ if (line[linelen - 1] == '\n') {
+ if (linelen >= 2 && line[linelen - 2] != '.')
+ line[linelen - 1] = '.';
+ else
+ line[linelen - 1] = '\0';
+ }
+
+ 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__);
+ RB_INSERT(bl_tree, &bl_head, bl_node);
+ }
+ free(line);
+ if (ferror(f))
+ log_warn("getline");
+ fclose(f);
+}
+
+int
+bl_cmp(struct bl_node *e1, struct bl_node *e2) {
+ return (strcasecmp(e1->domain, e2->domain));
+}
+
+void
+free_bl(void)
+{
+ struct bl_node *n, *nxt;
+
+ for (n = RB_MIN(bl_tree, &bl_head); n != NULL; n = nxt) {
+ nxt = RB_NEXT(bl_tree, &bl_head, n);
+ RB_REMOVE(bl_tree, &bl_head, n);
+ free(n);
+ }
+}
diff --git a/sbin/unwind/parse.y b/sbin/unwind/parse.y
index c7baa5d725e..6518975e47a 100644
--- a/sbin/unwind/parse.y
+++ b/sbin/unwind/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.4 2019/04/03 03:48:45 florian Exp $ */
+/* $OpenBSD: parse.y,v 1.5 2019/05/10 14:10:38 florian Exp $ */
/*
* Copyright (c) 2018 Florian Obser <florian@openbsd.org>
@@ -102,6 +102,7 @@ typedef struct {
%token STRICT YES NO INCLUDE ERROR
%token FORWARDER DOT PORT CAPTIVE PORTAL URL EXPECTED RESPONSE
%token STATUS AUTO AUTHENTICATION NAME PREFERENCE RECURSOR DHCP
+%token BLOCK LIST
%token <v.string> STRING
%token <v.number> NUMBER
@@ -118,6 +119,7 @@ grammar : /* empty */
| grammar uw_pref '\n'
| grammar uw_forwarder '\n'
| grammar captive_portal '\n'
+ | grammar block_list '\n'
| grammar error '\n' { file->errors++; }
;
@@ -180,6 +182,21 @@ optnl : '\n' optnl /* zero or more newlines */
| /*empty*/
;
+block_list : BLOCK LIST STRING {
+ if (conf->blocklist_file != NULL) {
+ yyerror("block list already "
+ "configured");
+ free($3);
+ YYERROR;
+ } else {
+ conf->blocklist_file = strdup($3);
+ if (conf->blocklist_file == NULL)
+ err(1, "strdup");
+ free($3);
+ }
+ }
+ ;
+
captive_portal : CAPTIVE PORTAL captive_portal_block
;
captive_portal_block : '{' optnl captive_portal_opts_l '}'
@@ -518,12 +535,14 @@ lookup(char *s)
{"DoT", DOT},
{"authentication", AUTHENTICATION},
{"auto", AUTO},
+ {"block", BLOCK},
{"captive", CAPTIVE},
{"dhcp", DHCP},
{"dot", DOT},
{"expected", EXPECTED},
{"forwarder", FORWARDER},
{"include", INCLUDE},
+ {"list", LIST},
{"name", NAME},
{"no", NO},
{"port", PORT},
diff --git a/sbin/unwind/printconf.c b/sbin/unwind/printconf.c
index b368c89cfaf..0c6fa5c5fe1 100644
--- a/sbin/unwind/printconf.c
+++ b/sbin/unwind/printconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: printconf.c,v 1.8 2019/04/02 07:47:22 florian Exp $ */
+/* $OpenBSD: printconf.c,v 1.9 2019/05/10 14:10:38 florian Exp $ */
/*
* Copyright (c) 2018 Florian Obser <florian@openbsd.org>
@@ -109,4 +109,7 @@ print_config(struct uw_conf *conf)
printf("\tauto %s\n", yesno(conf->captive_portal_auto));
printf("}\n");
}
+
+ if (conf->blocklist_file != NULL)
+ printf("block list \"%s\"\n", conf->blocklist_file);
}
diff --git a/sbin/unwind/resolver.c b/sbin/unwind/resolver.c
index 54446a08594..92c781c971b 100644
--- a/sbin/unwind/resolver.c
+++ b/sbin/unwind/resolver.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: resolver.c,v 1.38 2019/05/06 17:31:25 florian Exp $ */
+/* $OpenBSD: resolver.c,v 1.39 2019/05/10 14:10:38 florian Exp $ */
/*
* Copyright (c) 2018 Florian Obser <florian@openbsd.org>
@@ -611,6 +611,13 @@ resolver_dispatch_main(int fd, short event, void *bula)
strdup(imsg.data)) == NULL)
fatal("%s: strdup", __func__);
break;
+ case IMSG_RECONF_BLOCKLIST_FILE:
+ /* make sure this is a string */
+ ((char *)imsg.data)[IMSG_DATA_SIZE(imsg) - 1] = '\0';
+ if ((nconf->blocklist_file = strdup(imsg.data)) ==
+ NULL)
+ fatal("%s: strdup", __func__);
+ break;
case IMSG_RECONF_FORWARDER:
if (IMSG_DATA_SIZE(imsg) != sizeof(struct uw_forwarder))
fatalx("%s: IMSG_RECONF_FORWARDER wrong length:"
diff --git a/sbin/unwind/unwind.c b/sbin/unwind/unwind.c
index 4baf8bd331e..f6d9a6abe44 100644
--- a/sbin/unwind/unwind.c
+++ b/sbin/unwind/unwind.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: unwind.c,v 1.25 2019/05/03 13:02:00 florian Exp $ */
+/* $OpenBSD: unwind.c,v 1.26 2019/05/10 14:10:38 florian Exp $ */
/*
* Copyright (c) 2018 Florian Obser <florian@openbsd.org>
@@ -75,6 +75,7 @@ void open_dhcp_lease(int);
void open_ports(void);
void resolve_captive_portal(void);
void resolve_captive_portal_done(struct asr_result *, void *);
+void send_blocklist_fd(void);
struct uw_conf *main_conf;
struct imsgev *iev_frontend;
@@ -307,6 +308,9 @@ main(int argc, char *argv[])
main_imsg_compose_frontend_fd(IMSG_ROUTESOCK, 0, frontend_routesock);
main_imsg_send_config(main_conf);
+ if (main_conf->blocklist_file != NULL)
+ send_blocklist_fd();
+
if (pledge("stdio inet dns rpath sendfd", NULL) == -1)
fatal("pledge");
@@ -696,6 +700,9 @@ main_reload(void)
merge_config(main_conf, xconf);
+ if (main_conf->blocklist_file != NULL)
+ send_blocklist_fd();
+
return (0);
}
@@ -729,6 +736,13 @@ main_imsg_send_config(struct uw_conf *xconf)
return (-1);
}
+ if (xconf->blocklist_file != NULL) {
+ if (main_sendall(IMSG_RECONF_BLOCKLIST_FILE,
+ xconf->blocklist_file, strlen(xconf->blocklist_file) + 1)
+ == -1)
+ return (-1);
+ }
+
/* send static forwarders to children */
SIMPLEQ_FOREACH(uw_forwarder, &xconf->uw_forwarder_list, entry) {
if (main_sendall(IMSG_RECONF_FORWARDER, uw_forwarder,
@@ -801,6 +815,9 @@ merge_config(struct uw_conf *conf, struct uw_conf *xconf)
conf->captive_portal_auto = xconf->captive_portal_auto;
+ free(conf->blocklist_file);
+ conf->blocklist_file = xconf->blocklist_file;
+
/* Add new forwarders. */
while ((uw_forwarder = SIMPLEQ_FIRST(&xconf->uw_forwarder_list)) !=
NULL) {
@@ -995,3 +1012,14 @@ resolve_captive_portal_done(struct asr_result *ar, void *arg)
freeaddrinfo(ar->ar_addrinfo);
}
+
+void
+send_blocklist_fd(void)
+{
+ int bl_fd;
+
+ if ((bl_fd = open(main_conf->blocklist_file, O_RDONLY)) != -1)
+ main_imsg_compose_frontend_fd(IMSG_BLFD, 0, bl_fd);
+ else
+ log_warn("%s", main_conf->blocklist_file);
+}
diff --git a/sbin/unwind/unwind.conf.5 b/sbin/unwind/unwind.conf.5
index 44fd9feaff7..f87e0bab261 100644
--- a/sbin/unwind/unwind.conf.5
+++ b/sbin/unwind/unwind.conf.5
@@ -1,4 +1,4 @@
-.\" $OpenBSD: unwind.conf.5,v 1.13 2019/04/03 03:48:45 florian Exp $
+.\" $OpenBSD: unwind.conf.5,v 1.14 2019/05/10 14:10:38 florian Exp $
.\"
.\" Copyright (c) 2018 Florian Obser <florian@openbsd.org>
.\" Copyright (c) 2005 Esben Norby <norby@openbsd.org>
@@ -18,7 +18,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: April 3 2019 $
+.Dd $Mdocdate: May 10 2019 $
.Dt UNWIND.CONF 5
.Os
.Sh NAME
@@ -63,6 +63,12 @@ forwarder { $fwd1 $fwd2 }
.Ed
.Sh GLOBAL CONFIGURATION
.Bl -tag -width Ds
+.It Ic block list Ar file
+A file containing domains to block, one per line.
+If a domain from this list is queried
+.Nm unwind
+answers with a return code of
+.Cm refused .
.It Ic captive portal Brq ...
.Nm unwind
can detect when it is running behind a
diff --git a/sbin/unwind/unwind.h b/sbin/unwind/unwind.h
index f5ac2c99353..98e2df710c4 100644
--- a/sbin/unwind/unwind.h
+++ b/sbin/unwind/unwind.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: unwind.h,v 1.14 2019/04/02 07:47:23 florian Exp $ */
+/* $OpenBSD: unwind.h,v 1.15 2019/05/10 14:10:38 florian Exp $ */
/*
* Copyright (c) 2018 Florian Obser <florian@openbsd.org>
@@ -86,6 +86,7 @@ enum imsg_type {
IMSG_RECONF_CAPTIVE_PORTAL_HOST,
IMSG_RECONF_CAPTIVE_PORTAL_PATH,
IMSG_RECONF_CAPTIVE_PORTAL_EXPECTED_RESPONSE,
+ IMSG_RECONF_BLOCKLIST_FILE,
IMSG_RECONF_FORWARDER,
IMSG_RECONF_DOT_FORWARDER,
IMSG_RECONF_END,
@@ -120,6 +121,7 @@ enum imsg_type {
IMSG_NEW_TAS_DONE,
IMSG_RECHECK_RESOLVERS,
IMSG_RESOLVE_CAPTIVE_PORTAL,
+ IMSG_BLFD,
};
struct uw_forwarder {
@@ -139,6 +141,7 @@ struct uw_conf {
char *captive_portal_expected_response;
int captive_portal_expected_status;
int captive_portal_auto;
+ char *blocklist_file;
};
struct query_imsg {