summaryrefslogtreecommitdiff
path: root/sbin/unwind/unwind.c
diff options
context:
space:
mode:
Diffstat (limited to 'sbin/unwind/unwind.c')
-rw-r--r--sbin/unwind/unwind.c225
1 files changed, 206 insertions, 19 deletions
diff --git a/sbin/unwind/unwind.c b/sbin/unwind/unwind.c
index d72b98f98b0..5e829a9c389 100644
--- a/sbin/unwind/unwind.c
+++ b/sbin/unwind/unwind.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: unwind.c,v 1.9 2019/02/01 15:52:35 florian Exp $ */
+/* $OpenBSD: unwind.c,v 1.10 2019/02/03 12:02:30 florian Exp $ */
/*
* Copyright (c) 2018 Florian Obser <florian@openbsd.org>
@@ -45,6 +45,7 @@
#include "frontend.h"
#include "resolver.h"
#include "control.h"
+#include "captiveportal.h"
__dead void usage(void);
__dead void main_shutdown(void);
@@ -55,22 +56,26 @@ 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 *);
+static int main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *,
+ struct imsgbuf *);
static int main_imsg_send_config(struct unwind_conf *);
int main_reload(void);
-int main_sendboth(enum imsg_type, void *, uint16_t);
+int main_sendall(enum imsg_type, void *, uint16_t);
void open_dhcp_lease(int);
void open_ports(void);
struct unwind_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;
@@ -113,10 +118,12 @@ main(int argc, char *argv[])
{
struct event ev_sigint, ev_sigterm, ev_sighup;
int ch;
- int debug = 0, resolver_flag = 0, frontend_flag = 0;
+ int debug = 0, resolver_flag = 0;
+ int frontend_flag = 0, captiveportal_flag = 0;
char *saved_argv0;
int pipe_main2frontend[2];
int pipe_main2resolver[2];
+ int pipe_main2captiveportal[2];
int frontend_routesock, rtfilter;
int control_fd;
char *csock;
@@ -131,8 +138,11 @@ main(int argc, char *argv[])
if (saved_argv0 == NULL)
saved_argv0 = "unwind";
- while ((ch = getopt(argc, argv, "dEFf:ns:v")) != -1) {
+ while ((ch = getopt(argc, argv, "CdEFf:ns:v")) != -1) {
switch (ch) {
+ case 'C':
+ captiveportal_flag = 1;
+ break;
case 'd':
debug = 1;
break;
@@ -163,13 +173,15 @@ main(int argc, char *argv[])
argc -= optind;
argv += optind;
- if (argc > 0 || (resolver_flag && frontend_flag))
+ if (argc > 0 || (resolver_flag && frontend_flag && captiveportal_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);
@@ -204,6 +216,9 @@ 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,
@@ -212,6 +227,9 @@ 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));
unwind_process = PROC_MAIN;
log_procinit(log_procnames[unwind_process]);
@@ -230,14 +248,17 @@ 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 to resolver & frontend. */
+ /* Setup event handlers for pipes. */
iev_frontend->events = EV_READ;
event_set(&iev_frontend->ev, iev_frontend->ibuf.fd,
iev_frontend->events, iev_frontend->handler, iev_frontend);
@@ -248,7 +269,14 @@ main(int argc, char *argv[])
iev_resolver->handler, iev_resolver);
event_add(&iev_resolver->ev, NULL);
- if (main_imsg_send_ipc_sockets(&iev_frontend->ibuf, &iev_resolver->ibuf))
+ 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))
fatal("could not establish imsg links");
if ((control_fd = control_init(csock)) == -1)
@@ -290,6 +318,8 @@ 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);
@@ -307,6 +337,7 @@ main_shutdown(void)
free(iev_frontend);
free(iev_resolver);
+ free(iev_captiveportal);
log_info("terminating");
exit(0);
@@ -342,6 +373,9 @@ 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";
@@ -433,6 +467,77 @@ main_dispatch_frontend(int fd, short event, void *bula)
void
main_dispatch_resolver(int fd, short event, void *bula)
{
+ struct imsgev *iev = bula;
+ struct imsgbuf *ibuf;
+ struct imsg imsg;
+ struct sockaddr_in sin;
+ ssize_t n;
+ int shut = 0, httpsock;
+
+ 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");
+ if (n == 0) /* No more messages. */
+ break;
+
+ switch (imsg.hdr.type) {
+ case IMSG_OPEN_HTTP_PORT:
+ if (imsg.hdr.len != IMSG_HEADER_SIZE +
+ sizeof(sin))
+ fatalx("%s: IMSG_OPEN_HTTP_PORT wrong length: "
+ "%d", __func__, imsg.hdr.len);
+ memcpy(&sin, imsg.data, sizeof(sin));
+
+ if ((httpsock = socket(AF_INET, SOCK_STREAM |
+ SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) == -1) {
+ log_warn("%s: socket", __func__);
+ break;
+ }
+ if (connect(httpsock, (struct sockaddr *)&sin,
+ sin.sin_len) == -1) {
+ if (errno != EINPROGRESS) {
+ log_warn("%s: connect", __func__);
+ close(httpsock);
+ break;
+ }
+ }
+ main_imsg_compose_captiveportal_fd(IMSG_HTTPSOCK, 0,
+ httpsock);
+ 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;
@@ -492,7 +597,6 @@ main_imsg_compose_frontend_fd(int type, pid_t pid, int fd)
imsg_compose_event(iev_frontend, type, 0, pid, fd, NULL, 0);
}
-
void
main_imsg_compose_resolver(int type, pid_t pid, void *data, uint16_t datalen)
{
@@ -502,6 +606,23 @@ main_imsg_compose_resolver(int type, pid_t pid, void *data, uint16_t 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)
{
iev->events = EV_READ;
@@ -528,21 +649,45 @@ 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 *resolver_buf, struct imsgbuf *captiveportal_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 (imsg_compose(frontend_buf, IMSG_SOCKET_IPC, 0, 0,
+ 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);
- if (imsg_compose(resolver_buf, IMSG_SOCKET_IPC, 0, 0,
+ if (imsg_compose(resolver_buf, IMSG_SOCKET_IPC_FRONTEND, 0, 0,
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);
}
@@ -568,40 +713,62 @@ main_imsg_send_config(struct unwind_conf *xconf)
struct unwind_forwarder *unwind_forwarder;
/* Send fixed part of config to children. */
- if (main_sendboth(IMSG_RECONF_CONF, xconf, sizeof(*xconf)) == -1)
+ 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);
+ }
/* send static forwarders to children */
SIMPLEQ_FOREACH(unwind_forwarder, &xconf->unwind_forwarder_list, entry) {
- if (main_sendboth(IMSG_RECONF_FORWARDER, unwind_forwarder,
+ if (main_sendall(IMSG_RECONF_FORWARDER, unwind_forwarder,
sizeof(*unwind_forwarder)) == -1)
return (-1);
-
}
/* send static DoT forwarders to children */
SIMPLEQ_FOREACH(unwind_forwarder, &xconf->unwind_dot_forwarder_list,
entry) {
- if (main_sendboth(IMSG_RECONF_DOT_FORWARDER, unwind_forwarder,
+ if (main_sendall(IMSG_RECONF_DOT_FORWARDER, unwind_forwarder,
sizeof(*unwind_forwarder)) == -1)
return (-1);
-
}
/* Tell children the revised config is now complete. */
- if (main_sendboth(IMSG_RECONF_END, NULL, 0) == -1)
+ if (main_sendall(IMSG_RECONF_END, NULL, 0) == -1)
return (-1);
return (0);
}
int
-main_sendboth(enum imsg_type type, void *buf, uint16_t len)
+main_sendall(enum imsg_type type, void *buf, uint16_t len)
{
if (imsg_compose_event(iev_frontend, type, 0, 0, -1, buf, len) == -1)
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);
}
@@ -624,6 +791,21 @@ merge_config(struct unwind_conf *conf, struct unwind_conf *xconf)
conf->unwind_options = xconf->unwind_options;
+ 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;
+
/* Add new forwarders. */
while ((unwind_forwarder =
SIMPLEQ_FIRST(&xconf->unwind_forwarder_list)) != NULL) {
@@ -653,6 +835,11 @@ config_new_empty(void)
SIMPLEQ_INIT(&xconf->unwind_forwarder_list);
SIMPLEQ_INIT(&xconf->unwind_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);
}