2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-30 14:07:59 +00:00

Merge branch '1641-doh-dig' into 'main'

Resolve "RFC8484, DoH support in DIG (and any other relevant utilities)"

Closes #2464 and #1641

See merge request isc-projects/bind9!4672
This commit is contained in:
Artem Boldariev 2021-03-05 16:46:02 +00:00
commit d6f33fcd6c
43 changed files with 2672 additions and 2074 deletions

View File

@ -1,3 +1,7 @@
5596. [func] Client-side support for DNS-over-HTTPS (DoH) has
been added to dig. "dig +https" can now query
a server via HTTP/2. [GL #1641]
5595. [cleanup] Public header files for BIND 9 libraries no longer
directly include third-party library headers. This
prevents the need to include paths to third-party header

View File

@ -228,6 +228,10 @@ help(void) {
"SERVFAIL)\n"
" +[no]header-only (Send query without a "
"question section)\n"
" +[no]https[=###] (DNS over HTTPS mode) "
"[/]\n"
" +[no]https-get (Use GET instead of "
"default POST method\n"
" +[no]identify (ID responders in short "
"answers)\n"
#ifdef HAVE_LIBIDN2
@ -348,12 +352,18 @@ received(unsigned int bytes, isc_sockaddr_t *from, dig_query_t *query) {
}
if (query->lookup->tls_mode) {
proto = "TLS";
} else if (query->lookup->https_mode) {
if (query->lookup->http_plain) {
proto = "HTTP";
} else {
proto = "HTTPS";
}
} else if (query->lookup->tcp_mode) {
proto = "TCP";
} else {
proto = "UDP";
}
printf(";; SERVER: %s(%s) (%s)\n", fromtext, query->servname,
printf(";; SERVER: %s(%s) (%s)\n", fromtext, query->userarg,
proto);
time(&tnow);
(void)localtime_r(&tnow, &tmnow);
@ -1066,6 +1076,17 @@ plus_option(char *option, bool is_batchfile, bool *need_clone,
(_l >= sizeof(B) || strncasecmp(cmd, B, _l) != 0)) \
goto invalid_option; \
} while (0)
#define FULLCHECK6(A, B, C, D, E, F) \
do { \
size_t _l = strlen(cmd); \
if ((_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) && \
(_l >= sizeof(B) || strncasecmp(cmd, B, _l) != 0) && \
(_l >= sizeof(C) || strncasecmp(cmd, C, _l) != 0) && \
(_l >= sizeof(D) || strncasecmp(cmd, D, _l) != 0) && \
(_l >= sizeof(E) || strncasecmp(cmd, E, _l) != 0) && \
(_l >= sizeof(F) || strncasecmp(cmd, F, _l) != 0)) \
goto invalid_option; \
} while (0)
switch (cmd[0]) {
case 'a':
@ -1412,9 +1433,79 @@ plus_option(char *option, bool is_batchfile, bool *need_clone,
lookup->servfail_stops = state;
break;
case 'h':
switch (cmd[1]) {
case 'e': /* header-only */
FULLCHECK("header-only");
lookup->header_only = state;
break;
case 't':
FULLCHECK6("https", "https-get", "https-post",
"http-plain", "http-plain-get",
"http-plain-post");
if (lookup->https_path != NULL) {
isc_mem_free(mctx, lookup->https_path);
lookup->https_path = NULL;
}
if (!state) {
lookup->https_mode = false;
break;
}
lookup->https_mode = true;
if (cmd[4] == '-') {
lookup->http_plain = true;
switch (cmd[10]) {
case '\0':
FULLCHECK("http-plain");
break;
case '-':
switch (cmd[6]) {
case 'p':
FULLCHECK("https-plain-post");
break;
case 'g':
FULLCHECK("https-plain-get");
lookup->https_get = true;
break;
}
break;
default:
goto invalid_option;
}
} else {
switch (cmd[5]) {
case '\0':
FULLCHECK("https");
break;
case '-':
switch (cmd[6]) {
case 'p':
FULLCHECK("https-post");
break;
case 'g':
FULLCHECK("https-get");
lookup->https_get = true;
break;
}
break;
default:
goto invalid_option;
}
}
if (!lookup->tcp_mode_set) {
lookup->tcp_mode = state;
}
if (value == NULL) {
lookup->https_path = isc_mem_strdup(
mctx, DEFAULT_HTTPS_PATH);
} else {
lookup->https_path = isc_mem_strdup(mctx,
value);
}
break;
default:
goto invalid_option;
}
break;
case 'i':
switch (cmd[1]) {
case 'd': /* identify */

View File

@ -349,11 +349,38 @@ abbreviation is unambiguous; for example, ``+cd`` is equivalent to
default is to add a question section. The query type and query name
are ignored when this is set.
``+[no]https[=value]``
This option indicates whether to use DNS-over-HTTPS (DoH) when querying
name servers. When this option is in use, the port number defaults to 443.
The HTTP POST request mode is used when sending the query.
If ``value`` is specified, it will be used as the HTTP endpoint in the
query URI; the default is ``/dns-query``. So, for example, ``dig
@example.com +https`` will use the URI ``https://example.com/dns-query``.
``+[no]https-get[=value]``
Similar to ``+https``, except that the HTTP GET request mode is used
when sending the query.
``+[no]https-post[=value]``
Same as ``+https``.
``+[no]http-plain[=value]``
Similar to ``+https``, except that HTTP queries will be sent over a
non-encrypted channel. When this option is in use, the port number
defaults to 80 and the HTTP request mode is POST.
``+[no]http-plain-get[=value]``
Similar to ``+http-plain``, except that the HTTP request mode is GET.
``+[no]http-plain-post[=value]``
Same as ``+http-plain``.
``+[no]identify``
This option shows [or does not show] the IP address and port number that supplied
the answer, when the ``+short`` option is enabled. If short form
answers are requested, the default is not to show the source address
and port number of the server that provided the answer.
This option shows [or does not show] the IP address and port number that
supplied the answer, when the ``+short`` option is enabled. If short
form answers are requested, the default is not to show the source
address and port number of the server that provided the answer.
``+[no]idnin``
This option processes [or does not process] IDN domain names on input. This requires
@ -519,8 +546,9 @@ abbreviation is unambiguous; for example, ``+cd`` is equivalent to
5 seconds. An attempt to set ``T`` to less than 1 is silently set to 1.
``+[no]tls``
This option indicates whether to use DNS over TLS (DoT) when querying
name servers.
This option indicates whether to use DNS-over-TLS (DoT) when querying
name servers. When this option is in use, the port number defaults
to 853.
``+[no]topdown``
This feature is related to ``dig +sigchase``, which is obsolete and

View File

@ -603,102 +603,43 @@ clone_server_list(dig_serverlist_t src, dig_serverlist_t *dest) {
dig_lookup_t *
make_empty_lookup(void) {
dig_lookup_t *looknew;
#ifdef HAVE_LIBIDN2
bool idn_allowed = isatty(1) ? (getenv("IDN_DISABLE") == NULL) : false;
#endif /* HAVE_LIBIDN2 */
debug("make_empty_lookup()");
INSIST(!free_now);
looknew = isc_mem_allocate(mctx, sizeof(struct dig_lookup));
looknew->pending = true;
looknew->textname[0] = 0;
looknew->cmdline[0] = 0;
looknew->rdtype = dns_rdatatype_a;
looknew->qrdtype = dns_rdatatype_a;
looknew->rdclass = dns_rdataclass_in;
looknew->rdtypeset = false;
looknew->rdclassset = false;
looknew->sendspace = NULL;
looknew->sendmsg = NULL;
looknew->name = NULL;
looknew->oname = NULL;
looknew->xfr_q = NULL;
looknew->current_query = NULL;
looknew->doing_xfr = false;
looknew->ixfr_serial = 0;
looknew->trace = false;
looknew->trace_root = false;
looknew->identify = false;
looknew->identify_previous_line = false;
looknew->ignore = false;
looknew->servfail_stops = true;
looknew->besteffort = true;
looknew->dns64prefix = false;
looknew->dnssec = false;
looknew->ednsflags = 0;
looknew->opcode = dns_opcode_query;
looknew->expire = false;
looknew->nsid = false;
looknew->tcp_keepalive = false;
looknew->padding = 0;
looknew->header_only = false;
looknew->sendcookie = false;
looknew->seenbadcookie = false;
looknew->badcookie = true;
looknew->multiline = false;
looknew->nottl = false;
looknew->noclass = false;
looknew->onesoa = false;
looknew->use_usec = false;
looknew->nocrypto = false;
looknew->ttlunits = false;
looknew->expandaaaa = false;
looknew->qr = false;
looknew = isc_mem_allocate(mctx, sizeof(*looknew));
*looknew = (dig_lookup_t){
.pending = true,
.rdtype = dns_rdatatype_a,
.qrdtype = dns_rdatatype_a,
.rdclass = dns_rdataclass_in,
.servfail_stops = true,
.besteffort = true,
.opcode = dns_opcode_query,
.badcookie = true,
#ifdef HAVE_LIBIDN2
looknew->idnin = isatty(1) ? (getenv("IDN_DISABLE") == NULL) : false;
looknew->idnout = looknew->idnin;
#else /* ifdef HAVE_LIBIDN2 */
looknew->idnin = false;
looknew->idnout = false;
.idnin = idn_allowed,
.idnout = idn_allowed,
#endif /* HAVE_LIBIDN2 */
looknew->udpsize = -1;
looknew->edns = -1;
looknew->recurse = true;
looknew->aaonly = false;
looknew->adflag = false;
looknew->cdflag = false;
looknew->raflag = false;
looknew->tcflag = false;
looknew->print_unknown_format = false;
looknew->zflag = false;
looknew->setqid = false;
looknew->qid = 0;
looknew->ns_search_only = false;
looknew->origin = NULL;
looknew->tsigctx = NULL;
looknew->querysig = NULL;
looknew->retries = tries;
looknew->nsfound = 0;
looknew->tcp_mode = false;
looknew->tcp_mode_set = false;
looknew->tls_mode = false;
looknew->comments = true;
looknew->stats = true;
looknew->section_question = true;
looknew->section_answer = true;
looknew->section_authority = true;
looknew->section_additional = true;
looknew->new_search = false;
looknew->done_as_is = false;
looknew->need_search = false;
looknew->ecs_addr = NULL;
looknew->cookie = NULL;
looknew->ednsopts = NULL;
looknew->ednsoptscnt = 0;
looknew->ednsneg = true;
looknew->mapped = true;
looknew->dscp = -1;
looknew->rrcomments = 0;
looknew->eoferr = 0;
.udpsize = -1,
.edns = -1,
.recurse = true,
.retries = tries,
.comments = true,
.stats = true,
.section_question = true,
.section_answer = true,
.section_authority = true,
.section_additional = true,
.ednsneg = true,
.mapped = true,
.dscp = -1,
};
dns_fixedname_init(&looknew->fdomain);
ISC_LINK_INIT(looknew, link);
ISC_LIST_INIT(looknew->q);
@ -787,6 +728,12 @@ clone_lookup(dig_lookup_t *lookold, bool servers) {
looknew->nsid = lookold->nsid;
looknew->tcp_keepalive = lookold->tcp_keepalive;
looknew->header_only = lookold->header_only;
looknew->https_mode = lookold->https_mode;
if (lookold->https_path != NULL) {
looknew->https_path = isc_mem_strdup(mctx, lookold->https_path);
}
looknew->https_get = lookold->https_get;
looknew->http_plain = lookold->http_plain;
looknew->sendcookie = lookold->sendcookie;
looknew->seenbadcookie = lookold->seenbadcookie;
looknew->badcookie = lookold->badcookie;
@ -1638,6 +1585,10 @@ _destroy_lookup(dig_lookup_t *lookup) {
isc_mem_free(mctx, lookup->ednsopts);
}
if (lookup->https_path) {
isc_mem_free(mctx, lookup->https_path);
}
isc_mem_free(mctx, lookup);
}
@ -2760,7 +2711,20 @@ start_tcp(dig_query_t *query) {
* For TLS connections, we want to override the default
* port number.
*/
port = port_set ? port : (query->lookup->tls_mode ? 853 : 53);
if (!port_set) {
if (query->lookup->tls_mode) {
port = 853;
} else if (query->lookup->https_mode &&
!query->lookup->http_plain) {
port = 443;
} else if (query->lookup->https_mode) {
port = 80;
} else {
port = 53;
}
}
debug("query->servname = %s\n", query->servname);
result = get_address(query->servname, port, &query->sockaddr);
if (result != ISC_R_SUCCESS) {
@ -2835,7 +2799,27 @@ start_tcp(dig_query_t *query) {
(isc_nmiface_t *)&query->sockaddr,
tcp_connected, query, local_timeout, 0,
query->tlsctx);
check_result(result, "isc_nm_tcpdnsconnect");
check_result(result, "isc_nm_tlsdnsconnect");
} else if (query->lookup->https_mode) {
char uri[4096] = { 0 };
snprintf(uri, sizeof(uri), "https://%s:%u%s",
query->userarg, (uint16_t)port,
query->lookup->https_path);
if (!query->lookup->http_plain) {
result =
isc_tlsctx_createclient(&query->tlsctx);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
isc_tlsctx_enable_http2client_alpn(
query->tlsctx);
}
result = isc_nm_httpconnect(
netmgr, (isc_nmiface_t *)&localaddr,
(isc_nmiface_t *)&query->sockaddr, uri,
!query->lookup->https_get, tcp_connected, query,
query->tlsctx, local_timeout, 0);
check_result(result, "isc_nm_httpconnect");
} else {
result = isc_nm_tcpdnsconnect(
netmgr, (isc_nmiface_t *)&localaddr,
@ -3211,6 +3195,7 @@ launch_next_query(dig_query_t *query) {
}
}
}
lookup_detach(&l);
return;
}
@ -3582,8 +3567,7 @@ recv_done(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
isc_sockaddr_t peer;
REQUIRE(DIG_VALID_QUERY(query));
INSIST(query->readhandle != NULL);
INSIST(handle == query->readhandle);
REQUIRE(query->readhandle != NULL);
INSIST(!free_now);
debug("recv_done(%p, %s, %p, %p)", handle, isc_result_totext(eresult),

View File

@ -76,6 +76,9 @@
#define DEFAULT_EDNS_VERSION 0
#define DEFAULT_EDNS_BUFSIZE 1232
#define DEFAULT_HTTPS_PATH "/dns-query"
#define DEFAULT_HTTPS_QUERY "?dns="
/*%
* Lookup_limit is just a limiter, keeping too many lookups from being
* created. It's job is mainly to prevent the program from running away
@ -168,6 +171,12 @@ struct dig_lookup {
int rrcomments;
unsigned int eoferr;
uint16_t qid;
struct {
bool http_plain;
bool https_mode;
bool https_get;
char *https_path;
};
};
/*% The dig_query structure */

View File

@ -64,7 +64,7 @@ add_doh_transports(const cfg_obj_t *transportlist, dns_transport_list_t *list) {
create_name(dohid, &dohname);
transport = dns_transport_new(&dohname, DNS_TRANSPORT_DOH,
transport = dns_transport_new(&dohname, DNS_TRANSPORT_HTTP,
list);
parse_transport_option(doh, transport, "key-file",

View File

@ -95,6 +95,7 @@ TESTS += \
dlz \
dlzexternal \
dns64 \
doth \
dscp \
dsdigest \
dyndb \
@ -153,7 +154,6 @@ TESTS += \
views \
wildcard \
xferquota \
xot \
zonechecks
# The "stress" test is not run by default since it creates enough
@ -176,7 +176,6 @@ TESTS += \
nsupdate \
resolver \
statistics \
dot \
upforwd \
zero

View File

@ -668,7 +668,7 @@ copy_setports() {
atsign="@"
sed -e "s/${atsign}PORT${atsign}/${PORT}/g" \
-e "s/${atsign}TLSPORT${atsign}/${TLSPORT}/g" \
-e "s/${atsign}HTTPPORT${atsign}/${HTTPSPORT}/g" \
-e "s/${atsign}HTTPPORT${atsign}/${HTTPPORT}/g" \
-e "s/${atsign}HTTPSPORT${atsign}/${HTTPSPORT}/g" \
-e "s/${atsign}EXTRAPORT1${atsign}/${EXTRAPORT1}/g" \
-e "s/${atsign}EXTRAPORT2${atsign}/${EXTRAPORT2}/g" \

View File

@ -1,19 +0,0 @@
#!/bin/sh
#
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, you can obtain one at https://mozilla.org/MPL/2.0/.
#
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
rm -f */named.memstats
rm -f */named.run
rm -f */named.conf
rm -f */named.stats*
rm -f dig.out*
rm -f rndc.out*
rm -f ns*/named.lock
rm -f ns*/managed-keys.bind*

View File

@ -1,28 +0,0 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
options {
port @PORT@;
tls-port @TLSPORT@;
pid-file "named.pid";
listen-on { 10.53.0.1; };
listen-on-v6 { none; };
listen-on tls ephemeral { 10.53.0.1; };
recursion no;
notify no;
statistics-file "named.stats";
};
zone "." {
type primary;
file "root.db";
allow-transfer { any; };
};

View File

@ -1,16 +0,0 @@
#!/bin/sh
#
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, you can obtain one at https://mozilla.org/MPL/2.0/.
#
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
. ../conf.sh
$SHELL clean.sh
copy_setports ns1/named.conf.in ns1/named.conf

View File

@ -1,41 +0,0 @@
#!/bin/sh
#
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, you can obtain one at https://mozilla.org/MPL/2.0/.
#
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
set -e
# shellcheck source=../conf.sh
. ../conf.sh
dig_dot_with_opts() {
"${DIG}" -p "${TLSPORT}" +tls "$@"
}
status=0
n=0
n=$((n + 1))
echo_i "checking DoT query response ($n)"
ret=0
dig_dot_with_opts @10.53.0.1 . SOA > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
n=$((n + 1))
echo_i "checking DoT XFR ($n)"
ret=0
dig_dot_with_opts +comment @10.53.0.1 . AXFR > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
echo_i "exit status: $status"
[ $status -eq 0 ] || exit 1

View File

@ -18,4 +18,4 @@ rm -f ./*/named.memstats
rm -f ./*/named.run
rm -f ./*/named.run.prev
rm -f ./dig.out.*
rm -f ./*/*.db
rm -f ./*/example.db

View File

@ -15,13 +15,21 @@ controls {
inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
http local {
endpoints { "/dns-query"; "/alter"; };
};
options {
port @PORT@;
tls-port @TLSPORT@;
https-port @HTTPSPORT@;
http-port @HTTPPORT@;
pid-file "named.pid";
listen-on { 10.53.0.1; };
listen-on tls ephemeral { 10.53.0.1; }; // DoT
listen-on tls ephemeral http local { 10.53.0.1; }; // DoH
listen-on tls none http local { 10.53.0.1; }; // unencrypted DoH
listen-on-v6 { none; };
listen-on tls ephemeral { 10.53.0.1; };
recursion no;
notify explicit;
also-notify { 10.53.0.2 port @PORT@; };
@ -30,8 +38,9 @@ options {
};
zone "." {
type hint;
file "../../common/root.hint";
type primary;
file "root.db";
allow-transfer { any; };
};
zone "example" {

View File

@ -0,0 +1,14 @@
-----BEGIN CERTIFICATE-----
MIICHTCCAcOgAwIBAgIUATq1E48Hj7vAQBwn8H/1oQvqvJ0wCgYIKoZIzj0EAwIw
YzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRUwEwYDVQQHDAxSZWR3b29kIENp
dHkxDDAKBgNVBAoMA0lTQzEOMAwGA1UECwwFQklORDkxEjAQBgNVBAMMCWxvY2Fs
aG9zdDAgFw0yMTAyMTIwMzIxMzFaGA8yMTIxMDExOTAzMjEzMVowYzELMAkGA1UE
BhMCVVMxCzAJBgNVBAgMAkNBMRUwEwYDVQQHDAxSZWR3b29kIENpdHkxDDAKBgNV
BAoMA0lTQzEOMAwGA1UECwwFQklORDkxEjAQBgNVBAMMCWxvY2FsaG9zdDBZMBMG
ByqGSM49AgEGCCqGSM49AwEHA0IABC1uCviud7QFTJ8DfdrLwjkBolYHJJR9c9HP
bshvKDXahhRU9+HCbWBNLlqFR6aMs8wyE32cXHLZ70XaILkH88SjUzBRMB0GA1Ud
DgQWBBRPpE9aC2MO0TAlCp18vR9vqe4R2TAfBgNVHSMEGDAWgBRPpE9aC2MO0TAl
Cp18vR9vqe4R2TAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0gAMEUCIE3L
zx4iRVqjnOACc+/G0Shru+AIk/MEglfrvP5wxZaVAiEArcmut+hYb+cG0UW5ct/U
Q183Kk25XYJkTj39GSBiiiA=
-----END CERTIFICATE-----

View File

@ -0,0 +1,8 @@
-----BEGIN EC PARAMETERS-----
BggqhkjOPQMBBw==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIFBLYPWvhrGBMyfi04oC53LOl00LZRZbVOVnC0K30XOCoAoGCCqGSM49
AwEHoUQDQgAELW4K+K53tAVMnwN92svCOQGiVgcklH1z0c9uyG8oNdqGFFT34cJt
YE0uWoVHpoyzzDITfZxcctnvRdoguQfzxA==
-----END EC PRIVATE KEY-----

View File

@ -15,17 +15,29 @@ controls {
inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
tls local {
key-file "key.pem";
cert-file "cert.pem";
};
http local {
endpoints { "/dns-query"; };
};
options {
query-source address 10.53.0.2;
notify-source 10.53.0.2;
transfer-source 10.53.0.2;
port @PORT@;
tls-port @TLSPORT@;
https-port @HTTPSPORT@;
http-port @HTTPPORT@;
pid-file "named.pid";
listen-on { 10.53.0.2; };
listen-on tls ephemeral { 10.53.0.2; };
listen-on tls local { 10.53.0.2; }; // DoT
listen-on tls local http local { 10.53.0.2; }; // DoH
listen-on tls none http local { 10.53.0.2; }; // unencrypted DoH
listen-on-v6 { none; };
listen-on tls ephemeral { 10.53.0.2; };
recursion no;
notify no;
ixfr-from-differences yes;

View File

@ -0,0 +1,186 @@
#!/bin/sh
#
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, you can obtain one at https://mozilla.org/MPL/2.0/.
#
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
. ../conf.sh
dig_with_tls_opts() {
"$DIG" +tls +noadd +nosea +nostat +noquest +nocmd -p "${TLSPORT}" "$@"
}
dig_with_https_opts() {
"$DIG" +https +noadd +nosea +nostat +noquest +nocmd -p "${HTTPSPORT}" "$@"
}
dig_with_http_opts() {
"$DIG" +http-plain +noadd +nosea +nostat +noquest +nocmd -p "${HTTPPORT}" "$@"
}
wait_for_tls_xfer() (
dig_with_tls_opts -b 10.53.0.3 @10.53.0.2 example. AXFR > "dig.out.ns2.test$n" || return 1
grep "^;" "dig.out.ns2.test$n" > /dev/null && return 1
return 0
)
status=0
n=0
n=$((n+1))
echo_i "testing XoT server functionality (using dig) ($n)"
ret=0
dig_with_tls_opts example. -b 10.53.0.3 @10.53.0.1 axfr > dig.out.ns1.test$n || ret=1
grep "^;" dig.out.ns1.test$n | cat_i
digcomp dig1.good dig.out.ns1.test$n || ret=1
if test $ret != 0 ; then echo_i "failed"; fi
status=$((status+ret))
n=$((n+1))
echo_i "testing incoming XoT functionality (from secondary) ($n)"
ret=0
if retry_quiet 10 wait_for_tls_xfer; then
grep "^;" "dig.out.ns2.test$n" | cat_i
digcomp dig1.good "dig.out.ns2.test$n" || ret=1
else
echo_i "timed out waiting for zone transfer"
ret=1
fi
if test $ret != 0 ; then echo_i "failed"; fi
status=$((status+ret))
n=$((n + 1))
echo_i "checking DoT query (ephemeral key) ($n)"
ret=0
dig_with_tls_opts @10.53.0.1 . SOA > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
n=$((n + 1))
echo_i "checking DoT query (static key) ($n)"
ret=0
dig_with_tls_opts @10.53.0.2 example SOA > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
n=$((n + 1))
echo_i "checking DoT XFR ($n)"
ret=0
dig_with_tls_opts +comm @10.53.0.1 . AXFR > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
n=$((n + 1))
echo_i "checking DoH query (POST) ($n)"
ret=0
dig_with_https_opts @10.53.0.1 . SOA > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
n=$((n + 1))
echo_i "checking DoH query (POST, static key) ($n)"
ret=0
dig_with_https_opts @10.53.0.2 example SOA > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
n=$((n + 1))
echo_i "checking DoH query (POST, nonstandard endpoint) ($n)"
ret=0
dig_with_https_opts +https=/alter @10.53.0.1 . SOA > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
n=$((n + 1))
echo_i "checking DoH query (POST, undefined endpoint, failure expected) ($n)"
ret=0
dig_with_https_opts +tries=1 +time=1 +https=/fake @10.53.0.1 . SOA > dig.out.test$n
grep "communications error" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
n=$((n + 1))
echo_i "checking DoH XFR (POST) (failure expected) ($n)"
ret=0
dig_with_https_opts +comm @10.53.0.1 . AXFR > dig.out.test$n
grep "status: FORMERR" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
n=$((n + 1))
echo_i "checking DoH query (GET) ($n)"
ret=0
dig_with_https_opts +https-get @10.53.0.1 . SOA > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
n=$((n + 1))
echo_i "checking DoH query (GET, static key) ($n)"
ret=0
dig_with_https_opts +https-get @10.53.0.2 example SOA > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
n=$((n + 1))
echo_i "checking DoH query (GET, nonstandard endpoint) ($n)"
ret=0
dig_with_https_opts +https-get=/alter @10.53.0.1 . SOA > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
n=$((n + 1))
echo_i "checking DoH query (GET, undefined endpoint, failure expected) ($n)"
ret=0
dig_with_https_opts +tries=1 +time=1 +https-get=/fake @10.53.0.1 . SOA > dig.out.test$n
grep "communications error" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
n=$((n + 1))
echo_i "checking DoH XFR (GET) (failure expected) ($n)"
ret=0
dig_with_https_opts +https-get +comm @10.53.0.1 . AXFR > dig.out.test$n
grep "status: FORMERR" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
n=$((n + 1))
echo_i "checking unencrypted DoH query (POST) ($n)"
ret=0
dig_with_http_opts @10.53.0.1 . SOA > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
n=$((n + 1))
echo_i "checking unencrypted DoH query (GET) ($n)"
ret=0
dig_with_http_opts +http-plain-get @10.53.0.1 . SOA > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
n=$((n + 1))
echo_i "checking unencrypted DoH XFR (failure expected) ($n)"
ret=0
dig_with_http_opts +comm @10.53.0.1 . AXFR > dig.out.test$n
grep "status: FORMERR" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
echo_i "exit status: $status"
[ $status -eq 0 ] || exit 1

View File

@ -1,50 +0,0 @@
#!/bin/sh
#
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, you can obtain one at https://mozilla.org/MPL/2.0/.
#
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
. ../conf.sh
dig_with_opts() {
"$DIG" +tls +noadd +nosea +nostat +noquest +nocomm +nocmd -p "${TLSPORT}" "$@"
}
wait_for_xfer() (
dig_with_opts -b 10.53.0.3 @10.53.0.2 example. AXFR > "dig.out.ns2.test$n" || return 1
grep "^;" "dig.out.ns2.test$n" > /dev/null && return 1
return 0
)
status=0
n=0
n=$((n+1))
echo_i "testing XoT server functionality (using dig) ($n)"
ret=0
dig_with_opts example. -b 10.53.0.3 @10.53.0.1 axfr > dig.out.ns1.test$n || ret=1
grep "^;" dig.out.ns1.test$n | cat_i
digcomp dig1.good dig.out.ns1.test$n || ret=1
if test $ret != 0 ; then echo_i "failed"; fi
status=$((status+ret))
n=$((n+1))
echo_i "testing basic incoming XoT functionality (from secondary) ($n)"
ret=0
if retry_quiet 10 wait_for_xfer; then
grep "^;" "dig.out.ns2.test$n" | cat_i
digcomp dig1.good "dig.out.ns2.test$n" || ret=1
else
echo_i "timed out waiting for zone transfer"
ret=1
fi
if test $ret != 0 ; then echo_i "failed"; fi
status=$((status+ret))
echo_i "exit status: $status"
[ $status -eq 0 ] || exit 1

View File

@ -27,13 +27,27 @@
#include <isc/netaddr.h>
#include <isc/netmgr.h>
#include <isc/os.h>
#include <isc/print.h>
#include <isc/sockaddr.h>
#include <isc/string.h>
#include <isc/util.h>
typedef enum { UDP, TCP, DOT, DOH } protocol_t;
#define DEFAULT_DOH_PATH "/dns-query"
static const char *protocols[] = { "udp", "tcp", "dot", "doh" };
typedef enum {
UDP,
TCP,
DOT,
HTTPS_POST,
HTTPS_GET,
HTTP_POST,
HTTP_GET
} protocol_t;
static const char *protocols[] = { "udp", "tcp",
"dot", "https-post",
"https-get", "http-plain-post",
"http-plain-get" };
static isc_mem_t *mctx = NULL;
static isc_nm_t *netmgr = NULL;
@ -50,6 +64,8 @@ static uint8_t messagebuf[2 * 65536];
static isc_region_t message = { .length = 0, .base = messagebuf };
static int out = -1;
static isc_tlsctx_t *tls_ctx = NULL;
static isc_result_t
parse_port(const char *input) {
char *endptr = NULL;
@ -304,6 +320,9 @@ teardown(void) {
isc_nm_destroy(&netmgr);
isc_mem_destroy(&mctx);
if (tls_ctx) {
isc_tlsctx_free(&tls_ctx);
}
}
static void
@ -374,6 +393,33 @@ connect_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) {
isc_nm_send(handle, &message, send_cb, NULL);
}
static void
sockaddr_to_url(isc_sockaddr_t *sa, const bool https, char *outbuf,
size_t outbuf_len, const char *append) {
uint16_t sa_port;
char saddr[INET6_ADDRSTRLEN] = { 0 };
int sa_family;
if (sa == NULL || outbuf == NULL || outbuf_len == 0) {
return;
}
sa_family = ((struct sockaddr *)&sa->type.sa)->sa_family;
sa_port = ntohs(sa_family == AF_INET ? sa->type.sin.sin_port
: sa->type.sin6.sin6_port);
inet_ntop(sa_family,
sa_family == AF_INET
? (struct sockaddr *)&sa->type.sin.sin_addr
: (struct sockaddr *)&sa->type.sin6.sin6_addr,
saddr, sizeof(saddr));
snprintf(outbuf, outbuf_len, "%s://%s%s%s:%u%s",
https ? "https" : "http", sa_family == AF_INET ? "" : "[",
saddr, sa_family == AF_INET ? "" : "]", sa_port,
append ? append : "");
}
static void
run(void) {
isc_result_t result;
@ -392,19 +438,33 @@ run(void) {
connect_cb, NULL, timeout, 0);
break;
case DOT: {
isc_tlsctx_t *tlsdns_ctx = NULL;
isc_tlsctx_createclient(&tlsdns_ctx);
isc_tlsctx_createclient(&tls_ctx);
result = isc_nm_tlsdnsconnect(
netmgr, (isc_nmiface_t *)&sockaddr_local,
(isc_nmiface_t *)&sockaddr_remote, connect_cb, NULL,
timeout, 0, tlsdns_ctx);
timeout, 0, tls_ctx);
break;
}
case DOH:
INSIST(0);
ISC_UNREACHABLE();
break;
case HTTP_GET:
case HTTPS_GET:
case HTTPS_POST:
case HTTP_POST: {
bool is_https = (protocol == HTTPS_POST ||
protocol == HTTPS_GET);
bool is_post = (protocol == HTTPS_POST ||
protocol == HTTP_POST);
char req_url[256];
sockaddr_to_url(&sockaddr_remote, is_https, req_url,
sizeof(req_url), DEFAULT_DOH_PATH);
if (is_https) {
isc_tlsctx_createclient(&tls_ctx);
}
result = isc_nm_httpconnect(
netmgr, (isc_nmiface_t *)&sockaddr_local,
(isc_nmiface_t *)&sockaddr_remote, req_url, is_post,
connect_cb, NULL, tls_ctx, timeout, 0);
} break;
default:
INSIST(0);
ISC_UNREACHABLE();

View File

@ -25,9 +25,11 @@
#include <isc/string.h>
#include <isc/util.h>
typedef enum { UDP, TCP, DOT, DOH } protocol_t;
#define DEFAULT_DOH_PATH "/dns-query"
static const char *protocols[] = { "udp", "tcp", "dot", "doh" };
typedef enum { UDP, TCP, DOT, HTTPS, HTTP } protocol_t;
static const char *protocols[] = { "udp", "tcp", "dot", "https", "http-plain" };
static isc_mem_t *mctx = NULL;
static isc_nm_t *netmgr = NULL;
@ -38,6 +40,8 @@ static isc_netaddr_t netaddr;
static isc_sockaddr_t sockaddr __attribute__((unused));
static int workers;
static isc_tlsctx_t *tls_ctx = NULL;
static void
read_cb(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
void *cbarg);
@ -191,6 +195,9 @@ static void
teardown(void) {
isc_nm_destroy(&netmgr);
isc_mem_destroy(&mctx);
if (tls_ctx) {
isc_tlsctx_free(&tls_ctx);
}
}
static void
@ -267,18 +274,26 @@ run(void) {
0, NULL, &sock);
break;
case DOT: {
isc_tlsctx_t *tlsdns_ctx = NULL;
isc_tlsctx_createserver(NULL, NULL, &tlsdns_ctx);
isc_tlsctx_createserver(NULL, NULL, &tls_ctx);
result = isc_nm_listentlsdns(netmgr, (isc_nmiface_t *)&sockaddr,
read_cb, NULL, accept_cb, NULL, 0,
0, NULL, tlsdns_ctx, &sock);
0, NULL, tls_ctx, &sock);
break;
}
case DOH:
INSIST(0);
ISC_UNREACHABLE();
break;
case HTTPS:
case HTTP: {
bool is_https = protocol == HTTPS;
if (is_https) {
isc_tlsctx_createserver(NULL, NULL, &tls_ctx);
}
result = isc_nm_listenhttp(netmgr, (isc_nmiface_t *)&sockaddr,
0, NULL, tls_ctx, &sock);
if (result == ISC_R_SUCCESS) {
result = isc_nm_http_endpoint(sock, DEFAULT_DOH_PATH,
read_cb, NULL, 0);
}
} break;
default:
INSIST(0);
ISC_UNREACHABLE();

View File

@ -361,11 +361,38 @@ This option sends a query with a DNS header without a question section. The
default is to add a question section. The query type and query name
are ignored when this is set.
.TP
.B \fB+[no]https[=value]\fP
This option indicates whether to use DNS\-over\-HTTPS (DoH) when querying
name servers. When this option is in use, the port number defaults to 443.
The HTTP POST request mode is used when sending the query.
.sp
If \fBvalue\fP is specified, it will be used as the HTTP endpoint in the
query URI; the default is \fB/dns\-query\fP\&. So, for example, \fBdig
@example.com +https\fP will use the URI \fBhttps://example.com/dns\-query\fP\&.
.TP
.B \fB+[no]https\-get[=value]\fP
Similar to \fB+https\fP, except that the HTTP GET request mode is used
when sending the query.
.TP
.B \fB+[no]https\-post[=value]\fP
Same as \fB+https\fP\&.
.TP
.B \fB+[no]http\-plain[=value]\fP
Similar to \fB+https\fP, except that HTTP queries will be sent over a
non\-encrypted channel. When this option is in use, the port number
defaults to 80 and the HTTP request mode is POST.
.TP
.B \fB+[no]http\-plain\-get[=value]\fP
Similar to \fB+http\-plain\fP, except that the HTTP request mode is GET.
.TP
.B \fB+[no]http\-plain\-post[=value]\fP
Same as \fB+http\-plain\fP\&.
.TP
.B \fB+[no]identify\fP
This option shows [or does not show] the IP address and port number that supplied
the answer, when the \fB+short\fP option is enabled. If short form
answers are requested, the default is not to show the source address
and port number of the server that provided the answer.
This option shows [or does not show] the IP address and port number that
supplied the answer, when the \fB+short\fP option is enabled. If short
form answers are requested, the default is not to show the source
address and port number of the server that provided the answer.
.TP
.B \fB+[no]idnin\fP
This option processes [or does not process] IDN domain names on input. This requires
@ -531,8 +558,9 @@ This option sets the timeout for a query to \fBT\fP seconds. The default timeout
5 seconds. An attempt to set \fBT\fP to less than 1 is silently set to 1.
.TP
.B \fB+[no]tls\fP
This option indicates whether to use DNS over TLS (DoT) when querying
name servers.
This option indicates whether to use DNS\-over\-TLS (DoT) when querying
name servers. When this option is in use, the port number defaults
to 853.
.TP
.B \fB+[no]topdown\fP
This feature is related to \fBdig +sigchase\fP, which is obsolete and

View File

@ -24,7 +24,8 @@ Known Issues
New Features
~~~~~~~~~~~~
- None.
- ``dig`` has been extended to support DNS-over-HTTPS (DoH) queries,
using ``dig +https`` and related options. [GL #1641]
- A new option, ``purge-keys``, has been added to ``dnssec-policy``. It sets
the time how long key files should be retained after they have become

View File

@ -18,14 +18,14 @@ typedef enum {
DNS_TRANSPORT_UDP = 1,
DNS_TRANSPORT_TCP = 2,
DNS_TRANSPORT_TLS = 3,
DNS_TRANSPORT_DOH = 4,
DNS_TRANSPORT_HTTP = 4,
DNS_TRANSPORT_COUNT = 5,
} dns_transport_type_t;
typedef enum {
DNS_DOH_GET = 0,
DNS_DOH_POST = 1,
} dns_doh_mode_t;
DNS_HTTP_GET = 0,
DNS_HTTP_POST = 1,
} dns_http_mode_t;
typedef struct dns_transport dns_transport_t;
typedef struct dns_transport_list dns_transport_list_t;
@ -50,11 +50,11 @@ char *
dns_transport_get_hostname(dns_transport_t *transport);
char *
dns_transport_get_endpoint(dns_transport_t *transport);
dns_doh_mode_t
dns_http_mode_t
dns_transport_get_mode(dns_transport_t *transport);
/*%<
* Getter functions: return the type, cert file, key file, CA file,
* hostname, DoH endpoint, or DoH mode (GET or POST) for 'transport'.
* hostname, HTTP endpoint, or HTTP mode (GET or POST) for 'transport'.
*/
void
@ -68,16 +68,16 @@ dns_transport_set_hostname(dns_transport_t *transport, const char *hostname);
void
dns_transport_set_endpoint(dns_transport_t *transport, const char *endpoint);
void
dns_transport_set_mode(dns_transport_t *transport, dns_doh_mode_t mode);
dns_transport_set_mode(dns_transport_t *transport, dns_http_mode_t mode);
/*%<
* Setter functions: set the type, cert file, key file, CA file,
* hostname, DoH endpoint, or DoH mode (GET or POST) for 'transport'.
* hostname, HTTP endpoint, or HTTP mode (GET or POST) for 'transport'.
*
* Requires:
*\li 'transport' is valid.
*\li 'transport' is of type DNS_TRANSPORT_TLS or DNS_TRANSPORT_DOH
*\li 'transport' is of type DNS_TRANSPORT_TLS or DNS_TRANSPORT_HTTP
* (for certfile, keyfile, cafile, or hostname).
*\li 'transport' is of type DNS_TRANSPORT_DOH (for endpoint or mode).
*\li 'transport' is of type DNS_TRANSPORT_HTTP (for endpoint or mode).
*/
void

View File

@ -50,7 +50,7 @@ struct dns_transport {
} tls;
struct {
char *endpoint;
dns_doh_mode_t mode;
dns_http_mode_t mode;
} doh;
};
@ -124,7 +124,7 @@ dns_transport_get_endpoint(dns_transport_t *transport) {
return (transport->doh.endpoint);
}
dns_doh_mode_t
dns_http_mode_t
dns_transport_get_mode(dns_transport_t *transport) {
REQUIRE(VALID_TRANSPORT(transport));
@ -150,7 +150,7 @@ void
dns_transport_set_certfile(dns_transport_t *transport, const char *certfile) {
REQUIRE(VALID_TRANSPORT(transport));
REQUIRE(transport->type == DNS_TRANSPORT_TLS ||
transport->type == DNS_TRANSPORT_DOH);
transport->type == DNS_TRANSPORT_HTTP);
if (certfile != NULL) {
transport->tls.certfile = isc_mem_strdup(transport->mctx,
@ -162,7 +162,7 @@ void
dns_transport_set_keyfile(dns_transport_t *transport, const char *keyfile) {
REQUIRE(VALID_TRANSPORT(transport));
REQUIRE(transport->type == DNS_TRANSPORT_TLS ||
transport->type == DNS_TRANSPORT_DOH);
transport->type == DNS_TRANSPORT_HTTP);
if (keyfile != NULL) {
transport->tls.keyfile = isc_mem_strdup(transport->mctx,
@ -174,7 +174,7 @@ void
dns_transport_set_cafile(dns_transport_t *transport, const char *cafile) {
REQUIRE(VALID_TRANSPORT(transport));
REQUIRE(transport->type == DNS_TRANSPORT_TLS ||
transport->type == DNS_TRANSPORT_DOH);
transport->type == DNS_TRANSPORT_HTTP);
if (cafile != NULL) {
transport->tls.cafile = isc_mem_strdup(transport->mctx, cafile);
@ -185,7 +185,7 @@ void
dns_transport_set_hostname(dns_transport_t *transport, const char *hostname) {
REQUIRE(VALID_TRANSPORT(transport));
REQUIRE(transport->type == DNS_TRANSPORT_TLS ||
transport->type == DNS_TRANSPORT_DOH);
transport->type == DNS_TRANSPORT_HTTP);
if (hostname != NULL) {
transport->tls.hostname = isc_mem_strdup(transport->mctx,
@ -196,7 +196,7 @@ dns_transport_set_hostname(dns_transport_t *transport, const char *hostname) {
void
dns_transport_set_endpoint(dns_transport_t *transport, const char *endpoint) {
REQUIRE(VALID_TRANSPORT(transport));
REQUIRE(transport->type == DNS_TRANSPORT_DOH);
REQUIRE(transport->type == DNS_TRANSPORT_HTTP);
if (endpoint != NULL) {
transport->doh.endpoint = isc_mem_strdup(transport->mctx,
@ -205,9 +205,9 @@ dns_transport_set_endpoint(dns_transport_t *transport, const char *endpoint) {
}
void
dns_transport_set_mode(dns_transport_t *transport, dns_doh_mode_t mode) {
dns_transport_set_mode(dns_transport_t *transport, dns_http_mode_t mode) {
REQUIRE(VALID_TRANSPORT(transport));
REQUIRE(transport->type == DNS_TRANSPORT_DOH);
REQUIRE(transport->type == DNS_TRANSPORT_HTTP);
transport->doh.mode = mode;
}

View File

@ -506,45 +506,17 @@ isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
* 'cb'.
*/
typedef void (*isc_nm_http_cb_t)(isc_nmhandle_t *handle, isc_result_t eresult,
isc_region_t *data, void *cbarg);
/*%<
* Callback function to be used when receiving an HTTP request.
*
* 'handle' the handle that can be used to send back the answer.
* 'eresult' the result of the event.
* 'data' contains the received data, if any. It will be freed
* after return by caller.
* 'cbarg' the callback argument passed to listen function.
*/
isc_result_t
isc_nm_http_connect_send_request(isc_nm_t *mgr, const char *uri, bool POST,
isc_region_t *message, isc_nm_recv_cb_t cb,
void *cbarg, isc_tlsctx_t *ctx,
unsigned int timeout);
isc_result_t
isc_nm_httpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
const char *uri, bool POST, isc_nm_cb_t cb, void *cbarg,
isc_tlsctx_t *ctx, unsigned int timeout,
size_t extrahandlesize);
isc_result_t
isc_nm_httprequest(isc_nmhandle_t *handle, isc_region_t *region,
isc_nm_recv_cb_t reply_cb, void *cbarg);
isc_result_t
isc_nm_listenhttp(isc_nm_t *mgr, isc_nmiface_t *iface, int backlog,
isc_quota_t *quota, isc_tlsctx_t *ctx,
isc_nmsocket_t **sockp);
isc_result_t
isc_nm_http_add_endpoint(isc_nmsocket_t *sock, const char *uri,
isc_nm_http_cb_t cb, void *cbarg,
size_t extrahandlesize);
isc_result_t
isc_nm_http_add_doh_endpoint(isc_nmsocket_t *sock, const char *uri,
isc_nm_recv_cb_t cb, void *cbarg,
size_t extrahandlesize);
isc_nm_http_endpoint(isc_nmsocket_t *sock, const char *uri, isc_nm_recv_cb_t cb,
void *cbarg, size_t extrahandlesize);

View File

@ -89,9 +89,10 @@
#define ISC_R_DEFAULT 68 /*%< default */
#define ISC_R_IPV4PREFIX 69 /*%< IPv4 prefix */
#define ISC_R_TLSERROR 70 /*%< TLS error */
#define ISC_R_HTTP2ALPNERROR 71 /*%< ALPN for HTTP/2 failed */
/*% Not a result code: the number of results. */
#define ISC_R_NRESULTS 71
#define ISC_R_NRESULTS 72
ISC_LANG_BEGINDECLS

View File

@ -14,35 +14,72 @@
#include <isc/mem.h>
#include <isc/region.h>
#include <isc/result.h>
#include <isc/tls.h>
#include <isc/types.h>
typedef struct ssl_ctx_st isc_tlsctx_t;
typedef struct ssl_st isc_tls_t;
void
isc_tlsctx_free(isc_tlsctx_t **ctpx);
/*%
* Free the TLS client/server context.
/*%<
* Free a TLS client or server context.
*
* Require:
* Requires:
*\li 'ctxp' != NULL and '*ctxp' != NULL.
*/
isc_result_t
isc_tlsctx_createserver(const char *keyfile, const char *certfile,
isc_tlsctx_t **ctxp);
/*%
* Set up TLS server context.
/*%<
* Set up a TLS server context, using the key and certificate specified in
* 'keyfile' and 'certfile', or a self-generated ephemeral key and
* certificdate if both 'keyfile' and 'certfile' are NULL.
*
* Require:
* Requires:
*\li 'ctxp' != NULL and '*ctxp' == NULL.
*\li 'keyfile' and 'certfile' are either both NULL or both non-NULL.
*/
isc_result_t
isc_tlsctx_createclient(isc_tlsctx_t **ctxp);
/*%
* Set up TLS client context.
/*%<
* Set up a TLS client context.
*
* Require:
* Requires:
*\li 'ctxp' != NULL and '*ctxp' == NULL.
*/
isc_tls_t *
isc_tls_create(isc_tlsctx_t *ctx);
/*%<
* Set up the structure to hold data for a new TLS connection.
*
* Requires:
*\li 'ctx' != NULL.
*/
void
isc_tls_free(isc_tls_t **tlsp);
/*%<
* Free a TLS structure.
*
* Requires:
*\li 'tlsp' != NULL and '*tlsp' != NULL.
*/
void
isc_tlsctx_enable_http2client_alpn(isc_tlsctx_t *ctx);
void
isc_tlsctx_enable_http2server_alpn(isc_tlsctx_t *ctx);
/*%<
*
* Enable HTTP/2 Application Layer Protocol Negotation for 'ctx'.
*
* Requires:
*\li 'ctx' is not NULL.
*/
void
isc_tls_get_http2_alpn(isc_tls_t *tls, const unsigned char **alpn,
unsigned int *alpnlen);

File diff suppressed because it is too large Load Diff

View File

@ -34,6 +34,7 @@
#include <isc/sockaddr.h>
#include <isc/stats.h>
#include <isc/thread.h>
#include <isc/tls.h>
#include <isc/util.h>
#include "uv-compat.h"
@ -156,8 +157,6 @@ isc__nm_dump_active(isc_nm_t *nm);
#define isc__nmsocket_prep_destroy(sock) isc___nmsocket_prep_destroy(sock)
#endif
typedef struct isc_nm_http2_session isc_nm_http2_session_t;
/*
* Single network event loop worker.
*/
@ -195,6 +194,7 @@ typedef struct isc__networker {
atomic_load(&(t)->references) > 0)
typedef void (*isc__nm_closecb)(isc_nmhandle_t *);
typedef struct isc_nm_http_session isc_nm_http_session_t;
struct isc_nmhandle {
int magic;
@ -210,7 +210,7 @@ struct isc_nmhandle {
isc_nmsocket_t *sock;
size_t ah_pos; /* Position in the socket's 'active handles' array */
isc_nm_http2_session_t *httpsession;
isc_nm_http_session_t *httpsession;
isc_sockaddr_t peer;
isc_sockaddr_t local;
@ -302,20 +302,18 @@ typedef enum isc__netievent_type {
typedef union {
isc_nm_recv_cb_t recv;
isc_nm_http_cb_t http;
isc_nm_cb_t send;
isc_nm_cb_t connect;
isc_nm_accept_cb_t accept;
} isc__nm_cb_t;
typedef struct isc_nm_http2_server_handler isc_nm_http2_server_handler_t;
struct isc_nm_http2_server_handler {
typedef struct isc_nm_httphandler isc_nm_httphandler_t;
struct isc_nm_httphandler {
char *path;
isc_nm_http_cb_t cb;
isc_nm_recv_cb_t cb;
void *cbarg;
size_t extrahandlesize;
LINK(isc_nm_http2_server_handler_t) link;
LINK(isc_nm_httphandler_t) link;
};
/*
@ -674,7 +672,7 @@ typedef enum isc_nmsocket_type {
isc_nm_tlsdnslistener,
isc_nm_tlsdnssocket,
isc_nm_httplistener,
isc_nm_httpstream
isc_nm_httpsocket
} isc_nmsocket_type;
/*%
@ -704,25 +702,29 @@ enum {
typedef struct isc_nmsocket_tls_send_req {
isc_nmsocket_t *tlssock;
isc_region_t data;
isc_nm_cb_t cb;
void *cbarg;
isc_nmhandle_t *handle;
bool finish;
} isc_nmsocket_tls_send_req_t;
typedef enum isc_doh_request_type {
typedef enum isc_http_request_type {
ISC_HTTP_REQ_GET,
ISC_HTTP_REQ_POST,
ISC_HTTP_REQ_UNSUPPORTED
} isc_http2_request_type_t;
} isc_http_request_type_t;
typedef enum isc_http2_scheme_type {
typedef enum isc_http_scheme_type {
ISC_HTTP_SCHEME_HTTP,
ISC_HTTP_SCHEME_HTTP_SECURE,
ISC_HTTP_SCHEME_UNSUPPORTED
} isc_http2_scheme_type_t;
} isc_http_scheme_type_t;
typedef struct isc_nm_http_doh_cbarg {
typedef struct isc_nm_httpcbarg {
isc_nm_recv_cb_t cb;
void *cbarg;
LINK(struct isc_nm_http_doh_cbarg) link;
} isc_nm_http_doh_cbarg_t;
LINK(struct isc_nm_httpcbarg) link;
} isc_nm_httpcbarg_t;
typedef struct isc_nmsocket_h2 {
isc_nmsocket_t *psock; /* owner of the structure */
@ -730,38 +732,43 @@ typedef struct isc_nmsocket_h2 {
char *query_data;
size_t query_data_len;
bool query_too_large;
isc_nm_http2_server_handler_t *handler;
isc_nm_httphandler_t *handler;
uint8_t *buf;
size_t bufsize;
size_t bufpos;
int32_t stream_id;
isc_nm_http2_session_t *session;
isc_nm_http_session_t *session;
isc_nmsocket_t *httpserver;
isc_http2_request_type_t request_type;
isc_http2_scheme_type_t request_scheme;
size_t content_length;
bool content_type_verified;
bool accept_type_verified;
isc_http_request_type_t request_type;
isc_http_scheme_type_t request_scheme;
isc_nm_http_cb_t handler_cb;
void *handler_cbarg;
size_t content_length;
char clenbuf[128];
int headers_error_code;
size_t headers_data_processed;
isc_nm_recv_cb_t cb;
void *cbarg;
LINK(struct isc_nmsocket_h2) link;
ISC_LIST(isc_nm_http2_server_handler_t) handlers;
ISC_LIST(isc_nm_http_doh_cbarg_t) handlers_cbargs;
isc_rwlock_t handlers_lock;
ISC_LIST(isc_nm_httphandler_t) handlers;
ISC_LIST(isc_nm_httpcbarg_t) handler_cbargs;
isc_rwlock_t lock;
char response_content_length_str[128];
struct isc_nmsocket_h2_connect_data {
struct {
char *uri;
bool post;
isc_tlsctx_t *tlsctx;
isc_nmiface_t local_interface;
void *cstream;
} connect;
} isc_nmsocket_h2_t;
struct isc_nmsocket {
/*% Unlocked, RO */
int magic;
@ -778,8 +785,8 @@ struct isc_nmsocket {
/*% TLS stuff */
struct tls {
SSL *ssl;
SSL_CTX *ctx;
isc_tls_t *tls;
isc_tlsctx_t *ctx;
BIO *app_rbio;
BIO *app_wbio;
BIO *ssl_rbio;
@ -802,21 +809,22 @@ struct isc_nmsocket {
struct tlsstream {
bool server;
BIO *app_bio;
SSL *ssl;
SSL_CTX *ctx;
isc_tls_t *tls;
isc_tlsctx_t *ctx;
BIO *ssl_bio;
isc_nmsocket_t *tlslistener;
isc_nmiface_t server_iface;
isc_nmiface_t local_iface;
bool connect_from_networker;
atomic_bool result_updated;
enum {
TLS_INIT,
TLS_HANDSHAKE,
TLS_IO,
TLS_ERROR,
TLS_CLOSING,
TLS_CLOSED
} state;
} state; /*%< The order of these is significant */
size_t nsending;
/* List of active send requests. */
ISC_LIST(isc__nm_uvreq_t) sends;
} tlsstream;
isc_nmsocket_h2_t h2;
@ -1149,11 +1157,15 @@ isc__nmsocket_clearcb(isc_nmsocket_t *sock);
void
isc__nm_connectcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq,
isc_result_t eresult);
void
isc__nm_connectcb_force_async(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq,
isc_result_t eresult);
void
isc__nm_async_connectcb(isc__networker_t *worker, isc__netievent_t *ev0);
/*%<
* Issue a connect callback on the socket, used to call the callback
*/
void
@ -1518,19 +1530,42 @@ isc__nm_tls_cleanup_data(isc_nmsocket_t *sock);
void
isc__nm_tls_stoplistening(isc_nmsocket_t *sock);
void
isc__nm_tls_settimeout(isc_nmhandle_t *handle, uint32_t timeout);
/*%<
* Set the read timeout and reset the timer for the socket
* associated with 'handle', and the TCP socket it wraps
* around.
*/
void
isc__nm_http_stoplistening(isc_nmsocket_t *sock);
void
isc__nm_http_clear_handlers(isc_nmsocket_t *sock);
isc__nm_http_settimeout(isc_nmhandle_t *handle, uint32_t timeout);
/*%<
* Set the read timeout and reset the timer for the socket
* associated with 'handle', and the TLS/TCP socket it wraps
* around.
*/
void
isc__nm_http_clear_session(isc_nmsocket_t *sock);
isc__nm_http_initsocket(isc_nmsocket_t *sock);
void
isc__nm_http_cleanup_data(isc_nmsocket_t *sock);
isc_result_t
isc__nm_http_request(isc_nmhandle_t *handle, isc_region_t *region,
isc_nm_recv_cb_t reply_cb, void *cbarg);
void
isc__nm_http_send(isc_nmhandle_t *handle, const isc_region_t *region,
isc_nm_cb_t cb, void *cbarg);
void
isc__nm_http_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg);
void
isc__nm_http_close(isc_nmsocket_t *sock);
@ -1544,7 +1579,7 @@ void
isc__nm_async_httpclose(isc__networker_t *worker, isc__netievent_t *ev0);
bool
isc__nm_parse_doh_query_string(const char *query_string, const char **start,
isc__nm_parse_httpquery(const char *query_string, const char **start,
size_t *len);
char *
@ -1555,6 +1590,12 @@ char *
isc__nm_base64_to_base64url(isc_mem_t *mem, const char *base64,
const size_t base64_len, size_t *res_len);
void
isc__nm_httpsession_attach(isc_nm_http_session_t *source,
isc_nm_http_session_t **targetp);
void
isc__nm_httpsession_detach(isc_nm_http_session_t **sessionp);
#define isc__nm_uverr2result(x) \
isc___nm_uverr2result(x, true, __FILE__, __LINE__, __func__)
isc_result_t
@ -1646,6 +1687,12 @@ isc__nm_socket_connectiontimeout(uv_os_sock_t fd, int timeout_ms);
* the minimum value must be at least 1000 (1 second).
*/
isc_result_t
isc__nm_socket_tcp_nodelay(uv_os_sock_t fd);
/*%<
* Disables Nagle's algorithm on a TCP socket (sets TCP_NODELAY).
*/
/*
* typedef all the netievent types
*/

View File

@ -1004,33 +1004,7 @@ nmsocket_cleanup(isc_nmsocket_t *sock, bool dofree FLARG) {
isc_condition_destroy(&sock->cond);
isc_condition_destroy(&sock->scond);
isc__nm_tls_cleanup_data(sock);
if (sock->type == isc_nm_httplistener) {
isc__nm_http_clear_handlers(sock);
isc_rwlock_destroy(&sock->h2.handlers_lock);
}
if (sock->h2.request_path != NULL) {
isc_mem_free(sock->mgr->mctx, sock->h2.request_path);
sock->h2.request_path = NULL;
}
if (sock->h2.query_data != NULL) {
isc_mem_free(sock->mgr->mctx, sock->h2.query_data);
sock->h2.query_data = NULL;
}
if (sock->h2.connect.uri != NULL) {
isc_mem_free(sock->mgr->mctx, sock->h2.connect.uri);
sock->h2.query_data = NULL;
}
if (sock->h2.buf != NULL) {
isc_mem_free(sock->mgr->mctx, sock->h2.buf);
sock->h2.buf = NULL;
}
isc__nm_http_clear_session(sock);
isc__nm_http_cleanup_data(sock);
#ifdef NETMGR_TRACE
LOCK(&sock->mgr->lock);
ISC_LIST_UNLINK(sock->mgr->active_sockets, sock, active_link);
@ -1145,7 +1119,7 @@ isc___nmsocket_prep_destroy(isc_nmsocket_t *sock FLARG) {
case isc_nm_tlsdnssocket:
isc__nm_tlsdns_close(sock);
return;
case isc_nm_httpstream:
case isc_nm_httpsocket:
isc__nm_http_close(sock);
return;
default:
@ -1255,7 +1229,7 @@ isc___nmsocket_init(isc_nmsocket_t *sock, isc_nm_t *mgr, isc_nmsocket_type type,
case isc_nm_tcpdnslistener:
case isc_nm_tlsdnssocket:
case isc_nm_tlsdnslistener:
case isc_nm_httpstream:
case isc_nm_httpsocket:
case isc_nm_httplistener:
if (family == AF_INET) {
sock->statsindex = tcp4statsindex;
@ -1274,7 +1248,6 @@ isc___nmsocket_init(isc_nmsocket_t *sock, isc_nm_t *mgr, isc_nmsocket_type type,
isc_refcount_init(&sock->references, 1);
memset(&sock->tlsstream, 0, sizeof(sock->tlsstream));
ISC_LIST_INIT(sock->tlsstream.sends);
NETMGR_TRACE_LOG("isc__nmsocket_init():%p->references = %lu\n", sock,
isc_refcount_current(&sock->references));
@ -1286,27 +1259,7 @@ isc___nmsocket_init(isc_nmsocket_t *sock, isc_nm_t *mgr, isc_nmsocket_type type,
atomic_store(&sock->active_child_connections, 0);
if (type == isc_nm_httplistener) {
ISC_LIST_INIT(sock->h2.handlers);
ISC_LIST_INIT(sock->h2.handlers_cbargs);
isc_rwlock_init(&sock->h2.handlers_lock, 0, 1);
}
sock->h2.session = NULL;
sock->h2.httpserver = NULL;
sock->h2.query_data = NULL;
sock->h2.query_data_len = 0;
sock->h2.query_too_large = false;
sock->h2.request_path = NULL;
sock->h2.request_type = ISC_HTTP_REQ_UNSUPPORTED;
sock->h2.request_scheme = ISC_HTTP_SCHEME_UNSUPPORTED;
sock->h2.content_length = 0;
sock->h2.content_type_verified = false;
sock->h2.accept_type_verified = false;
sock->h2.handler_cb = NULL;
sock->h2.handler_cbarg = NULL;
sock->h2.connect.uri = NULL;
sock->h2.buf = NULL;
isc__nm_http_initsocket(sock);
sock->magic = NMSOCK_MAGIC;
}
@ -1449,8 +1402,9 @@ isc___nmhandle_get(isc_nmsocket_t *sock, isc_sockaddr_t *peer,
sock->statichandle = handle;
}
if (sock->type == isc_nm_httpstream) {
handle->httpsession = sock->h2.session;
if (sock->type == isc_nm_httpsocket && sock->h2.session) {
isc__nm_httpsession_attach(sock->h2.session,
&handle->httpsession);
}
return (handle);
@ -1582,6 +1536,10 @@ nmhandle_detach_cb(isc_nmhandle_t **handlep FLARG) {
handle->doreset(handle->opaque);
}
if (sock->type == isc_nm_httpsocket && handle->httpsession != NULL) {
isc__nm_httpsession_detach(&handle->httpsession);
}
nmhandle_deactivate(sock, handle);
/*
@ -1642,6 +1600,12 @@ isc_nmhandle_settimeout(isc_nmhandle_t *handle, uint32_t timeout) {
case isc_nm_tlsdnssocket:
isc__nm_tlsdns_settimeout(handle, timeout);
break;
case isc_nm_tlssocket:
isc__nm_tls_settimeout(handle, timeout);
break;
case isc_nm_httpsocket:
isc__nm_http_settimeout(handle, timeout);
break;
default:
INSIST(0);
ISC_UNREACHABLE();
@ -1758,7 +1722,7 @@ isc_nm_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
case isc_nm_tlsdnssocket:
isc__nm_tlsdns_send(handle, region, cb, cbarg);
break;
case isc_nm_httpstream:
case isc_nm_httpsocket:
isc__nm_http_send(handle, region, cb, cbarg);
break;
default:
@ -1794,6 +1758,9 @@ isc_nm_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
case isc_nm_tlsdnssocket:
isc__nm_tlsdns_read(handle, cb, cbarg);
break;
case isc_nm_httpsocket:
isc__nm_http_read(handle, cb, cbarg);
break;
default:
INSIST(0);
ISC_UNREACHABLE();
@ -1893,27 +1860,38 @@ isc_nm_stoplistening(isc_nmsocket_t *sock) {
}
}
void
isc__nm_connectcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq,
isc_result_t eresult) {
static void
nm_connectcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq, isc_result_t eresult,
bool force_async) {
isc__netievent_connectcb_t *ievent = NULL;
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(VALID_UVREQ(uvreq));
REQUIRE(VALID_NMHANDLE(uvreq->handle));
if (eresult == ISC_R_SUCCESS) {
isc__netievent_connectcb_t ievent = { .sock = sock,
.req = uvreq,
.result = eresult };
isc__nm_async_connectcb(NULL, (isc__netievent_t *)&ievent);
} else {
isc__netievent_connectcb_t *ievent =
isc__nm_get_netievent_connectcb(sock->mgr, sock, uvreq,
ievent = isc__nm_get_netievent_connectcb(sock->mgr, sock, uvreq,
eresult);
if (force_async) {
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
} else {
isc__nm_maybe_enqueue_ievent(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
}
}
void
isc__nm_connectcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq,
isc_result_t eresult) {
nm_connectcb(sock, uvreq, eresult, false);
}
void
isc__nm_connectcb_force_async(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq,
isc_result_t eresult) {
nm_connectcb(sock, uvreq, eresult, true);
}
void
isc__nm_async_connectcb(isc__networker_t *worker, isc__netievent_t *ev0) {
isc__netievent_connectcb_t *ievent = (isc__netievent_connectcb_t *)ev0;
@ -2429,6 +2407,20 @@ isc__nm_socket_connectiontimeout(uv_os_sock_t fd, int timeout_ms) {
#endif
}
isc_result_t
isc__nm_socket_tcp_nodelay(uv_os_sock_t fd) {
#ifdef TCP_NODELAY
if (setsockopt_on(fd, IPPROTO_TCP, TCP_NODELAY) == -1) {
return (ISC_R_FAILURE);
} else {
return (ISC_R_SUCCESS);
}
#else
UNUSED(fd);
return (ISC_R_SUCCESS);
#endif
}
#ifdef NETMGR_TRACE
/*
* Dump all active sockets in netmgr. We output to stderr
@ -2460,8 +2452,8 @@ nmsocket_type_totext(isc_nmsocket_type type) {
return ("isc_nm_tlsdnssocket");
case isc_nm_httplistener:
return ("isc_nm_httplistener");
case isc_nm_httpstream:
return ("isc_nm_httpstream");
case isc_nm_httpsocket:
return ("isc_nm_httpsocket");
default:
INSIST(0);
ISC_UNREACHABLE();

View File

@ -167,23 +167,6 @@ tcp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
REQUIRE(isc__nm_in_netthread());
REQUIRE(sock->tid == isc_nm_tid());
result = isc__nm_socket(req->peer.type.sa.sa_family, SOCK_STREAM, 0,
&sock->fd);
/*
* The socket() call can fail spuriously on FreeBSD 12, so we need to
* handle the failure early and gracefully.
*/
if (result != ISC_R_SUCCESS) {
atomic_store(&sock->closed, true);
isc__nm_uvreq_t *cbreq = NULL;
cbreq = isc__nm_uvreq_get(sock->mgr, sock);
cbreq->cb.connect = req->cb.connect;
cbreq->cbarg = req->cbarg;
isc_nmhandle_attach(req->handle, &cbreq->handle);
isc__nmsocket_clearcb(sock);
isc__nm_connectcb(sock, cbreq, result);
goto error;
}
result = isc__nm_socket_connectiontimeout(sock->fd,
sock->connect_timeout);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
@ -231,7 +214,7 @@ tcp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
done:
result = isc__nm_uverr2result(r);
error:
LOCK(&sock->lock);
sock->result = result;
SIGNAL(&sock->cond);
@ -260,7 +243,6 @@ isc__nm_async_tcpconnect(isc__networker_t *worker, isc__netievent_t *ev0) {
REQUIRE(sock->parent == NULL);
REQUIRE(sock->tid == isc_nm_tid());
sock->fd = (uv_os_sock_t)(-1);
result = tcp_connect_direct(sock, req);
if (result != ISC_R_SUCCESS) {
atomic_store(&sock->active, false);
@ -333,17 +315,31 @@ isc_nm_tcpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
isc_nmsocket_t *sock = NULL;
isc__netievent_tcpconnect_t *ievent = NULL;
isc__nm_uvreq_t *req = NULL;
sa_family_t sa_family;
uv_os_sock_t fd;
REQUIRE(VALID_NM(mgr));
REQUIRE(local != NULL);
REQUIRE(peer != NULL);
sa_family = peer->addr.type.sa.sa_family;
/*
* The socket() call can fail spuriously on FreeBSD 12, so we need to
* handle the failure early and gracefully.
*/
result = isc__nm_socket(sa_family, SOCK_STREAM, 0, &fd);
if (result != ISC_R_SUCCESS) {
return (result);
}
sock = isc_mem_get(mgr->mctx, sizeof(*sock));
isc__nmsocket_init(sock, mgr, isc_nm_tcpsocket, local);
sock->extrahandlesize = extrahandlesize;
sock->connect_timeout = timeout;
sock->result = ISC_R_DEFAULT;
sock->fd = fd;
atomic_init(&sock->client, true);
req = isc__nm_uvreq_get(mgr, sock);

View File

@ -338,8 +338,8 @@ tlsdns_connect_cb(uv_connect_t *uvreq, int status) {
}
sock->tls.state = TLS_STATE_NONE;
sock->tls.ssl = SSL_new(sock->tls.ctx);
RUNTIME_CHECK(sock->tls.ssl != NULL);
sock->tls.tls = isc_tls_create(sock->tls.ctx);
RUNTIME_CHECK(sock->tls.tls != NULL);
/*
*
@ -359,13 +359,13 @@ tlsdns_connect_cb(uv_connect_t *uvreq, int status) {
* may be necessary to increment the number of references available
* using BIO_up_ref(3) before calling the set0 functions.
*/
SSL_set0_rbio(sock->tls.ssl, sock->tls.ssl_rbio);
SSL_set0_wbio(sock->tls.ssl, sock->tls.ssl_wbio);
SSL_set0_rbio(sock->tls.tls, sock->tls.ssl_rbio);
SSL_set0_wbio(sock->tls.tls, sock->tls.ssl_wbio);
#else
SSL_set_bio(sock->tls.ssl, sock->tls.ssl_rbio, sock->tls.ssl_wbio);
SSL_set_bio(sock->tls.tls, sock->tls.ssl_rbio, sock->tls.ssl_wbio);
#endif
SSL_set_connect_state(sock->tls.ssl);
SSL_set_connect_state(sock->tls.tls);
result = isc_sockaddr_fromsockaddr(&sock->peer, (struct sockaddr *)&ss);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
@ -782,7 +782,7 @@ isc__nm_async_tlsdnsshutdown(isc__networker_t *worker, isc__netievent_t *ev0) {
return;
}
rv = SSL_shutdown(sock->tls.ssl);
rv = SSL_shutdown(sock->tls.tls);
if (rv == 1) {
sock->tls.state = TLS_STATE_NONE;
@ -802,7 +802,7 @@ isc__nm_async_tlsdnsshutdown(isc__networker_t *worker, isc__netievent_t *ev0) {
return;
}
err = SSL_get_error(sock->tls.ssl, rv);
err = SSL_get_error(sock->tls.tls, rv);
switch (err) {
case SSL_ERROR_WANT_READ:
@ -1167,9 +1167,9 @@ tls_cycle_input(isc_nmsocket_t *sock) {
size_t len;
for (;;) {
(void)SSL_peek(sock->tls.ssl, &(char){ '\0' }, 0);
(void)SSL_peek(sock->tls.tls, &(char){ '\0' }, 0);
int pending = SSL_pending(sock->tls.ssl);
int pending = SSL_pending(sock->tls.tls);
if (pending > TLS_BUF_SIZE) {
pending = TLS_BUF_SIZE;
}
@ -1179,7 +1179,7 @@ tls_cycle_input(isc_nmsocket_t *sock) {
}
len = 0;
rv = SSL_read_ex(sock->tls.ssl,
rv = SSL_read_ex(sock->tls.tls,
sock->buf + sock->buf_len,
sock->buf_size - sock->buf_len, &len);
if (rv != 1) {
@ -1196,11 +1196,11 @@ tls_cycle_input(isc_nmsocket_t *sock) {
process_sock_buffer(sock);
}
} else if (!SSL_is_init_finished(sock->tls.ssl)) {
if (SSL_is_server(sock->tls.ssl)) {
rv = SSL_accept(sock->tls.ssl);
} else if (!SSL_is_init_finished(sock->tls.tls)) {
if (SSL_is_server(sock->tls.tls)) {
rv = SSL_accept(sock->tls.tls);
} else {
rv = SSL_connect(sock->tls.ssl);
rv = SSL_connect(sock->tls.tls);
}
} else {
@ -1208,13 +1208,13 @@ tls_cycle_input(isc_nmsocket_t *sock) {
}
if (rv <= 0) {
err = SSL_get_error(sock->tls.ssl, rv);
err = SSL_get_error(sock->tls.tls, rv);
}
switch (err) {
case SSL_ERROR_WANT_READ:
if (sock->tls.state == TLS_STATE_NONE &&
!SSL_is_init_finished(sock->tls.ssl)) {
!SSL_is_init_finished(sock->tls.tls)) {
sock->tls.state = TLS_STATE_HANDSHAKE;
start_reading(sock);
}
@ -1237,11 +1237,11 @@ tls_cycle_input(isc_nmsocket_t *sock) {
/* Stop state after handshake */
if (sock->tls.state == TLS_STATE_HANDSHAKE &&
SSL_is_init_finished(sock->tls.ssl))
SSL_is_init_finished(sock->tls.tls))
{
sock->tls.state = TLS_STATE_IO;
if (SSL_is_server(sock->tls.ssl)) {
if (SSL_is_server(sock->tls.tls)) {
REQUIRE(sock->recv_handle != NULL);
result = sock->accept_cb(sock->recv_handle,
ISC_R_SUCCESS,
@ -1656,18 +1656,8 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) {
csock->tls.state = TLS_STATE_NONE;
csock->tls.ssl = SSL_new(ssock->tls.ctx);
if (csock->tls.ssl == NULL) {
char errbuf[256];
unsigned long err = ERR_get_error();
ERR_error_string_n(err, errbuf, sizeof(errbuf));
fprintf(stderr, "%s:SSL_new(%p) -> %s\n", __func__,
ssock->tls.ctx, errbuf);
}
RUNTIME_CHECK(csock->tls.ssl != NULL);
csock->tls.tls = isc_tls_create(ssock->tls.ctx);
RUNTIME_CHECK(csock->tls.tls != NULL);
r = BIO_new_bio_pair(&csock->tls.ssl_wbio, TLS_BUF_SIZE,
&csock->tls.app_rbio, TLS_BUF_SIZE);
@ -1684,13 +1674,13 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) {
* may be necessary to increment the number of references available
* using BIO_up_ref(3) before calling the set0 functions.
*/
SSL_set0_rbio(csock->tls.ssl, csock->tls.ssl_rbio);
SSL_set0_wbio(csock->tls.ssl, csock->tls.ssl_wbio);
SSL_set0_rbio(csock->tls.tls, csock->tls.ssl_rbio);
SSL_set0_wbio(csock->tls.tls, csock->tls.ssl_wbio);
#else
SSL_set_bio(csock->tls.ssl, csock->tls.ssl_rbio, csock->tls.ssl_wbio);
SSL_set_bio(csock->tls.tls, csock->tls.ssl_rbio, csock->tls.ssl_wbio);
#endif
SSL_set_accept_state(csock->tls.ssl);
SSL_set_accept_state(csock->tls.tls);
/* FIXME: Set SSL_MODE_RELEASE_BUFFERS */
@ -1823,7 +1813,7 @@ tlsdns_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
}
/* Writes won't succeed until handshake end */
if (!SSL_is_init_finished(sock->tls.ssl)) {
if (!SSL_is_init_finished(sock->tls.tls)) {
goto requeue;
}
@ -1837,7 +1827,7 @@ tlsdns_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
memmove(worker->sendbuf + sizeof(uint16_t), req->uvbuf.base,
req->uvbuf.len);
rv = SSL_write_ex(sock->tls.ssl, worker->sendbuf, sendlen, &bytes);
rv = SSL_write_ex(sock->tls.tls, worker->sendbuf, sendlen, &bytes);
if (rv > 0) {
/* SSL_write_ex() doesn't do partial writes */
INSIST(sendlen == bytes);
@ -1848,7 +1838,7 @@ tlsdns_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
}
/* Nothing was written, maybe enqueue? */
err = SSL_get_error(sock->tls.ssl, rv);
err = SSL_get_error(sock->tls.tls, rv);
switch (err) {
case SSL_ERROR_WANT_WRITE:
@ -1921,9 +1911,8 @@ tlsdns_close_cb(uv_handle_t *handle) {
atomic_store(&sock->connected, false);
if (sock->tls.ssl) {
SSL_free(sock->tls.ssl);
sock->tls.ssl = NULL;
if (sock->tls.tls != NULL) {
isc_tls_free(&sock->tls.tls);
}
BIO_free_all(sock->tls.app_rbio);

View File

@ -44,13 +44,15 @@ tls_error_to_result(int tls_err) {
switch (tls_err) {
case SSL_ERROR_ZERO_RETURN:
return (ISC_R_EOF);
case SSL_ERROR_SSL:
return (ISC_R_TLSERROR);
default:
return (ISC_R_UNEXPECTED);
}
}
static void
tls_do_bio(isc_nmsocket_t *sock);
tls_do_bio(isc_nmsocket_t *sock, isc__nm_uvreq_t *send_data, bool finish);
static void
tls_close_direct(isc_nmsocket_t *sock);
@ -67,6 +69,8 @@ static bool
inactive(isc_nmsocket_t *sock) {
return (!isc__nmsocket_active(sock) || atomic_load(&sock->closing) ||
sock->outerhandle == NULL ||
!isc__nmsocket_active(sock->outerhandle->sock) ||
atomic_load(&sock->outerhandle->sock->closing) ||
(sock->listener != NULL &&
!isc__nmsocket_active(sock->listener)) ||
atomic_load(&sock->mgr->closing));
@ -74,17 +78,34 @@ inactive(isc_nmsocket_t *sock) {
static void
update_result(isc_nmsocket_t *sock, const isc_result_t result) {
if (!atomic_load(&sock->tlsstream.result_updated)) {
atomic_store(&sock->tlsstream.result_updated, true);
if (!sock->tlsstream.server) {
LOCK(&sock->lock);
sock->result = result;
SIGNAL(&sock->cond);
if (!atomic_load(&sock->active)) {
while (!atomic_load(&sock->active)) {
WAIT(&sock->scond, &sock->lock);
}
UNLOCK(&sock->lock);
if (sock->parent) {
LOCK(&sock->parent->lock);
sock->parent->result = result;
UNLOCK(&sock->parent->lock);
} else {
LOCK(&sock->lock);
sock->result = result;
UNLOCK(&sock->lock);
}
}
}
static void
tls_call_connect_cb(isc_nmsocket_t *sock, isc_nmhandle_t *handle,
const isc_result_t result) {
if (sock->connect_cb == NULL) {
return;
}
sock->connect_cb(handle, result, sock->connect_cbarg);
update_result(sock, result);
if (result != ISC_R_SUCCESS) {
isc__nmsocket_clearcb(handle->sock);
}
}
@ -92,26 +113,38 @@ static void
tls_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) {
isc_nmsocket_tls_send_req_t *send_req =
(isc_nmsocket_tls_send_req_t *)cbarg;
isc_nmsocket_t *sock = send_req->tlssock;
isc_nmsocket_t *tlssock = NULL;
bool finish = send_req->finish;
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(VALID_NMSOCK(handle->sock));
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(VALID_NMSOCK(send_req->tlssock));
/* XXXWPK TODO */
UNUSED(eresult);
tlssock = send_req->tlssock;
send_req->tlssock = NULL;
if (send_req->cb != NULL) {
send_req->cb(send_req->handle, eresult, send_req->cbarg);
isc_nmhandle_detach(&send_req->handle);
}
isc_mem_put(handle->sock->mgr->mctx, send_req->data.base,
send_req->data.length);
isc_mem_put(handle->sock->mgr->mctx, send_req, sizeof(*send_req));
tlssock->tlsstream.nsending--;
sock->tlsstream.nsending--;
async_tls_do_bio(sock);
isc__nmsocket_detach(&sock);
if (finish && eresult == ISC_R_SUCCESS) {
isc_nm_cancelread(handle);
} else if (eresult == ISC_R_SUCCESS) {
tls_do_bio(tlssock, NULL, false);
}
isc__nmsocket_detach(&tlssock);
}
static void
tls_failed_read_cb(isc_nmsocket_t *sock, isc_nmhandle_t *handle,
const isc_result_t result, const bool close) {
const isc_result_t result) {
REQUIRE(VALID_NMSOCK(sock));
if (!sock->tlsstream.server &&
@ -121,9 +154,7 @@ tls_failed_read_cb(isc_nmsocket_t *sock, isc_nmhandle_t *handle,
{
INSIST(handle == NULL);
handle = isc__nmhandle_get(sock, NULL, NULL);
sock->connect_cb(handle, result, sock->connect_cbarg);
update_result(sock, result);
isc__nmsocket_clearcb(sock);
tls_call_connect_cb(sock, handle, result);
isc_nmhandle_detach(&handle);
} else if (sock->recv_cb != NULL) {
isc__nm_uvreq_t *req = NULL;
@ -131,7 +162,7 @@ tls_failed_read_cb(isc_nmsocket_t *sock, isc_nmhandle_t *handle,
req->cb.recv = sock->recv_cb;
req->cbarg = sock->recv_cbarg;
req->handle = NULL;
if (handle) {
if (handle != NULL) {
REQUIRE(VALID_NMHANDLE(handle));
isc_nmhandle_attach(handle, &req->handle);
} else {
@ -140,11 +171,9 @@ tls_failed_read_cb(isc_nmsocket_t *sock, isc_nmhandle_t *handle,
isc__nmsocket_clearcb(sock);
isc__nm_readcb(sock, req, result);
}
sock->tlsstream.state = TLS_ERROR;
if (close) {
isc__nmsocket_prep_destroy(sock);
}
isc__nmsocket_detach(&sock);
}
static void
@ -155,12 +184,70 @@ async_tls_do_bio(isc_nmsocket_t *sock) {
(isc__netievent_t *)ievent);
}
static int
tls_send_outgoing(isc_nmsocket_t *sock, bool finish, isc_nmhandle_t *tlshandle,
isc_nm_cb_t cb, void *cbarg) {
isc_nmsocket_tls_send_req_t *send_req = NULL;
int pending;
int rv;
if (inactive(sock)) {
if (cb != NULL) {
INSIST(VALID_NMHANDLE(tlshandle));
cb(tlshandle, ISC_R_CANCELED, cbarg);
}
return (0);
}
if (finish && (SSL_get_shutdown(sock->tlsstream.tls) &
SSL_SENT_SHUTDOWN) != SSL_SENT_SHUTDOWN)
{
(void)SSL_shutdown(sock->tlsstream.tls);
}
pending = BIO_pending(sock->tlsstream.app_bio);
if (pending <= 0) {
return (pending);
}
/* TODO Should we keep track of these requests in a list? */
if (pending > TLS_BUF_SIZE) {
pending = TLS_BUF_SIZE;
}
send_req = isc_mem_get(sock->mgr->mctx, sizeof(*send_req));
*send_req = (isc_nmsocket_tls_send_req_t){
.finish = finish,
.data.base = isc_mem_get(sock->mgr->mctx, pending),
.data.length = pending
};
isc__nmsocket_attach(sock, &send_req->tlssock);
if (cb != NULL) {
send_req->cb = cb;
send_req->cbarg = cbarg;
isc_nmhandle_attach(tlshandle, &send_req->handle);
}
rv = BIO_read(sock->tlsstream.app_bio, send_req->data.base, pending);
/* There's something pending, read must succeed */
RUNTIME_CHECK(rv == pending);
INSIST(VALID_NMHANDLE(sock->outerhandle));
sock->tlsstream.nsending++;
isc_nm_send(sock->outerhandle, &send_req->data, tls_senddone, send_req);
return (pending);
}
static void
tls_do_bio(isc_nmsocket_t *sock) {
tls_do_bio(isc_nmsocket_t *sock, isc__nm_uvreq_t *send_data, bool finish) {
isc_result_t result = ISC_R_SUCCESS;
int pending, tls_err = 0;
int rv;
isc__nm_uvreq_t *req;
char buf[1];
bool sent_shutdown, received_shutdown;
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_nm_tid());
@ -172,79 +259,91 @@ tls_do_bio(isc_nmsocket_t *sock) {
}
if (sock->tlsstream.state == TLS_INIT) {
(void)SSL_do_handshake(sock->tlsstream.ssl);
(void)SSL_do_handshake(sock->tlsstream.tls);
sock->tlsstream.state = TLS_HANDSHAKE;
} else if (sock->tlsstream.state == TLS_ERROR) {
result = ISC_R_FAILURE;
goto low_level_error;
} else if (sock->tlsstream.state == TLS_CLOSED) {
return;
}
received_shutdown = (SSL_get_shutdown(sock->tlsstream.tls) &
SSL_RECEIVED_SHUTDOWN) == SSL_RECEIVED_SHUTDOWN;
/* Data from TLS to client */
char buf[1];
if (sock->tlsstream.state == TLS_IO && sock->recv_cb != NULL &&
if (sock->tlsstream.state >= TLS_IO && sock->recv_cb != NULL &&
!atomic_load(&sock->readpaused))
{
(void)SSL_peek(sock->tlsstream.ssl, buf, 1);
while ((pending = SSL_pending(sock->tlsstream.ssl)) > 0) {
(void)SSL_peek(sock->tlsstream.tls, buf, 1);
while ((pending = SSL_pending(sock->tlsstream.tls)) > 0) {
uint8_t recv_buf[TLS_BUF_SIZE];
isc_region_t region, dregion;
if (pending > TLS_BUF_SIZE) {
pending = TLS_BUF_SIZE;
}
isc_region_t region = {
isc_mem_get(sock->mgr->mctx, pending), pending
};
isc_region_t dregion;
memset(region.base, 0, region.length);
rv = SSL_read(sock->tlsstream.ssl, region.base,
region = (isc_region_t){ .base = &recv_buf[0],
.length = pending };
rv = SSL_read(sock->tlsstream.tls, region.base,
region.length);
/* Pending succeded, so should read */
RUNTIME_CHECK(rv == pending);
dregion = (isc_region_t){ region.base, rv };
sock->recv_cb(sock->statichandle, ISC_R_SUCCESS,
&dregion, sock->recv_cbarg);
isc_mem_put(sock->mgr->mctx, region.base,
region.length);
}
}
if (send_data != NULL) {
INSIST(sock->tlsstream.state > TLS_HANDSHAKE);
rv = SSL_write(sock->tlsstream.tls, send_data->uvbuf.base,
send_data->uvbuf.len);
if (rv != (int)send_data->uvbuf.len) {
result = received_shutdown ? ISC_R_CANCELED
: ISC_R_TLSERROR;
send_data->cb.send(send_data->handle, result,
send_data->cbarg);
send_data = NULL;
if (!received_shutdown) {
isc__nmsocket_detach(&sock);
return;
}
}
}
sent_shutdown = (SSL_get_shutdown(sock->tlsstream.tls) &
SSL_SENT_SHUTDOWN) == SSL_SENT_SHUTDOWN;
/* Peek to move the session forward */
(void)SSL_peek(sock->tlsstream.ssl, buf, 1);
(void)SSL_peek(sock->tlsstream.tls, buf, 1);
/* Data from TLS to network */
pending = BIO_pending(sock->tlsstream.app_bio);
if (pending > 0) {
/*TODO Should we keep the track of these requests in a list? */
isc_nmsocket_tls_send_req_t *send_req = NULL;
if (pending > TLS_BUF_SIZE) {
pending = TLS_BUF_SIZE;
if (send_data != NULL) {
pending = tls_send_outgoing(sock, finish, send_data->handle,
send_data->cb.send,
send_data->cbarg);
} else {
if (received_shutdown && !sent_shutdown) {
finish = true;
(void)SSL_shutdown(sock->tlsstream.tls);
}
send_req = isc_mem_get(sock->mgr->mctx, sizeof(*send_req));
send_req->data.base = isc_mem_get(sock->mgr->mctx, pending);
send_req->data.length = pending;
send_req->tlssock = NULL;
isc__nmsocket_attach(sock, &send_req->tlssock);
rv = BIO_read(sock->tlsstream.app_bio, send_req->data.base,
pending);
/* There's something pending, read must succeed */
RUNTIME_CHECK(rv == pending);
INSIST(VALID_NMHANDLE(sock->outerhandle));
isc_nm_send(sock->outerhandle, &send_req->data, tls_senddone,
send_req);
pending = tls_send_outgoing(sock, finish, NULL, NULL, NULL);
}
if (pending > 0) {
/* We'll continue in tls_senddone */
return;
}
/* Get the potential error code */
rv = SSL_peek(sock->tlsstream.ssl, buf, 1);
rv = SSL_peek(sock->tlsstream.tls, buf, 1);
if (rv < 0) {
tls_err = SSL_get_error(sock->tlsstream.ssl, rv);
tls_err = SSL_get_error(sock->tlsstream.tls, rv);
}
/* Only after doing the IO we can check if SSL handshake is done */
if (sock->tlsstream.state == TLS_HANDSHAKE &&
SSL_is_init_finished(sock->tlsstream.ssl) == 1)
SSL_is_init_finished(sock->tlsstream.tls) == 1)
{
isc_nmhandle_t *tlshandle = isc__nmhandle_get(sock, NULL, NULL);
if (sock->tlsstream.server) {
@ -252,9 +351,7 @@ tls_do_bio(isc_nmsocket_t *sock) {
ISC_R_SUCCESS,
sock->listener->accept_cbarg);
} else {
sock->connect_cb(tlshandle, ISC_R_SUCCESS,
sock->connect_cbarg);
update_result(tlshandle->sock, ISC_R_SUCCESS);
tls_call_connect_cb(sock, tlshandle, ISC_R_SUCCESS);
}
isc_nmhandle_detach(&tlshandle);
sock->tlsstream.state = TLS_IO;
@ -263,8 +360,14 @@ tls_do_bio(isc_nmsocket_t *sock) {
}
switch (tls_err) {
case 0:
case SSL_ERROR_NONE:
if (sent_shutdown && received_shutdown) {
/* clean shutdown */
isc_nm_cancelread(sock->outerhandle);
isc__nm_tls_close(sock);
};
return;
break;
case SSL_ERROR_WANT_WRITE:
if (sock->tlsstream.nsending == 0) {
/*
@ -272,83 +375,30 @@ tls_do_bio(isc_nmsocket_t *sock) {
* already the send callback will call it.
*/
async_tls_do_bio(sock);
return;
} else {
return;
}
break;
case SSL_ERROR_WANT_READ:
if (sock->outerhandle != NULL) {
INSIST(VALID_NMHANDLE(sock->outerhandle));
isc_nm_resumeread(sock->outerhandle);
}
return;
break;
default:
result = tls_error_to_result(tls_err);
goto error;
}
while ((req = ISC_LIST_HEAD(sock->tlsstream.sends)) != NULL) {
INSIST(VALID_UVREQ(req));
rv = SSL_write(sock->tlsstream.ssl, req->uvbuf.base,
req->uvbuf.len);
if (rv < 0) {
if (sock->tlsstream.nsending == 0) {
async_tls_do_bio(sock);
}
return;
}
if (rv != (int)req->uvbuf.len) {
if (!sock->tlsstream.server &&
(sock->tlsstream.state == TLS_HANDSHAKE ||
TLS_INIT))
{
isc_nmhandle_t *tlshandle =
isc__nmhandle_get(sock, NULL, NULL);
sock->connect_cb(tlshandle, result,
sock->connect_cbarg);
update_result(tlshandle->sock, result);
isc_nmhandle_detach(&tlshandle);
}
sock->tlsstream.state = TLS_ERROR;
async_tls_do_bio(sock);
return;
}
ISC_LIST_UNLINK(sock->tlsstream.sends, req, link);
req->cb.send(sock->statichandle, ISC_R_SUCCESS, req->cbarg);
isc__nm_uvreq_put(&req, sock);
}
return;
error:
isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_NETMGR,
ISC_LOG_ERROR, "SSL error in BIO: %d %s", tls_err,
isc_result_totext(result));
low_level_error:
if (sock->tlsstream.state == TLS_HANDSHAKE) {
isc_nmhandle_t *tlshandle = isc__nmhandle_get(sock, NULL, NULL);
if (!sock->tlsstream.server) {
sock->connect_cb(tlshandle, result,
sock->connect_cbarg);
update_result(tlshandle->sock, result);
}
isc_nmhandle_detach(&tlshandle);
} else if (sock->tlsstream.state == TLS_IO) {
if (ISC_LIST_HEAD(sock->tlsstream.sends) != NULL) {
while ((req = ISC_LIST_HEAD(sock->tlsstream.sends)) !=
NULL) {
req->cb.send(sock->statichandle, result,
req->cbarg);
ISC_LIST_UNLINK(sock->tlsstream.sends, req,
link);
isc__nm_uvreq_put(&req, sock);
}
} else if (sock->recv_cb != NULL) {
tls_failed_read_cb(sock, sock->statichandle, result,
false);
} else {
tls_close_direct(sock);
}
}
sock->tlsstream.state = TLS_ERROR;
tls_failed_read_cb(sock, sock->statichandle, result);
}
static void
@ -360,19 +410,20 @@ tls_readcb(isc_nmhandle_t *handle, isc_result_t result, isc_region_t *region,
REQUIRE(VALID_NMSOCK(tlssock));
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(tlssock->tid == isc_nm_tid());
if (result != ISC_R_SUCCESS) {
tls_failed_read_cb(tlssock, tlssock->statichandle, result,
true);
tls_failed_read_cb(tlssock, tlssock->statichandle, result);
return;
}
rv = BIO_write(tlssock->tlsstream.app_bio, region->base,
region->length);
if (rv != (int)region->length) {
/* XXXWPK log it? */
tlssock->tlsstream.state = TLS_ERROR;
tls_failed_read_cb(tlssock, tlssock->statichandle,
ISC_R_TLSERROR);
return;
}
tls_do_bio(tlssock);
tls_do_bio(tlssock, NULL, false);
}
static isc_result_t
@ -382,20 +433,20 @@ initialize_tls(isc_nmsocket_t *sock, bool server) {
if (BIO_new_bio_pair(&(sock->tlsstream.ssl_bio), TLS_BUF_SIZE,
&(sock->tlsstream.app_bio), TLS_BUF_SIZE) != 1)
{
SSL_free(sock->tlsstream.ssl);
isc_tls_free(&sock->tlsstream.tls);
return (ISC_R_TLSERROR);
}
SSL_set_bio(sock->tlsstream.ssl, sock->tlsstream.ssl_bio,
SSL_set_bio(sock->tlsstream.tls, sock->tlsstream.ssl_bio,
sock->tlsstream.ssl_bio);
if (server) {
SSL_set_accept_state(sock->tlsstream.ssl);
SSL_set_accept_state(sock->tlsstream.tls);
} else {
SSL_set_connect_state(sock->tlsstream.ssl);
SSL_set_connect_state(sock->tlsstream.tls);
}
sock->tlsstream.nsending = 0;
isc_nm_read(sock->outerhandle, tls_readcb, sock);
tls_do_bio(sock);
tls_do_bio(sock, NULL, false);
return (ISC_R_SUCCESS);
}
@ -403,7 +454,6 @@ static isc_result_t
tlslisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
isc_nmsocket_t *tlslistensock = (isc_nmsocket_t *)cbarg;
isc_nmsocket_t *tlssock = NULL;
int r;
/* If accept() was unsuccessful we can't do anything */
if (result != ISC_R_SUCCESS) {
@ -420,14 +470,12 @@ tlslisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
*/
tlssock = isc_mem_get(handle->sock->mgr->mctx, sizeof(*tlssock));
isc__nmsocket_init(tlssock, handle->sock->mgr, isc_nm_tlssocket,
handle->sock->iface);
&tlslistensock->tlsstream.server_iface);
/* We need to initialize SSL now to reference SSL_CTX properly */
tlssock->tlsstream.ctx = tlslistensock->tlsstream.ctx;
tlssock->tlsstream.ssl = SSL_new(tlssock->tlsstream.ctx);
ISC_LIST_INIT(tlssock->tlsstream.sends);
if (tlssock->tlsstream.ssl == NULL) {
update_result(tlssock, ISC_R_TLSERROR);
tlssock->tlsstream.tls = isc_tls_create(tlssock->tlsstream.ctx);
if (tlssock->tlsstream.tls == NULL) {
atomic_store(&tlssock->closed, true);
isc__nmsocket_detach(&tlssock);
return (ISC_R_TLSERROR);
@ -442,12 +490,6 @@ tlslisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
tlssock->tlsstream.server = true;
tlssock->tlsstream.state = TLS_INIT;
r = uv_timer_init(&tlssock->mgr->workers[isc_nm_tid()].loop,
&tlssock->timer);
RUNTIME_CHECK(r == 0);
tlssock->timer.data = tlssock;
tlssock->timer_initialized = true;
tlssock->tlsstream.ctx = tlslistensock->tlsstream.ctx;
result = initialize_tls(tlssock, true);
@ -469,12 +511,15 @@ isc_nm_listentls(isc_nm_t *mgr, isc_nmiface_t *iface,
REQUIRE(VALID_NM(mgr));
isc__nmsocket_init(tlssock, mgr, isc_nm_tlslistener, iface);
tlssock->tlsstream.server_iface = *iface;
ISC_LINK_INIT(&tlssock->tlsstream.server_iface.addr, link);
tlssock->iface = &tlssock->tlsstream.server_iface;
tlssock->result = ISC_R_DEFAULT;
tlssock->accept_cb = accept_cb;
tlssock->accept_cbarg = accept_cbarg;
tlssock->extrahandlesize = extrahandlesize;
tlssock->tlsstream.ctx = sslctx;
tlssock->tlsstream.ssl = NULL;
tlssock->tlsstream.tls = NULL;
/*
* tlssock will be a TLS 'wrapper' around an unencrypted stream.
@ -515,46 +560,25 @@ isc_nm_listentls(isc_nm_t *mgr, isc_nmiface_t *iface,
void
isc__nm_async_tlssend(isc__networker_t *worker, isc__netievent_t *ev0) {
int rv;
isc__netievent_tlssend_t *ievent = (isc__netievent_tlssend_t *)ev0;
isc_nmsocket_t *sock = ievent->sock;
isc__nm_uvreq_t *req = ievent->req;
ievent->req = NULL;
REQUIRE(VALID_UVREQ(req));
REQUIRE(sock->tid == isc_nm_tid());
UNUSED(worker);
ievent->req = NULL;
if (inactive(sock)) {
req->cb.send(req->handle, ISC_R_CANCELED, req->cbarg);
isc__nm_uvreq_put(&req, sock);
return;
}
if (!ISC_LIST_EMPTY(sock->tlsstream.sends)) {
/* We're not the first */
ISC_LIST_APPEND(sock->tlsstream.sends, req, link);
tls_do_bio(sock);
return;
}
rv = SSL_write(sock->tlsstream.ssl, req->uvbuf.base, req->uvbuf.len);
if (rv < 0) {
/*
* We might need to read, we might need to write, or the
* TLS socket might be dead - in any case, we need to
* enqueue the uvreq and let the TLS BIO layer do the rest.
*/
ISC_LIST_APPEND(sock->tlsstream.sends, req, link);
tls_do_bio(sock);
return;
}
if (rv != (int)req->uvbuf.len) {
sock->tlsstream.state = TLS_ERROR;
async_tls_do_bio(sock);
return;
}
req->cb.send(sock->statichandle, ISC_R_SUCCESS, req->cbarg);
tls_do_bio(sock, req, false);
isc__nm_uvreq_put(&req, sock);
tls_do_bio(sock);
return;
}
@ -600,20 +624,24 @@ isc__nm_async_tlsstartread(isc__networker_t *worker, isc__netievent_t *ev0) {
isc_nmsocket_t *sock = ievent->sock;
REQUIRE(sock->tid == isc_nm_tid());
UNUSED(worker);
tls_do_bio(sock);
tls_do_bio(sock, NULL, false);
}
void
isc__nm_tls_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(VALID_NMSOCK(handle->sock));
REQUIRE(handle->sock->statichandle == handle);
REQUIRE(handle->sock->tid == isc_nm_tid());
isc__netievent_tlsstartread_t *ievent = NULL;
isc_nmsocket_t *sock = handle->sock;
isc_nmsocket_t *sock = NULL;
REQUIRE(VALID_NMHANDLE(handle));
sock = handle->sock;
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->statichandle == handle);
REQUIRE(sock->tid == isc_nm_tid());
if (inactive(sock)) {
cb(handle, ISC_R_NOTCONNECTED, NULL, cbarg);
@ -632,56 +660,26 @@ void
isc__nm_tls_pauseread(isc_nmhandle_t *handle) {
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(VALID_NMSOCK(handle->sock));
isc_nmsocket_t *sock = handle->sock;
atomic_store(&sock->readpaused, true);
atomic_store(&handle->sock->readpaused, true);
if (handle->sock->outerhandle != NULL) {
isc_nm_pauseread(handle->sock->outerhandle);
}
}
void
isc__nm_tls_resumeread(isc_nmhandle_t *handle) {
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(VALID_NMSOCK(handle->sock));
isc_nmsocket_t *sock = handle->sock;
atomic_store(&sock->readpaused, false);
async_tls_do_bio(sock);
}
static void
timer_close_cb(uv_handle_t *handle) {
isc_nmsocket_t *sock = (isc_nmsocket_t *)uv_handle_get_data(handle);
tls_close_direct(sock);
atomic_store(&handle->sock->readpaused, false);
async_tls_do_bio(handle->sock);
}
static void
tls_close_direct(isc_nmsocket_t *sock) {
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_nm_tid());
/* if (!sock->tlsstream.server) { */
/* INSIST(sock->tlsstream.state != TLS_HANDSHAKE && */
/* sock->tlsstream.state != TLS_INIT); */
/* } */
sock->tlsstream.state = TLS_CLOSING;
if (sock->timer_running) {
uv_timer_stop(&sock->timer);
sock->timer_running = false;
}
/* We don't need atomics here, it's all in single network thread
*/
if (sock->timer_initialized) {
/*
* We need to fire the timer callback to clean it up,
* it will then call us again (via detach) so that we
* can finally close the socket.
*/
sock->timer_initialized = false;
uv_timer_stop(&sock->timer);
uv_close((uv_handle_t *)&sock->timer, timer_close_cb);
} else {
/*
* At this point we're certain that there are no
* external references, we can close everything.
@ -690,28 +688,21 @@ tls_close_direct(isc_nmsocket_t *sock) {
isc_nm_pauseread(sock->outerhandle);
isc_nmhandle_detach(&sock->outerhandle);
}
if (sock->listener != NULL) {
isc__nmsocket_detach(&sock->listener);
}
if (sock->tlsstream.ssl != NULL) {
SSL_free(sock->tlsstream.ssl);
sock->tlsstream.ssl = NULL;
/* These are destroyed when we free SSL* */
sock->tlsstream.ctx = NULL;
sock->tlsstream.ssl_bio = NULL;
}
if (sock->tlsstream.app_bio != NULL) {
BIO_free(sock->tlsstream.app_bio);
sock->tlsstream.app_bio = NULL;
}
sock->tlsstream.state = TLS_CLOSED;
/* further cleanup performed in isc__nm_tls_cleanup_data() */
atomic_store(&sock->active, false);
atomic_store(&sock->closed, true);
isc__nmsocket_detach(&sock);
}
sock->tlsstream.state = TLS_CLOSED;
}
void
isc__nm_tls_close(isc_nmsocket_t *sock) {
isc__netievent_tlsclose_t *ievent = NULL;
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->type == isc_nm_tlssocket);
@ -720,24 +711,21 @@ isc__nm_tls_close(isc_nmsocket_t *sock) {
return;
}
if (sock->tid == isc_nm_tid()) {
tls_close_direct(sock);
} else {
isc__netievent_tlsclose_t *ievent =
isc__nm_get_netievent_tlsclose(sock->mgr, sock);
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
ievent = isc__nm_get_netievent_tlsclose(sock->mgr, sock);
isc__nm_maybe_enqueue_ievent(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
}
}
void
isc__nm_async_tlsclose(isc__networker_t *worker, isc__netievent_t *ev0) {
isc__netievent_tlsclose_t *ievent = (isc__netievent_tlsclose_t *)ev0;
isc_nmsocket_t *sock = ievent->sock;
REQUIRE(ievent->sock->tid == isc_nm_tid());
UNUSED(worker);
tls_close_direct(ievent->sock);
tls_close_direct(sock);
}
void
@ -749,9 +737,8 @@ isc__nm_tls_stoplistening(isc_nmsocket_t *sock) {
atomic_store(&sock->closed, true);
sock->recv_cb = NULL;
sock->recv_cbarg = NULL;
if (sock->tlsstream.ssl != NULL) {
SSL_free(sock->tlsstream.ssl);
sock->tlsstream.ssl = NULL;
if (sock->tlsstream.tls != NULL) {
isc_tls_free(&sock->tlsstream.tls);
sock->tlsstream.ctx = NULL;
}
@ -768,17 +755,25 @@ isc_nm_tlsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
isc_nmsocket_t *nsock = NULL, *tsock = NULL;
isc__netievent_tlsconnect_t *ievent = NULL;
isc_result_t result = ISC_R_DEFAULT;
#if defined(NETMGR_TRACE) && defined(NETMGR_TRACE_VERBOSE)
fprintf(stderr, "TLS: isc_nm_tlsconnect(): in net thread: %s\n",
isc__nm_in_netthread() ? "yes" : "no");
#endif /* NETMGR_TRACE */
REQUIRE(VALID_NM(mgr));
nsock = isc_mem_get(mgr->mctx, sizeof(*nsock));
isc__nmsocket_init(nsock, mgr, isc_nm_tlssocket, local);
nsock->tlsstream.local_iface = *local;
ISC_LINK_INIT(&nsock->tlsstream.local_iface.addr, link);
nsock->iface = &nsock->tlsstream.local_iface;
nsock->extrahandlesize = extrahandlesize;
nsock->result = ISC_R_DEFAULT;
nsock->connect_cb = cb;
nsock->connect_cbarg = cbarg;
nsock->connect_timeout = timeout;
nsock->tlsstream.ctx = ctx;
nsock->tlsstream.connect_from_networker = isc__nm_in_netthread();
ievent = isc__nm_get_netievent_tlsconnect(mgr, nsock);
ievent->local = local->addr;
@ -815,29 +810,31 @@ isc_nm_tlsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
}
static void
tls_connect_cb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
tcp_connected(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
isc_nmsocket_t *tlssock = (isc_nmsocket_t *)cbarg;
isc_nmhandle_t *tlshandle = NULL;
REQUIRE(VALID_NMSOCK(tlssock));
REQUIRE(VALID_NMHANDLE(handle));
if (result != ISC_R_SUCCESS) {
tlssock->connect_cb(handle, result, tlssock->connect_cbarg);
update_result(tlssock, result);
tls_close_direct(tlssock);
return;
goto error;
}
INSIST(VALID_NMHANDLE(handle));
tlssock->peer = isc_nmhandle_peeraddr(handle);
isc_nmhandle_attach(handle, &tlssock->outerhandle);
result = initialize_tls(tlssock, false);
if (result != ISC_R_SUCCESS) {
tlssock->connect_cb(handle, result, tlssock->connect_cbarg);
update_result(tlssock, result);
tls_close_direct(tlssock);
return;
goto error;
}
return;
error:
tlshandle = isc__nmhandle_get(tlssock, NULL, NULL);
atomic_store(&tlssock->closed, true);
tls_call_connect_cb(tlssock, tlshandle, result);
isc_nmhandle_detach(&tlshandle);
isc__nmsocket_detach(&tlssock);
}
void
@ -846,7 +843,6 @@ isc__nm_async_tlsconnect(isc__networker_t *worker, isc__netievent_t *ev0) {
(isc__netievent_tlsconnect_t *)ev0;
isc_nmsocket_t *tlssock = ievent->sock;
isc_result_t result;
int r;
isc_nmhandle_t *tlshandle = NULL;
UNUSED(worker);
@ -854,36 +850,39 @@ isc__nm_async_tlsconnect(isc__networker_t *worker, isc__netievent_t *ev0) {
/*
* We need to initialize SSL now to reference SSL_CTX properly.
*/
tlssock->tlsstream.ssl = SSL_new(tlssock->tlsstream.ctx);
if (tlssock->tlsstream.ssl == NULL) {
tlssock->tlsstream.tls = isc_tls_create(tlssock->tlsstream.ctx);
if (tlssock->tlsstream.tls == NULL) {
result = ISC_R_TLSERROR;
goto error;
}
tlssock->tid = isc_nm_tid();
r = uv_timer_init(&tlssock->mgr->workers[isc_nm_tid()].loop,
&tlssock->timer);
RUNTIME_CHECK(r == 0);
tlssock->timer.data = tlssock;
tlssock->timer_initialized = true;
tlssock->tlsstream.state = TLS_INIT;
result = isc_nm_tcpconnect(worker->mgr, (isc_nmiface_t *)&ievent->local,
(isc_nmiface_t *)&ievent->peer,
tls_connect_cb, tlssock,
tcp_connected, tlssock,
tlssock->connect_timeout, 0);
if (result != ISC_R_SUCCESS) {
goto error;
if (tlssock->tlsstream.connect_from_networker) {
update_result(tlssock, result);
}
return;
error:
tlshandle = isc__nmhandle_get(tlssock, NULL, NULL);
atomic_store(&tlssock->closed, true);
tlssock->connect_cb(tlshandle, result, tlssock->connect_cbarg);
tls_call_connect_cb(tlssock, tlshandle, result);
isc_nmhandle_detach(&tlshandle);
update_result(tlssock, result);
tls_close_direct(tlssock);
isc__nmsocket_detach(&tlssock);
}
static void
tls_cancelread(isc_nmsocket_t *sock) {
if (!inactive(sock) && sock->tlsstream.state == TLS_IO) {
tls_do_bio(sock, NULL, true);
} else if (sock->outerhandle != NULL) {
isc_nm_cancelread(sock->outerhandle);
}
}
void
@ -897,40 +896,69 @@ isc__nm_tls_cancelread(isc_nmhandle_t *handle) {
REQUIRE(sock->type == isc_nm_tlssocket);
ievent = isc__nm_get_netievent_tlscancel(sock->mgr, sock, handle);
if (sock->tid == isc_nm_tid()) {
tls_cancelread(sock);
} else {
ievent = isc__nm_get_netievent_tlscancel(sock->mgr, sock,
handle);
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
}
}
void
isc__nm_async_tlscancel(isc__networker_t *worker, isc__netievent_t *ev0) {
isc__netievent_tlscancel_t *ievent = (isc__netievent_tlscancel_t *)ev0;
isc_nmsocket_t *sock = ievent->sock;
isc_nmhandle_t *handle = ievent->handle;
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(worker->id == sock->tid);
REQUIRE(sock->tid == isc_nm_tid());
UNUSED(worker);
tls_failed_read_cb(sock, handle, ISC_R_EOF, false);
if (sock->outerhandle) {
isc__nm_tcp_cancelread(sock->outerhandle);
}
tls_cancelread(sock);
}
void
isc__nm_async_tlsdobio(isc__networker_t *worker, isc__netievent_t *ev0) {
UNUSED(worker);
isc__netievent_tlsdobio_t *ievent = (isc__netievent_tlsdobio_t *)ev0;
tls_do_bio(ievent->sock);
UNUSED(worker);
tls_do_bio(ievent->sock, NULL, false);
}
void
isc__nm_tls_cleanup_data(isc_nmsocket_t *sock) {
if (sock->tlsstream.tlslistener) {
if (sock->type == isc_nm_tcplistener &&
sock->tlsstream.tlslistener != NULL) {
REQUIRE(VALID_NMSOCK(sock->tlsstream.tlslistener));
isc__nmsocket_detach(&sock->tlsstream.tlslistener);
} else if (sock->type == isc_nm_tlssocket) {
if (sock->tlsstream.tls != NULL) {
isc_tls_free(&sock->tlsstream.tls);
/* These are destroyed when we free SSL */
sock->tlsstream.ctx = NULL;
sock->tlsstream.ssl_bio = NULL;
}
if (sock->tlsstream.app_bio != NULL) {
BIO_free(sock->tlsstream.app_bio);
sock->tlsstream.app_bio = NULL;
}
}
}
void
isc__nm_tls_settimeout(isc_nmhandle_t *handle, uint32_t timeout) {
isc_nmsocket_t *sock = NULL;
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(VALID_NMSOCK(handle->sock));
REQUIRE(handle->sock->type == isc_nm_tlssocket);
sock = handle->sock;
if (sock->outerhandle != NULL) {
INSIST(VALID_NMHANDLE(sock->outerhandle));
isc_nmhandle_settimeout(sock->outerhandle, timeout);
}
}

View File

@ -102,10 +102,10 @@ static const char *description[ISC_R_NRESULTS] = {
"default", /*%< 68 */
"IPv4 prefix", /*%< 69 */
"TLS error", /*%< 70 */
"ALPN for HTTP/2 failed" /*%< 71 */
};
static const char *identifier[ISC_R_NRESULTS] = {
"ISC_R_SUCCESS",
static const char *identifier[ISC_R_NRESULTS] = { "ISC_R_SUCCESS",
"ISC_R_NOMEMORY",
"ISC_R_TIMEDOUT",
"ISC_R_NOTHREADS",
@ -176,7 +176,7 @@ static const char *identifier[ISC_R_NRESULTS] = {
"ISC_R_DEFAULT",
"ISC_R_IPV4PREFIX",
"ISC_R_TLSERROR",
};
"ISC_R_HTTP2ALPNERROR" };
#define ISC_RESULT_RESULTSET 2
#define ISC_RESULT_UNAVAILABLESET 3

View File

@ -72,7 +72,8 @@ static bool reuse_supported = true;
static atomic_bool POST = ATOMIC_VAR_INIT(true);
static atomic_bool use_TLS = ATOMIC_VAR_INIT(false);
static SSL_CTX *server_ssl_ctx = NULL;
static isc_tlsctx_t *server_tlsctx = NULL;
static isc_tlsctx_t *client_tlsctx = NULL;
#define NSENDS 100
#define NWRITES 10
@ -101,6 +102,63 @@ static SSL_CTX *server_ssl_ctx = NULL;
#define X(v)
#endif
typedef struct csdata {
isc_nm_recv_cb_t reply_cb;
void *cb_arg;
isc_region_t region;
} csdata_t;
static void
connect_send_cb(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
csdata_t data;
REQUIRE(VALID_NMHANDLE(handle));
memmove(&data, arg, sizeof(data));
isc_mem_put(handle->sock->mgr->mctx, arg, sizeof(data));
if (result != ISC_R_SUCCESS) {
goto error;
}
result = isc__nm_http_request(handle, &data.region, data.reply_cb,
data.cb_arg);
if (result != ISC_R_SUCCESS) {
goto error;
}
isc_mem_put(handle->sock->mgr->mctx, data.region.base,
data.region.length);
return;
error:
data.reply_cb(handle, result, NULL, data.cb_arg);
isc_mem_put(handle->sock->mgr->mctx, data.region.base,
data.region.length);
}
static isc_result_t
connect_send_request(isc_nm_t *mgr, const char *uri, bool post,
isc_region_t *region, isc_nm_recv_cb_t cb, void *cbarg,
bool tls, unsigned int timeout) {
isc_result_t result;
isc_region_t copy;
csdata_t *data = NULL;
isc_tlsctx_t *ctx = NULL;
copy = (isc_region_t){ .base = isc_mem_get(mgr->mctx, region->length),
.length = region->length };
memmove(copy.base, region->base, region->length);
data = isc_mem_get(mgr->mctx, sizeof(*data));
*data = (csdata_t){ .reply_cb = cb, .cb_arg = cbarg, .region = copy };
if (tls) {
ctx = client_tlsctx;
}
result = isc_nm_httpconnect(
mgr, NULL, (isc_nmiface_t *)&tcp_listen_addr, uri, post,
connect_send_cb, data, ctx, timeout, 0);
return (result);
}
static int
setup_ephemeral_port(isc_sockaddr_t *addr, sa_family_t family) {
isc_result_t result;
@ -171,7 +229,7 @@ static int
_setup(void **state) {
UNUSED(state);
/*workers = isc_os_ncpus();*/
workers = isc_os_ncpus();
if (isc_test_begin(NULL, false, workers) != ISC_R_SUCCESS) {
return (-1);
@ -243,8 +301,11 @@ nm_setup(void **state) {
assert_non_null(nm[i]);
}
server_ssl_ctx = NULL;
isc_tlsctx_createserver(NULL, NULL, &server_ssl_ctx);
server_tlsctx = NULL;
isc_tlsctx_createserver(NULL, NULL, &server_tlsctx);
client_tlsctx = NULL;
isc_tlsctx_createclient(&client_tlsctx);
isc_tlsctx_enable_http2client_alpn(client_tlsctx);
*state = nm;
@ -261,8 +322,11 @@ nm_teardown(void **state) {
}
isc_mem_put(test_mctx, nm, MAX_NM * sizeof(nm[0]));
if (server_ssl_ctx) {
isc_tlsctx_free(&server_ssl_ctx);
if (server_tlsctx != NULL) {
isc_tlsctx_free(&server_tlsctx);
}
if (client_tlsctx != NULL) {
isc_tlsctx_free(&client_tlsctx);
}
return (0);
@ -276,6 +340,7 @@ sockaddr_to_url(isc_sockaddr_t *sa, const bool https, char *outbuf,
uint16_t port;
char saddr[INET6_ADDRSTRLEN] = { 0 };
int family;
if (sa == NULL || outbuf == NULL || outbuf_len == 0) {
return;
}
@ -321,8 +386,6 @@ doh_receive_reply_cb(isc_nmhandle_t *handle, isc_result_t eresult,
}
}
atomic_store(&was_error, true);
/* Send failed, we need to stop reading too */
isc_nm_cancelread(handle);
}
}
@ -382,10 +445,6 @@ mock_doh_uv_tcp_bind(void **state) {
isc_nm_t *listen_nm = nm[0];
isc_result_t result = ISC_R_SUCCESS;
isc_nmsocket_t *listen_sock = NULL;
isc_sockaddr_t tcp_connect_addr;
tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
WILL_RETURN(uv_tcp_bind, UV_EADDRINUSE);
@ -404,17 +463,13 @@ doh_noop(void **state) {
isc_nm_t *connect_nm = nm[1];
isc_result_t result = ISC_R_SUCCESS;
isc_nmsocket_t *listen_sock = NULL;
isc_sockaddr_t tcp_connect_addr;
char req_url[256];
tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
result = isc_nm_listenhttp(listen_nm, (isc_nmiface_t *)&tcp_listen_addr,
0, NULL, NULL, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
result = isc_nm_http_add_doh_endpoint(listen_sock, DOH_PATH,
noop_read_cb, NULL, 0);
result = isc_nm_http_endpoint(listen_sock, DOH_PATH, noop_read_cb, NULL,
0);
isc_nm_stoplistening(listen_sock);
isc_nmsocket_close(&listen_sock);
@ -422,11 +477,11 @@ doh_noop(void **state) {
sockaddr_to_url(&tcp_listen_addr, false, req_url, sizeof(req_url),
DOH_PATH);
(void)isc_nm_http_connect_send_request(
(void)connect_send_request(
connect_nm, req_url, atomic_load(&POST),
&(isc_region_t){ .base = (uint8_t *)send_msg.base,
.length = send_msg.len },
noop_read_cb, NULL, NULL, 30000);
noop_read_cb, NULL, atomic_load(&use_TLS), 30000);
isc_nm_closedown(connect_nm);
@ -455,27 +510,23 @@ doh_noresponse(void **state) {
isc_nm_t *connect_nm = nm[1];
isc_result_t result = ISC_R_SUCCESS;
isc_nmsocket_t *listen_sock = NULL;
isc_sockaddr_t tcp_connect_addr;
char req_url[256];
tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
result = isc_nm_listenhttp(listen_nm, (isc_nmiface_t *)&tcp_listen_addr,
0, NULL, NULL, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
result = isc_nm_http_add_doh_endpoint(listen_sock, DOH_PATH,
noop_read_cb, NULL, 0);
result = isc_nm_http_endpoint(listen_sock, DOH_PATH, noop_read_cb, NULL,
0);
assert_int_equal(result, ISC_R_SUCCESS);
sockaddr_to_url(&tcp_listen_addr, false, req_url, sizeof(req_url),
DOH_PATH);
(void)isc_nm_http_connect_send_request(
(void)connect_send_request(
connect_nm, req_url, atomic_load(&POST),
&(isc_region_t){ .base = (uint8_t *)send_msg.base,
.length = send_msg.len },
noop_read_cb, NULL, NULL, 30000);
noop_read_cb, NULL, atomic_load(&use_TLS), 30000);
isc_nm_stoplistening(listen_sock);
isc_nmsocket_close(&listen_sock);
@ -509,7 +560,7 @@ doh_receive_send_reply_cb(isc_nmhandle_t *handle, isc_result_t eresult,
size_t i;
atomic_fetch_sub(&nsends, 1);
for (i = 0; i < NWRITES / 2; i++) {
eresult = isc_nm_httprequest(
eresult = isc__nm_http_request(
handle,
&(isc_region_t){
.base = (uint8_t *)send_msg.base,
@ -535,20 +586,18 @@ doh_receive_send_reply_cb(isc_nmhandle_t *handle, isc_result_t eresult,
static isc_threadresult_t
doh_connect_thread(isc_threadarg_t arg) {
isc_nm_t *connect_nm = (isc_nm_t *)arg;
isc_sockaddr_t tcp_connect_addr;
char req_url[256];
tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
sockaddr_to_url(&tcp_listen_addr, atomic_load(&use_TLS), req_url,
sizeof(req_url), DOH_PATH);
while (atomic_load(&nsends) > 0) {
(void)isc_nm_http_connect_send_request(
(void)connect_send_request(
connect_nm, req_url, atomic_load(&POST),
&(isc_region_t){ .base = (uint8_t *)send_msg.base,
.length = send_msg.len },
doh_receive_send_reply_cb, NULL, NULL, 5000);
doh_receive_send_reply_cb, NULL, atomic_load(&use_TLS),
30000);
}
return ((isc_threadresult_t)0);
@ -561,33 +610,26 @@ doh_recv_one(void **state) {
isc_nm_t *connect_nm = nm[1];
isc_result_t result = ISC_R_SUCCESS;
isc_nmsocket_t *listen_sock = NULL;
isc_sockaddr_t tcp_connect_addr;
char req_url[256];
tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
atomic_store(&nsends, 1);
tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
result = isc_nm_listenhttp(
listen_nm, (isc_nmiface_t *)&tcp_listen_addr, 0, NULL,
atomic_load(&use_TLS) ? server_ssl_ctx : NULL, &listen_sock);
atomic_load(&use_TLS) ? server_tlsctx : NULL, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
result = isc_nm_http_add_doh_endpoint(listen_sock, DOH_PATH,
result = isc_nm_http_endpoint(listen_sock, DOH_PATH,
doh_receive_request_cb, NULL, 0);
assert_int_equal(result, ISC_R_SUCCESS);
sockaddr_to_url(&tcp_listen_addr, atomic_load(&use_TLS), req_url,
sizeof(req_url), DOH_PATH);
result = isc_nm_http_connect_send_request(
result = connect_send_request(
connect_nm, req_url, atomic_load(&POST),
&(isc_region_t){ .base = (uint8_t *)send_msg.base,
.length = send_msg.len },
doh_receive_reply_cb, NULL, NULL, 5000);
doh_receive_reply_cb, NULL, atomic_load(&use_TLS), 30000);
assert_int_equal(result, ISC_R_SUCCESS);
@ -657,7 +699,7 @@ doh_connect_send_two_requests_cb(isc_nmhandle_t *handle, isc_result_t result,
goto error;
}
result = isc_nm_httprequest(
result = isc__nm_http_request(
handle,
&(isc_region_t){ .base = (uint8_t *)send_msg.base,
.length = send_msg.len },
@ -666,7 +708,7 @@ doh_connect_send_two_requests_cb(isc_nmhandle_t *handle, isc_result_t result,
goto error;
}
result = isc_nm_httprequest(
result = isc__nm_http_request(
handle,
&(isc_region_t){ .base = (uint8_t *)send_msg.base,
.length = send_msg.len },
@ -674,8 +716,6 @@ doh_connect_send_two_requests_cb(isc_nmhandle_t *handle, isc_result_t result,
if (result != ISC_R_SUCCESS) {
goto error;
}
isc_nm_resumeread(handle);
return;
error:
atomic_store(&was_error, true);
@ -688,31 +728,31 @@ doh_recv_two(void **state) {
isc_nm_t *connect_nm = nm[1];
isc_result_t result = ISC_R_SUCCESS;
isc_nmsocket_t *listen_sock = NULL;
isc_sockaddr_t tcp_connect_addr;
char req_url[256];
tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
isc_tlsctx_t *ctx = NULL;
atomic_store(&nsends, 2);
tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
result = isc_nm_listenhttp(
listen_nm, (isc_nmiface_t *)&tcp_listen_addr, 0, NULL,
atomic_load(&use_TLS) ? server_ssl_ctx : NULL, &listen_sock);
atomic_load(&use_TLS) ? server_tlsctx : NULL, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
result = isc_nm_http_add_doh_endpoint(listen_sock, DOH_PATH,
result = isc_nm_http_endpoint(listen_sock, DOH_PATH,
doh_receive_request_cb, NULL, 0);
assert_int_equal(result, ISC_R_SUCCESS);
sockaddr_to_url(&tcp_listen_addr, atomic_load(&use_TLS), req_url,
sizeof(req_url), DOH_PATH);
if (atomic_load(&use_TLS)) {
ctx = client_tlsctx;
}
result = isc_nm_httpconnect(
connect_nm, NULL, NULL, req_url, atomic_load(&POST),
doh_connect_send_two_requests_cb, NULL, NULL, 5000, 0);
connect_nm, NULL, (isc_nmiface_t *)&tcp_listen_addr, req_url,
atomic_load(&POST), doh_connect_send_two_requests_cb, NULL, ctx,
5000, 0);
assert_int_equal(result, ISC_R_SUCCESS);
@ -783,20 +823,13 @@ doh_recv_send(void **state) {
isc_nmsocket_t *listen_sock = NULL;
size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1);
isc_thread_t threads[32] = { 0 };
isc_sockaddr_t tcp_connect_addr;
tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
result = isc_nm_listenhttp(
listen_nm, (isc_nmiface_t *)&tcp_listen_addr, 0, NULL,
atomic_load(&use_TLS) ? server_ssl_ctx : NULL, &listen_sock);
atomic_load(&use_TLS) ? server_tlsctx : NULL, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
result = isc_nm_http_add_doh_endpoint(listen_sock, DOH_PATH,
result = isc_nm_http_endpoint(listen_sock, DOH_PATH,
doh_receive_request_cb, NULL, 0);
assert_int_equal(result, ISC_R_SUCCESS);
@ -859,20 +892,13 @@ doh_recv_half_send(void **state) {
isc_nmsocket_t *listen_sock = NULL;
size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1);
isc_thread_t threads[32] = { 0 };
isc_sockaddr_t tcp_connect_addr;
tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
result = isc_nm_listenhttp(
listen_nm, (isc_nmiface_t *)&tcp_listen_addr, 0, NULL,
atomic_load(&use_TLS) ? server_ssl_ctx : NULL, &listen_sock);
atomic_load(&use_TLS) ? server_tlsctx : NULL, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
result = isc_nm_http_add_doh_endpoint(listen_sock, DOH_PATH,
result = isc_nm_http_endpoint(listen_sock, DOH_PATH,
doh_receive_request_cb, NULL, 0);
assert_int_equal(result, ISC_R_SUCCESS);
@ -940,20 +966,13 @@ doh_half_recv_send(void **state) {
isc_nmsocket_t *listen_sock = NULL;
size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1);
isc_thread_t threads[32] = { 0 };
isc_sockaddr_t tcp_connect_addr;
tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
result = isc_nm_listenhttp(
listen_nm, (isc_nmiface_t *)&tcp_listen_addr, 0, NULL,
atomic_load(&use_TLS) ? server_ssl_ctx : NULL, &listen_sock);
atomic_load(&use_TLS) ? server_tlsctx : NULL, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
result = isc_nm_http_add_doh_endpoint(listen_sock, DOH_PATH,
result = isc_nm_http_endpoint(listen_sock, DOH_PATH,
doh_receive_request_cb, NULL, 0);
assert_int_equal(result, ISC_R_SUCCESS);
@ -1021,20 +1040,13 @@ doh_half_recv_half_send(void **state) {
isc_nmsocket_t *listen_sock = NULL;
size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1);
isc_thread_t threads[32] = { 0 };
isc_sockaddr_t tcp_connect_addr;
tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
result = isc_nm_listenhttp(
listen_nm, (isc_nmiface_t *)&tcp_listen_addr, 0, NULL,
atomic_load(&use_TLS) ? server_ssl_ctx : NULL, &listen_sock);
atomic_load(&use_TLS) ? server_tlsctx : NULL, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
result = isc_nm_http_add_doh_endpoint(listen_sock, DOH_PATH,
result = isc_nm_http_endpoint(listen_sock, DOH_PATH,
doh_receive_request_cb, NULL, 0);
assert_int_equal(result, ISC_R_SUCCESS);
@ -1105,7 +1117,7 @@ doh_parse_GET_query_string(void **state) {
"NjJjaGFyYWN0ZXJsYWJlbC1tYWtlcy1iYXNlNjR1cmwtZGlzdGluY3"
"QtZnJvbS1zdGFuZGFyZC1iYXNlNjQHZXhhbXBsZQNjb20AAAEAAQ";
ret = isc__nm_parse_doh_query_string(str, &queryp, &len);
ret = isc__nm_parse_httpquery(str, &queryp, &len);
assert_true(ret);
assert_non_null(queryp);
assert_true(len > 0);
@ -1122,7 +1134,7 @@ doh_parse_GET_query_string(void **state) {
"NjJjaGFyYWN0ZXJsYWJlbC1tYWtlcy1iYXNlNjR1cmwtZGlzdGluY3"
"QtZnJvbS1zdGFuZGFyZC1iYXNlNjQHZXhhbXBsZQNjb20AAAEAAQ&";
ret = isc__nm_parse_doh_query_string(str, &queryp, &len);
ret = isc__nm_parse_httpquery(str, &queryp, &len);
assert_true(ret);
assert_non_null(queryp);
assert_true(len > 0);
@ -1136,7 +1148,7 @@ doh_parse_GET_query_string(void **state) {
size_t len = 0;
char str[] = "?dns=123&dns=567";
ret = isc__nm_parse_doh_query_string(str, &queryp, &len);
ret = isc__nm_parse_httpquery(str, &queryp, &len);
assert_true(ret);
assert_non_null(queryp);
assert_true(len > 0);
@ -1150,7 +1162,7 @@ doh_parse_GET_query_string(void **state) {
size_t len = 0;
char str[] = "?name1=123&dns=567&name2=123&";
ret = isc__nm_parse_doh_query_string(str, &queryp, &len);
ret = isc__nm_parse_httpquery(str, &queryp, &len);
assert_true(ret);
assert_non_null(queryp);
assert_true(len > 0);
@ -1167,7 +1179,7 @@ doh_parse_GET_query_string(void **state) {
"BE%D0%B2%D0%B5_%D0%BA%D0%BE%D0%B4%D1%83%D0%B2%D0%B0%"
"D0%BD%D0%BD%D1%8F&dns=123&veaction=edit&section=0";
ret = isc__nm_parse_doh_query_string(str, &queryp, &len);
ret = isc__nm_parse_httpquery(str, &queryp, &len);
assert_true(ret);
assert_non_null(queryp);
assert_true(len > 0);
@ -1184,7 +1196,7 @@ doh_parse_GET_query_string(void **state) {
"BE%D0%B2%D0%B5_%D0%BA%D0%BE%D0%B4%D1%83%D0%B2%D0%B0%"
"D0%BD%D0%BD%D1%8F&veaction=edit&section=0";
ret = isc__nm_parse_doh_query_string(str, &queryp, &len);
ret = isc__nm_parse_httpquery(str, &queryp, &len);
assert_false(ret);
assert_null(queryp);
assert_true(len == 0);
@ -1196,7 +1208,7 @@ doh_parse_GET_query_string(void **state) {
size_t len = 0;
char str[] = "";
ret = isc__nm_parse_doh_query_string(str, &queryp, &len);
ret = isc__nm_parse_httpquery(str, &queryp, &len);
assert_false(ret);
assert_null(queryp);
assert_true(len == 0);
@ -1208,7 +1220,7 @@ doh_parse_GET_query_string(void **state) {
size_t len = 0;
char str[] = "?&";
ret = isc__nm_parse_doh_query_string(str, &queryp, &len);
ret = isc__nm_parse_httpquery(str, &queryp, &len);
assert_false(ret);
assert_null(queryp);
assert_true(len == 0);
@ -1220,7 +1232,7 @@ doh_parse_GET_query_string(void **state) {
size_t len = 0;
char str[] = "?dns&";
ret = isc__nm_parse_doh_query_string(str, &queryp, &len);
ret = isc__nm_parse_httpquery(str, &queryp, &len);
assert_false(ret);
assert_null(queryp);
assert_true(len == 0);
@ -1232,7 +1244,7 @@ doh_parse_GET_query_string(void **state) {
size_t len = 0;
char str[] = "?dns=&";
ret = isc__nm_parse_doh_query_string(str, &queryp, &len);
ret = isc__nm_parse_httpquery(str, &queryp, &len);
assert_false(ret);
assert_null(queryp);
assert_true(len == 0);
@ -1244,7 +1256,7 @@ doh_parse_GET_query_string(void **state) {
size_t len = 0;
char str[] = "?dns=123&&";
ret = isc__nm_parse_doh_query_string(str, &queryp, &len);
ret = isc__nm_parse_httpquery(str, &queryp, &len);
assert_false(ret);
assert_null(queryp);
assert_true(len == 0);
@ -1256,7 +1268,7 @@ doh_parse_GET_query_string(void **state) {
size_t len = 0;
char str[] = "?dns=123%12&";
ret = isc__nm_parse_doh_query_string(str, &queryp, &len);
ret = isc__nm_parse_httpquery(str, &queryp, &len);
assert_true(ret);
assert_non_null(queryp);
assert_true(len > 0);
@ -1270,7 +1282,7 @@ doh_parse_GET_query_string(void **state) {
size_t len = 0;
char str[] = "?dns=123%ZZ&";
ret = isc__nm_parse_doh_query_string(str, &queryp, &len);
ret = isc__nm_parse_httpquery(str, &queryp, &len);
assert_false(ret);
assert_null(queryp);
assert_true(len == 0);
@ -1282,7 +1294,7 @@ doh_parse_GET_query_string(void **state) {
size_t len = 0;
char str[] = "?dns=123%%&";
ret = isc__nm_parse_doh_query_string(str, &queryp, &len);
ret = isc__nm_parse_httpquery(str, &queryp, &len);
assert_false(ret);
assert_null(queryp);
assert_true(len == 0);
@ -1294,7 +1306,7 @@ doh_parse_GET_query_string(void **state) {
size_t len = 0;
char str[] = "?dns=123%AZ&";
ret = isc__nm_parse_doh_query_string(str, &queryp, &len);
ret = isc__nm_parse_httpquery(str, &queryp, &len);
assert_false(ret);
assert_null(queryp);
assert_true(len == 0);
@ -1306,7 +1318,7 @@ doh_parse_GET_query_string(void **state) {
size_t len = 0;
char str[] = "?dns=123%0AZ&";
ret = isc__nm_parse_doh_query_string(str, &queryp, &len);
ret = isc__nm_parse_httpquery(str, &queryp, &len);
assert_true(ret);
assert_non_null(queryp);
assert_true(len > 0);
@ -1593,66 +1605,6 @@ doh_base64_to_base64url(void **state) {
}
}
/*
static char wikipedia_org_A[] = { 0xae, 0x35, 0x01, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x77,
0x69, 0x6b, 0x69, 0x70, 0x65, 0x64, 0x69,
0x61, 0x03, 0x6f, 0x72, 0x67, 0x00, 0x00,
0x01, 0x00, 0x01 };
static void
doh_print_reply_cb(isc_nmhandle_t *handle, isc_result_t eresult,
isc_region_t *region, void *cbarg) {
assert_non_null(handle);
UNUSED(cbarg);
UNUSED(region);
puts("Cloudflare DNS query result:");
if (eresult == ISC_R_SUCCESS) {
puts("success!");
printf("Response size: %lu\n", region->length);
atomic_fetch_add(&creads, 1);
isc_nm_resumeread(handle);
} else {
puts("failure!");
atomic_store(&was_error, true);
isc_nm_cancelread(handle);
}
}
static void
doh_cloudflare(void **state) {
isc_nm_t **nm = (isc_nm_t **)*state;
isc_result_t result = ISC_R_SUCCESS;
result = isc_nm_http_connect_send_request(
nm[0], "https://cloudflare-dns.com/dns-query",
atomic_load(&POST),
&(isc_region_t){ .base = (uint8_t *)wikipedia_org_A,
.length = sizeof(wikipedia_org_A) },
doh_print_reply_cb, NULL, NULL, 5000);
assert_int_equal(result, ISC_R_SUCCESS);
while (atomic_load(&creads) != 1 && atomic_load(&was_error) == false) {
isc_thread_yield();
}
isc_nm_closedown(nm[0]);
}
static void
doh_cloudflare_POST(void **state) {
atomic_store(&POST, true);
doh_cloudflare(state);
}
static void
doh_cloudflare_GET(void **state) {
atomic_store(&POST, false);
doh_cloudflare(state);
}
*/
int
main(void) {
const struct CMUnitTest tests_short[] = {
@ -1745,17 +1697,21 @@ main(void) {
cmocka_unit_test_setup_teardown(doh_cloudflare_POST, nm_setup,
nm_teardown)*/
};
int result = 0;
#if OPENSSL_VERSION_NUMBER < 0x10100000L
UNUSED(tests_long);
return (cmocka_run_group_tests(tests_short, _setup, _teardown));
result = (cmocka_run_group_tests(tests_short, _setup, _teardown));
#else
if (getenv("CI") != NULL || !reuse_supported) {
return (cmocka_run_group_tests(tests_short, _setup, _teardown));
result = (cmocka_run_group_tests(tests_short, _setup,
_teardown));
} else {
return (cmocka_run_group_tests(tests_long, _setup, _teardown));
result =
(cmocka_run_group_tests(tests_long, _setup, _teardown));
}
#endif
return result;
}
#else /* HAVE_CMOCKA */

View File

@ -9,6 +9,9 @@
* information regarding copyright ownership.
*/
#include <inttypes.h>
#include <nghttp2/nghttp2.h>
#include <openssl/conf.h>
#include <openssl/err.h>
#include <openssl/opensslv.h>
@ -220,14 +223,7 @@ isc_tlsctx_createserver(const char *keyfile, const char *certfile,
const SSL_METHOD *method = NULL;
REQUIRE(ctxp != NULL && *ctxp == NULL);
if (ephemeral) {
INSIST(keyfile == NULL);
INSIST(certfile == NULL);
} else {
INSIST(keyfile != NULL);
INSIST(certfile != NULL);
}
REQUIRE((keyfile == NULL) == (certfile == NULL));
method = TLS_server_method();
if (method == NULL) {
@ -355,3 +351,123 @@ ssl_error:
return (ISC_R_TLSERROR);
}
isc_tls_t *
isc_tls_create(isc_tlsctx_t *ctx) {
isc_tls_t *newctx = NULL;
REQUIRE(ctx != NULL);
newctx = SSL_new(ctx);
if (newctx == NULL) {
char errbuf[256];
unsigned long err = ERR_get_error();
ERR_error_string_n(err, errbuf, sizeof(errbuf));
fprintf(stderr, "%s:SSL_new(%p) -> %s\n", __func__, ctx,
errbuf);
}
return (newctx);
}
void
isc_tls_free(isc_tls_t **tlsp) {
REQUIRE(tlsp != NULL && *tlsp != NULL);
SSL_free(*tlsp);
*tlsp = NULL;
}
#ifndef OPENSSL_NO_NEXTPROTONEG
/*
* NPN TLS extension client callback.
*/
static int
select_next_proto_cb(SSL *ssl, unsigned char **out, unsigned char *outlen,
const unsigned char *in, unsigned int inlen, void *arg) {
UNUSED(ssl);
UNUSED(arg);
if (nghttp2_select_next_protocol(out, outlen, in, inlen) <= 0) {
return (SSL_TLSEXT_ERR_NOACK);
}
return (SSL_TLSEXT_ERR_OK);
}
#endif /* !OPENSSL_NO_NEXTPROTONEG */
void
isc_tlsctx_enable_http2client_alpn(isc_tlsctx_t *ctx) {
REQUIRE(ctx != NULL);
#ifndef OPENSSL_NO_NEXTPROTONEG
SSL_CTX_set_next_proto_select_cb(ctx, select_next_proto_cb, NULL);
#endif /* !OPENSSL_NO_NEXTPROTONEG */
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
SSL_CTX_set_alpn_protos(ctx, (const unsigned char *)NGHTTP2_PROTO_ALPN,
NGHTTP2_PROTO_ALPN_LEN);
#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
}
#ifndef OPENSSL_NO_NEXTPROTONEG
static int
next_proto_cb(isc_tls_t *ssl, const unsigned char **data, unsigned int *len,
void *arg) {
UNUSED(ssl);
UNUSED(arg);
*data = (const unsigned char *)NGHTTP2_PROTO_ALPN;
*len = (unsigned int)NGHTTP2_PROTO_ALPN_LEN;
return (SSL_TLSEXT_ERR_OK);
}
#endif /* !OPENSSL_NO_NEXTPROTONEG */
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
static int
alpn_select_proto_cb(SSL *ssl, const unsigned char **out, unsigned char *outlen,
const unsigned char *in, unsigned int inlen, void *arg) {
int ret;
UNUSED(ssl);
UNUSED(arg);
ret = nghttp2_select_next_protocol((unsigned char **)(uintptr_t)out,
outlen, in, inlen);
if (ret != 1) {
return (SSL_TLSEXT_ERR_NOACK);
}
return (SSL_TLSEXT_ERR_OK);
}
#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
void
isc_tlsctx_enable_http2server_alpn(isc_tlsctx_t *tls) {
REQUIRE(tls != NULL);
#ifndef OPENSSL_NO_NEXTPROTONEG
SSL_CTX_set_next_protos_advertised_cb(tls, next_proto_cb, NULL);
#endif // OPENSSL_NO_NEXTPROTONEG
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
SSL_CTX_set_alpn_select_cb(tls, alpn_select_proto_cb, NULL);
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
}
void
isc_tls_get_http2_alpn(isc_tls_t *tls, const unsigned char **alpn,
unsigned int *alpnlen) {
REQUIRE(tls != NULL);
REQUIRE(alpn != NULL);
REQUIRE(alpnlen != NULL);
#ifndef OPENSSL_NO_NEXTPROTONEG
SSL_get0_next_proto_negotiated(tls, alpn, alpnlen);
#endif
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
if (*alpn == NULL) {
SSL_get0_alpn_selected(tls, alpn, alpnlen);
}
#endif
}

View File

@ -452,11 +452,8 @@ isc_nm_cancelread
isc_nm_closedown
isc_nm_destroy
isc_nm_detach
isc_nm_http_add_doh_endpoint
isc_nm_http_add_endpoint
isc_nm_http_connect_send_request
isc_nm_http_endpoint
isc_nm_httpconnect
isc_nm_httprequest
isc_nm_listenhttp
isc_nm_listentcpdns
isc_nm_listentls
@ -710,17 +707,20 @@ isc_timermgr_create
isc_timermgr_createinctx
isc_timermgr_destroy
isc_timermgr_poke
isc__tls_initialize
isc__tls_shutdown
isc_tls_get_http2_alpn
isc_tls_create
isc_tls_free
isc_tlsctx_createclient
isc_tlsctx_createserver
isc_tlsctx_free
isc_tlsctx_enable_http2client_alpn
isc_tlsctx_enable_http2server_alpn
isc_tm_timegm
isc_tm_strptime
isc__trampoline_initialize
isc__trampoline_shutdown
isc__trampoline_get
isc__trampoline_run
isc_tm_timegm
isc_tm_strptime
isc_url_parse
isc_utf8_bom
isc_utf8_valid

View File

@ -556,8 +556,8 @@ ns_interface_listenhttp(ns_interface_t *ifp, isc_tlsctx_t *sslctx, char **eps,
if (result == ISC_R_SUCCESS) {
for (i = 0; i < neps; i++) {
result = isc_nm_http_add_doh_endpoint(
sock, eps[i], ns__client_request, ifp,
result = isc_nm_http_endpoint(sock, eps[i],
ns__client_request, ifp,
sizeof(ns_client_t));
}
}

View File

@ -368,9 +368,12 @@
./bin/tests/system/dnstap/setup.sh SH 2018,2019,2020,2021
./bin/tests/system/dnstap/tests.sh SH 2015,2016,2017,2018,2019,2020,2021
./bin/tests/system/dnstap/ydump.py PYTHON 2016,2017,2018,2019,2020,2021
./bin/tests/system/dot/clean.sh SH 2020,2021
./bin/tests/system/dot/setup.sh SH 2020,2021
./bin/tests/system/dot/tests.sh SH 2020,2021
./bin/tests/system/doth/clean.sh SH 2020,2021
./bin/tests/system/doth/dig1.good X 2021
./bin/tests/system/doth/ns2/cert.pem X 2021
./bin/tests/system/doth/ns2/key.pem X 2021
./bin/tests/system/doth/setup.sh SH 2021
./bin/tests/system/doth/tests.sh SH 2021
./bin/tests/system/dscp/clean.sh SH 2013,2014,2015,2016,2018,2019,2020,2021
./bin/tests/system/dscp/ns1/named.args X 2013,2014,2018,2019,2020,2021
./bin/tests/system/dscp/ns2/named.args X 2013,2014,2018,2019,2020,2021
@ -987,10 +990,6 @@
./bin/tests/system/xferquota/setup.pl PERL 2000,2001,2004,2007,2011,2012,2016,2018,2019,2020,2021
./bin/tests/system/xferquota/setup.sh SH 2000,2001,2004,2007,2012,2016,2018,2019,2020,2021
./bin/tests/system/xferquota/tests.sh SH 2000,2001,2004,2007,2012,2016,2018,2019,2020,2021
./bin/tests/system/xot/clean.sh SH 2021
./bin/tests/system/xot/dig1.good X 2021
./bin/tests/system/xot/setup.sh SH 2021
./bin/tests/system/xot/tests.sh SH 2021
./bin/tests/system/zero/ans5/ans.pl PERL 2016,2018,2019,2020,2021
./bin/tests/system/zero/clean.sh SH 2013,2014,2015,2016,2018,2019,2020,2021
./bin/tests/system/zero/setup.sh SH 2013,2014,2016,2018,2019,2020,2021