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

Add parser support for DoH configuration options

This commit adds stub parser support and tests for:
- an "http" global option for HTTP/2 endpoint configuration.
- command line options to set http or https port numbers by
  specifying -p http=PORT or -p https=PORT.  (NOTE: this change
  only affects syntax; specifying HTTP and HTTPS ports on the
  command line currently has no effect.)
- named.conf options "http-port" and "https-port"
- HTTPSPORT environment variable for use when running tests.
This commit is contained in:
Evan Hunt
2020-09-16 12:21:32 -07:00
committed by Ondřej Surý
parent 6b9a31989c
commit 06951472dd
25 changed files with 719 additions and 15 deletions

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\

View File

@@ -73,6 +73,8 @@ EXTERN const char *named_g_configargs INIT(PACKAGE_CONFIGARGS);
EXTERN const char *named_g_builder INIT(PACKAGE_BUILDER);
EXTERN in_port_t named_g_port INIT(0);
EXTERN in_port_t named_g_tlsport INIT(0);
EXTERN in_port_t named_g_httpport INIT(0);
EXTERN in_port_t named_g_httpsport INIT(0);
EXTERN isc_dscp_t named_g_dscp INIT(-1);
EXTERN named_server_t *named_g_server INIT(NULL);

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, HTTPSPORT, HTTPPORT } ptype = DNSPORT;
char *value = arg;
int port;
@@ -714,6 +714,12 @@ parse_port(char *arg) {
} else if (strncmp(arg, "tls=", 4) == 0) {
value = arg + 4;
ptype = TLSPORT;
} else if (strncmp(arg, "https=", 6) == 0) {
value = arg + 6;
ptype = HTTPSPORT;
} else if (strncmp(arg, "http=", 5) == 0) {
value = arg + 6;
ptype = HTTPPORT;
}
port = parse_int(value, "port");
@@ -728,6 +734,12 @@ parse_port(char *arg) {
case TLSPORT:
named_g_tlsport = port;
break;
case HTTPSPORT:
named_g_httpsport = port;
break;
case HTTPPORT:
named_g_httpport = port;
break;
default:
INSIST(0);
ISC_UNREACHABLE();

View File

@@ -86,6 +86,15 @@ DYNDB
dyndb string quoted_string {
unspecified-text };
HTTP
^^^^
::
http string {
endpoints { quoted_string; ... };
};
KEY
^^^
@@ -264,6 +273,8 @@ OPTIONS
glue-cache boolean;// deprecated
heartbeat-interval integer;
hostname ( quoted_string | none );
http-port integer;
https-port integer;
inline-signing boolean;
interface-interval duration;
ipv4only-contact string;
@@ -275,10 +286,12 @@ OPTIONS
key-directory quoted_string;
lame-ttl duration;
listen-on [ port integer ] [ dscp
integer ] [ tls string ] {
integer ] [ tls string ] [ http
string ] {
address_match_element; ... };
listen-on-v6 [ port integer ] [ dscp
integer ] [ tls string ] {
integer ] [ tls string ] [ http
string ] {
address_match_element; ... };
lmdb-mapsize sizeval;
lock-file ( quoted_string | none );

View File

@@ -115,7 +115,9 @@ 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.
``-s``
This option writes memory usage statistics to ``stdout`` on exit.

View File

@@ -0,0 +1,27 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
tls local-tls {
key-file "key.pem";
cert-file "cert.pem";
};
http local-http-server {
endpoints { "/dns-query"; };
};
options {
listen-on { 10.53.0.1; };
http-port 80;
https-port 443;
listen-on port 443 tls local-tls http local-http-server { 10.53.0.1; };
listen-on port 8080 http local-http-server { 10.53.0.1; };
};

View File

@@ -0,0 +1,19 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
tls local-tls {
key-file "key.pem";
cert-file "cert.pem";
};
options {
listen-on port 853 tls local-tls { 10.53.0.1; };
};

View File

@@ -668,6 +668,7 @@ copy_setports() {
atsign="@"
sed -e "s/${atsign}PORT${atsign}/${PORT}/g" \
-e "s/${atsign}TLSPORT${atsign}/${TLSPORT}/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" \

View File

@@ -82,6 +82,7 @@ done
echo "export PORT=$(get_port "$baseport")"
echo "export TLSPORT=$(get_port)"
echo "export HTTPSPORT=$(get_port)"
echo "export EXTRAPORT1=$(get_port)"
echo "export EXTRAPORT2=$(get_port)"
echo "export EXTRAPORT3=$(get_port)"

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},${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."

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 a DNS-over-HTTPS (DoH) 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

View File

@@ -115,6 +115,8 @@ 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.
.TP
.B \fB\-s\fP
This option writes memory usage statistics to \fBstdout\fP on exit.

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; ... };
};
.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 );

View File

@@ -37,7 +37,8 @@ OPTIONS_FILES = \
tls.grammar.rst \
trust-anchors.grammar.rst \
managed-keys.grammar.rst \
trusted-keys.grammar.rst
trusted-keys.grammar.rst \
http.grammar.rst
EXTRA_DIST = \
$(OPTIONS_FILES) \
@@ -175,4 +176,7 @@ managed-keys.grammar.rst: options.active
trusted-keys.grammar.rst: options.active
$(AM_V_RST_GRAMMARS)$(PERL) $(srcdir)/rst-grammars.pl options.active trusted-keys > $@
http.grammar.rst: options.active
$(AM_V_RST_GRAMMARS)$(PERL) $(srcdir)/rst-grammars.pl options.active http > $@
endif

View File

@@ -0,0 +1,5 @@
::
http <string> {
endpoints { <quoted_string>; ... };
};

View File

@@ -42,6 +42,10 @@ dnssec-policy <string> {
dyndb <string> <quoted_string> {
<unspecified-text> }; // may occur multiple times
http <string> {
endpoints { <quoted_string>; ... };
}; // may occur multiple times
key <string> {
algorithm <string>;
secret <string>;
@@ -193,6 +197,8 @@ options {
glue-cache <boolean>; // deprecated
heartbeat-interval <integer>;
hostname ( <quoted_string> | none );
http-port <integer>;
https-port <integer>;
inline-signing <boolean>;
interface-interval <duration>;
ipv4only-contact <string>;
@@ -204,10 +210,12 @@ options {
key-directory <quoted_string>;
lame-ttl <duration>;
listen-on [ port <integer> ] [ dscp
<integer> ] [ tls <string> ] {
<integer> ] [ tls <string> ] [ http
<string> ] {
<address_match_element>; ... }; // may occur multiple times
listen-on-v6 [ port <integer> ] [ dscp
<integer> ] [ tls <string> ] {
<integer> ] [ tls <string> ] [ http
<string> ] {
<address_match_element>; ... }; // may occur multiple times
lmdb-mapsize <sizeval>;
lock-file ( <quoted_string> | none );

View File

@@ -41,6 +41,10 @@ dnssec-policy <string> {
dyndb <string> <quoted_string> {
<unspecified-text> }; // may occur multiple times
http <string> {
endpoints { <quoted_string>; ... };
}; // may occur multiple times
key <string> {
algorithm <string>;
secret <string>;
@@ -192,6 +196,8 @@ options {
glue-cache <boolean>; // deprecated
heartbeat-interval <integer>;
hostname ( <quoted_string> | none );
http-port <integer>;
https-port <integer>;
inline-signing <boolean>;
interface-interval <duration>;
ipv4only-contact <string>;
@@ -203,10 +209,12 @@ options {
key-directory <quoted_string>;
lame-ttl <duration>;
listen-on [ port <integer> ] [ dscp
<integer> ] [ tls <string> ] {
<integer> ] [ tls <string> ] [ http
<string> ] {
<address_match_element>; ... }; // may occur multiple times
listen-on-v6 [ port <integer> ] [ dscp
<integer> ] [ tls <string> ] {
<integer> ] [ tls <string> ] [ http
<string> ] {
<address_match_element>; ... }; // may occur multiple times
lmdb-mapsize <sizeval>;
lock-file ( <quoted_string> | none );

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 );

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). [GL !4566]
Removed Features
~~~~~~~~~~~~~~~~

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 = \

180
lib/isccfg/httpconf.c Normal file
View File

@@ -0,0 +1,180 @@
/*
* 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) {
isc_mem_t *mctx = NULL;
REQUIRE(storage != NULL);
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->count--;
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->count--;
}
}
isc_mem_put(mctx, http, sizeof(*http));
http = next;
}
}
INSIST(storage->count == 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->count++;
}
ISC_LINK_INIT(new, link);
ISC_LIST_PREPEND(storage->list, new, link);
storage->count++;
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->count == 0) {
return (ISC_R_FAILURE);
}
return (ISC_R_SUCCESS);
}

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 count;
} 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 count;
} 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 */

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 */

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,31 @@ static cfg_type_t cfg_type_optional_tls = {
"tlsoptional", parse_optional_keyvalue, print_keyvalue,
doc_optional_keyvalue, &cfg_rep_string, &tls_kw
};
/* http and https */
static cfg_type_t cfg_type_bracketed_qstring_list = { "bracketed_qstring_list",
cfg_parse_bracketed_list,
cfg_print_bracketed_list,
cfg_doc_bracketed_list,
&cfg_rep_list,
&cfg_type_qstring };
static cfg_clausedef_t cfg_http_description_clauses[] = {
{ "endpoints", &cfg_type_bracketed_qstring_list, 0 }, { NULL, NULL, 0 }
};
static cfg_clausedef_t *http_description_clausesets[] = {
cfg_http_description_clauses, NULL
};
static cfg_type_t cfg_type_http_description = {
"http_desc", cfg_parse_named_map, cfg_print_map,
cfg_doc_map, &cfg_rep_map, http_description_clausesets
};
static keyword_type_t http_kw = { "http", &cfg_type_astring };
static cfg_type_t cfg_type_optional_http = {
"http_optional", parse_optional_keyvalue, print_keyvalue,
doc_optional_keyvalue, &cfg_rep_string, &http_kw
};

194
lib/isccfg/tlsconf.c Normal file
View File

@@ -0,0 +1,194 @@
/*
* 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) {
isc_mem_t *mctx = NULL;
REQUIRE(storage != NULL);
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 = NULL;
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);
}
INSIST(key_file != NULL);
if (cfg_map_get(map, "cert-file", &cert_file) != ISC_R_SUCCESS) {
return (ISC_R_FAILURE);
}
INSIST(cert_file != NULL);
(void)cfg_map_get(map, "dh-param", &dh_param);
(void)cfg_map_get(map, "protocols", &protocols);
(void)cfg_map_get(map, "ciphers", &ciphers);
new = isc_mem_get(mctx, sizeof(*new));
*new = (isc_cfg_tls_obj_t){
.name = isc_mem_strdup(mctx,
cfg_obj_asstring(map->value.map.id)),
.key_file = isc_mem_strdup(mctx, cfg_obj_asstring(key_file)),
.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);
}
INSIST(tls != NULL);
cfg_tls_storage_clear(storage);
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);
}