Compare commits

...
Author SHA1 Message Date
Ondřej SurýandArtem Boldariev b6889fbf10 WIP: Add preliminary DoH client support to dig 2021-02-02 20:20:10 +02:00
Ondřej SurýandArtem Boldariev 81340a9ee0 Unit-test fixes and manual page updates for DoH configuration
This commit contains fixes to unit tests to make them work well on
various platforms (in particular ones shipping old versions of
OpenSSL) and fo different configurations.

It also updates the generated manpage to include DoH configuration
options.
2021-02-02 20:20:10 +02:00
Artem Boldariev bc1b832603 Initial support for DNS-over-HTTP(S)
This commit completes the support for DNS-over-HTTP(S) built on top of
nghttp2 and plugs it into the BIND. Support for both GET and POST
requests is present, as required by RFC8484.

Both encrypted (via TLS) and unencrypted HTTP/2 connections are
supported. The latter are mostly there for debugging/troubleshooting
purposes and for the means of encryption offloading to third-party
software (as might be desirable in some environments to simplify TLS
certificates management).
2021-02-02 20:20:01 +02:00
Witold KręcickiandArtem Boldariev 16966e5174 nghttp2-based HTTP layer in netmgr
This commit includes work-in-progress implementation of
DNS-over-HTTP(S).

Server-side code remains mostly untested, and there is only support
for POST requests.
2021-02-02 20:02:13 +02:00
Witold KręcickiandArtem Boldariev ba72d6f015 Add isc_mem_strndup() function
This commit adds an implementation of strndup() function which
allocates memory from the supplied isc_mem_t memory context.
2021-02-02 19:53:34 +02:00
Evan HuntandArtem Boldariev 37f81ca5fb Add parser support for DoH configuration options
This commit adds stub parser support and tests for:
- an "https-server" global option for HTTP/2 configuration.
- an "https-endpoint" view option for DoH configuration.
- add specific -p options to set dns, tls, or https port numbers by
  specifying -p dns-PORT, -p tls=PORT, or -p https=PORT.  NOTE: this
  change only affects syntax; specifying the TLS port on the command
  line DOES NOT CURRENTLY HAVE ANY EFFECT.
- change option names to tls-port and https-port for consistency.
- change variable names in system tests to TLSPORT and HTTPSPORT,
  and report them when running tests.

Documentation for these options has also been added to the ARM, but
needs further work.
2021-02-02 19:44:52 +02:00
Artem Boldariev fcb0b6a781 Resurrect old TLS code
This commit resurrects the old TLS code from
8f73c70d23.

It also includes numerous stability fixes and support for
isc_nm_cancelread() for the TLS layer.

The code was resurrected to be used for DoH.
2021-02-02 19:29:56 +02:00
60 changed files with 7836 additions and 215 deletions
+1
View File
@@ -285,6 +285,7 @@ stages:
"with-openssl=C:/OpenSSL"
"with-libxml2=C:/libxml2"
"with-libuv=C:/libuv"
"with-nghttp2=C:/nghttp2"
"without-python"
"with-system-tests"
x64'
+5
View File
@@ -1,3 +1,8 @@
5575. [func] Initial support for DNS-over-HTTP(S). BIND now
includes DNS-over-HTTP(S) layer built on top of nghttp2.
Both encrypted (via TLS) and unencrypted HTTP/2 connections
are supported.
5574. [func] Incoming zone transfers can now use TLS.
Addresses in a "primaries" list take an optional
"tls" argument, specifying either a previously
+22
View File
@@ -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.
+39 -2
View File
@@ -228,6 +228,10 @@ help(void) {
"SERVFAIL)\n"
" +[no]header-only (Send query without a "
"question section)\n"
" +[no]https[=###] (DNS over HTTPS mode) "
"[/]\n"
" +[no]https-get (Use GET instead of "
"default POST method\n"
" +[no]identify (ID responders in short "
"answers)\n"
#ifdef HAVE_LIBIDN2
@@ -348,6 +352,8 @@ received(unsigned int bytes, isc_sockaddr_t *from, dig_query_t *query) {
}
if (query->lookup->tls_mode) {
proto = "TLS";
} else if (query->lookup->https_mode) {
proto = "HTTPS";
} else if (query->lookup->tcp_mode) {
proto = "TCP";
} else {
@@ -1412,8 +1418,39 @@ plus_option(char *option, bool is_batchfile, bool *need_clone,
lookup->servfail_stops = state;
break;
case 'h':
FULLCHECK("header-only");
lookup->header_only = state;
switch (cmd[1]) {
case 'e': /* header-only */
FULLCHECK("header-only");
lookup->header_only = state;
break;
case 't':
FULLCHECK2("https", "https-get");
switch (cmd[5]) {
case '\0':
FULLCHECK("https");
lookup->https_mode = state;
if (!lookup->tcp_mode_set) {
lookup->tcp_mode = state;
}
if (value == NULL) {
lookup->https_path = isc_mem_strdup(
mctx, DEFAULT_HTTPS_PATH);
break;
}
lookup->https_path = isc_mem_strdup(mctx,
value);
break;
case '-':
FULLCHECK("https-get");
lookup->https_get = true;
break;
default:
goto invalid_option;
}
break;
default:
goto invalid_option;
}
break;
case 'i':
switch (cmd[1]) {
+75 -92
View File
@@ -608,97 +608,35 @@ make_empty_lookup(void) {
INSIST(!free_now);
looknew = isc_mem_allocate(mctx, sizeof(struct dig_lookup));
looknew->pending = true;
looknew->textname[0] = 0;
looknew->cmdline[0] = 0;
looknew->rdtype = dns_rdatatype_a;
looknew->qrdtype = dns_rdatatype_a;
looknew->rdclass = dns_rdataclass_in;
looknew->rdtypeset = false;
looknew->rdclassset = false;
looknew->sendspace = NULL;
looknew->sendmsg = NULL;
looknew->name = NULL;
looknew->oname = NULL;
looknew->xfr_q = NULL;
looknew->current_query = NULL;
looknew->doing_xfr = false;
looknew->ixfr_serial = 0;
looknew->trace = false;
looknew->trace_root = false;
looknew->identify = false;
looknew->identify_previous_line = false;
looknew->ignore = false;
looknew->servfail_stops = true;
looknew->besteffort = true;
looknew->dns64prefix = false;
looknew->dnssec = false;
looknew->ednsflags = 0;
looknew->opcode = dns_opcode_query;
looknew->expire = false;
looknew->nsid = false;
looknew->tcp_keepalive = false;
looknew->padding = 0;
looknew->header_only = false;
looknew->sendcookie = false;
looknew->seenbadcookie = false;
looknew->badcookie = true;
looknew->multiline = false;
looknew->nottl = false;
looknew->noclass = false;
looknew->onesoa = false;
looknew->use_usec = false;
looknew->nocrypto = false;
looknew->ttlunits = false;
looknew->expandaaaa = false;
looknew->qr = false;
looknew = isc_mem_allocate(mctx, sizeof(*looknew));
*looknew = (dig_lookup_t){
.pending = true,
.rdtype = dns_rdatatype_a,
.qrdtype = dns_rdatatype_a,
.rdclass = dns_rdataclass_in,
.servfail_stops = true,
.besteffort = true,
.opcode = dns_opcode_query,
.badcookie = true,
#ifdef HAVE_LIBIDN2
looknew->idnin = isatty(1) ? (getenv("IDN_DISABLE") == NULL) : false;
looknew->idnout = looknew->idnin;
#else /* ifdef HAVE_LIBIDN2 */
looknew->idnin = false;
looknew->idnout = false;
.idnin = isatty(1) ? (getenv("IDN_DISABLE") == NULL) : false,
.idnout = looknew->idnin,
#endif /* HAVE_LIBIDN2 */
looknew->udpsize = -1;
looknew->edns = -1;
looknew->recurse = true;
looknew->aaonly = false;
looknew->adflag = false;
looknew->cdflag = false;
looknew->raflag = false;
looknew->tcflag = false;
looknew->print_unknown_format = false;
looknew->zflag = false;
looknew->setqid = false;
looknew->qid = 0;
looknew->ns_search_only = false;
looknew->origin = NULL;
looknew->tsigctx = NULL;
looknew->querysig = NULL;
looknew->retries = tries;
looknew->nsfound = 0;
looknew->tcp_mode = false;
looknew->tcp_mode_set = false;
looknew->tls_mode = false;
looknew->comments = true;
looknew->stats = true;
looknew->section_question = true;
looknew->section_answer = true;
looknew->section_authority = true;
looknew->section_additional = true;
looknew->new_search = false;
looknew->done_as_is = false;
looknew->need_search = false;
looknew->ecs_addr = NULL;
looknew->cookie = NULL;
looknew->ednsopts = NULL;
looknew->ednsoptscnt = 0;
looknew->ednsneg = true;
looknew->mapped = true;
looknew->dscp = -1;
looknew->rrcomments = 0;
looknew->eoferr = 0;
.udpsize = -1,
.edns = -1,
.recurse = true,
.retries = tries,
.comments = true,
.stats = true,
.section_question = true,
.section_answer = true,
.section_authority = true,
.section_additional = true,
.ednsneg = true,
.mapped = true,
.dscp = -1,
};
dns_fixedname_init(&looknew->fdomain);
ISC_LINK_INIT(looknew, link);
ISC_LIST_INIT(looknew->q);
@@ -787,6 +725,11 @@ clone_lookup(dig_lookup_t *lookold, bool servers) {
looknew->nsid = lookold->nsid;
looknew->tcp_keepalive = lookold->tcp_keepalive;
looknew->header_only = lookold->header_only;
looknew->https_mode = lookold->https_mode;
if (lookold->https_path != NULL) {
looknew->https_path = isc_mem_strdup(mctx, lookold->https_path);
}
looknew->https_get = lookold->https_get;
looknew->sendcookie = lookold->sendcookie;
looknew->seenbadcookie = lookold->seenbadcookie;
looknew->badcookie = lookold->badcookie;
@@ -1638,6 +1581,10 @@ _destroy_lookup(dig_lookup_t *lookup) {
isc_mem_free(mctx, lookup->ednsopts);
}
if (lookup->https_path) {
isc_mem_free(mctx, lookup->https_path);
}
isc_mem_free(mctx, lookup);
}
@@ -2760,7 +2707,17 @@ start_tcp(dig_query_t *query) {
* For TLS connections, we want to override the default
* port number.
*/
port = port_set ? port : (query->lookup->tls_mode ? 853 : 53);
if (!port_set) {
if (query->lookup->tls_mode) {
port = 853;
} else if (query->lookup->https_mode) {
port = 443;
} else {
port = 53;
}
}
fprintf(stderr, "query->servname = %s\n", query->servname);
result = get_address(query->servname, port, &query->sockaddr);
if (result != ISC_R_SUCCESS) {
@@ -2835,7 +2792,27 @@ start_tcp(dig_query_t *query) {
(isc_nmiface_t *)&query->sockaddr,
tcp_connected, query, local_timeout, 0,
query->tlsctx);
check_result(result, "isc_nm_tcpdnsconnect");
check_result(result, "isc_nm_tlsdnsconnect");
} else if (query->lookup->https_mode) {
char portbuf[12];
char uri[4096] = { 0 };
snprintf(portbuf, sizeof(portbuf), "%u",
(uint16_t)port);
strlcpy(uri, "https://", sizeof(uri));
strlcat(uri, query->servname, sizeof(uri));
strlcat(uri, ":", sizeof(uri));
strlcat(uri, portbuf, sizeof(uri));
strlcat(uri, query->lookup->https_path, sizeof(uri));
result = isc_tlsctx_createclient(&query->tlsctx);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
result = isc_nm_httpconnect(
netmgr, (isc_nmiface_t *)&localaddr,
(isc_nmiface_t *)&query->sockaddr, uri,
!query->lookup->https_get, tcp_connected, query,
query->tlsctx, local_timeout, 0);
check_result(result, "isc_nm_httpconnect");
} else {
result = isc_nm_tcpdnsconnect(
netmgr, (isc_nmiface_t *)&localaddr,
@@ -3183,7 +3160,12 @@ launch_next_query(dig_query_t *query) {
isc_nmhandle_settimeout(query->handle, local_timeout);
query_attach(query, &readquery);
isc_nm_read(query->handle, recv_done, readquery);
if (query->lookup->https_mode) {
isc_nm_httprequest(query->handle, &r, recv_done, readquery);
goto cleanup;
} else {
isc_nm_read(query->handle, recv_done, readquery);
}
if (!query->first_soa_rcvd) {
dig_query_t *sendquery = NULL;
@@ -3211,6 +3193,7 @@ launch_next_query(dig_query_t *query) {
}
}
}
cleanup:
lookup_detach(&l);
return;
}
+8
View File
@@ -76,6 +76,9 @@
#define DEFAULT_EDNS_VERSION 0
#define DEFAULT_EDNS_BUFSIZE 1232
#define DEFAULT_HTTPS_PATH "/dns-query"
#define DEFAULT_HTTPS_QUERY "?dns="
/*%
* Lookup_limit is just a limiter, keeping too many lookups from being
* created. It's job is mainly to prevent the program from running away
@@ -168,6 +171,11 @@ struct dig_lookup {
int rrcomments;
unsigned int eoferr;
uint16_t qid;
struct {
bool https_mode;
bool https_get;
char *https_path;
};
};
/*% The dig_query structure */
+2
View File
@@ -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\
+12 -10
View File
@@ -64,16 +64,18 @@ EXTERN isc_timermgr_t *named_g_timermgr INIT(NULL);
EXTERN isc_socketmgr_t *named_g_socketmgr INIT(NULL);
EXTERN isc_nm_t *named_g_nm INIT(NULL);
EXTERN cfg_parser_t *named_g_parser INIT(NULL);
EXTERN cfg_parser_t *named_g_addparser INIT(NULL);
EXTERN const char *named_g_version INIT(PACKAGE_VERSION);
EXTERN const char *named_g_product INIT(PACKAGE_NAME);
EXTERN const char *named_g_description INIT(PACKAGE_DESCRIPTION);
EXTERN const char *named_g_srcid INIT(PACKAGE_SRCID);
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 isc_dscp_t named_g_dscp INIT(-1);
EXTERN cfg_parser_t *named_g_addparser INIT(NULL);
EXTERN const char *named_g_version INIT(PACKAGE_VERSION);
EXTERN const char *named_g_product INIT(PACKAGE_NAME);
EXTERN const char *named_g_description INIT(PACKAGE_DESCRIPTION);
EXTERN const char *named_g_srcid INIT(PACKAGE_SRCID);
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_http_secure_port INIT(0);
EXTERN in_port_t named_g_http_port INIT(0);
EXTERN isc_dscp_t named_g_dscp INIT(-1);
EXTERN named_server_t *named_g_server INIT(NULL);
+13 -1
View File
@@ -705,7 +705,7 @@ parse_T_opt(char *option) {
static void
parse_port(char *arg) {
enum { DNSPORT, TLSPORT } ptype = DNSPORT;
enum { DNSPORT, TLSPORT, HTTP_SECURE_PORT, HTTP_PORT } 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 = HTTP_SECURE_PORT;
} else if (strncmp(arg, "http=", 5) == 0) {
value = arg + 6;
ptype = HTTP_PORT;
}
port = parse_int(value, "port");
@@ -728,6 +734,12 @@ parse_port(char *arg) {
case TLSPORT:
named_g_tlsport = port;
break;
case HTTP_SECURE_PORT:
named_g_http_secure_port = port;
break;
case HTTP_PORT:
named_g_http_port = port;
break;
default:
INSIST(0);
ISC_UNREACHABLE();
+15 -2
View File
@@ -86,6 +86,15 @@ DYNDB
dyndb string quoted_string {
unspecified-text };
HTTP
^^^^
::
http string {
endpoints { quoted_string; ... }; // experimental
};
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 );
+5 -1
View File
@@ -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.
+166 -41
View File
@@ -101,8 +101,10 @@
#include <dst/result.h>
#include <isccfg/grammar.h>
#include <isccfg/httpconf.h>
#include <isccfg/kaspconf.h>
#include <isccfg/namedconf.h>
#include <isccfg/tlsconf.h>
#include <ns/client.h>
#include <ns/hooks.h>
@@ -397,14 +399,24 @@ fatal(named_server_t *server, const char *msg, isc_result_t result);
static void
named_server_reload(isc_task_t *task, isc_event_t *event);
static isc_result_t
ns_listenelt_from_http(isc_cfg_http_obj_t *http, isc_cfg_tls_obj_t *tls,
in_port_t port, isc_mem_t *mctx,
ns_listenelt_t **target);
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);
uint16_t family, isc_cfg_http_storage_t *http_servers,
isc_cfg_tls_data_storage_t *tls_storage,
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);
uint16_t family, isc_cfg_http_storage_t *http_servers,
isc_cfg_tls_data_storage_t *tls_storage,
ns_listenlist_t **target);
static isc_result_t
configure_forward(const cfg_obj_t *config, dns_view_t *view,
@@ -8505,6 +8517,8 @@ load_configuration(const char *filename, named_server_t *server,
unsigned int initial, idle, keepalive, advertised;
dns_aclenv_t *env =
ns_interfacemgr_getaclenv(named_g_server->interfacemgr);
isc_cfg_tls_data_storage_t tls_storage;
isc_cfg_http_storage_t http_storage;
ISC_LIST_INIT(kasplist);
ISC_LIST_INIT(viewlist);
@@ -8512,6 +8526,9 @@ load_configuration(const char *filename, named_server_t *server,
ISC_LIST_INIT(cachelist);
ISC_LIST_INIT(altsecrets);
cfg_tls_storage_init(named_g_mctx, &tls_storage);
cfg_http_storage_init(named_g_mctx, &http_storage);
/* Create the ACL configuration context */
if (named_g_aclconfctx != NULL) {
cfg_aclconfctx_detach(&named_g_aclconfctx);
@@ -8573,6 +8590,19 @@ 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_http_port = (in_port_t)cfg_obj_asuint32(obj);
obj = NULL;
result = named_config_get(maps, "https-port", &obj);
INSIST(result == ISC_R_SUCCESS);
named_g_http_secure_port = (in_port_t)cfg_obj_asuint32(obj);
CHECK(cfg_tls_storage_load(config, &tls_storage));
CHECK(cfg_http_storage_load(config, &http_storage));
/*
* If bind.keys exists, load it. If "dnssec-validation auto"
* is turned on, the root key found there will be used as a
@@ -8991,7 +9021,8 @@ load_configuration(const char *filename, named_server_t *server,
/* check return code? */
(void)ns_listenlist_fromconfig(
clistenon, config, named_g_aclconfctx,
named_g_mctx, AF_INET, &listenon);
named_g_mctx, AF_INET, &http_storage,
&tls_storage, &listenon);
} else {
/*
* Not specified, use default.
@@ -9019,7 +9050,8 @@ load_configuration(const char *filename, named_server_t *server,
/* check return code? */
(void)ns_listenlist_fromconfig(
clistenon, config, named_g_aclconfctx,
named_g_mctx, AF_INET6, &listenon);
named_g_mctx, AF_INET6, &http_storage,
&tls_storage, &listenon);
} else {
/*
* Not specified, use default.
@@ -9780,6 +9812,9 @@ cleanup:
isc_task_endexclusive(server->task);
}
cfg_http_storage_uninit(&http_storage);
cfg_tls_storage_uninit(&tls_storage);
isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
"load_configuration: %s", isc_result_totext(result));
@@ -10987,7 +11022,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) {
uint16_t family, isc_cfg_http_storage_t *http_servers,
isc_cfg_tls_data_storage_t *tls_storage,
ns_listenlist_t **target) {
isc_result_t result;
const cfg_listelt_t *element;
ns_listenlist_t *dlist = NULL;
@@ -11005,7 +11042,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);
family, http_servers,
tls_storage, &delt);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
@@ -11026,14 +11064,18 @@ cleanup:
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) {
uint16_t family, isc_cfg_http_storage_t *http_servers,
isc_cfg_tls_data_storage_t *tls_storage,
ns_listenelt_t **target) {
isc_result_t result;
const cfg_obj_t *tlsobj, *portobj, *dscpobj;
in_port_t port;
const cfg_obj_t *tlsobj, *portobj, *dscpobj, *httpobj;
in_port_t port = 0;
isc_dscp_t dscp = -1;
const char *key = NULL, *cert = NULL;
bool tls = false;
bool tls = false, http = false;
ns_listenelt_t *delt = NULL;
isc_cfg_http_obj_t *http_server = NULL;
isc_cfg_tls_obj_t *tls_cert = NULL;
REQUIRE(target != NULL && *target == NULL);
/* XXXWPK TODO be more verbose on failures. */
@@ -11042,43 +11084,60 @@ ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
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;
}
tls_cert = cfg_tls_storage_find(
cfg_obj_asstring(tlsobj), tls_storage);
if (tls_cert != NULL) {
tls = true;
key = tls_cert->key_file;
cert = tls_cert->cert_file;
INSIST(key != NULL);
INSIST(cert != NULL);
}
}
if (!tls) {
return (ISC_R_FAILURE);
}
}
httpobj = cfg_tuple_get(listener, "http");
if (httpobj != NULL && cfg_obj_isstring(httpobj)) {
if (tls && tls_cert == NULL) {
return (ISC_R_FAILURE);
}
http = true;
http_server = cfg_http_find(cfg_obj_asstring(httpobj),
http_servers);
if (http_server == NULL) {
isc_log_write(
named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
"HTTP(S) server \"%s\" is nowhere to be found",
cfg_obj_asstring(httpobj));
return (ISC_R_FAILURE);
}
}
portobj = cfg_tuple_get(listener, "port");
if (!cfg_obj_isuint32(portobj)) {
if (tls) {
if (http && tls) {
if (named_g_http_secure_port != 0) {
port = named_g_http_secure_port;
} else {
result = named_config_getport(
config, "https-port", &port);
if (result != ISC_R_SUCCESS) {
return (result);
}
}
} else if (http && !tls) {
if (named_g_http_port != 0) {
port = named_g_port;
} else {
result = named_config_getport(
config, "http-port", &port);
if (result != ISC_R_SUCCESS) {
return (result);
}
}
} else if (tls) {
if (named_g_tlsport != 0) {
port = named_g_tlsport;
} else {
@@ -11122,8 +11181,14 @@ 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 (http) {
INSIST(http_server != NULL);
result = ns_listenelt_from_http(http_server, tls_cert, port,
mctx, &delt);
} else {
result = ns_listenelt_create(mctx, port, dscp, NULL, tls, key,
cert, &delt);
}
if (result != ISC_R_SUCCESS) {
return (result);
}
@@ -11139,6 +11204,66 @@ ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
return (ISC_R_SUCCESS);
}
/*
* Create a listen list for HTTP/HTTPS
*/
static isc_result_t
ns_listenelt_from_http(isc_cfg_http_obj_t *http, isc_cfg_tls_obj_t *tls,
in_port_t port, isc_mem_t *mctx,
ns_listenelt_t **target) {
isc_result_t result = ISC_R_SUCCESS;
ns_listenelt_t *delt = NULL;
const char *key = NULL, *cert = NULL;
char **http_endpoints = NULL;
size_t http_endpoints_number;
isc_cfg_http_endpoint_t *ep;
size_t i = 0;
REQUIRE(target != NULL && *target == NULL);
if (tls) {
INSIST(tls->key_file != NULL);
INSIST(tls->cert_file != NULL);
key = tls->key_file;
cert = tls->cert_file;
}
if (port == 0) {
port = tls != NULL ? named_g_http_secure_port
: named_g_http_port;
}
for (ep = ISC_LIST_HEAD(http->endpoints), i = 0; ep != NULL;
ep = ISC_LIST_NEXT(ep, link), i++)
;
INSIST(i > 0);
http_endpoints_number = i;
http_endpoints = isc_mem_allocate(mctx, sizeof(http_endpoints[0]) *
http_endpoints_number);
for (ep = ISC_LIST_HEAD(http->endpoints), i = 0; ep != NULL;
ep = ISC_LIST_NEXT(ep, link), i++)
{
http_endpoints[i] = isc_mem_strdup(mctx, ep->path);
}
INSIST(i == http_endpoints_number);
result = ns_listenelt_create_http(mctx, port, named_g_dscp, NULL, key,
cert, http_endpoints,
http_endpoints_number, &delt);
if (result != ISC_R_SUCCESS) {
if (delt != NULL) {
ns_listenelt_destroy(delt);
}
return result;
}
*target = delt;
return (result);
}
isc_result_t
named_server_dumpstats(named_server_t *server) {
isc_result_t result;
@@ -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; };
};
@@ -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; };
};
+2
View File
@@ -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" \
+2
View File
@@ -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)"
+1 -1
View File
@@ -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."
+2 -1
View File
@@ -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
+10 -1
View File
@@ -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
#
+19
View File
@@ -1078,6 +1078,14 @@ default is used.
the default is the ``named`` working directory. See :ref:`acl`
for details about ``geoip`` ACLs.
.. _https_endpoint:
``https-endpoint``
This configures an DNS-over-HTTPS service endpoint. It takes a string
which specifies the endpoint URL path, and an ``https-server``
parameter specifying the server name of an HTTPS listener. (See
:ref:`Link title <https_server>`.)
``key-directory``
This is the directory where the public and private DNSSEC key files should be
found when performing a dynamic update of secure zones, if different
@@ -2436,6 +2444,8 @@ Interfaces
The interfaces and ports that the server answers queries from may be
specified using the ``listen-on`` and ``listen-on-v6`` options.
specified using the ``listen-on`` and ``listen-on-v6`` options, as
well as the ``https-server`` option for HTTPS queries.
``listen-on`` takes an optional port, an optional TLS configuration
identifier, and an ``address_match_list`` of IPv4 addresses. (IPv6
@@ -2488,6 +2498,15 @@ To instruct the server not to listen on any IPv6 addresses, use:
listen-on-v6 { none; };
.. _https_server:
``https-server`` takes a server name, an optional port, a TLS
configuration identifier, and an ``address_match_list`` of both IPv4 and
IPv6 addresses. This sets up an HTTPS responder using the key and
certificate specified in the referenced ``tls`` statement. The endpoint
for incoming HTTPS queries must be specified using the ``https-endpoint``
option (see :ref:`Link title <https_endpoint>`).
.. _query_address:
Query Address
+4
View File
@@ -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.
+19 -2
View File
@@ -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; ... }; // experimental
};
.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 );
+10 -2
View File
@@ -42,6 +42,10 @@ dnssec-policy <string> {
dyndb <string> <quoted_string> {
<unspecified-text> }; // may occur multiple times
http <string> {
endpoints { <quoted_string>; ... }; // experimental
}; // 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 );
+10 -2
View File
@@ -41,6 +41,10 @@ dnssec-policy <string> {
dyndb <string> <quoted_string> {
<unspecified-text> }; // may occur multiple times
http <string> {
endpoints { <quoted_string>; ... }; // experimental
}; // 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 );
+6 -2
View File
@@ -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 );
+7
View File
@@ -52,6 +52,13 @@ New Features
an optional ``tls`` option which specifies either a previously configured
``tls`` statement or ``ephemeral``. [GL #2392]
- ``named`` now has initial support for DNS-over-HTTP(S). Both
encrypted (via TLS) and unencrypted HTTP/2 connections are supported.
The latter are mostly there for debugging/troubleshooting
purposes and for the means of encryption offloading to third-party
software (as might be desirable in some environments to aid in TLS
certificates management).
Removed Features
~~~~~~~~~~~~~~~~
+4
View File
@@ -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 \
+6 -1
View File
@@ -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);
+54
View File
@@ -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
View 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
*/
+33 -1
View File
@@ -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));
File diff suppressed because it is too large Load Diff
+237 -5
View File
@@ -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);
+123 -2
View File
@@ -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();
+28 -21
View File
@@ -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
View 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);
}
}
+2 -2
View File
@@ -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;
+13 -2
View File
@@ -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) \
$(OPENSSL_CFLAGS) \
$(LIBUV_CFLAGS)
doh_test_LDADD = \
$(LDADD) \
$(OPENSSL_LIBS) \
$(LIBUV_LIBS)
hmac_test_CPPFLAGS = \
$(AM_CPPFLAGS) \
$(OPENSSL_CFLAGS)
File diff suppressed because it is too large Load Diff
+4 -2
View File
@@ -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
View 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);
}
+9
View File
@@ -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
@@ -467,6 +474,7 @@ isc_nm_settimeouts
isc_nm_tcpdns_keepalive
isc_nm_tcpdns_sequential
isc_nm_tid
isc_nm_tlsconnect
isc_nm_tlsdnsconnect
isc_nm_udpconnect
isc_nmsocket_close
@@ -706,6 +714,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
+7 -1
View File
@@ -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>
+19 -9
View File
@@ -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" />
+5 -1
View File
@@ -7,17 +7,21 @@ libisccfg_la_HEADERS = \
include/isccfg/aclconf.h \
include/isccfg/cfg.h \
include/isccfg/grammar.h \
include/isccfg/httpconf.h \
include/isccfg/kaspconf.h \
include/isccfg/log.h \
include/isccfg/namedconf.h
include/isccfg/namedconf.h \
include/isccfg/tlsconf.h
libisccfg_la_SOURCES = \
$(libisccfg_la_HEADERS) \
aclconf.c \
httpconf.c \
dnsconf.c \
kaspconf.c \
log.c \
namedconf.c \
tlsconf.c \
parser.c
libisccfg_la_CPPFLAGS = \
+178
View File
@@ -0,0 +1,178 @@
/*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <isc/util.h>
#include <isccfg/grammar.h>
#include <isccfg/httpconf.h>
void
cfg_http_storage_init(isc_mem_t *mctx, isc_cfg_http_storage_t *storage) {
REQUIRE(mctx != NULL);
REQUIRE(storage != NULL);
memset(storage, 0, sizeof(*storage));
isc_mem_attach(mctx, &storage->mctx);
ISC_LIST_INIT(storage->list);
}
void
cfg_http_storage_uninit(isc_cfg_http_storage_t *storage) {
REQUIRE(storage != NULL);
cfg_http_storage_clear(storage);
isc_mem_detach(&storage->mctx);
}
void
cfg_http_storage_clear(isc_cfg_http_storage_t *storage) {
REQUIRE(storage != NULL);
isc_mem_t *mctx = storage->mctx;
if (!ISC_LIST_EMPTY(storage->list)) {
isc_cfg_http_obj_t *http = ISC_LIST_HEAD(storage->list);
while (http != NULL) {
isc_cfg_http_obj_t *next = ISC_LIST_NEXT(http, link);
ISC_LIST_DEQUEUE(storage->list, http, link);
storage->nservers--;
isc_mem_free(mctx, http->name);
if (!ISC_LIST_EMPTY(http->endpoints)) {
isc_cfg_http_endpoint_t *ep =
ISC_LIST_HEAD(http->endpoints);
while (ep != NULL) {
isc_cfg_http_endpoint_t *epnext =
ISC_LIST_NEXT(ep, link);
isc_mem_free(mctx, ep->path);
isc_mem_put(mctx, ep, sizeof(*ep));
ep = epnext;
http->nendponts--;
}
}
isc_mem_put(mctx, http, sizeof(*http));
http = next;
}
}
INSIST(storage->nservers == 0);
}
isc_cfg_http_obj_t *
cfg_http_find(const char *name, isc_cfg_http_storage_t *storage) {
isc_cfg_http_obj_t *http = NULL;
REQUIRE(name != NULL && *name != '\0');
REQUIRE(storage != NULL);
for (http = ISC_LIST_HEAD(storage->list); http != NULL;
http = ISC_LIST_NEXT(http, link))
{
if (strcasecmp(name, http->name) == 0) {
break;
}
}
return (http);
}
static isc_result_t
push_http_obj(const cfg_obj_t *map, isc_cfg_http_storage_t *storage) {
isc_mem_t *mctx = storage->mctx;
isc_cfg_http_obj_t *new;
const cfg_obj_t *endpoints = NULL;
const cfg_listelt_t *elt;
if (!cfg_obj_ismap(map) || map->value.map.id == NULL ||
!cfg_obj_isstring(map->value.map.id))
{
return (ISC_R_FAILURE);
}
if (cfg_http_find(cfg_obj_asstring(map->value.map.id), storage) != NULL)
{
return (ISC_R_FAILURE);
}
if (cfg_map_get(map, "endpoints", &endpoints) != ISC_R_SUCCESS ||
!cfg_obj_islist(endpoints))
{
return (ISC_R_FAILURE);
}
INSIST(endpoints != NULL);
new = isc_mem_get(mctx, sizeof(*new));
memset(new, 0, sizeof(*new));
ISC_LIST_INIT(new->endpoints);
new->name = isc_mem_strdup(mctx, cfg_obj_asstring(map->value.map.id));
for (elt = cfg_list_first(endpoints); elt != NULL;
elt = cfg_list_next(elt)) {
isc_cfg_http_endpoint_t *newep = NULL;
const cfg_obj_t *endp = cfg_listelt_value(elt);
newep = isc_mem_get(mctx, sizeof(*newep));
ISC_LINK_INIT(newep, link);
newep->path = isc_mem_strdup(mctx, cfg_obj_asstring(endp));
ISC_LIST_PREPEND(new->endpoints, newep, link);
new->nendponts++;
}
ISC_LINK_INIT(new, link);
ISC_LIST_PREPEND(storage->list, new, link);
storage->nservers++;
return (ISC_R_SUCCESS);
}
isc_result_t
cfg_http_storage_load(const cfg_obj_t *cfg_ctx,
isc_cfg_http_storage_t *storage) {
bool found = false;
isc_result_t result = ISC_R_SUCCESS;
const cfg_obj_t *http = NULL;
const cfg_listelt_t *elt;
const cfg_obj_t *map = NULL;
REQUIRE(cfg_ctx != NULL);
REQUIRE(storage != NULL);
cfg_http_storage_clear(storage);
result = cfg_map_get(cfg_ctx, "http", &http);
if (result != ISC_R_SUCCESS) {
/* No statements found, but it is fine. */
return (ISC_R_SUCCESS);
}
INSIST(http != NULL);
for (elt = cfg_list_first(http); elt != NULL; elt = cfg_list_next(elt))
{
map = cfg_listelt_value(elt);
INSIST(map != NULL);
found = true;
result = push_http_obj(map, storage);
if (result != ISC_R_SUCCESS) {
return result;
}
}
if (found == true && storage->nservers == 0) {
return (ISC_R_FAILURE);
}
return (ISC_R_SUCCESS);
}
+69
View File
@@ -0,0 +1,69 @@
/*
* 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.
*/
#ifndef ISCCFG_HTTPCONF_H
#define ISCCFG_HTTPCONF_H 1
#include <inttypes.h>
#include <isc/lang.h>
#include <isc/list.h>
#include <isc/mem.h>
#include <isc/util.h>
#include <dns/types.h>
#include <isccfg/cfg.h>
#include <isccfg/tlsconf.h>
typedef struct isc_cfg_http_endpoint {
char *path;
LINK(struct isc_cfg_http_endpoint) link;
} isc_cfg_http_endpoint_t;
typedef struct isc_cfg_http_obj {
char *name;
LINK(struct isc_cfg_http_obj) link;
ISC_LIST(isc_cfg_http_endpoint_t) endpoints;
size_t nendponts;
} isc_cfg_http_obj_t;
typedef struct isc_cfg_http_storage {
isc_mem_t *mctx;
ISC_LIST(isc_cfg_http_obj_t) list;
size_t nservers;
} isc_cfg_http_storage_t;
/***
*** Functions
***/
ISC_LANG_BEGINDECLS
void
cfg_http_storage_init(isc_mem_t *mctx, isc_cfg_http_storage_t *storage);
void
cfg_http_storage_uninit(isc_cfg_http_storage_t *storage);
isc_result_t
cfg_http_storage_load(const cfg_obj_t * cfg_ctx,
isc_cfg_http_storage_t *storage);
isc_cfg_http_obj_t *
cfg_http_find(const char *name, isc_cfg_http_storage_t *storage);
void
cfg_http_storage_clear(isc_cfg_http_storage_t *storage);
ISC_LANG_ENDDECLS
#endif /* ISCCFG_HTTPCONF_H */
+69
View File
@@ -0,0 +1,69 @@
/*
* 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.
*/
#ifndef ISCCFG_TLSCONF_H
#define ISCCFG_TLSCONF_H 1
#include <inttypes.h>
#include <isc/lang.h>
#include <isc/list.h>
#include <isc/mem.h>
#include <isc/util.h>
#include <dns/types.h>
#include <isccfg/cfg.h>
typedef struct isc_cfg_tls_obj {
char *name;
char *key_file;
char *cert_file;
char *dh_param;
char *protocols;
char *ciphers;
LINK(struct isc_cfg_tls_obj) link;
} isc_cfg_tls_obj_t;
typedef struct isc_cfg_tls_data_storage {
isc_mem_t *mctx;
size_t count;
ISC_LIST(isc_cfg_tls_obj_t) list;
} isc_cfg_tls_data_storage_t;
/***
*** Functions
***/
ISC_LANG_BEGINDECLS
void
cfg_tls_storage_init(isc_mem_t *mctx, isc_cfg_tls_data_storage_t *storage);
void
cfg_tls_storage_uninit(isc_cfg_tls_data_storage_t *storage);
isc_result_t
cfg_tls_storage_load(const cfg_obj_t * cfg_ctx,
isc_cfg_tls_data_storage_t *storage);
isc_cfg_tls_obj_t *
cfg_tls_storage_find(const char *name, isc_cfg_tls_data_storage_t *storage);
/*
* Looks for TLS key/certificate pair.
*/
void
cfg_tls_storage_clear(isc_cfg_tls_data_storage_t *storage);
ISC_LANG_ENDDECLS
#endif /* ISCCFG_TLSCONF_H */
+37
View File
@@ -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,33 @@ 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,
CFG_CLAUSEFLAG_EXPERIMENTAL },
{ 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
};
+191
View File
@@ -0,0 +1,191 @@
/*
* 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 <string.h>
#include <isc/util.h>
#include <isccfg/grammar.h>
#include <isccfg/tlsconf.h>
void
cfg_tls_storage_init(isc_mem_t *mctx, isc_cfg_tls_data_storage_t *storage) {
REQUIRE(mctx != NULL);
REQUIRE(storage != NULL);
memset(storage, 0, sizeof(*storage));
isc_mem_attach(mctx, &storage->mctx);
ISC_LIST_INIT(storage->list);
}
void
cfg_tls_storage_uninit(isc_cfg_tls_data_storage_t *storage) {
REQUIRE(storage != NULL);
cfg_tls_storage_clear(storage);
isc_mem_detach(&storage->mctx);
}
void
cfg_tls_storage_clear(isc_cfg_tls_data_storage_t *storage) {
REQUIRE(storage != NULL);
isc_mem_t *mctx = storage->mctx;
if (!ISC_LIST_EMPTY(storage->list)) {
isc_cfg_tls_obj_t *tls_obj = ISC_LIST_HEAD(storage->list);
while (tls_obj != NULL) {
isc_cfg_tls_obj_t *next = ISC_LIST_NEXT(tls_obj, link);
ISC_LIST_DEQUEUE(storage->list, tls_obj, link);
storage->count--;
isc_mem_free(mctx, tls_obj->name);
isc_mem_free(mctx, tls_obj->key_file);
isc_mem_free(mctx, tls_obj->cert_file);
if (tls_obj->dh_param != NULL) {
isc_mem_free(mctx, tls_obj->dh_param);
}
if (tls_obj->protocols != NULL) {
isc_mem_free(mctx, tls_obj->protocols);
}
if (tls_obj->ciphers != NULL) {
isc_mem_free(mctx, tls_obj->ciphers);
}
isc_mem_put(mctx, tls_obj, sizeof(*tls_obj));
tls_obj = next;
}
}
INSIST(storage->count == 0);
}
static isc_result_t
push_tls_obj(const cfg_obj_t *map, isc_cfg_tls_data_storage_t *storage) {
isc_mem_t *mctx = storage->mctx;
isc_cfg_tls_obj_t *new;
const cfg_obj_t *key_file = NULL, *cert_file = NULL, *dh_param = NULL,
*protocols = NULL, *ciphers = NULL;
if (!cfg_obj_ismap(map) || map->value.map.id == NULL ||
!cfg_obj_isstring(map->value.map.id))
{
return (ISC_R_FAILURE);
}
if (cfg_tls_storage_find(cfg_obj_asstring(map->value.map.id),
storage) != NULL) {
return (ISC_R_FAILURE);
}
if (cfg_map_get(map, "key-file", &key_file) != ISC_R_SUCCESS ||
!cfg_obj_isstring(key_file))
{
return (ISC_R_FAILURE);
}
if (cfg_map_get(map, "cert-file", &cert_file) != ISC_R_SUCCESS) {
return (ISC_R_FAILURE);
}
(void)cfg_map_get(map, "dh-param", &dh_param);
(void)cfg_map_get(map, "protocols", &protocols);
(void)cfg_map_get(map, "ciphers", &ciphers);
INSIST(key_file != NULL);
INSIST(cert_file != NULL);
new = isc_mem_get(mctx, sizeof(*new));
memset(new, 0, sizeof(*new));
new->name = isc_mem_strdup(mctx, cfg_obj_asstring(map->value.map.id));
new->key_file = isc_mem_strdup(mctx, cfg_obj_asstring(key_file));
new->cert_file = isc_mem_strdup(mctx, cfg_obj_asstring(cert_file));
if (dh_param != NULL && cfg_obj_isstring(dh_param)) {
new->dh_param = isc_mem_strdup(mctx,
cfg_obj_asstring(dh_param));
}
if (protocols != NULL && cfg_obj_isstring(protocols)) {
new->protocols = isc_mem_strdup(mctx,
cfg_obj_asstring(protocols));
}
if (ciphers != NULL && cfg_obj_isstring(ciphers)) {
new->ciphers = isc_mem_strdup(mctx, cfg_obj_asstring(ciphers));
}
ISC_LINK_INIT(new, link);
ISC_LIST_PREPEND(storage->list, new, link);
storage->count++;
return (ISC_R_SUCCESS);
}
isc_result_t
cfg_tls_storage_load(const cfg_obj_t *cfg_ctx,
isc_cfg_tls_data_storage_t *storage) {
isc_result_t result = ISC_R_SUCCESS;
bool found = false;
const cfg_obj_t *tls = NULL;
const cfg_listelt_t *elt;
const cfg_obj_t *map = NULL;
REQUIRE(cfg_ctx != NULL);
REQUIRE(storage != NULL);
result = cfg_map_get(cfg_ctx, "tls", &tls);
if (result != ISC_R_SUCCESS) {
/* No tls statements found, but it is fine. */
return (ISC_R_SUCCESS);
}
cfg_tls_storage_clear(storage);
INSIST(tls != NULL);
for (elt = cfg_list_first(tls); elt != NULL; elt = cfg_list_next(elt)) {
map = cfg_listelt_value(elt);
INSIST(map != NULL);
found = true;
result = push_tls_obj(map, storage);
if (result != ISC_R_SUCCESS) {
return result;
}
}
if (found == true && storage->count == 0) {
return (ISC_R_FAILURE);
}
return (ISC_R_SUCCESS);
}
isc_cfg_tls_obj_t *
cfg_tls_storage_find(const char *name, isc_cfg_tls_data_storage_t *storage) {
isc_cfg_tls_obj_t *tls_obj = NULL;
REQUIRE(storage != NULL);
if (name == NULL) {
return NULL;
}
for (tls_obj = ISC_LIST_HEAD(storage->list); tls_obj != NULL;
tls_obj = ISC_LIST_NEXT(tls_obj, link))
{
if (strcasecmp(name, tls_obj->name) == 0) {
break;
}
}
return tls_obj;
}
+10
View File
@@ -23,6 +23,11 @@ cfg_doc_terminal
cfg_doc_tuple
cfg_doc_void
cfg_gettoken
cfg_http_storage_clear
cfg_http_storage_init
cfg_http_storage_uninit
cfg_http_storage_load
cfg_http_find
cfg_is_enum
cfg_kasp_fromconfig
cfg_list_first
@@ -65,6 +70,11 @@ cfg_obj_isuint64
cfg_obj_isvoid
cfg_obj_line
cfg_obj_log
cfg_tls_storage_clear
cfg_tls_storage_init
cfg_tls_storage_uninit
cfg_tls_storage_load
cfg_tls_storage_find
cfg_parse_addressed_map
cfg_parse_astring
cfg_parse_boolean
@@ -27,12 +27,18 @@
<ClCompile Include="..\dnsconf.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\httpconf.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\kaspconf.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\log.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\tlsconf.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\namedconf.c">
<Filter>Source Files</Filter>
</ClCompile>
@@ -50,12 +56,18 @@
<ClInclude Include="..\include\isccfg\grammar.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\isccfg\httpconf.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\isccfg\kaspconf.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\isccfg\log.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\isccfg\tlsconf.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\isccfg\namedconf.h">
<Filter>Header Files</Filter>
</ClInclude>
+4
View File
@@ -120,9 +120,11 @@
<ItemGroup>
<ClCompile Include="..\aclconf.c" />
<ClCompile Include="..\dnsconf.c" />
<ClCompile Include="..\httpconf.c" />
<ClCompile Include="..\kaspconf.c" />
<ClCompile Include="..\log.c" />
<ClCompile Include="..\namedconf.c" />
<ClCompile Include="..\tlsconf.c" />
<ClCompile Include="..\parser.c" />
<ClCompile Include="DLLMain.c" />
</ItemGroup>
@@ -130,9 +132,11 @@
<ClInclude Include="..\include\isccfg\aclconf.h" />
<ClInclude Include="..\include\isccfg\cfg.h" />
<ClInclude Include="..\include\isccfg\grammar.h" />
<ClInclude Include="..\include\isccfg\httpconf.h" />
<ClInclude Include="..\include\isccfg\kaspconf.h" />
<ClInclude Include="..\include\isccfg\log.h" />
<ClInclude Include="..\include\isccfg\namedconf.h" />
<ClInclude Include="..\include\isccfg\tlsconf.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\lib\isc\win32\libisc.vcxproj">
+2
View File
@@ -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
+12
View File
@@ -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, 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);
/*%<
+71
View File
@@ -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);
}
+48 -8
View File
@@ -30,24 +30,56 @@ 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, 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, key != NULL,
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 +88,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));
}
+1
View File
@@ -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
+9
View File
@@ -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
@@ -2100,18 +2105,22 @@
./lib/isccc/win32/libisccc.vcxproj.user X 2013,2018,2019,2020,2021
./lib/isccfg/aclconf.c C 1999,2000,2001,2002,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021
./lib/isccfg/dnsconf.c C 2009,2016,2018,2019,2020,2021
./lib/isccfg/httpconf.c C 2021
./lib/isccfg/include/isccfg/aclconf.h C 1999,2000,2001,2004,2005,2006,2007,2010,2011,2012,2013,2014,2016,2018,2019,2020,2021
./lib/isccfg/include/isccfg/cfg.h C 2000,2001,2002,2004,2005,2006,2007,2010,2013,2014,2015,2016,2018,2019,2020,2021
./lib/isccfg/include/isccfg/grammar.h C 2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2013,2014,2015,2016,2017,2018,2019,2020,2021
./lib/isccfg/include/isccfg/httpconf.h C 2021
./lib/isccfg/include/isccfg/kaspconf.h C 2019,2020,2021
./lib/isccfg/include/isccfg/log.h C 2001,2004,2005,2006,2007,2009,2016,2018,2019,2020,2021
./lib/isccfg/include/isccfg/namedconf.h C 2002,2004,2005,2006,2007,2009,2010,2014,2016,2018,2019,2020,2021
./lib/isccfg/include/isccfg/tlsconf.h C 2021
./lib/isccfg/kaspconf.c C 2019,2020,2021
./lib/isccfg/log.c C 2001,2004,2005,2006,2007,2016,2018,2019,2020,2021
./lib/isccfg/namedconf.c C 2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021
./lib/isccfg/parser.c C 2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021
./lib/isccfg/tests/duration_test.c C 2019,2020,2021
./lib/isccfg/tests/parser_test.c C 2016,2018,2019,2020,2021
./lib/isccfg/tlsconf.c C 2021
./lib/isccfg/win32/DLLMain.c C 2001,2004,2007,2016,2018,2019,2020,2021
./lib/isccfg/win32/libisccfg.def X 2001,2002,2005,2009,2010,2011,2013,2014,2015,2016,2018,2019,2020,2021
./lib/isccfg/win32/libisccfg.vcxproj.filters.in X 2013,2014,2015,2016,2018,2019,2020
+73
View File
@@ -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;