diff --git a/bin/named/config.c b/bin/named/config.c index 9daa0c079b..57932107a6 100644 --- a/bin/named/config.c +++ b/bin/named/config.c @@ -132,6 +132,8 @@ options {\n\ /* view */\n\ allow-new-zones no;\n\ allow-notify {none;};\n\ + allow-proxy {none;};\n\ + allow-proxy-on {any;};\n\ allow-query-cache { localnets; localhost; };\n\ allow-query-cache-on { any; };\n\ allow-recursion { localnets; localhost; };\n\ diff --git a/bin/named/server.c b/bin/named/server.c index 5af25d1c09..a8d39608b6 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -5205,6 +5205,13 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config, CHECK(configure_view_acl(vconfig, config, NULL, "allow-query-cache-on", NULL, actx, named_g_mctx, &view->cacheonacl)); + CHECK(configure_view_acl(vconfig, config, named_g_config, "allow-proxy", + NULL, actx, named_g_mctx, &view->proxyacl)); + + CHECK(configure_view_acl(vconfig, config, named_g_config, + "allow-proxy-on", NULL, actx, named_g_mctx, + &view->proxyonacl)); + if (strcmp(view->name, "_bind") != 0 && view->rdclass != dns_rdataclass_chaos) { diff --git a/doc/arm/reference.rst b/doc/arm/reference.rst index 16c46183c6..3434bc70fd 100644 --- a/doc/arm/reference.rst +++ b/doc/arm/reference.rst @@ -2833,6 +2833,44 @@ for details on how to specify IP address lists. the configured :any:`primaries` for the zone. :any:`allow-notify` can be used to expand the list of permitted hosts, not to reduce it. +.. namedconf:statement:: allow-proxy + :tags: server + :short: Defines an :any:`address_match_list` for the client addresses allowed to send PROXYv2 headers. + + The default :any:`address_match_list` is `none`, which means that + no client is allowed to do that by default for security reasons, as + the PROXYv2 protocol provides an easy way to spoof both source and + destination addresses. + + This :any:`address_match_list` is primarily meant to have addresses + and subnets of the proxies that are allowed to send PROXYv2 headers + to BIND. In most cases, we do not recommend setting this + :any:`address_match_list` to be very allowing, in particular, to + set it to `any`, especially in the cases when PROXYv2 headers can be + accepted on publically available networking interfaces. + + The specified option is the only option that matches against real + peer addresses when PROXYv2 headers are used. Most of the options + that work with peer addresses, use the ones extracted from PROXYv2 + headers. + + Also, see: :namedconf:ref:`allow-proxy-on` + +.. namedconf:statement:: allow-proxy-on + :tags: server + :short: Defines an :any:`address_match_list` for the interface addresses allowed to accept PROXYv2 headers. The option is mostly intended for multi-homed configurations. + + The default :any:`address_match_list` is `any`, which means that + accepting PROXYv2 is allowed on any interface. + + The option is useful in cases when you need to have precise control + over which interfaces PROXYv2 is allowed, as it is the only one + that matches against real interface addresses when PROXYv2 headers + are used. Most of the options that work with interface addresses + will use the ones extracted from PROXYv2 headers. + + You may want to set :namedconf:ref:`allow-proxy` first. + .. namedconf:statement:: allow-query :tags: query :short: Specifies which hosts (an IP address list) are allowed to send queries to this resolver. @@ -3128,6 +3166,14 @@ queries may be specified using the :any:`listen-on` and :any:`listen-on-v6` opti headers. Apart from that, this additional data, while accepted, is not currently used by BIND for anything else. + By default, no client is allowed to send queries that contain + PROXYv2 protocol headers, even when support for the protocol is + enabled in a :any:`listen-on` statement. If you are interested in + enabling the PROXYv2 protocol support, you may also want to take a + look at :namedconf:ref:`allow-proxy` and + :namedconf:ref:`allow-proxy-on` options to adjust the corresponding + ACLs. + If a TLS configuration is specified, :iscman:`named` will listen for DNS-over-TLS (DoT) connections, using the key and certificate specified in the referenced :any:`tls` statement. If the name ``ephemeral`` is used, diff --git a/doc/misc/options b/doc/misc/options index 4055c9596c..0842327a73 100644 --- a/doc/misc/options +++ b/doc/misc/options @@ -62,6 +62,8 @@ managed-keys { ( static-key | initial-key | static-ds | initial-ds ) ; allow-notify { ; ... }; + allow-proxy { ; ... }; // experimental + allow-proxy-on { ; ... }; // experimental allow-query { ; ... }; allow-query-cache { ; ... }; allow-query-cache-on { ; ... }; @@ -366,6 +368,8 @@ trusted-keys { ; ... }; // view [ ] { allow-new-zones ; allow-notify { ; ... }; + allow-proxy { ; ... }; // experimental + allow-proxy-on { ; ... }; // experimental allow-query { ; ... }; allow-query-cache { ; ... }; allow-query-cache-on { ; ... }; diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index ab7098af7c..dea045fc3a 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -139,6 +139,8 @@ struct dns_view { dns_acl_t *upfwdacl; dns_acl_t *denyansweracl; dns_acl_t *nocasecompress; + dns_acl_t *proxyacl; + dns_acl_t *proxyonacl; bool msgcompression; dns_nametree_t *answeracl_exclude; dns_nametree_t *denyanswernames; diff --git a/lib/dns/view.c b/lib/dns/view.c index d71892721a..d277816252 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -339,6 +339,12 @@ destroy(dns_view_t *view) { if (view->pad_acl != NULL) { dns_acl_detach(&view->pad_acl); } + if (view->proxyacl != NULL) { + dns_acl_detach(&view->proxyacl); + } + if (view->proxyonacl != NULL) { + dns_acl_detach(&view->proxyonacl); + } if (view->answeracl_exclude != NULL) { dns_nametree_detach(&view->answeracl_exclude); } diff --git a/lib/isccfg/check.c b/lib/isccfg/check.c index cd5df28c33..476f3fe04d 100644 --- a/lib/isccfg/check.c +++ b/lib/isccfg/check.c @@ -595,11 +595,17 @@ check_viewacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions, isc_result_t result = ISC_R_SUCCESS, tresult; int i = 0; - static const char *acls[] = { - "allow-query", "allow-query-on", "allow-query-cache", - "allow-query-cache-on", "blackhole", "match-clients", - "match-destinations", "sortlist", NULL - }; + static const char *acls[] = { "allow-proxy", + "allow-proxy-on", + "allow-query", + "allow-query-on", + "allow-query-cache", + "allow-query-cache-on", + "blackhole", + "match-clients", + "match-destinations", + "sortlist", + NULL }; while (acls[i] != NULL) { tresult = checkacl(acls[i++], actx, NULL, voptions, config, diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index b042d5a620..c3f2a7d03b 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -2026,6 +2026,9 @@ static cfg_clausedef_t view_clauses[] = { { "additional-from-auth", NULL, CFG_CLAUSEFLAG_ANCIENT }, { "additional-from-cache", NULL, CFG_CLAUSEFLAG_ANCIENT }, { "allow-new-zones", &cfg_type_boolean, 0 }, + { "allow-proxy", &cfg_type_bracketed_aml, CFG_CLAUSEFLAG_EXPERIMENTAL }, + { "allow-proxy-on", &cfg_type_bracketed_aml, + CFG_CLAUSEFLAG_EXPERIMENTAL }, { "allow-query-cache", &cfg_type_bracketed_aml, 0 }, { "allow-query-cache-on", &cfg_type_bracketed_aml, 0 }, { "allow-recursion", &cfg_type_bracketed_aml, 0 }, diff --git a/lib/ns/client.c b/lib/ns/client.c index 6a363c4509..34ab13caa3 100644 --- a/lib/ns/client.c +++ b/lib/ns/client.c @@ -2001,6 +2001,60 @@ ns_client_request(isc_nmhandle_t *handle, isc_result_t eresult, return; } + if (isc_nm_is_proxy_handle(client->handle)) { + char fmtbuf[ISC_SOCKADDR_FORMATSIZE] = { 0 }; + isc_netaddr_t real_local_addr, real_peer_addr; + isc_sockaddr_t real_local, real_peer; + int log_level = ISC_LOG_DEBUG(10); + + real_peer = isc_nmhandle_real_peeraddr(client->handle); + isc_netaddr_fromsockaddr(&real_peer_addr, &real_peer); + real_local = isc_nmhandle_real_localaddr(client->handle); + isc_netaddr_fromsockaddr(&real_local_addr, &real_local); + + /* do not allow by default */ + if (ns_client_checkaclsilent(client, &real_peer_addr, + client->view->proxyacl, + false) != ISC_R_SUCCESS) + { + if (isc_log_wouldlog(ns_lctx, log_level)) { + isc_sockaddr_format(&real_peer, fmtbuf, + sizeof(fmtbuf)); + ns_client_log( + client, DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_CLIENT, log_level, + "dropped request: PROXY is not allowed " + "for that client (real client address: " + "%s). Rejected by the 'allow-proxy' " + "ACL", + fmtbuf); + } + isc_nm_bad_request(handle); + return; + } + + /* allow by default */ + if (ns_client_checkaclsilent(client, &real_local_addr, + client->view->proxyonacl, + true) != ISC_R_SUCCESS) + { + if (isc_log_wouldlog(ns_lctx, log_level)) { + isc_sockaddr_format(&real_local, fmtbuf, + sizeof(fmtbuf)); + ns_client_log( + client, DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_CLIENT, log_level, + "dropped request: PROXY is not allowed " + "on the interface (real interface " + "address: %s). Rejected by the " + "'allow-proxy-on' ACL", + fmtbuf); + } + isc_nm_bad_request(handle); + return; + } + } + ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(5), "using view '%s'", client->view->name);