diff --git a/CHANGES b/CHANGES index 3c1adb50e6..eda0b74b72 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,9 @@ +5966. [func] You can now specify if a server must return a DNS + COOKIE before accepting the response over UDP. + [GL #2295] + + server { require-cookie ; }; + 5965. [cleanup] Move the duplicated ASCII case conversion tables to isc_ascii where they can be shared, and replace the various hot-path tolower() loops with calls to new diff --git a/bin/named/server.c b/bin/named/server.c index abd700da73..0c366242ea 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -1470,6 +1470,12 @@ configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) { CHECK(dns_peer_setsendcookie(peer, cfg_obj_asboolean(obj))); } + obj = NULL; + (void)cfg_map_get(cpeer, "require-cookie", &obj); + if (obj != NULL) { + CHECK(dns_peer_setrequirecookie(peer, cfg_obj_asboolean(obj))); + } + obj = NULL; (void)cfg_map_get(cpeer, "edns", &obj); if (obj != NULL) { diff --git a/bin/tests/system/checkconf/good-server-christmas-tree.conf.in b/bin/tests/system/checkconf/good-server-christmas-tree.conf.in index a786a11cb1..f619913bee 100644 --- a/bin/tests/system/checkconf/good-server-christmas-tree.conf.in +++ b/bin/tests/system/checkconf/good-server-christmas-tree.conf.in @@ -30,6 +30,7 @@ server 0.0.0.0 { request-expire no; request-ixfr no; request-nsid no; + require-cookie no; send-cookie no; tcp-keepalive no; tcp-only no; @@ -52,6 +53,7 @@ server :: { request-expire no; request-ixfr no; request-nsid no; + require-cookie no; send-cookie no; tcp-keepalive no; tcp-only no; diff --git a/bin/tests/system/cookie/ns7/from-no-cookie-server.example.db b/bin/tests/system/cookie/ns7/from-no-cookie-server.example.db new file mode 100644 index 0000000000..8e466a6921 --- /dev/null +++ b/bin/tests/system/cookie/ns7/from-no-cookie-server.example.db @@ -0,0 +1,14 @@ +; Copyright (C) Internet Systems Consortium, Inc. ("ISC") +; +; SPDX-License-Identifier: MPL-2.0 +; +; 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. + +@ SOA ns7 hostmaster.isc.org. 1 600 600 1200 600 +@ NS ns7 +ns7 A 10.53.0.7 diff --git a/bin/tests/system/cookie/ns7/named.conf.in b/bin/tests/system/cookie/ns7/named.conf.in index c9518ae051..c910880cb7 100644 --- a/bin/tests/system/cookie/ns7/named.conf.in +++ b/bin/tests/system/cookie/ns7/named.conf.in @@ -29,3 +29,8 @@ zone "." { type primary; file "root.db"; }; + +zone "from-no-cookie-server.example" { + type primary; + file "from-no-cookie-server.example.db"; +}; diff --git a/bin/tests/system/cookie/ns8/example.db b/bin/tests/system/cookie/ns8/example.db index 7fa64d602d..443d5db417 100644 --- a/bin/tests/system/cookie/ns8/example.db +++ b/bin/tests/system/cookie/ns8/example.db @@ -9,5 +9,7 @@ ; See the COPYRIGHT file distributed with this work for additional ; information regarding copyright ownership. -@ 3600 SOA . . 0 0 0 0 0 -@ 3600 NS . +@ 3600 SOA . . 0 0 0 0 0 +@ 3600 NS . +from-no-cookie-server 3600 NS ns7.from-no-cookie-server +ns7.from-no-cookie-server 3600 A 10.53.0.7 diff --git a/bin/tests/system/cookie/ns8/named.conf.in b/bin/tests/system/cookie/ns8/named.conf.in index 99ff66b1a2..693f06a81e 100644 --- a/bin/tests/system/cookie/ns8/named.conf.in +++ b/bin/tests/system/cookie/ns8/named.conf.in @@ -33,6 +33,8 @@ options { require-server-cookie yes; }; +server 10.53.0.7 { require-cookie yes; }; + zone "example" { type primary; file "example.db"; diff --git a/bin/tests/system/cookie/tests.sh b/bin/tests/system/cookie/tests.sh index 2e5de5ae90..fc8e4225b7 100755 --- a/bin/tests/system/cookie/tests.sh +++ b/bin/tests/system/cookie/tests.sh @@ -214,6 +214,17 @@ if [ $linecount != 2 ]; then ret=1; fi if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` +n=`expr $n + 1` +echo_i "checking 'server { require-cookie yes; };' triggers TCP when cookie not returned ($n)" +ret=0 +nextpart ns8/named.run > /dev/null +$DIG $DIGOPTS +cookie soa from-no-cookie-server.example @10.53.0.8 > dig.out.test$n +grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1 +wait_for_log_peek 3 "missing required cookie from 10.53.0.7#" ns8/named.run || ret=1 +wait_for_log_peek 3 "from-no-cookie-server.example/SOA): connecting via TCP" ns8/named.run || ret=1 +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` + n=`expr $n + 1` echo_i "send undersized cookie ($n)" ret=0 diff --git a/doc/arm/reference.rst b/doc/arm/reference.rst index c6fd9f505e..3d9b2a6c6f 100644 --- a/doc/arm/reference.rst +++ b/doc/arm/reference.rst @@ -2320,6 +2320,34 @@ Boolean Options option in its response, then its contents are logged in the ``nsid`` category at level ``info``. The default is ``no``. +.. namedconf:statement:: require-cookie + :tags: query + :short: Controls whether responses without a server cookie are accepted + + The ``require-cookie`` clause can be used to indicate that the + remote server is known to support DNS COOKIE. Setting this option + to ``yes`` causes ``named`` to always retry a request over TCP when + it receives a UDP response without a DNS COOKIE from the remote + server, even if UDP responses with DNS COOKIE have not been sent + by this server before. This prevents spoofed answers from being + accepted without a retry over TCP when ``named`` has not yet + determined whether the remote server supports DNS COOKIE. Setting + this option to ``no`` (the default) causes ``named`` to rely on + autodetection of DNS COOKIE support to determine when to retry a + request over TCP. + + + .. note:: + If a UDP response is signed using TSIG, ``named`` accepts it even if + ``require-cookie`` is set to ``yes`` and the response does not + contain a DNS COOKIE. + + The ``send-cookie`` clause determines whether the local server adds + a COOKIE EDNS option to requests sent to the server. This overrides + ``send-cookie`` set at the view or option level. The :iscman:`named` server + may determine that COOKIE is not supported by the remote server and not + add a COOKIE EDNS option to requests. + .. namedconf:statement:: require-server-cookie :tags: query :short: Controls whether a valid server cookie is required before sending a full response to a UDP request. @@ -5829,6 +5857,7 @@ and :namedconf:ref:`options` blocks: - :namedconf:ref:`request-expire` - :namedconf:ref:`request-ixfr` - :namedconf:ref:`request-nsid` + - :namedconf:ref:`require-cookie` - :namedconf:ref:`send-cookie` - :namedconf:ref:`transfer-format` - :namedconf:ref:`transfer-source-v6` diff --git a/doc/man/named.conf.5in b/doc/man/named.conf.5in index 47ef15b08e..9f448cf68d 100644 --- a/doc/man/named.conf.5in +++ b/doc/man/named.conf.5in @@ -399,6 +399,7 @@ server { request\-expire ; request\-ixfr ; request\-nsid ; + require\-cookie ; send\-cookie ; tcp\-keepalive ; tcp\-only ; @@ -612,6 +613,7 @@ view [ ] { request\-expire ; request\-ixfr ; request\-nsid ; + require\-cookie ; send\-cookie ; tcp\-keepalive ; tcp\-only ; diff --git a/doc/misc/options b/doc/misc/options index 6b0609394f..5de8c20b60 100644 --- a/doc/misc/options +++ b/doc/misc/options @@ -342,6 +342,7 @@ server { request-expire ; request-ixfr ; request-nsid ; + require-cookie ; send-cookie ; tcp-keepalive ; tcp-only ; @@ -555,6 +556,7 @@ view [ ] { request-expire ; request-ixfr ; request-nsid ; + require-cookie ; send-cookie ; tcp-keepalive ; tcp-only ; diff --git a/doc/notes/notes-current.rst b/doc/notes/notes-current.rst index 6b9730770d..e1f3761303 100644 --- a/doc/notes/notes-current.rst +++ b/doc/notes/notes-current.rst @@ -27,6 +27,12 @@ New Features - None. +- A new configuration option ``require-cookie`` has been introduced, it + specifies if there should be a DNS COOKIE in the response for a given + prefix and if not named falls back to TCP. This is useful if you know + a given server support DNS COOKIE. It can also be used to force all + non DNS COOKIE responses to fall back to TCP. :gl:`#2295` + Removed Features ~~~~~~~~~~~~~~~~ diff --git a/lib/dns/include/dns/peer.h b/lib/dns/include/dns/peer.h index d4a7b12640..4037386140 100644 --- a/lib/dns/include/dns/peer.h +++ b/lib/dns/include/dns/peer.h @@ -118,6 +118,12 @@ dns_peer_setsendcookie(dns_peer_t *peer, bool newval); isc_result_t dns_peer_getsendcookie(dns_peer_t *peer, bool *retval); +isc_result_t +dns_peer_setrequirecookie(dns_peer_t *peer, bool newval); + +isc_result_t +dns_peer_getrequirecookie(dns_peer_t *peer, bool *retval); + isc_result_t dns_peer_setrequestexpire(dns_peer_t *peer, bool newval); diff --git a/lib/dns/peer.c b/lib/dns/peer.c index bac2624e09..bca288c4bb 100644 --- a/lib/dns/peer.c +++ b/lib/dns/peer.c @@ -56,6 +56,7 @@ struct dns_peer { bool support_edns; bool request_nsid; bool send_cookie; + bool require_cookie; bool request_expire; bool force_tcp; bool tcp_keepalive; @@ -98,6 +99,7 @@ struct dns_peer { #define FORCE_TCP_BIT 15 #define SERVER_PADDING_BIT 16 #define REQUEST_TCP_KEEPALIVE_BIT 17 +#define REQUIRE_COOKIE_BIT 18 static void peerlist_delete(dns_peerlist_t **list); @@ -348,302 +350,141 @@ peer_delete(dns_peer_t **peer) { isc_mem_put(mem, p, sizeof(*p)); } -isc_result_t -dns_peer_setbogus(dns_peer_t *peer, bool newval) { - bool existed; - - REQUIRE(DNS_PEER_VALID(peer)); - - existed = DNS_BIT_CHECK(BOGUS_BIT, &peer->bitflags); - - peer->bogus = newval; - DNS_BIT_SET(BOGUS_BIT, &peer->bitflags); - - return (existed ? ISC_R_EXISTS : ISC_R_SUCCESS); -} - -isc_result_t -dns_peer_getbogus(dns_peer_t *peer, bool *retval) { - REQUIRE(DNS_PEER_VALID(peer)); - REQUIRE(retval != NULL); - - if (DNS_BIT_CHECK(BOGUS_BIT, &peer->bitflags)) { - *retval = peer->bogus; - return (ISC_R_SUCCESS); - } else { - return (ISC_R_NOTFOUND); +#define ACCESS_OPTION(name, macro, type, element) \ + isc_result_t dns_peer_get##name(dns_peer_t *peer, type *value) { \ + REQUIRE(DNS_PEER_VALID(peer)); \ + REQUIRE(value != NULL); \ + if (DNS_BIT_CHECK(macro, &peer->bitflags)) { \ + *value = peer->element; \ + return (ISC_R_SUCCESS); \ + } else { \ + return (ISC_R_NOTFOUND); \ + } \ + } \ + isc_result_t dns_peer_set##name(dns_peer_t *peer, type value) { \ + bool existed; \ + REQUIRE(DNS_PEER_VALID(peer)); \ + existed = DNS_BIT_CHECK(macro, &peer->bitflags); \ + peer->element = value; \ + DNS_BIT_SET(macro, &peer->bitflags); \ + return (existed ? ISC_R_EXISTS : ISC_R_SUCCESS); \ } -} -isc_result_t -dns_peer_setprovideixfr(dns_peer_t *peer, bool newval) { - bool existed; +ACCESS_OPTION(bogus, BOGUS_BIT, bool, bogus) +ACCESS_OPTION(forcetcp, FORCE_TCP_BIT, bool, force_tcp) +ACCESS_OPTION(maxudp, SERVER_MAXUDP_BIT, uint16_t, maxudp) +ACCESS_OPTION(provideixfr, PROVIDE_IXFR_BIT, bool, provide_ixfr) +ACCESS_OPTION(requestexpire, REQUEST_EXPIRE_BIT, bool, request_expire) +ACCESS_OPTION(requestixfr, REQUEST_IXFR_BIT, bool, request_ixfr) +ACCESS_OPTION(requestnsid, REQUEST_NSID_BIT, bool, request_nsid) +ACCESS_OPTION(requirecookie, REQUIRE_COOKIE_BIT, bool, require_cookie) +ACCESS_OPTION(sendcookie, SEND_COOKIE_BIT, bool, send_cookie) +ACCESS_OPTION(supportedns, SUPPORT_EDNS_BIT, bool, support_edns) +ACCESS_OPTION(tcpkeepalive, REQUEST_TCP_KEEPALIVE_BIT, bool, tcp_keepalive) +ACCESS_OPTION(transferformat, SERVER_TRANSFER_FORMAT_BIT, dns_transfer_format_t, + transfer_format) +ACCESS_OPTION(transfers, TRANSFERS_BIT, uint32_t, transfers) +ACCESS_OPTION(udpsize, SERVER_UDPSIZE_BIT, uint16_t, udpsize) - REQUIRE(DNS_PEER_VALID(peer)); - - existed = DNS_BIT_CHECK(PROVIDE_IXFR_BIT, &peer->bitflags); - - peer->provide_ixfr = newval; - DNS_BIT_SET(PROVIDE_IXFR_BIT, &peer->bitflags); - - return (existed ? ISC_R_EXISTS : ISC_R_SUCCESS); -} - -isc_result_t -dns_peer_getprovideixfr(dns_peer_t *peer, bool *retval) { - REQUIRE(DNS_PEER_VALID(peer)); - REQUIRE(retval != NULL); - - if (DNS_BIT_CHECK(PROVIDE_IXFR_BIT, &peer->bitflags)) { - *retval = peer->provide_ixfr; - return (ISC_R_SUCCESS); - } else { - return (ISC_R_NOTFOUND); +#define ACCESS_OPTIONMAX(name, macro, type, element, max) \ + isc_result_t dns_peer_get##name(dns_peer_t *peer, type *value) { \ + REQUIRE(DNS_PEER_VALID(peer)); \ + REQUIRE(value != NULL); \ + if (DNS_BIT_CHECK(macro, &peer->bitflags)) { \ + *value = peer->element; \ + return (ISC_R_SUCCESS); \ + } else { \ + return (ISC_R_NOTFOUND); \ + } \ + } \ + isc_result_t dns_peer_set##name(dns_peer_t *peer, type value) { \ + bool existed; \ + REQUIRE(DNS_PEER_VALID(peer)); \ + existed = DNS_BIT_CHECK(macro, &peer->bitflags); \ + if (value > max) { \ + value = max; \ + } \ + peer->element = value; \ + DNS_BIT_SET(macro, &peer->bitflags); \ + return (existed ? ISC_R_EXISTS : ISC_R_SUCCESS); \ } -} -isc_result_t -dns_peer_setrequestixfr(dns_peer_t *peer, bool newval) { - bool existed; +ACCESS_OPTIONMAX(padding, SERVER_PADDING_BIT, uint16_t, padding, 512) - REQUIRE(DNS_PEER_VALID(peer)); - - existed = DNS_BIT_CHECK(REQUEST_IXFR_BIT, &peer->bitflags); - - peer->request_ixfr = newval; - DNS_BIT_SET(REQUEST_IXFR_BIT, &peer->bitflags); - - return (existed ? ISC_R_EXISTS : ISC_R_SUCCESS); -} - -isc_result_t -dns_peer_getrequestixfr(dns_peer_t *peer, bool *retval) { - REQUIRE(DNS_PEER_VALID(peer)); - REQUIRE(retval != NULL); - - if (DNS_BIT_CHECK(REQUEST_IXFR_BIT, &peer->bitflags)) { - *retval = peer->request_ixfr; - return (ISC_R_SUCCESS); - } else { - return (ISC_R_NOTFOUND); +#define ACCESS_SOCKADDR(name, element) \ + isc_result_t dns_peer_get##name(dns_peer_t *peer, \ + isc_sockaddr_t *value) { \ + REQUIRE(DNS_PEER_VALID(peer)); \ + REQUIRE(value != NULL); \ + if (peer->element == NULL) { \ + return (ISC_R_NOTFOUND); \ + } \ + *value = *peer->element; \ + return (ISC_R_SUCCESS); \ + } \ + isc_result_t dns_peer_set##name(dns_peer_t *peer, \ + const isc_sockaddr_t *value) { \ + REQUIRE(DNS_PEER_VALID(peer)); \ + if (peer->element != NULL) { \ + isc_mem_put(peer->mem, peer->element, \ + sizeof(*peer->element)); \ + peer->element = NULL; \ + } \ + if (value != NULL) { \ + peer->element = isc_mem_get(peer->mem, \ + sizeof(*peer->element)); \ + *peer->element = *value; \ + } \ + return (ISC_R_SUCCESS); \ } -} -isc_result_t -dns_peer_setsupportedns(dns_peer_t *peer, bool newval) { - bool existed; +ACCESS_SOCKADDR(notifysource, notify_source) +ACCESS_SOCKADDR(querysource, query_source) +ACCESS_SOCKADDR(transfersource, transfer_source) - REQUIRE(DNS_PEER_VALID(peer)); - - existed = DNS_BIT_CHECK(SUPPORT_EDNS_BIT, &peer->bitflags); - - peer->support_edns = newval; - DNS_BIT_SET(SUPPORT_EDNS_BIT, &peer->bitflags); - - return (existed ? ISC_R_EXISTS : ISC_R_SUCCESS); -} - -isc_result_t -dns_peer_getsupportedns(dns_peer_t *peer, bool *retval) { - REQUIRE(DNS_PEER_VALID(peer)); - REQUIRE(retval != NULL); - - if (DNS_BIT_CHECK(SUPPORT_EDNS_BIT, &peer->bitflags)) { - *retval = peer->support_edns; - return (ISC_R_SUCCESS); - } else { - return (ISC_R_NOTFOUND); +#define ACCESS_OPTION_OVERWRITE(name, macro, type, element) \ + isc_result_t dns_peer_get##name(dns_peer_t *peer, type *value) { \ + REQUIRE(DNS_PEER_VALID(peer)); \ + REQUIRE(value != NULL); \ + if (DNS_BIT_CHECK(macro, &peer->bitflags)) { \ + *value = peer->element; \ + return (ISC_R_SUCCESS); \ + } else { \ + return (ISC_R_NOTFOUND); \ + } \ + } \ + isc_result_t dns_peer_set##name(dns_peer_t *peer, type value) { \ + REQUIRE(DNS_PEER_VALID(peer)); \ + peer->element = value; \ + DNS_BIT_SET(macro, &peer->bitflags); \ + return (ISC_R_SUCCESS); \ } -} -isc_result_t -dns_peer_setrequestnsid(dns_peer_t *peer, bool newval) { - bool existed; +ACCESS_OPTION_OVERWRITE(ednsversion, EDNS_VERSION_BIT, uint8_t, ednsversion) - REQUIRE(DNS_PEER_VALID(peer)); - - existed = DNS_BIT_CHECK(REQUEST_NSID_BIT, &peer->bitflags); - - peer->request_nsid = newval; - DNS_BIT_SET(REQUEST_NSID_BIT, &peer->bitflags); - - return (existed ? ISC_R_EXISTS : ISC_R_SUCCESS); -} - -isc_result_t -dns_peer_getrequestnsid(dns_peer_t *peer, bool *retval) { - REQUIRE(DNS_PEER_VALID(peer)); - REQUIRE(retval != NULL); - - if (DNS_BIT_CHECK(REQUEST_NSID_BIT, &peer->bitflags)) { - *retval = peer->request_nsid; - return (ISC_R_SUCCESS); - } else { - return (ISC_R_NOTFOUND); +#define ACCESS_OPTION_OVERWRITEDSCP(name, macro, type, element) \ + isc_result_t dns_peer_get##name(dns_peer_t *peer, type *value) { \ + REQUIRE(DNS_PEER_VALID(peer)); \ + REQUIRE(value != NULL); \ + if (DNS_BIT_CHECK(macro, &peer->bitflags)) { \ + *value = peer->element; \ + return (ISC_R_SUCCESS); \ + } else { \ + return (ISC_R_NOTFOUND); \ + } \ + } \ + isc_result_t dns_peer_set##name(dns_peer_t *peer, type value) { \ + REQUIRE(DNS_PEER_VALID(peer)); \ + REQUIRE(value < 64); \ + peer->element = value; \ + DNS_BIT_SET(macro, &peer->bitflags); \ + return (ISC_R_SUCCESS); \ } -} - -isc_result_t -dns_peer_setsendcookie(dns_peer_t *peer, bool newval) { - bool existed; - - REQUIRE(DNS_PEER_VALID(peer)); - - existed = DNS_BIT_CHECK(SEND_COOKIE_BIT, &peer->bitflags); - - peer->send_cookie = newval; - DNS_BIT_SET(SEND_COOKIE_BIT, &peer->bitflags); - - return (existed ? ISC_R_EXISTS : ISC_R_SUCCESS); -} - -isc_result_t -dns_peer_getsendcookie(dns_peer_t *peer, bool *retval) { - REQUIRE(DNS_PEER_VALID(peer)); - REQUIRE(retval != NULL); - - if (DNS_BIT_CHECK(SEND_COOKIE_BIT, &peer->bitflags)) { - *retval = peer->send_cookie; - return (ISC_R_SUCCESS); - } else { - return (ISC_R_NOTFOUND); - } -} - -isc_result_t -dns_peer_setrequestexpire(dns_peer_t *peer, bool newval) { - bool existed; - - REQUIRE(DNS_PEER_VALID(peer)); - - existed = DNS_BIT_CHECK(REQUEST_EXPIRE_BIT, &peer->bitflags); - - peer->request_expire = newval; - DNS_BIT_SET(REQUEST_EXPIRE_BIT, &peer->bitflags); - - return (existed ? ISC_R_EXISTS : ISC_R_SUCCESS); -} - -isc_result_t -dns_peer_getrequestexpire(dns_peer_t *peer, bool *retval) { - REQUIRE(DNS_PEER_VALID(peer)); - REQUIRE(retval != NULL); - - if (DNS_BIT_CHECK(REQUEST_EXPIRE_BIT, &peer->bitflags)) { - *retval = peer->request_expire; - return (ISC_R_SUCCESS); - } else { - return (ISC_R_NOTFOUND); - } -} - -isc_result_t -dns_peer_setforcetcp(dns_peer_t *peer, bool newval) { - bool existed; - - REQUIRE(DNS_PEER_VALID(peer)); - - existed = DNS_BIT_CHECK(FORCE_TCP_BIT, &peer->bitflags); - - peer->force_tcp = newval; - DNS_BIT_SET(FORCE_TCP_BIT, &peer->bitflags); - - return (existed ? ISC_R_EXISTS : ISC_R_SUCCESS); -} - -isc_result_t -dns_peer_getforcetcp(dns_peer_t *peer, bool *retval) { - REQUIRE(DNS_PEER_VALID(peer)); - REQUIRE(retval != NULL); - - if (DNS_BIT_CHECK(FORCE_TCP_BIT, &peer->bitflags)) { - *retval = peer->force_tcp; - return (ISC_R_SUCCESS); - } else { - return (ISC_R_NOTFOUND); - } -} - -isc_result_t -dns_peer_settcpkeepalive(dns_peer_t *peer, bool newval) { - bool existed; - - REQUIRE(DNS_PEER_VALID(peer)); - - existed = DNS_BIT_CHECK(REQUEST_TCP_KEEPALIVE_BIT, &peer->bitflags); - - peer->tcp_keepalive = newval; - DNS_BIT_SET(REQUEST_TCP_KEEPALIVE_BIT, &peer->bitflags); - - return (existed ? ISC_R_EXISTS : ISC_R_SUCCESS); -} - -isc_result_t -dns_peer_gettcpkeepalive(dns_peer_t *peer, bool *retval) { - REQUIRE(DNS_PEER_VALID(peer)); - REQUIRE(retval != NULL); - - if (DNS_BIT_CHECK(REQUEST_TCP_KEEPALIVE_BIT, &peer->bitflags)) { - *retval = peer->tcp_keepalive; - return (ISC_R_SUCCESS); - } else { - return (ISC_R_NOTFOUND); - } -} - -isc_result_t -dns_peer_settransfers(dns_peer_t *peer, uint32_t newval) { - bool existed; - - REQUIRE(DNS_PEER_VALID(peer)); - - existed = DNS_BIT_CHECK(TRANSFERS_BIT, &peer->bitflags); - - peer->transfers = newval; - DNS_BIT_SET(TRANSFERS_BIT, &peer->bitflags); - - return (existed ? ISC_R_EXISTS : ISC_R_SUCCESS); -} - -isc_result_t -dns_peer_gettransfers(dns_peer_t *peer, uint32_t *retval) { - REQUIRE(DNS_PEER_VALID(peer)); - REQUIRE(retval != NULL); - - if (DNS_BIT_CHECK(TRANSFERS_BIT, &peer->bitflags)) { - *retval = peer->transfers; - return (ISC_R_SUCCESS); - } else { - return (ISC_R_NOTFOUND); - } -} - -isc_result_t -dns_peer_settransferformat(dns_peer_t *peer, dns_transfer_format_t newval) { - bool existed; - - REQUIRE(DNS_PEER_VALID(peer)); - - existed = DNS_BIT_CHECK(SERVER_TRANSFER_FORMAT_BIT, &peer->bitflags); - - peer->transfer_format = newval; - DNS_BIT_SET(SERVER_TRANSFER_FORMAT_BIT, &peer->bitflags); - - return (existed ? ISC_R_EXISTS : ISC_R_SUCCESS); -} - -isc_result_t -dns_peer_gettransferformat(dns_peer_t *peer, dns_transfer_format_t *retval) { - REQUIRE(DNS_PEER_VALID(peer)); - REQUIRE(retval != NULL); - - if (DNS_BIT_CHECK(SERVER_TRANSFER_FORMAT_BIT, &peer->bitflags)) { - *retval = peer->transfer_format; - return (ISC_R_SUCCESS); - } else { - return (ISC_R_NOTFOUND); - } -} +ACCESS_OPTION_OVERWRITEDSCP(notifydscp, NOTIFY_DSCP_BIT, isc_dscp_t, + notify_dscp) +ACCESS_OPTION_OVERWRITEDSCP(querydscp, QUERY_DSCP_BIT, isc_dscp_t, query_dscp) +ACCESS_OPTION_OVERWRITEDSCP(transferdscp, TRANSFER_DSCP_BIT, isc_dscp_t, + transfer_dscp) isc_result_t dns_peer_getkey(dns_peer_t *peer, dns_name_t **retval) { @@ -701,268 +542,3 @@ dns_peer_setkeybycharp(dns_peer_t *peer, const char *keyval) { return (result); } - -isc_result_t -dns_peer_settransfersource(dns_peer_t *peer, - const isc_sockaddr_t *transfer_source) { - REQUIRE(DNS_PEER_VALID(peer)); - - if (peer->transfer_source != NULL) { - isc_mem_put(peer->mem, peer->transfer_source, - sizeof(*peer->transfer_source)); - peer->transfer_source = NULL; - } - if (transfer_source != NULL) { - peer->transfer_source = - isc_mem_get(peer->mem, sizeof(*peer->transfer_source)); - - *peer->transfer_source = *transfer_source; - } - return (ISC_R_SUCCESS); -} - -isc_result_t -dns_peer_gettransfersource(dns_peer_t *peer, isc_sockaddr_t *transfer_source) { - REQUIRE(DNS_PEER_VALID(peer)); - REQUIRE(transfer_source != NULL); - - if (peer->transfer_source == NULL) { - return (ISC_R_NOTFOUND); - } - *transfer_source = *peer->transfer_source; - return (ISC_R_SUCCESS); -} - -isc_result_t -dns_peer_setnotifysource(dns_peer_t *peer, - const isc_sockaddr_t *notify_source) { - REQUIRE(DNS_PEER_VALID(peer)); - - if (peer->notify_source != NULL) { - isc_mem_put(peer->mem, peer->notify_source, - sizeof(*peer->notify_source)); - peer->notify_source = NULL; - } - if (notify_source != NULL) { - peer->notify_source = isc_mem_get(peer->mem, - sizeof(*peer->notify_source)); - - *peer->notify_source = *notify_source; - } - return (ISC_R_SUCCESS); -} - -isc_result_t -dns_peer_getnotifysource(dns_peer_t *peer, isc_sockaddr_t *notify_source) { - REQUIRE(DNS_PEER_VALID(peer)); - REQUIRE(notify_source != NULL); - - if (peer->notify_source == NULL) { - return (ISC_R_NOTFOUND); - } - *notify_source = *peer->notify_source; - return (ISC_R_SUCCESS); -} - -isc_result_t -dns_peer_setquerysource(dns_peer_t *peer, const isc_sockaddr_t *query_source) { - REQUIRE(DNS_PEER_VALID(peer)); - - if (peer->query_source != NULL) { - isc_mem_put(peer->mem, peer->query_source, - sizeof(*peer->query_source)); - peer->query_source = NULL; - } - if (query_source != NULL) { - peer->query_source = isc_mem_get(peer->mem, - sizeof(*peer->query_source)); - - *peer->query_source = *query_source; - } - return (ISC_R_SUCCESS); -} - -isc_result_t -dns_peer_getquerysource(dns_peer_t *peer, isc_sockaddr_t *query_source) { - REQUIRE(DNS_PEER_VALID(peer)); - REQUIRE(query_source != NULL); - - if (peer->query_source == NULL) { - return (ISC_R_NOTFOUND); - } - *query_source = *peer->query_source; - return (ISC_R_SUCCESS); -} - -isc_result_t -dns_peer_setudpsize(dns_peer_t *peer, uint16_t udpsize) { - bool existed; - - REQUIRE(DNS_PEER_VALID(peer)); - - existed = DNS_BIT_CHECK(SERVER_UDPSIZE_BIT, &peer->bitflags); - - peer->udpsize = udpsize; - DNS_BIT_SET(SERVER_UDPSIZE_BIT, &peer->bitflags); - - return (existed ? ISC_R_EXISTS : ISC_R_SUCCESS); -} - -isc_result_t -dns_peer_getudpsize(dns_peer_t *peer, uint16_t *udpsize) { - REQUIRE(DNS_PEER_VALID(peer)); - REQUIRE(udpsize != NULL); - - if (DNS_BIT_CHECK(SERVER_UDPSIZE_BIT, &peer->bitflags)) { - *udpsize = peer->udpsize; - return (ISC_R_SUCCESS); - } else { - return (ISC_R_NOTFOUND); - } -} - -isc_result_t -dns_peer_setmaxudp(dns_peer_t *peer, uint16_t maxudp) { - bool existed; - - REQUIRE(DNS_PEER_VALID(peer)); - - existed = DNS_BIT_CHECK(SERVER_MAXUDP_BIT, &peer->bitflags); - - peer->maxudp = maxudp; - DNS_BIT_SET(SERVER_MAXUDP_BIT, &peer->bitflags); - - return (existed ? ISC_R_EXISTS : ISC_R_SUCCESS); -} - -isc_result_t -dns_peer_getmaxudp(dns_peer_t *peer, uint16_t *maxudp) { - REQUIRE(DNS_PEER_VALID(peer)); - REQUIRE(maxudp != NULL); - - if (DNS_BIT_CHECK(SERVER_MAXUDP_BIT, &peer->bitflags)) { - *maxudp = peer->maxudp; - return (ISC_R_SUCCESS); - } else { - return (ISC_R_NOTFOUND); - } -} - -isc_result_t -dns_peer_setpadding(dns_peer_t *peer, uint16_t padding) { - bool existed; - - REQUIRE(DNS_PEER_VALID(peer)); - - existed = DNS_BIT_CHECK(SERVER_PADDING_BIT, &peer->bitflags); - - if (padding > 512) { - padding = 512; - } - peer->padding = padding; - DNS_BIT_SET(SERVER_PADDING_BIT, &peer->bitflags); - - return (existed ? ISC_R_EXISTS : ISC_R_SUCCESS); -} - -isc_result_t -dns_peer_getpadding(dns_peer_t *peer, uint16_t *padding) { - REQUIRE(DNS_PEER_VALID(peer)); - REQUIRE(padding != NULL); - - if (DNS_BIT_CHECK(SERVER_PADDING_BIT, &peer->bitflags)) { - *padding = peer->padding; - return (ISC_R_SUCCESS); - } else { - return (ISC_R_NOTFOUND); - } -} - -isc_result_t -dns_peer_setnotifydscp(dns_peer_t *peer, isc_dscp_t dscp) { - REQUIRE(DNS_PEER_VALID(peer)); - REQUIRE(dscp < 64); - - peer->notify_dscp = dscp; - DNS_BIT_SET(NOTIFY_DSCP_BIT, &peer->bitflags); - return (ISC_R_SUCCESS); -} - -isc_result_t -dns_peer_getnotifydscp(dns_peer_t *peer, isc_dscp_t *dscpp) { - REQUIRE(DNS_PEER_VALID(peer)); - REQUIRE(dscpp != NULL); - - if (DNS_BIT_CHECK(NOTIFY_DSCP_BIT, &peer->bitflags)) { - *dscpp = peer->notify_dscp; - return (ISC_R_SUCCESS); - } - return (ISC_R_NOTFOUND); -} - -isc_result_t -dns_peer_settransferdscp(dns_peer_t *peer, isc_dscp_t dscp) { - REQUIRE(DNS_PEER_VALID(peer)); - REQUIRE(dscp < 64); - - peer->transfer_dscp = dscp; - DNS_BIT_SET(TRANSFER_DSCP_BIT, &peer->bitflags); - return (ISC_R_SUCCESS); -} - -isc_result_t -dns_peer_gettransferdscp(dns_peer_t *peer, isc_dscp_t *dscpp) { - REQUIRE(DNS_PEER_VALID(peer)); - REQUIRE(dscpp != NULL); - - if (DNS_BIT_CHECK(TRANSFER_DSCP_BIT, &peer->bitflags)) { - *dscpp = peer->transfer_dscp; - return (ISC_R_SUCCESS); - } - return (ISC_R_NOTFOUND); -} - -isc_result_t -dns_peer_setquerydscp(dns_peer_t *peer, isc_dscp_t dscp) { - REQUIRE(DNS_PEER_VALID(peer)); - REQUIRE(dscp < 64); - - peer->query_dscp = dscp; - DNS_BIT_SET(QUERY_DSCP_BIT, &peer->bitflags); - return (ISC_R_SUCCESS); -} - -isc_result_t -dns_peer_getquerydscp(dns_peer_t *peer, isc_dscp_t *dscpp) { - REQUIRE(DNS_PEER_VALID(peer)); - REQUIRE(dscpp != NULL); - - if (DNS_BIT_CHECK(QUERY_DSCP_BIT, &peer->bitflags)) { - *dscpp = peer->query_dscp; - return (ISC_R_SUCCESS); - } - return (ISC_R_NOTFOUND); -} - -isc_result_t -dns_peer_setednsversion(dns_peer_t *peer, uint8_t ednsversion) { - REQUIRE(DNS_PEER_VALID(peer)); - - peer->ednsversion = ednsversion; - DNS_BIT_SET(EDNS_VERSION_BIT, &peer->bitflags); - - return (ISC_R_SUCCESS); -} - -isc_result_t -dns_peer_getednsversion(dns_peer_t *peer, uint8_t *ednsversion) { - REQUIRE(DNS_PEER_VALID(peer)); - REQUIRE(ednsversion != NULL); - - if (DNS_BIT_CHECK(EDNS_VERSION_BIT, &peer->bitflags)) { - *ednsversion = peer->ednsversion; - return (ISC_R_SUCCESS); - } else { - return (ISC_R_NOTFOUND); - } -} diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index e424835f0b..9051fdc201 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -7714,7 +7714,9 @@ resquery_response(isc_result_t eresult, isc_region_t *region, void *arg) { /* * If we have had a server cookie and don't get one retry over * TCP. This may be a misconfigured anycast server or an attempt - * to send a spoofed response. Skip if we have a valid tsig. + * to send a spoofed response. Additionally retry over TCP if + * require-cookie is true and we don't have a got client cookie. + * Skip if we have a valid TSIG. */ if (dns_message_gettsig(query->rmessage, NULL) == NULL && !query->rmessage->cc_ok && !query->rmessage->cc_bad && @@ -7739,6 +7741,43 @@ resquery_response(isc_result_t eresult, isc_region_t *region, void *arg) { rctx.resend = true; rctx_done(&rctx, result); return; + } else if (fctx->res->view->peers != NULL) { + dns_peer_t *peer = NULL; + isc_netaddr_t netaddr; + isc_netaddr_fromsockaddr(&netaddr, + &query->addrinfo->sockaddr); + result = dns_peerlist_peerbyaddr(fctx->res->view->peers, + &netaddr, &peer); + if (result == ISC_R_SUCCESS) { + bool required = false; + result = dns_peer_getrequirecookie(peer, + &required); + if (result == ISC_R_SUCCESS && required) { + if (isc_log_wouldlog(dns_lctx, + ISC_LOG_INFO)) { + char addrbuf + [ISC_SOCKADDR_FORMATSIZE]; + isc_sockaddr_format( + &query->addrinfo + ->sockaddr, + addrbuf, + sizeof(addrbuf)); + isc_log_write( + dns_lctx, + DNS_LOGCATEGORY_RESOLVER, + DNS_LOGMODULE_RESOLVER, + ISC_LOG_INFO, + "missing required " + "cookie " + "from %s", + addrbuf); + } + rctx.retryopts |= DNS_FETCHOPT_TCP; + rctx.resend = true; + rctx_done(&rctx, result); + return; + } + } } } diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index 481bc9827b..d8a88d46fd 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -2539,6 +2539,7 @@ static cfg_clausedef_t server_clauses[] = { { "request-ixfr", &cfg_type_boolean, 0 }, { "request-nsid", &cfg_type_boolean, 0 }, { "request-sit", NULL, CFG_CLAUSEFLAG_ANCIENT }, + { "require-cookie", &cfg_type_boolean, 0 }, { "send-cookie", &cfg_type_boolean, 0 }, { "support-ixfr", NULL, CFG_CLAUSEFLAG_ANCIENT }, { "tcp-keepalive", &cfg_type_boolean, 0 },