Hi, So here's a new diff that incorporates the bug fix mentioned plus debug printf line changes suggested by Stuart.
Please note that this is a diff on top of very recent current, i.e. florian's work he committed today. That means that you need to be up-to-date (including a recent libc update that was committed a few days ago) to be able to test this version. -Otto Index: sbin/unwind/parse.y =================================================================== RCS file: /cvs/src/sbin/unwind/parse.y,v retrieving revision 1.12 diff -u -p -r1.12 parse.y --- sbin/unwind/parse.y 31 Oct 2019 12:51:43 -0000 1.12 +++ sbin/unwind/parse.y 31 Oct 2019 16:32:27 -0000 @@ -84,7 +84,6 @@ int check_pref_uniq(enum uw_resolver_ty static struct uw_conf *conf; static int errors; -static struct uw_forwarder *uw_forwarder; void clear_config(struct uw_conf *xconf); struct sockaddr_storage *host_ip(const char *); @@ -287,7 +286,9 @@ forwarderopts_l : forwarderopts_l forwa forwarderoptsl : STRING port authname dot { int ret, port; + struct uw_forwarder *uw_fwd; struct sockaddr_storage *ss; + if ((ss = host_ip($1)) == NULL) { yyerror("%s is not an ip-address", $1); free($1); @@ -305,37 +306,53 @@ forwarderoptsl : STRING port authname d else port = $2; - if ((uw_forwarder = calloc(1, - sizeof(*uw_forwarder))) == NULL) + if ($3 != NULL && $4 == 0) { + yyerror("authentication name can only " + "be used with DoT"); + free($1); + YYERROR; + } + + + if ((uw_fwd = calloc(1, + sizeof(*uw_fwd))) == NULL) err(1, NULL); - if ($3 == NULL) - ret = snprintf(uw_forwarder->name, - sizeof(uw_forwarder->name), - "%s@%d", $1, port); - else - ret = snprintf(uw_forwarder->name, - sizeof(uw_forwarder->name), - "%s@%d#%s", $1, port, $3); + if ($4 == DOT) { + if ($3 == NULL) + ret = snprintf(uw_fwd->name, + sizeof(uw_fwd->name), + "%s@%d", $1, port); + else + ret = snprintf(uw_fwd->name, + sizeof(uw_fwd->name), + "%s@%d#%s", $1, port, $3); + } else { + uw_fwd->port = $2; + /* complete string wil be done later */ + ret = snprintf(uw_fwd->name, + sizeof(uw_fwd->name), "%s", $1); + } if (ret < 0 || (size_t)ret >= - sizeof(uw_forwarder->name)) { - free(uw_forwarder); + sizeof(uw_fwd->name)) { + free(uw_fwd); yyerror("forwarder %s too long", $1); free($1); YYERROR; } - free($1); if ($4 == DOT) SIMPLEQ_INSERT_TAIL( &conf->uw_dot_forwarder_list, - uw_forwarder, entry); - else + uw_fwd, entry); + else { SIMPLEQ_INSERT_TAIL( &conf->uw_forwarder_list, - uw_forwarder, entry); + uw_fwd, entry); + } + free($1); } - ; + ; port : PORT NUMBER { $$ = $2; } | /* empty */ { $$ = 0; } @@ -874,12 +891,14 @@ symget(const char *nam) void clear_config(struct uw_conf *xconf) { - while((uw_forwarder = SIMPLEQ_FIRST(&xconf->uw_forwarder_list)) != + struct uw_forwarder *uw_forwarder; + + while ((uw_forwarder = SIMPLEQ_FIRST(&xconf->uw_forwarder_list)) != NULL) { SIMPLEQ_REMOVE_HEAD(&xconf->uw_forwarder_list, entry); free(uw_forwarder); } - while((uw_forwarder = SIMPLEQ_FIRST(&xconf->uw_dot_forwarder_list)) != + while ((uw_forwarder = SIMPLEQ_FIRST(&xconf->uw_dot_forwarder_list)) != NULL) { SIMPLEQ_REMOVE_HEAD(&xconf->uw_dot_forwarder_list, entry); free(uw_forwarder); Index: sbin/unwind/resolver.c =================================================================== RCS file: /cvs/src/sbin/unwind/resolver.c,v retrieving revision 1.48 diff -u -p -r1.48 resolver.c --- sbin/unwind/resolver.c 31 Oct 2019 12:54:40 -0000 1.48 +++ sbin/unwind/resolver.c 31 Oct 2019 16:32:27 -0000 @@ -115,6 +115,8 @@ struct uw_resolver *create_resolver(enum void free_resolver(struct uw_resolver *); void set_forwarders(struct uw_resolver *, struct uw_forwarder_head *); +void set_forwarders_oppdot(struct uw_resolver *, + struct uw_forwarder_head *, int); void resolver_check_timo(int, short, void *); void resolver_free_timo(int, short, void *); void check_resolver(struct uw_resolver *); @@ -164,6 +166,7 @@ struct event_base *ev_base; enum uw_resolver_state global_state = DEAD; enum captive_portal_state captive_portal_state = PORTAL_UNCHECKED; +int dhcp_oppdot, forw_oppdot; void resolver_sig_handler(int sig, short event, void *arg) @@ -607,6 +610,7 @@ resolver_dispatch_main(int fd, short eve nconf = NULL; if (forwarders_changed) { log_debug("static forwarders changed"); + forw_oppdot = 1; new_static_forwarders(); } if (dot_forwarders_changed) { @@ -768,7 +772,7 @@ parse_dhcp_forwarders(char *forwarders) if (forwarders != NULL) { while((ns = strsep(&forwarders, ",")) != NULL) { log_debug("%s: %s", __func__, ns); - if ((uw_forwarder = malloc(sizeof(struct + if ((uw_forwarder = calloc(1, sizeof(struct uw_forwarder))) == NULL) fatal(NULL); if (strlcpy(uw_forwarder->name, ns, @@ -782,6 +786,7 @@ parse_dhcp_forwarders(char *forwarders) if (check_forwarders_changed(&new_forwarder_list, &dhcp_forwarder_list)) { + dhcp_oppdot = 1; replace_forwarders(&new_forwarder_list, &dhcp_forwarder_list); new_forwarders(); new_asr_forwarders(); @@ -985,10 +990,24 @@ create_resolver(enum uw_resolver_type ty case UW_RES_RECURSOR: break; case UW_RES_DHCP: - set_forwarders(res, &dhcp_forwarder_list); + if (dhcp_oppdot) { + set_forwarders_oppdot(res, &dhcp_forwarder_list, 853); + ub_ctx_set_option(res->ctx, "tls-cert-bundle:", + tls_default_ca_cert_file()); + ub_ctx_set_tls(res->ctx, 1); + } else + set_forwarders_oppdot(res, &dhcp_forwarder_list, 53); break; case UW_RES_FORWARDER: - set_forwarders(res, &resolver_conf->uw_forwarder_list); + if (forw_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()); + ub_ctx_set_tls(res->ctx, 1); + } else + set_forwarders_oppdot(res, + &resolver_conf->uw_forwarder_list, 53); break; case UW_RES_DOT: set_forwarders(res, &resolver_conf->uw_dot_forwarder_list); @@ -1034,6 +1053,22 @@ set_forwarders(struct uw_resolver *res, } void +set_forwarders_oppdot(struct uw_resolver *res, struct uw_forwarder_head + *uw_forwarder_list, int def_port) +{ + struct uw_forwarder *uw_forwarder; + + SIMPLEQ_FOREACH(uw_forwarder, uw_forwarder_list, entry) { + char name[1024]; + int port = uw_forwarder->port; + if (port == 0) + port = def_port; + snprintf(name, sizeof(name), "%s@%d", uw_forwarder->name, port); + ub_ctx_set_fwd(res->ctx, name); + } +} + +void resolver_check_timo(int fd, short events, void *arg) { check_resolver((struct uw_resolver *)arg); @@ -1089,7 +1124,7 @@ check_resolver_done(void *arg, int rcode data = (struct check_resolver_data *)arg; - log_debug("%s: rcode: %d", __func__, rcode); + log_debug("%s: %s rcode: %d", __func__, uw_resolver_type_str[data->res->type], rcode); prev_state = data->res->state; @@ -1101,6 +1136,25 @@ check_resolver_done(void *arg, int rcode if (rcode == LDNS_RCODE_SERVFAIL) { data->res->state = DEAD; + + switch (data->res->type) { + case UW_RES_DHCP: + if (dhcp_oppdot) { + dhcp_oppdot = 0; + log_debug("disabling DHCP OppDoT"); + new_forwarders(); + } + break; + case UW_RES_FORWARDER: + if (forw_oppdot) { + forw_oppdot = 0; + log_debug("disabling forwarder OppDoT"); + new_static_forwarders(); + } + break; + default: + break; + } goto out; } @@ -1259,9 +1313,9 @@ struct uw_resolver* best_resolver(void) { struct uw_resolver *res = NULL; - int i; + int i, oppdot; - log_debug("%s: %s: %s, %s: %s, %s: %s, %s: %s, %s: %s, " + 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] @@ -1269,9 +1323,11 @@ best_resolver(void) : "NA", uw_resolver_type_str[UW_RES_DHCP], resolvers[UW_RES_DHCP] != NULL ? uw_resolver_state_str[resolvers[UW_RES_DHCP]->state] : "NA", + 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", + forw_oppdot ? " (OppDot)" : "", uw_resolver_type_str[UW_RES_DOT], resolvers[UW_RES_DOT] != NULL ? uw_resolver_state_str[resolvers[UW_RES_DOT]->state] : "NA", @@ -1295,8 +1351,10 @@ best_resolver(void) resolvers[resolver_conf->res_pref[i]]) < 0) res = resolvers[resolver_conf->res_pref[i]]; out: - log_debug("%s: %s state: %s", __func__, uw_resolver_type_str[res->type], - uw_resolver_state_str[res->state]); + oppdot = (res->type == UW_RES_DHCP && dhcp_oppdot) || + (res->type == UW_RES_FORWARDER && forw_oppdot); + log_debug("%s: %s state: %s%s", __func__, uw_resolver_type_str[res->type], + uw_resolver_state_str[res->state], oppdot ? " (OppDoT)" : ""); return (res); } @@ -1376,6 +1434,12 @@ send_resolver_info(struct uw_resolver *r cri.state = res->state; cri.type = res->type; cri.selected = selected; + if (cri.type == UW_RES_DHCP && dhcp_oppdot) + cri.oppdot = 1; + else if (cri.type == UW_RES_FORWARDER && forw_oppdot) + cri.oppdot = 1; + else + cri.oppdot = 0; resolver_imsg_compose_frontend(IMSG_CTL_RESOLVER_INFO, pid, &cri, sizeof(cri)); } Index: sbin/unwind/resolver.h =================================================================== RCS file: /cvs/src/sbin/unwind/resolver.h,v retrieving revision 1.6 diff -u -p -r1.6 resolver.h --- sbin/unwind/resolver.h 2 Apr 2019 07:47:23 -0000 1.6 +++ sbin/unwind/resolver.h 31 Oct 2019 16:32:27 -0000 @@ -51,6 +51,7 @@ struct ctl_resolver_info { enum uw_resolver_state state; enum uw_resolver_type type; int selected; + int oppdot; }; void resolver(int, int); Index: sbin/unwind/unwind.h =================================================================== RCS file: /cvs/src/sbin/unwind/unwind.h,v retrieving revision 1.20 diff -u -p -r1.20 unwind.h --- sbin/unwind/unwind.h 31 Oct 2019 12:54:40 -0000 1.20 +++ sbin/unwind/unwind.h 31 Oct 2019 16:32:27 -0000 @@ -126,6 +126,7 @@ enum imsg_type { struct uw_forwarder { SIMPLEQ_ENTRY(uw_forwarder) entry; char name[1024]; /* XXX */ + uint16_t port; }; SIMPLEQ_HEAD(uw_forwarder_head, uw_forwarder); Index: usr.sbin/unwindctl/parser.c =================================================================== RCS file: /cvs/src/usr.sbin/unwindctl/parser.c,v retrieving revision 1.4 diff -u -p -r1.4 parser.c --- usr.sbin/unwindctl/parser.c 31 Oct 2019 12:51:43 -0000 1.4 +++ usr.sbin/unwindctl/parser.c 31 Oct 2019 16:32:27 -0000 @@ -72,7 +72,7 @@ static const struct token t_status[] = { {NOTOKEN, "", NONE, NULL}, {KEYWORD, "recursor", STATUS_RECURSOR, NULL}, {KEYWORD, "dhcp", STATUS_DHCP, NULL}, - {KEYWORD, "static", STATUS_STATIC, NULL}, + {KEYWORD, "forwarder", STATUS_STATIC, NULL}, {KEYWORD, "DoT", STATUS_DOT, NULL}, {KEYWORD, "asr", STATUS_ASR, NULL}, {ENDTOKEN, "", STATUS, NULL} Index: usr.sbin/unwindctl/unwindctl.8 =================================================================== RCS file: /cvs/src/usr.sbin/unwindctl/unwindctl.8,v retrieving revision 1.4 diff -u -p -r1.4 unwindctl.8 --- usr.sbin/unwindctl/unwindctl.8 5 Feb 2019 20:41:12 -0000 1.4 +++ usr.sbin/unwindctl/unwindctl.8 31 Oct 2019 16:32:27 -0000 @@ -55,14 +55,14 @@ Enable very noisy debug logging. Reload the configuration file. .It Cm recheck portal Run the captive portal detection. -.It Cm status Op Cm recursor | dhcp | DoT | static +.It Cm status Op Cm recursor | dhcp | DoT | forwarder Show a status summary. If one of .Cm recursor , .Cm dhcp , .Cm DoT , or -.Cm static +.Cm forwarder is specified, more detailed information about that type of resolver is given including reasons why DNSSEC validation might be failing and a query time histogram. Index: usr.sbin/unwindctl/unwindctl.c =================================================================== RCS file: /cvs/src/usr.sbin/unwindctl/unwindctl.c,v retrieving revision 1.7 diff -u -p -r1.7 unwindctl.c --- usr.sbin/unwindctl/unwindctl.c 31 Oct 2019 12:51:43 -0000 1.7 +++ usr.sbin/unwindctl/unwindctl.c 31 Oct 2019 16:32:27 -0000 @@ -247,9 +247,10 @@ show_status_msg(struct imsg *imsg) break; case IMSG_CTL_RESOLVER_INFO: cri = imsg->data; - printf("%8s %16s %s\n", cri->selected ? "*" : " ", + printf("%8s %16s %s%s\n", cri->selected ? "*" : " ", uw_resolver_type_str[cri->type], - uw_resolver_state_str[cri->state]); + uw_resolver_state_str[cri->state], + cri->oppdot ? " (OppDoT)" : ""); break; case IMSG_CTL_RESOLVER_WHY_BOGUS: /* make sure this is a string */