summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorFlorian Obser <florian@cvs.openbsd.org>2019-01-23 13:12:20 +0000
committerFlorian Obser <florian@cvs.openbsd.org>2019-01-23 13:12:20 +0000
commiteef168c6991c247f694d60bbe6311a78d10cd5ae (patch)
tree445b1488af062855ba94ec38307be78dc897d70f /usr.sbin
parent1cfcc63ce1c2f5f9337681007a3e1e0ced56970f (diff)
import unwindctl
"toss it in man" deraadt@
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/unwindctl/Makefile17
-rw-r--r--usr.sbin/unwindctl/parser.c175
-rw-r--r--usr.sbin/unwindctl/parser.h36
-rw-r--r--usr.sbin/unwindctl/unwindctl.881
-rw-r--r--usr.sbin/unwindctl/unwindctl.c276
5 files changed, 585 insertions, 0 deletions
diff --git a/usr.sbin/unwindctl/Makefile b/usr.sbin/unwindctl/Makefile
new file mode 100644
index 00000000000..790e451757b
--- /dev/null
+++ b/usr.sbin/unwindctl/Makefile
@@ -0,0 +1,17 @@
+# $OpenBSD: Makefile,v 1.1 2019/01/23 13:12:19 florian Exp $
+
+PROG= unwindctl
+SRCS= unwindctl.c parser.c
+
+MAN= unwindctl.8
+
+CFLAGS+= -Wall
+CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes
+CFLAGS+= -Wmissing-declarations
+CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual
+CFLAGS+= -Wsign-compare
+CFLAGS+= -I${.CURDIR} -I${.CURDIR}/../../sbin/unwind
+LDADD= -lutil
+DPADD= ${LIBUTIL}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/unwindctl/parser.c b/usr.sbin/unwindctl/parser.c
new file mode 100644
index 00000000000..3f8fac4bb27
--- /dev/null
+++ b/usr.sbin/unwindctl/parser.c
@@ -0,0 +1,175 @@
+/* $OpenBSD: parser.c,v 1.1 2019/01/23 13:12:19 florian Exp $ */
+
+/*
+ * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
+ * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
+ *
+ * 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 <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <err.h>
+#include <errno.h>
+#include <event.h>
+#include <imsg.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "unwind.h"
+#include "parser.h"
+
+enum token_type {
+ NOTOKEN,
+ ENDTOKEN,
+ KEYWORD
+};
+
+struct token {
+ enum token_type type;
+ const char *keyword;
+ int value;
+ const struct token *next;
+};
+
+static const struct token t_main[];
+static const struct token t_log[];
+static const struct token t_status[];
+
+static const struct token t_main[] = {
+ {KEYWORD, "reload", RELOAD, NULL},
+ {KEYWORD, "status", STATUS, t_status},
+ {KEYWORD, "log", NONE, t_log},
+ {ENDTOKEN, "", NONE, NULL}
+};
+
+static const struct token t_log[] = {
+ {KEYWORD, "debug", LOG_DEBUG, NULL},
+ {KEYWORD, "verbose", LOG_VERBOSE, NULL},
+ {KEYWORD, "brief", LOG_BRIEF, NULL},
+ {ENDTOKEN, "", NONE, NULL}
+};
+
+static const struct token t_status[] = {
+ {NOTOKEN, "", NONE, NULL},
+ {KEYWORD, "recursor", STATUS_RECURSOR, NULL},
+ {KEYWORD, "dhcp", STATUS_DHCP, NULL},
+ {KEYWORD, "static", STATUS_STATIC, NULL},
+ {ENDTOKEN, "", STATUS, NULL}
+};
+
+static const struct token *match_token(const char *, const struct token *,
+ struct parse_result *);
+static void show_valid_args(const struct token *);
+
+struct parse_result *
+parse(int argc, char *argv[])
+{
+ static struct parse_result res;
+ const struct token *table = t_main;
+ const struct token *match;
+
+ memset(&res, 0, sizeof(res));
+
+ while (argc >= 0) {
+ if ((match = match_token(argv[0], table, &res)) == NULL) {
+ fprintf(stderr, "valid commands/args:\n");
+ show_valid_args(table);
+ return (NULL);
+ }
+
+ argc--;
+ argv++;
+
+ if (match->type == NOTOKEN || match->next == NULL)
+ break;
+
+ table = match->next;
+ }
+
+ if (argc > 0) {
+ fprintf(stderr, "superfluous argument: %s\n", argv[0]);
+ return (NULL);
+ }
+
+ return (&res);
+}
+
+static const struct token *
+match_token(const char *word, const struct token *table,
+ struct parse_result *res)
+{
+ u_int i, match;
+ const struct token *t = NULL;
+
+ match = 0;
+
+ for (i = 0; table[i].type != ENDTOKEN; i++) {
+ switch (table[i].type) {
+ case NOTOKEN:
+ if (word == NULL || strlen(word) == 0) {
+ match++;
+ t = &table[i];
+ }
+ break;
+ case KEYWORD:
+ if (word != NULL && strncmp(word, table[i].keyword,
+ strlen(word)) == 0) {
+ match++;
+ t = &table[i];
+ if (t->value)
+ res->action = t->value;
+ }
+ break;
+ case ENDTOKEN:
+ break;
+ }
+ }
+
+ if (match != 1) {
+ if (word == NULL)
+ fprintf(stderr, "missing argument:\n");
+ else if (match > 1)
+ fprintf(stderr, "ambiguous argument: %s\n", word);
+ else if (match < 1)
+ fprintf(stderr, "unknown argument: %s\n", word);
+ return (NULL);
+ }
+
+ return (t);
+}
+
+static void
+show_valid_args(const struct token *table)
+{
+ int i;
+
+ for (i = 0; table[i].type != ENDTOKEN; i++) {
+ switch (table[i].type) {
+ case NOTOKEN:
+ fprintf(stderr, " <cr>\n");
+ break;
+ case KEYWORD:
+ fprintf(stderr, " %s\n", table[i].keyword);
+ break;
+ case ENDTOKEN:
+ break;
+ }
+ }
+}
diff --git a/usr.sbin/unwindctl/parser.h b/usr.sbin/unwindctl/parser.h
new file mode 100644
index 00000000000..65efcb7e10b
--- /dev/null
+++ b/usr.sbin/unwindctl/parser.h
@@ -0,0 +1,36 @@
+/* $OpenBSD: parser.h,v 1.1 2019/01/23 13:12:19 florian Exp $ */
+
+/*
+ * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
+ * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
+ *
+ * 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 actions {
+ NONE,
+ LOG_DEBUG,
+ LOG_VERBOSE,
+ LOG_BRIEF,
+ RELOAD,
+ STATUS,
+ STATUS_RECURSOR,
+ STATUS_DHCP,
+ STATUS_STATIC
+};
+
+struct parse_result {
+ enum actions action;
+};
+
+struct parse_result *parse(int, char *[]);
diff --git a/usr.sbin/unwindctl/unwindctl.8 b/usr.sbin/unwindctl/unwindctl.8
new file mode 100644
index 00000000000..f8dd5a47b2e
--- /dev/null
+++ b/usr.sbin/unwindctl/unwindctl.8
@@ -0,0 +1,81 @@
+.\" $OpenBSD: unwindctl.8,v 1.1 2019/01/23 13:12:19 florian Exp $
+.\"
+.\" Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
+.\"
+.\" 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.
+.\"
+.Dd $Mdocdate: January 23 2019 $
+.Dt UNWINDCTL 8
+.Os
+.Sh NAME
+.Nm unwindctl
+.Nd control the unwind daemon
+.Sh SYNOPSIS
+.Nm
+.Op Fl s Ar socket
+.Ar command
+.Op Ar argument ...
+.Sh DESCRIPTION
+The
+.Nm
+program controls the
+.Xr unwind 8
+daemon.
+.Pp
+The following options are available:
+.Bl -tag -width Ds
+.It Fl s Ar socket
+Use
+.Ar socket
+instead of the default
+.Pa /var/run/unwind.sock
+to communicate with
+.Xr unwind 8 .
+.El
+.Pp
+The following commands are available:
+.Bl -tag -width Ds
+.It Cm log brief
+Disable verbose logging.
+.It Cm log verbose
+Enable verbose logging.
+.It Cm log debug
+Enable very noisy debug logging.
+.It Cm reload
+Reload the configuration file.
+.It Cm status Op Cm recursor Cm dhcp Cm static
+Show a status summary.
+If one of
+.Cm recursor ,
+.Cm dhcp
+or
+.Cm static
+is given more detailed information is given.
+Including reasons why DNSSEC validation might be failing and a query time
+histogram.
+.El
+.Sh FILES
+.Bl -tag -width "/var/run/unwind.sockXX" -compact
+.It Pa /var/run/unwind.sock
+.Ux Ns -domain
+socket used for communication with
+.Xr unwind 8 .
+.El
+.Sh SEE ALSO
+.Xr unwind.conf 5 ,
+.Xr unwind 8
+.Sh HISTORY
+The
+.Nm
+program first appeared in
+.Ox 6.5 .
diff --git a/usr.sbin/unwindctl/unwindctl.c b/usr.sbin/unwindctl/unwindctl.c
new file mode 100644
index 00000000000..4cd62d4908b
--- /dev/null
+++ b/usr.sbin/unwindctl/unwindctl.c
@@ -0,0 +1,276 @@
+/* $OpenBSD: unwindctl.c,v 1.1 2019/01/23 13:12:19 florian Exp $ */
+
+/*
+ * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
+ * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
+ * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
+ *
+ * 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/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+
+#include <err.h>
+#include <errno.h>
+#include <event.h>
+#include <imsg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "unwind.h"
+#include "frontend.h"
+#include "resolver.h"
+#include "parser.h"
+
+__dead void usage(void);
+int show_status_msg(struct imsg *);
+void print_indented_str(char *);
+void print_histogram(void*, size_t len);
+
+struct imsgbuf *ibuf;
+
+__dead void
+usage(void)
+{
+ extern char *__progname;
+
+ fprintf(stderr, "usage: %s [-s socket] command [argument ...]\n",
+ __progname);
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct sockaddr_un sun;
+ struct parse_result *res;
+ struct imsg imsg;
+ int ctl_sock;
+ int done = 0;
+ int n, verbose = 0;
+ int ch;
+ int type;
+ char *sockname;
+
+ sockname = UNWIND_SOCKET;
+ while ((ch = getopt(argc, argv, "s:")) != -1) {
+ switch (ch) {
+ case 's':
+ sockname = optarg;
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* Parse command line. */
+ if ((res = parse(argc, argv)) == NULL)
+ exit(1);
+
+ /* Connect to control socket. */
+ if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
+ err(1, "socket");
+
+ memset(&sun, 0, sizeof(sun));
+ sun.sun_family = AF_UNIX;
+
+ strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path));
+ if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1)
+ err(1, "connect: %s", sockname);
+
+ if (pledge("stdio", NULL) == -1)
+ err(1, "pledge");
+
+ if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)
+ err(1, NULL);
+ imsg_init(ibuf, ctl_sock);
+ done = 0;
+
+ /* Process user request. */
+ switch (res->action) {
+ case LOG_DEBUG:
+ verbose |= OPT_VERBOSE2;
+ /* FALLTHROUGH */
+ case LOG_VERBOSE:
+ verbose |= OPT_VERBOSE;
+ /* FALLTHROUGH */
+ case LOG_BRIEF:
+ imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1,
+ &verbose, sizeof(verbose));
+ printf("logging request sent.\n");
+ done = 1;
+ break;
+ case RELOAD:
+ imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0);
+ printf("reload request sent.\n");
+ done = 1;
+ break;
+ case STATUS_RECURSOR:
+ type = RECURSOR;
+ imsg_compose(ibuf, IMSG_CTL_STATUS, 0, 0, -1, &type,
+ sizeof(type));
+ break;
+ case STATUS_DHCP:
+ type = FORWARDER;
+ imsg_compose(ibuf, IMSG_CTL_STATUS, 0, 0, -1, &type,
+ sizeof(type));
+ break;
+ case STATUS_STATIC:
+ type = STATIC_FORWARDER;
+ imsg_compose(ibuf, IMSG_CTL_STATUS, 0, 0, -1, &type,
+ sizeof(type));
+ break;
+ case STATUS:
+ type = RESOLVER_NONE;
+ imsg_compose(ibuf, IMSG_CTL_STATUS, 0, 0, -1, &type,
+ sizeof(type));
+ break;
+ default:
+ usage();
+ }
+
+ while (ibuf->w.queued)
+ if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN)
+ err(1, "write error");
+
+ while (!done) {
+ if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
+ errx(1, "imsg_read error");
+ if (n == 0)
+ errx(1, "pipe closed");
+
+ while (!done) {
+ if ((n = imsg_get(ibuf, &imsg)) == -1)
+ errx(1, "imsg_get error");
+ if (n == 0)
+ break;
+
+ switch (res->action) {
+ case STATUS:
+ case STATUS_RECURSOR:
+ case STATUS_DHCP:
+ case STATUS_STATIC:
+ done = show_status_msg(&imsg);
+ break;
+ default:
+ break;
+ }
+ imsg_free(&imsg);
+ }
+ }
+ close(ctl_sock);
+ free(ibuf);
+
+ return (0);
+}
+
+int
+show_status_msg(struct imsg *imsg)
+{
+ static int header;
+ struct ctl_resolver_info *cri;
+
+ if (!header++)
+ printf("%8s %16s %s\n", "selected", "type", "status");
+
+ switch (imsg->hdr.type) {
+ case IMSG_CTL_RESOLVER_INFO:
+ cri = imsg->data;
+ printf("%8s %16s %s\n", cri->selected ? "*" : " ",
+ unwind_resolver_type_str[cri->type],
+ unwind_resolver_state_str[cri->state]);
+ break;
+ case IMSG_CTL_RESOLVER_WHY_BOGUS:
+ /* make sure this is a string */
+ ((char *)imsg->data)[imsg->hdr.len - IMSG_HEADER_SIZE -1] =
+ '\0';
+ printf("\nReason for not validating:\n");
+ print_indented_str(imsg->data);
+ break;
+ case IMSG_CTL_RESOLVER_HISTOGRAM:
+ print_histogram(imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE);
+ break;
+ case IMSG_CTL_END:
+ return (1);
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+void
+print_indented_str(char * str)
+{
+ int i;
+ char *cur;
+
+ if (strlen(str) <= 72) {
+ printf("\t%s\n", str);
+ return;
+ }
+
+ for (i = 71; i >= 0; i--)
+ if (str[i] == ' ')
+ break;
+
+ if (i < 0)
+ cur = strchr(str, ' ');
+ else
+ cur = &str[i];
+
+
+ if (cur == NULL)
+ printf("\t%s\n", str);
+ else {
+ *cur = '\0';
+ printf("\t%s\n", str);
+ print_indented_str(cur + 1);
+ }
+}
+
+void
+print_histogram(void* data, size_t len)
+{
+ int64_t histogram[nitems(histogram_limits)];
+ size_t i;
+ char buf[10];
+
+ if (len != sizeof(histogram))
+ errx(1, "invalid histogram size");
+
+ printf("\n%40s\n", "histogram[ms]");
+
+ memcpy(histogram, data, len);
+
+ for(i = 1; i < nitems(histogram_limits) - 1; i++) {
+ snprintf(buf, sizeof(buf), "<%lld", histogram_limits[i]);
+ printf("%6s", buf);
+ }
+ printf("%6s\n", ">");
+ for(i = 1; i < nitems(histogram); i++)
+ printf("%6lld", histogram[i]);
+ printf("\n");
+}