]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
WIP: Add preliminary DoH client support to dig artem/dns-over-https-dig
authorOndřej Surý <ondrej@isc.org>
Wed, 27 Jan 2021 14:49:27 +0000 (15:49 +0100)
committerArtem Boldariev <artem@boldariev.com>
Tue, 2 Feb 2021 18:20:10 +0000 (20:20 +0200)
bin/dig/dig.c
bin/dig/dighost.c
bin/dig/dighost.h

index 76c491f073b0326f05f5247180369b6e5b324483..7059da9cdcebdaec707899961819e48b75e9fba5 100644 (file)
@@ -228,6 +228,10 @@ help(void) {
               "SERVFAIL)\n"
               "                 +[no]header-only    (Send query without a "
               "question section)\n"
+              "                 +[no]https[=###]    (DNS over HTTPS mode) "
+              "[/]\n"
+              "                 +[no]https-get      (Use GET instead of "
+              "default POST method\n"
               "                 +[no]identify       (ID responders in short "
               "answers)\n"
 #ifdef HAVE_LIBIDN2
@@ -348,6 +352,8 @@ received(unsigned int bytes, isc_sockaddr_t *from, dig_query_t *query) {
                }
                if (query->lookup->tls_mode) {
                        proto = "TLS";
+               } else if (query->lookup->https_mode) {
+                       proto = "HTTPS";
                } else if (query->lookup->tcp_mode) {
                        proto = "TCP";
                } else {
@@ -1412,8 +1418,39 @@ plus_option(char *option, bool is_batchfile, bool *need_clone,
                lookup->servfail_stops = state;
                break;
        case 'h':
-               FULLCHECK("header-only");
-               lookup->header_only = state;
+               switch (cmd[1]) {
+               case 'e': /* header-only */
+                       FULLCHECK("header-only");
+                       lookup->header_only = state;
+                       break;
+               case 't':
+                       FULLCHECK2("https", "https-get");
+                       switch (cmd[5]) {
+                       case '\0':
+                               FULLCHECK("https");
+                               lookup->https_mode = state;
+                               if (!lookup->tcp_mode_set) {
+                                       lookup->tcp_mode = state;
+                               }
+                               if (value == NULL) {
+                                       lookup->https_path = isc_mem_strdup(
+                                               mctx, DEFAULT_HTTPS_PATH);
+                                       break;
+                               }
+                               lookup->https_path = isc_mem_strdup(mctx,
+                                                                   value);
+                               break;
+                       case '-':
+                               FULLCHECK("https-get");
+                               lookup->https_get = true;
+                               break;
+                       default:
+                               goto invalid_option;
+                       }
+                       break;
+               default:
+                       goto invalid_option;
+               }
                break;
        case 'i':
                switch (cmd[1]) {
index a8df930b54373470c4224c70e7f1d3d28110a88b..f18f6aaef5fcba3d87a08d360954da4d7d55d358 100644 (file)
@@ -608,97 +608,35 @@ make_empty_lookup(void) {
 
        INSIST(!free_now);
 
-       looknew = isc_mem_allocate(mctx, sizeof(struct dig_lookup));
-       looknew->pending = true;
-       looknew->textname[0] = 0;
-       looknew->cmdline[0] = 0;
-       looknew->rdtype = dns_rdatatype_a;
-       looknew->qrdtype = dns_rdatatype_a;
-       looknew->rdclass = dns_rdataclass_in;
-       looknew->rdtypeset = false;
-       looknew->rdclassset = false;
-       looknew->sendspace = NULL;
-       looknew->sendmsg = NULL;
-       looknew->name = NULL;
-       looknew->oname = NULL;
-       looknew->xfr_q = NULL;
-       looknew->current_query = NULL;
-       looknew->doing_xfr = false;
-       looknew->ixfr_serial = 0;
-       looknew->trace = false;
-       looknew->trace_root = false;
-       looknew->identify = false;
-       looknew->identify_previous_line = false;
-       looknew->ignore = false;
-       looknew->servfail_stops = true;
-       looknew->besteffort = true;
-       looknew->dns64prefix = false;
-       looknew->dnssec = false;
-       looknew->ednsflags = 0;
-       looknew->opcode = dns_opcode_query;
-       looknew->expire = false;
-       looknew->nsid = false;
-       looknew->tcp_keepalive = false;
-       looknew->padding = 0;
-       looknew->header_only = false;
-       looknew->sendcookie = false;
-       looknew->seenbadcookie = false;
-       looknew->badcookie = true;
-       looknew->multiline = false;
-       looknew->nottl = false;
-       looknew->noclass = false;
-       looknew->onesoa = false;
-       looknew->use_usec = false;
-       looknew->nocrypto = false;
-       looknew->ttlunits = false;
-       looknew->expandaaaa = false;
-       looknew->qr = false;
+       looknew = isc_mem_allocate(mctx, sizeof(*looknew));
+       *looknew = (dig_lookup_t){
+               .pending = true,
+               .rdtype = dns_rdatatype_a,
+               .qrdtype = dns_rdatatype_a,
+               .rdclass = dns_rdataclass_in,
+               .servfail_stops = true,
+               .besteffort = true,
+               .opcode = dns_opcode_query,
+               .badcookie = true,
 #ifdef HAVE_LIBIDN2
-       looknew->idnin = isatty(1) ? (getenv("IDN_DISABLE") == NULL) : false;
-       looknew->idnout = looknew->idnin;
-#else  /* ifdef HAVE_LIBIDN2 */
-       looknew->idnin = false;
-       looknew->idnout = false;
+               .idnin = isatty(1) ? (getenv("IDN_DISABLE") == NULL) : false,
+               .idnout = looknew->idnin,
 #endif /* HAVE_LIBIDN2 */
-       looknew->udpsize = -1;
-       looknew->edns = -1;
-       looknew->recurse = true;
-       looknew->aaonly = false;
-       looknew->adflag = false;
-       looknew->cdflag = false;
-       looknew->raflag = false;
-       looknew->tcflag = false;
-       looknew->print_unknown_format = false;
-       looknew->zflag = false;
-       looknew->setqid = false;
-       looknew->qid = 0;
-       looknew->ns_search_only = false;
-       looknew->origin = NULL;
-       looknew->tsigctx = NULL;
-       looknew->querysig = NULL;
-       looknew->retries = tries;
-       looknew->nsfound = 0;
-       looknew->tcp_mode = false;
-       looknew->tcp_mode_set = false;
-       looknew->tls_mode = false;
-       looknew->comments = true;
-       looknew->stats = true;
-       looknew->section_question = true;
-       looknew->section_answer = true;
-       looknew->section_authority = true;
-       looknew->section_additional = true;
-       looknew->new_search = false;
-       looknew->done_as_is = false;
-       looknew->need_search = false;
-       looknew->ecs_addr = NULL;
-       looknew->cookie = NULL;
-       looknew->ednsopts = NULL;
-       looknew->ednsoptscnt = 0;
-       looknew->ednsneg = true;
-       looknew->mapped = true;
-       looknew->dscp = -1;
-       looknew->rrcomments = 0;
-       looknew->eoferr = 0;
+               .udpsize = -1,
+               .edns = -1,
+               .recurse = true,
+               .retries = tries,
+               .comments = true,
+               .stats = true,
+               .section_question = true,
+               .section_answer = true,
+               .section_authority = true,
+               .section_additional = true,
+               .ednsneg = true,
+               .mapped = true,
+               .dscp = -1,
+       };
+
        dns_fixedname_init(&looknew->fdomain);
        ISC_LINK_INIT(looknew, link);
        ISC_LIST_INIT(looknew->q);
@@ -787,6 +725,11 @@ clone_lookup(dig_lookup_t *lookold, bool servers) {
        looknew->nsid = lookold->nsid;
        looknew->tcp_keepalive = lookold->tcp_keepalive;
        looknew->header_only = lookold->header_only;
+       looknew->https_mode = lookold->https_mode;
+       if (lookold->https_path != NULL) {
+               looknew->https_path = isc_mem_strdup(mctx, lookold->https_path);
+       }
+       looknew->https_get = lookold->https_get;
        looknew->sendcookie = lookold->sendcookie;
        looknew->seenbadcookie = lookold->seenbadcookie;
        looknew->badcookie = lookold->badcookie;
@@ -1638,6 +1581,10 @@ _destroy_lookup(dig_lookup_t *lookup) {
                isc_mem_free(mctx, lookup->ednsopts);
        }
 
+       if (lookup->https_path) {
+               isc_mem_free(mctx, lookup->https_path);
+       }
+
        isc_mem_free(mctx, lookup);
 }
 
@@ -2760,7 +2707,17 @@ start_tcp(dig_query_t *query) {
         * For TLS connections, we want to override the default
         * port number.
         */
-       port = port_set ? port : (query->lookup->tls_mode ? 853 : 53);
+       if (!port_set) {
+               if (query->lookup->tls_mode) {
+                       port = 853;
+               } else if (query->lookup->https_mode) {
+                       port = 443;
+               } else {
+                       port = 53;
+               }
+       }
+
+       fprintf(stderr, "query->servname = %s\n", query->servname);
 
        result = get_address(query->servname, port, &query->sockaddr);
        if (result != ISC_R_SUCCESS) {
@@ -2835,7 +2792,27 @@ start_tcp(dig_query_t *query) {
                                (isc_nmiface_t *)&query->sockaddr,
                                tcp_connected, query, local_timeout, 0,
                                query->tlsctx);
-                       check_result(result, "isc_nm_tcpdnsconnect");
+                       check_result(result, "isc_nm_tlsdnsconnect");
+               } else if (query->lookup->https_mode) {
+                       char portbuf[12];
+                       char uri[4096] = { 0 };
+                       snprintf(portbuf, sizeof(portbuf), "%u",
+                                (uint16_t)port);
+
+                       strlcpy(uri, "https://", sizeof(uri));
+                       strlcat(uri, query->servname, sizeof(uri));
+                       strlcat(uri, ":", sizeof(uri));
+                       strlcat(uri, portbuf, sizeof(uri));
+                       strlcat(uri, query->lookup->https_path, sizeof(uri));
+
+                       result = isc_tlsctx_createclient(&query->tlsctx);
+                       RUNTIME_CHECK(result == ISC_R_SUCCESS);
+                       result = isc_nm_httpconnect(
+                               netmgr, (isc_nmiface_t *)&localaddr,
+                               (isc_nmiface_t *)&query->sockaddr, uri,
+                               !query->lookup->https_get, tcp_connected, query,
+                               query->tlsctx, local_timeout, 0);
+                       check_result(result, "isc_nm_httpconnect");
                } else {
                        result = isc_nm_tcpdnsconnect(
                                netmgr, (isc_nmiface_t *)&localaddr,
@@ -3183,7 +3160,12 @@ launch_next_query(dig_query_t *query) {
        isc_nmhandle_settimeout(query->handle, local_timeout);
 
        query_attach(query, &readquery);
-       isc_nm_read(query->handle, recv_done, readquery);
+       if (query->lookup->https_mode) {
+               isc_nm_httprequest(query->handle, &r, recv_done, readquery);
+               goto cleanup;
+       } else {
+               isc_nm_read(query->handle, recv_done, readquery);
+       }
 
        if (!query->first_soa_rcvd) {
                dig_query_t *sendquery = NULL;
@@ -3211,6 +3193,7 @@ launch_next_query(dig_query_t *query) {
                        }
                }
        }
+cleanup:
        lookup_detach(&l);
        return;
 }
index b719b4856e5f7e1ebab3baaa01c74fa39543ab61..d124486fdb95d24d352c21ccc7a051dbb2f7dffa 100644 (file)
@@ -76,6 +76,9 @@
 #define DEFAULT_EDNS_VERSION 0
 #define DEFAULT_EDNS_BUFSIZE 1232
 
+#define DEFAULT_HTTPS_PATH  "/dns-query"
+#define DEFAULT_HTTPS_QUERY "?dns="
+
 /*%
  * Lookup_limit is just a limiter, keeping too many lookups from being
  * created.  It's job is mainly to prevent the program from running away
@@ -168,6 +171,11 @@ struct dig_lookup {
        int rrcomments;
        unsigned int eoferr;
        uint16_t qid;
+       struct {
+               bool https_mode;
+               bool https_get;
+               char *https_path;
+       };
 };
 
 /*% The dig_query structure */