2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-31 14:35:26 +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\ # pid-file \"" NAMED_LOCALSTATEDIR "/run/named/named.pid\"; \n\
port 53;\n\ port 53;\n\
tls-port 853;\n\ tls-port 853;\n\
http-port 80;\n\
https-port 443;\n\
prefetch 2 9;\n\ prefetch 2 9;\n\
recursing-file \"named.recursing\";\n\ recursing-file \"named.recursing\";\n\
recursive-clients 1000;\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 const char *named_g_builder INIT(PACKAGE_BUILDER);
EXTERN in_port_t named_g_port INIT(0); EXTERN in_port_t named_g_port INIT(0);
EXTERN in_port_t named_g_tlsport 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 isc_dscp_t named_g_dscp INIT(-1);
EXTERN named_server_t *named_g_server INIT(NULL); EXTERN named_server_t *named_g_server INIT(NULL);

View File

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

View File

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

View File

@@ -115,6 +115,8 @@ Options
``portnum``; if not not specified, the default is port 53. If ``portnum``; if not not specified, the default is port 53. If
``value`` is of the form ``tls=<portnum>``, the server will ``value`` is of the form ``tls=<portnum>``, the server will
listen for TLS queries on ``portnum``; the default is 853. 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`` ``-s``
This option writes memory usage statistics to ``stdout`` on exit. 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="@" atsign="@"
sed -e "s/${atsign}PORT${atsign}/${PORT}/g" \ sed -e "s/${atsign}PORT${atsign}/${PORT}/g" \
-e "s/${atsign}TLSPORT${atsign}/${TLSPORT}/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}EXTRAPORT1${atsign}/${EXTRAPORT1}/g" \
-e "s/${atsign}EXTRAPORT2${atsign}/${EXTRAPORT2}/g" \ -e "s/${atsign}EXTRAPORT2${atsign}/${EXTRAPORT2}/g" \
-e "s/${atsign}EXTRAPORT3${atsign}/${EXTRAPORT3}/g" \ -e "s/${atsign}EXTRAPORT3${atsign}/${EXTRAPORT3}/g" \

View File

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

View File

@@ -149,7 +149,7 @@ stop_servers() {
echostart "S:$systest:$(date_with_args)" echostart "S:$systest:$(date_with_args)"
echoinfo "T:$systest:1:A" echoinfo "T:$systest:1:A"
echoinfo "A:$systest:System test $systest" 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" || { $PERL ${srcdir}/testsock.pl -p "$PORT" || {
echowarn "I:$systest:Network interface aliases not set up. Skipping test." 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` the default is the ``named`` working directory. See :ref:`acl`
for details about ``geoip`` ACLs. 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`` ``key-directory``
This is the directory where the public and private DNSSEC key files should be 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 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 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.
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 ``listen-on`` takes an optional port, an optional TLS configuration
identifier, and an ``address_match_list`` of IPv4 addresses. (IPv6 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; }; 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:
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 \fBportnum\fP; if not not specified, the default is port 53. If
\fBvalue\fP is of the form \fBtls=<portnum>\fP, the server will \fBvalue\fP is of the form \fBtls=<portnum>\fP, the server will
listen for TLS queries on \fBportnum\fP; the default is 853. 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 .TP
.B \fB\-s\fP .B \fB\-s\fP
This option writes memory usage statistics to \fBstdout\fP on exit. This option writes memory usage statistics to \fBstdout\fP on exit.

View File

@@ -132,6 +132,19 @@ dyndb string quoted_string {
.fi .fi
.UNINDENT .UNINDENT
.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 .SS KEY
.INDENT 0.0 .INDENT 0.0
.INDENT 3.5 .INDENT 3.5
@@ -327,6 +340,8 @@ options {
glue\-cache boolean;// deprecated glue\-cache boolean;// deprecated
heartbeat\-interval integer; heartbeat\-interval integer;
hostname ( quoted_string | none ); hostname ( quoted_string | none );
http\-port integer;
https\-port integer;
inline\-signing boolean; inline\-signing boolean;
interface\-interval duration; interface\-interval duration;
ipv4only\-contact string; ipv4only\-contact string;
@@ -338,10 +353,12 @@ options {
key\-directory quoted_string; key\-directory quoted_string;
lame\-ttl duration; lame\-ttl duration;
listen\-on [ port integer ] [ dscp listen\-on [ port integer ] [ dscp
integer ] [ tls string ] { integer ] [ tls string ] [ http
string ] {
address_match_element; ... }; address_match_element; ... };
listen\-on\-v6 [ port integer ] [ dscp listen\-on\-v6 [ port integer ] [ dscp
integer ] [ tls string ] { integer ] [ tls string ] [ http
string ] {
address_match_element; ... }; address_match_element; ... };
lmdb\-mapsize sizeval; lmdb\-mapsize sizeval;
lock\-file ( quoted_string | none ); lock\-file ( quoted_string | none );

View File

@@ -37,7 +37,8 @@ OPTIONS_FILES = \
tls.grammar.rst \ tls.grammar.rst \
trust-anchors.grammar.rst \ trust-anchors.grammar.rst \
managed-keys.grammar.rst \ managed-keys.grammar.rst \
trusted-keys.grammar.rst trusted-keys.grammar.rst \
http.grammar.rst
EXTRA_DIST = \ EXTRA_DIST = \
$(OPTIONS_FILES) \ $(OPTIONS_FILES) \
@@ -175,4 +176,7 @@ managed-keys.grammar.rst: options.active
trusted-keys.grammar.rst: options.active trusted-keys.grammar.rst: options.active
$(AM_V_RST_GRAMMARS)$(PERL) $(srcdir)/rst-grammars.pl options.active trusted-keys > $@ $(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 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> { dyndb <string> <quoted_string> {
<unspecified-text> }; // may occur multiple times <unspecified-text> }; // may occur multiple times
http <string> {
endpoints { <quoted_string>; ... };
}; // may occur multiple times
key <string> { key <string> {
algorithm <string>; algorithm <string>;
secret <string>; secret <string>;
@@ -193,6 +197,8 @@ options {
glue-cache <boolean>; // deprecated glue-cache <boolean>; // deprecated
heartbeat-interval <integer>; heartbeat-interval <integer>;
hostname ( <quoted_string> | none ); hostname ( <quoted_string> | none );
http-port <integer>;
https-port <integer>;
inline-signing <boolean>; inline-signing <boolean>;
interface-interval <duration>; interface-interval <duration>;
ipv4only-contact <string>; ipv4only-contact <string>;
@@ -204,10 +210,12 @@ options {
key-directory <quoted_string>; key-directory <quoted_string>;
lame-ttl <duration>; lame-ttl <duration>;
listen-on [ port <integer> ] [ dscp listen-on [ port <integer> ] [ dscp
<integer> ] [ tls <string> ] { <integer> ] [ tls <string> ] [ http
<string> ] {
<address_match_element>; ... }; // may occur multiple times <address_match_element>; ... }; // may occur multiple times
listen-on-v6 [ port <integer> ] [ dscp listen-on-v6 [ port <integer> ] [ dscp
<integer> ] [ tls <string> ] { <integer> ] [ tls <string> ] [ http
<string> ] {
<address_match_element>; ... }; // may occur multiple times <address_match_element>; ... }; // may occur multiple times
lmdb-mapsize <sizeval>; lmdb-mapsize <sizeval>;
lock-file ( <quoted_string> | none ); lock-file ( <quoted_string> | none );

View File

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

View File

@@ -119,6 +119,8 @@
glue-cache <boolean>; // deprecated glue-cache <boolean>; // deprecated
heartbeat-interval <integer>; heartbeat-interval <integer>;
hostname ( <quoted_string> | none ); hostname ( <quoted_string> | none );
http-port <integer>;
https-port <integer>;
inline-signing <boolean>; inline-signing <boolean>;
interface-interval <duration>; interface-interval <duration>;
ipv4only-contact <string>; ipv4only-contact <string>;
@@ -130,10 +132,12 @@
key-directory <quoted_string>; key-directory <quoted_string>;
lame-ttl <duration>; lame-ttl <duration>;
listen-on [ port <integer> ] [ dscp listen-on [ port <integer> ] [ dscp
<integer> ] [ tls <string> ] { <integer> ] [ tls <string> ] [ http
<string> ] {
<address_match_element>; ... }; <address_match_element>; ... };
listen-on-v6 [ port <integer> ] [ dscp listen-on-v6 [ port <integer> ] [ dscp
<integer> ] [ tls <string> ] { <integer> ] [ tls <string> ] [ http
<string> ] {
<address_match_element>; ... }; <address_match_element>; ... };
lmdb-mapsize <sizeval>; lmdb-mapsize <sizeval>;
lock-file ( <quoted_string> | none ); lock-file ( <quoted_string> | none );

View File

@@ -52,6 +52,13 @@ New Features
an optional ``tls`` option which specifies either a previously configured an optional ``tls`` option which specifies either a previously configured
``tls`` statement or ``ephemeral``. [GL #2392] ``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 Removed Features
~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~

View File

@@ -7,17 +7,21 @@ libisccfg_la_HEADERS = \
include/isccfg/aclconf.h \ include/isccfg/aclconf.h \
include/isccfg/cfg.h \ include/isccfg/cfg.h \
include/isccfg/grammar.h \ include/isccfg/grammar.h \
include/isccfg/httpconf.h \
include/isccfg/kaspconf.h \ include/isccfg/kaspconf.h \
include/isccfg/log.h \ include/isccfg/log.h \
include/isccfg/namedconf.h include/isccfg/namedconf.h \
include/isccfg/tlsconf.h
libisccfg_la_SOURCES = \ libisccfg_la_SOURCES = \
$(libisccfg_la_HEADERS) \ $(libisccfg_la_HEADERS) \
aclconf.c \ aclconf.c \
httpconf.c \
dnsconf.c \ dnsconf.c \
kaspconf.c \ kaspconf.c \
log.c \ log.c \
namedconf.c \ namedconf.c \
tlsconf.c \
parser.c parser.c
libisccfg_la_CPPFLAGS = \ 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_namesockaddrkeylist;
static cfg_type_t cfg_type_bracketed_netaddrlist; static cfg_type_t cfg_type_bracketed_netaddrlist;
static cfg_type_t cfg_type_bracketed_sockaddrnameportlist; 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;
static cfg_type_t cfg_type_controls_sockaddr; static cfg_type_t cfg_type_controls_sockaddr;
static cfg_type_t cfg_type_destinationlist; 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_dnstapoutput;
static cfg_type_t cfg_type_dyndb; static cfg_type_t cfg_type_dyndb;
static cfg_type_t cfg_type_plugin; 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_ixfrdifftype;
static cfg_type_t cfg_type_ixfrratio; static cfg_type_t cfg_type_ixfrratio;
static cfg_type_t cfg_type_key; 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_class;
static cfg_type_t cfg_type_optional_dscp; static cfg_type_t cfg_type_optional_dscp;
static cfg_type_t cfg_type_optional_facility; 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_keyref;
static cfg_type_t cfg_type_optional_port; static cfg_type_t cfg_type_optional_port;
static cfg_type_t cfg_type_optional_uint32; static cfg_type_t cfg_type_optional_uint32;
@@ -151,6 +154,7 @@ static cfg_tuplefielddef_t listenon_fields[] = {
{ "port", &cfg_type_optional_port, 0 }, { "port", &cfg_type_optional_port, 0 },
{ "dscp", &cfg_type_optional_dscp, 0 }, { "dscp", &cfg_type_optional_dscp, 0 },
{ "tls", &cfg_type_optional_tls, 0 }, { "tls", &cfg_type_optional_tls, 0 },
{ "http", &cfg_type_optional_http, 0 },
{ "acl", &cfg_type_bracketed_aml, 0 }, { "acl", &cfg_type_bracketed_aml, 0 },
{ NULL, NULL, 0 } { NULL, NULL, 0 }
}; };
@@ -1088,6 +1092,7 @@ static cfg_clausedef_t namedconf_clauses[] = {
{ "acl", &cfg_type_acl, CFG_CLAUSEFLAG_MULTI }, { "acl", &cfg_type_acl, CFG_CLAUSEFLAG_MULTI },
{ "controls", &cfg_type_controls, CFG_CLAUSEFLAG_MULTI }, { "controls", &cfg_type_controls, CFG_CLAUSEFLAG_MULTI },
{ "dnssec-policy", &cfg_type_dnssecpolicy, CFG_CLAUSEFLAG_MULTI }, { "dnssec-policy", &cfg_type_dnssecpolicy, CFG_CLAUSEFLAG_MULTI },
{ "http", &cfg_type_http_description, CFG_CLAUSEFLAG_MULTI },
{ "logging", &cfg_type_logging, 0 }, { "logging", &cfg_type_logging, 0 },
{ "lwres", NULL, CFG_CLAUSEFLAG_MULTI | CFG_CLAUSEFLAG_ANCIENT }, { "lwres", NULL, CFG_CLAUSEFLAG_MULTI | CFG_CLAUSEFLAG_ANCIENT },
{ "masters", &cfg_type_primaries, CFG_CLAUSEFLAG_MULTI }, { "masters", &cfg_type_primaries, CFG_CLAUSEFLAG_MULTI },
@@ -1221,6 +1226,8 @@ static cfg_clausedef_t options_clauses[] = {
{ "pid-file", &cfg_type_qstringornone, 0 }, { "pid-file", &cfg_type_qstringornone, 0 },
{ "port", &cfg_type_uint32, 0 }, { "port", &cfg_type_uint32, 0 },
{ "tls-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 }, { "querylog", &cfg_type_boolean, 0 },
{ "random-device", &cfg_type_qstringornone, 0 }, { "random-device", &cfg_type_qstringornone, 0 },
{ "recursing-file", &cfg_type_qstring, 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, "tlsoptional", parse_optional_keyvalue, print_keyvalue,
doc_optional_keyvalue, &cfg_rep_string, &tls_kw 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);
}