mirror of
https://github.com/isc-projects/bind9.git
synced 2026-05-28 04:34:54 -04:00
Merge branch '1144-dns-over-https-server' into 'main'
Resolve "Encrypted DNS - RFC 8484, DNS over HTTPS, DOH (also DoT comments)" Closes #1144 See merge request isc-projects/bind9!4644
This commit is contained in:
commit
adf5051afc
51 changed files with 7316 additions and 198 deletions
|
|
@ -70,11 +70,6 @@ stages:
|
|||
- linux
|
||||
- amd64
|
||||
|
||||
.linux-i386: &linux_i386
|
||||
tags:
|
||||
- linux
|
||||
- i386
|
||||
|
||||
.linux-stress-amd64: &linux_stress_amd64
|
||||
tags:
|
||||
- amd64
|
||||
|
|
@ -133,10 +128,6 @@ stages:
|
|||
image: "$CI_REGISTRY_IMAGE:debian-sid-amd64"
|
||||
<<: *linux_amd64
|
||||
|
||||
.debian-sid-i386: &debian_sid_i386_image
|
||||
image: "$CI_REGISTRY_IMAGE:debian-sid-i386"
|
||||
<<: *linux_i386
|
||||
|
||||
# openSUSE Tumbleweed
|
||||
|
||||
.tumbleweed-latest-amd64: &tumbleweed_latest_amd64_image
|
||||
|
|
@ -285,6 +276,7 @@ stages:
|
|||
"with-openssl=C:/OpenSSL"
|
||||
"with-libxml2=C:/libxml2"
|
||||
"with-libuv=C:/libuv"
|
||||
"with-nghttp2=C:/nghttp2"
|
||||
"without-python"
|
||||
"with-system-tests"
|
||||
x64'
|
||||
|
|
@ -836,30 +828,6 @@ unit:gcc:tarball:
|
|||
- schedules
|
||||
- tags
|
||||
|
||||
# Jobs for regular GCC builds on Debian "sid" (i386)
|
||||
|
||||
gcc:sid:i386:
|
||||
variables:
|
||||
CC: gcc
|
||||
CFLAGS: "${CFLAGS_COMMON}"
|
||||
EXTRA_CONFIGURE: "--with-libidn2"
|
||||
<<: *debian_sid_i386_image
|
||||
<<: *build_job
|
||||
|
||||
system:gcc:sid:i386:
|
||||
<<: *debian_sid_i386_image
|
||||
<<: *system_test_job
|
||||
needs:
|
||||
- job: gcc:sid:i386
|
||||
artifacts: true
|
||||
|
||||
unit:gcc:sid:i386:
|
||||
<<: *debian_sid_i386_image
|
||||
<<: *unit_test_job
|
||||
needs:
|
||||
- job: gcc:sid:i386
|
||||
artifacts: true
|
||||
|
||||
# Jobs for debug GCC builds on openSUSE Tumbleweed (amd64)
|
||||
|
||||
gcc:tumbleweed:amd64:
|
||||
|
|
|
|||
7
CHANGES
7
CHANGES
|
|
@ -1,3 +1,10 @@
|
|||
5576. [experimental] Initial server-side implementation of DNS-over-HTTPS
|
||||
(DoH). Support for both TLS-encrypted and unencrypted
|
||||
HTTP/2 connections has been added to the network manager
|
||||
and integrated into named. (Note: there is currently no
|
||||
client-side support for DNS-over-HTTPS; this will be
|
||||
added to dig in a future release.) [GL #1144]
|
||||
|
||||
5575. [bug] When migrating to dnssec-policy, BIND considered keys
|
||||
with the "Inactive" and/or "Delete" timing metadata as
|
||||
possible active keys. This has been fixed. [GL #2406]
|
||||
|
|
|
|||
22
COPYRIGHT
22
COPYRIGHT
|
|
@ -367,3 +367,25 @@ distributed under the License is distributed on an "AS IS" BASIS,
|
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
||||
|
|
|
|||
|
|
@ -94,6 +94,8 @@ options {\n\
|
|||
# pid-file \"" NAMED_LOCALSTATEDIR "/run/named/named.pid\"; \n\
|
||||
port 53;\n\
|
||||
tls-port 853;\n\
|
||||
http-port 80;\n\
|
||||
https-port 443;\n\
|
||||
prefetch 2 9;\n\
|
||||
recursing-file \"named.recursing\";\n\
|
||||
recursive-clients 1000;\n\
|
||||
|
|
|
|||
|
|
@ -73,6 +73,8 @@ EXTERN const char *named_g_configargs INIT(PACKAGE_CONFIGARGS);
|
|||
EXTERN const char *named_g_builder INIT(PACKAGE_BUILDER);
|
||||
EXTERN in_port_t named_g_port INIT(0);
|
||||
EXTERN in_port_t named_g_tlsport INIT(0);
|
||||
EXTERN in_port_t named_g_httpsport INIT(0);
|
||||
EXTERN in_port_t named_g_httpport INIT(0);
|
||||
EXTERN isc_dscp_t named_g_dscp INIT(-1);
|
||||
|
||||
EXTERN named_server_t *named_g_server INIT(NULL);
|
||||
|
|
|
|||
|
|
@ -705,7 +705,7 @@ parse_T_opt(char *option) {
|
|||
|
||||
static void
|
||||
parse_port(char *arg) {
|
||||
enum { DNSPORT, TLSPORT } ptype = DNSPORT;
|
||||
enum { DNSPORT, TLSPORT, HTTPSPORT, HTTPPORT } ptype = DNSPORT;
|
||||
char *value = arg;
|
||||
int port;
|
||||
|
||||
|
|
@ -714,6 +714,12 @@ parse_port(char *arg) {
|
|||
} else if (strncmp(arg, "tls=", 4) == 0) {
|
||||
value = arg + 4;
|
||||
ptype = TLSPORT;
|
||||
} else if (strncmp(arg, "https=", 6) == 0) {
|
||||
value = arg + 6;
|
||||
ptype = HTTPSPORT;
|
||||
} else if (strncmp(arg, "http=", 5) == 0) {
|
||||
value = arg + 6;
|
||||
ptype = HTTPPORT;
|
||||
}
|
||||
|
||||
port = parse_int(value, "port");
|
||||
|
|
@ -728,6 +734,12 @@ parse_port(char *arg) {
|
|||
case TLSPORT:
|
||||
named_g_tlsport = port;
|
||||
break;
|
||||
case HTTPSPORT:
|
||||
named_g_httpsport = port;
|
||||
break;
|
||||
case HTTPPORT:
|
||||
named_g_httpport = port;
|
||||
break;
|
||||
default:
|
||||
INSIST(0);
|
||||
ISC_UNREACHABLE();
|
||||
|
|
|
|||
|
|
@ -86,6 +86,15 @@ DYNDB
|
|||
dyndb string quoted_string {
|
||||
unspecified-text };
|
||||
|
||||
HTTP
|
||||
^^^^
|
||||
|
||||
::
|
||||
|
||||
http string {
|
||||
endpoints { quoted_string; ... };
|
||||
};
|
||||
|
||||
KEY
|
||||
^^^
|
||||
|
||||
|
|
@ -264,6 +273,8 @@ OPTIONS
|
|||
glue-cache boolean;// deprecated
|
||||
heartbeat-interval integer;
|
||||
hostname ( quoted_string | none );
|
||||
http-port integer;
|
||||
https-port integer;
|
||||
inline-signing boolean;
|
||||
interface-interval duration;
|
||||
ipv4only-contact string;
|
||||
|
|
@ -275,10 +286,12 @@ OPTIONS
|
|||
key-directory quoted_string;
|
||||
lame-ttl duration;
|
||||
listen-on [ port integer ] [ dscp
|
||||
integer ] [ tls string ] {
|
||||
integer ] [ tls string ] [ http
|
||||
string ] {
|
||||
address_match_element; ... };
|
||||
listen-on-v6 [ port integer ] [ dscp
|
||||
integer ] [ tls string ] {
|
||||
integer ] [ tls string ] [ http
|
||||
string ] {
|
||||
address_match_element; ... };
|
||||
lmdb-mapsize sizeval;
|
||||
lock-file ( quoted_string | none );
|
||||
|
|
|
|||
|
|
@ -115,7 +115,11 @@ Options
|
|||
``portnum``; if not not specified, the default is port 53. If
|
||||
``value`` is of the form ``tls=<portnum>``, the server will
|
||||
listen for TLS queries on ``portnum``; the default is 853.
|
||||
|
||||
If ``value`` is of the form ``https=<portnum>``, the server will
|
||||
listen for HTTPS queries on ``portnum``; the default is 443.
|
||||
If ``value`` is of the form ``http=<portnum>``, the server will
|
||||
listen for HTTP queries on ``portnum``; the default is 80.
|
||||
|
||||
``-s``
|
||||
This option writes memory usage statistics to ``stdout`` on exit.
|
||||
|
||||
|
|
|
|||
|
|
@ -398,13 +398,19 @@ static void
|
|||
named_server_reload(isc_task_t *task, isc_event_t *event);
|
||||
|
||||
static isc_result_t
|
||||
ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
|
||||
cfg_aclconfctx_t *actx, isc_mem_t *mctx,
|
||||
uint16_t family, ns_listenelt_t **target);
|
||||
listenelt_http(const cfg_obj_t *http, bool tls, const char *key,
|
||||
const char *cert, in_port_t port, isc_mem_t *mctx,
|
||||
ns_listenelt_t **target);
|
||||
|
||||
static isc_result_t
|
||||
ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
|
||||
cfg_aclconfctx_t *actx, isc_mem_t *mctx,
|
||||
uint16_t family, ns_listenlist_t **target);
|
||||
listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
|
||||
cfg_aclconfctx_t *actx, isc_mem_t *mctx, uint16_t family,
|
||||
ns_listenelt_t **target);
|
||||
|
||||
static isc_result_t
|
||||
listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
|
||||
cfg_aclconfctx_t *actx, isc_mem_t *mctx, uint16_t family,
|
||||
ns_listenlist_t **target);
|
||||
|
||||
static isc_result_t
|
||||
configure_forward(const cfg_obj_t *config, dns_view_t *view,
|
||||
|
|
@ -8573,6 +8579,16 @@ load_configuration(const char *filename, named_server_t *server,
|
|||
maps[i++] = named_g_defaults;
|
||||
maps[i] = NULL;
|
||||
|
||||
obj = NULL;
|
||||
result = named_config_get(maps, "http-port", &obj);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
named_g_httpport = (in_port_t)cfg_obj_asuint32(obj);
|
||||
|
||||
obj = NULL;
|
||||
result = named_config_get(maps, "https-port", &obj);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
named_g_httpsport = (in_port_t)cfg_obj_asuint32(obj);
|
||||
|
||||
/*
|
||||
* If bind.keys exists, load it. If "dnssec-validation auto"
|
||||
* is turned on, the root key found there will be used as a
|
||||
|
|
@ -8989,7 +9005,7 @@ load_configuration(const char *filename, named_server_t *server,
|
|||
}
|
||||
if (clistenon != NULL) {
|
||||
/* check return code? */
|
||||
(void)ns_listenlist_fromconfig(
|
||||
(void)listenlist_fromconfig(
|
||||
clistenon, config, named_g_aclconfctx,
|
||||
named_g_mctx, AF_INET, &listenon);
|
||||
} else {
|
||||
|
|
@ -9017,7 +9033,7 @@ load_configuration(const char *filename, named_server_t *server,
|
|||
}
|
||||
if (clistenon != NULL) {
|
||||
/* check return code? */
|
||||
(void)ns_listenlist_fromconfig(
|
||||
(void)listenlist_fromconfig(
|
||||
clistenon, config, named_g_aclconfctx,
|
||||
named_g_mctx, AF_INET6, &listenon);
|
||||
} else {
|
||||
|
|
@ -10985,9 +11001,9 @@ named_server_togglequerylog(named_server_t *server, isc_lex_t *lex) {
|
|||
}
|
||||
|
||||
static isc_result_t
|
||||
ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
|
||||
cfg_aclconfctx_t *actx, isc_mem_t *mctx,
|
||||
uint16_t family, ns_listenlist_t **target) {
|
||||
listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
|
||||
cfg_aclconfctx_t *actx, isc_mem_t *mctx, uint16_t family,
|
||||
ns_listenlist_t **target) {
|
||||
isc_result_t result;
|
||||
const cfg_listelt_t *element;
|
||||
ns_listenlist_t *dlist = NULL;
|
||||
|
|
@ -11004,8 +11020,8 @@ ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
|
|||
{
|
||||
ns_listenelt_t *delt = NULL;
|
||||
const cfg_obj_t *listener = cfg_listelt_value(element);
|
||||
result = ns_listenelt_fromconfig(listener, config, actx, mctx,
|
||||
family, &delt);
|
||||
result = listenelt_fromconfig(listener, config, actx, mctx,
|
||||
family, &delt);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
|
@ -11019,66 +11035,114 @@ cleanup:
|
|||
return (result);
|
||||
}
|
||||
|
||||
static const cfg_obj_t *
|
||||
find_maplist(const cfg_obj_t *config, const char *listname, const char *name) {
|
||||
isc_result_t result;
|
||||
const cfg_obj_t *maplist = NULL;
|
||||
const cfg_listelt_t *elt = NULL;
|
||||
|
||||
REQUIRE(config != NULL);
|
||||
REQUIRE(name != NULL);
|
||||
|
||||
result = cfg_map_get(config, listname, &maplist);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
for (elt = cfg_list_first(maplist); elt != NULL;
|
||||
elt = cfg_list_next(elt)) {
|
||||
const cfg_obj_t *map = cfg_listelt_value(elt);
|
||||
if (strcasecmp(cfg_obj_asstring(cfg_map_getname(map)), name) ==
|
||||
0) {
|
||||
return (map);
|
||||
}
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a listen list from the corresponding configuration
|
||||
* data structure.
|
||||
*/
|
||||
static isc_result_t
|
||||
ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
|
||||
cfg_aclconfctx_t *actx, isc_mem_t *mctx,
|
||||
uint16_t family, ns_listenelt_t **target) {
|
||||
listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
|
||||
cfg_aclconfctx_t *actx, isc_mem_t *mctx, uint16_t family,
|
||||
ns_listenelt_t **target) {
|
||||
isc_result_t result;
|
||||
const cfg_obj_t *tlsobj, *portobj, *dscpobj;
|
||||
in_port_t port;
|
||||
const cfg_obj_t *tlsobj = NULL, *httpobj = NULL;
|
||||
const cfg_obj_t *portobj = NULL, *dscpobj = NULL;
|
||||
const cfg_obj_t *http_server = NULL;
|
||||
in_port_t port = 0;
|
||||
isc_dscp_t dscp = -1;
|
||||
const char *key = NULL, *cert = NULL;
|
||||
bool tls = false;
|
||||
bool do_tls = false, http = false;
|
||||
ns_listenelt_t *delt = NULL;
|
||||
|
||||
REQUIRE(target != NULL && *target == NULL);
|
||||
|
||||
/* XXXWPK TODO be more verbose on failures. */
|
||||
tlsobj = cfg_tuple_get(listener, "tls");
|
||||
if (tlsobj != NULL && cfg_obj_isstring(tlsobj)) {
|
||||
if (!strcmp(cfg_obj_asstring(tlsobj), "ephemeral")) {
|
||||
tls = true;
|
||||
} else {
|
||||
const cfg_obj_t *tlsconfigs = NULL;
|
||||
const cfg_listelt_t *element;
|
||||
(void)cfg_map_get(config, "tls", &tlsconfigs);
|
||||
for (element = cfg_list_first(tlsconfigs);
|
||||
element != NULL; element = cfg_list_next(element))
|
||||
{
|
||||
cfg_obj_t *tconfig = cfg_listelt_value(element);
|
||||
const cfg_obj_t *name =
|
||||
cfg_map_getname(tconfig);
|
||||
if (!strcmp(cfg_obj_asstring(name),
|
||||
cfg_obj_asstring(tlsobj))) {
|
||||
tls = true;
|
||||
const cfg_obj_t *keyo = NULL,
|
||||
*certo = NULL;
|
||||
(void)cfg_map_get(tconfig, "key-file",
|
||||
&keyo);
|
||||
if (keyo == NULL) {
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
(void)cfg_map_get(tconfig, "cert-file",
|
||||
&certo);
|
||||
if (certo == NULL) {
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
key = cfg_obj_asstring(keyo);
|
||||
cert = cfg_obj_asstring(certo);
|
||||
break;
|
||||
}
|
||||
const char *tlsname = cfg_obj_asstring(tlsobj);
|
||||
|
||||
if (strcmp(tlsname, "ephemeral") != 0) {
|
||||
const cfg_obj_t *keyobj = NULL, *certobj = NULL;
|
||||
const cfg_obj_t *tlsmap = NULL;
|
||||
|
||||
tlsmap = find_maplist(config, "tls", tlsname);
|
||||
if (tlsmap == NULL) {
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
|
||||
CHECK(cfg_map_get(tlsmap, "key-file", &keyobj));
|
||||
key = cfg_obj_asstring(keyobj);
|
||||
|
||||
CHECK(cfg_map_get(tlsmap, "cert-file", &certobj));
|
||||
cert = cfg_obj_asstring(certobj);
|
||||
}
|
||||
if (!tls) {
|
||||
|
||||
do_tls = true;
|
||||
}
|
||||
|
||||
httpobj = cfg_tuple_get(listener, "http");
|
||||
if (httpobj != NULL && cfg_obj_isstring(httpobj)) {
|
||||
const char *httpname = cfg_obj_asstring(httpobj);
|
||||
|
||||
http_server = find_maplist(config, "http", httpname);
|
||||
if (http_server == NULL) {
|
||||
cfg_obj_log(httpobj, named_g_lctx, ISC_LOG_ERROR,
|
||||
"http '%s' is not defined",
|
||||
cfg_obj_asstring(httpobj));
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
|
||||
http = true;
|
||||
}
|
||||
|
||||
portobj = cfg_tuple_get(listener, "port");
|
||||
if (!cfg_obj_isuint32(portobj)) {
|
||||
if (tls) {
|
||||
if (http && do_tls) {
|
||||
if (named_g_httpsport != 0) {
|
||||
port = named_g_httpsport;
|
||||
} else {
|
||||
result = named_config_getport(
|
||||
config, "https-port", &port);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return (result);
|
||||
}
|
||||
}
|
||||
} else if (http && !do_tls) {
|
||||
if (named_g_httpport != 0) {
|
||||
port = named_g_port;
|
||||
} else {
|
||||
result = named_config_getport(
|
||||
config, "http-port", &port);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return (result);
|
||||
}
|
||||
}
|
||||
} else if (do_tls) {
|
||||
if (named_g_tlsport != 0) {
|
||||
port = named_g_tlsport;
|
||||
} else {
|
||||
|
|
@ -11103,6 +11167,7 @@ ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
|
|||
if (cfg_obj_asuint32(portobj) >= UINT16_MAX) {
|
||||
cfg_obj_log(portobj, named_g_lctx, ISC_LOG_ERROR,
|
||||
"port value '%u' is out of range",
|
||||
|
||||
cfg_obj_asuint32(portobj));
|
||||
return (ISC_R_RANGE);
|
||||
}
|
||||
|
|
@ -11122,10 +11187,13 @@ ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
|
|||
dscp = (isc_dscp_t)cfg_obj_asuint32(dscpobj);
|
||||
}
|
||||
|
||||
result = ns_listenelt_create(mctx, port, dscp, NULL, tls, key, cert,
|
||||
&delt);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return (result);
|
||||
if (http) {
|
||||
INSIST(http_server != NULL);
|
||||
CHECK(listenelt_http(http_server, do_tls, key, cert, port, mctx,
|
||||
&delt));
|
||||
} else {
|
||||
CHECK(ns_listenelt_create(mctx, port, dscp, NULL, do_tls, key,
|
||||
cert, &delt));
|
||||
}
|
||||
|
||||
result = cfg_acl_fromconfig2(cfg_tuple_get(listener, "acl"), config,
|
||||
|
|
@ -11136,7 +11204,55 @@ ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
|
|||
return (result);
|
||||
}
|
||||
*target = delt;
|
||||
return (ISC_R_SUCCESS);
|
||||
|
||||
cleanup:
|
||||
return (result);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
listenelt_http(const cfg_obj_t *http, bool tls, const char *key,
|
||||
const char *cert, in_port_t port, isc_mem_t *mctx,
|
||||
ns_listenelt_t **target) {
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
ns_listenelt_t *delt = NULL;
|
||||
char **endpoints = NULL;
|
||||
const cfg_obj_t *eplist = NULL;
|
||||
const cfg_listelt_t *elt = NULL;
|
||||
size_t len, i = 0;
|
||||
|
||||
REQUIRE(target != NULL && *target == NULL);
|
||||
REQUIRE((key == NULL) == (cert == NULL));
|
||||
|
||||
if (port == 0) {
|
||||
port = tls ? named_g_httpsport : named_g_httpport;
|
||||
}
|
||||
|
||||
CHECK(cfg_map_get(http, "endpoints", &eplist));
|
||||
len = cfg_list_length(eplist, false);
|
||||
endpoints = isc_mem_allocate(mctx, sizeof(endpoints[0]) * len);
|
||||
|
||||
for (elt = cfg_list_first(eplist); elt != NULL;
|
||||
elt = cfg_list_next(elt)) {
|
||||
const cfg_obj_t *ep = cfg_listelt_value(elt);
|
||||
const char *path = cfg_obj_asstring(ep);
|
||||
endpoints[i++] = isc_mem_strdup(mctx, path);
|
||||
}
|
||||
|
||||
INSIST(i == len);
|
||||
|
||||
result = ns_listenelt_create_http(mctx, port, named_g_dscp, NULL, tls,
|
||||
key, cert, endpoints, len, &delt);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
if (delt != NULL) {
|
||||
ns_listenelt_destroy(delt);
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
*target = delt;
|
||||
|
||||
cleanup:
|
||||
return (result);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
|
|
|
|||
27
bin/tests/system/checkconf/good-doh-global.conf
Normal file
27
bin/tests/system/checkconf/good-doh-global.conf
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
tls local-tls {
|
||||
key-file "key.pem";
|
||||
cert-file "cert.pem";
|
||||
};
|
||||
|
||||
http local-http-server {
|
||||
endpoints { "/dns-query"; };
|
||||
};
|
||||
|
||||
options {
|
||||
listen-on { 10.53.0.1; };
|
||||
http-port 80;
|
||||
https-port 443;
|
||||
listen-on port 443 tls local-tls http local-http-server { 10.53.0.1; };
|
||||
listen-on port 8080 http local-http-server { 10.53.0.1; };
|
||||
};
|
||||
19
bin/tests/system/checkconf/good-dot-global.conf
Normal file
19
bin/tests/system/checkconf/good-dot-global.conf
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
tls local-tls {
|
||||
key-file "key.pem";
|
||||
cert-file "cert.pem";
|
||||
};
|
||||
|
||||
options {
|
||||
listen-on port 853 tls local-tls { 10.53.0.1; };
|
||||
};
|
||||
|
|
@ -668,6 +668,8 @@ 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}HTTPSPORT${atsign}/${HTTPSPORT}/g" \
|
||||
-e "s/${atsign}EXTRAPORT1${atsign}/${EXTRAPORT1}/g" \
|
||||
-e "s/${atsign}EXTRAPORT2${atsign}/${EXTRAPORT2}/g" \
|
||||
-e "s/${atsign}EXTRAPORT3${atsign}/${EXTRAPORT3}/g" \
|
||||
|
|
|
|||
|
|
@ -82,6 +82,8 @@ done
|
|||
|
||||
echo "export PORT=$(get_port "$baseport")"
|
||||
echo "export TLSPORT=$(get_port)"
|
||||
echo "export HTTPPORT=$(get_port)"
|
||||
echo "export HTTPSPORT=$(get_port)"
|
||||
echo "export EXTRAPORT1=$(get_port)"
|
||||
echo "export EXTRAPORT2=$(get_port)"
|
||||
echo "export EXTRAPORT3=$(get_port)"
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ stop_servers() {
|
|||
echostart "S:$systest:$(date_with_args)"
|
||||
echoinfo "T:$systest:1:A"
|
||||
echoinfo "A:$systest:System test $systest"
|
||||
echoinfo "I:$systest:PORTS:${PORT},${TLSPORT},${EXTRAPORT1},${EXTRAPORT2},${EXTRAPORT3},${EXTRAPORT4},${EXTRAPORT5},${EXTRAPORT6},${EXTRAPORT7},${EXTRAPORT8},${CONTROLPORT}"
|
||||
echoinfo "I:$systest:PORTS:${PORT},${TLSPORT},${HTTPPORT},${HTTPSPORT},${EXTRAPORT1},${EXTRAPORT2},${EXTRAPORT3},${EXTRAPORT4},${EXTRAPORT5},${EXTRAPORT6},${EXTRAPORT7},${EXTRAPORT8},${CONTROLPORT}"
|
||||
|
||||
$PERL ${srcdir}/testsock.pl -p "$PORT" || {
|
||||
echowarn "I:$systest:Network interface aliases not set up. Skipping test."
|
||||
|
|
|
|||
|
|
@ -138,7 +138,8 @@ const FileData installFiles[] =
|
|||
{"libdns.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
|
||||
{"libirs.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
|
||||
{"libeay32.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
|
||||
{"libuv.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
|
||||
{"nghttp2.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
|
||||
{"uv.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
|
||||
#ifdef HAVE_LIBXML2
|
||||
{"libxml2.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
|
||||
#endif
|
||||
|
|
|
|||
11
configure.ac
11
configure.ac
|
|
@ -124,7 +124,7 @@ AS_IF([test "$enable_static" != "no" && test "$enable_developer" != "yes"],
|
|||
#
|
||||
# Set the default CFLAGS and CPPFLAGS
|
||||
#
|
||||
STD_CFLAGS="-Wall -Wextra -Wwrite-strings -Wcast-qual -Wpointer-arith -Wno-missing-field-initializers -Wformat -Wshadow"
|
||||
STD_CFLAGS="-Wall -Wextra -Wwrite-strings -Wpointer-arith -Wno-missing-field-initializers -Wformat -Wshadow"
|
||||
|
||||
# These should be always errors
|
||||
STD_CFLAGS="$STD_CFLAGS -Werror=implicit-function-declaration -Werror=missing-prototypes -Werror=format-security -Werror=parentheses -Werror=implicit -Werror=strict-prototypes"
|
||||
|
|
@ -574,6 +574,15 @@ LIBS="$LIBS $LIBUV_LIBS"
|
|||
AC_CHECK_FUNCS([uv_handle_get_data uv_handle_set_data uv_import uv_udp_connect uv_translate_sys_error])
|
||||
AX_RESTORE_FLAGS([libuv])
|
||||
|
||||
# libnghttp2
|
||||
AC_MSG_CHECKING([for libnghttp2])
|
||||
PKG_CHECK_MODULES([LIBNGHTTP2], [libnghttp2 >= 1.6.0], [],
|
||||
[AC_MSG_ERROR([libnghttp2 not found])])
|
||||
AX_SAVE_FLAGS([libnghttp2])
|
||||
|
||||
CFLAGS="$CFLAGS $LIBNGHTTP2_CFLAGS"
|
||||
LIBS="$LIBS $LIBNGHTTP2_LIBS"
|
||||
|
||||
#
|
||||
# flockfile is usually provided by pthreads
|
||||
#
|
||||
|
|
|
|||
|
|
@ -1256,6 +1256,20 @@ default is used.
|
|||
for server testing; a server using a port other than 53 is not
|
||||
able to communicate with the global DNS.
|
||||
|
||||
``tls-port``
|
||||
This is the TCP port number the server uses to receive and send
|
||||
DNS-over-TLS protocol traffic. The default is 853.
|
||||
|
||||
``https-port``
|
||||
This is the TCP port number the server uses to receive and send
|
||||
DNS-over-HTTPS protocol traffic. The default is 443.
|
||||
|
||||
``http-port``
|
||||
This is the TCP port number the server uses to receive and send
|
||||
unencrypted DNS traffic via HTTP (a configuration that may be useful
|
||||
when encryption is handled by third-party software or by a reverse
|
||||
proxy).
|
||||
|
||||
``dscp``
|
||||
This is the global Differentiated Services Code Point (DSCP) value to
|
||||
classify outgoing DNS traffic, on operating systems that support DSCP.
|
||||
|
|
@ -2434,17 +2448,36 @@ for details on how to specify IP address lists.
|
|||
Interfaces
|
||||
^^^^^^^^^^
|
||||
|
||||
The interfaces and ports that the server answers queries from may be
|
||||
specified using the ``listen-on`` and ``listen-on-v6`` options.
|
||||
The interfaces, ports, and protocols that the server can use to answer
|
||||
queries may be specified using the ``listen-on`` and ``listen-on-v6`` options.
|
||||
|
||||
``listen-on`` takes an optional port, an optional TLS configuration
|
||||
identifier, and an ``address_match_list`` of IPv4 addresses. (IPv6
|
||||
addresses are ignored, with a logged warning.) The server listens on all
|
||||
interfaces allowed by the address match list. If a TLS configuration is
|
||||
specified, ``named`` will listen for DNS-over-TLS (DoT) connections, using
|
||||
the key and certificate specified in the referenced ``tls`` statement. If a
|
||||
port number is not specified, the default is 53 for standard DNS and 853
|
||||
for DNS-over-TLS.
|
||||
``listen-on`` and ``listen-on-v6`` statements can each take an optional
|
||||
port, TLS configuration identifier, and/or HTTP configuration identifier,
|
||||
in addition to an ``address_match_list``.
|
||||
|
||||
The ``address_match_list`` in ``listen-on`` specifies the IPv4 addresses
|
||||
on which the server will listen. (IPv6 addresses are ignored, with a
|
||||
logged warning.) The server listens on all interfaces allowed by the
|
||||
address match list. If no ``listen-on`` is specified, the default is
|
||||
to listen for standard DNS queries on port 53 of all IPv4 interfaces.
|
||||
|
||||
``listen-on-v6`` takes an ``address_match_list`` of IPv6 addresses.
|
||||
The server listens on all interfaces allowed by the address match list.
|
||||
If no ``listen-on-v6`` is specified, the default is to listen for standard
|
||||
DNS queries on port 53 of all IPv6 interfaces.
|
||||
|
||||
If a TLS configuration is specified, ``named`` will listen for DNS-over-TLS
|
||||
(DoT) connections, using the key and certificate specified in the
|
||||
referenced ``tls`` statement.
|
||||
|
||||
If an HTTP configuration is specified, ``named`` will listen for
|
||||
DNS-over-HTTPS (DoH) connections using the HTTP endpoint specified in the
|
||||
referenced ``http`` statement. Normally, ``http`` and ``tls``
|
||||
configurations will be used together, but ``tls`` may be omitted if
|
||||
encryption is being handled by external software.
|
||||
|
||||
If a port number is not specified, the default is 53 for standard DNS, 853
|
||||
for DNS-over-TLS, and 443 for DNS-over-HTTPS.
|
||||
|
||||
Multiple ``listen-on`` statements are allowed. For example:
|
||||
|
||||
|
|
@ -2453,20 +2486,17 @@ Multiple ``listen-on`` statements are allowed. For example:
|
|||
listen-on { 5.6.7.8; };
|
||||
listen-on port 1234 { !1.2.3.4; 1.2/16; };
|
||||
listen-on port 8853 tls ephemeral { 4.3.2.1; };
|
||||
listen-on port 8453 tls ephemeral http myserver { 8.7.6.5; };
|
||||
|
||||
enables the name server to listen for standard DNS queries on port 53 of the
|
||||
IP address 5.6.7.8 and on port 1234 of an address on the machine in net 1.2
|
||||
that is not 1.2.3.4, and to listen for DNS-over-TLS connections on port
|
||||
8853 of the IP address 4.3.2.1, using an ephemeral TLS key and certificate
|
||||
created for the currently running ``named`` process.
|
||||
|
||||
If no ``listen-on`` is specified, the server listens for standard DNS
|
||||
on port 53 of all IPv4 interfaces.
|
||||
|
||||
The ``listen-on-v6`` option is used to specify the interfaces and the ports
|
||||
on which the server listens for incoming queries sent using IPv6. If not
|
||||
specified, the server listens for standard DNS queries on port 53 of all
|
||||
IPv6 interfaces.
|
||||
The first two lines instruct the name server to listen for standard DNS
|
||||
queries on port 53 of the IP address 5.6.7.8 and on port 1234 of an address
|
||||
on the machine in net 1.2 that is not 1.2.3.4. The third line instructs the
|
||||
server to listen for DNS-over-TLS connections on port 8853 of the IP
|
||||
address 4.3.2.1 using an ephemeral TLS key and certificate created for the
|
||||
currently running ``named`` process. The fourth line enables DNS-over-HTTPS
|
||||
connections on port 8453 of address 8.7.6.5, using the same ephemeral
|
||||
key and certificate, and the HTTP endpoint or endpoints configured in
|
||||
an ``http`` statement with the name ``myserver``.
|
||||
|
||||
Multiple ``listen-on-v6`` options can be used. For example:
|
||||
|
||||
|
|
@ -2475,12 +2505,19 @@ Multiple ``listen-on-v6`` options can be used. For example:
|
|||
listen-on-v6 { any; };
|
||||
listen-on-v6 port 1234 { !2001:db8::/32; any; };
|
||||
listen-on port 8853 tls example-tls { 2001:db8::100; };
|
||||
listen-on port 8453 tls example-tls http myserver { 2001:db8::100; };
|
||||
listen-on port 8000 http myserver { 2001:db8::100; };
|
||||
|
||||
enables the name server to listen for standard DNS queries on port 53 of
|
||||
any IPv6 addresses and on port 1234 of IPv6 addresses that are not in the
|
||||
prefix 2001:db8::/32, and for DNS-over-TLS connections on port 8853 of
|
||||
the address 2001:db8::100, using a TLS key and certificate specified in
|
||||
the a ``tls`` statement with the name ``example-tls``.
|
||||
The first two lines instruct the name server to listen for standard DNS
|
||||
queries on port 53 of any IPv6 addresses, and on port 1234 of IPv6
|
||||
addresses that are not in the prefix 2001:db8::/32. The third line
|
||||
instructs the server to listen for for DNS-over-TLS connections on port
|
||||
8853 of the address 2001:db8::100, using a TLS key and certificate specified
|
||||
in the a ``tls`` statement with the name ``example-tls``. The fourth
|
||||
instructs the server to listen for DNS-over-HTTPS connections, again using
|
||||
``example-tls``, on the HTTP endpoint specified in ``http myserver``. The
|
||||
fifth line, in which the ``tls`` parameter is omitted, instructs the server
|
||||
to listen for *unencrypted* DNS queries over HTTP.
|
||||
|
||||
To instruct the server not to listen on any IPv6 addresses, use:
|
||||
|
||||
|
|
@ -4624,6 +4661,45 @@ The following options can be specified in a ``tls`` statement:
|
|||
The built-in ``ephemeral`` TLS connection object represents a temporary
|
||||
key and certificate created for the current ``named`` session only.
|
||||
|
||||
.. _http:
|
||||
|
||||
``http`` Statement Grammar
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. include:: ../misc/http.grammar.rst
|
||||
|
||||
``http`` Statement Definition and Usage
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The ``http`` statement is used to configure HTTP endpoints on which
|
||||
to listen for DNS-over-HTTPS (DoH) queries. This configuration can
|
||||
then be referenced by a ``listen-on`` or ``listen-on-v6`` statement to
|
||||
cause ``named`` to listen for incoming requests over HTTPS.
|
||||
|
||||
``http`` can only be set at the top level of ``named.conf``.
|
||||
|
||||
The following options can be specified in an ``http`` statement:
|
||||
|
||||
``endpoints``
|
||||
A list of HTTP query paths on which to listen. A typical path
|
||||
is "/dns-query".
|
||||
|
||||
for example, the following configuration enables DNS-over-HTTPS queries on
|
||||
all local addresses:
|
||||
|
||||
::
|
||||
|
||||
http local {
|
||||
endpoints { "/dns-query"; };
|
||||
};
|
||||
|
||||
options {
|
||||
....
|
||||
listen-on tls ephemeral http local { any; };
|
||||
listen-on-v6 tls ephemeral http local { any; };
|
||||
};
|
||||
|
||||
|
||||
.. _trust_anchors:
|
||||
|
||||
``trust-anchors`` Statement Grammar
|
||||
|
|
|
|||
|
|
@ -115,6 +115,10 @@ for queries. If \fBvalue\fP is of the form \fB<portnum>\fP or
|
|||
\fBportnum\fP; if not not specified, the default is port 53. If
|
||||
\fBvalue\fP is of the form \fBtls=<portnum>\fP, the server will
|
||||
listen for TLS queries on \fBportnum\fP; the default is 853.
|
||||
If \fBvalue\fP is of the form \fBhttps=<portnum>\fP, the server will
|
||||
listen for HTTPS queries on \fBportnum\fP; the default is 443.
|
||||
If \fBvalue\fP is of the form \fBhttp=<portnum>\fP, the server will
|
||||
listen for HTTP queries on \fBportnum\fP; the default is 80.
|
||||
.TP
|
||||
.B \fB\-s\fP
|
||||
This option writes memory usage statistics to \fBstdout\fP on exit.
|
||||
|
|
|
|||
|
|
@ -132,6 +132,19 @@ dyndb string quoted_string {
|
|||
.fi
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.SS HTTP
|
||||
.INDENT 0.0
|
||||
.INDENT 3.5
|
||||
.sp
|
||||
.nf
|
||||
.ft C
|
||||
http string {
|
||||
endpoints { quoted_string; ... };
|
||||
};
|
||||
.ft P
|
||||
.fi
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.SS KEY
|
||||
.INDENT 0.0
|
||||
.INDENT 3.5
|
||||
|
|
@ -327,6 +340,8 @@ options {
|
|||
glue\-cache boolean;// deprecated
|
||||
heartbeat\-interval integer;
|
||||
hostname ( quoted_string | none );
|
||||
http\-port integer;
|
||||
https\-port integer;
|
||||
inline\-signing boolean;
|
||||
interface\-interval duration;
|
||||
ipv4only\-contact string;
|
||||
|
|
@ -338,10 +353,12 @@ options {
|
|||
key\-directory quoted_string;
|
||||
lame\-ttl duration;
|
||||
listen\-on [ port integer ] [ dscp
|
||||
integer ] [ tls string ] {
|
||||
integer ] [ tls string ] [ http
|
||||
string ] {
|
||||
address_match_element; ... };
|
||||
listen\-on\-v6 [ port integer ] [ dscp
|
||||
integer ] [ tls string ] {
|
||||
integer ] [ tls string ] [ http
|
||||
string ] {
|
||||
address_match_element; ... };
|
||||
lmdb\-mapsize sizeval;
|
||||
lock\-file ( quoted_string | none );
|
||||
|
|
|
|||
|
|
@ -37,7 +37,8 @@ OPTIONS_FILES = \
|
|||
tls.grammar.rst \
|
||||
trust-anchors.grammar.rst \
|
||||
managed-keys.grammar.rst \
|
||||
trusted-keys.grammar.rst
|
||||
trusted-keys.grammar.rst \
|
||||
http.grammar.rst
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(OPTIONS_FILES) \
|
||||
|
|
@ -175,4 +176,7 @@ managed-keys.grammar.rst: options.active
|
|||
trusted-keys.grammar.rst: options.active
|
||||
$(AM_V_RST_GRAMMARS)$(PERL) $(srcdir)/rst-grammars.pl options.active trusted-keys > $@
|
||||
|
||||
http.grammar.rst: options.active
|
||||
$(AM_V_RST_GRAMMARS)$(PERL) $(srcdir)/rst-grammars.pl options.active http > $@
|
||||
|
||||
endif
|
||||
|
|
|
|||
5
doc/misc/http.grammar.rst
Normal file
5
doc/misc/http.grammar.rst
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
::
|
||||
|
||||
http <string> {
|
||||
endpoints { <quoted_string>; ... };
|
||||
};
|
||||
|
|
@ -42,6 +42,10 @@ dnssec-policy <string> {
|
|||
dyndb <string> <quoted_string> {
|
||||
<unspecified-text> }; // may occur multiple times
|
||||
|
||||
http <string> {
|
||||
endpoints { <quoted_string>; ... };
|
||||
}; // may occur multiple times
|
||||
|
||||
key <string> {
|
||||
algorithm <string>;
|
||||
secret <string>;
|
||||
|
|
@ -193,6 +197,8 @@ options {
|
|||
glue-cache <boolean>; // deprecated
|
||||
heartbeat-interval <integer>;
|
||||
hostname ( <quoted_string> | none );
|
||||
http-port <integer>;
|
||||
https-port <integer>;
|
||||
inline-signing <boolean>;
|
||||
interface-interval <duration>;
|
||||
ipv4only-contact <string>;
|
||||
|
|
@ -204,10 +210,12 @@ options {
|
|||
key-directory <quoted_string>;
|
||||
lame-ttl <duration>;
|
||||
listen-on [ port <integer> ] [ dscp
|
||||
<integer> ] [ tls <string> ] {
|
||||
<integer> ] [ tls <string> ] [ http
|
||||
<string> ] {
|
||||
<address_match_element>; ... }; // may occur multiple times
|
||||
listen-on-v6 [ port <integer> ] [ dscp
|
||||
<integer> ] [ tls <string> ] {
|
||||
<integer> ] [ tls <string> ] [ http
|
||||
<string> ] {
|
||||
<address_match_element>; ... }; // may occur multiple times
|
||||
lmdb-mapsize <sizeval>;
|
||||
lock-file ( <quoted_string> | none );
|
||||
|
|
|
|||
|
|
@ -41,6 +41,10 @@ dnssec-policy <string> {
|
|||
dyndb <string> <quoted_string> {
|
||||
<unspecified-text> }; // may occur multiple times
|
||||
|
||||
http <string> {
|
||||
endpoints { <quoted_string>; ... };
|
||||
}; // may occur multiple times
|
||||
|
||||
key <string> {
|
||||
algorithm <string>;
|
||||
secret <string>;
|
||||
|
|
@ -192,6 +196,8 @@ options {
|
|||
glue-cache <boolean>; // deprecated
|
||||
heartbeat-interval <integer>;
|
||||
hostname ( <quoted_string> | none );
|
||||
http-port <integer>;
|
||||
https-port <integer>;
|
||||
inline-signing <boolean>;
|
||||
interface-interval <duration>;
|
||||
ipv4only-contact <string>;
|
||||
|
|
@ -203,10 +209,12 @@ options {
|
|||
key-directory <quoted_string>;
|
||||
lame-ttl <duration>;
|
||||
listen-on [ port <integer> ] [ dscp
|
||||
<integer> ] [ tls <string> ] {
|
||||
<integer> ] [ tls <string> ] [ http
|
||||
<string> ] {
|
||||
<address_match_element>; ... }; // may occur multiple times
|
||||
listen-on-v6 [ port <integer> ] [ dscp
|
||||
<integer> ] [ tls <string> ] {
|
||||
<integer> ] [ tls <string> ] [ http
|
||||
<string> ] {
|
||||
<address_match_element>; ... }; // may occur multiple times
|
||||
lmdb-mapsize <sizeval>;
|
||||
lock-file ( <quoted_string> | none );
|
||||
|
|
|
|||
|
|
@ -119,6 +119,8 @@
|
|||
glue-cache <boolean>; // deprecated
|
||||
heartbeat-interval <integer>;
|
||||
hostname ( <quoted_string> | none );
|
||||
http-port <integer>;
|
||||
https-port <integer>;
|
||||
inline-signing <boolean>;
|
||||
interface-interval <duration>;
|
||||
ipv4only-contact <string>;
|
||||
|
|
@ -130,10 +132,12 @@
|
|||
key-directory <quoted_string>;
|
||||
lame-ttl <duration>;
|
||||
listen-on [ port <integer> ] [ dscp
|
||||
<integer> ] [ tls <string> ] {
|
||||
<integer> ] [ tls <string> ] [ http
|
||||
<string> ] {
|
||||
<address_match_element>; ... };
|
||||
listen-on-v6 [ port <integer> ] [ dscp
|
||||
<integer> ] [ tls <string> ] {
|
||||
<integer> ] [ tls <string> ] [ http
|
||||
<string> ] {
|
||||
<address_match_element>; ... };
|
||||
lmdb-mapsize <sizeval>;
|
||||
lock-file ( <quoted_string> | none );
|
||||
|
|
|
|||
|
|
@ -52,6 +52,13 @@ New Features
|
|||
an optional ``tls`` option which specifies either a previously configured
|
||||
``tls`` statement or ``ephemeral``. [GL #2392]
|
||||
|
||||
- ``named`` now supports DNS-over-HTTPS (DoH). Both TLS-encrypted and
|
||||
unencrypted HTTP/2 connections are supported (the latter may be used to
|
||||
offload encryption to other software).
|
||||
|
||||
Note that there is no client-side support for HTTPS as yet; this will be
|
||||
added to ``dig`` in a future release. [GL #1144]
|
||||
|
||||
Removed Features
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ libisc_la_HEADERS = \
|
|||
include/isc/tls.h \
|
||||
include/isc/tm.h \
|
||||
include/isc/types.h \
|
||||
include/isc/url.h \
|
||||
include/isc/utf8.h \
|
||||
include/isc/util.h \
|
||||
pthreads/include/isc/condition.h\
|
||||
|
|
@ -124,11 +125,13 @@ libisc_la_SOURCES = \
|
|||
$(libisc_la_HEADERS) \
|
||||
$(pk11_HEADERS) \
|
||||
$(pkcs11_HEADERS) \
|
||||
netmgr/http.c \
|
||||
netmgr/netmgr-int.h \
|
||||
netmgr/netmgr.c \
|
||||
netmgr/tcp.c \
|
||||
netmgr/tcpdns.c \
|
||||
netmgr/tlsdns.c \
|
||||
netmgr/tlsstream.c \
|
||||
netmgr/udp.c \
|
||||
netmgr/uv-compat.c \
|
||||
netmgr/uv-compat.h \
|
||||
|
|
@ -149,6 +152,7 @@ libisc_la_SOURCES = \
|
|||
unix/stdtime.c \
|
||||
unix/syslog.c \
|
||||
unix/time.c \
|
||||
url.c \
|
||||
pk11.c \
|
||||
pk11_result.c \
|
||||
aes.c \
|
||||
|
|
|
|||
|
|
@ -172,6 +172,8 @@ typedef struct isc_memmethods {
|
|||
void *(*memreallocate)(isc_mem_t *mctx, void *ptr,
|
||||
size_t size _ISC_MEM_FLARG);
|
||||
char *(*memstrdup)(isc_mem_t *mctx, const char *s _ISC_MEM_FLARG);
|
||||
char *(*memstrndup)(isc_mem_t *mctx, const char *s,
|
||||
size_t size _ISC_MEM_FLARG);
|
||||
void (*memfree)(isc_mem_t *mctx, void *ptr _ISC_MEM_FLARG);
|
||||
} isc_memmethods_t;
|
||||
|
||||
|
|
@ -226,7 +228,9 @@ struct isc_mempool {
|
|||
#define isc_mem_reallocate(c, p, s) \
|
||||
ISCMEMFUNC(reallocate)((c), (p), (s)_ISC_MEM_FILELINE)
|
||||
#define isc_mem_strdup(c, p) ISCMEMFUNC(strdup)((c), (p)_ISC_MEM_FILELINE)
|
||||
#define isc_mempool_get(c) ISCMEMPOOLFUNC(get)((c)_ISC_MEM_FILELINE)
|
||||
#define isc_mem_strndup(c, p, l) \
|
||||
ISCMEMFUNC(strndup)((c), (p), (l)_ISC_MEM_FILELINE)
|
||||
#define isc_mempool_get(c) ISCMEMPOOLFUNC(get)((c)_ISC_MEM_FILELINE)
|
||||
|
||||
#define isc_mem_put(c, p, s) \
|
||||
do { \
|
||||
|
|
@ -596,6 +600,7 @@ void *ISCMEMFUNC(allocate)(isc_mem_t *, size_t _ISC_MEM_FLARG);
|
|||
void *ISCMEMFUNC(reallocate)(isc_mem_t *, void *, size_t _ISC_MEM_FLARG);
|
||||
void ISCMEMFUNC(free)(isc_mem_t *, void *_ISC_MEM_FLARG);
|
||||
char *ISCMEMFUNC(strdup)(isc_mem_t *, const char *_ISC_MEM_FLARG);
|
||||
char *ISCMEMFUNC(strndup)(isc_mem_t *, const char *, size_t _ISC_MEM_FLARG);
|
||||
void *ISCMEMPOOLFUNC(get)(isc_mempool_t *_ISC_MEM_FLARG);
|
||||
void ISCMEMPOOLFUNC(put)(isc_mempool_t *, void *_ISC_MEM_FLARG);
|
||||
|
||||
|
|
|
|||
|
|
@ -473,6 +473,17 @@ isc_nm_setstats(isc_nm_t *mgr, isc_stats_t *stats);
|
|||
* full range of socket-related stats counter numbers.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
isc_nm_listentls(isc_nm_t *mgr, isc_nmiface_t *iface,
|
||||
isc_nm_accept_cb_t accept_cb, void *accept_cbarg,
|
||||
size_t extrahandlesize, int backlog, isc_quota_t *quota,
|
||||
isc_tlsctx_t *sslctx, isc_nmsocket_t **sockp);
|
||||
|
||||
isc_result_t
|
||||
isc_nm_tlsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
|
||||
isc_nm_cb_t cb, void *cbarg, isc_tlsctx_t *ctx,
|
||||
unsigned int timeout, size_t extrahandlesize);
|
||||
|
||||
isc_result_t
|
||||
isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
|
||||
isc_nm_cb_t cb, void *cbarg, unsigned int timeout,
|
||||
|
|
@ -494,3 +505,46 @@ isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
|
|||
* The connected socket can only be accessed via the handle passed to
|
||||
* '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);
|
||||
|
|
|
|||
80
lib/isc/include/isc/url.h
Normal file
80
lib/isc/include/isc/url.h
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <isc/result.h>
|
||||
|
||||
/*
|
||||
* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run
|
||||
* faster
|
||||
*/
|
||||
#ifndef HTTP_PARSER_STRICT
|
||||
#define HTTP_PARSER_STRICT 1
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
ISC_UF_SCHEMA = 0,
|
||||
ISC_UF_HOST = 1,
|
||||
ISC_UF_PORT = 2,
|
||||
ISC_UF_PATH = 3,
|
||||
ISC_UF_QUERY = 4,
|
||||
ISC_UF_FRAGMENT = 5,
|
||||
ISC_UF_USERINFO = 6,
|
||||
ISC_UF_MAX = 7
|
||||
} isc_url_field_t;
|
||||
|
||||
/* Result structure for isc_url_parse().
|
||||
*
|
||||
* Callers should index into field_data[] with UF_* values iff field_set
|
||||
* has the relevant (1 << UF_*) bit set. As a courtesy to clients (and
|
||||
* because we probably have padding left over), we convert any port to
|
||||
* a uint16_t.
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t field_set; /* Bitmask of (1 << UF_*) values */
|
||||
uint16_t port; /* Converted UF_PORT string */
|
||||
|
||||
struct {
|
||||
uint16_t off; /* Offset into buffer in which field starts */
|
||||
uint16_t len; /* Length of run in buffer */
|
||||
} field_data[ISC_UF_MAX];
|
||||
} isc_url_parser_t;
|
||||
|
||||
isc_result_t
|
||||
isc_url_parse(const char *buf, size_t buflen, bool is_connect,
|
||||
isc_url_parser_t *up);
|
||||
/*%<
|
||||
* Parse a URL; return nonzero on failure
|
||||
*/
|
||||
|
|
@ -244,13 +244,15 @@ static void *
|
|||
isc___mem_reallocate(isc_mem_t *ctx, void *ptr, size_t size FLARG);
|
||||
static char *
|
||||
isc___mem_strdup(isc_mem_t *mctx, const char *s FLARG);
|
||||
static char *
|
||||
isc___mem_strndup(isc_mem_t *mctx, const char *s, size_t size FLARG);
|
||||
static void
|
||||
isc___mem_free(isc_mem_t *ctx, void *ptr FLARG);
|
||||
|
||||
static isc_memmethods_t memmethods = {
|
||||
isc___mem_get, isc___mem_put, isc___mem_putanddetach,
|
||||
isc___mem_allocate, isc___mem_reallocate, isc___mem_strdup,
|
||||
isc___mem_free,
|
||||
isc___mem_strndup, isc___mem_free,
|
||||
};
|
||||
|
||||
#if ISC_MEM_TRACKLINES
|
||||
|
|
@ -1439,6 +1441,29 @@ isc___mem_strdup(isc_mem_t *mctx0, const char *s FLARG) {
|
|||
return (ns);
|
||||
}
|
||||
|
||||
char *
|
||||
isc___mem_strndup(isc_mem_t *mctx0, const char *s, size_t size FLARG) {
|
||||
REQUIRE(VALID_CONTEXT(mctx0));
|
||||
REQUIRE(s != NULL);
|
||||
|
||||
isc__mem_t *mctx = (isc__mem_t *)mctx0;
|
||||
size_t len;
|
||||
char *ns;
|
||||
|
||||
len = strlen(s) + 1;
|
||||
if (len > size) {
|
||||
len = size;
|
||||
}
|
||||
|
||||
ns = isc__mem_allocate((isc_mem_t *)mctx, len FLARG_PASS);
|
||||
|
||||
if (ns != NULL) {
|
||||
strlcpy(ns, s, len);
|
||||
}
|
||||
|
||||
return (ns);
|
||||
}
|
||||
|
||||
void
|
||||
isc_mem_setdestroycheck(isc_mem_t *ctx0, bool flag) {
|
||||
REQUIRE(VALID_CONTEXT(ctx0));
|
||||
|
|
@ -2467,6 +2492,13 @@ isc__mem_strdup(isc_mem_t *mctx, const char *s FLARG) {
|
|||
return (mctx->methods->memstrdup(mctx, s FLARG_PASS));
|
||||
}
|
||||
|
||||
char *
|
||||
isc__mem_strndup(isc_mem_t *mctx, const char *s, size_t size FLARG) {
|
||||
REQUIRE(ISCAPI_MCTX_VALID(mctx));
|
||||
|
||||
return (mctx->methods->memstrndup(mctx, s, size FLARG_PASS));
|
||||
}
|
||||
|
||||
void
|
||||
isc__mem_free(isc_mem_t *mctx, void *ptr FLARG) {
|
||||
REQUIRE(ISCAPI_MCTX_VALID(mctx));
|
||||
|
|
|
|||
2591
lib/isc/netmgr/http.c
Normal file
2591
lib/isc/netmgr/http.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -30,6 +30,7 @@
|
|||
#include <isc/refcount.h>
|
||||
#include <isc/region.h>
|
||||
#include <isc/result.h>
|
||||
#include <isc/rwlock.h>
|
||||
#include <isc/sockaddr.h>
|
||||
#include <isc/stats.h>
|
||||
#include <isc/thread.h>
|
||||
|
|
@ -155,6 +156,8 @@ 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.
|
||||
*/
|
||||
|
|
@ -207,6 +210,8 @@ 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_sockaddr_t peer;
|
||||
isc_sockaddr_t local;
|
||||
isc_nm_opaquecb_t doreset; /* reset extra callback, external */
|
||||
|
|
@ -252,6 +257,13 @@ typedef enum isc__netievent_type {
|
|||
netievent_tcpdnsclose,
|
||||
netievent_tcpdnsstop,
|
||||
|
||||
netievent_tlsclose,
|
||||
netievent_tlssend,
|
||||
netievent_tlsstartread,
|
||||
netievent_tlsconnect,
|
||||
netievent_tlsdobio,
|
||||
netievent_tlscancel,
|
||||
|
||||
netievent_tlsdnsaccept,
|
||||
netievent_tlsdnsconnect,
|
||||
netievent_tlsdnssend,
|
||||
|
|
@ -262,6 +274,10 @@ typedef enum isc__netievent_type {
|
|||
netievent_tlsdnscycle,
|
||||
netievent_tlsdnsshutdown,
|
||||
|
||||
netievent_httpstop,
|
||||
netievent_httpsend,
|
||||
netievent_httpclose,
|
||||
|
||||
netievent_close,
|
||||
netievent_shutdown,
|
||||
netievent_stop,
|
||||
|
|
@ -286,11 +302,22 @@ 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 {
|
||||
char *path;
|
||||
isc_nm_http_cb_t cb;
|
||||
void *cbarg;
|
||||
size_t extrahandlesize;
|
||||
LINK(isc_nm_http2_server_handler_t) link;
|
||||
};
|
||||
|
||||
/*
|
||||
* Wrapper around uv_req_t with 'our' fields in it. req->data should
|
||||
* always point to its parent. Note that we always allocate more than
|
||||
|
|
@ -642,8 +669,12 @@ typedef enum isc_nmsocket_type {
|
|||
isc_nm_tcplistener,
|
||||
isc_nm_tcpdnslistener,
|
||||
isc_nm_tcpdnssocket,
|
||||
isc_nm_tlslistener,
|
||||
isc_nm_tlssocket,
|
||||
isc_nm_tlsdnslistener,
|
||||
isc_nm_tlsdnssocket
|
||||
isc_nm_tlsdnssocket,
|
||||
isc_nm_httplistener,
|
||||
isc_nm_httpstream
|
||||
} isc_nmsocket_type;
|
||||
|
||||
/*%
|
||||
|
|
@ -670,12 +701,74 @@ enum {
|
|||
STATID_ACTIVE = 10
|
||||
};
|
||||
|
||||
typedef struct isc_nmsocket_tls_send_req {
|
||||
isc_nmsocket_t *tlssock;
|
||||
isc_region_t data;
|
||||
} isc_nmsocket_tls_send_req_t;
|
||||
|
||||
typedef enum isc_doh_request_type {
|
||||
ISC_HTTP_REQ_GET,
|
||||
ISC_HTTP_REQ_POST,
|
||||
ISC_HTTP_REQ_UNSUPPORTED
|
||||
} isc_http2_request_type_t;
|
||||
|
||||
typedef enum isc_http2_scheme_type {
|
||||
ISC_HTTP_SCHEME_HTTP,
|
||||
ISC_HTTP_SCHEME_HTTP_SECURE,
|
||||
ISC_HTTP_SCHEME_UNSUPPORTED
|
||||
} isc_http2_scheme_type_t;
|
||||
|
||||
typedef struct isc_nm_http_doh_cbarg {
|
||||
isc_nm_recv_cb_t cb;
|
||||
void *cbarg;
|
||||
LINK(struct isc_nm_http_doh_cbarg) link;
|
||||
} isc_nm_http_doh_cbarg_t;
|
||||
|
||||
typedef struct isc_nmsocket_h2 {
|
||||
isc_nmsocket_t *psock; /* owner of the structure */
|
||||
char *request_path;
|
||||
char *query_data;
|
||||
size_t query_data_len;
|
||||
bool query_too_large;
|
||||
isc_nm_http2_server_handler_t *handler;
|
||||
|
||||
uint8_t *buf;
|
||||
size_t bufsize;
|
||||
size_t bufpos;
|
||||
|
||||
int32_t stream_id;
|
||||
isc_nm_http2_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_nm_http_cb_t handler_cb;
|
||||
void *handler_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;
|
||||
|
||||
char response_content_length_str[128];
|
||||
|
||||
struct isc_nmsocket_h2_connect_data {
|
||||
char *uri;
|
||||
bool post;
|
||||
} connect;
|
||||
} isc_nmsocket_h2_t;
|
||||
struct isc_nmsocket {
|
||||
/*% Unlocked, RO */
|
||||
int magic;
|
||||
int tid;
|
||||
isc_nmsocket_type type;
|
||||
isc_nm_t *mgr;
|
||||
|
||||
/*% Parent socket for multithreaded listeners */
|
||||
isc_nmsocket_t *parent;
|
||||
/*% Listener socket this connection was accepted on */
|
||||
|
|
@ -705,6 +798,28 @@ struct isc_nmsocket {
|
|||
isc__nm_uvreq_t *pending_req;
|
||||
} tls;
|
||||
|
||||
/*% TLS stuff */
|
||||
struct tlsstream {
|
||||
bool server;
|
||||
BIO *app_bio;
|
||||
SSL *ssl;
|
||||
SSL_CTX *ctx;
|
||||
BIO *ssl_bio;
|
||||
isc_nmsocket_t *tlslistener;
|
||||
enum {
|
||||
TLS_INIT,
|
||||
TLS_HANDSHAKE,
|
||||
TLS_IO,
|
||||
TLS_ERROR,
|
||||
TLS_CLOSING,
|
||||
TLS_CLOSED
|
||||
} state;
|
||||
size_t nsending;
|
||||
/* List of active send requests. */
|
||||
ISC_LIST(isc__nm_uvreq_t) sends;
|
||||
} tlsstream;
|
||||
|
||||
isc_nmsocket_h2_t h2;
|
||||
/*%
|
||||
* quota is the TCP client, attached when a TCP connection
|
||||
* is established. pquota is a non-attached pointer to the
|
||||
|
|
@ -906,6 +1021,7 @@ struct isc_nmsocket {
|
|||
void *accept_cbarg;
|
||||
|
||||
atomic_int_fast32_t active_child_connections;
|
||||
|
||||
#ifdef NETMGR_TRACE
|
||||
void *backtrace[TRACE_SIZE];
|
||||
int backtrace_size;
|
||||
|
|
@ -1070,8 +1186,8 @@ isc__nm_async_shutdown(isc__networker_t *worker, isc__netievent_t *ev0);
|
|||
*/
|
||||
|
||||
void
|
||||
isc__nm_udp_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
|
||||
void *cbarg);
|
||||
isc__nm_udp_send(isc_nmhandle_t *handle, const isc_region_t *region,
|
||||
isc_nm_cb_t cb, void *cbarg);
|
||||
/*%<
|
||||
* Back-end implementation of isc_nm_send() for UDP handles.
|
||||
*/
|
||||
|
|
@ -1132,8 +1248,8 @@ isc__nm_async_udpclose(isc__networker_t *worker, isc__netievent_t *ev0);
|
|||
*/
|
||||
|
||||
void
|
||||
isc__nm_tcp_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
|
||||
void *cbarg);
|
||||
isc__nm_tcp_send(isc_nmhandle_t *handle, const isc_region_t *region,
|
||||
isc_nm_cb_t cb, void *cbarg);
|
||||
/*%<
|
||||
* Back-end implementation of isc_nm_send() for TCP handles.
|
||||
*/
|
||||
|
|
@ -1220,6 +1336,28 @@ isc__nm_async_tcpclose(isc__networker_t *worker, isc__netievent_t *ev0);
|
|||
* stoplisten, send, read, pause, close).
|
||||
*/
|
||||
|
||||
void
|
||||
isc__nm_async_tlsclose(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
|
||||
void
|
||||
isc__nm_async_tlssend(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
|
||||
void
|
||||
isc__nm_async_tlsconnect(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
|
||||
void
|
||||
isc__nm_async_tlsstartread(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
|
||||
void
|
||||
isc__nm_async_tlsdobio(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
|
||||
void
|
||||
isc__nm_async_tlscancel(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
|
||||
/*%<
|
||||
* Callback handlers for asynchronouse TLS events.
|
||||
*/
|
||||
|
||||
void
|
||||
isc__nm_async_tcpdnsaccept(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
void
|
||||
|
|
@ -1291,6 +1429,14 @@ isc__nm_async_tlsdnslisten(isc__networker_t *worker, isc__netievent_t *ev0);
|
|||
void
|
||||
isc__nm_tlsdns_send(isc_nmhandle_t *handle, isc_region_t *region,
|
||||
isc_nm_cb_t cb, void *cbarg);
|
||||
|
||||
void
|
||||
isc__nm_tls_send(isc_nmhandle_t *handle, const isc_region_t *region,
|
||||
isc_nm_cb_t cb, void *cbarg);
|
||||
|
||||
void
|
||||
isc__nm_tls_cancelread(isc_nmhandle_t *handle);
|
||||
|
||||
/*%<
|
||||
* Back-end implementation of isc_nm_send() for TLSDNS handles.
|
||||
*/
|
||||
|
|
@ -1344,6 +1490,71 @@ isc__nm_tlsdns_cancelread(isc_nmhandle_t *handle);
|
|||
* Stop reading on a connected TLSDNS handle.
|
||||
*/
|
||||
|
||||
void
|
||||
isc__nm_tls_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg);
|
||||
|
||||
void
|
||||
isc__nm_tls_close(isc_nmsocket_t *sock);
|
||||
/*%<
|
||||
* Close a TLS socket.
|
||||
*/
|
||||
|
||||
void
|
||||
isc__nm_tls_pauseread(isc_nmhandle_t *handle);
|
||||
/*%<
|
||||
* Pause reading on this handle, while still remembering the callback.
|
||||
*/
|
||||
|
||||
void
|
||||
isc__nm_tls_resumeread(isc_nmhandle_t *handle);
|
||||
/*%<
|
||||
* Resume reading from the handle.
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
isc__nm_tls_cleanup_data(isc_nmsocket_t *sock);
|
||||
|
||||
void
|
||||
isc__nm_tls_stoplistening(isc_nmsocket_t *sock);
|
||||
|
||||
void
|
||||
isc__nm_http_stoplistening(isc_nmsocket_t *sock);
|
||||
|
||||
void
|
||||
isc__nm_http_clear_handlers(isc_nmsocket_t *sock);
|
||||
|
||||
void
|
||||
isc__nm_http_clear_session(isc_nmsocket_t *sock);
|
||||
|
||||
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_close(isc_nmsocket_t *sock);
|
||||
|
||||
void
|
||||
isc__nm_async_httpsend(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
|
||||
void
|
||||
isc__nm_async_httpstop(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
|
||||
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,
|
||||
size_t *len);
|
||||
|
||||
char *
|
||||
isc__nm_base64url_to_base64(isc_mem_t *mem, const char *base64url,
|
||||
const size_t base64url_len, size_t *res_len);
|
||||
|
||||
char *
|
||||
isc__nm_base64_to_base64url(isc_mem_t *mem, const char *base64,
|
||||
const size_t base64_len, size_t *res_len);
|
||||
|
||||
#define isc__nm_uverr2result(x) \
|
||||
isc___nm_uverr2result(x, true, __FILE__, __LINE__, __func__)
|
||||
isc_result_t
|
||||
|
|
@ -1444,6 +1655,12 @@ NETIEVENT_SOCKET_TYPE(tcpclose);
|
|||
NETIEVENT_SOCKET_TYPE(tcplisten);
|
||||
NETIEVENT_SOCKET_TYPE(tcppauseread);
|
||||
NETIEVENT_SOCKET_TYPE(tcpstop);
|
||||
NETIEVENT_SOCKET_TYPE(tlsclose);
|
||||
/* NETIEVENT_SOCKET_TYPE(tlsconnect); */ /* unique type, defined independently
|
||||
*/
|
||||
NETIEVENT_SOCKET_TYPE(tlsdobio);
|
||||
NETIEVENT_SOCKET_TYPE(tlsstartread);
|
||||
NETIEVENT_SOCKET_HANDLE_TYPE(tlscancel);
|
||||
NETIEVENT_SOCKET_TYPE(udpclose);
|
||||
NETIEVENT_SOCKET_TYPE(udplisten);
|
||||
NETIEVENT_SOCKET_TYPE(udpread);
|
||||
|
|
@ -1470,9 +1687,14 @@ NETIEVENT_SOCKET_HANDLE_TYPE(tlsdnscancel);
|
|||
NETIEVENT_SOCKET_QUOTA_TYPE(tlsdnsaccept);
|
||||
NETIEVENT_SOCKET_TYPE(tlsdnscycle);
|
||||
|
||||
NETIEVENT_SOCKET_TYPE(httpstop);
|
||||
NETIEVENT_SOCKET_REQ_TYPE(httpsend);
|
||||
NETIEVENT_SOCKET_TYPE(httpclose);
|
||||
|
||||
NETIEVENT_SOCKET_REQ_TYPE(tcpconnect);
|
||||
NETIEVENT_SOCKET_REQ_TYPE(tcpsend);
|
||||
NETIEVENT_SOCKET_TYPE(tcpstartread);
|
||||
NETIEVENT_SOCKET_REQ_TYPE(tlssend);
|
||||
NETIEVENT_SOCKET_REQ_TYPE(udpconnect);
|
||||
|
||||
NETIEVENT_SOCKET_REQ_RESULT_TYPE(connectcb);
|
||||
|
|
@ -1498,6 +1720,11 @@ NETIEVENT_SOCKET_DECL(tcplisten);
|
|||
NETIEVENT_SOCKET_DECL(tcppauseread);
|
||||
NETIEVENT_SOCKET_DECL(tcpstartread);
|
||||
NETIEVENT_SOCKET_DECL(tcpstop);
|
||||
NETIEVENT_SOCKET_DECL(tlsclose);
|
||||
NETIEVENT_SOCKET_DECL(tlsconnect);
|
||||
NETIEVENT_SOCKET_DECL(tlsdobio);
|
||||
NETIEVENT_SOCKET_DECL(tlsstartread);
|
||||
NETIEVENT_SOCKET_HANDLE_DECL(tlscancel);
|
||||
NETIEVENT_SOCKET_DECL(udpclose);
|
||||
NETIEVENT_SOCKET_DECL(udplisten);
|
||||
NETIEVENT_SOCKET_DECL(udpread);
|
||||
|
|
@ -1524,8 +1751,13 @@ NETIEVENT_SOCKET_HANDLE_DECL(tlsdnscancel);
|
|||
NETIEVENT_SOCKET_QUOTA_DECL(tlsdnsaccept);
|
||||
NETIEVENT_SOCKET_DECL(tlsdnscycle);
|
||||
|
||||
NETIEVENT_SOCKET_DECL(httpstop);
|
||||
NETIEVENT_SOCKET_REQ_DECL(httpsend);
|
||||
NETIEVENT_SOCKET_DECL(httpclose);
|
||||
|
||||
NETIEVENT_SOCKET_REQ_DECL(tcpconnect);
|
||||
NETIEVENT_SOCKET_REQ_DECL(tcpsend);
|
||||
NETIEVENT_SOCKET_REQ_DECL(tlssend);
|
||||
NETIEVENT_SOCKET_REQ_DECL(udpconnect);
|
||||
|
||||
NETIEVENT_SOCKET_REQ_RESULT_DECL(connectcb);
|
||||
|
|
|
|||
|
|
@ -716,6 +716,13 @@ process_netievent(isc__networker_t *worker, isc__netievent_t *ievent) {
|
|||
NETIEVENT_CASE(tcpdnsread);
|
||||
NETIEVENT_CASE(tcpdnsstop);
|
||||
|
||||
NETIEVENT_CASE(tlsstartread);
|
||||
NETIEVENT_CASE(tlssend);
|
||||
NETIEVENT_CASE(tlsclose);
|
||||
NETIEVENT_CASE(tlsconnect);
|
||||
NETIEVENT_CASE(tlsdobio);
|
||||
NETIEVENT_CASE(tlscancel);
|
||||
|
||||
NETIEVENT_CASE(tlsdnscycle);
|
||||
NETIEVENT_CASE(tlsdnsaccept);
|
||||
NETIEVENT_CASE(tlsdnslisten);
|
||||
|
|
@ -727,6 +734,10 @@ process_netievent(isc__networker_t *worker, isc__netievent_t *ievent) {
|
|||
NETIEVENT_CASE(tlsdnsstop);
|
||||
NETIEVENT_CASE(tlsdnsshutdown);
|
||||
|
||||
NETIEVENT_CASE(httpstop);
|
||||
NETIEVENT_CASE(httpsend);
|
||||
NETIEVENT_CASE(httpclose);
|
||||
|
||||
NETIEVENT_CASE(connectcb);
|
||||
NETIEVENT_CASE(readcb);
|
||||
NETIEVENT_CASE(sendcb);
|
||||
|
|
@ -776,6 +787,11 @@ NETIEVENT_SOCKET_DEF(tcplisten);
|
|||
NETIEVENT_SOCKET_DEF(tcppauseread);
|
||||
NETIEVENT_SOCKET_DEF(tcpstartread);
|
||||
NETIEVENT_SOCKET_DEF(tcpstop);
|
||||
NETIEVENT_SOCKET_DEF(tlsclose);
|
||||
NETIEVENT_SOCKET_DEF(tlsconnect);
|
||||
NETIEVENT_SOCKET_DEF(tlsdobio);
|
||||
NETIEVENT_SOCKET_DEF(tlsstartread);
|
||||
NETIEVENT_SOCKET_HANDLE_DEF(tlscancel);
|
||||
NETIEVENT_SOCKET_DEF(udpclose);
|
||||
NETIEVENT_SOCKET_DEF(udplisten);
|
||||
NETIEVENT_SOCKET_DEF(udpread);
|
||||
|
|
@ -802,8 +818,13 @@ NETIEVENT_SOCKET_QUOTA_DEF(tlsdnsaccept);
|
|||
NETIEVENT_SOCKET_DEF(tlsdnscycle);
|
||||
NETIEVENT_SOCKET_DEF(tlsdnsshutdown);
|
||||
|
||||
NETIEVENT_SOCKET_DEF(httpstop);
|
||||
NETIEVENT_SOCKET_REQ_DEF(httpsend);
|
||||
NETIEVENT_SOCKET_DEF(httpclose);
|
||||
|
||||
NETIEVENT_SOCKET_REQ_DEF(tcpconnect);
|
||||
NETIEVENT_SOCKET_REQ_DEF(tcpsend);
|
||||
NETIEVENT_SOCKET_REQ_DEF(tlssend);
|
||||
NETIEVENT_SOCKET_REQ_DEF(udpconnect);
|
||||
|
||||
NETIEVENT_SOCKET_REQ_RESULT_DEF(connectcb);
|
||||
|
|
@ -986,6 +1007,34 @@ nmsocket_cleanup(isc_nmsocket_t *sock, bool dofree FLARG) {
|
|||
isc_mutex_destroy(&sock->lock);
|
||||
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);
|
||||
#ifdef NETMGR_TRACE
|
||||
LOCK(&sock->mgr->lock);
|
||||
ISC_LIST_UNLINK(sock->mgr->active_sockets, sock, active_link);
|
||||
|
|
@ -1094,9 +1143,15 @@ isc___nmsocket_prep_destroy(isc_nmsocket_t *sock FLARG) {
|
|||
case isc_nm_tcpdnssocket:
|
||||
isc__nm_tcpdns_close(sock);
|
||||
return;
|
||||
case isc_nm_tlssocket:
|
||||
isc__nm_tls_close(sock);
|
||||
break;
|
||||
case isc_nm_tlsdnssocket:
|
||||
isc__nm_tlsdns_close(sock);
|
||||
return;
|
||||
case isc_nm_httpstream:
|
||||
isc__nm_http_close(sock);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -1139,7 +1194,9 @@ isc_nmsocket_close(isc_nmsocket_t **sockp) {
|
|||
REQUIRE((*sockp)->type == isc_nm_udplistener ||
|
||||
(*sockp)->type == isc_nm_tcplistener ||
|
||||
(*sockp)->type == isc_nm_tcpdnslistener ||
|
||||
(*sockp)->type == isc_nm_tlsdnslistener);
|
||||
(*sockp)->type == isc_nm_tlsdnslistener ||
|
||||
(*sockp)->type == isc_nm_tlslistener ||
|
||||
(*sockp)->type == isc_nm_httplistener);
|
||||
|
||||
isc__nmsocket_detach(sockp);
|
||||
}
|
||||
|
|
@ -1202,6 +1259,8 @@ 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_httplistener:
|
||||
if (family == AF_INET) {
|
||||
sock->statsindex = tcp4statsindex;
|
||||
} else {
|
||||
|
|
@ -1218,6 +1277,9 @@ isc___nmsocket_init(isc_nmsocket_t *sock, isc_nm_t *mgr, isc_nmsocket_type type,
|
|||
isc_condition_init(&sock->scond);
|
||||
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));
|
||||
|
||||
|
|
@ -1228,6 +1290,28 @@ 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;
|
||||
|
||||
sock->magic = NMSOCK_MAGIC;
|
||||
}
|
||||
|
||||
|
|
@ -1353,7 +1437,7 @@ isc___nmhandle_get(isc_nmsocket_t *sock, isc_sockaddr_t *peer,
|
|||
#endif
|
||||
UNLOCK(&sock->lock);
|
||||
|
||||
if (sock->type == isc_nm_tcpsocket ||
|
||||
if (sock->type == isc_nm_tcpsocket || sock->type == isc_nm_tlssocket ||
|
||||
(sock->type == isc_nm_udpsocket && atomic_load(&sock->client)) ||
|
||||
(sock->type == isc_nm_tcpdnssocket && atomic_load(&sock->client)) ||
|
||||
(sock->type == isc_nm_tlsdnssocket && atomic_load(&sock->client)))
|
||||
|
|
@ -1369,6 +1453,10 @@ 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;
|
||||
}
|
||||
|
||||
return (handle);
|
||||
}
|
||||
|
||||
|
|
@ -1390,6 +1478,7 @@ isc_nmhandle_is_stream(isc_nmhandle_t *handle) {
|
|||
|
||||
return (handle->sock->type == isc_nm_tcpsocket ||
|
||||
handle->sock->type == isc_nm_tcpdnssocket ||
|
||||
handle->sock->type == isc_nm_tlssocket ||
|
||||
handle->sock->type == isc_nm_tlsdnssocket);
|
||||
}
|
||||
|
||||
|
|
@ -1667,9 +1756,15 @@ isc_nm_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
|
|||
case isc_nm_tcpdnssocket:
|
||||
isc__nm_tcpdns_send(handle, region, cb, cbarg);
|
||||
break;
|
||||
case isc_nm_tlssocket:
|
||||
isc__nm_tls_send(handle, region, cb, cbarg);
|
||||
break;
|
||||
case isc_nm_tlsdnssocket:
|
||||
isc__nm_tlsdns_send(handle, region, cb, cbarg);
|
||||
break;
|
||||
case isc_nm_httpstream:
|
||||
isc__nm_http_send(handle, region, cb, cbarg);
|
||||
break;
|
||||
default:
|
||||
INSIST(0);
|
||||
ISC_UNREACHABLE();
|
||||
|
|
@ -1697,6 +1792,9 @@ isc_nm_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
|
|||
case isc_nm_tcpdnssocket:
|
||||
isc__nm_tcpdns_read(handle, cb, cbarg);
|
||||
break;
|
||||
case isc_nm_tlssocket:
|
||||
isc__nm_tls_read(handle, cb, cbarg);
|
||||
break;
|
||||
case isc_nm_tlsdnssocket:
|
||||
isc__nm_tlsdns_read(handle, cb, cbarg);
|
||||
break;
|
||||
|
|
@ -1723,6 +1821,9 @@ isc_nm_cancelread(isc_nmhandle_t *handle) {
|
|||
case isc_nm_tlsdnssocket:
|
||||
isc__nm_tlsdns_cancelread(handle);
|
||||
break;
|
||||
case isc_nm_tlssocket:
|
||||
isc__nm_tls_cancelread(handle);
|
||||
break;
|
||||
default:
|
||||
INSIST(0);
|
||||
ISC_UNREACHABLE();
|
||||
|
|
@ -1739,6 +1840,9 @@ isc_nm_pauseread(isc_nmhandle_t *handle) {
|
|||
case isc_nm_tcpsocket:
|
||||
isc__nm_tcp_pauseread(handle);
|
||||
break;
|
||||
case isc_nm_tlssocket:
|
||||
isc__nm_tls_pauseread(handle);
|
||||
break;
|
||||
default:
|
||||
INSIST(0);
|
||||
ISC_UNREACHABLE();
|
||||
|
|
@ -1755,6 +1859,9 @@ isc_nm_resumeread(isc_nmhandle_t *handle) {
|
|||
case isc_nm_tcpsocket:
|
||||
isc__nm_tcp_resumeread(handle);
|
||||
break;
|
||||
case isc_nm_tlssocket:
|
||||
isc__nm_tls_resumeread(handle);
|
||||
break;
|
||||
default:
|
||||
INSIST(0);
|
||||
ISC_UNREACHABLE();
|
||||
|
|
@ -1775,9 +1882,15 @@ isc_nm_stoplistening(isc_nmsocket_t *sock) {
|
|||
case isc_nm_tcplistener:
|
||||
isc__nm_tcp_stoplistening(sock);
|
||||
break;
|
||||
case isc_nm_tlslistener:
|
||||
isc__nm_tls_stoplistening(sock);
|
||||
break;
|
||||
case isc_nm_tlsdnslistener:
|
||||
isc__nm_tlsdns_stoplistening(sock);
|
||||
break;
|
||||
case isc_nm_httplistener:
|
||||
isc__nm_http_stoplistening(sock);
|
||||
break;
|
||||
default:
|
||||
INSIST(0);
|
||||
ISC_UNREACHABLE();
|
||||
|
|
@ -2322,10 +2435,18 @@ nmsocket_type_totext(isc_nmsocket_type type) {
|
|||
return ("isc_nm_tcpdnslistener");
|
||||
case isc_nm_tcpdnssocket:
|
||||
return ("isc_nm_tcpdnssocket");
|
||||
case isc_nm_tlssocket:
|
||||
return ("isc_nm_tlssocket");
|
||||
case isc_nm_tlslistener:
|
||||
return ("isc_nm_tlslistener");
|
||||
case isc_nm_tlsdnslistener:
|
||||
return ("isc_nm_tlsdnslistener");
|
||||
case isc_nm_tlsdnssocket:
|
||||
return ("isc_nm_tlsdnssocket");
|
||||
case isc_nm_httplistener:
|
||||
return ("isc_nm_httplistener");
|
||||
case isc_nm_httpstream:
|
||||
return ("isc_nm_httpstream");
|
||||
default:
|
||||
INSIST(0);
|
||||
ISC_UNREACHABLE();
|
||||
|
|
|
|||
|
|
@ -167,6 +167,27 @@ 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);
|
||||
|
||||
worker = &sock->mgr->workers[sock->tid];
|
||||
|
||||
atomic_store(&sock->connecting, true);
|
||||
|
|
@ -210,7 +231,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);
|
||||
|
|
@ -239,10 +260,13 @@ 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);
|
||||
isc__nm_tcp_close(sock);
|
||||
if (sock->fd != (uv_os_sock_t)(-1)) {
|
||||
isc__nm_tcp_close(sock);
|
||||
}
|
||||
isc__nm_uvreq_put(&req, sock);
|
||||
}
|
||||
|
||||
|
|
@ -309,36 +333,19 @@ 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);
|
||||
|
||||
result = isc__nm_socket_connectiontimeout(fd, timeout);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
|
||||
req = isc__nm_uvreq_get(mgr, sock);
|
||||
req->cb.connect = cb;
|
||||
req->cbarg = cbarg;
|
||||
|
|
@ -1155,8 +1162,8 @@ failure:
|
|||
}
|
||||
|
||||
void
|
||||
isc__nm_tcp_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
|
||||
void *cbarg) {
|
||||
isc__nm_tcp_send(isc_nmhandle_t *handle, const isc_region_t *region,
|
||||
isc_nm_cb_t cb, void *cbarg) {
|
||||
REQUIRE(VALID_NMHANDLE(handle));
|
||||
REQUIRE(VALID_NMSOCK(handle->sock));
|
||||
|
||||
|
|
|
|||
936
lib/isc/netmgr/tlsstream.c
Normal file
936
lib/isc/netmgr/tlsstream.c
Normal file
|
|
@ -0,0 +1,936 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <libgen.h>
|
||||
#include <unistd.h>
|
||||
#include <uv.h>
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include <isc/atomic.h>
|
||||
#include <isc/buffer.h>
|
||||
#include <isc/condition.h>
|
||||
#include <isc/log.h>
|
||||
#include <isc/magic.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/netmgr.h>
|
||||
#include <isc/once.h>
|
||||
#include <isc/quota.h>
|
||||
#include <isc/random.h>
|
||||
#include <isc/refcount.h>
|
||||
#include <isc/region.h>
|
||||
#include <isc/result.h>
|
||||
#include <isc/sockaddr.h>
|
||||
#include <isc/stdtime.h>
|
||||
#include <isc/thread.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#include "netmgr-int.h"
|
||||
#include "uv-compat.h"
|
||||
|
||||
#define TLS_BUF_SIZE 65536
|
||||
|
||||
static isc_result_t
|
||||
tls_error_to_result(int tls_err) {
|
||||
switch (tls_err) {
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
return (ISC_R_EOF);
|
||||
default:
|
||||
return (ISC_R_UNEXPECTED);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tls_do_bio(isc_nmsocket_t *sock);
|
||||
|
||||
static void
|
||||
tls_close_direct(isc_nmsocket_t *sock);
|
||||
|
||||
static void
|
||||
async_tls_do_bio(isc_nmsocket_t *sock);
|
||||
|
||||
/*
|
||||
* The socket is closing, outerhandle has been detached, listener is
|
||||
* inactive, or the netmgr is closing: any operation on it should abort
|
||||
* with ISC_R_CANCELED.
|
||||
*/
|
||||
static bool
|
||||
inactive(isc_nmsocket_t *sock) {
|
||||
return (!isc__nmsocket_active(sock) || atomic_load(&sock->closing) ||
|
||||
sock->outerhandle == NULL ||
|
||||
(sock->listener != NULL &&
|
||||
!isc__nmsocket_active(sock->listener)) ||
|
||||
atomic_load(&sock->mgr->closing));
|
||||
}
|
||||
|
||||
static void
|
||||
update_result(isc_nmsocket_t *sock, const isc_result_t result) {
|
||||
LOCK(&sock->lock);
|
||||
sock->result = result;
|
||||
SIGNAL(&sock->cond);
|
||||
if (!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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
REQUIRE(VALID_NMHANDLE(handle));
|
||||
REQUIRE(VALID_NMSOCK(handle->sock));
|
||||
REQUIRE(VALID_NMSOCK(sock));
|
||||
|
||||
/* XXXWPK TODO */
|
||||
UNUSED(eresult);
|
||||
|
||||
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));
|
||||
|
||||
sock->tlsstream.nsending--;
|
||||
async_tls_do_bio(sock);
|
||||
isc__nmsocket_detach(&sock);
|
||||
}
|
||||
|
||||
static void
|
||||
tls_failed_read_cb(isc_nmsocket_t *sock, isc_nmhandle_t *handle,
|
||||
const isc_result_t result, const bool close) {
|
||||
REQUIRE(VALID_NMSOCK(sock));
|
||||
|
||||
if (!sock->tlsstream.server &&
|
||||
(sock->tlsstream.state == TLS_INIT ||
|
||||
sock->tlsstream.state == TLS_HANDSHAKE) &&
|
||||
sock->connect_cb != NULL)
|
||||
{
|
||||
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);
|
||||
isc_nmhandle_detach(&handle);
|
||||
} else if (sock->recv_cb != NULL) {
|
||||
isc__nm_uvreq_t *req = NULL;
|
||||
req = isc__nm_uvreq_get(sock->mgr, sock);
|
||||
req->cb.recv = sock->recv_cb;
|
||||
req->cbarg = sock->recv_cbarg;
|
||||
req->handle = NULL;
|
||||
if (handle) {
|
||||
REQUIRE(VALID_NMHANDLE(handle));
|
||||
isc_nmhandle_attach(handle, &req->handle);
|
||||
} else {
|
||||
req->handle = isc__nmhandle_get(sock, NULL, NULL);
|
||||
}
|
||||
isc__nmsocket_clearcb(sock);
|
||||
isc__nm_readcb(sock, req, result);
|
||||
}
|
||||
sock->tlsstream.state = TLS_ERROR;
|
||||
|
||||
if (close) {
|
||||
isc__nmsocket_prep_destroy(sock);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
async_tls_do_bio(isc_nmsocket_t *sock) {
|
||||
isc__netievent_tlsdobio_t *ievent =
|
||||
isc__nm_get_netievent_tlsdobio(sock->mgr, sock);
|
||||
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
|
||||
(isc__netievent_t *)ievent);
|
||||
}
|
||||
|
||||
static void
|
||||
tls_do_bio(isc_nmsocket_t *sock) {
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
int pending, tls_err = 0;
|
||||
int rv;
|
||||
isc__nm_uvreq_t *req;
|
||||
|
||||
REQUIRE(VALID_NMSOCK(sock));
|
||||
REQUIRE(sock->tid == isc_nm_tid());
|
||||
|
||||
/* We will resume read if TLS layer wants us to */
|
||||
if (sock->outerhandle != NULL) {
|
||||
REQUIRE(VALID_NMHANDLE(sock->outerhandle));
|
||||
isc_nm_pauseread(sock->outerhandle);
|
||||
}
|
||||
|
||||
if (sock->tlsstream.state == TLS_INIT) {
|
||||
(void)SSL_do_handshake(sock->tlsstream.ssl);
|
||||
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;
|
||||
}
|
||||
|
||||
/* Data from TLS to client */
|
||||
char buf[1];
|
||||
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) {
|
||||
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.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);
|
||||
}
|
||||
}
|
||||
|
||||
/* Peek to move the session forward */
|
||||
(void)SSL_peek(sock->tlsstream.ssl, 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;
|
||||
}
|
||||
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);
|
||||
/* We'll continue in tls_senddone */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the potential error code */
|
||||
rv = SSL_peek(sock->tlsstream.ssl, buf, 1);
|
||||
|
||||
if (rv < 0) {
|
||||
tls_err = SSL_get_error(sock->tlsstream.ssl, 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)
|
||||
{
|
||||
isc_nmhandle_t *tlshandle = isc__nmhandle_get(sock, NULL, NULL);
|
||||
if (sock->tlsstream.server) {
|
||||
sock->listener->accept_cb(sock->statichandle,
|
||||
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);
|
||||
}
|
||||
isc_nmhandle_detach(&tlshandle);
|
||||
sock->tlsstream.state = TLS_IO;
|
||||
async_tls_do_bio(sock);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (tls_err) {
|
||||
case 0:
|
||||
return;
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
if (sock->tlsstream.nsending == 0) {
|
||||
/*
|
||||
* Launch tls_do_bio asynchronously. If we're sending
|
||||
* already the send callback will call it.
|
||||
*/
|
||||
async_tls_do_bio(sock);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case SSL_ERROR_WANT_READ:
|
||||
INSIST(VALID_NMHANDLE(sock->outerhandle));
|
||||
isc_nm_resumeread(sock->outerhandle);
|
||||
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;
|
||||
}
|
||||
|
||||
static void
|
||||
tls_readcb(isc_nmhandle_t *handle, isc_result_t result, isc_region_t *region,
|
||||
void *cbarg) {
|
||||
isc_nmsocket_t *tlssock = (isc_nmsocket_t *)cbarg;
|
||||
int rv;
|
||||
|
||||
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);
|
||||
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_do_bio(tlssock);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
initialize_tls(isc_nmsocket_t *sock, bool server) {
|
||||
REQUIRE(sock->tid == isc_nm_tid());
|
||||
|
||||
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);
|
||||
return (ISC_R_TLSERROR);
|
||||
}
|
||||
|
||||
SSL_set_bio(sock->tlsstream.ssl, sock->tlsstream.ssl_bio,
|
||||
sock->tlsstream.ssl_bio);
|
||||
if (server) {
|
||||
SSL_set_accept_state(sock->tlsstream.ssl);
|
||||
} else {
|
||||
SSL_set_connect_state(sock->tlsstream.ssl);
|
||||
}
|
||||
sock->tlsstream.nsending = 0;
|
||||
isc_nm_read(sock->outerhandle, tls_readcb, sock);
|
||||
tls_do_bio(sock);
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
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) {
|
||||
return (result);
|
||||
}
|
||||
|
||||
REQUIRE(VALID_NMHANDLE(handle));
|
||||
REQUIRE(VALID_NMSOCK(handle->sock));
|
||||
REQUIRE(VALID_NMSOCK(tlslistensock));
|
||||
REQUIRE(tlslistensock->type == isc_nm_tlslistener);
|
||||
|
||||
/*
|
||||
* We need to create a 'wrapper' tlssocket for this connection.
|
||||
*/
|
||||
tlssock = isc_mem_get(handle->sock->mgr->mctx, sizeof(*tlssock));
|
||||
isc__nmsocket_init(tlssock, handle->sock->mgr, isc_nm_tlssocket,
|
||||
handle->sock->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);
|
||||
atomic_store(&tlssock->closed, true);
|
||||
isc__nmsocket_detach(&tlssock);
|
||||
return (ISC_R_TLSERROR);
|
||||
}
|
||||
|
||||
tlssock->extrahandlesize = tlslistensock->extrahandlesize;
|
||||
isc__nmsocket_attach(tlslistensock, &tlssock->listener);
|
||||
isc_nmhandle_attach(handle, &tlssock->outerhandle);
|
||||
tlssock->peer = handle->sock->peer;
|
||||
tlssock->read_timeout = atomic_load(&handle->sock->mgr->init);
|
||||
tlssock->tid = isc_nm_tid();
|
||||
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);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
/* TODO: catch failure code, detach tlssock, and log the error */
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc_nm_listentls(isc_nm_t *mgr, isc_nmiface_t *iface,
|
||||
isc_nm_accept_cb_t accept_cb, void *accept_cbarg,
|
||||
size_t extrahandlesize, int backlog, isc_quota_t *quota,
|
||||
SSL_CTX *sslctx, isc_nmsocket_t **sockp) {
|
||||
isc_result_t result;
|
||||
isc_nmsocket_t *tlssock = isc_mem_get(mgr->mctx, sizeof(*tlssock));
|
||||
isc_nmsocket_t *tsock = NULL;
|
||||
|
||||
REQUIRE(VALID_NM(mgr));
|
||||
|
||||
isc__nmsocket_init(tlssock, mgr, isc_nm_tlslistener, 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 will be a TLS 'wrapper' around an unencrypted stream.
|
||||
* We set tlssock->outer to a socket listening for a TCP connection.
|
||||
*/
|
||||
result = isc_nm_listentcp(mgr, iface, tlslisten_acceptcb, tlssock,
|
||||
extrahandlesize, backlog, quota,
|
||||
&tlssock->outer);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
atomic_store(&tlssock->closed, true);
|
||||
isc__nmsocket_detach(&tlssock);
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* wait for listen result */
|
||||
isc__nmsocket_attach(tlssock->outer, &tsock);
|
||||
LOCK(&tlssock->outer->lock);
|
||||
while (tlssock->outer->rchildren != tlssock->outer->nchildren) {
|
||||
WAIT(&tlssock->outer->cond, &tlssock->outer->lock);
|
||||
}
|
||||
result = tlssock->outer->result;
|
||||
tlssock->result = result;
|
||||
atomic_store(&tlssock->active, true);
|
||||
INSIST(tlssock->outer->tlsstream.tlslistener == NULL);
|
||||
isc__nmsocket_attach(tlssock, &tlssock->outer->tlsstream.tlslistener);
|
||||
BROADCAST(&tlssock->outer->scond);
|
||||
UNLOCK(&tlssock->outer->lock);
|
||||
isc__nmsocket_detach(&tsock);
|
||||
INSIST(result != ISC_R_DEFAULT);
|
||||
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
atomic_store(&tlssock->listening, true);
|
||||
*sockp = tlssock;
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
isc__nm_uvreq_put(&req, sock);
|
||||
tls_do_bio(sock);
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
isc__nm_tls_send(isc_nmhandle_t *handle, const isc_region_t *region,
|
||||
isc_nm_cb_t cb, void *cbarg) {
|
||||
isc__netievent_tlssend_t *ievent = NULL;
|
||||
isc__nm_uvreq_t *uvreq = NULL;
|
||||
isc_nmsocket_t *sock = NULL;
|
||||
|
||||
REQUIRE(VALID_NMHANDLE(handle));
|
||||
REQUIRE(VALID_NMSOCK(handle->sock));
|
||||
|
||||
sock = handle->sock;
|
||||
|
||||
REQUIRE(sock->type == isc_nm_tlssocket);
|
||||
|
||||
if (inactive(sock)) {
|
||||
cb(handle, ISC_R_CANCELED, cbarg);
|
||||
return;
|
||||
}
|
||||
|
||||
uvreq = isc__nm_uvreq_get(sock->mgr, sock);
|
||||
isc_nmhandle_attach(handle, &uvreq->handle);
|
||||
uvreq->cb.send = cb;
|
||||
uvreq->cbarg = cbarg;
|
||||
|
||||
uvreq->uvbuf.base = (char *)region->base;
|
||||
uvreq->uvbuf.len = region->length;
|
||||
|
||||
/*
|
||||
* We need to create an event and pass it using async channel
|
||||
*/
|
||||
ievent = isc__nm_get_netievent_tlssend(sock->mgr, sock, uvreq);
|
||||
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
|
||||
(isc__netievent_t *)ievent);
|
||||
}
|
||||
|
||||
void
|
||||
isc__nm_async_tlsstartread(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
isc__netievent_tlsstartread_t *ievent =
|
||||
(isc__netievent_tlsstartread_t *)ev0;
|
||||
isc_nmsocket_t *sock = ievent->sock;
|
||||
|
||||
REQUIRE(sock->tid == isc_nm_tid());
|
||||
UNUSED(worker);
|
||||
|
||||
tls_do_bio(sock);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (inactive(sock)) {
|
||||
cb(handle, ISC_R_NOTCONNECTED, NULL, cbarg);
|
||||
return;
|
||||
}
|
||||
|
||||
sock->recv_cb = cb;
|
||||
sock->recv_cbarg = cbarg;
|
||||
|
||||
ievent = isc__nm_get_netievent_tlsstartread(sock->mgr, sock);
|
||||
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
|
||||
(isc__netievent_t *)ievent);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
if (sock->outerhandle != NULL) {
|
||||
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;
|
||||
atomic_store(&sock->closed, true);
|
||||
isc__nmsocket_detach(&sock);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
isc__nm_tls_close(isc_nmsocket_t *sock) {
|
||||
REQUIRE(VALID_NMSOCK(sock));
|
||||
REQUIRE(sock->type == isc_nm_tlssocket);
|
||||
|
||||
if (!atomic_compare_exchange_strong(&sock->closing, &(bool){ false },
|
||||
true)) {
|
||||
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],
|
||||
(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;
|
||||
|
||||
REQUIRE(ievent->sock->tid == isc_nm_tid());
|
||||
UNUSED(worker);
|
||||
|
||||
tls_close_direct(ievent->sock);
|
||||
}
|
||||
|
||||
void
|
||||
isc__nm_tls_stoplistening(isc_nmsocket_t *sock) {
|
||||
REQUIRE(VALID_NMSOCK(sock));
|
||||
REQUIRE(sock->type == isc_nm_tlslistener);
|
||||
|
||||
atomic_store(&sock->listening, false);
|
||||
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;
|
||||
sock->tlsstream.ctx = NULL;
|
||||
}
|
||||
|
||||
if (sock->outer != NULL) {
|
||||
isc_nm_stoplistening(sock->outer);
|
||||
isc__nmsocket_detach(&sock->outer);
|
||||
}
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc_nm_tlsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
|
||||
isc_nm_cb_t cb, void *cbarg, SSL_CTX *ctx,
|
||||
unsigned int timeout, size_t extrahandlesize) {
|
||||
isc_nmsocket_t *nsock = NULL, *tsock = NULL;
|
||||
isc__netievent_tlsconnect_t *ievent = NULL;
|
||||
isc_result_t result = ISC_R_DEFAULT;
|
||||
|
||||
REQUIRE(VALID_NM(mgr));
|
||||
|
||||
nsock = isc_mem_get(mgr->mctx, sizeof(*nsock));
|
||||
isc__nmsocket_init(nsock, mgr, isc_nm_tlssocket, local);
|
||||
nsock->extrahandlesize = extrahandlesize;
|
||||
nsock->result = ISC_R_DEFAULT;
|
||||
nsock->connect_cb = cb;
|
||||
nsock->connect_cbarg = cbarg;
|
||||
nsock->connect_timeout = timeout;
|
||||
nsock->tlsstream.ctx = ctx;
|
||||
|
||||
ievent = isc__nm_get_netievent_tlsconnect(mgr, nsock);
|
||||
ievent->local = local->addr;
|
||||
ievent->peer = peer->addr;
|
||||
ievent->ctx = ctx;
|
||||
|
||||
isc__nmsocket_attach(nsock, &tsock);
|
||||
if (isc__nm_in_netthread()) {
|
||||
nsock->tid = isc_nm_tid();
|
||||
isc__nm_async_tlsconnect(&mgr->workers[nsock->tid],
|
||||
(isc__netievent_t *)ievent);
|
||||
isc__nm_put_netievent_tlsconnect(mgr, ievent);
|
||||
} else {
|
||||
nsock->tid = isc_random_uniform(mgr->nworkers);
|
||||
isc__nm_enqueue_ievent(&mgr->workers[nsock->tid],
|
||||
(isc__netievent_t *)ievent);
|
||||
}
|
||||
|
||||
LOCK(&nsock->lock);
|
||||
result = nsock->result;
|
||||
while (result == ISC_R_DEFAULT) {
|
||||
WAIT(&nsock->cond, &nsock->lock);
|
||||
result = nsock->result;
|
||||
}
|
||||
atomic_store(&nsock->active, true);
|
||||
BROADCAST(&nsock->scond);
|
||||
UNLOCK(&nsock->lock);
|
||||
INSIST(VALID_NMSOCK(nsock));
|
||||
isc__nmsocket_detach(&tsock);
|
||||
|
||||
INSIST(result != ISC_R_DEFAULT);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
static void
|
||||
tls_connect_cb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
|
||||
isc_nmsocket_t *tlssock = (isc_nmsocket_t *)cbarg;
|
||||
|
||||
REQUIRE(VALID_NMSOCK(tlssock));
|
||||
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
tlssock->connect_cb(handle, result, tlssock->connect_cbarg);
|
||||
update_result(tlssock, result);
|
||||
tls_close_direct(tlssock);
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
isc__nm_async_tlsconnect(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
isc__netievent_tlsconnect_t *ievent =
|
||||
(isc__netievent_tlsconnect_t *)ev0;
|
||||
isc_nmsocket_t *tlssock = ievent->sock;
|
||||
isc_result_t result;
|
||||
int r;
|
||||
isc_nmhandle_t *tlshandle = NULL;
|
||||
|
||||
UNUSED(worker);
|
||||
|
||||
/*
|
||||
* We need to initialize SSL now to reference SSL_CTX properly.
|
||||
*/
|
||||
tlssock->tlsstream.ssl = SSL_new(tlssock->tlsstream.ctx);
|
||||
if (tlssock->tlsstream.ssl == 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,
|
||||
tlssock->connect_timeout, 0);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto error;
|
||||
}
|
||||
return;
|
||||
error:
|
||||
tlshandle = isc__nmhandle_get(tlssock, NULL, NULL);
|
||||
atomic_store(&tlssock->closed, true);
|
||||
tlssock->connect_cb(tlshandle, result, tlssock->connect_cbarg);
|
||||
isc_nmhandle_detach(&tlshandle);
|
||||
update_result(tlssock, result);
|
||||
tls_close_direct(tlssock);
|
||||
}
|
||||
|
||||
void
|
||||
isc__nm_tls_cancelread(isc_nmhandle_t *handle) {
|
||||
isc_nmsocket_t *sock = NULL;
|
||||
isc__netievent_tlscancel_t *ievent = NULL;
|
||||
|
||||
REQUIRE(VALID_NMHANDLE(handle));
|
||||
|
||||
sock = handle->sock;
|
||||
|
||||
REQUIRE(sock->type == isc_nm_tlssocket);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
isc__nm_tls_cleanup_data(isc_nmsocket_t *sock) {
|
||||
if (sock->tlsstream.tlslistener) {
|
||||
REQUIRE(VALID_NMSOCK(sock->tlsstream.tlslistener));
|
||||
isc__nmsocket_detach(&sock->tlsstream.tlslistener);
|
||||
}
|
||||
}
|
||||
|
|
@ -478,8 +478,8 @@ free:
|
|||
* another thread.
|
||||
*/
|
||||
void
|
||||
isc__nm_udp_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
|
||||
void *cbarg) {
|
||||
isc__nm_udp_send(isc_nmhandle_t *handle, const isc_region_t *region,
|
||||
isc_nm_cb_t cb, void *cbarg) {
|
||||
isc_nmsocket_t *sock = handle->sock;
|
||||
isc_nmsocket_t *psock = NULL, *rsock = sock;
|
||||
isc_sockaddr_t *peer = &handle->peer;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ TESTS = \
|
|||
buffer_test \
|
||||
counter_test \
|
||||
crc64_test \
|
||||
doh_test \
|
||||
errno_test \
|
||||
file_test \
|
||||
hash_test \
|
||||
|
|
@ -44,17 +45,27 @@ TESTS = \
|
|||
symtab_test \
|
||||
task_test \
|
||||
taskpool_test \
|
||||
tcp_test \
|
||||
tcp_quota_test \
|
||||
tcp_test \
|
||||
tcpdns_test \
|
||||
tlsdns_test \
|
||||
time_test \
|
||||
timer_test \
|
||||
tlsdns_test \
|
||||
udp_test
|
||||
|
||||
check_PROGRAMS = \
|
||||
$(TESTS)
|
||||
|
||||
doh_test_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(LIBUV_CFLAGS) \
|
||||
$(OPENSSL_CFLAGS)
|
||||
|
||||
doh_test_LDADD = \
|
||||
$(LDADD) \
|
||||
$(LIBUV_LIBS) \
|
||||
$(OPENSSL_LIBS)
|
||||
|
||||
hmac_test_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(OPENSSL_CFLAGS)
|
||||
|
|
@ -77,8 +88,8 @@ random_test_LDADD = \
|
|||
|
||||
tcp_test_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(OPENSSL_CFLAGS) \
|
||||
$(LIBUV_CFLAGS)
|
||||
$(LIBUV_CFLAGS) \
|
||||
$(OPENSSL_CFLAGS)
|
||||
|
||||
tcp_test_LDADD = \
|
||||
$(LDADD) \
|
||||
|
|
@ -86,8 +97,8 @@ tcp_test_LDADD = \
|
|||
|
||||
tcp_quota_test_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(OPENSSL_CFLAGS) \
|
||||
$(LIBUV_CFLAGS)
|
||||
$(LIBUV_CFLAGS) \
|
||||
$(OPENSSL_CFLAGS)
|
||||
|
||||
tcp_quota_test_LDADD = \
|
||||
$(LDADD) \
|
||||
|
|
@ -95,8 +106,8 @@ tcp_quota_test_LDADD = \
|
|||
|
||||
tcpdns_test_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(OPENSSL_CFLAGS) \
|
||||
$(LIBUV_CFLAGS)
|
||||
$(LIBUV_CFLAGS) \
|
||||
$(OPENSSL_CFLAGS)
|
||||
|
||||
tcpdns_test_LDADD = \
|
||||
$(LDADD) \
|
||||
|
|
@ -104,8 +115,8 @@ tcpdns_test_LDADD = \
|
|||
|
||||
tlsdns_test_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(OPENSSL_CFLAGS) \
|
||||
$(LIBUV_CFLAGS)
|
||||
$(LIBUV_CFLAGS) \
|
||||
$(OPENSSL_CFLAGS)
|
||||
|
||||
tlsdns_test_LDADD = \
|
||||
$(LDADD) \
|
||||
|
|
@ -113,8 +124,8 @@ tlsdns_test_LDADD = \
|
|||
|
||||
udp_test_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(OPENSSL_CFLAGS) \
|
||||
$(LIBUV_CFLAGS)
|
||||
$(LIBUV_CFLAGS) \
|
||||
$(OPENSSL_CFLAGS)
|
||||
|
||||
udp_test_LDADD = \
|
||||
$(LDADD) \
|
||||
|
|
|
|||
1771
lib/isc/tests/doh_test.c
Normal file
1771
lib/isc/tests/doh_test.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -127,8 +127,10 @@ isc_tlsctx_createclient(isc_tlsctx_t **ctxp) {
|
|||
#if HAVE_SSL_CTX_SET_MIN_PROTO_VERSION
|
||||
SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
|
||||
#else
|
||||
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
|
||||
SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1);
|
||||
SSL_CTX_set_options(
|
||||
ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 |
|
||||
SSL_OP_NO_TLSv1_1 | SSL_OP_NO_COMPRESSION |
|
||||
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
|
||||
#endif
|
||||
|
||||
*ctxp = ctx;
|
||||
|
|
|
|||
667
lib/isc/url.c
Normal file
667
lib/isc/url.c
Normal file
|
|
@ -0,0 +1,667 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <isc/url.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#ifndef BIT_AT
|
||||
#define BIT_AT(a, i) \
|
||||
(!!((unsigned int)(a)[(unsigned int)(i) >> 3] & \
|
||||
(1 << ((unsigned int)(i)&7))))
|
||||
#endif
|
||||
|
||||
#if HTTP_PARSER_STRICT
|
||||
#define T(v) 0
|
||||
#else
|
||||
#define T(v) v
|
||||
#endif
|
||||
|
||||
static const uint8_t normal_url_char[32] = {
|
||||
/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */
|
||||
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
|
||||
/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */
|
||||
0 | T(2) | 0 | 0 | T(16) | 0 | 0 | 0,
|
||||
/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */
|
||||
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
|
||||
/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */
|
||||
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
|
||||
/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */
|
||||
0 | 2 | 4 | 0 | 16 | 32 | 64 | 128,
|
||||
/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */
|
||||
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||
/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */
|
||||
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||
/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */
|
||||
1 | 2 | 4 | 8 | 16 | 32 | 64 | 0,
|
||||
/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */
|
||||
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||
/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */
|
||||
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||
/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */
|
||||
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||
/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */
|
||||
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||
/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */
|
||||
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||
/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */
|
||||
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||
/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */
|
||||
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||
/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
|
||||
1 | 2 | 4 | 8 | 16 | 32 | 64 | 0,
|
||||
};
|
||||
|
||||
#undef T
|
||||
|
||||
typedef enum {
|
||||
s_dead = 1, /* important that this is > 0 */
|
||||
|
||||
s_start_req_or_res,
|
||||
s_res_or_resp_H,
|
||||
s_start_res,
|
||||
s_res_H,
|
||||
s_res_HT,
|
||||
s_res_HTT,
|
||||
s_res_HTTP,
|
||||
s_res_http_major,
|
||||
s_res_http_dot,
|
||||
s_res_http_minor,
|
||||
s_res_http_end,
|
||||
s_res_first_status_code,
|
||||
s_res_status_code,
|
||||
s_res_status_start,
|
||||
s_res_status,
|
||||
s_res_line_almost_done,
|
||||
|
||||
s_start_req,
|
||||
|
||||
s_req_method,
|
||||
s_req_spaces_before_url,
|
||||
s_req_schema,
|
||||
s_req_schema_slash,
|
||||
s_req_schema_slash_slash,
|
||||
s_req_server_start,
|
||||
s_req_server,
|
||||
s_req_server_with_at,
|
||||
s_req_path,
|
||||
s_req_query_string_start,
|
||||
s_req_query_string,
|
||||
s_req_fragment_start,
|
||||
s_req_fragment,
|
||||
s_req_http_start,
|
||||
s_req_http_H,
|
||||
s_req_http_HT,
|
||||
s_req_http_HTT,
|
||||
s_req_http_HTTP,
|
||||
s_req_http_I,
|
||||
s_req_http_IC,
|
||||
s_req_http_major,
|
||||
s_req_http_dot,
|
||||
s_req_http_minor,
|
||||
s_req_http_end,
|
||||
s_req_line_almost_done,
|
||||
|
||||
s_header_field_start,
|
||||
s_header_field,
|
||||
s_header_value_discard_ws,
|
||||
s_header_value_discard_ws_almost_done,
|
||||
s_header_value_discard_lws,
|
||||
s_header_value_start,
|
||||
s_header_value,
|
||||
s_header_value_lws,
|
||||
|
||||
s_header_almost_done,
|
||||
|
||||
s_chunk_size_start,
|
||||
s_chunk_size,
|
||||
s_chunk_parameters,
|
||||
s_chunk_size_almost_done,
|
||||
|
||||
s_headers_almost_done,
|
||||
s_headers_done,
|
||||
|
||||
/*
|
||||
* Important: 's_headers_done' must be the last 'header' state. All
|
||||
* states beyond this must be 'body' states. It is used for overflow
|
||||
* checking. See the PARSING_HEADER() macro.
|
||||
*/
|
||||
|
||||
s_chunk_data,
|
||||
s_chunk_data_almost_done,
|
||||
s_chunk_data_done,
|
||||
|
||||
s_body_identity,
|
||||
s_body_identity_eof,
|
||||
|
||||
s_message_done
|
||||
} state_t;
|
||||
|
||||
typedef enum {
|
||||
s_http_host_dead = 1,
|
||||
s_http_userinfo_start,
|
||||
s_http_userinfo,
|
||||
s_http_host_start,
|
||||
s_http_host_v6_start,
|
||||
s_http_host,
|
||||
s_http_host_v6,
|
||||
s_http_host_v6_end,
|
||||
s_http_host_v6_zone_start,
|
||||
s_http_host_v6_zone,
|
||||
s_http_host_port_start,
|
||||
s_http_host_port
|
||||
} host_state_t;
|
||||
|
||||
/* Macros for character classes; depends on strict-mode */
|
||||
#define IS_MARK(c) \
|
||||
((c) == '-' || (c) == '_' || (c) == '.' || (c) == '!' || (c) == '~' || \
|
||||
(c) == '*' || (c) == '\'' || (c) == '(' || (c) == ')')
|
||||
#define IS_USERINFO_CHAR(c) \
|
||||
(isalnum(c) || IS_MARK(c) || (c) == '%' || (c) == ';' || (c) == ':' || \
|
||||
(c) == '&' || (c) == '=' || (c) == '+' || (c) == '$' || (c) == ',')
|
||||
|
||||
#if HTTP_PARSER_STRICT
|
||||
#define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c))
|
||||
#define IS_HOST_CHAR(c) (isalnum(c) || (c) == '.' || (c) == '-')
|
||||
#else
|
||||
#define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c) || ((c)&0x80))
|
||||
#define IS_HOST_CHAR(c) (isalnum(c) || (c) == '.' || (c) == '-' || (c) == '_')
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Our URL parser.
|
||||
*
|
||||
* This is designed to be shared by http_parser_execute() for URL validation,
|
||||
* hence it has a state transition + byte-for-byte interface. In addition, it
|
||||
* is meant to be embedded in http_parser_parse_url(), which does the dirty
|
||||
* work of turning state transitions URL components for its API.
|
||||
*
|
||||
* This function should only be invoked with non-space characters. It is
|
||||
* assumed that the caller cares about (and can detect) the transition between
|
||||
* URL and non-URL states by looking for these.
|
||||
*/
|
||||
static state_t
|
||||
parse_url_char(state_t s, const char ch) {
|
||||
if (ch == ' ' || ch == '\r' || ch == '\n') {
|
||||
return (s_dead);
|
||||
}
|
||||
|
||||
#if HTTP_PARSER_STRICT
|
||||
if (ch == '\t' || ch == '\f') {
|
||||
return (s_dead);
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (s) {
|
||||
case s_req_spaces_before_url:
|
||||
/* Proxied requests are followed by scheme of an absolute URI
|
||||
* (alpha). All methods except CONNECT are followed by '/' or
|
||||
* '*'.
|
||||
*/
|
||||
|
||||
if (ch == '/' || ch == '*') {
|
||||
return (s_req_path);
|
||||
}
|
||||
|
||||
if (isalpha(ch)) {
|
||||
return (s_req_schema);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case s_req_schema:
|
||||
if (isalpha(ch)) {
|
||||
return (s);
|
||||
}
|
||||
|
||||
if (ch == ':') {
|
||||
return (s_req_schema_slash);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case s_req_schema_slash:
|
||||
if (ch == '/') {
|
||||
return (s_req_schema_slash_slash);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case s_req_schema_slash_slash:
|
||||
if (ch == '/') {
|
||||
return (s_req_server_start);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case s_req_server_with_at:
|
||||
if (ch == '@') {
|
||||
return (s_dead);
|
||||
}
|
||||
|
||||
/* FALLTHROUGH */
|
||||
case s_req_server_start:
|
||||
case s_req_server:
|
||||
if (ch == '/') {
|
||||
return (s_req_path);
|
||||
}
|
||||
|
||||
if (ch == '?') {
|
||||
return (s_req_query_string_start);
|
||||
}
|
||||
|
||||
if (ch == '@') {
|
||||
return (s_req_server_with_at);
|
||||
}
|
||||
|
||||
if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') {
|
||||
return (s_req_server);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case s_req_path:
|
||||
if (IS_URL_CHAR(ch)) {
|
||||
return (s);
|
||||
}
|
||||
|
||||
switch (ch) {
|
||||
case '?':
|
||||
return (s_req_query_string_start);
|
||||
|
||||
case '#':
|
||||
return (s_req_fragment_start);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case s_req_query_string_start:
|
||||
case s_req_query_string:
|
||||
if (IS_URL_CHAR(ch)) {
|
||||
return (s_req_query_string);
|
||||
}
|
||||
|
||||
switch (ch) {
|
||||
case '?':
|
||||
/* allow extra '?' in query string */
|
||||
return (s_req_query_string);
|
||||
|
||||
case '#':
|
||||
return (s_req_fragment_start);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case s_req_fragment_start:
|
||||
if (IS_URL_CHAR(ch)) {
|
||||
return (s_req_fragment);
|
||||
}
|
||||
|
||||
switch (ch) {
|
||||
case '?':
|
||||
return (s_req_fragment);
|
||||
|
||||
case '#':
|
||||
return (s);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case s_req_fragment:
|
||||
if (IS_URL_CHAR(ch)) {
|
||||
return (s);
|
||||
}
|
||||
|
||||
switch (ch) {
|
||||
case '?':
|
||||
case '#':
|
||||
return (s);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* We should never fall out of the switch above unless there's an
|
||||
* error.
|
||||
*/
|
||||
return (s_dead);
|
||||
}
|
||||
|
||||
static host_state_t
|
||||
http_parse_host_char(host_state_t s, const char ch) {
|
||||
switch (s) {
|
||||
case s_http_userinfo:
|
||||
case s_http_userinfo_start:
|
||||
if (ch == '@') {
|
||||
return (s_http_host_start);
|
||||
}
|
||||
|
||||
if (IS_USERINFO_CHAR(ch)) {
|
||||
return (s_http_userinfo);
|
||||
}
|
||||
break;
|
||||
|
||||
case s_http_host_start:
|
||||
if (ch == '[') {
|
||||
return (s_http_host_v6_start);
|
||||
}
|
||||
|
||||
if (IS_HOST_CHAR(ch)) {
|
||||
return (s_http_host);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case s_http_host:
|
||||
if (IS_HOST_CHAR(ch)) {
|
||||
return (s_http_host);
|
||||
}
|
||||
|
||||
/* FALLTHROUGH */
|
||||
case s_http_host_v6_end:
|
||||
if (ch == ':') {
|
||||
return (s_http_host_port_start);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case s_http_host_v6:
|
||||
if (ch == ']') {
|
||||
return (s_http_host_v6_end);
|
||||
}
|
||||
|
||||
/* FALLTHROUGH */
|
||||
case s_http_host_v6_start:
|
||||
if (isxdigit(ch) || ch == ':' || ch == '.') {
|
||||
return (s_http_host_v6);
|
||||
}
|
||||
|
||||
if (s == s_http_host_v6 && ch == '%') {
|
||||
return (s_http_host_v6_zone_start);
|
||||
}
|
||||
break;
|
||||
|
||||
case s_http_host_v6_zone:
|
||||
if (ch == ']') {
|
||||
return (s_http_host_v6_end);
|
||||
}
|
||||
|
||||
/* FALLTHROUGH */
|
||||
case s_http_host_v6_zone_start:
|
||||
/* RFC 6874 Zone ID consists of 1*( unreserved / pct-encoded) */
|
||||
if (isalnum(ch) || ch == '%' || ch == '.' || ch == '-' ||
|
||||
ch == '_' || ch == '~')
|
||||
{
|
||||
return (s_http_host_v6_zone);
|
||||
}
|
||||
break;
|
||||
|
||||
case s_http_host_port:
|
||||
case s_http_host_port_start:
|
||||
if (isdigit(ch)) {
|
||||
return (s_http_host_port);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (s_http_host_dead);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
http_parse_host(const char *buf, isc_url_parser_t *up, int found_at) {
|
||||
host_state_t s;
|
||||
const char *p = NULL;
|
||||
size_t buflen = up->field_data[ISC_UF_HOST].off +
|
||||
up->field_data[ISC_UF_HOST].len;
|
||||
|
||||
REQUIRE((up->field_set & (1 << ISC_UF_HOST)) != 0);
|
||||
|
||||
up->field_data[ISC_UF_HOST].len = 0;
|
||||
|
||||
s = found_at ? s_http_userinfo_start : s_http_host_start;
|
||||
|
||||
for (p = buf + up->field_data[ISC_UF_HOST].off; p < buf + buflen; p++) {
|
||||
host_state_t new_s = http_parse_host_char(s, *p);
|
||||
|
||||
if (new_s == s_http_host_dead) {
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
|
||||
switch (new_s) {
|
||||
case s_http_host:
|
||||
if (s != s_http_host) {
|
||||
up->field_data[ISC_UF_HOST].off =
|
||||
(uint16_t)(p - buf);
|
||||
}
|
||||
up->field_data[ISC_UF_HOST].len++;
|
||||
break;
|
||||
|
||||
case s_http_host_v6:
|
||||
if (s != s_http_host_v6) {
|
||||
up->field_data[ISC_UF_HOST].off =
|
||||
(uint16_t)(p - buf);
|
||||
}
|
||||
up->field_data[ISC_UF_HOST].len++;
|
||||
break;
|
||||
|
||||
case s_http_host_v6_zone_start:
|
||||
case s_http_host_v6_zone:
|
||||
up->field_data[ISC_UF_HOST].len++;
|
||||
break;
|
||||
|
||||
case s_http_host_port:
|
||||
if (s != s_http_host_port) {
|
||||
up->field_data[ISC_UF_PORT].off =
|
||||
(uint16_t)(p - buf);
|
||||
up->field_data[ISC_UF_PORT].len = 0;
|
||||
up->field_set |= (1 << ISC_UF_PORT);
|
||||
}
|
||||
up->field_data[ISC_UF_PORT].len++;
|
||||
break;
|
||||
|
||||
case s_http_userinfo:
|
||||
if (s != s_http_userinfo) {
|
||||
up->field_data[ISC_UF_USERINFO].off =
|
||||
(uint16_t)(p - buf);
|
||||
up->field_data[ISC_UF_USERINFO].len = 0;
|
||||
up->field_set |= (1 << ISC_UF_USERINFO);
|
||||
}
|
||||
up->field_data[ISC_UF_USERINFO].len++;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
s = new_s;
|
||||
}
|
||||
|
||||
/* Make sure we don't end somewhere unexpected */
|
||||
switch (s) {
|
||||
case s_http_host_start:
|
||||
case s_http_host_v6_start:
|
||||
case s_http_host_v6:
|
||||
case s_http_host_v6_zone_start:
|
||||
case s_http_host_v6_zone:
|
||||
case s_http_host_port_start:
|
||||
case s_http_userinfo:
|
||||
case s_http_userinfo_start:
|
||||
return (ISC_R_FAILURE);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc_url_parse(const char *buf, size_t buflen, bool is_connect,
|
||||
isc_url_parser_t *up) {
|
||||
state_t s;
|
||||
isc_url_field_t uf, old_uf;
|
||||
int found_at = 0;
|
||||
const char *p = NULL;
|
||||
|
||||
if (buflen == 0) {
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
|
||||
up->port = up->field_set = 0;
|
||||
s = is_connect ? s_req_server_start : s_req_spaces_before_url;
|
||||
old_uf = ISC_UF_MAX;
|
||||
|
||||
for (p = buf; p < buf + buflen; p++) {
|
||||
s = parse_url_char(s, *p);
|
||||
|
||||
/* Figure out the next field that we're operating on */
|
||||
switch (s) {
|
||||
case s_dead:
|
||||
return (ISC_R_FAILURE);
|
||||
|
||||
/* Skip delimiters */
|
||||
case s_req_schema_slash:
|
||||
case s_req_schema_slash_slash:
|
||||
case s_req_server_start:
|
||||
case s_req_query_string_start:
|
||||
case s_req_fragment_start:
|
||||
continue;
|
||||
|
||||
case s_req_schema:
|
||||
uf = ISC_UF_SCHEMA;
|
||||
break;
|
||||
|
||||
case s_req_server_with_at:
|
||||
found_at = 1;
|
||||
/* FALLTHROUGH */
|
||||
case s_req_server:
|
||||
uf = ISC_UF_HOST;
|
||||
break;
|
||||
|
||||
case s_req_path:
|
||||
uf = ISC_UF_PATH;
|
||||
break;
|
||||
|
||||
case s_req_query_string:
|
||||
uf = ISC_UF_QUERY;
|
||||
break;
|
||||
|
||||
case s_req_fragment:
|
||||
uf = ISC_UF_FRAGMENT;
|
||||
break;
|
||||
|
||||
default:
|
||||
INSIST(0);
|
||||
ISC_UNREACHABLE();
|
||||
}
|
||||
|
||||
/* Nothing's changed; soldier on */
|
||||
if (uf == old_uf) {
|
||||
up->field_data[uf].len++;
|
||||
continue;
|
||||
}
|
||||
|
||||
up->field_data[uf].off = (uint16_t)(p - buf);
|
||||
up->field_data[uf].len = 1;
|
||||
|
||||
up->field_set |= (1 << uf);
|
||||
old_uf = uf;
|
||||
}
|
||||
|
||||
/* host must be present if there is a schema */
|
||||
/* parsing http:///toto will fail */
|
||||
if ((up->field_set & (1 << ISC_UF_SCHEMA)) &&
|
||||
(up->field_set & (1 << ISC_UF_HOST)) == 0)
|
||||
{
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
|
||||
if (up->field_set & (1 << ISC_UF_HOST)) {
|
||||
isc_result_t result;
|
||||
|
||||
result = http_parse_host(buf, up, found_at);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return (result);
|
||||
}
|
||||
}
|
||||
|
||||
/* CONNECT requests can only contain "hostname:port" */
|
||||
if (is_connect &&
|
||||
up->field_set != ((1 << ISC_UF_HOST) | (1 << ISC_UF_PORT))) {
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
|
||||
if (up->field_set & (1 << ISC_UF_PORT)) {
|
||||
uint16_t off;
|
||||
uint16_t len;
|
||||
const char *pp = NULL;
|
||||
const char *end = NULL;
|
||||
unsigned long v;
|
||||
|
||||
off = up->field_data[ISC_UF_PORT].off;
|
||||
len = up->field_data[ISC_UF_PORT].len;
|
||||
end = buf + off + len;
|
||||
|
||||
/*
|
||||
* NOTE: The characters are already validated and are in the
|
||||
* [0-9] range
|
||||
*/
|
||||
INSIST(off + len <= buflen);
|
||||
|
||||
v = 0;
|
||||
for (pp = buf + off; pp < end; pp++) {
|
||||
v *= 10;
|
||||
v += *pp - '0';
|
||||
|
||||
/* Ports have a max value of 2^16 */
|
||||
if (v > 0xffff) {
|
||||
return (ISC_R_RANGE);
|
||||
}
|
||||
}
|
||||
|
||||
up->port = (uint16_t)v;
|
||||
}
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
|
@ -448,7 +448,14 @@ 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_httpconnect
|
||||
isc_nm_httprequest
|
||||
isc_nm_listenhttp
|
||||
isc_nm_listentcpdns
|
||||
isc_nm_listentls
|
||||
isc_nm_listentlsdns
|
||||
isc_nm_listentcp
|
||||
isc_nm_listenudp
|
||||
|
|
@ -706,6 +713,7 @@ isc_tlsctx_createserver
|
|||
isc_tlsctx_free
|
||||
isc_tm_timegm
|
||||
isc_tm_strptime
|
||||
isc_url_parse
|
||||
isc_utf8_bom
|
||||
isc_utf8_valid
|
||||
isc_win32os_versioncheck
|
||||
|
|
|
|||
|
|
@ -260,6 +260,9 @@
|
|||
<ClInclude Include="..\include\isc\types.h">
|
||||
<Filter>Library Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\include\isc\url.h">
|
||||
<Filter>Library Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\include\isc\utf8.h">
|
||||
<Filter>Library Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
|
@ -608,12 +611,15 @@
|
|||
<ClCompile Include="..\timer.c">
|
||||
<Filter>Library Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\tls.c">
|
||||
<ClCompile Include="..\tlsstream.c">
|
||||
<Filter>Library Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\tm.c">
|
||||
<Filter>Library Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\url.c">
|
||||
<Filter>Library Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\utf8.c">
|
||||
<Filter>Library Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
|
|
|||
|
|
@ -62,11 +62,11 @@
|
|||
@IF PKCS11
|
||||
<PreprocessorDefinitions>BIND9;@PK11_LIB_LOCATION@WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBISC_EXPORTS;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ForcedIncludeFiles>..\..\..\config.h</ForcedIncludeFiles>
|
||||
<AdditionalIncludeDirectories>.\;..\..\..\;@LIBXML2_INC@@LIBUV_INC@@OPENSSL_INC@@ZLIB_INC@include;..\include;..\;win32;..\..\isccfg\include;..\..\dns\win32\include;..\..\dns\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>.\;..\..\..\;@LIBXML2_INC@@LIBUV_INC@@NGHTTP2_INC@@OPENSSL_INC@@ZLIB_INC@include;..\include;..\;win32;..\..\isccfg\include;..\..\dns\win32\include;..\..\dns\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
@ELSE PKCS11
|
||||
<PreprocessorDefinitions>BIND9;WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBISC_EXPORTS;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ForcedIncludeFiles>..\..\..\config.h</ForcedIncludeFiles>
|
||||
<AdditionalIncludeDirectories>.\;..\..\..\;@LIBXML2_INC@@LIBUV_INC@@OPENSSL_INC@@ZLIB_INC@include;..\include;..\;win32;..\..\isccfg\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>.\;..\..\..\;@LIBXML2_INC@@LIBUV_INC@@NGHTTP2_INC@@OPENSSL_INC@@ZLIB_INC@include;..\include;..\;win32;..\..\isccfg\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
@END PKCS11
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<PrecompiledHeaderOutputFile>.\$(Configuration)\$(TargetName).pch</PrecompiledHeaderOutputFile>
|
||||
|
|
@ -80,7 +80,7 @@
|
|||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<OutputFile>..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt)</OutputFile>
|
||||
<AdditionalDependencies>@OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@@LIBUV_LIB@@LIBXML2_LIB@@ZLIB_LIB@ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>@OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@@LIBUV_LIB@@NGHTTP2_LIB@@LIBXML2_LIB@@ZLIB_LIB@ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ModuleDefinitionFile>$(ProjectName).def</ModuleDefinitionFile>
|
||||
<ImportLibrary>.\$(Configuration)\$(ProjectName).lib</ImportLibrary>
|
||||
</Link>
|
||||
|
|
@ -116,6 +116,9 @@ echo Copying the libxml DLL.
|
|||
copy @LIBXML2_DLL@ ..\Build\Debug\
|
||||
@END LIBXML2
|
||||
|
||||
echo Copying nghttp2 DLL.
|
||||
copy @NGHTTP2_DLL@ ..\Build\Debug\
|
||||
|
||||
@IF GSSAPI
|
||||
echo Copying the GSSAPI and KRB5 DLLs.
|
||||
|
||||
|
|
@ -163,11 +166,11 @@ copy InstallFiles ..\Build\Debug\
|
|||
@IF PKCS11
|
||||
<PreprocessorDefinitions>BIND9;@PK11_LIB_LOCATION@WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBISC_EXPORTS;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ForcedIncludeFiles>..\..\..\config.h</ForcedIncludeFiles>
|
||||
<AdditionalIncludeDirectories>.\;..\..\..\;@LIBXML2_INC@@LIBUV_INC@@OPENSSL_INC@@ZLIB_INC@include;..\include;..\;win32;..\..\isccfg\include;..\..\dns\win32\include;..\..\dns\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>.\;..\..\..\;@LIBXML2_INC@@LIBUV_INC@@NGHTTP2_INC@@OPENSSL_INC@@ZLIB_INC@include;..\include;..\;win32;..\..\isccfg\include;..\..\dns\win32\include;..\..\dns\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
@ELSE PKCS11
|
||||
<PreprocessorDefinitions>BIND9;WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBISC_EXPORTS;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ForcedIncludeFiles>..\..\..\config.h</ForcedIncludeFiles>
|
||||
<AdditionalIncludeDirectories>.\;..\..\..\;@LIBXML2_INC@@LIBUV_INC@@OPENSSL_INC@@ZLIB_INC@include;..\include;..\;win32;..\..\isccfg\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>.\;..\..\..\;@LIBXML2_INC@@LIBUV_INC@@NGHTTP2_INC@@OPENSSL_INC@@ZLIB_INC@include;..\include;..\;win32;..\..\isccfg\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
@END PKCS11
|
||||
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
|
|
@ -184,7 +187,7 @@ copy InstallFiles ..\Build\Debug\
|
|||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<OutputFile>..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt)</OutputFile>
|
||||
<AdditionalDependencies>@OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@@LIBUV_LIB@@LIBXML2_LIB@@ZLIB_LIB@ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>@OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@@LIBUV_LIB@@NGHTTP2_LIB@@LIBXML2_LIB@@ZLIB_LIB@ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ModuleDefinitionFile>$(ProjectName).def</ModuleDefinitionFile>
|
||||
<ImportLibrary>.\$(Configuration)\$(ProjectName).lib</ImportLibrary>
|
||||
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
|
||||
|
|
@ -211,6 +214,9 @@ copy @OPENSSL_PATH@\LICENSE ..\Build\Release\OpenSSL-LICENSE
|
|||
echo Copying libuv DLL.
|
||||
copy @LIBUV_DLL@ ..\Build\Release\
|
||||
|
||||
echo Copying nghttp2 DLL.
|
||||
copy @NGHTTP2_DLL@ ..\Build\Release\
|
||||
|
||||
@IF LIBXML2
|
||||
echo Copying the libxml DLL.
|
||||
|
||||
|
|
@ -337,6 +343,7 @@ copy InstallFiles ..\Build\Release\
|
|||
<ClInclude Include="..\include\isc\tls.h" />
|
||||
<ClInclude Include="..\include\isc\tm.h" />
|
||||
<ClInclude Include="..\include\isc\types.h" />
|
||||
<ClInclude Include="..\include\isc\url.h" />
|
||||
<ClInclude Include="..\include\isc\utf8.h" />
|
||||
<ClInclude Include="..\include\isc\util.h" />
|
||||
@IF PKCS11
|
||||
|
|
@ -408,13 +415,15 @@ copy InstallFiles ..\Build\Release\
|
|||
<ClCompile Include="..\mem.c" />
|
||||
<ClCompile Include="..\mutexblock.c" />
|
||||
<ClCompile Include="..\netaddr.c" />
|
||||
<ClCompile Include="..\netmgr\http.c" />
|
||||
<ClCompile Include="..\netmgr\netmgr.c" />
|
||||
<ClCompile Include="..\netmgr\tcp.c" />
|
||||
<ClCompile Include="..\netmgr\udp.c" />
|
||||
<ClCompile Include="..\netmgr\uverr2result.c" />
|
||||
<ClCompile Include="..\netmgr\uv-compat.c" />
|
||||
<ClCompile Include="..\netmgr\tcpdns.c" />
|
||||
<ClCompile Include="..\netmgr\tlsstream.c" />
|
||||
<ClCompile Include="..\netmgr\udp.c" />
|
||||
<ClCompile Include="..\netmgr\tlsdns.c" />
|
||||
<ClCompile Include="..\netmgr\uv-compat.c" />
|
||||
<ClCompile Include="..\netmgr\uverr2result.c" />
|
||||
<ClCompile Include="..\netscope.c" />
|
||||
<ClCompile Include="..\nonce.c" />
|
||||
<ClCompile Include="..\openssl_shim.c" />
|
||||
|
|
@ -442,6 +451,7 @@ copy InstallFiles ..\Build\Release\
|
|||
<ClCompile Include="..\timer.c" />
|
||||
<ClCompile Include="..\tls.c" />
|
||||
<ClCompile Include="..\tm.c" />
|
||||
<ClCompile Include="..\url.c" />
|
||||
<ClCompile Include="..\utf8.c" />
|
||||
@IF PKCS11
|
||||
<ClCompile Include="..\pk11.c" />
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ static cfg_type_t cfg_type_bracketed_dscpsockaddrlist;
|
|||
static cfg_type_t cfg_type_bracketed_namesockaddrkeylist;
|
||||
static cfg_type_t cfg_type_bracketed_netaddrlist;
|
||||
static cfg_type_t cfg_type_bracketed_sockaddrnameportlist;
|
||||
static cfg_type_t cfg_type_bracketed_qstring_list;
|
||||
static cfg_type_t cfg_type_controls;
|
||||
static cfg_type_t cfg_type_controls_sockaddr;
|
||||
static cfg_type_t cfg_type_destinationlist;
|
||||
|
|
@ -91,6 +92,7 @@ static cfg_type_t cfg_type_dnstap;
|
|||
static cfg_type_t cfg_type_dnstapoutput;
|
||||
static cfg_type_t cfg_type_dyndb;
|
||||
static cfg_type_t cfg_type_plugin;
|
||||
static cfg_type_t cfg_type_http_description;
|
||||
static cfg_type_t cfg_type_ixfrdifftype;
|
||||
static cfg_type_t cfg_type_ixfrratio;
|
||||
static cfg_type_t cfg_type_key;
|
||||
|
|
@ -108,6 +110,7 @@ static cfg_type_t cfg_type_optional_allow;
|
|||
static cfg_type_t cfg_type_optional_class;
|
||||
static cfg_type_t cfg_type_optional_dscp;
|
||||
static cfg_type_t cfg_type_optional_facility;
|
||||
static cfg_type_t cfg_type_optional_http;
|
||||
static cfg_type_t cfg_type_optional_keyref;
|
||||
static cfg_type_t cfg_type_optional_port;
|
||||
static cfg_type_t cfg_type_optional_uint32;
|
||||
|
|
@ -151,6 +154,7 @@ static cfg_tuplefielddef_t listenon_fields[] = {
|
|||
{ "port", &cfg_type_optional_port, 0 },
|
||||
{ "dscp", &cfg_type_optional_dscp, 0 },
|
||||
{ "tls", &cfg_type_optional_tls, 0 },
|
||||
{ "http", &cfg_type_optional_http, 0 },
|
||||
{ "acl", &cfg_type_bracketed_aml, 0 },
|
||||
{ NULL, NULL, 0 }
|
||||
};
|
||||
|
|
@ -1088,6 +1092,7 @@ static cfg_clausedef_t namedconf_clauses[] = {
|
|||
{ "acl", &cfg_type_acl, CFG_CLAUSEFLAG_MULTI },
|
||||
{ "controls", &cfg_type_controls, CFG_CLAUSEFLAG_MULTI },
|
||||
{ "dnssec-policy", &cfg_type_dnssecpolicy, CFG_CLAUSEFLAG_MULTI },
|
||||
{ "http", &cfg_type_http_description, CFG_CLAUSEFLAG_MULTI },
|
||||
{ "logging", &cfg_type_logging, 0 },
|
||||
{ "lwres", NULL, CFG_CLAUSEFLAG_MULTI | CFG_CLAUSEFLAG_ANCIENT },
|
||||
{ "masters", &cfg_type_primaries, CFG_CLAUSEFLAG_MULTI },
|
||||
|
|
@ -1221,6 +1226,8 @@ static cfg_clausedef_t options_clauses[] = {
|
|||
{ "pid-file", &cfg_type_qstringornone, 0 },
|
||||
{ "port", &cfg_type_uint32, 0 },
|
||||
{ "tls-port", &cfg_type_uint32, 0 },
|
||||
{ "http-port", &cfg_type_uint32, 0 },
|
||||
{ "https-port", &cfg_type_uint32, 0 },
|
||||
{ "querylog", &cfg_type_boolean, 0 },
|
||||
{ "random-device", &cfg_type_qstringornone, 0 },
|
||||
{ "recursing-file", &cfg_type_qstring, 0 },
|
||||
|
|
@ -3853,3 +3860,31 @@ static cfg_type_t cfg_type_optional_tls = {
|
|||
"tlsoptional", parse_optional_keyvalue, print_keyvalue,
|
||||
doc_optional_keyvalue, &cfg_rep_string, &tls_kw
|
||||
};
|
||||
|
||||
/* http and https */
|
||||
|
||||
static cfg_type_t cfg_type_bracketed_qstring_list = { "bracketed_qstring_list",
|
||||
cfg_parse_bracketed_list,
|
||||
cfg_print_bracketed_list,
|
||||
cfg_doc_bracketed_list,
|
||||
&cfg_rep_list,
|
||||
&cfg_type_qstring };
|
||||
|
||||
static cfg_clausedef_t cfg_http_description_clauses[] = {
|
||||
{ "endpoints", &cfg_type_bracketed_qstring_list, 0 }, { NULL, NULL, 0 }
|
||||
};
|
||||
|
||||
static cfg_clausedef_t *http_description_clausesets[] = {
|
||||
cfg_http_description_clauses, NULL
|
||||
};
|
||||
|
||||
static cfg_type_t cfg_type_http_description = {
|
||||
"http_desc", cfg_parse_named_map, cfg_print_map,
|
||||
cfg_doc_map, &cfg_rep_map, http_description_clausesets
|
||||
};
|
||||
|
||||
static keyword_type_t http_kw = { "http", &cfg_type_astring };
|
||||
static cfg_type_t cfg_type_optional_http = {
|
||||
"http_optional", parse_optional_keyvalue, print_keyvalue,
|
||||
doc_optional_keyvalue, &cfg_rep_string, &http_kw
|
||||
};
|
||||
|
|
|
|||
|
|
@ -80,6 +80,8 @@ struct ns_interface {
|
|||
isc_socket_t * tcpsocket; /*%< TCP socket. */
|
||||
isc_nmsocket_t *udplistensocket;
|
||||
isc_nmsocket_t *tcplistensocket;
|
||||
isc_nmsocket_t *http_listensocket;
|
||||
isc_nmsocket_t *http_secure_listensocket;
|
||||
isc_dscp_t dscp; /*%< "listen-on" DSCP value */
|
||||
isc_refcount_t ntcpaccepting; /*%< Number of clients
|
||||
* ready to accept new
|
||||
|
|
|
|||
|
|
@ -42,9 +42,12 @@ typedef struct ns_listenlist ns_listenlist_t;
|
|||
struct ns_listenelt {
|
||||
isc_mem_t * mctx;
|
||||
in_port_t port;
|
||||
bool is_http;
|
||||
isc_dscp_t dscp; /* -1 = not set, 0..63 */
|
||||
dns_acl_t * acl;
|
||||
isc_tlsctx_t *sslctx;
|
||||
char ** http_endpoints;
|
||||
size_t http_endpoints_number;
|
||||
ISC_LINK(ns_listenelt_t) link;
|
||||
};
|
||||
|
||||
|
|
@ -66,6 +69,15 @@ ns_listenelt_create(isc_mem_t *mctx, in_port_t port, isc_dscp_t dscp,
|
|||
* Create a listen-on list element.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
ns_listenelt_create_http(isc_mem_t *mctx, in_port_t http_port, isc_dscp_t dscp,
|
||||
dns_acl_t *acl, bool tls, const char *key,
|
||||
const char *cert, char **endpoints, size_t nendpoints,
|
||||
ns_listenelt_t **target);
|
||||
/*%<
|
||||
* Create a listen-on list element for HTTP(S).
|
||||
*/
|
||||
|
||||
void
|
||||
ns_listenelt_destroy(ns_listenelt_t *elt);
|
||||
/*%<
|
||||
|
|
|
|||
|
|
@ -437,6 +437,10 @@ ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
|
|||
goto failure;
|
||||
}
|
||||
|
||||
ifp->tcplistensocket = NULL;
|
||||
ifp->http_listensocket = NULL;
|
||||
ifp->http_secure_listensocket = NULL;
|
||||
|
||||
*ifpret = ifp;
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
|
|
@ -539,6 +543,54 @@ ns_interface_listentls(ns_interface_t *ifp, isc_tlsctx_t *sslctx) {
|
|||
return (result);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
ns_interface_listenhttp(ns_interface_t *ifp, isc_tlsctx_t *sslctx, char **eps,
|
||||
size_t neps) {
|
||||
isc_result_t result;
|
||||
isc_nmsocket_t *sock = NULL;
|
||||
size_t i = 0;
|
||||
|
||||
result = isc_nm_listenhttp(ifp->mgr->nm, (isc_nmiface_t *)&ifp->addr,
|
||||
ifp->mgr->backlog, &ifp->mgr->sctx->tcpquota,
|
||||
sslctx, &sock);
|
||||
|
||||
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,
|
||||
sizeof(ns_client_t));
|
||||
}
|
||||
}
|
||||
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
|
||||
"creating %s socket: %s",
|
||||
sslctx ? "HTTPS" : "HTTP",
|
||||
isc_result_totext(result));
|
||||
return (result);
|
||||
}
|
||||
|
||||
if (sslctx) {
|
||||
ifp->http_secure_listensocket = sock;
|
||||
} else {
|
||||
ifp->http_listensocket = sock;
|
||||
}
|
||||
|
||||
/*
|
||||
* We call this now to update the tcp-highwater statistic:
|
||||
* this is necessary because we are adding to the TCP quota just
|
||||
* by listening.
|
||||
*/
|
||||
result = ns__client_tcpconn(NULL, ISC_R_SUCCESS, ifp);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
|
||||
"updating TCP stats: %s",
|
||||
isc_result_totext(result));
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
ns_interface_setup(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
|
||||
const char *name, ns_interface_t **ifpret, bool accept_tcp,
|
||||
|
|
@ -555,6 +607,17 @@ ns_interface_setup(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
|
|||
|
||||
ifp->dscp = elt->dscp;
|
||||
|
||||
if (elt->is_http) {
|
||||
result = ns_interface_listenhttp(ifp, elt->sslctx,
|
||||
elt->http_endpoints,
|
||||
elt->http_endpoints_number);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup_interface;
|
||||
}
|
||||
*ifpret = ifp;
|
||||
return (result);
|
||||
}
|
||||
|
||||
if (elt->sslctx != NULL) {
|
||||
result = ns_interface_listentls(ifp, elt->sslctx);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
|
|
@ -611,6 +674,14 @@ ns_interface_shutdown(ns_interface_t *ifp) {
|
|||
isc_nm_stoplistening(ifp->tcplistensocket);
|
||||
isc_nmsocket_close(&ifp->tcplistensocket);
|
||||
}
|
||||
if (ifp->http_listensocket != NULL) {
|
||||
isc_nm_stoplistening(ifp->http_listensocket);
|
||||
isc_nmsocket_close(&ifp->http_listensocket);
|
||||
}
|
||||
if (ifp->http_secure_listensocket != NULL) {
|
||||
isc_nm_stoplistening(ifp->http_secure_listensocket);
|
||||
isc_nmsocket_close(&ifp->http_secure_listensocket);
|
||||
}
|
||||
if (ifp->clientmgr != NULL) {
|
||||
ns_clientmgr_destroy(&ifp->clientmgr);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,24 +30,59 @@ ns_listenelt_create(isc_mem_t *mctx, in_port_t port, isc_dscp_t dscp,
|
|||
ns_listenelt_t **target) {
|
||||
ns_listenelt_t *elt = NULL;
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
isc_tlsctx_t *sslctx = NULL;
|
||||
|
||||
REQUIRE(target != NULL && *target == NULL);
|
||||
elt = isc_mem_get(mctx, sizeof(*elt));
|
||||
elt->mctx = mctx;
|
||||
ISC_LINK_INIT(elt, link);
|
||||
elt->port = port;
|
||||
elt->dscp = dscp;
|
||||
elt->acl = acl;
|
||||
elt->sslctx = NULL;
|
||||
|
||||
if (tls) {
|
||||
result = isc_tlsctx_createserver(key, cert, &elt->sslctx);
|
||||
result = isc_tlsctx_createserver(key, cert, &sslctx);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return (result);
|
||||
}
|
||||
}
|
||||
|
||||
elt = isc_mem_get(mctx, sizeof(*elt));
|
||||
elt->mctx = mctx;
|
||||
ISC_LINK_INIT(elt, link);
|
||||
elt->port = port;
|
||||
elt->is_http = false;
|
||||
elt->dscp = dscp;
|
||||
elt->acl = acl;
|
||||
elt->sslctx = sslctx;
|
||||
elt->http_endpoints = NULL;
|
||||
elt->http_endpoints_number = 0;
|
||||
|
||||
*target = elt;
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
ns_listenelt_create_http(isc_mem_t *mctx, in_port_t http_port, isc_dscp_t dscp,
|
||||
dns_acl_t *acl, bool tls, const char *key,
|
||||
const char *cert, char **endpoints, size_t nendpoints,
|
||||
ns_listenelt_t **target) {
|
||||
isc_result_t result;
|
||||
|
||||
REQUIRE(target != NULL && *target == NULL);
|
||||
REQUIRE(endpoints != NULL && *endpoints != NULL);
|
||||
REQUIRE(nendpoints > 0);
|
||||
|
||||
result = ns_listenelt_create(mctx, http_port, dscp, acl, tls, key, cert,
|
||||
target);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
(*target)->is_http = true;
|
||||
(*target)->http_endpoints = endpoints;
|
||||
(*target)->http_endpoints_number = nendpoints;
|
||||
} else {
|
||||
size_t i;
|
||||
for (i = 0; i < nendpoints; i++) {
|
||||
isc_mem_free(mctx, endpoints[i]);
|
||||
}
|
||||
isc_mem_free(mctx, endpoints);
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
void
|
||||
ns_listenelt_destroy(ns_listenelt_t *elt) {
|
||||
if (elt->acl != NULL) {
|
||||
|
|
@ -56,6 +91,14 @@ ns_listenelt_destroy(ns_listenelt_t *elt) {
|
|||
if (elt->sslctx != NULL) {
|
||||
isc_tlsctx_free(&elt->sslctx);
|
||||
}
|
||||
if (elt->http_endpoints != NULL) {
|
||||
size_t i;
|
||||
INSIST(elt->http_endpoints_number > 0);
|
||||
for (i = 0; i < elt->http_endpoints_number; i++) {
|
||||
isc_mem_free(elt->mctx, elt->http_endpoints[i]);
|
||||
}
|
||||
isc_mem_free(elt->mctx, elt->http_endpoints);
|
||||
}
|
||||
isc_mem_put(elt->mctx, elt, sizeof(*elt));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ ns_interfacemgr_shutdown
|
|||
ns_lib_init
|
||||
ns_lib_shutdown
|
||||
ns_listenelt_create
|
||||
ns_listenelt_create_http
|
||||
ns_listenelt_destroy
|
||||
ns_listenlist_attach
|
||||
ns_listenlist_create
|
||||
|
|
|
|||
|
|
@ -1887,6 +1887,7 @@
|
|||
./lib/isc/include/isc/tls.h C 2021
|
||||
./lib/isc/include/isc/tm.h C 2014,2016,2018,2019,2020,2021
|
||||
./lib/isc/include/isc/types.h C 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2012,2013,2014,2016,2017,2018,2019,2020,2021
|
||||
./lib/isc/include/isc/url.h C 2021
|
||||
./lib/isc/include/isc/utf8.h C 2020,2021
|
||||
./lib/isc/include/isc/util.h C 1998,1999,2000,2001,2004,2005,2006,2007,2010,2011,2012,2015,2016,2017,2018,2019,2020,2021
|
||||
./lib/isc/include/pk11/constants.h C 2014,2016,2017,2018,2019,2020,2021
|
||||
|
|
@ -1904,11 +1905,13 @@
|
|||
./lib/isc/mem_p.h C 2018,2019,2020,2021
|
||||
./lib/isc/mutexblock.c C 1999,2000,2001,2004,2005,2007,2011,2012,2016,2018,2019,2020,2021
|
||||
./lib/isc/netaddr.c C 1999,2000,2001,2002,2004,2005,2007,2010,2011,2012,2014,2015,2016,2017,2018,2019,2020,2021
|
||||
./lib/isc/netmgr/http.c C 2021
|
||||
./lib/isc/netmgr/netmgr-int.h C 2019,2020,2021
|
||||
./lib/isc/netmgr/netmgr.c C 2019,2020,2021
|
||||
./lib/isc/netmgr/tcp.c C 2019,2020,2021
|
||||
./lib/isc/netmgr/tcpdns.c C 2019,2020,2021
|
||||
./lib/isc/netmgr/tlsdns.c C 2020,2021
|
||||
./lib/isc/netmgr/tlsstream.c C 2019,2020,2021
|
||||
./lib/isc/netmgr/udp.c C 2019,2020,2021
|
||||
./lib/isc/netmgr/uv-compat.c C 2020,2021
|
||||
./lib/isc/netmgr/uv-compat.h C 2019,2020,2021
|
||||
|
|
@ -1952,6 +1955,7 @@
|
|||
./lib/isc/tests/buffer_test.c C 2014,2015,2016,2017,2018,2019,2020,2021
|
||||
./lib/isc/tests/counter_test.c C 2014,2016,2018,2019,2020,2021
|
||||
./lib/isc/tests/crc64_test.c C 2018,2019,2020,2021
|
||||
./lib/isc/tests/doh_test.c C 2020,2021
|
||||
./lib/isc/tests/errno_test.c C 2016,2018,2019,2020,2021
|
||||
./lib/isc/tests/file_test.c C 2014,2016,2017,2018,2019,2020,2021
|
||||
./lib/isc/tests/hash_test.c C 2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021
|
||||
|
|
@ -2018,6 +2022,7 @@
|
|||
./lib/isc/unix/stdtime.c C 1999,2000,2001,2004,2005,2007,2016,2018,2019,2020,2021
|
||||
./lib/isc/unix/syslog.c C 2001,2004,2005,2007,2016,2018,2019,2020,2021
|
||||
./lib/isc/unix/time.c C 1998,1999,2000,2001,2003,2004,2005,2006,2007,2008,2011,2012,2014,2015,2016,2017,2018,2019,2020,2021
|
||||
./lib/isc/url.c C 2021
|
||||
./lib/isc/utf8.c C 2020,2021
|
||||
./lib/isc/win32/DLLMain.c C 2001,2004,2007,2016,2018,2019,2020,2021
|
||||
./lib/isc/win32/condition.c C 1998,1999,2000,2001,2004,2006,2007,2016,2018,2019,2020,2021
|
||||
|
|
|
|||
|
|
@ -221,6 +221,7 @@ my @substinc = ("GSSAPI_INC",
|
|||
"IDN_INC",
|
||||
"LIBXML2_INC",
|
||||
"LIBUV_INC",
|
||||
"NGHTTP2_INC",
|
||||
"OPENSSL_INC",
|
||||
"READLINE_INC",
|
||||
"ZLIB_INC");
|
||||
|
|
@ -235,6 +236,7 @@ my @substlib = ("GSSAPI_LIB",
|
|||
"KRB5_LIB",
|
||||
"LIBXML2_LIB",
|
||||
"LIBUV_LIB",
|
||||
"NGHTTP2_LIB",
|
||||
"OPENSSL_LIBCRYPTO",
|
||||
"OPENSSL_LIBSSL",
|
||||
"READLINE_LIB",
|
||||
|
|
@ -253,6 +255,7 @@ my @substdll = ("COMERR_DLL",
|
|||
"K5SPRT_DLL",
|
||||
"LIBXML2_DLL",
|
||||
"LIBUV_DLL",
|
||||
"NGHTTP2_DLL",
|
||||
"OPENSSL_DLLCRYPTO",
|
||||
"OPENSSL_DLLSSL",
|
||||
"WSHELP_DLL",
|
||||
|
|
@ -341,6 +344,7 @@ my @withlist = ("aes",
|
|||
"idn",
|
||||
"openssl",
|
||||
"libxml2",
|
||||
"nghttp2",
|
||||
"pkcs11",
|
||||
"pssuspend",
|
||||
"python",
|
||||
|
|
@ -389,6 +393,7 @@ my @help = (
|
|||
" with-samples build with sample programs\n",
|
||||
" with-openssl[=PATH] build with OpenSSL yes|path (mandatory)\n",
|
||||
" with-libuv[=PATH] build with libuv yes|path (mandatory)\n",
|
||||
" with-nghttp2[=PATH] build with nghttp2 yes|path (mandatory)\n",
|
||||
" with-pkcs11[=PATH] build with PKCS#11 support yes|no|provider-path\n",
|
||||
" with-gssapi[=PATH] build with MIT KfW GSSAPI yes|no|path\n",
|
||||
" with-libxml2[=PATH] build with libxml2 library yes|no|path\n",
|
||||
|
|
@ -431,6 +436,8 @@ my $use_stests = "no";
|
|||
my $use_samples = "no";
|
||||
my $use_libuv = "auto";
|
||||
my $libuv_path = "../../";
|
||||
my $nghttp2_path = "../../";
|
||||
my $use_nghttp2 = "auto";
|
||||
my $use_openssl = "auto";
|
||||
my $openssl_path = "../../";
|
||||
my $use_pkcs11 = "no";
|
||||
|
|
@ -758,6 +765,13 @@ sub mywith {
|
|||
$use_libuv = "yes";
|
||||
$libuv_path = $val;
|
||||
}
|
||||
} elsif ($key =~ /^nghttp2$/i) {
|
||||
if ($val =~ /^no$/i) {
|
||||
die "nghttp2 is required\n";
|
||||
} elsif ($val !~ /^yes$/i) {
|
||||
$use_nghttp2 = "yes";
|
||||
$nghttp2_path = $val;
|
||||
}
|
||||
} elsif ($key =~ /^pkcs11$/i) {
|
||||
if ($val =~ /^yes$/i) {
|
||||
$use_pkcs11 = "yes";
|
||||
|
|
@ -949,6 +963,7 @@ if ($verbose) {
|
|||
print "querytrace: disabled\n";
|
||||
}
|
||||
print "libuv-path: $libuv_path\n";
|
||||
print "nghttp2-path: $nghttp2_path\n";
|
||||
print "openssl-path: $openssl_path\n";
|
||||
if ($use_tests eq "yes") {
|
||||
print "tests: enabled\n";
|
||||
|
|
@ -1327,6 +1342,63 @@ if ($use_libuv eq "yes") {
|
|||
# $configdefh{"HAVE_UV_IMPORT"} = 1;
|
||||
}
|
||||
|
||||
# with-nghttp2
|
||||
if ($use_nghttp2 eq "auto") {
|
||||
if ($verbose) {
|
||||
print "checking for an nghttp2 built directory at sibling root\n";
|
||||
}
|
||||
opendir DIR, $nghttp2_path || die "No Directory: $!\n";
|
||||
my @dirlist = grep (/^nghttp2-[0-9]+\.[0-9]+\.[0-9]+$/i, readdir(DIR));
|
||||
closedir(DIR);
|
||||
|
||||
# Make sure we have something
|
||||
if (scalar(@dirlist) == 0) {
|
||||
die "can't find an nghttp2 at sibling root\n";
|
||||
}
|
||||
# Now see if we have a directory or just a file.
|
||||
# Make sure we are case insensitive
|
||||
my $file;
|
||||
foreach $file (sort {uc($b) cmp uc($a)} @dirlist) {
|
||||
if (-f File::Spec->catfile($nghttp2_path,
|
||||
$file,
|
||||
"include", "nghttp2", "nghttp2.h")) {
|
||||
$nghttp2_path = File::Spec->catdir($nghttp2_path, $file);
|
||||
$use_nghttp2 = "yes";
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
# If we have one use it otherwise report the error
|
||||
if ($use_nghttp2 eq "auto") {
|
||||
die "can't find an nghttp2 built directory at sibling root\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ($use_nghttp2 eq "yes") {
|
||||
$nghttp2_path = File::Spec->rel2abs($nghttp2_path);
|
||||
if ($verbose) {
|
||||
print "checking for nghttp2 directory at \"$nghttp2_path\"\n";
|
||||
}
|
||||
if (!-f File::Spec->catfile($nghttp2_path,
|
||||
"include", "nghttp2", "nghttp2.h")) {
|
||||
die "can't find nghttp2 nghttp2.h include\n";
|
||||
}
|
||||
my $nghttp2_inc = File::Spec->catdir($nghttp2_path, "include");
|
||||
my $nghttp2_bindir = File::Spec->catdir($nghttp2_path, "bin");
|
||||
my $nghttp2_libdir = File::Spec->catdir($nghttp2_path, "lib");
|
||||
my $nghttp2_dll = File::Spec->catfile($nghttp2_bindir, "nghttp2.dll");
|
||||
my $nghttp2_lib = File::Spec->catfile($nghttp2_libdir, "nghttp2.lib");
|
||||
if (!-f $nghttp2_lib) {
|
||||
die "can't find nghttp2.lib library\n";
|
||||
}
|
||||
if (!-f $nghttp2_dll) {
|
||||
die "can't find nghttp2.dll library\n";
|
||||
}
|
||||
$configinc{"NGHTTP2_INC"} = "$nghttp2_inc";
|
||||
$configlib{"NGHTTP2_LIB"} = "$nghttp2_lib";
|
||||
$configdll{"NGHTTP2_DLL"} = "$nghttp2_dll";
|
||||
}
|
||||
|
||||
# with-openssl
|
||||
if ($use_openssl eq "auto") {
|
||||
if ($verbose) {
|
||||
|
|
@ -2433,6 +2505,7 @@ sub makeinstallfile {
|
|||
print LOUT "libdns.dll-BCFT\n";
|
||||
print LOUT "libirs.dll-BCFT\n";
|
||||
print LOUT "libns.dll-BCFT\n";
|
||||
print LOUT "nghttp2.dll-BCFT\n";
|
||||
print LOUT "uv.dll-BCFT\n";
|
||||
if ($use_openssl eq "yes") {
|
||||
my $v;
|
||||
|
|
|
|||
Loading…
Reference in a new issue