]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Add parser support for DoH configuration options
authorEvan Hunt <each@isc.org>
Wed, 16 Sep 2020 19:21:32 +0000 (12:21 -0700)
committerOndřej Surý <ondrej@sury.org>
Wed, 3 Feb 2021 11:06:17 +0000 (12:06 +0100)
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.

25 files changed:
bin/named/config.c
bin/named/include/named/globals.h
bin/named/main.c
bin/named/named.conf.rst
bin/named/named.rst
bin/tests/system/checkconf/good-doh-global.conf [new file with mode: 0644]
bin/tests/system/checkconf/good-dot-global.conf [new file with mode: 0644]
bin/tests/system/conf.sh.common
bin/tests/system/get_ports.sh
bin/tests/system/run.sh.in
doc/arm/reference.rst
doc/man/named.8in
doc/man/named.conf.5in
doc/misc/Makefile.am
doc/misc/http.grammar.rst [new file with mode: 0644]
doc/misc/options
doc/misc/options.active
doc/misc/options.grammar.rst
doc/notes/notes-current.rst
lib/isccfg/Makefile.am
lib/isccfg/httpconf.c [new file with mode: 0644]
lib/isccfg/include/isccfg/httpconf.h [new file with mode: 0644]
lib/isccfg/include/isccfg/tlsconf.h [new file with mode: 0644]
lib/isccfg/namedconf.c
lib/isccfg/tlsconf.c [new file with mode: 0644]

index 72094f8302ee854b140fc16cc15c725fda02583e..99af2dd570cb7c9420b5581b9032cc1d0acd3881 100644 (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\
index 501bedaea4c8bde056e0b6477db68aa30ca2923c..302eb10cd39011ac3037493932a122fc84be66d4 100644 (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);
index eacb18cc813f623a1ce6fd671f9b744520ffdda3..cfdc941e05597a357163607264fa1cc07258ba2d 100644 (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();
index 722c514dbce29e2f269568cc9a8ddc28e9158427..08a1476bc3c523edbd2d9398c648ac96e7833941 100644 (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 );
index 9b039cdbf0280aa5a7134814c063224c5a849aea..c2b19f6dd60d13302bedbc12d57647a93ca93424 100644 (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.
 
diff --git a/bin/tests/system/checkconf/good-doh-global.conf b/bin/tests/system/checkconf/good-doh-global.conf
new file mode 100644 (file)
index 0000000..f5eb634
--- /dev/null
@@ -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; };
+};
diff --git a/bin/tests/system/checkconf/good-dot-global.conf b/bin/tests/system/checkconf/good-dot-global.conf
new file mode 100644 (file)
index 0000000..2a17297
--- /dev/null
@@ -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; };
+};
index de998c050e5552aaeee58b9f9e07d4f043fae2e5..df88dd1d1065aa688d3c1524fc4ae630c743adf1 100644 (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" \
index eac854d65c8a337e31c1fdebcd5ce0602d2b9c52..f63ba472535a98c63b41f31ff4d8ddbdfe1b7874 100755 (executable)
@@ -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)"
index e802332c8cc8f8beae382c2f483e2de097d45657..38021817622d5ac33faa923f94dfa11da935c6b6 100644 (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."
index f3599be319ffaf00bcd655d6ad874d6270b96989..7f304cfc119a68d895e4e9afd6856818db10179e 100644 (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
index db3ddd4176b148021809115f5203d7503f515917..f758454cdebb4740af190a82dd82986c1b36f3db 100644 (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.
index 7884fd5f28c80b22fa2f99dcc51fc9c9e95e134c..a26bcf3c0bb48b20349d3c735fb2c9e8f869dc7c 100644 (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 );
index d4db7194a6f421fbeab35ef620b4aceab984d0a3..e78e108171c83069b11619ee764a48c4349a1bb1 100644 (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
diff --git a/doc/misc/http.grammar.rst b/doc/misc/http.grammar.rst
new file mode 100644 (file)
index 0000000..dcb66a2
--- /dev/null
@@ -0,0 +1,5 @@
+::
+
+  http <string> {
+       endpoints { <quoted_string>; ... };
+  };
index 1e5bedec9c3edffe722301238869dc27ea211175..39da1adf993b6da132387934997ce25cabc39a5f 100644 (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 );
index 0e007d68554e19d6e2d86f1792ace16b3375ce05..9ac0f03351baf7f6865cfdc5faf77311a5930ad3 100644 (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 );
index 30aee7b7c98a6292dde8d7c6978bd2bf4383aa85..5176f572bd6f09123577b0a1ac34b740c8bab054 100644 (file)
        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>;
        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 );
index 844902dcf4ffa6660f5768c946be2ceadb195cc0..ae6b01a7e29f0d6e5088d3b93e0fe70293b902d6 100644 (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
 ~~~~~~~~~~~~~~~~
 
index 3205e3b93bb9ff7b5bc2db137c7b3e95761a4507..e13294281b477961eab051a9797a4956e8a1dcea 100644 (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 =                        \
diff --git a/lib/isccfg/httpconf.c b/lib/isccfg/httpconf.c
new file mode 100644 (file)
index 0000000..cd210b5
--- /dev/null
@@ -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);
+}
diff --git a/lib/isccfg/include/isccfg/httpconf.h b/lib/isccfg/include/isccfg/httpconf.h
new file mode 100644 (file)
index 0000000..bf049b9
--- /dev/null
@@ -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 */
diff --git a/lib/isccfg/include/isccfg/tlsconf.h b/lib/isccfg/include/isccfg/tlsconf.h
new file mode 100644 (file)
index 0000000..534236a
--- /dev/null
@@ -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 */
index c18196ea5b333fc06d28bc2c4684000f301f39b5..e90ab215f855edc77ce75926ba62b57cf68c63ce 100644 (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
+};
diff --git a/lib/isccfg/tlsconf.c b/lib/isccfg/tlsconf.c
new file mode 100644 (file)
index 0000000..6320fc5
--- /dev/null
@@ -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);
+}