]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Add server clause require-cookie
authorMark Andrews <marka@isc.org>
Mon, 23 Nov 2020 23:44:40 +0000 (10:44 +1100)
committerMark Andrews <marka@isc.org>
Tue, 13 Sep 2022 02:07:13 +0000 (12:07 +1000)
Specifies if an UDP response requires a DNS COOKIE or not.
Fallback to TCP if not present and not TSIG signed.

bin/named/server.c
bin/tests/system/checkconf/good-server-christmas-tree.conf.in
doc/arm/reference.rst
doc/man/named.conf.5in
doc/misc/options
lib/dns/include/dns/peer.h
lib/dns/peer.c
lib/dns/resolver.c
lib/isccfg/namedconf.c

index abd700da73f2da7d145c57b90c01e23552bfbf19..0c366242ea209a050b75820c4a4133432eabb7a0 100644 (file)
@@ -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) {
index a786a11cb1051d478542cff0e29b838496351cb8..f619913bee2f5c363468813f007985c4ded026aa 100644 (file)
@@ -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;
index c6fd9f505e573db5af448a8a6e52e3050f6443f5..3d9b2a6c6fbeac8b5e1899e10b7b0f6d5c70bbdd 100644 (file)
@@ -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`
index 47ef15b08ee85e7ffc18db7537e18333a75bb0f3..9f448cf68d653e3a02b5238312289f821e126eb9 100644 (file)
@@ -399,6 +399,7 @@ server <netprefix> {
        request\-expire <boolean>;
        request\-ixfr <boolean>;
        request\-nsid <boolean>;
+       require\-cookie <boolean>;
        send\-cookie <boolean>;
        tcp\-keepalive <boolean>;
        tcp\-only <boolean>;
@@ -612,6 +613,7 @@ view <string> [ <class> ] {
                request\-expire <boolean>;
                request\-ixfr <boolean>;
                request\-nsid <boolean>;
+               require\-cookie <boolean>;
                send\-cookie <boolean>;
                tcp\-keepalive <boolean>;
                tcp\-only <boolean>;
index 6b0609394f20b9a408f1c5005fbdd492fe68f29c..5de8c20b60f58e542446a78eea5243ac4e5e07a2 100644 (file)
@@ -342,6 +342,7 @@ server <netprefix> {
        request-expire <boolean>;
        request-ixfr <boolean>;
        request-nsid <boolean>;
+       require-cookie <boolean>;
        send-cookie <boolean>;
        tcp-keepalive <boolean>;
        tcp-only <boolean>;
@@ -555,6 +556,7 @@ view <string> [ <class> ] {
                request-expire <boolean>;
                request-ixfr <boolean>;
                request-nsid <boolean>;
+               require-cookie <boolean>;
                send-cookie <boolean>;
                tcp-keepalive <boolean>;
                tcp-only <boolean>;
index d4a7b1264066189f15ec2f4872676de82d2b52bb..4037386140e175436c78a1ccfce8caa75e3a8ce4 100644 (file)
@@ -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);
 
index bac2624e09ff51682f2f715ab5172c26934e8e87..bca288c4bba1d33c3ddcf7da8a0476d48505649a 100644 (file)
@@ -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);
-       }
-}
-
-isc_result_t
-dns_peer_setprovideixfr(dns_peer_t *peer, bool newval) {
-       bool existed;
-
-       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);
-       }
-}
-
-isc_result_t
-dns_peer_setrequestixfr(dns_peer_t *peer, bool newval) {
-       bool existed;
-
-       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);
-       }
-}
-
-isc_result_t
-dns_peer_setsupportedns(dns_peer_t *peer, bool newval) {
-       bool existed;
-
-       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);
-       }
-}
-
-isc_result_t
-dns_peer_setrequestnsid(dns_peer_t *peer, bool newval) {
-       bool existed;
-
-       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);
-       }
-}
-
-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);
-       }
-}
+#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);         \
+       }
+
+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)
+
+#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);         \
+       }
+
+ACCESS_OPTIONMAX(padding, SERVER_PADDING_BIT, uint16_t, padding, 512)
+
+#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);                                      \
+       }
+
+ACCESS_SOCKADDR(notifysource, notify_source)
+ACCESS_SOCKADDR(querysource, query_source)
+ACCESS_SOCKADDR(transfersource, transfer_source)
+
+#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);                                  \
+       }
+
+ACCESS_OPTION_OVERWRITE(ednsversion, EDNS_VERSION_BIT, uint8_t, ednsversion)
+
+#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);                                  \
+       }
+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);
-       }
-}
index e424835f0baba7198d8f24ddf700dce36c568ff8..9051fdc2019afe4d29f75528d15a606a34be110b 100644 (file)
@@ -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;
+                               }
+                       }
                }
        }
 
index 481bc9827b2025365b8a943265848fa7b5aad7d3..d8a88d46fd6a6757e789c1273ed12aee87821943 100644 (file)
@@ -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 },