In case you are wondering why happy eyballs: It's a variation on this:
https://en.wikipedia.org/wiki/Happy_Eyeballs
unwind has a concept of a best nameserver type. It considers a
configured DoT nameserver to be better than doing it's own recursive
resolving. Recursive resolving is considered to be better than asking
the dhcp provided nameservers.
It also actively checks the quality of a nameserver. Does it actually
work? Than it's better than an unreachable one. Does it support DNSSEC
validation by passing through the required records, than it's better
than a non-validating one. (The crypto is always done by unwind
itself.)
Now, this is all static. Once it figured out that DoT works and can do
validation, DoT it is. Always. No matter how far away it is.
Or you don't have DoT configured but you can talk unfiltered DNS to
the internet. The recursor will be picked. No matter if you can only
see parts of the internet. Maybe all .org nameservers are unreachable
from your location.
unwind knows about this. It tracks how long it takes to get an answer.
It knows when it can't talk to the .org nameservers. Either the
queries time out or we get a icmp error back. But it doesn't do
anything about it. Because unwind determind (statically) that you are
already using the best nameserver type, why try something else? Well,
because that particular query might be better answerd by a different
nameserver type. Or maybe you are sitting behind a sat link and
everything is terribly slow.
This diff sorts the nameserver types by quality, as above (validation,
resolving, dead...), and as a tie breaker it adds the median of the
round trip time of previous queries into the mix.
Then it considers the whole list, not just the best one. It picks the
top one from the list, sends a query and waits "median" time for an
answer. If none comes in it picks the next one and so on. Eventually
an answer is found (maybe the first one came back, or the 2nd one was
faster) and the answer is send back to the client.
To keep the configured (or default) preference the first resolver type
gets a head start of 200ms.
One other interesting thing about this is that it gets us past captive
portals without a check URL, that's why this diff is so huge, it rips
out all the captive portal stuff (please apply with patch -E):
17 files changed, 385 insertions(+), 1683 deletions(-)
Please test this. I'm particularly interested in reports from people
who move between networks and need to get past captive portals.
diff --git etc/examples/unwind.conf etc/examples/unwind.conf
deleted file mode 100644
index ea60cf9b6ff..00000000000
--- etc/examples/unwind.conf
+++ /dev/null
@@ -1,35 +0,0 @@
-# $OpenBSD: unwind.conf,v 1.1 2019/02/05 16:23:58 florian Exp $
-#
-# unwind(8) works without a configuration file in most cases.
-# See unwind.conf(5) for configuration options.
-
-# Non-exhaustive list of connectivity test providers.
-# To only occasionally run a captive portal check manually from unwindctl(8)
-# add "auto no" to the block.
-#captive portal {
-# url "http://captive.apple.com/"
-# expected response
"<HTML><HEAD><TITLE>Success</TITLE></HEAD><BODY>Success</BODY></HTML>\n"
-# # auto no # uncomment to run manually from unwindctl(8)
-#}
-#captive portal {
-# url "http://clients3.google.com/generate_204"
-# expected status 204
-# # auto no # uncomment to run manually from unwindctl(8)
-#}
-#captive portal {
-# url "http://detectportal.firefox.com/"
-# expected response "success\n"
-# # auto no # uncomment to run manually from unwindctl(8)
-#}
-
-# Running a connectivity test provider with httpd(8).
-# httpd.conf
-#server "c.YOUR-DOMAIN.com" {
-# listen on * port 80
-# location "*" { block return 204 }
-#}
-# unwind.conf
-#captive portal {
-# url "http://c.YOUR-DOMAIN.com/"
-# expected status 204
-#}
diff --git sbin/unwind/Makefile sbin/unwind/Makefile
index b48a14ce4b1..cdc8af97170 100644
--- sbin/unwind/Makefile
+++ sbin/unwind/Makefile
@@ -2,7 +2,6 @@
PROG= unwind
SRCS= control.c resolver.c frontend.c log.c unwind.c parse.y printconf.c
-SRCS+= captiveportal.c
MAN= unwind.8 unwind.conf.5
.include "${.CURDIR}/libunbound/Makefile.inc"
@@ -15,7 +14,7 @@ CFLAGS+= -Wmissing-declarations
CFLAGS+= -Wshadow -Wpointer-arith
CFLAGS+= -Wsign-compare
YFLAGS=
-LDADD+= -levent -lutil -ltls -lssl -lcrypto
-DPADD+= ${LIBEVENT} ${LIBUTIL} ${LIBTLS} ${LIBSSL} ${LIBCRYPTO}
+LDADD+= -levent -lutil -lssl -lcrypto
+DPADD+= ${LIBEVENT} ${LIBUTIL} ${LIBSSL} ${LIBCRYPTO}
.include <bsd.prog.mk>
diff --git sbin/unwind/captiveportal.c sbin/unwind/captiveportal.c
deleted file mode 100644
index 0c7b0c1f207..00000000000
--- sbin/unwind/captiveportal.c
+++ /dev/null
@@ -1,676 +0,0 @@
-/* $OpenBSD: captiveportal.c,v 1.12 2019/05/14 14:51:31 florian Exp $
*/
-
-/*
- * Copyright (c) 2018 Florian Obser <[email protected]>
- * Copyright (c) 2005 Claudio Jeker <[email protected]>
- * Copyright (c) 2004 Esben Norby <[email protected]>
- * Copyright (c) 2003, 2004 Henning Brauer <[email protected]>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/types.h>
-#include <sys/queue.h>
-#include <sys/socket.h>
-#include <sys/syslog.h>
-#include <sys/uio.h>
-
-#include <netinet/in.h>
-#include <net/if.h>
-#include <net/route.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <event.h>
-#include <imsg.h>
-#include <limits.h>
-#include <netdb.h>
-#include <pwd.h>
-#include <signal.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <vis.h>
-
-#include "log.h"
-#include "unwind.h"
-#include "captiveportal.h"
-
-enum http_global_state {
- IDLE,
- READING
-};
-
-enum http_state {
- INIT,
- SENT_QUERY,
- HEADER_READ
-};
-
-struct http_ctx {
- TAILQ_ENTRY(http_ctx) entry;
- struct event ev;
- int fd;
- enum http_state state;
- char *buf;
- size_t bufsz;
- int status;
- int content_length;
-};
-
-__dead void captiveportal_shutdown(void);
-void captiveportal_sig_handler(int, short, void *);
-void captiveportal_startup(void);
-void http_callback(int, short, void *);
-int parse_http_header(struct http_ctx *);
-void check_http_body(struct http_ctx *ctx);
-void free_http_ctx(struct http_ctx *);
-void close_other_http_contexts(struct http_ctx *);
-
-struct uw_conf *captiveportal_conf;
-struct imsgev *iev_main;
-struct imsgev *iev_resolver;
-struct imsgev *iev_frontend;
-
-#define MAX_SERVERS_DNS 8
-enum http_global_state http_global_state = IDLE;
-TAILQ_HEAD(, http_ctx) http_contexts;
-int http_contexts_count;
-
-struct timeval tv = {5, 0};
-
-void
-captiveportal_sig_handler(int sig, short event, void *bula)
-{
- /*
- * Normal signal handler rules don't apply because libevent
- * decouples for us.
- */
-
- switch (sig) {
- case SIGINT:
- case SIGTERM:
- captiveportal_shutdown();
- default:
- fatalx("unexpected signal");
- }
-}
-
-void
-captiveportal(int debug, int verbose)
-{
- struct event ev_sigint, ev_sigterm;
- struct passwd *pw;
-
- captiveportal_conf = config_new_empty();
-
- log_init(debug, LOG_DAEMON);
- log_setverbose(verbose);
-
- if ((pw = getpwnam(UNWIND_USER)) == NULL)
- fatal("getpwnam");
-
- if (chroot(pw->pw_dir) == -1)
- fatal("chroot");
- if (chdir("/") == -1)
- fatal("chdir(\"/\")");
-
- uw_process = PROC_CAPTIVEPORTAL;
- setproctitle("%s", log_procnames[uw_process]);
- log_procinit(log_procnames[uw_process]);
-
- if (setgroups(1, &pw->pw_gid) ||
- setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
- setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
- fatal("can't drop privileges");
-
- if (pledge("stdio recvfd", NULL) == -1)
- fatal("pledge");
-
- event_init();
-
- /* Setup signal handler. */
- signal_set(&ev_sigint, SIGINT, captiveportal_sig_handler, NULL);
- signal_set(&ev_sigterm, SIGTERM, captiveportal_sig_handler, NULL);
- signal_add(&ev_sigint, NULL);
- signal_add(&ev_sigterm, NULL);
- signal(SIGPIPE, SIG_IGN);
- signal(SIGHUP, SIG_IGN);
-
- /* Setup pipe and event handler to the parent process. */
- if ((iev_main = malloc(sizeof(struct imsgev))) == NULL)
- fatal(NULL);
- imsg_init(&iev_main->ibuf, 3);
- iev_main->handler = captiveportal_dispatch_main;
- iev_main->events = EV_READ;
- event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
- iev_main->handler, iev_main);
- event_add(&iev_main->ev, NULL);
-
- TAILQ_INIT(&http_contexts);
-
- event_dispatch();
-
- captiveportal_shutdown();
-}
-
-__dead void
-captiveportal_shutdown(void)
-{
- /* Close pipes. */
- msgbuf_write(&iev_resolver->ibuf.w);
- msgbuf_clear(&iev_resolver->ibuf.w);
- close(iev_resolver->ibuf.fd);
- msgbuf_write(&iev_frontend->ibuf.w);
- msgbuf_clear(&iev_frontend->ibuf.w);
- close(iev_frontend->ibuf.fd);
- msgbuf_write(&iev_main->ibuf.w);
- msgbuf_clear(&iev_main->ibuf.w);
- close(iev_main->ibuf.fd);
-
- config_clear(captiveportal_conf);
-
- free(iev_resolver);
- free(iev_frontend);
- free(iev_main);
-
- log_info("captiveportal exiting");
- exit(0);
-}
-
-int
-captiveportal_imsg_compose_main(int type, pid_t pid, void *data,
- uint16_t datalen)
-{
- return (imsg_compose_event(iev_main, type, 0, pid, -1, data, datalen));
-}
-
-int
-captiveportal_imsg_compose_resolver(int type, pid_t pid, void *data,
- uint16_t datalen)
-{
- return (imsg_compose_event(iev_resolver, type, 0, pid, -1, data,
- datalen));
-}
-
-int
-captiveportal_imsg_compose_frontend(int type, pid_t pid, void *data,
- uint16_t datalen)
-{
- return (imsg_compose_event(iev_frontend, type, 0, pid, -1, data,
- datalen));
-}
-
-void
-captiveportal_dispatch_main(int fd, short event, void *bula)
-{
- static struct uw_conf *nconf;
- struct imsg imsg;
- struct imsgev *iev = bula;
- struct imsgbuf *ibuf = &iev->ibuf;
- struct http_ctx *ctx;
- int n, shut = 0;
-
- if (event & EV_READ) {
- if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
- fatal("imsg_read error");
- if (n == 0) /* Connection closed. */
- shut = 1;
- }
- if (event & EV_WRITE) {
- if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
- fatal("msgbuf_write");
- if (n == 0) /* Connection closed. */
- shut = 1;
- }
-
- for (;;) {
- if ((n = imsg_get(ibuf, &imsg)) == -1)
- fatal("%s: imsg_get error", __func__);
- if (n == 0) /* No more messages. */
- break;
-
- switch (imsg.hdr.type) {
- case IMSG_SOCKET_IPC_RESOLVER:
- /*
- * Setup pipe and event handler to the resolver
- * process.
- */
- if (iev_resolver) {
- fatalx("%s: received unexpected imsg fd "
- "to captiveportal", __func__);
- break;
- }
- if ((fd = imsg.fd) == -1) {
- fatalx("%s: expected to receive imsg fd to "
- "captiveportal but didn't receive any",
- __func__);
- break;
- }
-
- iev_resolver = malloc(sizeof(struct imsgev));
- if (iev_resolver == NULL)
- fatal(NULL);
-
- imsg_init(&iev_resolver->ibuf, fd);
- iev_resolver->handler = captiveportal_dispatch_resolver;
- iev_resolver->events = EV_READ;
-
- event_set(&iev_resolver->ev, iev_resolver->ibuf.fd,
- iev_resolver->events, iev_resolver->handler,
- iev_resolver);
- event_add(&iev_resolver->ev, NULL);
- break;
- case IMSG_SOCKET_IPC_FRONTEND:
- /*
- * Setup pipe and event handler to the frontend
- * process.
- */
- if (iev_frontend) {
- fatalx("%s: received unexpected imsg fd "
- "to frontend", __func__);
- break;
- }
- if ((fd = imsg.fd) == -1) {
- fatalx("%s: expected to receive imsg fd to "
- "frontend but didn't receive any",
- __func__);
- break;
- }
-
- iev_frontend = malloc(sizeof(struct imsgev));
- if (iev_frontend == NULL)
- fatal(NULL);
-
- imsg_init(&iev_frontend->ibuf, fd);
- iev_frontend->handler = captiveportal_dispatch_frontend;
- iev_frontend->events = EV_READ;
-
- event_set(&iev_frontend->ev, iev_frontend->ibuf.fd,
- iev_frontend->events, iev_frontend->handler,
- iev_frontend);
- event_add(&iev_frontend->ev, NULL);
- break;
- case IMSG_RECONF_CONF:
- case IMSG_RECONF_CAPTIVE_PORTAL_HOST:
- case IMSG_RECONF_CAPTIVE_PORTAL_PATH:
- case IMSG_RECONF_CAPTIVE_PORTAL_EXPECTED_RESPONSE:
- case IMSG_RECONF_BLOCKLIST_FILE:
- case IMSG_RECONF_FORWARDER:
- case IMSG_RECONF_DOT_FORWARDER:
- imsg_receive_config(&imsg, &nconf);
- break;
- case IMSG_RECONF_END:
- if (nconf == NULL)
- fatalx("%s: IMSG_RECONF_END without "
- "IMSG_RECONF_CONF", __func__);
- merge_config(captiveportal_conf, nconf);
- nconf = NULL;
- break;
- case IMSG_HTTPSOCK:
- if ((fd = imsg.fd) == -1) {
- fatalx("%s: expected to receive imsg fd to "
- "captiveportal but didn't receive any",
- __func__);
- break;
- }
-
- if (http_global_state == READING ||
- http_contexts_count >= MAX_SERVERS_DNS) {
- /* don't try more servers */
- close(fd);
- break;
- }
-
- if ((ctx = malloc(sizeof(*ctx))) == NULL) {
- close(fd);
- break;
- }
-
- ctx->state = INIT;
- ctx->fd = fd;
- ctx->bufsz = 0;
- ctx->buf = NULL;
- ctx->status = -1;
- ctx->content_length = -1;
-
- event_set(&ctx->ev, fd, EV_READ | EV_WRITE |
- EV_PERSIST, http_callback, ctx);
- event_add(&ctx->ev, &tv);
-
- TAILQ_INSERT_TAIL(&http_contexts, ctx, entry);
-
- http_contexts_count++;
-
- break;
- default:
- log_debug("%s: error handling imsg %d", __func__,
- imsg.hdr.type);
- break;
- }
- imsg_free(&imsg);
- }
- if (!shut)
- imsg_event_add(iev);
- else {
- /* This pipe is dead. Remove its event handler. */
- event_del(&iev->ev);
- event_loopexit(NULL);
- }
-}
-
-void
-captiveportal_dispatch_resolver(int fd, short event, void *bula)
-{
- struct imsgev *iev = bula;
- struct imsgbuf *ibuf = &iev->ibuf;
- struct imsg imsg;
- int n, shut = 0;
-
- if (event & EV_READ) {
- if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
- fatal("imsg_read error");
- if (n == 0) /* Connection closed. */
- shut = 1;
- }
- if (event & EV_WRITE) {
- if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
- fatal("msgbuf_write");
- if (n == 0) /* Connection closed. */
- shut = 1;
- }
-
- for (;;) {
- if ((n = imsg_get(ibuf, &imsg)) == -1)
- fatal("%s: imsg_get error", __func__);
- if (n == 0) /* No more messages. */
- break;
-
- switch (imsg.hdr.type) {
- default:
- log_debug("%s: error handling imsg %d", __func__,
- imsg.hdr.type);
- break;
- }
- imsg_free(&imsg);
- }
- if (!shut)
- imsg_event_add(iev);
- else {
- /* This pipe is dead. Remove its event handler. */
- event_del(&iev->ev);
- event_loopexit(NULL);
- }
-}
-
-void
-captiveportal_dispatch_frontend(int fd, short event, void *bula)
-{
- struct imsgev *iev = bula;
- struct imsgbuf *ibuf = &iev->ibuf;
- struct imsg imsg;
- int n, verbose, shut = 0;
-
- if (event & EV_READ) {
- if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
- fatal("imsg_read error");
- if (n == 0) /* Connection closed. */
- shut = 1;
- }
- if (event & EV_WRITE) {
- if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
- fatal("msgbuf_write");
- if (n == 0) /* Connection closed. */
- shut = 1;
- }
-
- for (;;) {
- if ((n = imsg_get(ibuf, &imsg)) == -1)
- fatal("%s: imsg_get error", __func__);
- if (n == 0) /* No more messages. */
- break;
-
- switch (imsg.hdr.type) {
- case IMSG_CTL_LOG_VERBOSE:
- if (IMSG_DATA_SIZE(imsg) != sizeof(verbose))
- fatalx("%s: IMSG_CTL_LOG_VERBOSE wrong length: "
- "%lu", __func__, IMSG_DATA_SIZE(imsg));
- memcpy(&verbose, imsg.data, sizeof(verbose));
- log_setverbose(verbose);
- break;
- default:
- log_debug("%s: error handling imsg %d", __func__,
- imsg.hdr.type);
- break;
- }
- imsg_free(&imsg);
- }
- if (!shut)
- imsg_event_add(iev);
- else {
- /* This pipe is dead. Remove its event handler. */
- event_del(&iev->ev);
- event_loopexit(NULL);
- }
-}
-
-void
-http_callback(int fd, short events, void *arg)
-{
- struct http_ctx *ctx;
- ssize_t n;
- char *query, buf[512], *vis_str, *p, *ep;
-
- ctx = (struct http_ctx *)arg;
-
- if (events & EV_TIMEOUT) {
- log_debug("%s: TIMEOUT", __func__);
- goto err;
- }
-
- if (events & EV_READ) {
- if ((n = read(fd, buf, sizeof(buf))) == -1) {
- if (errno == EAGAIN || errno == EINTR)
- return;
- else {
- log_warn("%s: read", __func__);
- if (http_global_state == READING)
- http_global_state = IDLE;
- goto err;
- }
- }
-
- if (http_contexts_count > 1)
- close_other_http_contexts(ctx);
- http_global_state = READING;
-
- if (n == 0) {
- check_http_body(ctx);
- return;
- }
- p = recallocarray(ctx->buf, ctx->bufsz, ctx->bufsz + n, 1);
- if (p == NULL) {
- log_warn("%s", __func__);
- goto err;
- }
- ctx->buf = p;
- memcpy(ctx->buf + ctx->bufsz, buf, n);
- ctx->bufsz += n;
-
- if (ctx->state == HEADER_READ && ctx->content_length != -1 &&
- ctx->bufsz >= (size_t)ctx->content_length) {
- check_http_body(ctx);
- return;
- }
-
- if (ctx->state == SENT_QUERY) {
- ep = memmem(ctx->buf, ctx->bufsz, "\r\n\r\n", 4);
- if (ep != NULL) {
- ctx->state = HEADER_READ;
- *ep = '\0';
- if (strlen(ctx->buf) != (uintptr_t)
- (ep - ctx->buf)) {
- log_warnx("binary data in header");
- goto err;
- }
- stravis(&vis_str, ctx->buf,
- VIS_NL | VIS_CSTYLE);
- log_debug("header\n%s", vis_str);
- free(vis_str);
-
- if (parse_http_header(ctx) != 0)
- goto err;
-
- p = ctx->buf;
- ep += 4;
- ctx->bufsz = (ctx->buf + ctx->bufsz) - ep;
- ctx->buf = malloc(ctx->bufsz);
- memcpy(ctx->buf, ep, ctx->bufsz);
- free(p);
- }
- }
- }
-
- if (events & EV_WRITE) {
- if (ctx->state == INIT) {
- n = asprintf(&query,
- "GET %s HTTP/1.1\r\nHost: %s\r\n"
- "Connection: close\r\n\r\n",
- captiveportal_conf->captive_portal_path,
- captiveportal_conf->captive_portal_host);
- write(fd, query, n);
- free(query);
- event_del(&ctx->ev);
- event_set(&ctx->ev, fd, EV_READ | EV_PERSIST,
- http_callback, ctx);
- event_add(&ctx->ev, &tv);
- ctx->state = SENT_QUERY;
- } else {
- log_warnx("invalid state: %d", ctx->state);
- goto err;
- }
- }
- return;
-err:
- free_http_ctx(ctx);
-}
-
-int
-parse_http_header(struct http_ctx *ctx)
-{
- char *p, *ep;
- const char *errstr;
-
- /* scan past HTTP/1.x */
- p = strchr(ctx->buf, ' ');
- if (p == NULL)
- return (1);
- while (isspace((int)*p))
- p++;
- ep = strchr(p, ' ');
- if (ep == NULL)
- return (1);
- *ep = '\0';
- ctx->status = strtonum(p, 100, 599, &errstr);
- if (errstr != NULL) {
- log_warnx("%s: status is %s: %s", __func__, errstr, p);
- return (1);
- }
-
- log_debug("%s: status: %d", __func__, ctx->status);
-
- /* ignore parse errors from here on out, we got the status */
-
- p = strcasestr(ep + 1, "Content-Length:");
- if (p == NULL)
- return (0);
-
- p += sizeof("Content-Length:") - 1;
- while (isspace((int)*p))
- p++;
-
- ep = strchr(p, '\r');
- if (ep == NULL)
- return (0);
-
- *ep = '\0';
- ctx->content_length = strtonum(p, 0, INT_MAX, &errstr);
- if (errstr != NULL) {
- log_warnx("%s: Content-Lenght is %s: %s", __func__, errstr, p);
- ctx->content_length = -1;
- return (0);
- }
- log_debug("content-length: %d", ctx->content_length);
- return (0);
-}
-
-void
-check_http_body(struct http_ctx *ctx)
-{
- enum captive_portal_state state;
- char *p, *vis_str;
-
- p = recallocarray(ctx->buf, ctx->bufsz, ctx->bufsz + 1, 1);
- if (p == NULL) {
- log_warn("%s", __func__);
- free_http_ctx(ctx);
- return;
- }
- ctx->buf = p;
- *(ctx->buf + ctx->bufsz) = '\0';
- ctx->bufsz++;
- stravis(&vis_str, ctx->buf, VIS_NL | VIS_CSTYLE);
- log_debug("body[%ld]\n%s", ctx->bufsz, vis_str);
-
- if (ctx->status == captiveportal_conf->captive_portal_expected_status &&
- strcmp(vis_str,
- captiveportal_conf->captive_portal_expected_response) == 0) {
- log_debug("%s: not behind captive portal", __func__);
- state = NOT_BEHIND;
- } else {
- log_debug("%s: behind captive portal", __func__);
- state = BEHIND;
- }
- captiveportal_imsg_compose_resolver(IMSG_CAPTIVEPORTAL_STATE, 0,
- &state, sizeof(state));
- free_http_ctx(ctx);
- http_global_state = IDLE;
-}
-
-void
-free_http_ctx(struct http_ctx *ctx)
-{
- if (ctx == NULL)
- return;
-
- event_del(&ctx->ev);
- close(ctx->fd);
- TAILQ_REMOVE(&http_contexts, ctx, entry);
- free(ctx->buf);
- free(ctx);
- http_contexts_count--;
-}
-
-void
-close_other_http_contexts(struct http_ctx *octx)
-{
- struct http_ctx *ctx, *t;
-
- log_debug("%s", __func__);
- TAILQ_FOREACH_SAFE(ctx, &http_contexts, entry, t)
- if(ctx != octx)
- free_http_ctx(ctx);
-}
diff --git sbin/unwind/captiveportal.h sbin/unwind/captiveportal.h
deleted file mode 100644
index cee72005e5c..00000000000
--- sbin/unwind/captiveportal.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* $OpenBSD: captiveportal.h,v 1.1 2019/02/03 12:02:30 florian Exp $
*/
-
-/*
- * Copyright (c) 2018 Florian Obser <[email protected]>
- * Copyright (c) 2004, 2005 Esben Norby <[email protected]>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-
-enum captive_portal_state {
- PORTAL_UNCHECKED,
- PORTAL_UNKNOWN,
- BEHIND,
- NOT_BEHIND
-};
-
-static const char * const captive_portal_state_str[] = {
- "unchecked",
- "unknown",
- "behind",
- "not behind"
-};
-
-void captiveportal(int, int);
-void captiveportal_dispatch_main(int, short, void *);
-void captiveportal_dispatch_resolver(int, short, void *);
-void captiveportal_dispatch_frontend(int, short, void *);
-int captiveportal_imsg_compose_main(int, pid_t, void *, uint16_t);
-int captiveportal_imsg_compose_resolver(int, pid_t, void *, uint16_t);
-int captiveportal_imsg_compose_frontend(int, pid_t, void *, uint16_t);
diff --git sbin/unwind/control.c sbin/unwind/control.c
index f2dd612dc46..66c762d891e 100644
--- sbin/unwind/control.c
+++ sbin/unwind/control.c
@@ -259,10 +259,6 @@ control_dispatch_imsg(int fd, short event, void *bula)
case IMSG_CTL_RELOAD:
frontend_imsg_compose_main(imsg.hdr.type, 0, NULL, 0);
break;
- case IMSG_CTL_RECHECK_CAPTIVEPORTAL:
- frontend_imsg_compose_resolver(imsg.hdr.type,
- imsg.hdr.pid, NULL, 0);
- break;
case IMSG_CTL_LOG_VERBOSE:
if (IMSG_DATA_SIZE(imsg) != sizeof(verbose))
break;
@@ -272,8 +268,6 @@ control_dispatch_imsg(int fd, short event, void *bula)
imsg.data, IMSG_DATA_SIZE(imsg));
frontend_imsg_compose_resolver(imsg.hdr.type,
imsg.hdr.pid, imsg.data, IMSG_DATA_SIZE(imsg));
- frontend_imsg_compose_captiveportal(imsg.hdr.type,
- imsg.hdr.pid, imsg.data, IMSG_DATA_SIZE(imsg));
memcpy(&verbose, imsg.data, sizeof(verbose));
log_setverbose(verbose);
diff --git sbin/unwind/frontend.c sbin/unwind/frontend.c
index e81c7b247ef..f1ee3572259 100644
--- sbin/unwind/frontend.c
+++ sbin/unwind/frontend.c
@@ -121,7 +121,6 @@ void free_bl(void);
struct uw_conf *frontend_conf;
struct imsgev *iev_main;
struct imsgev *iev_resolver;
-struct imsgev *iev_captiveportal;
struct event ev_route;
int udp4sock = -1, udp6sock = -1, routesock = -1;
int ta_fd = -1;
@@ -247,9 +246,6 @@ frontend_shutdown(void)
msgbuf_write(&iev_resolver->ibuf.w);
msgbuf_clear(&iev_resolver->ibuf.w);
close(iev_resolver->ibuf.fd);
- msgbuf_write(&iev_captiveportal->ibuf.w);
- msgbuf_clear(&iev_captiveportal->ibuf.w);
- close(iev_captiveportal->ibuf.fd);
msgbuf_write(&iev_main->ibuf.w);
msgbuf_clear(&iev_main->ibuf.w);
close(iev_main->ibuf.fd);
@@ -257,7 +253,6 @@ frontend_shutdown(void)
config_clear(frontend_conf);
free(iev_resolver);
- free(iev_captiveportal);
free(iev_main);
log_info("frontend exiting");
@@ -278,14 +273,6 @@ frontend_imsg_compose_resolver(int type, pid_t pid, void
*data,
datalen));
}
-int
-frontend_imsg_compose_captiveportal(int type, pid_t pid, void *data,
- uint16_t datalen)
-{
- return (imsg_compose_event(iev_captiveportal, type, 0, pid, -1, data,
- datalen));
-}
-
void
frontend_dispatch_main(int fd, short event, void *bula)
{
@@ -345,42 +332,7 @@ frontend_dispatch_main(int fd, short event, void *bula)
iev_resolver);
event_add(&iev_resolver->ev, NULL);
break;
- case IMSG_SOCKET_IPC_CAPTIVEPORTAL:
- /*
- * Setup pipe and event handler to the captiveportal
- * process.
- */
- if (iev_captiveportal) {
- fatalx("%s: received unexpected imsg fd "
- "to frontend", __func__);
- break;
- }
- if ((fd = imsg.fd) == -1) {
- fatalx("%s: expected to receive imsg fd to "
- "frontend but didn't receive any",
- __func__);
- break;
- }
-
- iev_captiveportal = malloc(sizeof(struct imsgev));
- if (iev_captiveportal == NULL)
- fatal(NULL);
-
- imsg_init(&iev_captiveportal->ibuf, fd);
- iev_captiveportal->handler =
- frontend_dispatch_captiveportal;
- iev_captiveportal->events = EV_READ;
-
- event_set(&iev_captiveportal->ev,
- iev_captiveportal->ibuf.fd,
- iev_captiveportal->events,
- iev_captiveportal->handler, iev_captiveportal);
- event_add(&iev_captiveportal->ev, NULL);
- break;
case IMSG_RECONF_CONF:
- case IMSG_RECONF_CAPTIVE_PORTAL_HOST:
- case IMSG_RECONF_CAPTIVE_PORTAL_PATH:
- case IMSG_RECONF_CAPTIVE_PORTAL_EXPECTED_RESPONSE:
case IMSG_RECONF_BLOCKLIST_FILE:
case IMSG_RECONF_FORWARDER:
case IMSG_RECONF_DOT_FORWARDER:
@@ -533,7 +485,6 @@ frontend_dispatch_resolver(int fd, short event, void *bula)
send_answer(pq);
break;
case IMSG_CTL_RESOLVER_INFO:
- case IMSG_CTL_CAPTIVEPORTAL_INFO:
case IMSG_CTL_RESOLVER_WHY_BOGUS:
case IMSG_CTL_RESOLVER_HISTOGRAM:
case IMSG_CTL_AUTOCONF_RESOLVER_INFO:
@@ -579,50 +530,6 @@ frontend_dispatch_resolver(int fd, short event, void *bula)
}
}
-void
-frontend_dispatch_captiveportal(int fd, short event, void *bula)
-{
- struct imsgev *iev = bula;
- struct imsgbuf *ibuf = &iev->ibuf;
- struct imsg imsg;
- int n, shut = 0;
-
- if (event & EV_READ) {
- if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
- fatal("imsg_read error");
- if (n == 0) /* Connection closed. */
- shut = 1;
- }
- if (event & EV_WRITE) {
- if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
- fatal("msgbuf_write");
- if (n == 0) /* Connection closed. */
- shut = 1;
- }
-
- for (;;) {
- if ((n = imsg_get(ibuf, &imsg)) == -1)
- fatal("%s: imsg_get error", __func__);
- if (n == 0) /* No more messages. */
- break;
-
- switch (imsg.hdr.type) {
- default:
- log_debug("%s: error handling imsg %d", __func__,
- imsg.hdr.type);
- break;
- }
- imsg_free(&imsg);
- }
- if (!shut)
- imsg_event_add(iev);
- else {
- /* This pipe is dead. Remove its event handler. */
- event_del(&iev->ev);
- event_loopexit(NULL);
- }
-}
-
void
frontend_startup(void)
{
diff --git sbin/unwind/frontend.h sbin/unwind/frontend.h
index 10ee9952bf9..919c17b0dfb 100644
--- sbin/unwind/frontend.h
+++ sbin/unwind/frontend.h
@@ -35,10 +35,8 @@ struct imsg_rdns_proposal {
void frontend(int, int);
void frontend_dispatch_main(int, short, void *);
void frontend_dispatch_resolver(int, short, void *);
-void frontend_dispatch_captiveportal(int, short, void *);
int frontend_imsg_compose_main(int, pid_t, void *, uint16_t);
int frontend_imsg_compose_resolver(int, pid_t, void *, uint16_t);
-int frontend_imsg_compose_captiveportal(int, pid_t, void *,
uint16_t);
char *ip_port(struct sockaddr *);
void add_new_ta(struct trust_anchor_head *, char *);
void free_tas(struct trust_anchor_head *);
diff --git sbin/unwind/parse.y sbin/unwind/parse.y
index a26f46e6c08..da4ab78fb54 100644
--- sbin/unwind/parse.y
+++ sbin/unwind/parse.y
@@ -98,9 +98,9 @@ typedef struct {
%}
-%token YES NO INCLUDE ERROR
-%token FORWARDER DOT PORT CAPTIVE PORTAL URL EXPECTED RESPONSE
-%token STATUS AUTO AUTHENTICATION NAME PREFERENCE RECURSOR DHCP STUB
+%token INCLUDE ERROR
+%token FORWARDER DOT PORT
+%token AUTHENTICATION NAME PREFERENCE RECURSOR DHCP STUB
%token BLOCK LIST LOG
%token <v.string> STRING
@@ -116,7 +116,6 @@ grammar : /* empty */
| grammar varset '\n'
| grammar uw_pref '\n'
| grammar uw_forwarder '\n'
- | grammar captive_portal '\n'
| grammar block_list '\n'
| grammar error '\n' { file->errors++; }
;
@@ -149,10 +148,6 @@ string : string STRING {
| STRING
;
-yesno : YES { $$ = 1; }
- | NO { $$ = 0; }
- ;
-
varset : STRING '=' string {
char *s = $1;
if (cmd_opts & OPT_VERBOSE)
@@ -194,57 +189,7 @@ block_list : BLOCK LIST STRING log {
}
;
-captive_portal : CAPTIVE PORTAL captive_portal_block
- ;
-captive_portal_block : '{' optnl captive_portal_opts_l '}'
- | captive_portal_optsl
- ;
-
-captive_portal_opts_l : captive_portal_opts_l captive_portal_optsl optnl
- | captive_portal_optsl optnl
- ;
-
-captive_portal_optsl : URL STRING {
- char *ep;
- if (strncmp($2, "http://", 7) != 0) {
- yyerror("only http:// urls are "
- "supported: %s", $2);
- free($2);
- YYERROR;
- }
- if ((ep = strchr($2 + 7, '/')) != NULL) {
- conf->captive_portal_path =
- strdup(ep);
- *ep = '\0';
- } else
- conf->captive_portal_path = strdup("/");
- if (conf->captive_portal_path == NULL)
- err(1, "strdup");
- if ((conf->captive_portal_host =
- strdup($2 + 7)) == NULL)
- err(1, "strdup");
- free($2);
- }
- | EXPECTED RESPONSE STRING {
- if ((conf->captive_portal_expected_response =
- strdup($3)) == NULL)
- err(1, "strdup");
- free($3);
- }
- | EXPECTED STATUS NUMBER {
- if ($3 < 100 || $3 > 599) {
- yyerror("%lld is an invalid http "
- "status", $3);
- YYERROR;
- }
- conf->captive_portal_expected_status = $3;
- }
- | AUTO yesno {
- conf->captive_portal_auto = $2;
- }
- ;
-
-uw_pref : PREFERENCE { conf->res_pref_len = 0; }
pref_block
+uw_pref : PREFERENCE { conf->res_pref.len = 0; }
pref_block
;
pref_block : '{' optnl prefopts_l '}'
@@ -258,11 +203,11 @@ prefopts_l : prefopts_l prefoptsl optnl
prefoptsl : prefopt {
if (!check_pref_uniq($1))
YYERROR;
- if (conf->res_pref_len >= UW_RES_NONE) {
+ if (conf->res_pref.len >= UW_RES_NONE) {
yyerror("preference list too long");
YYERROR;
}
- conf->res_pref[conf->res_pref_len++] = $1;
+ conf->res_pref.types[conf->res_pref.len++] = $1;
}
;
@@ -405,28 +350,19 @@ lookup(char *s)
static const struct keywords keywords[] = {
{"DoT", DOT},
{"authentication", AUTHENTICATION},
- {"auto", AUTO},
{"block", BLOCK},
- {"captive", CAPTIVE},
{"dhcp", DHCP},
{"dot", DOT},
- {"expected", EXPECTED},
{"forwarder", FORWARDER},
{"include", INCLUDE},
{"list", LIST},
{"log", LOG},
{"name", NAME},
- {"no", NO},
{"port", PORT},
- {"portal", PORTAL},
{"preference", PREFERENCE},
{"recursor", RECURSOR},
- {"response", RESPONSE},
- {"status", STATUS},
{"stub", STUB},
{"tls", DOT},
- {"url", URL},
- {"yes", YES},
};
const struct keywords *p;
@@ -936,8 +872,8 @@ check_pref_uniq(enum uw_resolver_type type)
{
int i;
- for (i = 0; i < conf->res_pref_len; i++)
- if (conf->res_pref[i] == type) {
+ for (i = 0; i < conf->res_pref.len; i++)
+ if (conf->res_pref.types[i] == type) {
yyerror("%s is already in the preference list",
uw_resolver_type_str[type]);
return (0);
diff --git sbin/unwind/printconf.c sbin/unwind/printconf.c
index e84a99bfeb6..25f5af81495 100644
--- sbin/unwind/printconf.c
+++ sbin/unwind/printconf.c
@@ -68,10 +68,11 @@ print_config(struct uw_conf *conf)
struct uw_forwarder *uw_forwarder;
int i;
- if (conf->res_pref_len > 0) {
+ if (conf->res_pref.len > 0) {
printf("preference {");
- for (i = 0; i < conf->res_pref_len; i++) {
- printf(" %s", uw_resolver_type_str[conf->res_pref[i]]);
+ for (i = 0; i < conf->res_pref.len; i++) {
+ printf(" %s",
+ uw_resolver_type_str[conf->res_pref.types[i]]);
}
printf(" }\n");
}
@@ -93,19 +94,6 @@ print_config(struct uw_conf *conf)
printf("}\n");
}
- if (conf->captive_portal_host != NULL) {
- printf("captive portal {\n");
- printf("\turl \"http://%s%s\"\n", conf->captive_portal_host,
- conf->captive_portal_path);
- printf("\texpected status %d\n",
- conf->captive_portal_expected_status);
- if (conf->captive_portal_expected_response != NULL)
- printf("\texpected response \"%s\"\n",
- conf->captive_portal_expected_response);
- printf("\tauto %s\n", yesno(conf->captive_portal_auto));
- printf("}\n");
- }
-
if (conf->blocklist_file != NULL)
printf("block list \"%s\"%s\n", conf->blocklist_file,
conf->blocklist_log ? " log" : "");
diff --git sbin/unwind/resolver.c sbin/unwind/resolver.c
index 39bee165c87..1a576bdbb71 100644
--- sbin/unwind/resolver.c
+++ sbin/unwind/resolver.c
@@ -54,21 +54,26 @@
#include <openssl/crypto.h>
-#include "captiveportal.h"
#include "log.h"
#include "frontend.h"
#include "unwind.h"
#include "resolver.h"
+#define TLS_DEFAULT_CA_CERT_FILE "/etc/ssl/cert.pem"
#define UB_LOG_VERBOSE 4
#define UB_LOG_BRIEF 0
+/*
+ * The prefered resolver type can be this many ms slower than the next
+ * best and still be picked
+ */
+#define PREF_RESOLVER_MEDIAN_SKEW 200 /* 200 ms */
+
+#define DOUBT_NXDOMAIN_SEC 5 * 60 /* 5 minutes */
+
#define RESOLVER_CHECK_SEC 1
#define RESOLVER_CHECK_MAXSEC 1024 /* ~17 minutes */
-#define PORTAL_CHECK_SEC 15
-#define PORTAL_CHECK_MAXSEC 600
-
#define TRUST_ANCHOR_RETRY_INTERVAL 8640
#define TRUST_ANCHOR_QUERY_INTERVAL 43200
@@ -91,8 +96,21 @@ struct uw_resolver {
int check_running;
char *why_bogus;
int64_t histogram[nitems(histogram_limits)];
+ int64_t latest_histogram[nitems(histogram_limits)];
};
+struct running_query {
+ TAILQ_ENTRY(running_query) entry;
+ struct query_imsg *query_imsg;
+ struct event timer_ev;
+ struct timespec tp;
+ struct resolver_preference res_pref;
+ int next_resolver;
+ int running;
+};
+
+TAILQ_HEAD(, running_query) running_queries;
+
typedef void (*resolve_cb_t)(struct uw_resolver *, void *, int, void *, int,
int, char *);
@@ -105,8 +123,13 @@ struct resolver_cb_data {
__dead void resolver_shutdown(void);
void resolver_sig_handler(int sig, short, void *);
void resolver_dispatch_frontend(int, short, void *);
-void resolver_dispatch_captiveportal(int, short, void *);
void resolver_dispatch_main(int, short, void *);
+int sort_resolver_types(struct resolver_preference *);
+void setup_query(struct query_imsg *);
+struct running_query *find_running_query(uint64_t);
+void try_resolver_timo(int, short, void *);
+int try_next_resolver(struct running_query *);
+
int resolve(struct uw_resolver *, const char*, int, int,
void*, resolve_cb_t);
void resolve_done(struct uw_resolver *, void *, int, void *,
@@ -137,22 +160,14 @@ void replace_forwarders(struct
uw_forwarder_head *,
struct uw_forwarder_head *);
void resolver_ref(struct uw_resolver *);
void resolver_unref(struct uw_resolver *);
-struct uw_resolver *best_resolver(void);
-int resolver_cmp(struct uw_resolver *,
- struct uw_resolver *);
+int resolver_cmp(const void *, const void *);
void restart_resolvers(void);
void show_status(enum uw_resolver_type, pid_t);
-void send_resolver_info(struct uw_resolver *, int, pid_t);
+void send_resolver_info(struct uw_resolver *, pid_t);
void send_detailed_resolver_info(struct uw_resolver *,
pid_t);
void send_resolver_histogram_info(struct uw_resolver *,
pid_t);
-void check_captive_portal(int);
-void check_captive_portal_timo(int, short, void *);
-int check_captive_portal_changed(struct uw_conf *,
- struct uw_conf *);
-void captive_portal_resolve_done(struct uw_resolver *,
- void *, int, void *, int, int, char *);
void trust_anchor_resolve(void);
void trust_anchor_timo(int, short, void *);
void trust_anchor_resolve_done(struct uw_resolver *, void *,
@@ -161,16 +176,14 @@ void
replace_autoconf_forwarders(struct
imsg_rdns_proposal *);
struct uw_forwarder *find_forwarder(struct uw_forwarder_head *,
const char *);
+int64_t histogram_median(int64_t *);
struct uw_conf *resolver_conf;
struct imsgev *iev_frontend;
-struct imsgev *iev_captiveportal;
struct imsgev *iev_main;
struct uw_forwarder_head autoconf_forwarder_list;
struct uw_resolver *resolvers[UW_RES_NONE];
-struct timeval captive_portal_check_tv =
- {PORTAL_CHECK_SEC, 0};
-struct event captive_portal_check_ev;
+struct timespec last_network_change;
struct event trust_anchor_timer;
@@ -178,8 +191,6 @@ static struct trust_anchor_head trust_anchors,
new_trust_anchors;
struct event_base *ev_base;
-enum captive_portal_state captive_portal_state = PORTAL_UNCHECKED;
-
static const char * const as112_zones[] = {
/* RFC1918 */
"10.in-addr.arpa. transparent",
@@ -318,7 +329,7 @@ resolver(int debug, int verbose)
setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
fatal("can't drop privileges");
- if (unveil(tls_default_ca_cert_file(), "r") == -1)
+ if (unveil(TLS_DEFAULT_CA_CERT_FILE, "r") == -1)
fatal("unveil");
if (pledge("stdio inet dns rpath recvfd", NULL) == -1)
@@ -347,14 +358,16 @@ resolver(int debug, int verbose)
iev_main->handler, iev_main);
event_add(&iev_main->ev, NULL);
- evtimer_set(&captive_portal_check_ev, check_captive_portal_timo, NULL);
evtimer_set(&trust_anchor_timer, trust_anchor_timo, NULL);
+ clock_gettime(CLOCK_MONOTONIC, &last_network_change);
+
new_recursor();
TAILQ_INIT(&autoconf_forwarder_list);
TAILQ_INIT(&trust_anchors);
TAILQ_INIT(&new_trust_anchors);
+ TAILQ_INIT(&running_queries);
event_dispatch();
@@ -369,15 +382,12 @@ resolver_shutdown(void)
/* Close pipes. */
msgbuf_clear(&iev_frontend->ibuf.w);
close(iev_frontend->ibuf.fd);
- msgbuf_clear(&iev_captiveportal->ibuf.w);
- close(iev_captiveportal->ibuf.fd);
msgbuf_clear(&iev_main->ibuf.w);
close(iev_main->ibuf.fd);
config_clear(resolver_conf);
free(iev_frontend);
- free(iev_captiveportal);
free(iev_main);
log_info("resolver exiting");
@@ -398,14 +408,6 @@ resolver_imsg_compose_frontend(int type, pid_t pid, void
*data,
data, datalen));
}
-int
-resolver_imsg_compose_captiveportal(int type, pid_t pid, void *data,
- uint16_t datalen)
-{
- return (imsg_compose_event(iev_captiveportal, type, 0, pid, -1,
- data, datalen));
-}
-
void
resolver_dispatch_frontend(int fd, short event, void *bula)
{
@@ -413,11 +415,10 @@ resolver_dispatch_frontend(int fd, short event, void
*bula)
struct imsgbuf *ibuf;
struct imsg imsg;
struct query_imsg *query_imsg;
- struct uw_resolver *res;
enum uw_resolver_type type;
ssize_t n;
int shut = 0, verbose;
- int update_resolvers;
+ int update_resolvers, i;
char *ta;
ibuf = &iev->ibuf;
@@ -468,23 +469,7 @@ resolver_dispatch_frontend(int fd, short event, void *bula)
log_debug("%s: IMSG_QUERY[%llu], qname: %s, t: %d, "
"c: %d", __func__, query_imsg->id,
query_imsg->qname, query_imsg->t, query_imsg->c);
-
- res = best_resolver();
-
- if (res == NULL) {
- log_warnx("can't find working resolver");
- free(query_imsg);
- break;
- }
-
- log_debug("%s: choosing %s", __func__,
- uw_resolver_type_str[res->type]);
-
- clock_gettime(CLOCK_MONOTONIC, &query_imsg->tp);
-
- if (resolve(res, query_imsg->qname, query_imsg->t,
- query_imsg->c, query_imsg, resolve_done) != 0)
- free(query_imsg);
+ setup_query(query_imsg);
break;
case IMSG_CTL_STATUS:
if (IMSG_DATA_SIZE(imsg) != sizeof(type))
@@ -493,9 +478,6 @@ resolver_dispatch_frontend(int fd, short event, void *bula)
memcpy(&type, imsg.data, sizeof(type));
show_status(type, imsg.hdr.pid);
break;
- case IMSG_CTL_RECHECK_CAPTIVEPORTAL:
- check_captive_portal(1);
- break;
case IMSG_NEW_TA:
/* make sure this is a string */
((char *)imsg.data)[IMSG_DATA_SIZE(imsg) - 1] = '\0';
@@ -517,7 +499,15 @@ resolver_dispatch_frontend(int fd, short event, void *bula)
}
break;
case IMSG_NETWORK_CHANGED:
+ clock_gettime(CLOCK_MONOTONIC, &last_network_change);
schedule_recheck_all_resolvers();
+ for (i = 0; i < UW_RES_NONE; i++) {
+ if (resolvers[i] == NULL)
+ continue;
+ memset(resolvers[i]->latest_histogram, 0,
+ sizeof(resolvers[i]->latest_histogram));
+ }
+
break;
case IMSG_REPLACE_DNS:
if (IMSG_DATA_SIZE(imsg) !=
@@ -543,70 +533,6 @@ resolver_dispatch_frontend(int fd, short event, void *bula)
}
}
-void
-resolver_dispatch_captiveportal(int fd, short event, void *bula)
-{
- struct imsgev *iev = bula;
- struct imsgbuf *ibuf;
- struct imsg imsg;
- ssize_t n;
- int shut = 0;
-
-
- ibuf = &iev->ibuf;
-
- if (event & EV_READ) {
- if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
- fatal("imsg_read error");
- if (n == 0) /* Connection closed. */
- shut = 1;
- }
- if (event & EV_WRITE) {
- if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
- fatal("msgbuf_write");
- if (n == 0) /* Connection closed. */
- shut = 1;
- }
-
- for (;;) {
- if ((n = imsg_get(ibuf, &imsg)) == -1)
- fatal("%s: imsg_get error", __func__);
- if (n == 0) /* No more messages. */
- break;
-
- switch (imsg.hdr.type) {
- case IMSG_CAPTIVEPORTAL_STATE:
- if (IMSG_DATA_SIZE(imsg) !=
- sizeof(captive_portal_state))
- fatalx("%s: IMSG_CAPTIVEPORTAL_STATE wrong "
- "length: %lu", __func__,
- IMSG_DATA_SIZE(imsg));
- memcpy(&captive_portal_state, imsg.data,
- sizeof(captive_portal_state));
- log_debug("%s: IMSG_CAPTIVEPORTAL_STATE: %s", __func__,
- captive_portal_state_str[captive_portal_state]);
-
- if (captive_portal_state == NOT_BEHIND) {
- evtimer_del(&captive_portal_check_ev);
- schedule_recheck_all_resolvers();
- }
- break;
- default:
- log_debug("%s: unexpected imsg %d", __func__,
- imsg.hdr.type);
- break;
- }
- imsg_free(&imsg);
- }
- if (!shut)
- imsg_event_add(iev);
- else {
- /* This pipe is dead. Remove its event handler. */
- event_del(&iev->ev);
- event_loopexit(NULL);
- }
-}
-
void
resolver_dispatch_main(int fd, short event, void *bula)
{
@@ -617,7 +543,6 @@ resolver_dispatch_main(int fd, short event, void *bula)
ssize_t n;
int shut = 0, forwarders_changed;
int dot_forwarders_changed;
- int captive_portal_changed;
ibuf = &iev->ibuf;
@@ -667,42 +592,12 @@ resolver_dispatch_main(int fd, short event, void *bula)
iev_frontend);
event_add(&iev_frontend->ev, NULL);
break;
- case IMSG_SOCKET_IPC_CAPTIVEPORTAL:
- /*
- * Setup pipe and event handler to the captiveportal
- * process.
- */
- if (iev_captiveportal)
- fatalx("%s: received unexpected imsg fd "
- "to resolver", __func__);
- if ((fd = imsg.fd) == -1)
- fatalx("%s: expected to receive imsg fd to "
- "resolver but didn't receive any", __func__);
-
- iev_captiveportal = malloc(sizeof(struct imsgev));
- if (iev_captiveportal == NULL)
- fatal(NULL);
-
- imsg_init(&iev_captiveportal->ibuf, fd);
- iev_captiveportal->handler =
- resolver_dispatch_captiveportal;
- iev_captiveportal->events = EV_READ;
-
- event_set(&iev_captiveportal->ev,
- iev_captiveportal->ibuf.fd,
- iev_captiveportal->events, iev_captiveportal->handler,
- iev_captiveportal);
- event_add(&iev_captiveportal->ev, NULL);
- break;
case IMSG_STARTUP:
if (pledge("stdio inet dns rpath", NULL) == -1)
fatal("pledge");
break;
case IMSG_RECONF_CONF:
- case IMSG_RECONF_CAPTIVE_PORTAL_HOST:
- case IMSG_RECONF_CAPTIVE_PORTAL_PATH:
- case IMSG_RECONF_CAPTIVE_PORTAL_EXPECTED_RESPONSE:
case IMSG_RECONF_BLOCKLIST_FILE:
case IMSG_RECONF_FORWARDER:
case IMSG_RECONF_DOT_FORWARDER:
@@ -718,8 +613,6 @@ resolver_dispatch_main(int fd, short event, void *bula)
dot_forwarders_changed = check_forwarders_changed(
&resolver_conf->uw_dot_forwarder_list,
&nconf->uw_dot_forwarder_list);
- captive_portal_changed = check_captive_portal_changed(
- resolver_conf, nconf);
merge_config(resolver_conf, nconf);
nconf = NULL;
if (forwarders_changed) {
@@ -730,14 +623,6 @@ resolver_dispatch_main(int fd, short event, void *bula)
log_debug("static DoT forwarders changed");
new_static_dot_forwarders();
}
- if (captive_portal_changed) {
- if (resolver_conf->captive_portal_auto)
- check_captive_portal(1);
- else {
- captive_portal_state = PORTAL_UNCHECKED;
- schedule_recheck_all_resolvers();
- }
- }
break;
default:
log_debug("%s: unexpected imsg %d", __func__,
@@ -755,6 +640,142 @@ resolver_dispatch_main(int fd, short event, void *bula)
}
}
+int
+sort_resolver_types(struct resolver_preference *dst)
+{
+ memcpy(dst, &resolver_conf->res_pref, sizeof(*dst));
+ /*
+ * Sort by resolver quality, validating > resolving etc.
+ * mergesort is stable and keeps the configured preference order
+ */
+
+ return mergesort(dst->types, dst->len, sizeof(dst->types[0]),
+ resolver_cmp);
+}
+
+void
+setup_query(struct query_imsg *query_imsg)
+{
+ struct running_query *rq;
+ int i;
+
+ if (find_running_query(query_imsg->id) != NULL) {
+ free(query_imsg);
+ return;
+ }
+
+ if ((rq = calloc(1, sizeof(*rq))) == NULL) {
+ log_warnx(NULL);
+ free(query_imsg);
+ return;
+ }
+
+ clock_gettime(CLOCK_MONOTONIC, &rq->tp);
+ rq->query_imsg = query_imsg;
+ rq->next_resolver = 0;
+
+ if (sort_resolver_types(&rq->res_pref) == -1) {
+ log_warn("mergesort");
+ free(rq->query_imsg);
+ free(rq);
+ return;
+ }
+
+ for (i = 0; i < rq->res_pref.len; i++) {
+ if (resolvers[rq->res_pref.types[i]] == NULL)
+ continue;
+ log_debug("%s: %s[%s] %lldms", __func__,
+ uw_resolver_type_str[rq->res_pref.types[i]],
+ uw_resolver_state_str[resolvers[rq->res_pref.types[i]]
+ ->state], histogram_median(resolvers[rq->res_pref.types[i]]
+ ->latest_histogram));
+ }
+
+ evtimer_set(&rq->timer_ev, try_resolver_timo, rq);
+
+ TAILQ_INSERT_TAIL(&running_queries, rq, entry);
+ try_next_resolver(rq);
+}
+
+struct running_query *
+find_running_query(uint64_t id)
+{
+ struct running_query *rq;
+
+ TAILQ_FOREACH(rq, &running_queries, entry) {
+ if (rq->query_imsg->id == id)
+ return rq;
+ }
+ return NULL;
+}
+
+void
+try_resolver_timo(int fd, short events, void *arg)
+{
+ struct running_query *rq = arg;
+
+ try_next_resolver(rq);
+}
+
+int
+try_next_resolver(struct running_query *rq)
+{
+ struct uw_resolver *res = NULL;
+ struct query_imsg *query_imsg = NULL;
+ struct timespec tp, elapsed;
+ struct timeval tv = {0, 0};
+ int64_t ms;
+
+ while(rq->next_resolver < rq->res_pref.len &&
+ (res=resolvers[rq->res_pref.types[rq->next_resolver]]) == NULL)
+ rq->next_resolver++;
+
+ if (res == NULL) {
+ evtimer_del(&rq->timer_ev); /* we are not going to find one */
+ log_warnx("%s: could not find working resolver", __func__);
+ goto err;
+ }
+
+ rq->next_resolver++;
+ clock_gettime(CLOCK_MONOTONIC, &tp);
+ timespecsub(&tp, &rq->tp, &elapsed);
+ ms = elapsed.tv_sec * 1000 + elapsed.tv_nsec / 1000000;
+
+ log_debug("%s[+%lldms]: %s[%s]", __func__, ms,
+ uw_resolver_type_str[res->type], uw_resolver_state_str[res->state]);
+ if ((query_imsg = malloc(sizeof(*query_imsg))) == NULL) {
+ log_warnx("%s", __func__);
+ goto err;
+ }
+ memcpy(query_imsg, rq->query_imsg, sizeof(*query_imsg));
+ clock_gettime(CLOCK_MONOTONIC, &query_imsg->tp);
+
+ if (res->type == resolver_conf->res_pref.types[0])
+ tv.tv_usec = 1000 * (PREF_RESOLVER_MEDIAN_SKEW +
+ histogram_median(res->latest_histogram));
+ else
+ tv.tv_usec = 1000 * histogram_median(res->latest_histogram);
+
+ evtimer_add(&rq->timer_ev, &tv);
+
+ if (resolve(res, query_imsg->qname, query_imsg->t,
+ query_imsg->c, query_imsg, resolve_done) != 0)
+ goto err;
+ rq->running++;
+
+ return 0;
+
+ err:
+ free(query_imsg);
+ if (rq->running == 0) {
+ TAILQ_REMOVE(&running_queries, rq, entry);
+ evtimer_del(&rq->timer_ev);
+ free(rq->query_imsg);
+ free(rq);
+ }
+ return 1;
+}
+
int
resolve(struct uw_resolver *res, const char* name, int rrtype, int rrclass,
void *mydata, resolve_cb_t cb)
@@ -811,20 +832,25 @@ void
resolve_done(struct uw_resolver *res, void *arg, int rcode,
void *answer_packet, int answer_len, int sec, char *why_bogus)
{
+ struct ub_result *result = NULL;
+ sldns_buffer *buf = NULL;
+ struct regional *region = NULL;
struct query_imsg *query_imsg;
+ struct running_query *rq;
struct timespec tp, elapsed;
int64_t ms;
size_t i;
+ int asr_pref_pos = -1;
char *str;
+ char rcode_buf[16];
clock_gettime(CLOCK_MONOTONIC, &tp);
query_imsg = (struct query_imsg *)arg;
+ rq = find_running_query(query_imsg->id);
timespecsub(&tp, &query_imsg->tp, &elapsed);
- log_debug("elapsed: %lld.%ld", elapsed.tv_sec, elapsed.tv_nsec);
-
ms = elapsed.tv_sec * 1000 + elapsed.tv_nsec / 1000000;
for (i = 0; i < nitems(histogram_limits); i++) {
@@ -833,14 +859,10 @@ resolve_done(struct uw_resolver *res, void *arg, int
rcode,
}
if (i == nitems(histogram_limits))
log_debug("histogram bucket error");
- else
+ else {
res->histogram[i]++;
-
- log_debug("%s: ref_cnt: %d, elapsed: %lldms, "
- "histogram: %lld - %lld", __func__, res->ref_cnt, ms,
- histogram_limits[i], res->histogram[i]);
-
- log_debug("%s: rcode: %d", __func__, rcode);
+ res->latest_histogram[i]++;
+ }
if (answer_len < LDNS_HEADER_SIZE) {
log_warnx("bad packet: too short");
@@ -853,32 +875,122 @@ resolve_done(struct uw_resolver *res, void *arg, int
rcode,
goto servfail;
}
+ if ((result = calloc(1, sizeof(*result))) == NULL)
+ goto servfail;
+ if ((buf = sldns_buffer_new(answer_len)) == NULL)
+ goto servfail;
+ if ((region = regional_create()) == NULL)
+ goto servfail;
+
+ result->rcode = LDNS_RCODE_SERVFAIL;
+
+ sldns_buffer_clear(buf);
+ sldns_buffer_write(buf, answer_packet, answer_len);
+ sldns_buffer_flip(buf);
+ libworker_enter_result(result, buf, region, sec);
+ result->answer_packet = NULL;
+ result->answer_len = 0;
+
+ sldns_wire2str_rcode_buf(result->rcode, rcode_buf, sizeof(rcode_buf));
+ log_debug("%s[%s]: rcode: %s[%d], elapsed: %lldms, "
+ "histogram: %lld - %lld", __func__, uw_resolver_type_str[res->type],
+ rcode_buf, result->rcode, ms, histogram_limits[i],
+ res->histogram[i]);
+
+ if (result->rcode == LDNS_RCODE_NXDOMAIN && res->type != UW_RES_ASR) {
+ timespecsub(&tp, &last_network_change, &elapsed);
+ if (elapsed.tv_sec < DOUBT_NXDOMAIN_SEC) {
+ /*
+ * Doubt NXDOMAIN if we just switched networks,
+ * we might be behind a captive portal.
+ */
+ log_debug("%s: doubt NXDOMAIN from %s", __func__,
+ uw_resolver_type_str[res->type]);
+ if (rq) {
+ /* search for ASR */
+ for (i = 0; i < (size_t)rq->res_pref.len; i++)
+ if (rq->res_pref.types[i] ==
+ UW_RES_ASR) {
+ asr_pref_pos = i;
+ break;
+ }
+
+ if (asr_pref_pos != -1) {
+ /* go to ASR if not yet scheduled */
+ if (asr_pref_pos >= rq->next_resolver &&
+ resolvers[UW_RES_ASR] != NULL) {
+ rq->next_resolver =
+ asr_pref_pos;
+ goto retry;
+ } else
+ goto out;
+ }
+ log_debug("%s: answering NXDOMAIN, couldn't "
+ "find working ASR", __func__);
+ }
+ } else
+ log_debug("%s: answering NXDOMAIN, network change "
+ "%llds ago", __func__, elapsed.tv_sec);
+ }
+
if ((str = sldns_wire2str_pkt(answer_packet, answer_len)) != NULL) {
log_debug("%s", str);
free(str);
}
+ if (result->rcode == LDNS_RCODE_SERVFAIL)
+ goto servfail;
+
query_imsg->err = 0;
if (res->state == VALIDATING)
query_imsg->bogus = sec == BOGUS;
else
query_imsg->bogus = 0;
- resolver_imsg_compose_frontend(IMSG_ANSWER_HEADER, 0, query_imsg,
- sizeof(*query_imsg));
- /* XXX imsg overflow */
- resolver_imsg_compose_frontend(IMSG_ANSWER, 0,
- answer_packet, answer_len);
+ if (rq) {
+ rq->running--;
+ resolver_imsg_compose_frontend(IMSG_ANSWER_HEADER, 0,
+ query_imsg, sizeof(*query_imsg));
+
+ /* XXX imsg overflow */
+ resolver_imsg_compose_frontend(IMSG_ANSWER, 0, answer_packet,
+ answer_len);
+
+ TAILQ_REMOVE(&running_queries, rq, entry);
+ evtimer_del(&rq->timer_ev);
+ free(rq->query_imsg);
+ free(rq);
+ }
free(query_imsg);
+ sldns_buffer_free(buf);
+ regional_destroy(region);
+ ub_resolve_free(result);
+
return;
-servfail:
- query_imsg->err = -4; /* UB_SERVFAIL */
- resolver_imsg_compose_frontend(IMSG_ANSWER_HEADER, 0, query_imsg,
- sizeof(*query_imsg));
+ servfail:
+ if (rq) {
+ rq->running--;
+ if (try_next_resolver(rq) != 0 && rq->running == 0) {
+ /* we are the last one, send SERVFAIL */
+ query_imsg->err = -4; /* UB_SERVFAIL */
+ resolver_imsg_compose_frontend(IMSG_ANSWER_HEADER, 0,
+ query_imsg, sizeof(*query_imsg));
+ }
+ }
+ goto out;
+ retry:
+ if (rq) {
+ rq->running--;
+ try_next_resolver(rq);
+ }
+ out:
free(query_imsg);
+ sldns_buffer_free(buf);
+ regional_destroy(region);
+ ub_resolve_free(result);
}
void
@@ -1087,7 +1199,7 @@ create_resolver(enum uw_resolver_type type, int oppdot)
set_forwarders_oppdot(res, &autoconf_forwarder_list,
853);
ub_ctx_set_option(res->ctx, "tls-cert-bundle:",
- tls_default_ca_cert_file());
+ TLS_DEFAULT_CA_CERT_FILE);
ub_ctx_set_tls(res->ctx, 1);
} else {
set_forwarders_oppdot(res, &autoconf_forwarder_list,
@@ -1100,7 +1212,7 @@ create_resolver(enum uw_resolver_type type, int oppdot)
set_forwarders_oppdot(res,
&resolver_conf->uw_forwarder_list, 853);
ub_ctx_set_option(res->ctx, "tls-cert-bundle:",
- tls_default_ca_cert_file());
+ TLS_DEFAULT_CA_CERT_FILE);
ub_ctx_set_tls(res->ctx, 1);
} else
set_forwarders_oppdot(res,
@@ -1109,7 +1221,7 @@ create_resolver(enum uw_resolver_type type, int oppdot)
case UW_RES_DOT:
set_forwarders(res, &resolver_conf->uw_dot_forwarder_list);
ub_ctx_set_option(res->ctx, "tls-cert-bundle:",
- tls_default_ca_cert_file());
+ TLS_DEFAULT_CA_CERT_FILE);
ub_ctx_set_tls(res->ctx, 1);
break;
default:
@@ -1471,75 +1583,40 @@ replace_forwarders(struct uw_forwarder_head *new_list,
struct
}
}
-struct uw_resolver*
-best_resolver(void)
-{
- struct uw_resolver *res = NULL;
- int i;
-
- log_debug("%s: %s: %s, %s: %s%s, %s: %s%s, %s: %s, %s: %s, "
- "captive_portal: %s",
- __func__,
- uw_resolver_type_str[UW_RES_RECURSOR], resolvers[UW_RES_RECURSOR]
- != NULL ? uw_resolver_state_str[resolvers[UW_RES_RECURSOR]->state]
- : "NA",
- uw_resolver_type_str[UW_RES_DHCP], resolvers[UW_RES_DHCP] != NULL ?
- uw_resolver_state_str[resolvers[UW_RES_DHCP]->state] : "NA",
- resolvers[UW_RES_DHCP] != NULL &&
- resolvers[UW_RES_DHCP]->oppdot ? " (OppDot)" : "",
- uw_resolver_type_str[UW_RES_FORWARDER],
- resolvers[UW_RES_FORWARDER] != NULL ?
- uw_resolver_state_str[resolvers[UW_RES_FORWARDER]->state] : "NA",
- resolvers[UW_RES_FORWARDER] != NULL &&
- resolvers[UW_RES_FORWARDER]->oppdot ? " (OppDot)" : "",
- uw_resolver_type_str[UW_RES_DOT],
- resolvers[UW_RES_DOT] != NULL ?
- uw_resolver_state_str[resolvers[UW_RES_DOT]->state] : "NA",
- uw_resolver_type_str[UW_RES_ASR],
- resolvers[UW_RES_ASR] != NULL ?
- uw_resolver_state_str[resolvers[UW_RES_ASR]->state] : "NA",
- captive_portal_state_str[captive_portal_state]);
-
- if (captive_portal_state == PORTAL_UNKNOWN || captive_portal_state ==
- BEHIND) {
- if (resolvers[UW_RES_ASR] != NULL && resolvers[UW_RES_ASR]->
- state != DEAD) {
- res = resolvers[UW_RES_ASR];
- goto out;
- }
- }
-
- res = resolvers[resolver_conf->res_pref[0]];
-
- for (i = 1; i < resolver_conf->res_pref_len; i++)
- if (resolver_cmp(res,
- resolvers[resolver_conf->res_pref[i]]) < 0)
- res = resolvers[resolver_conf->res_pref[i]];
-out:
- if (res != NULL)
- log_debug("%s: %s state: %s%s", __func__,
- uw_resolver_type_str[res->type],
- uw_resolver_state_str[res->state],
- res->oppdot ? " (OppDoT)" : "");
- else
- log_debug("%s: non found", __func__);
-
- return (res);
-}
-
int
-resolver_cmp(struct uw_resolver *a, struct uw_resolver *b)
+resolver_cmp(const void *_a, const void *_b)
{
- if (a == NULL && b == NULL)
+ const enum uw_resolver_type a = *(const enum uw_resolver_type *)_a;
+ const enum uw_resolver_type b = *(const enum uw_resolver_type *)_b;
+ int64_t a_median, b_median;
+
+ if (resolvers[a] == NULL && resolvers[b] == NULL)
return 0;
- if (b == NULL)
+ if (resolvers[b] == NULL)
+ return -1;
+
+ if (resolvers[a] == NULL)
return 1;
- if (a == NULL)
+ if (resolvers[a]->state < resolvers[b]->state)
+ return 1;
+ else if (resolvers[a]->state > resolvers[b]->state)
return -1;
-
- return (a->state < b->state ? -1 : a->state > b->state ? 1 : 0);
+ else {
+ a_median = histogram_median(resolvers[a]->latest_histogram);
+ b_median = histogram_median(resolvers[b]->latest_histogram);
+ if (resolvers[a]->type == resolver_conf->res_pref.types[0])
+ a_median -= PREF_RESOLVER_MEDIAN_SKEW;
+ else if (resolvers[b]->type == resolver_conf->res_pref.types[0])
+ b_median -= PREF_RESOLVER_MEDIAN_SKEW;
+ if (a_median < b_median)
+ return -1;
+ else if (a_median > b_median)
+ return 1;
+ else
+ return 0;
+ }
}
void
@@ -1561,22 +1638,19 @@ restart_resolvers(void)
void
show_status(enum uw_resolver_type type, pid_t pid)
{
- struct uw_resolver *best;
struct uw_forwarder *uw_forwarder;
struct ctl_forwarder_info cfi;
+ struct resolver_preference res_pref;
int i;
- best = best_resolver();
-
switch(type) {
case UW_RES_NONE:
- resolver_imsg_compose_frontend(IMSG_CTL_CAPTIVEPORTAL_INFO,
- pid, &captive_portal_state, sizeof(captive_portal_state));
- for (i = 0; i < resolver_conf->res_pref_len; i++)
- send_resolver_info(
- resolvers[resolver_conf->res_pref[i]],
- resolvers[resolver_conf->res_pref[i]] ==
- best, pid);
+ if (sort_resolver_types(&res_pref) == -1)
+ log_warn("mergesort");
+
+ for (i = 0; i < resolver_conf->res_pref.len; i++)
+ send_resolver_info(resolvers[res_pref.types[i]], pid);
+
TAILQ_FOREACH(uw_forwarder, &autoconf_forwarder_list, entry) {
memset(&cfi, 0, sizeof(cfi));
cfi.if_index = uw_forwarder->if_index;
@@ -1594,8 +1668,7 @@ show_status(enum uw_resolver_type type, pid_t pid)
case UW_RES_FORWARDER:
case UW_RES_DOT:
case UW_RES_ASR:
- send_resolver_info(resolvers[type], resolvers[type] == best,
- pid);
+ send_resolver_info(resolvers[type], pid);
send_detailed_resolver_info(resolvers[type], pid);
break;
default:
@@ -1606,7 +1679,7 @@ show_status(enum uw_resolver_type type, pid_t pid)
}
void
-send_resolver_info(struct uw_resolver *res, int selected, pid_t pid)
+send_resolver_info(struct uw_resolver *res, pid_t pid)
{
struct ctl_resolver_info cri;
@@ -1615,7 +1688,6 @@ send_resolver_info(struct uw_resolver *res, int selected,
pid_t pid)
cri.state = res->state;
cri.type = res->type;
- cri.selected = selected;
cri.oppdot = res->oppdot;
resolver_imsg_compose_frontend(IMSG_CTL_RESOLVER_INFO, pid, &cri,
sizeof(cri));
@@ -1648,154 +1720,18 @@ send_resolver_histogram_info(struct uw_resolver *res,
pid_t pid)
pid, histogram, sizeof(histogram));
}
-void
-check_captive_portal_timo(int fd, short events, void *arg)
-{
- captive_portal_check_tv.tv_sec *= 2;
- if (captive_portal_check_tv.tv_sec > PORTAL_CHECK_MAXSEC)
- captive_portal_check_tv.tv_sec = PORTAL_CHECK_MAXSEC;
- check_captive_portal(0);
-}
-
-void
-check_captive_portal(int timer_reset)
-{
- struct uw_resolver *res;
-
- log_debug("%s", __func__);
-
- if (resolver_conf->captive_portal_host == NULL) {
- log_debug("%s: no captive portal url configured", __func__);
- captive_portal_state = PORTAL_UNCHECKED;
- schedule_recheck_all_resolvers();
- return;
- }
-
- if (timer_reset)
- captive_portal_check_tv.tv_sec = PORTAL_CHECK_SEC;
-
- evtimer_add(&captive_portal_check_ev, &captive_portal_check_tv);
-
- captive_portal_state = PORTAL_UNKNOWN;
-
- if ((res = best_resolver()) == NULL)
- return;
-
- resolve(res, resolver_conf->captive_portal_host,
- LDNS_RR_TYPE_A, LDNS_RR_CLASS_IN, NULL,
- captive_portal_resolve_done);
-}
-
-void
-captive_portal_resolve_done(struct uw_resolver *res, void *arg, int rcode,
- void *answer_packet, int answer_len, int sec, char *why_bogus)
-{
- struct ub_result *result = NULL;
- sldns_buffer *buf = NULL;
- struct regional *region = NULL;
- struct in_addr *in;
- int i;
- char *str, rdata_buf[sizeof("xxx.xxx.xxx.xxx")];
-
- if (answer_len < LDNS_HEADER_SIZE) {
- log_warnx("bad packet: too short");
- goto out;
- }
-
- if ((result = calloc(1, sizeof(*result))) == NULL)
- goto out;
-
- log_debug("%s: rcode: %d", __func__, rcode);
- if ((str = sldns_wire2str_pkt(answer_packet, answer_len)) != NULL) {
- log_debug("%s", str);
- free(str);
- }
-
- if ((buf = sldns_buffer_new(answer_len)) == NULL)
- goto out;
- if ((region = regional_create()) == NULL)
- goto out;
- result->rcode = LDNS_RCODE_SERVFAIL;
-
- sldns_buffer_clear(buf);
- sldns_buffer_write(buf, answer_packet, answer_len);
- sldns_buffer_flip(buf);
- libworker_enter_result(result, buf, region, sec);
- result->answer_packet = NULL;
- result->answer_len = 0;
-
- if (result->rcode != LDNS_RCODE_NOERROR) {
- log_debug("%s: result->rcode: %d", __func__,
- result->rcode);
- goto out;
- }
-
- i = 0;
- while(result->data[i] != NULL) {
- if (result->len[i] == 4) {
- in = (struct in_addr*) result->data[i];
- log_debug("%s: %s", __func__, inet_ntop(AF_INET,
- in, rdata_buf, sizeof(rdata_buf)));
- resolver_imsg_compose_main(
- IMSG_CONNECT_CAPTIVE_PORTAL_HOST, 0, in,
- sizeof(*in));
- }
- i++;
- }
- out:
- sldns_buffer_free(buf);
- regional_destroy(region);
- ub_resolve_free(result);
-}
-
-int
-check_captive_portal_changed(struct uw_conf *a, struct uw_conf *b)
-{
-
- if (a->captive_portal_expected_status !=
- b->captive_portal_expected_status)
- return (1);
-
- if (a->captive_portal_host == NULL && b->captive_portal_host != NULL)
- return (1);
- if (a->captive_portal_host != NULL && b->captive_portal_host == NULL)
- return (1);
- if (a->captive_portal_host != NULL && b->captive_portal_host != NULL &&
- strcmp(a->captive_portal_host, b->captive_portal_host) != 0)
- return (1);
-
- if (a->captive_portal_path == NULL && b->captive_portal_path != NULL)
- return (1);
- if (a->captive_portal_path != NULL && b->captive_portal_path == NULL)
- return (1);
- if (a->captive_portal_path != NULL && b->captive_portal_path != NULL &&
- strcmp(a->captive_portal_path, b->captive_portal_path) != 0)
- return (1);
-
- if (a->captive_portal_expected_response == NULL &&
- b->captive_portal_expected_response != NULL)
- return (1);
- if (a->captive_portal_expected_response != NULL &&
- b->captive_portal_expected_response == NULL)
- return (1);
- if (a->captive_portal_expected_response != NULL &&
- b->captive_portal_expected_response != NULL &&
- strcmp(a->captive_portal_expected_response,
- b->captive_portal_expected_response) != 0)
- return (1);
-
- return (0);
-}
-
void
trust_anchor_resolve(void)
{
- struct uw_resolver *res;
- struct timeval tv = {TRUST_ANCHOR_RETRY_INTERVAL, 0};
+ struct resolver_preference res_pref;
+ struct uw_resolver *res;
+ struct timeval tv = {TRUST_ANCHOR_RETRY_INTERVAL, 0};
log_debug("%s", __func__);
+ if (sort_resolver_types(&res_pref) == -1)
+ log_warn("mergesort");
- res = best_resolver();
+ res = resolvers[res_pref.types[0]];
if (res == NULL || res->state < VALIDATING)
goto err;
@@ -1994,8 +1930,6 @@ replace_autoconf_forwarders(struct imsg_rdns_proposal
*rdns_proposal)
&autoconf_forwarder_list);
new_forwarders(0);
new_asr_forwarders();
- if (resolver_conf->captive_portal_auto)
- check_captive_portal(1);
log_debug("%s: forwarders changed", __func__);
} else {
log_debug("%s: forwarders didn't change", __func__);
@@ -2016,3 +1950,21 @@ find_forwarder(struct uw_forwarder_head *list, const
char *name) {
}
return NULL;
}
+
+int64_t
+histogram_median(int64_t *histogram)
+{
+ size_t i;
+ int64_t sample_count = 0, running_count = 0;
+
+ for (i = 1; i < nitems(histogram_limits); i++)
+ sample_count += histogram[i];
+
+ for (i = 1; i < nitems(histogram_limits); i++) {
+ running_count += histogram[i];
+ if (running_count >= sample_count / 2)
+ break;
+ }
+
+ return histogram_limits[i];
+}
diff --git sbin/unwind/resolver.h sbin/unwind/resolver.h
index 9be94385c4c..f8e312c5d6c 100644
--- sbin/unwind/resolver.h
+++ sbin/unwind/resolver.h
@@ -49,7 +49,6 @@ static const int64_t histogram_limits[] = {
struct ctl_resolver_info {
enum uw_resolver_state state;
enum uw_resolver_type type;
- int selected;
int oppdot;
};
@@ -62,4 +61,3 @@ struct ctl_forwarder_info {
void resolver(int, int);
int resolver_imsg_compose_main(int, pid_t, void *, uint16_t);
int resolver_imsg_compose_frontend(int, pid_t, void *, uint16_t);
-int resolver_imsg_compose_captiveportal(int, pid_t, void *, uint16_t);
diff --git sbin/unwind/unwind.c sbin/unwind/unwind.c
index 87e3fa87ac3..b9c576e08fc 100644
--- sbin/unwind/unwind.c
+++ sbin/unwind/unwind.c
@@ -47,7 +47,6 @@
#include "frontend.h"
#include "resolver.h"
#include "control.h"
-#include "captiveportal.h"
#define TRUST_ANCHOR_FILE "/var/db/unwind.key"
@@ -60,28 +59,23 @@ static pid_t start_child(int, char *, int, int, int);
void main_dispatch_frontend(int, short, void *);
void main_dispatch_resolver(int, short, void *);
-void main_dispatch_captiveportal(int, short, void *);
-static int main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *,
- struct imsgbuf *);
+static int main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *);
static int main_imsg_send_config(struct uw_conf *);
int main_reload(void);
int main_sendall(enum imsg_type, void *, uint16_t);
void open_ports(void);
void solicit_dns_proposals(void);
-void connect_captive_portal_host(struct in_addr *);
void send_blocklist_fd(void);
struct uw_conf *main_conf;
struct imsgev *iev_frontend;
struct imsgev *iev_resolver;
-struct imsgev *iev_captiveportal;
char *conffile;
pid_t frontend_pid;
pid_t resolver_pid;
-pid_t captiveportal_pid;
uint32_t cmd_opts;
@@ -126,9 +120,8 @@ main(int argc, char *argv[])
{
struct event ev_sigint, ev_sigterm, ev_sighup;
int ch, debug = 0, resolver_flag = 0, frontend_flag = 0;
- int captiveportal_flag = 0, frontend_routesock, rtfilter;
+ int frontend_routesock, rtfilter;
int pipe_main2frontend[2], pipe_main2resolver[2];
- int pipe_main2captiveportal[2];
int control_fd, ta_fd;
char *csock, *saved_argv0;
@@ -142,11 +135,8 @@ main(int argc, char *argv[])
if (saved_argv0 == NULL)
saved_argv0 = "unwind";
- while ((ch = getopt(argc, argv, "CdEFf:ns:v")) != -1) {
+ while ((ch = getopt(argc, argv, "dEFf:ns:v")) != -1) {
switch (ch) {
- case 'C':
- captiveportal_flag = 1;
- break;
case 'd':
debug = 1;
break;
@@ -177,15 +167,13 @@ main(int argc, char *argv[])
argc -= optind;
argv += optind;
- if (argc > 0 || (resolver_flag && frontend_flag && captiveportal_flag))
+ if (argc > 0 || (resolver_flag && frontend_flag))
usage();
if (resolver_flag)
resolver(debug, cmd_opts & (OPT_VERBOSE | OPT_VERBOSE2));
else if (frontend_flag)
frontend(debug, cmd_opts & (OPT_VERBOSE | OPT_VERBOSE2));
- else if (captiveportal_flag)
- captiveportal(debug, cmd_opts & (OPT_VERBOSE | OPT_VERBOSE2));
if ((main_conf = parse_config(conffile)) == NULL)
exit(1);
@@ -220,9 +208,6 @@ main(int argc, char *argv[])
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
PF_UNSPEC, pipe_main2resolver) == -1)
fatal("main2resolver socketpair");
- if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
- PF_UNSPEC, pipe_main2captiveportal) == -1)
- fatal("main2captiveportal socketpair");
/* Start children. */
resolver_pid = start_child(PROC_RESOLVER, saved_argv0,
@@ -231,9 +216,6 @@ main(int argc, char *argv[])
frontend_pid = start_child(PROC_FRONTEND, saved_argv0,
pipe_main2frontend[1], debug, cmd_opts & (OPT_VERBOSE |
OPT_VERBOSE2));
- captiveportal_pid = start_child(PROC_CAPTIVEPORTAL, saved_argv0,
- pipe_main2captiveportal[1], debug, cmd_opts & (OPT_VERBOSE |
- OPT_VERBOSE2));
uw_process = PROC_MAIN;
log_procinit(log_procnames[uw_process]);
@@ -252,15 +234,12 @@ main(int argc, char *argv[])
/* Setup pipes to children. */
if ((iev_frontend = malloc(sizeof(struct imsgev))) == NULL ||
- (iev_captiveportal = malloc(sizeof(struct imsgev))) == NULL ||
(iev_resolver = malloc(sizeof(struct imsgev))) == NULL)
fatal(NULL);
imsg_init(&iev_frontend->ibuf, pipe_main2frontend[0]);
iev_frontend->handler = main_dispatch_frontend;
imsg_init(&iev_resolver->ibuf, pipe_main2resolver[0]);
iev_resolver->handler = main_dispatch_resolver;
- imsg_init(&iev_captiveportal->ibuf, pipe_main2captiveportal[0]);
- iev_captiveportal->handler = main_dispatch_captiveportal;
/* Setup event handlers for pipes. */
iev_frontend->events = EV_READ;
@@ -273,14 +252,8 @@ main(int argc, char *argv[])
iev_resolver->events, iev_resolver->handler, iev_resolver);
event_add(&iev_resolver->ev, NULL);
- iev_captiveportal->events = EV_READ;
- event_set(&iev_captiveportal->ev, iev_captiveportal->ibuf.fd,
- iev_captiveportal->events, iev_captiveportal->handler,
- iev_captiveportal);
- event_add(&iev_captiveportal->ev, NULL);
-
if (main_imsg_send_ipc_sockets(&iev_frontend->ibuf,
- &iev_resolver->ibuf, &iev_captiveportal->ibuf))
+ &iev_resolver->ibuf))
fatal("could not establish imsg links");
if ((control_fd = control_init(csock)) == -1)
@@ -336,8 +309,6 @@ main_shutdown(void)
close(iev_frontend->ibuf.fd);
msgbuf_clear(&iev_resolver->ibuf.w);
close(iev_resolver->ibuf.fd);
- msgbuf_clear(&iev_captiveportal->ibuf.w);
- close(iev_captiveportal->ibuf.fd);
config_clear(main_conf);
@@ -355,7 +326,6 @@ main_shutdown(void)
free(iev_frontend);
free(iev_resolver);
- free(iev_captiveportal);
log_info("terminating");
exit(0);
@@ -394,9 +364,6 @@ start_child(int p, char *argv0, int fd, int debug, int
verbose)
case PROC_FRONTEND:
argv[argc++] = "-F";
break;
- case PROC_CAPTIVEPORTAL:
- argv[argc++] = "-C";
- break;
}
if (debug)
argv[argc++] = "-d";
@@ -480,7 +447,6 @@ main_dispatch_resolver(int fd, short event, void *bula)
struct imsgev *iev = bula;
struct imsgbuf *ibuf;
struct imsg imsg;
- struct in_addr *in;
ssize_t n;
int shut = 0;
@@ -499,61 +465,6 @@ main_dispatch_resolver(int fd, short event, void *bula)
shut = 1;
}
- for (;;) {
- if ((n = imsg_get(ibuf, &imsg)) == -1)
- fatal("imsg_get");
- if (n == 0) /* No more messages. */
- break;
-
- switch (imsg.hdr.type) {
- case IMSG_CONNECT_CAPTIVE_PORTAL_HOST:
- if (IMSG_DATA_SIZE(imsg) != sizeof(*in))
- fatalx("%s: IMSG_CONNECT_CAPTIVE_PORTAL_HOST "
- "wrong length: %lu", __func__,
- IMSG_DATA_SIZE(imsg));
- in = (struct in_addr *)imsg.data;
- connect_captive_portal_host(in);
- break;
- default:
- log_debug("%s: error handling imsg %d", __func__,
- imsg.hdr.type);
- break;
- }
- imsg_free(&imsg);
- }
- if (!shut)
- imsg_event_add(iev);
- else {
- /* This pipe is dead. Remove its event handler. */
- event_del(&iev->ev);
- event_loopexit(NULL);
- }
-}
-
-void
-main_dispatch_captiveportal(int fd, short event, void *bula)
-{
- struct imsgev *iev = bula;
- struct imsgbuf *ibuf;
- struct imsg imsg;
- ssize_t n;
- int shut = 0;
-
- ibuf = &iev->ibuf;
-
- if (event & EV_READ) {
- if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
- fatal("imsg_read error");
- if (n == 0) /* Connection closed. */
- shut = 1;
- }
- if (event & EV_WRITE) {
- if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
- fatal("msgbuf_write");
- if (n == 0) /* Connection closed. */
- shut = 1;
- }
-
for (;;) {
if ((n = imsg_get(ibuf, &imsg)) == -1)
fatal("imsg_get");
@@ -600,23 +511,6 @@ main_imsg_compose_resolver(int type, pid_t pid, void
*data, uint16_t datalen)
datalen);
}
-void
-main_imsg_compose_captiveportal(int type, pid_t pid, void *data,
- uint16_t datalen)
-{
- if (iev_captiveportal)
- imsg_compose_event(iev_captiveportal, type, 0, pid, -1, data,
- datalen);
-}
-
-void
-main_imsg_compose_captiveportal_fd(int type, pid_t pid, int fd)
-{
- if (iev_frontend)
- imsg_compose_event(iev_captiveportal, type, 0, pid, fd, NULL,
- 0);
-}
-
void
imsg_event_add(struct imsgev *iev)
{
@@ -644,24 +538,14 @@ imsg_compose_event(struct imsgev *iev, uint16_t type,
uint32_t peerid,
static int
main_imsg_send_ipc_sockets(struct imsgbuf *frontend_buf,
- struct imsgbuf *resolver_buf, struct imsgbuf *captiveportal_buf)
+ struct imsgbuf *resolver_buf)
{
int pipe_frontend2resolver[2];
- int pipe_frontend2captiveportal[2];
- int pipe_resolver2captiveportal[2];
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
PF_UNSPEC, pipe_frontend2resolver) == -1)
return (-1);
- if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
- PF_UNSPEC, pipe_frontend2captiveportal) == -1)
- return (-1);
-
- if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
- PF_UNSPEC, pipe_resolver2captiveportal) == -1)
- return (-1);
-
if (imsg_compose(frontend_buf, IMSG_SOCKET_IPC_RESOLVER, 0, 0,
pipe_frontend2resolver[0], NULL, 0) == -1)
return (-1);
@@ -669,20 +553,6 @@ main_imsg_send_ipc_sockets(struct imsgbuf *frontend_buf,
pipe_frontend2resolver[1], NULL, 0) == -1)
return (-1);
- if (imsg_compose(frontend_buf, IMSG_SOCKET_IPC_CAPTIVEPORTAL, 0, 0,
- pipe_frontend2captiveportal[0], NULL, 0) == -1)
- return (-1);
- if (imsg_compose(captiveportal_buf, IMSG_SOCKET_IPC_FRONTEND, 0, 0,
- pipe_frontend2captiveportal[1], NULL, 0) == -1)
- return (-1);
-
- if (imsg_compose(resolver_buf, IMSG_SOCKET_IPC_CAPTIVEPORTAL, 0, 0,
- pipe_resolver2captiveportal[0], NULL, 0) == -1)
- return (-1);
- if (imsg_compose(captiveportal_buf, IMSG_SOCKET_IPC_RESOLVER, 0, 0,
- pipe_resolver2captiveportal[1], NULL, 0) == -1)
- return (-1);
-
return (0);
}
@@ -713,27 +583,6 @@ main_imsg_send_config(struct uw_conf *xconf)
/* Send fixed part of config to children. */
if (main_sendall(IMSG_RECONF_CONF, xconf, sizeof(*xconf)) == -1)
return (-1);
- if (xconf->captive_portal_host != NULL) {
- if (main_sendall(IMSG_RECONF_CAPTIVE_PORTAL_HOST,
- xconf->captive_portal_host,
- strlen(xconf->captive_portal_host) + 1) == -1)
- return (-1);
- }
-
- if (xconf->captive_portal_path != NULL) {
- if (main_sendall(IMSG_RECONF_CAPTIVE_PORTAL_PATH,
- xconf->captive_portal_path,
- strlen(xconf->captive_portal_path) + 1) == -1)
- return (-1);
- }
-
- if (xconf->captive_portal_expected_response != NULL) {
- if (main_sendall(IMSG_RECONF_CAPTIVE_PORTAL_EXPECTED_RESPONSE,
- xconf->captive_portal_expected_response,
- strlen(xconf->captive_portal_expected_response) + 1)
- == -1)
- return (-1);
- }
if (xconf->blocklist_file != NULL) {
if (main_sendall(IMSG_RECONF_BLOCKLIST_FILE,
@@ -771,9 +620,6 @@ main_sendall(enum imsg_type type, void *buf, uint16_t len)
return (-1);
if (imsg_compose_event(iev_resolver, type, 0, 0, -1, buf, len) == -1)
return (-1);
- if (imsg_compose_event(iev_captiveportal, type, 0, 0, -1, buf, len) ==
- -1)
- return (-1);
return (0);
}
@@ -794,25 +640,9 @@ merge_config(struct uw_conf *conf, struct uw_conf *xconf)
free(uw_forwarder);
}
- conf->res_pref_len = xconf->res_pref_len;
memcpy(&conf->res_pref, &xconf->res_pref,
sizeof(conf->res_pref));
- free(conf->captive_portal_host);
- conf->captive_portal_host = xconf->captive_portal_host;
-
- free(conf->captive_portal_path);
- conf->captive_portal_path = xconf->captive_portal_path;
-
- free(conf->captive_portal_expected_response);
- conf->captive_portal_expected_response =
- xconf->captive_portal_expected_response;
-
- conf->captive_portal_expected_status =
- xconf->captive_portal_expected_status;
-
- conf->captive_portal_auto = xconf->captive_portal_auto;
-
free(conf->blocklist_file);
conf->blocklist_file = xconf->blocklist_file;
conf->blocklist_log = xconf->blocklist_log;
@@ -850,19 +680,13 @@ config_new_empty(void)
if (xconf == NULL)
fatal(NULL);
- memcpy(&xconf->res_pref, &default_res_pref,
+ memcpy(&xconf->res_pref.types, &default_res_pref,
sizeof(default_res_pref));
- xconf->res_pref_len = 5;
+ xconf->res_pref.len = 5;
TAILQ_INIT(&xconf->uw_forwarder_list);
TAILQ_INIT(&xconf->uw_dot_forwarder_list);
- if ((xconf->captive_portal_expected_response = strdup("")) == NULL)
- fatal(NULL);
-
- xconf->captive_portal_expected_status = 200;
- xconf->captive_portal_auto = 1;
-
return (xconf);
}
@@ -951,38 +775,6 @@ solicit_dns_proposals(void)
log_warn("failed to send solicitation");
}
-void
-connect_captive_portal_host(struct in_addr *in)
-{
- struct sockaddr *sa;
- struct sockaddr_in sin;
- int httpsock;
-
- sa = (struct sockaddr *)&sin;
- memset(&sin, 0, sizeof(sin));
- sin.sin_len = sizeof(sin);
- sin.sin_family = AF_INET;
- sin.sin_addr = *in;
- sin.sin_port = htons(80);
- log_debug("%s: ip_port: %s", __func__, ip_port(sa));
-
- if ((httpsock = socket(AF_INET, SOCK_STREAM |
- SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) == -1) {
- log_warn("%s: socket", __func__);
- return;
- }
- if (connect(httpsock, sa, sizeof(sin)) == -1) {
- if (errno != EINPROGRESS) {
- log_warn("%s: connect", __func__);
- close(httpsock);
- return;
- }
- }
-
- main_imsg_compose_captiveportal_fd(IMSG_HTTPSOCK, 0,
- httpsock);
-}
-
void
send_blocklist_fd(void)
{
@@ -1014,33 +806,9 @@ imsg_receive_config(struct imsg *imsg, struct uw_conf
**xconf)
fatal(NULL);
nconf = *xconf;
memcpy(nconf, imsg->data, sizeof(struct uw_conf));
- nconf->captive_portal_host = NULL;
- nconf->captive_portal_path = NULL;
- nconf->captive_portal_expected_response = NULL;
TAILQ_INIT(&nconf->uw_forwarder_list);
TAILQ_INIT(&nconf->uw_dot_forwarder_list);
break;
- case IMSG_RECONF_CAPTIVE_PORTAL_HOST:
- /* make sure this is a string */
- ((char *)imsg->data)[IMSG_DATA_SIZE(*imsg) - 1] = '\0';
- if ((nconf->captive_portal_host = strdup(imsg->data)) ==
- NULL)
- fatal("%s: strdup", __func__);
- break;
- case IMSG_RECONF_CAPTIVE_PORTAL_PATH:
- /* make sure this is a string */
- ((char *)imsg->data)[IMSG_DATA_SIZE(*imsg) - 1] = '\0';
- if ((nconf->captive_portal_path = strdup(imsg->data)) ==
- NULL)
- fatal("%s: strdup", __func__);
- break;
- case IMSG_RECONF_CAPTIVE_PORTAL_EXPECTED_RESPONSE:
- /* make sure this is a string */
- ((char *)imsg->data)[IMSG_DATA_SIZE(*imsg) - 1] = '\0';
- if ((nconf->captive_portal_expected_response =
- 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';
diff --git sbin/unwind/unwind.conf.5 sbin/unwind/unwind.conf.5
index 597c989b17d..6a659382a16 100644
--- sbin/unwind/unwind.conf.5
+++ sbin/unwind/unwind.conf.5
@@ -72,45 +72,6 @@ answers with a return code of
With
.Cm log
blocked queries are logged.
-.It Ic captive portal Brq ...
-.Nm unwind
-can detect when it is running behind a
-.Dq captive portal
-by sending an HTTP request and checking the response against the
-configured expected response.
-The check is triggered when
-.Xr dhclient 8
-reports new nameservers.
-If the response does not match,
-.Nm unwind
-uses the DHCP provided nameservers and periodically re-checks if the user
-passed the captive portal.
-.Bl -tag -width Ds
-.It Ic auto Op Cm yes | no
-When
-.Ic auto
-is set to
-.Cm yes
-.Nm unwind
-automatically triggers a captive portal check
-when the network is changed.
-When set to
-.Cm no
-a captive portal check can be triggered by
-.Xr unwindctl 8 .
-The default is
-.Cm yes .
-.It Ic expected response Ar response
-The body of the HTTP response is compared to
-.Ar response .
-The default is the empty string.
-.It Ic expected status Ar status
-The expected HTTP status code.
-The default is 200.
-.It Ic url Ar URL
-URL to send HTTP queries to.
-This parameter is required.
-.El
.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
diff --git sbin/unwind/unwind.h sbin/unwind/unwind.h
index 3dda5fc5136..eec3778ca1a 100644
--- sbin/unwind/unwind.h
+++ sbin/unwind/unwind.h
@@ -44,14 +44,12 @@ enum {
PROC_MAIN,
PROC_RESOLVER,
PROC_FRONTEND,
- PROC_CAPTIVEPORTAL,
} uw_process;
static const char * const log_procnames[] = {
"main",
"resolver",
"frontend",
- "captive portal",
};
enum uw_resolver_type {
@@ -83,11 +81,7 @@ enum imsg_type {
IMSG_CTL_LOG_VERBOSE,
IMSG_CTL_RELOAD,
IMSG_CTL_STATUS,
- IMSG_CTL_CAPTIVEPORTAL_INFO,
IMSG_RECONF_CONF,
- 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,
@@ -100,7 +94,6 @@ enum imsg_type {
IMSG_STARTUP_DONE,
IMSG_SOCKET_IPC_FRONTEND,
IMSG_SOCKET_IPC_RESOLVER,
- IMSG_SOCKET_IPC_CAPTIVEPORTAL,
IMSG_QUERY,
IMSG_ANSWER_HEADER,
IMSG_ANSWER,
@@ -109,15 +102,12 @@ enum imsg_type {
IMSG_CTL_RESOLVER_HISTOGRAM,
IMSG_CTL_AUTOCONF_RESOLVER_INFO,
IMSG_CTL_END,
- IMSG_CTL_RECHECK_CAPTIVEPORTAL,
IMSG_HTTPSOCK,
- IMSG_CAPTIVEPORTAL_STATE,
IMSG_TAFD,
IMSG_NEW_TA,
IMSG_NEW_TAS_ABORT,
IMSG_NEW_TAS_DONE,
IMSG_NETWORK_CHANGED,
- IMSG_CONNECT_CAPTIVE_PORTAL_HOST,
IMSG_BLFD,
IMSG_REPLACE_DNS,
};
@@ -130,17 +120,16 @@ struct uw_forwarder {
uint16_t port;
};
+struct resolver_preference {
+ enum uw_resolver_type types[UW_RES_NONE];
+ int len;
+};
+
TAILQ_HEAD(uw_forwarder_head, uw_forwarder);
struct uw_conf {
struct uw_forwarder_head uw_forwarder_list;
struct uw_forwarder_head uw_dot_forwarder_list;
- enum uw_resolver_type res_pref[UW_RES_NONE];
- int res_pref_len;
- char *captive_portal_host;
- char *captive_portal_path;
- char *captive_portal_expected_response;
- int captive_portal_expected_status;
- int captive_portal_auto;
+ struct resolver_preference res_pref;
char *blocklist_file;
int blocklist_log;
};
@@ -161,8 +150,6 @@ extern uint32_t cmd_opts;
void main_imsg_compose_frontend(int, pid_t, void *, uint16_t);
void main_imsg_compose_frontend_fd(int, pid_t, int);
void main_imsg_compose_resolver(int, pid_t, void *, uint16_t);
-void main_imsg_compose_captiveportal(int, pid_t, void *, uint16_t);
-void main_imsg_compose_captiveportal_fd(int, pid_t, int);
void merge_config(struct uw_conf *, struct uw_conf *);
void imsg_event_add(struct imsgev *);
int imsg_compose_event(struct imsgev *, uint16_t, uint32_t, pid_t,
diff --git usr.sbin/unwindctl/parser.c usr.sbin/unwindctl/parser.c
index a130de587f7..ba2402d7936 100644
--- usr.sbin/unwindctl/parser.c
+++ usr.sbin/unwindctl/parser.c
@@ -51,13 +51,11 @@ struct token {
static const struct token t_main[];
static const struct token t_log[];
static const struct token t_status[];
-static const struct token t_recheck[];
static const struct token t_main[] = {
{KEYWORD, "reload", RELOAD, NULL},
{KEYWORD, "status", STATUS, t_status},
{KEYWORD, "log", NONE, t_log},
- {KEYWORD, "recheck", NONE, t_recheck},
{ENDTOKEN, "", NONE, NULL}
};
@@ -78,11 +76,6 @@ static const struct token t_status[] = {
{ENDTOKEN, "", STATUS, NULL}
};
-static const struct token t_recheck[] = {
- {KEYWORD, "portal", PORTAL, NULL},
- {ENDTOKEN, "", NONE, NULL}
-};
-
static const struct token *match_token(const char *, const struct token *,
struct parse_result *);
static void show_valid_args(const struct token *);
diff --git usr.sbin/unwindctl/unwindctl.8 usr.sbin/unwindctl/unwindctl.8
index b1b26112421..1c1ff9656cb 100644
--- usr.sbin/unwindctl/unwindctl.8
+++ usr.sbin/unwindctl/unwindctl.8
@@ -53,8 +53,6 @@ Enable verbose logging.
Enable very noisy debug logging.
.It Cm reload
Reload the configuration file.
-.It Cm recheck portal
-Run the captive portal detection.
.It Cm status Op Cm recursor | dhcp | DoT | forwarder
Show a status summary.
If one of
diff --git usr.sbin/unwindctl/unwindctl.c usr.sbin/unwindctl/unwindctl.c
index 791a3d5fa15..6658941ce52 100644
--- usr.sbin/unwindctl/unwindctl.c
+++ usr.sbin/unwindctl/unwindctl.c
@@ -39,7 +39,6 @@
#include <unistd.h>
#include "unwind.h"
-#include "captiveportal.h"
#include "frontend.h"
#include "resolver.h"
#include "parser.h"
@@ -142,12 +141,6 @@ main(int argc, char *argv[])
printf("reload request sent.\n");
done = 1;
break;
- case PORTAL:
- imsg_compose(ibuf, IMSG_CTL_RECHECK_CAPTIVEPORTAL, 0, 0, -1,
- NULL, 0);
- printf("recheck request sent.\n");
- done = 1;
- break;
case STATUS_RECURSOR:
type = UW_RES_RECURSOR;
imsg_compose(ibuf, IMSG_CTL_STATUS, 0, 0, -1, &type,
@@ -225,34 +218,16 @@ show_status_msg(struct imsg *imsg)
static int header, autoconf_forwarders;
struct ctl_resolver_info *cri;
struct ctl_forwarder_info *cfi;
- enum captive_portal_state captive_portal_state;
char ifnamebuf[IFNAMSIZ];
char *if_name;
- if (imsg->hdr.type != IMSG_CTL_CAPTIVEPORTAL_INFO && !header++)
- printf("%8s %16s %s\n", "selected", "type", "status");
+ if (!header++)
+ printf("preference:\n");
switch (imsg->hdr.type) {
- case IMSG_CTL_CAPTIVEPORTAL_INFO:
- memcpy(&captive_portal_state, imsg->data,
- sizeof(captive_portal_state));
- switch (captive_portal_state) {
- case PORTAL_UNCHECKED:
- case PORTAL_UNKNOWN:
- printf("captive portal is %s\n\n",
- captive_portal_state_str[captive_portal_state]);
- break;
- case BEHIND:
- case NOT_BEHIND:
- printf("%s captive portal\n\n",
- captive_portal_state_str[captive_portal_state]);
- break;
- }
- break;
case IMSG_CTL_RESOLVER_INFO:
cri = imsg->data;
- printf("%8s %16s %s%s\n", cri->selected ? "*" : " ",
- uw_resolver_type_str[cri->type],
+ printf("%-10s %s%s\n", uw_resolver_type_str[cri->type],
uw_resolver_state_str[cri->state],
cri->oppdot ? " (opportunistic DoT)" : "");
break;
--
I'm not entirely sure you are real.