diff options
Diffstat (limited to 'sbin')
-rw-r--r-- | sbin/unwind/parse.y | 6 | ||||
-rw-r--r-- | sbin/unwind/resolver.c | 213 | ||||
-rw-r--r-- | sbin/unwind/unwind.c | 7 | ||||
-rw-r--r-- | sbin/unwind/unwind.conf.5 | 12 | ||||
-rw-r--r-- | sbin/unwind/unwind.h | 4 |
5 files changed, 187 insertions, 55 deletions
diff --git a/sbin/unwind/parse.y b/sbin/unwind/parse.y index ee9a7b74fd0..af81e630cd7 100644 --- a/sbin/unwind/parse.y +++ b/sbin/unwind/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.11 2019/10/21 07:16:09 florian Exp $ */ +/* $OpenBSD: parse.y,v 1.12 2019/10/31 12:51:43 florian Exp $ */ /* * Copyright (c) 2018 Florian Obser <florian@openbsd.org> @@ -101,7 +101,7 @@ typedef struct { %token YES NO INCLUDE ERROR %token FORWARDER DOT PORT CAPTIVE PORTAL URL EXPECTED RESPONSE -%token STATUS AUTO AUTHENTICATION NAME PREFERENCE RECURSOR DHCP +%token STATUS AUTO AUTHENTICATION NAME PREFERENCE RECURSOR DHCP ASR %token BLOCK LIST LOG %token <v.string> STRING @@ -271,6 +271,7 @@ prefopt : DOT { $$ = UW_RES_DOT; } | FORWARDER { $$ = UW_RES_FORWARDER; } | RECURSOR { $$ = UW_RES_RECURSOR; } | DHCP { $$ = UW_RES_DHCP; } + | ASR { $$ = UW_RES_ASR; } ; uw_forwarder : FORWARDER forwarder_block @@ -386,6 +387,7 @@ lookup(char *s) /* This has to be sorted always. */ static const struct keywords keywords[] = { {"DoT", DOT}, + {"asr", ASR}, {"authentication", AUTHENTICATION}, {"auto", AUTO}, {"block", BLOCK}, diff --git a/sbin/unwind/resolver.c b/sbin/unwind/resolver.c index 6287cad7326..9700e396bfc 100644 --- a/sbin/unwind/resolver.c +++ b/sbin/unwind/resolver.c @@ -1,4 +1,4 @@ -/* $OpenBSD: resolver.c,v 1.46 2019/10/19 17:42:21 otto Exp $ */ +/* $OpenBSD: resolver.c,v 1.47 2019/10/31 12:51:43 florian Exp $ */ /* * Copyright (c) 2018 Florian Obser <florian@openbsd.org> @@ -29,6 +29,8 @@ #include <event.h> #include <imsg.h> #include <limits.h> +#include <netdb.h> +#include <asr.h> #include <pwd.h> #include <signal.h> #include <stdio.h> @@ -77,6 +79,7 @@ struct uw_resolver { struct event check_ev; struct event free_ev; struct ub_ctx *ctx; + void *asr_ctx; struct timeval check_tv; int ref_cnt; int stop; @@ -96,11 +99,16 @@ 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 resolve(struct uw_resolver *, const char*, int, int, + void*, int, int*); void resolve_done(void *, int, void *, int, int, char *, int); +void asr_resolve_done(struct asr_result *, void *); +void check_asr_resolver_done(struct asr_result *, void *); void parse_dhcp_forwarders(char *); void new_recursor(void); void new_forwarders(void); +void new_asr_forwarders(void); void new_static_forwarders(void); void new_static_dot_forwarders(void); struct uw_resolver *create_resolver(enum uw_resolver_type); @@ -359,14 +367,10 @@ resolver_dispatch_frontend(int fd, short event, void *bula) clock_gettime(CLOCK_MONOTONIC, &query_imsg->tp); - if ((err = ub_resolve_event(res->ctx, - query_imsg->qname, query_imsg->t, query_imsg->c, - query_imsg, resolve_done, - &query_imsg->async_id)) != 0) { - log_warn("%s: ub_resolve_async: err: %d, %s", - __func__, err, ub_strerror(err)); + if ((err = resolve(res, query_imsg->qname, + query_imsg->t, query_imsg->c, query_imsg, 0, + &query_imsg->async_id)) != 0) resolver_unref(res); - } break; case IMSG_FORWARDER: /* make sure this is a string */ @@ -398,6 +402,7 @@ resolver_dispatch_frontend(int fd, short event, void *bula) if (merge_tas(&new_trust_anchors, &trust_anchors)) { new_recursor(); new_forwarders(); + new_asr_forwarders(); new_static_forwarders(); new_static_dot_forwarders(); } @@ -636,6 +641,46 @@ resolver_dispatch_main(int fd, short event, void *bula) } } +int +resolve(struct uw_resolver *res, const char* name, int rrtype, int rrclass, + void *mydata, int check, int *async_id) +{ + struct asr_query *aq; + int err = 0; + + switch(res->type) { + case UW_RES_ASR: + if ((aq = res_query_async(name, rrclass, rrtype, res->asr_ctx)) + == NULL) { + log_warn("%s: res_query_async", __func__); + err =1; + } else { + if (event_asr_run(aq, check ? check_asr_resolver_done : + asr_resolve_done, mydata) == NULL) { + free(aq); + log_warn("%s: res_query_async", __func__); + err =1; + } + } + break; + case UW_RES_RECURSOR: + case UW_RES_DHCP: + case UW_RES_FORWARDER: + case UW_RES_DOT: + if ((err = ub_resolve_event(res->ctx, name, rrtype, rrclass, + mydata, check ? check_resolver_done : resolve_done, + async_id)) != 0) { + log_warn("%s: ub_resolve_event: err: %d, %s", __func__, + err, ub_strerror(err)); + } + break; + default: + fatalx("unknown resolver type %d", res->type); + break; + } + return (err); +} + void resolve_done(void *arg, int rcode, void *answer_packet, int answer_len, int sec, char *why_bogus, int was_ratelimited) @@ -742,6 +787,7 @@ parse_dhcp_forwarders(char *forwarders) &dhcp_forwarder_list)) { replace_forwarders(&new_forwarder_list, &dhcp_forwarder_list); new_forwarders(); + new_asr_forwarders(); if (resolver_conf->captive_portal_auto) check_captive_portal(1); } else { @@ -786,6 +832,21 @@ new_forwarders(void) } void +new_asr_forwarders(void) +{ + free_resolver(resolvers[UW_RES_ASR]); + resolvers[UW_RES_ASR] = NULL; + + if (SIMPLEQ_EMPTY(&dhcp_forwarder_list)) + return; + + log_debug("%s: create_resolver", __func__); + resolvers[UW_RES_ASR] = create_resolver(UW_RES_ASR); + + check_resolver(resolvers[UW_RES_ASR]); +} + +void new_static_forwarders(void) { free_resolver(resolvers[UW_RES_FORWARDER]); @@ -826,63 +887,104 @@ create_resolver(enum uw_resolver_type type) { struct uw_resolver *res; struct trust_anchor *ta; + struct uw_forwarder *uw_forwarder; int err; + char *resolv_conf = NULL, *tmp = NULL; if ((res = calloc(1, sizeof(*res))) == NULL) { log_warn("%s", __func__); return (NULL); } - res->type = type; - log_debug("%s: %p", __func__, res); - if ((res->ctx = ub_ctx_create_event(ev_base)) == NULL) { - free(res); - log_warnx("could not create unbound context"); - return (NULL); - } - + res->type = type; res->state = UNKNOWN; res->check_tv.tv_sec = RESOLVER_CHECK_SEC; res->check_tv.tv_usec = arc4random() % 1000000; /* modulo bias is ok */ - ub_ctx_debuglevel(res->ctx, log_getverbose() & OPT_VERBOSE2 ? - UB_LOG_VERBOSE : UB_LOG_BRIEF); - - TAILQ_FOREACH(ta, &trust_anchors, entry) { - if ((err = ub_ctx_add_ta(res->ctx, ta->ta)) != 0) { - ub_ctx_delete(res->ctx); + switch (type) { + case UW_RES_ASR: + if (SIMPLEQ_EMPTY(&dhcp_forwarder_list)) { free(res); - log_warnx("error adding trust anchor: %s", - ub_strerror(err)); return (NULL); } - } + SIMPLEQ_FOREACH(uw_forwarder, &dhcp_forwarder_list, entry) { + tmp = resolv_conf; + if (asprintf(&resolv_conf, "%snameserver %s\n", tmp == + NULL ? "" : tmp, uw_forwarder->name) == -1) { + free(tmp); + free(res); + log_warnx("could not create asr context"); + return (NULL); + } + free(tmp); + } + log_debug("%s: UW_RES_ASR resolv.conf: %s", __func__, + resolv_conf); + if ((res->asr_ctx = asr_resolver_from_string(resolv_conf)) == + NULL) { + free(res); + free(resolv_conf); + log_warnx("could not create asr context"); + return (NULL); + } + free(resolv_conf); + break; + case UW_RES_RECURSOR: + case UW_RES_DHCP: + case UW_RES_FORWARDER: + case UW_RES_DOT: + if ((res->ctx = ub_ctx_create_event(ev_base)) == NULL) { + free(res); + log_warnx("could not create unbound context"); + return (NULL); + } - if((err = ub_ctx_set_option(res->ctx, "aggressive-nsec:", "yes")) - != 0) { - ub_ctx_delete(res->ctx); - free(res); - log_warnx("error setting aggressive-nsec: yes: %s", - ub_strerror(err)); - return (NULL); - } + ub_ctx_debuglevel(res->ctx, log_getverbose() & OPT_VERBOSE2 ? + UB_LOG_VERBOSE : UB_LOG_BRIEF); - if (!log_getdebug()) { - if((err = ub_ctx_set_option(res->ctx, "use-syslog:", "yes")) - != 0) { + TAILQ_FOREACH(ta, &trust_anchors, entry) { + if ((err = ub_ctx_add_ta(res->ctx, ta->ta)) != 0) { + ub_ctx_delete(res->ctx); + free(res); + log_warnx("error adding trust anchor: %s", + ub_strerror(err)); + return (NULL); + } + } + + if((err = ub_ctx_set_option(res->ctx, "aggressive-nsec:", + "yes")) != 0) { ub_ctx_delete(res->ctx); free(res); - log_warnx("error setting use-syslog: yes: %s", + log_warnx("error setting aggressive-nsec: yes: %s", ub_strerror(err)); return (NULL); } + + if (!log_getdebug()) { + if((err = ub_ctx_set_option(res->ctx, "use-syslog:", + "yes")) != 0) { + ub_ctx_delete(res->ctx); + free(res); + log_warnx("error setting use-syslog: yes: %s", + ub_strerror(err)); + return (NULL); + } + } + + break; + default: + fatalx("unknown resolver type %d", type); + break; } evtimer_set(&res->check_ev, resolver_check_timo, res); switch(res->type) { + case UW_RES_ASR: + break; case UW_RES_RECURSOR: break; case UW_RES_DHCP: @@ -918,6 +1020,7 @@ free_resolver(struct uw_resolver *res) else { evtimer_del(&res->check_ev); ub_ctx_delete(res->ctx); + asr_resolver_free(res->asr_ctx); free(res->why_bogus); free(res); } @@ -963,11 +1066,8 @@ check_resolver(struct uw_resolver *res) data->check_res = check_res; data->res = res; - if ((err = ub_resolve_event(check_res->ctx, ".", LDNS_RR_TYPE_NS, - LDNS_RR_CLASS_IN, data, - check_resolver_done, NULL)) != 0) { - log_warn("%s: ub_resolve_event: err: %d, %s", __func__, err, - ub_strerror(err)); + if ((err = resolve(check_res, ".", LDNS_RR_TYPE_NS, LDNS_RR_CLASS_IN, + data, 1, NULL)) != 0) { res->state = UNKNOWN; resolver_unref(check_res); resolver_unref(res); @@ -1072,6 +1172,21 @@ out: } void +check_asr_resolver_done(struct asr_result *ar, void *arg) +{ + check_resolver_done(arg, ar->ar_rcode, ar->ar_data, ar->ar_datalen, 0, + "", 0); + free(ar->ar_data); +} + +void +asr_resolve_done(struct asr_result *ar, void *arg) +{ + resolve_done(arg, ar->ar_rcode, ar->ar_data, ar->ar_datalen, 0, "", 0); + free(ar->ar_data); +} + +void schedule_recheck_all_resolvers(void) { struct timeval tv; @@ -1164,7 +1279,8 @@ best_resolver(void) struct uw_resolver *res = NULL; int i; - log_debug("%s: %s: %s, %s: %s, %s: %s, %s: %s, captive_portal: %s", + log_debug("%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] @@ -1176,8 +1292,11 @@ best_resolver(void) uw_resolver_state_str[resolvers[UW_RES_FORWARDER]->state] : "NA", uw_resolver_type_str[UW_RES_DOT], resolvers[UW_RES_DOT] != NULL ? - uw_resolver_state_str[resolvers[UW_RES_DOT]->state] : - "NA", captive_portal_state_str[captive_portal_state]); + 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) { @@ -1227,6 +1346,7 @@ restart_resolvers(void) new_static_forwarders(); new_static_dot_forwarders(); new_forwarders(); + new_asr_forwarders(); } void @@ -1251,6 +1371,7 @@ show_status(enum uw_resolver_type type, pid_t pid) case UW_RES_DHCP: case UW_RES_FORWARDER: case UW_RES_DOT: + case UW_RES_ASR: send_resolver_info(resolvers[type], resolvers[type] == best, pid); send_detailed_resolver_info(resolvers[type], pid); @@ -1390,7 +1511,7 @@ trust_anchor_resolve(void) res = best_resolver(); - if (res == NULL || res->state < VALIDATING) { + if (res == NULL || res->state < VALIDATING || res->type == UW_RES_ASR) { evtimer_add(&trust_anchor_timer, &tv); return; } diff --git a/sbin/unwind/unwind.c b/sbin/unwind/unwind.c index e45b335e9d7..15515fcf81a 100644 --- a/sbin/unwind/unwind.c +++ b/sbin/unwind/unwind.c @@ -1,4 +1,4 @@ -/* $OpenBSD: unwind.c,v 1.31 2019/10/21 07:16:09 florian Exp $ */ +/* $OpenBSD: unwind.c,v 1.32 2019/10/31 12:51:43 florian Exp $ */ /* * Copyright (c) 2018 Florian Obser <florian@openbsd.org> @@ -842,7 +842,8 @@ config_new_empty(void) UW_RES_DOT, UW_RES_FORWARDER, UW_RES_RECURSOR, - UW_RES_DHCP}; + UW_RES_DHCP, + UW_RES_ASR}; struct uw_conf *xconf; xconf = calloc(1, sizeof(*xconf)); @@ -851,7 +852,7 @@ config_new_empty(void) memcpy(&xconf->res_pref, &default_res_pref, sizeof(default_res_pref)); - xconf->res_pref_len = 4; + xconf->res_pref_len = 5; SIMPLEQ_INIT(&xconf->uw_forwarder_list); SIMPLEQ_INIT(&xconf->uw_dot_forwarder_list); diff --git a/sbin/unwind/unwind.conf.5 b/sbin/unwind/unwind.conf.5 index f94bc80667c..f4d1d3352d8 100644 --- a/sbin/unwind/unwind.conf.5 +++ b/sbin/unwind/unwind.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: unwind.conf.5,v 1.15 2019/10/21 07:16:09 florian Exp $ +.\" $OpenBSD: unwind.conf.5,v 1.16 2019/10/31 12:51:43 florian Exp $ .\" .\" Copyright (c) 2018 Florian Obser <florian@openbsd.org> .\" Copyright (c) 2005 Esben Norby <norby@openbsd.org> @@ -18,7 +18,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: October 21 2019 $ +.Dd $Mdocdate: October 31 2019 $ .Dt UNWIND.CONF 5 .Os .Sh NAME @@ -131,6 +131,12 @@ Validating name servers are always picked over non-validating name servers. DNS name server types are: .Pp .Bl -tag -width "forwarder" -compact +.It Ic asr +Name servers learned via DHCP, queried using the asr functions. +See +.Xr asr_run 3 . +Will never validate. +Useful when running behind broken middle boxes that do not like edns0. .It Ic dhcp Name servers learned via DHCP. .It Ic DoT @@ -145,7 +151,7 @@ itself recursively resolves names. .El .Pp The default preference is -.Ic DoT forwarder recursor dhcp . +.Ic DoT forwarder recursor dhcp asr . .El .Sh FILES .Bl -tag -width "/etc/examples/unwind.conf" -compact diff --git a/sbin/unwind/unwind.h b/sbin/unwind/unwind.h index 41ec58f9025..b7d0cd0f8dc 100644 --- a/sbin/unwind/unwind.h +++ b/sbin/unwind/unwind.h @@ -1,4 +1,4 @@ -/* $OpenBSD: unwind.h,v 1.18 2019/10/21 07:16:09 florian Exp $ */ +/* $OpenBSD: unwind.h,v 1.19 2019/10/31 12:51:43 florian Exp $ */ /* * Copyright (c) 2018 Florian Obser <florian@openbsd.org> @@ -57,6 +57,7 @@ static const char * const log_procnames[] = { enum uw_resolver_type { UW_RES_RECURSOR, UW_RES_DHCP, + UW_RES_ASR, UW_RES_FORWARDER, UW_RES_DOT, UW_RES_NONE @@ -65,6 +66,7 @@ enum uw_resolver_type { static const char * const uw_resolver_type_str[] = { "recursor", "dhcp", + "asr", "forwarder", "DoT" }; |