1*28ba4729Sflorian /* $OpenBSD: unwindctl.c,v 1.11 2019/11/11 05:51:06 florian Exp $ */ 25c077b0fSflorian 35c077b0fSflorian /* 45c077b0fSflorian * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 55c077b0fSflorian * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org> 65c077b0fSflorian * Copyright (c) 2003 Henning Brauer <henning@openbsd.org> 75c077b0fSflorian * 85c077b0fSflorian * Permission to use, copy, modify, and distribute this software for any 95c077b0fSflorian * purpose with or without fee is hereby granted, provided that the above 105c077b0fSflorian * copyright notice and this permission notice appear in all copies. 115c077b0fSflorian * 125c077b0fSflorian * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 135c077b0fSflorian * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 145c077b0fSflorian * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 155c077b0fSflorian * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 165c077b0fSflorian * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 175c077b0fSflorian * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 185c077b0fSflorian * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 195c077b0fSflorian */ 205c077b0fSflorian 215c077b0fSflorian #include <sys/types.h> 225c077b0fSflorian #include <sys/queue.h> 235c077b0fSflorian #include <sys/socket.h> 245c077b0fSflorian #include <sys/un.h> 255c077b0fSflorian #include <netinet/in.h> 265c077b0fSflorian #include <arpa/inet.h> 275c077b0fSflorian #include <net/if.h> 285c077b0fSflorian #include <net/if_media.h> 295c077b0fSflorian #include <net/if_types.h> 30*28ba4729Sflorian #include <net/route.h> 315c077b0fSflorian 325c077b0fSflorian #include <err.h> 335c077b0fSflorian #include <errno.h> 345c077b0fSflorian #include <event.h> 355c077b0fSflorian #include <imsg.h> 365c077b0fSflorian #include <stdio.h> 375c077b0fSflorian #include <stdlib.h> 385c077b0fSflorian #include <string.h> 395c077b0fSflorian #include <unistd.h> 405c077b0fSflorian 415c077b0fSflorian #include "unwind.h" 42b2501eadSflorian #include "captiveportal.h" 435c077b0fSflorian #include "frontend.h" 445c077b0fSflorian #include "resolver.h" 455c077b0fSflorian #include "parser.h" 465c077b0fSflorian 475c077b0fSflorian __dead void usage(void); 485c077b0fSflorian int show_status_msg(struct imsg *); 495c077b0fSflorian void print_indented_str(char *); 505c077b0fSflorian void print_histogram(void*, size_t len); 515c077b0fSflorian 525c077b0fSflorian struct imsgbuf *ibuf; 535c077b0fSflorian 545c077b0fSflorian __dead void 555c077b0fSflorian usage(void) 565c077b0fSflorian { 575c077b0fSflorian extern char *__progname; 585c077b0fSflorian 595c077b0fSflorian fprintf(stderr, "usage: %s [-s socket] command [argument ...]\n", 605c077b0fSflorian __progname); 615c077b0fSflorian exit(1); 625c077b0fSflorian } 635c077b0fSflorian 645c077b0fSflorian int 655c077b0fSflorian main(int argc, char *argv[]) 665c077b0fSflorian { 675c077b0fSflorian struct sockaddr_un sun; 685c077b0fSflorian struct parse_result *res; 695c077b0fSflorian struct imsg imsg; 705c077b0fSflorian int ctl_sock; 715c077b0fSflorian int done = 0; 725c077b0fSflorian int n, verbose = 0; 735c077b0fSflorian int ch; 745c077b0fSflorian int type; 755c077b0fSflorian char *sockname; 765c077b0fSflorian 775c077b0fSflorian sockname = UNWIND_SOCKET; 785c077b0fSflorian while ((ch = getopt(argc, argv, "s:")) != -1) { 795c077b0fSflorian switch (ch) { 805c077b0fSflorian case 's': 815c077b0fSflorian sockname = optarg; 825c077b0fSflorian break; 835c077b0fSflorian default: 845c077b0fSflorian usage(); 855c077b0fSflorian } 865c077b0fSflorian } 875c077b0fSflorian argc -= optind; 885c077b0fSflorian argv += optind; 895c077b0fSflorian 905c077b0fSflorian /* Parse command line. */ 915c077b0fSflorian if ((res = parse(argc, argv)) == NULL) 925c077b0fSflorian exit(1); 935c077b0fSflorian 945c077b0fSflorian /* Connect to control socket. */ 955c077b0fSflorian if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 965c077b0fSflorian err(1, "socket"); 975c077b0fSflorian 985c077b0fSflorian memset(&sun, 0, sizeof(sun)); 995c077b0fSflorian sun.sun_family = AF_UNIX; 1005c077b0fSflorian strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path)); 101cee51daaSflorian 1025c077b0fSflorian if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) 1035c077b0fSflorian err(1, "connect: %s", sockname); 1045c077b0fSflorian 1055c077b0fSflorian if (pledge("stdio", NULL) == -1) 1065c077b0fSflorian err(1, "pledge"); 1075c077b0fSflorian 1085c077b0fSflorian if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL) 1095c077b0fSflorian err(1, NULL); 1105c077b0fSflorian imsg_init(ibuf, ctl_sock); 1115c077b0fSflorian done = 0; 1125c077b0fSflorian 1133a1cc939Ssolene /* Check for root-only actions */ 1143a1cc939Ssolene switch (res->action) { 1153a1cc939Ssolene case LOG_DEBUG: 1163a1cc939Ssolene case LOG_VERBOSE: 1173a1cc939Ssolene case LOG_BRIEF: 1183a1cc939Ssolene case RELOAD: 1193a1cc939Ssolene if (geteuid() != 0) 1203a1cc939Ssolene errx(1, "need root privileges"); 1213a1cc939Ssolene break; 1223a1cc939Ssolene default: 1233a1cc939Ssolene break; 1243a1cc939Ssolene } 1253a1cc939Ssolene 1265c077b0fSflorian /* Process user request. */ 1275c077b0fSflorian switch (res->action) { 1285c077b0fSflorian case LOG_DEBUG: 1295c077b0fSflorian verbose |= OPT_VERBOSE2; 1305c077b0fSflorian /* FALLTHROUGH */ 1315c077b0fSflorian case LOG_VERBOSE: 1325c077b0fSflorian verbose |= OPT_VERBOSE; 1335c077b0fSflorian /* FALLTHROUGH */ 1345c077b0fSflorian case LOG_BRIEF: 1355c077b0fSflorian imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1, 1365c077b0fSflorian &verbose, sizeof(verbose)); 1375c077b0fSflorian printf("logging request sent.\n"); 1385c077b0fSflorian done = 1; 1395c077b0fSflorian break; 1405c077b0fSflorian case RELOAD: 1415c077b0fSflorian imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0); 1425c077b0fSflorian printf("reload request sent.\n"); 1435c077b0fSflorian done = 1; 1445c077b0fSflorian break; 145b2501eadSflorian case PORTAL: 146b2501eadSflorian imsg_compose(ibuf, IMSG_CTL_RECHECK_CAPTIVEPORTAL, 0, 0, -1, 147b2501eadSflorian NULL, 0); 148b2501eadSflorian printf("recheck request sent.\n"); 149b2501eadSflorian done = 1; 150b2501eadSflorian break; 1515c077b0fSflorian case STATUS_RECURSOR: 152fd873f7fSflorian type = UW_RES_RECURSOR; 1535c077b0fSflorian imsg_compose(ibuf, IMSG_CTL_STATUS, 0, 0, -1, &type, 1545c077b0fSflorian sizeof(type)); 1555c077b0fSflorian break; 1565c077b0fSflorian case STATUS_DHCP: 157fd873f7fSflorian type = UW_RES_DHCP; 1585c077b0fSflorian imsg_compose(ibuf, IMSG_CTL_STATUS, 0, 0, -1, &type, 1595c077b0fSflorian sizeof(type)); 1605c077b0fSflorian break; 1615c077b0fSflorian case STATUS_STATIC: 162fd873f7fSflorian type = UW_RES_FORWARDER; 1635c077b0fSflorian imsg_compose(ibuf, IMSG_CTL_STATUS, 0, 0, -1, &type, 1645c077b0fSflorian sizeof(type)); 1655c077b0fSflorian break; 16646e4cbfcSflorian case STATUS_DOT: 167fd873f7fSflorian type = UW_RES_DOT; 16846e4cbfcSflorian imsg_compose(ibuf, IMSG_CTL_STATUS, 0, 0, -1, &type, 16946e4cbfcSflorian sizeof(type)); 17046e4cbfcSflorian break; 171217b4d33Sflorian case STATUS_STUB: 172530f5ecfSflorian type = UW_RES_ASR; 173530f5ecfSflorian imsg_compose(ibuf, IMSG_CTL_STATUS, 0, 0, -1, &type, 174530f5ecfSflorian sizeof(type)); 175530f5ecfSflorian break; 1765c077b0fSflorian case STATUS: 177fd873f7fSflorian type = UW_RES_NONE; 1785c077b0fSflorian imsg_compose(ibuf, IMSG_CTL_STATUS, 0, 0, -1, &type, 1795c077b0fSflorian sizeof(type)); 1805c077b0fSflorian break; 1815c077b0fSflorian default: 1825c077b0fSflorian usage(); 1835c077b0fSflorian } 1845c077b0fSflorian 1855c077b0fSflorian while (ibuf->w.queued) 1865c077b0fSflorian if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) 1875c077b0fSflorian err(1, "write error"); 1885c077b0fSflorian 1895c077b0fSflorian while (!done) { 1905c077b0fSflorian if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 1915c077b0fSflorian errx(1, "imsg_read error"); 1925c077b0fSflorian if (n == 0) 1935c077b0fSflorian errx(1, "pipe closed"); 1945c077b0fSflorian 1955c077b0fSflorian while (!done) { 1965c077b0fSflorian if ((n = imsg_get(ibuf, &imsg)) == -1) 1975c077b0fSflorian errx(1, "imsg_get error"); 1985c077b0fSflorian if (n == 0) 1995c077b0fSflorian break; 2005c077b0fSflorian 2015c077b0fSflorian switch (res->action) { 2025c077b0fSflorian case STATUS: 2035c077b0fSflorian case STATUS_RECURSOR: 2045c077b0fSflorian case STATUS_DHCP: 2055c077b0fSflorian case STATUS_STATIC: 20646e4cbfcSflorian case STATUS_DOT: 207217b4d33Sflorian case STATUS_STUB: 2085c077b0fSflorian done = show_status_msg(&imsg); 2095c077b0fSflorian break; 2105c077b0fSflorian default: 2115c077b0fSflorian break; 2125c077b0fSflorian } 2135c077b0fSflorian imsg_free(&imsg); 2145c077b0fSflorian } 2155c077b0fSflorian } 2165c077b0fSflorian close(ctl_sock); 2175c077b0fSflorian free(ibuf); 2185c077b0fSflorian 2195c077b0fSflorian return (0); 2205c077b0fSflorian } 2215c077b0fSflorian 2225c077b0fSflorian int 2235c077b0fSflorian show_status_msg(struct imsg *imsg) 2245c077b0fSflorian { 2255c077b0fSflorian static int header; 2265c077b0fSflorian struct ctl_resolver_info *cri; 227b2501eadSflorian enum captive_portal_state captive_portal_state; 2285c077b0fSflorian 229b2501eadSflorian if (imsg->hdr.type != IMSG_CTL_CAPTIVEPORTAL_INFO && !header++) 2305c077b0fSflorian printf("%8s %16s %s\n", "selected", "type", "status"); 2315c077b0fSflorian 2325c077b0fSflorian switch (imsg->hdr.type) { 233b2501eadSflorian case IMSG_CTL_CAPTIVEPORTAL_INFO: 234b2501eadSflorian memcpy(&captive_portal_state, imsg->data, 235b2501eadSflorian sizeof(captive_portal_state)); 236b2501eadSflorian switch (captive_portal_state) { 237b2501eadSflorian case PORTAL_UNCHECKED: 238b2501eadSflorian case PORTAL_UNKNOWN: 239b2501eadSflorian printf("captive portal is %s\n\n", 240b2501eadSflorian captive_portal_state_str[captive_portal_state]); 241b2501eadSflorian break; 242b2501eadSflorian case BEHIND: 243b2501eadSflorian case NOT_BEHIND: 244b2501eadSflorian printf("%s captive portal\n\n", 245b2501eadSflorian captive_portal_state_str[captive_portal_state]); 246b2501eadSflorian break; 247b2501eadSflorian } 248b2501eadSflorian break; 2495c077b0fSflorian case IMSG_CTL_RESOLVER_INFO: 2505c077b0fSflorian cri = imsg->data; 2511d722b06Sotto printf("%8s %16s %s%s\n", cri->selected ? "*" : " ", 25215621e39Sflorian uw_resolver_type_str[cri->type], 2531d722b06Sotto uw_resolver_state_str[cri->state], 2541d722b06Sotto cri->oppdot ? " (opportunistic DoT)" : ""); 2555c077b0fSflorian break; 2565c077b0fSflorian case IMSG_CTL_RESOLVER_WHY_BOGUS: 2575c077b0fSflorian /* make sure this is a string */ 2585c077b0fSflorian ((char *)imsg->data)[imsg->hdr.len - IMSG_HEADER_SIZE -1] = 2595c077b0fSflorian '\0'; 2605c077b0fSflorian printf("\nReason for not validating:\n"); 2615c077b0fSflorian print_indented_str(imsg->data); 2625c077b0fSflorian break; 2635c077b0fSflorian case IMSG_CTL_RESOLVER_HISTOGRAM: 2645c077b0fSflorian print_histogram(imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE); 2655c077b0fSflorian break; 2665c077b0fSflorian case IMSG_CTL_END: 2675c077b0fSflorian return (1); 2685c077b0fSflorian default: 2695c077b0fSflorian break; 2705c077b0fSflorian } 2715c077b0fSflorian 2725c077b0fSflorian return (0); 2735c077b0fSflorian } 2745c077b0fSflorian 2755c077b0fSflorian void 2765c077b0fSflorian print_indented_str(char * str) 2775c077b0fSflorian { 2785c077b0fSflorian int i; 2795c077b0fSflorian char *cur; 2805c077b0fSflorian 2815c077b0fSflorian if (strlen(str) <= 72) { 2825c077b0fSflorian printf("\t%s\n", str); 2835c077b0fSflorian return; 2845c077b0fSflorian } 2855c077b0fSflorian 2865c077b0fSflorian for (i = 71; i >= 0; i--) 2875c077b0fSflorian if (str[i] == ' ') 2885c077b0fSflorian break; 2895c077b0fSflorian 2905c077b0fSflorian if (i < 0) 2915c077b0fSflorian cur = strchr(str, ' '); 2925c077b0fSflorian else 2935c077b0fSflorian cur = &str[i]; 2945c077b0fSflorian 2955c077b0fSflorian 2965c077b0fSflorian if (cur == NULL) 2975c077b0fSflorian printf("\t%s\n", str); 2985c077b0fSflorian else { 2995c077b0fSflorian *cur = '\0'; 3005c077b0fSflorian printf("\t%s\n", str); 3015c077b0fSflorian print_indented_str(cur + 1); 3025c077b0fSflorian } 3035c077b0fSflorian } 3045c077b0fSflorian 3055c077b0fSflorian void 3065c077b0fSflorian print_histogram(void* data, size_t len) 3075c077b0fSflorian { 3085c077b0fSflorian int64_t histogram[nitems(histogram_limits)]; 3095c077b0fSflorian size_t i; 3105c077b0fSflorian char buf[10]; 3115c077b0fSflorian 3125c077b0fSflorian if (len != sizeof(histogram)) 3135c077b0fSflorian errx(1, "invalid histogram size"); 3145c077b0fSflorian 3155c077b0fSflorian printf("\n%40s\n", "histogram[ms]"); 3165c077b0fSflorian 3175c077b0fSflorian memcpy(histogram, data, len); 3185c077b0fSflorian 3195c077b0fSflorian for(i = 1; i < nitems(histogram_limits) - 1; i++) { 3205c077b0fSflorian snprintf(buf, sizeof(buf), "<%lld", histogram_limits[i]); 3215c077b0fSflorian printf("%6s", buf); 3225c077b0fSflorian } 3235c077b0fSflorian printf("%6s\n", ">"); 3245c077b0fSflorian for(i = 1; i < nitems(histogram); i++) 3255c077b0fSflorian printf("%6lld", histogram[i]); 3265c077b0fSflorian printf("\n"); 3275c077b0fSflorian } 328