From: Willem Toorop Date: Sun, 24 Mar 2019 09:43:57 +0000 (+0100) Subject: AXFR over TLS X-Git-Tag: release-1.9.2rc1~22^2~15 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=48ad6477eb2f476bc4e42a0f79358c1d994b0f3d;p=thirdparty%2Funbound.git AXFR over TLS Enable by specifying an auth name, like this: ``` auth-zone: name: nlnetlabs.nl master: 185.49.140.60#ns.nlnetlabs.nl ``` --- diff --git a/services/authzone.c b/services/authzone.c index a87c2274f..2649867ed 100644 --- a/services/authzone.c +++ b/services/authzone.c @@ -5034,6 +5034,7 @@ xfr_transfer_init_fetch(struct auth_xfer* xfr, struct module_env* env) struct sockaddr_storage addr; socklen_t addrlen = 0; struct auth_master* master = xfr->task_transfer->master; + char *auth_name = NULL; if(!master) return 0; if(master->allow_notify) return 0; /* only for notify */ @@ -5042,7 +5043,7 @@ xfr_transfer_init_fetch(struct auth_xfer* xfr, struct module_env* env) addrlen = xfr->task_transfer->scan_addr->addrlen; memmove(&addr, &xfr->task_transfer->scan_addr->addr, addrlen); } else { - if(!extstrtoaddr(master->host, &addr, &addrlen)) { + if(!authextstrtoaddr(master->host, &addr, &addrlen, &auth_name)) { /* the ones that are not in addr format are supposed * to be looked up. The lookup has failed however, * so skip them */ @@ -5091,7 +5092,8 @@ xfr_transfer_init_fetch(struct auth_xfer* xfr, struct module_env* env) /* connect on fd */ xfr->task_transfer->cp = outnet_comm_point_for_tcp(env->outnet, auth_xfer_transfer_tcp_callback, xfr, &addr, addrlen, - env->scratch_buffer, AUTH_TRANSFER_TIMEOUT); + env->scratch_buffer, AUTH_TRANSFER_TIMEOUT, + auth_name != NULL, auth_name); if(!xfr->task_transfer->cp) { char zname[255+1]; dname_str(xfr->name, zname); @@ -5809,6 +5811,7 @@ xfr_probe_send_probe(struct auth_xfer* xfr, struct module_env* env, struct timeval t; /* pick master */ struct auth_master* master = xfr_probe_current_master(xfr); + char *auth_name = NULL; if(!master) return 0; if(master->allow_notify) return 0; /* only for notify */ if(master->http) return 0; /* only masters get SOA UDP probe, @@ -5819,7 +5822,7 @@ xfr_probe_send_probe(struct auth_xfer* xfr, struct module_env* env, addrlen = xfr->task_probe->scan_addr->addrlen; memmove(&addr, &xfr->task_probe->scan_addr->addr, addrlen); } else { - if(!extstrtoaddr(master->host, &addr, &addrlen)) { + if(!authextstrtoaddr(master->host, &addr, &addrlen, &auth_name)) { /* the ones that are not in addr format are supposed * to be looked up. The lookup has failed however, * so skip them */ @@ -5829,6 +5832,18 @@ xfr_probe_send_probe(struct auth_xfer* xfr, struct module_env* env, zname, master->host); return 0; } + if (auth_name != NULL) { + if (addr.ss_family == AF_INET + && ntohs(((struct sockaddr_in *)&addr)->sin_port) + == 853) + ((struct sockaddr_in *)&addr)->sin_port + = htons(53); + else if (addr.ss_family == AF_INET6 + && ntohs(((struct sockaddr_in6 *)&addr)->sin6_port) + == 853) + ((struct sockaddr_in6 *)&addr)->sin6_port + = htons(853); + } } /* create packet */ diff --git a/services/outside_network.c b/services/outside_network.c index 3347c38e7..e687e405e 100644 --- a/services/outside_network.c +++ b/services/outside_network.c @@ -2285,7 +2285,7 @@ struct comm_point* outnet_comm_point_for_tcp(struct outside_network* outnet, comm_point_callback_type* cb, void* cb_arg, struct sockaddr_storage* to_addr, socklen_t to_addrlen, - sldns_buffer* query, int timeout) + sldns_buffer* query, int timeout, int ssl, char* host) { struct comm_point* cp; int fd = outnet_get_tcp_fd(to_addr, to_addrlen, outnet->tcp_mss); @@ -2305,6 +2305,53 @@ outnet_comm_point_for_tcp(struct outside_network* outnet, } cp->repinfo.addrlen = to_addrlen; memcpy(&cp->repinfo.addr, to_addr, to_addrlen); + + /* setup for SSL (if needed) */ + if(ssl) { + cp->ssl = outgoing_ssl_fd(outnet->sslctx, fd); + if(!cp->ssl) { + log_err("cannot setup https"); + comm_point_delete(cp); + return NULL; + } +#ifdef USE_WINSOCK + comm_point_tcp_win_bio_cb(cp, cp->ssl); +#endif + cp->ssl_shake_state = comm_ssl_shake_write; + /* https verification */ +#ifdef HAVE_SSL_SET1_HOST + if((SSL_CTX_get_verify_mode(outnet->sslctx)&SSL_VERIFY_PEER)) { + /* because we set SSL_VERIFY_PEER, in netevent in + * ssl_handshake, it'll check if the certificate + * verification has succeeded */ + /* SSL_VERIFY_PEER is set on the sslctx */ + /* and the certificates to verify with are loaded into + * it with SSL_load_verify_locations or + * SSL_CTX_set_default_verify_paths */ + /* setting the hostname makes openssl verify the + * host name in the x509 certificate in the + * SSL connection*/ + if(!SSL_set1_host(cp->ssl, host)) { + log_err("SSL_set1_host failed"); + comm_point_delete(cp); + return NULL; + } + } +#elif defined(HAVE_X509_VERIFY_PARAM_SET1_HOST) + /* openssl 1.0.2 has this function that can be used for + * set1_host like verification */ + if((SSL_CTX_get_verify_mode(outnet->sslctx)&SSL_VERIFY_PEER)) { + X509_VERIFY_PARAM* param = SSL_get0_param(cp->ssl); + X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); + if(!X509_VERIFY_PARAM_set1_host(param, host, strlen(host))) { + log_err("X509_VERIFY_PARAM_set1_host failed"); + comm_point_delete(cp); + return NULL; + } + } +#endif /* HAVE_SSL_SET1_HOST */ + } + /* set timeout on TCP connection */ comm_point_start_listening(cp, fd, timeout); /* copy scratch buffer to cp->buffer */ diff --git a/services/outside_network.h b/services/outside_network.h index 48ef03edb..79e32bcbf 100644 --- a/services/outside_network.h +++ b/services/outside_network.h @@ -575,7 +575,7 @@ struct comm_point* outnet_comm_point_for_udp(struct outside_network* outnet, struct comm_point* outnet_comm_point_for_tcp(struct outside_network* outnet, comm_point_callback_type* cb, void* cb_arg, struct sockaddr_storage* to_addr, socklen_t to_addrlen, - struct sldns_buffer* query, int timeout); + struct sldns_buffer* query, int timeout, int ssl, char* host); /** * Create http commpoint suitable for communication to the destination.