mirror of
https://github.com/isc-projects/bind9.git
synced 2026-05-28 04:34:54 -04:00
Merge tag 'v9.21.4'
This commit is contained in:
commit
3a64b288c1
19 changed files with 1073 additions and 150 deletions
|
|
@ -1,12 +0,0 @@
|
|||
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.
|
||||
|
||||
Add -T noaa.
|
||||
|
|
@ -234,6 +234,10 @@ done
|
|||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
stop_server ns4
|
||||
touch ns4/named.noaa
|
||||
start_server --noclean --restart --port ${PORT} ns4 || ret=1
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "RT21594 regression test check setup ($n)"
|
||||
ret=0
|
||||
|
|
@ -270,6 +274,10 @@ grep "status: NXDOMAIN" dig.ns5.out.${n} >/dev/null || ret=1
|
|||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
stop_server ns4
|
||||
rm ns4/named.noaa
|
||||
start_server --noclean --restart --port ${PORT} ns4 || ret=1
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "check that replacement of additional data by a negative cache no data entry clears the additional RRSIGs ($n)"
|
||||
ret=0
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ from a primary server, the secondary checks to see that its version of
|
|||
the zone is the current version and, if not, initiates a zone transfer.
|
||||
|
||||
For more information about DNS NOTIFY, see the description of the
|
||||
:namedconf:ref:`notify` and :namedconf:ref`also-notify` statements.
|
||||
:namedconf:ref:`notify` and :namedconf:ref:`also-notify` statements.
|
||||
The NOTIFY protocol is specified in :rfc:`1996`.
|
||||
|
||||
.. note::
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ Changelog
|
|||
development. Regular users should refer to :ref:`Release Notes <relnotes>`
|
||||
for changes relevant to them.
|
||||
|
||||
.. include:: ../changelog/changelog-9.21.4.rst
|
||||
.. include:: ../changelog/changelog-9.21.3.rst
|
||||
.. include:: ../changelog/changelog-9.21.2.rst
|
||||
.. include:: ../changelog/changelog-9.21.1.rst
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ The list of known issues affecting the latest version in the 9.21 branch can be
|
|||
found at
|
||||
https://gitlab.isc.org/isc-projects/bind9/-/wikis/Known-Issues-in-BIND-9.21
|
||||
|
||||
.. include:: ../notes/notes-9.21.4.rst
|
||||
.. include:: ../notes/notes-9.21.3.rst
|
||||
.. include:: ../notes/notes-9.21.2.rst
|
||||
.. include:: ../notes/notes-9.21.1.rst
|
||||
|
|
|
|||
304
doc/changelog/changelog-9.21.4.rst
Normal file
304
doc/changelog/changelog-9.21.4.rst
Normal file
|
|
@ -0,0 +1,304 @@
|
|||
.. 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.
|
||||
|
||||
BIND 9.21.4
|
||||
-----------
|
||||
|
||||
Security Fixes
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
- [CVE-2024-12705] DNS-over-HTTP(s) flooding fixes. ``bddaff32104``
|
||||
|
||||
Fix DNS-over-HTTP(S) implementation issues that arise under heavy
|
||||
query load. Optimize resource usage for :iscman:`named` instances that
|
||||
accept queries over DNS-over-HTTP(S).
|
||||
|
||||
Previously, :iscman:`named` would process all incoming HTTP/2 data at
|
||||
once, which could overwhelm the server, especially when dealing with
|
||||
clients that send requests but don't wait for responses. That has been
|
||||
fixed. Now, :iscman:`named` handles HTTP/2 data in smaller chunks and
|
||||
throttles reading until the remote side reads the response data. It
|
||||
also throttles clients that send too many requests at once.
|
||||
|
||||
Additionally, :iscman:`named` now carefully processes data sent by
|
||||
some clients, which can be considered "flooding." It logs these
|
||||
clients and drops connections from them. :gl:`#4795`
|
||||
|
||||
In some cases, :iscman:`named` could leave DNS-over-HTTP(S)
|
||||
connections in the `CLOSE_WAIT` state indefinitely. That also has been
|
||||
fixed. ISC would like to thank JF Billaud for thoroughly investigating
|
||||
the issue and verifying the fix. :gl:`#5083` :gl:`#4795` :gl:`#5083`
|
||||
|
||||
- [CVE-2024-11187] Limit the additional processing for large RDATA sets.
|
||||
``4d054cca7a0``
|
||||
|
||||
When answering queries, don't add data to the additional section if
|
||||
the answer has more than 13 names in the RDATA. This limits the number
|
||||
of lookups into the database(s) during a single client query, reducing
|
||||
query processing load. :gl:`#5034`
|
||||
|
||||
New Features
|
||||
~~~~~~~~~~~~
|
||||
|
||||
- Add Extended DNS Error Code 22 - No Reachable Authority.
|
||||
``3972eacdad2``
|
||||
|
||||
When the resolver is trying to query an authority server and
|
||||
eventually timed out, a SERVFAIL answer is given to the client. Add
|
||||
the Extended DNS Error Code 22 - No Reachable Authority to the
|
||||
response. :gl:`#2268` :gl:`!9743`
|
||||
|
||||
- Enable extraction of exact local socket addresses. ``44d5dbeab63``
|
||||
|
||||
Enable extracting the exact address/port that a local wildcard/TCP
|
||||
socket is bound to, improving the accuracy of dnstap logging and
|
||||
providing more information in debug logs produced by system tests.
|
||||
Since this requires issuing an extra system call on some hot paths,
|
||||
this new feature is only enabled when the ``ISC_SOCKET_DETAILS``
|
||||
preprocessor macro is set at compile time. :gl:`#4344` :gl:`!8348`
|
||||
|
||||
- Log both "from" and "to" socket in debug messages. ``6230bc883a5``
|
||||
|
||||
Debug messages logging network traffic now include information about
|
||||
both sides of each communication channel rather than just one of them.
|
||||
:gl:`#4345` :gl:`!8349`
|
||||
|
||||
- Add "Zone has [AAAA/A] records but is not served by IPv[6/4]"
|
||||
warnings. ``ef6dc36e530``
|
||||
|
||||
Check that zones with AAAA records are served by IPv6 servers and that
|
||||
zones with A records are served by IPv4 servers. Sometimes, IPv6
|
||||
services are accidentally misconfigured and zones with IPv6 (AAAA)
|
||||
address records are not served by DNS servers with IPv6 addresses,
|
||||
which means they need to use translation devices to look up those IPv6
|
||||
addresses. The reverse is also sometimes true: zones with A records
|
||||
are not resolvable over IPv4 when they should be. To prevent this,
|
||||
BIND now looks for these misconfigured zones and issues a warning if
|
||||
they are found. :gl:`#4370` :gl:`!8393`
|
||||
|
||||
- Add a new option to configure the maximum number of outgoing queries
|
||||
per client request. ``80a5745a1f8``
|
||||
|
||||
The configuration option 'max-query-count' sets how many outgoing
|
||||
queries per client request is allowed. The existing
|
||||
'max-recursion-queries' is the number of permissible queries for a
|
||||
single name and is reset on every CNAME redirection. This new option
|
||||
is a global limit on the client request. The default is 200.
|
||||
|
||||
This allows us to send a bit more queries while looking up a single
|
||||
name. The default for 'max-recursion-queries' is changed from 32 to
|
||||
50. :gl:`#4980` :gl:`#4921` :gl:`!9737`
|
||||
|
||||
Removed Features
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
- Remove dnssec-must-be-secure feature. ``f5f792f1ed2``
|
||||
|
||||
:gl:`#4482` :gl:`!9851`
|
||||
|
||||
- Remove 'sortlist' option. ``2bce06e170a``
|
||||
|
||||
The `sortlist` option, which was deprecated in BIND 9.20, has now been
|
||||
removed. :gl:`#4665` :gl:`!9839`
|
||||
|
||||
- Remove fixed value for the rrset-order option. ``5bee088dd1f``
|
||||
|
||||
Remove the "fixed" value from the "rrset-order" option and from the
|
||||
autoconf script. :gl:`#4666` :gl:`!9852`
|
||||
|
||||
- Remove the log message about incomplete IPv6 API. ``3779a81d501``
|
||||
|
||||
The log message would not be ever reached, because the IPv6 API is
|
||||
always considered to be complete. Just remove the dead code.
|
||||
:gl:`#5068` :gl:`!9798`
|
||||
|
||||
- Remove trusted-keys and managed-keys options. ``9de6b228d41``
|
||||
|
||||
These options have been deprecated in 9.19 in favor of the
|
||||
'trust-anchors' option and are now being removed. :gl:`#5080`
|
||||
:gl:`!9855`
|
||||
|
||||
- Drop single-use RETERR macro. ``f6ff4fff85e``
|
||||
|
||||
If the RETERR define is only used once in a file, just drop the macro.
|
||||
:gl:`!9871`
|
||||
|
||||
- Remove C++ support from the public header. ``8d9bc93e81e``
|
||||
|
||||
Since BIND 9 headers are not longer public, there's no reason to keep
|
||||
the ISC_LANG_BEGINDECL and ISC_LANG_ENDDECL macros to support
|
||||
including them from C++ projects. :gl:`!9925`
|
||||
|
||||
- Remove DLV remnants. ``f4377a3cd69``
|
||||
|
||||
DLV is long gone, so we can remove design documentation around DLV,
|
||||
related command line options (that were already a hard failure), and
|
||||
some DLV related test remnants. :gl:`!9888`
|
||||
|
||||
Feature Changes
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
- Update picohttpparser.{c,h} with upstream repository. ``9428077f481``
|
||||
|
||||
:gl:`#4485` :gl:`!9857`
|
||||
|
||||
- The configuration clauses parental-agents and primaries are renamed to
|
||||
remote-servers. ``858ba71eafc``
|
||||
|
||||
The top blocks 'primaries' and 'parental-agents' are no longer
|
||||
preferred and should be renamed to 'remote-servers'. The zone
|
||||
statements 'parental-agents' and 'primaries' are still used, and may
|
||||
refer to any 'remote-servers' top block. :gl:`#4544` :gl:`!9822`
|
||||
|
||||
- Add TLS SNI extension to all outgoing TLS connections. ``6eb77ed2b07``
|
||||
|
||||
This change ensures that SNI extension is used in outgoing connections
|
||||
over TLS (e.g. for DoT and DoH) when applicable. :gl:`#5099`
|
||||
:gl:`!9923`
|
||||
|
||||
- Detect and possibly define constexpr using Autoconf. ``1fea227ab8b``
|
||||
|
||||
Previously, we had an ISC_CONSTEXPR macro that was expanded to either
|
||||
`constexpr` or `static const`, depending on compiler support. To make
|
||||
the code cleaner, move `constexpr` support detection to Autoconf; if
|
||||
`constexpr` support is missing from the compiler, define `constexpr`
|
||||
as `static const` in config.h. :gl:`!9924`
|
||||
|
||||
- Remove unused maxquerycount. ``43622594f48``
|
||||
|
||||
Related to #4980 :gl:`!9850`
|
||||
|
||||
- Use query counters in validator code. ``63060314098``
|
||||
|
||||
Commit af7db8951364a89c468eda1535efb3f53adc2c1f as part of #4141 was
|
||||
supposed to apply the 'max-recursion-queries' quota to validator
|
||||
queries, but the counter was never actually passed on to
|
||||
'dns_resolver_createfetch()'. This has been fixed, and the global
|
||||
query counter ('max-query-count', per client request) is now also
|
||||
added.
|
||||
|
||||
Related to #4980 :gl:`!9856`
|
||||
|
||||
Bug Fixes
|
||||
~~~~~~~~~
|
||||
|
||||
- Accept resolv.conf with more than 8 search domains. ``eda02dc3424``
|
||||
|
||||
:gl:`#1259` :gl:`!2446`
|
||||
|
||||
- Fix nsupdate hang when processing a large update. ``fa56e0d8b10``
|
||||
|
||||
To mitigate DNS flood attacks over a single TCP connection, we
|
||||
throttle the connection when the other side does not read the data.
|
||||
Throttling should only occur on server-side sockets, but erroneously
|
||||
also happened for nsupdate, which acts as a client. When nsupdate
|
||||
started throttling the connection, it never attempts to read again.
|
||||
This has been fixed. :gl:`#4910` :gl:`!9709`
|
||||
|
||||
- Lock and attach when returning zone stats. ``3c720c64250``
|
||||
|
||||
When returning zone statistics counters, the statistics sets are now
|
||||
attached while the zone is locked. This addresses Coverity warnings
|
||||
CID 468720, 468728 and 468729. :gl:`#4934` :gl:`!9488`
|
||||
|
||||
- Fix possible assertion failure when reloading server while processing
|
||||
updates. ``be5266a7c61``
|
||||
|
||||
:gl:`#5006` :gl:`!9745`
|
||||
|
||||
- Preserve cache across reconfig when using attach-cache.
|
||||
``0b287f3aaf9``
|
||||
|
||||
When the `attach-cache` option is used in the `options` block with an
|
||||
arbitrary name, it causes all views to use the same cache. Previously,
|
||||
this configuration caused the cache to be deleted and a new cache
|
||||
created every time the server was reconfigured. This has been fixed.
|
||||
:gl:`#5061` :gl:`!9787`
|
||||
|
||||
- Resolve the spurious drops in performance due GLUE cache.
|
||||
``e2c1941efd2``
|
||||
|
||||
For performance reasons, the returned GLUE records are cached on the
|
||||
first use. The current implementation could randomly cause a
|
||||
performance drop and increased memory use. This has been fixed.
|
||||
:gl:`#5064` :gl:`!9831`
|
||||
|
||||
- Fix dnssec-signzone signing non-DNSKEY RRsets with revoked keys.
|
||||
``1435770b1a7``
|
||||
|
||||
`dnssec-signzone` was using revoked keys for signing RRsets other than
|
||||
DNSKEY. This has been corrected. :gl:`#5070` :gl:`!9800`
|
||||
|
||||
- Disable deterministic ecdsa for fips builds. ``707dded9798``
|
||||
|
||||
FIPS 186-5 [1] allows the usage deterministic ECDSA (Section 6.3)
|
||||
which is compabile with RFC 6979 [2] but OpenSSL seems to follow FIPS
|
||||
186-4 (Section 6.3) [3] which only allows for random k values, failing
|
||||
k value generation for OpenSSL >=3.2. [4]
|
||||
|
||||
Fix signing by not using deterministic ECDSA when FIPS mode is active.
|
||||
|
||||
[1]: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-5.pdf [2]:
|
||||
https://datatracker.ietf.org/doc/html/rfc6979 [3]:
|
||||
https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf [4]: https:
|
||||
//github.com/openssl/openssl/blob/85f17585b0d8b55b335f561e2862db14a20b
|
||||
1e64/crypto/ec/ecdsa_ossl.c#L201-L207 :gl:`#5072` :gl:`!9808`
|
||||
|
||||
- Revert "Lock and attach when returning zone stats" ``de6f199f4d2``
|
||||
|
||||
:gl:`#5082` :gl:`!9859`
|
||||
|
||||
- Unknown directive in resolv.conf not handled properly. ``48901ef57e7``
|
||||
|
||||
The line after an unknown directive in resolv.conf could accidentally
|
||||
be skipped, potentially affecting dig, host, nslookup, nsupdate, or
|
||||
delv. This has been fixed. :gl:`#5084` :gl:`!9865`
|
||||
|
||||
- Querying an NSEC3-signed zone for an empty record could trigger an
|
||||
assertion. ``3a94afa03a1``
|
||||
|
||||
A bug in the qpzone database could trigger a crash when querying for a
|
||||
deleted name, or a newly-added empty non-terminal name, in an
|
||||
NSEC3-signed zone. This has been fixed. :gl:`#5108` :gl:`!9928`
|
||||
|
||||
- Fix response policy zones and catalog zones with an $INCLUDE statement
|
||||
defined. ``19a2aab136a``
|
||||
|
||||
Response policy zones (RPZ) and catalog zones were not working
|
||||
correctly if they had an $INCLUDE statement defined. This has been
|
||||
fixed. :gl:`#5111` :gl:`!9930`
|
||||
|
||||
- Clean up incorrect logging module names. ``3db39ec7ad5``
|
||||
|
||||
Some files used logmodule names that had been copied in from
|
||||
elsewhere; these have now been given module names of their own. Also,
|
||||
the RBT and RBTDB logmodules have been removed, since they are now
|
||||
unused. :gl:`!9895`
|
||||
|
||||
- Finalize removal of memory debug flags size and mctx. ``667383587b2``
|
||||
|
||||
Commit 4b3d0c66009d30f5c0bc12ee128fc59f1d853f44 has removed them, but
|
||||
did not remove few traces in documentation and help. Remove them from
|
||||
remaining places. :gl:`!9606`
|
||||
|
||||
- Mark loop as shuttingdown earlier in shutdown_cb. ``d71869d6a78``
|
||||
|
||||
:gl:`!9827`
|
||||
|
||||
- Use CMM_{STORE,LOAD}_SHARED to store/load glue in gluelist.
|
||||
``6ce55429f14``
|
||||
|
||||
ThreadSanitizer has trouble understanding that gluelist->glue is
|
||||
constant after it is assigned to the slabheader with cmpxchg. Help
|
||||
ThreadSanitizer to understand the code by using CMM_STORE_SHARED and
|
||||
CMM_LOAD_SHARED on gluelist->glue. :gl:`!9929`
|
||||
|
||||
|
||||
195
doc/notes/notes-9.21.4.rst
Normal file
195
doc/notes/notes-9.21.4.rst
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
.. 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.
|
||||
|
||||
Notes for BIND 9.21.4
|
||||
---------------------
|
||||
|
||||
Security Fixes
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
- DNS-over-HTTPS flooding fixes. :cve:`2024-12705`
|
||||
|
||||
Fix DNS-over-HTTPS implementation issues that arise under heavy
|
||||
query load. Optimize resource usage for :iscman:`named` instances that
|
||||
accept queries over DNS-over-HTTPS.
|
||||
|
||||
Previously, :iscman:`named` processed all incoming HTTP/2 data at
|
||||
once, which could overwhelm the server, especially when dealing with
|
||||
clients that sent requests but did not wait for responses. That has been
|
||||
fixed. Now, :iscman:`named` handles HTTP/2 data in smaller chunks and
|
||||
throttles reading until the remote side reads the response data. It
|
||||
also throttles clients that send too many requests at once.
|
||||
|
||||
In addition, :iscman:`named` now evaluates excessive streams opened by
|
||||
clients that include no DNS data, which is considered "flooding." It
|
||||
logs these clients and drops connections from them. :gl:`#4795`
|
||||
|
||||
In some cases, :iscman:`named` could leave DNS-over-HTTPS
|
||||
connections in the `CLOSE_WAIT` state indefinitely. That has also been
|
||||
fixed. :gl:`#5083`
|
||||
|
||||
ISC would like to thank Jean-François Billaud for his assistance with
|
||||
investigating this issue.
|
||||
|
||||
- Limit additional section processing for large RDATA sets.
|
||||
:cve:`2024-11187`
|
||||
|
||||
When answering queries, don't add data to the additional section if
|
||||
the answer has more than 13 names in the RDATA. This limits the number
|
||||
of lookups into the database(s) during a single client query, reducing
|
||||
the query-processing load. :gl:`#5034`
|
||||
|
||||
ISC would like to thank Toshifumi Sakaguchi for bringing this
|
||||
vulnerability to our attention.
|
||||
|
||||
New Features
|
||||
~~~~~~~~~~~~
|
||||
|
||||
- Add Extended DNS Error Code 22 - No Reachable Authority.
|
||||
|
||||
When the resolver is trying to query an authoritative server and
|
||||
eventually times out, a SERVFAIL answer is given to the client. Add
|
||||
the Extended DNS Error Code 22 - No Reachable Authority to the
|
||||
response. :gl:`#2268`
|
||||
|
||||
- Add "Zone has [AAAA/A] records but is not served by IPv[6/4]"
|
||||
warnings.
|
||||
|
||||
Check that zones with AAAA records are served by IPv6 servers and that
|
||||
zones with A records are served by IPv4 servers. Sometimes, IPv6
|
||||
services are accidentally misconfigured and zones with IPv6 (AAAA)
|
||||
address records are not served by DNS servers with IPv6 addresses,
|
||||
which means they need to use translation devices to look up those IPv6
|
||||
addresses. The reverse is also sometimes true: zones with A records
|
||||
are not resolvable over IPv4 when they should be. To prevent this,
|
||||
BIND now looks for these misconfigured zones and issues a warning if
|
||||
they are found. :gl:`#4370`
|
||||
|
||||
- Add a new option to configure the maximum number of outgoing queries
|
||||
per client request.
|
||||
|
||||
The configuration option :any:`max-query-count` sets how many outgoing
|
||||
queries per client request are allowed. The existing
|
||||
:any:`max-recursion-queries` value is the number of permissible queries for a
|
||||
single name and is reset on every CNAME redirection. This new option
|
||||
is a global limit on the client request. The default is 200.
|
||||
|
||||
The default for :any:`max-recursion-queries` is changed from 32 to
|
||||
50. This allows :any:`named` to send a few more queries
|
||||
while looking up a single name. :gl:`#4980` :gl:`#4921`
|
||||
|
||||
- Use the Server Name Indication (SNI) extension for all outgoing TLS
|
||||
connections.
|
||||
|
||||
This improves compatibility with other DNS server software.
|
||||
:gl:`#5099`
|
||||
|
||||
Removed Features
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
- Remove the ``dnssec-must-be-secure`` feature. :gl:`#4482`
|
||||
|
||||
- Remove ``sortlist`` option.
|
||||
|
||||
The ``sortlist`` option, which was deprecated in BIND 9.20, has now been
|
||||
removed. :gl:`#4665`
|
||||
|
||||
- Remove support for fixed RRset ordering.
|
||||
|
||||
Remove the ``fixed`` value from the :any:`rrset-order` option and the
|
||||
``--enable-fixed-rrset`` option from the ``./configure`` script.
|
||||
:gl:`#4666`
|
||||
|
||||
- Remove ``trusted-keys`` and ``managed-keys`` options.
|
||||
|
||||
These options have been deprecated in 9.19 in favor of the
|
||||
:any:`trust-anchors` option and are now being removed. :gl:`#5080`
|
||||
|
||||
Feature Changes
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
- The configuration clauses ``parental-agents`` and ``primaries`` are renamed to
|
||||
:any:`remote-servers`.
|
||||
|
||||
The top blocks ``primaries`` and ``parental-agents`` are no longer
|
||||
preferred and should be renamed to :any:`remote-servers`. The zone
|
||||
statements :any:`parental-agents` and :any:`primaries` are still used, and may
|
||||
refer to any :any:`remote-servers` top block. :gl:`#4544`
|
||||
|
||||
Bug Fixes
|
||||
~~~~~~~~~
|
||||
|
||||
- Querying an NSEC3-signed zone for an empty record could trigger an
|
||||
assertion.
|
||||
|
||||
A bug in the qpzone database could trigger a crash when querying for a
|
||||
deleted name, or a newly added empty non-terminal name, in an
|
||||
NSEC3-signed zone. This has been fixed. :gl:`#5108`
|
||||
|
||||
- Fix :iscman:`nsupdate` hang when processing a large update.
|
||||
|
||||
To mitigate DNS flood attacks over a single TCP connection, throttle
|
||||
the connection when the other side does not read the data. Throttling
|
||||
should only occur on server-side sockets, but erroneously also
|
||||
happened for :iscman:`nsupdate`, which acts as a client. When
|
||||
:iscman:`nsupdate` started throttling the connection, it never
|
||||
attempted to read again. This has been fixed. :gl:`#4910`
|
||||
|
||||
- Fix possible assertion failure when reloading server while processing
|
||||
update policy rules. :gl:`#5006`
|
||||
|
||||
- Preserve cache across reconfig when using :any:`attach-cache`.
|
||||
|
||||
When the :any:`attach-cache` option is used in the ``options`` block with an
|
||||
arbitrary name, it causes all views to use the same cache. Previously,
|
||||
this configuration caused the cache to be deleted and a new cache
|
||||
to be created every time the server was reconfigured. This has been fixed.
|
||||
:gl:`#5061`
|
||||
|
||||
- Resolve the spurious drops in performance due to glue cache.
|
||||
|
||||
For performance reasons, the returned glue records are cached on the
|
||||
first use. The current implementation could randomly cause a
|
||||
performance drop and increased memory use. This has been fixed.
|
||||
:gl:`#5064`
|
||||
|
||||
- Fix :iscman:`dnssec-signzone` signing non-DNSKEY RRsets with revoked keys.
|
||||
|
||||
:any:`dnssec-signzone` was using revoked keys for signing RRsets other than
|
||||
DNSKEY. This has been corrected. :gl:`#5070`
|
||||
|
||||
- Disable deterministic ECDSA for FIPS builds.
|
||||
|
||||
`FIPS 186-5 <https://csrc.nist.gov/pubs/fips/186-5/final>`_ allows use
|
||||
of deterministic ECDSA (Section 6.3), which is compatible with
|
||||
:rfc:`6979`, but OpenSSL seems to follow `FIPS 186-4
|
||||
<https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf>`_
|
||||
(Section 6.3), which only allows random ``k`` values. This causes ``k``
|
||||
value generation to fail for OpenSSL >= 3.2, making BIND unable to
|
||||
generate ECDSA signatures when in FIPS mode.
|
||||
|
||||
This signing is now fixed by not using deterministic ECDSA when FIPS mode is active. :gl:`#5072`
|
||||
|
||||
- Fix improper handling of unknown directives in ``resolv.conf``.
|
||||
|
||||
The line after an unknown directive in ``resolv.conf`` could accidentally be
|
||||
skipped, potentially affecting :iscman:`dig`, :iscman:`host`,
|
||||
:iscman:`nslookup`, :iscman:`nsupdate`, or :iscman:`delv`. This has been
|
||||
fixed. :gl:`#5084`
|
||||
|
||||
- Fix response policy zones and catalog zones with an ``$INCLUDE`` statement
|
||||
defined.
|
||||
|
||||
Response policy zones (RPZ) and catalog zones were not working
|
||||
correctly if they had an ``$INCLUDE`` statement defined. This has been
|
||||
fixed. :gl:`#5111`
|
||||
|
||||
|
||||
|
|
@ -53,6 +53,8 @@
|
|||
#include <dns/rdatastruct.h>
|
||||
#include <dns/types.h>
|
||||
|
||||
#define DNS_RDATASET_MAXADDITIONAL 13
|
||||
|
||||
/* Fixed RRSet helper macros */
|
||||
|
||||
#define DNS_RDATASET_LENGTH 2;
|
||||
|
|
@ -503,7 +505,8 @@ dns_rdataset_towirepartial(dns_rdataset_t *rdataset,
|
|||
isc_result_t
|
||||
dns_rdataset_additionaldata(dns_rdataset_t *rdataset,
|
||||
const dns_name_t *owner_name,
|
||||
dns_additionaldatafunc_t add, void *arg);
|
||||
dns_additionaldatafunc_t add, void *arg,
|
||||
size_t limit);
|
||||
/*%<
|
||||
* For each rdata in rdataset, call 'add' for each name and type in the
|
||||
* rdata which is subject to additional section processing.
|
||||
|
|
@ -522,10 +525,15 @@ dns_rdataset_additionaldata(dns_rdataset_t *rdataset,
|
|||
*\li If a call to dns_rdata_additionaldata() is not successful, the
|
||||
* result returned will be the result of dns_rdataset_additionaldata().
|
||||
*
|
||||
*\li If the 'limit' is non-zero and the number of the rdatasets is larger
|
||||
* than the 'limit', no additional data will be generated.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
*\li #ISC_R_SUCCESS
|
||||
*
|
||||
*\li #DNS_R_TOOMANYRECORDS in case rdataset count is larger than 'limit'
|
||||
*
|
||||
*\li Any error that dns_rdata_additionaldata() can return.
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -1532,10 +1532,11 @@ find_coveringnsec(qpc_search_t *search, const dns_name_t *name,
|
|||
}
|
||||
|
||||
static isc_result_t
|
||||
find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
|
||||
dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
|
||||
dns_dbnode_t **nodep, dns_name_t *foundname, dns_rdataset_t *rdataset,
|
||||
dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
|
||||
qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
|
||||
dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
|
||||
dns_dbnode_t **nodep, dns_name_t *foundname,
|
||||
dns_rdataset_t *rdataset,
|
||||
dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
|
||||
qpcnode_t *node = NULL;
|
||||
isc_result_t result;
|
||||
qpc_search_t search;
|
||||
|
|
@ -1977,10 +1978,11 @@ tree_exit:
|
|||
}
|
||||
|
||||
static isc_result_t
|
||||
findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
|
||||
isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname,
|
||||
dns_name_t *dcname, dns_rdataset_t *rdataset,
|
||||
dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
|
||||
qpcache_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
|
||||
isc_stdtime_t now, dns_dbnode_t **nodep,
|
||||
dns_name_t *foundname, dns_name_t *dcname,
|
||||
dns_rdataset_t *rdataset,
|
||||
dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
|
||||
qpcnode_t *node = NULL;
|
||||
isc_rwlock_t *lock = NULL;
|
||||
isc_result_t result;
|
||||
|
|
@ -2152,10 +2154,10 @@ tree_exit:
|
|||
}
|
||||
|
||||
static isc_result_t
|
||||
findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
||||
dns_rdatatype_t type, dns_rdatatype_t covers, isc_stdtime_t now,
|
||||
dns_rdataset_t *rdataset,
|
||||
dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
|
||||
qpcache_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
||||
dns_rdatatype_t type, dns_rdatatype_t covers,
|
||||
isc_stdtime_t now, dns_rdataset_t *rdataset,
|
||||
dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
|
||||
qpcache_t *qpdb = (qpcache_t *)db;
|
||||
qpcnode_t *qpnode = (qpcnode_t *)node;
|
||||
dns_slabheader_t *header = NULL, *header_next = NULL;
|
||||
|
|
@ -2554,7 +2556,7 @@ free_qpdb(qpcache_t *qpdb, bool log) {
|
|||
}
|
||||
|
||||
static void
|
||||
qpdb_destroy(dns_db_t *arg) {
|
||||
qpcache_destroy(dns_db_t *arg) {
|
||||
qpcache_t *qpdb = (qpcache_t *)arg;
|
||||
bool want_free = false;
|
||||
unsigned int i;
|
||||
|
|
@ -2682,8 +2684,8 @@ new_qpcnode(qpcache_t *qpdb, const dns_name_t *name) {
|
|||
}
|
||||
|
||||
static isc_result_t
|
||||
findnode(dns_db_t *db, const dns_name_t *name, bool create,
|
||||
dns_dbnode_t **nodep DNS__DB_FLARG) {
|
||||
qpcache_findnode(dns_db_t *db, const dns_name_t *name, bool create,
|
||||
dns_dbnode_t **nodep DNS__DB_FLARG) {
|
||||
qpcache_t *qpdb = (qpcache_t *)db;
|
||||
qpcnode_t *node = NULL;
|
||||
isc_result_t result;
|
||||
|
|
@ -2718,8 +2720,8 @@ unlock:
|
|||
}
|
||||
|
||||
static void
|
||||
attachnode(dns_db_t *db, dns_dbnode_t *source,
|
||||
dns_dbnode_t **targetp DNS__DB_FLARG) {
|
||||
qpcache_attachnode(dns_db_t *db, dns_dbnode_t *source,
|
||||
dns_dbnode_t **targetp DNS__DB_FLARG) {
|
||||
REQUIRE(VALID_QPDB((qpcache_t *)db));
|
||||
REQUIRE(targetp != NULL && *targetp == NULL);
|
||||
|
||||
|
|
@ -2733,7 +2735,7 @@ attachnode(dns_db_t *db, dns_dbnode_t *source,
|
|||
}
|
||||
|
||||
static void
|
||||
detachnode(dns_db_t *db, dns_dbnode_t **targetp DNS__DB_FLARG) {
|
||||
qpcache_detachnode(dns_db_t *db, dns_dbnode_t **targetp DNS__DB_FLARG) {
|
||||
qpcache_t *qpdb = (qpcache_t *)db;
|
||||
qpcnode_t *node = NULL;
|
||||
bool want_free = false;
|
||||
|
|
@ -2788,8 +2790,8 @@ detachnode(dns_db_t *db, dns_dbnode_t **targetp DNS__DB_FLARG) {
|
|||
}
|
||||
|
||||
static isc_result_t
|
||||
createiterator(dns_db_t *db, unsigned int options ISC_ATTR_UNUSED,
|
||||
dns_dbiterator_t **iteratorp) {
|
||||
qpcache_createiterator(dns_db_t *db, unsigned int options ISC_ATTR_UNUSED,
|
||||
dns_dbiterator_t **iteratorp) {
|
||||
qpcache_t *qpdb = (qpcache_t *)db;
|
||||
qpc_dbit_t *qpdbiter = NULL;
|
||||
|
||||
|
|
@ -2811,9 +2813,9 @@ createiterator(dns_db_t *db, unsigned int options ISC_ATTR_UNUSED,
|
|||
}
|
||||
|
||||
static isc_result_t
|
||||
allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
||||
unsigned int options, isc_stdtime_t now,
|
||||
dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) {
|
||||
qpcache_allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
||||
unsigned int options, isc_stdtime_t now,
|
||||
dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) {
|
||||
qpcache_t *qpdb = (qpcache_t *)db;
|
||||
qpcnode_t *qpnode = (qpcnode_t *)node;
|
||||
qpc_rditer_t *iterator = NULL;
|
||||
|
|
@ -3388,9 +3390,10 @@ expire_ttl_headers(qpcache_t *qpdb, unsigned int locknum,
|
|||
isc_stdtime_t now, bool cache_is_overmem DNS__DB_FLARG);
|
||||
|
||||
static isc_result_t
|
||||
addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
||||
isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
|
||||
dns_rdataset_t *addedrdataset DNS__DB_FLARG) {
|
||||
qpcache_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
||||
isc_stdtime_t now, dns_rdataset_t *rdataset,
|
||||
unsigned int options,
|
||||
dns_rdataset_t *addedrdataset DNS__DB_FLARG) {
|
||||
qpcache_t *qpdb = (qpcache_t *)db;
|
||||
qpcnode_t *qpnode = (qpcnode_t *)node;
|
||||
isc_region_t region;
|
||||
|
|
@ -3571,8 +3574,9 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
|||
}
|
||||
|
||||
static isc_result_t
|
||||
deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
||||
dns_rdatatype_t type, dns_rdatatype_t covers DNS__DB_FLARG) {
|
||||
qpcache_deleterdataset(dns_db_t *db, dns_dbnode_t *node,
|
||||
dns_dbversion_t *version, dns_rdatatype_t type,
|
||||
dns_rdatatype_t covers DNS__DB_FLARG) {
|
||||
qpcache_t *qpdb = (qpcache_t *)db;
|
||||
qpcnode_t *qpnode = (qpcnode_t *)node;
|
||||
isc_result_t result;
|
||||
|
|
@ -4380,17 +4384,17 @@ setmaxtypepername(dns_db_t *db, uint32_t value) {
|
|||
}
|
||||
|
||||
static dns_dbmethods_t qpdb_cachemethods = {
|
||||
.destroy = qpdb_destroy,
|
||||
.findnode = findnode,
|
||||
.find = find,
|
||||
.findzonecut = findzonecut,
|
||||
.attachnode = attachnode,
|
||||
.detachnode = detachnode,
|
||||
.createiterator = createiterator,
|
||||
.findrdataset = findrdataset,
|
||||
.allrdatasets = allrdatasets,
|
||||
.addrdataset = addrdataset,
|
||||
.deleterdataset = deleterdataset,
|
||||
.destroy = qpcache_destroy,
|
||||
.findnode = qpcache_findnode,
|
||||
.find = qpcache_find,
|
||||
.findzonecut = qpcache_findzonecut,
|
||||
.attachnode = qpcache_attachnode,
|
||||
.detachnode = qpcache_detachnode,
|
||||
.createiterator = qpcache_createiterator,
|
||||
.findrdataset = qpcache_findrdataset,
|
||||
.allrdatasets = qpcache_allrdatasets,
|
||||
.addrdataset = qpcache_addrdataset,
|
||||
.deleterdataset = qpcache_deleterdataset,
|
||||
.nodecount = nodecount,
|
||||
.getoriginnode = getoriginnode,
|
||||
.getrrsetstats = getrrsetstats,
|
||||
|
|
|
|||
107
lib/dns/qpzone.c
107
lib/dns/qpzone.c
|
|
@ -1555,10 +1555,11 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp,
|
|||
}
|
||||
|
||||
static isc_result_t
|
||||
findrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
|
||||
dns_rdatatype_t type, dns_rdatatype_t covers,
|
||||
isc_stdtime_t now ISC_ATTR_UNUSED, dns_rdataset_t *rdataset,
|
||||
dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
|
||||
qpzone_findrdataset(dns_db_t *db, dns_dbnode_t *dbnode,
|
||||
dns_dbversion_t *dbversion, dns_rdatatype_t type,
|
||||
dns_rdatatype_t covers, isc_stdtime_t now ISC_ATTR_UNUSED,
|
||||
dns_rdataset_t *rdataset,
|
||||
dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
|
||||
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
||||
qpznode_t *node = (qpznode_t *)dbnode;
|
||||
dns_slabheader_t *header = NULL, *header_next = NULL;
|
||||
|
|
@ -2556,8 +2557,8 @@ findnodeintree(qpzonedb_t *qpdb, const dns_name_t *name, bool create,
|
|||
}
|
||||
|
||||
static isc_result_t
|
||||
findnode(dns_db_t *db, const dns_name_t *name, bool create,
|
||||
dns_dbnode_t **nodep DNS__DB_FLARG) {
|
||||
qpzone_findnode(dns_db_t *db, const dns_name_t *name, bool create,
|
||||
dns_dbnode_t **nodep DNS__DB_FLARG) {
|
||||
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
||||
|
||||
REQUIRE(VALID_QPZONE(qpdb));
|
||||
|
|
@ -2567,8 +2568,8 @@ findnode(dns_db_t *db, const dns_name_t *name, bool create,
|
|||
}
|
||||
|
||||
static isc_result_t
|
||||
findnsec3node(dns_db_t *db, const dns_name_t *name, bool create,
|
||||
dns_dbnode_t **nodep DNS__DB_FLARG) {
|
||||
qpzone_findnsec3node(dns_db_t *db, const dns_name_t *name, bool create,
|
||||
dns_dbnode_t **nodep DNS__DB_FLARG) {
|
||||
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
||||
|
||||
REQUIRE(VALID_QPZONE(qpdb));
|
||||
|
|
@ -2616,9 +2617,9 @@ matchparams(dns_slabheader_t *header, qpz_search_t *search) {
|
|||
}
|
||||
|
||||
static isc_result_t
|
||||
setup_delegation(qpz_search_t *search, dns_dbnode_t **nodep,
|
||||
dns_name_t *foundname, dns_rdataset_t *rdataset,
|
||||
dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
|
||||
qpzone_setup_delegation(qpz_search_t *search, dns_dbnode_t **nodep,
|
||||
dns_name_t *foundname, dns_rdataset_t *rdataset,
|
||||
dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
|
||||
dns_name_t *zcname = NULL;
|
||||
dns_typepair_t type;
|
||||
qpznode_t *node = NULL;
|
||||
|
|
@ -3212,7 +3213,7 @@ again:
|
|||
}
|
||||
|
||||
static isc_result_t
|
||||
check_zonecut(qpznode_t *node, void *arg DNS__DB_FLARG) {
|
||||
qpzone_check_zonecut(qpznode_t *node, void *arg DNS__DB_FLARG) {
|
||||
qpz_search_t *search = arg;
|
||||
dns_slabheader_t *header = NULL, *header_next = NULL;
|
||||
dns_slabheader_t *dname_header = NULL, *sigdname_header = NULL;
|
||||
|
|
@ -3339,11 +3340,11 @@ check_zonecut(qpznode_t *node, void *arg DNS__DB_FLARG) {
|
|||
}
|
||||
|
||||
static isc_result_t
|
||||
find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
|
||||
dns_rdatatype_t type, unsigned int options,
|
||||
isc_stdtime_t now ISC_ATTR_UNUSED, dns_dbnode_t **nodep,
|
||||
dns_name_t *foundname, dns_rdataset_t *rdataset,
|
||||
dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
|
||||
qpzone_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
|
||||
dns_rdatatype_t type, unsigned int options,
|
||||
isc_stdtime_t now ISC_ATTR_UNUSED, dns_dbnode_t **nodep,
|
||||
dns_name_t *foundname, dns_rdataset_t *rdataset,
|
||||
dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
|
||||
isc_result_t result;
|
||||
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
||||
qpznode_t *node = NULL;
|
||||
|
|
@ -3413,7 +3414,7 @@ find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
|
|||
isc_result_t tresult;
|
||||
|
||||
dns_qpchain_node(&search.chain, i, NULL, (void **)&n, NULL);
|
||||
tresult = check_zonecut(n, &search DNS__DB_FLARG_PASS);
|
||||
tresult = qpzone_check_zonecut(n, &search DNS__DB_FLARG_PASS);
|
||||
if (tresult != DNS_R_CONTINUE) {
|
||||
result = tresult;
|
||||
search.chain.len = i - 1;
|
||||
|
|
@ -3425,7 +3426,7 @@ find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
|
|||
if (result == DNS_R_PARTIALMATCH) {
|
||||
partial_match:
|
||||
if (search.zonecut != NULL) {
|
||||
result = setup_delegation(
|
||||
result = qpzone_setup_delegation(
|
||||
&search, nodep, foundname, rdataset,
|
||||
sigrdataset DNS__DB_FLARG_PASS);
|
||||
goto tree_exit;
|
||||
|
|
@ -3715,7 +3716,7 @@ found:
|
|||
* Return the delegation.
|
||||
*/
|
||||
NODE_UNLOCK(lock, &nlocktype);
|
||||
result = setup_delegation(
|
||||
result = qpzone_setup_delegation(
|
||||
&search, nodep, foundname, rdataset,
|
||||
sigrdataset DNS__DB_FLARG_PASS);
|
||||
goto tree_exit;
|
||||
|
|
@ -3863,9 +3864,10 @@ tree_exit:
|
|||
}
|
||||
|
||||
static isc_result_t
|
||||
allrdatasets(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
|
||||
unsigned int options, isc_stdtime_t now ISC_ATTR_UNUSED,
|
||||
dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) {
|
||||
qpzone_allrdatasets(dns_db_t *db, dns_dbnode_t *dbnode,
|
||||
dns_dbversion_t *dbversion, unsigned int options,
|
||||
isc_stdtime_t now ISC_ATTR_UNUSED,
|
||||
dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) {
|
||||
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
||||
qpznode_t *node = (qpznode_t *)dbnode;
|
||||
qpz_version_t *version = (qpz_version_t *)dbversion;
|
||||
|
|
@ -4599,8 +4601,8 @@ dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
|
|||
}
|
||||
|
||||
static isc_result_t
|
||||
createiterator(dns_db_t *db, unsigned int options,
|
||||
dns_dbiterator_t **iteratorp) {
|
||||
qpzone_createiterator(dns_db_t *db, unsigned int options,
|
||||
dns_dbiterator_t **iteratorp) {
|
||||
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
||||
qpdb_dbiterator_t *iter = NULL;
|
||||
|
||||
|
|
@ -4638,9 +4640,11 @@ createiterator(dns_db_t *db, unsigned int options,
|
|||
}
|
||||
|
||||
static isc_result_t
|
||||
addrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
|
||||
isc_stdtime_t now ISC_ATTR_UNUSED, dns_rdataset_t *rdataset,
|
||||
unsigned int options, dns_rdataset_t *addedrdataset DNS__DB_FLARG) {
|
||||
qpzone_addrdataset(dns_db_t *db, dns_dbnode_t *dbnode,
|
||||
dns_dbversion_t *dbversion,
|
||||
isc_stdtime_t now ISC_ATTR_UNUSED, dns_rdataset_t *rdataset,
|
||||
unsigned int options,
|
||||
dns_rdataset_t *addedrdataset DNS__DB_FLARG) {
|
||||
isc_result_t result;
|
||||
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
||||
qpznode_t *node = (qpznode_t *)dbnode;
|
||||
|
|
@ -4767,9 +4771,10 @@ addrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
|
|||
}
|
||||
|
||||
static isc_result_t
|
||||
subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
|
||||
dns_rdataset_t *rdataset, unsigned int options,
|
||||
dns_rdataset_t *newrdataset DNS__DB_FLARG) {
|
||||
qpzone_subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode,
|
||||
dns_dbversion_t *dbversion, dns_rdataset_t *rdataset,
|
||||
unsigned int options,
|
||||
dns_rdataset_t *newrdataset DNS__DB_FLARG) {
|
||||
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
||||
qpznode_t *node = (qpznode_t *)dbnode;
|
||||
qpz_version_t *version = (qpz_version_t *)dbversion;
|
||||
|
|
@ -4958,8 +4963,9 @@ unlock:
|
|||
}
|
||||
|
||||
static isc_result_t
|
||||
deleterdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
|
||||
dns_rdatatype_t type, dns_rdatatype_t covers DNS__DB_FLARG) {
|
||||
qpzone_deleterdataset(dns_db_t *db, dns_dbnode_t *dbnode,
|
||||
dns_dbversion_t *dbversion, dns_rdatatype_t type,
|
||||
dns_rdatatype_t covers DNS__DB_FLARG) {
|
||||
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
||||
qpznode_t *node = (qpznode_t *)dbnode;
|
||||
qpz_version_t *version = (qpz_version_t *)dbversion;
|
||||
|
|
@ -5071,9 +5077,10 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
|
|||
dns_rdataset_init(&rdataset_aaaa);
|
||||
dns_rdataset_init(&sigrdataset_aaaa);
|
||||
|
||||
result = find(ctx->db, name, ctx->version, dns_rdatatype_a,
|
||||
DNS_DBFIND_GLUEOK, 0, (dns_dbnode_t **)&node_a, name_a,
|
||||
&rdataset_a, &sigrdataset_a DNS__DB_FLARG_PASS);
|
||||
result = qpzone_find(ctx->db, name, ctx->version, dns_rdatatype_a,
|
||||
DNS_DBFIND_GLUEOK, 0, (dns_dbnode_t **)&node_a,
|
||||
name_a, &rdataset_a,
|
||||
&sigrdataset_a DNS__DB_FLARG_PASS);
|
||||
if (result == DNS_R_GLUE) {
|
||||
glue = new_glue(ctx->db->mctx, name_a);
|
||||
|
||||
|
|
@ -5089,10 +5096,10 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
|
|||
}
|
||||
}
|
||||
|
||||
result = find(ctx->db, name, ctx->version, dns_rdatatype_aaaa,
|
||||
DNS_DBFIND_GLUEOK, 0, (dns_dbnode_t **)&node_aaaa,
|
||||
name_aaaa, &rdataset_aaaa,
|
||||
&sigrdataset_aaaa DNS__DB_FLARG_PASS);
|
||||
result = qpzone_find(ctx->db, name, ctx->version, dns_rdatatype_aaaa,
|
||||
DNS_DBFIND_GLUEOK, 0, (dns_dbnode_t **)&node_aaaa,
|
||||
name_aaaa, &rdataset_aaaa,
|
||||
&sigrdataset_aaaa DNS__DB_FLARG_PASS);
|
||||
if (result == DNS_R_GLUE) {
|
||||
if (glue == NULL) {
|
||||
glue = new_glue(ctx->db->mctx, name_aaaa);
|
||||
|
|
@ -5264,7 +5271,7 @@ create_gluelist(qpzonedb_t *qpdb, qpz_version_t *version, qpznode_t *node,
|
|||
*/
|
||||
|
||||
(void)dns_rdataset_additionaldata(rdataset, dns_rootname,
|
||||
glue_nsdname_cb, &ctx);
|
||||
glue_nsdname_cb, &ctx, 0);
|
||||
|
||||
CMM_STORE_SHARED(gluelist->glue, ctx.glue);
|
||||
|
||||
|
|
@ -5358,22 +5365,22 @@ static dns_dbmethods_t qpdb_zonemethods = {
|
|||
.newversion = newversion,
|
||||
.attachversion = attachversion,
|
||||
.closeversion = closeversion,
|
||||
.findnode = findnode,
|
||||
.find = find,
|
||||
.findnode = qpzone_findnode,
|
||||
.find = qpzone_find,
|
||||
.attachnode = attachnode,
|
||||
.detachnode = detachnode,
|
||||
.createiterator = createiterator,
|
||||
.findrdataset = findrdataset,
|
||||
.allrdatasets = allrdatasets,
|
||||
.addrdataset = addrdataset,
|
||||
.subtractrdataset = subtractrdataset,
|
||||
.deleterdataset = deleterdataset,
|
||||
.createiterator = qpzone_createiterator,
|
||||
.findrdataset = qpzone_findrdataset,
|
||||
.allrdatasets = qpzone_allrdatasets,
|
||||
.addrdataset = qpzone_addrdataset,
|
||||
.subtractrdataset = qpzone_subtractrdataset,
|
||||
.deleterdataset = qpzone_deleterdataset,
|
||||
.issecure = issecure,
|
||||
.nodecount = nodecount,
|
||||
.setloop = setloop,
|
||||
.getoriginnode = getoriginnode,
|
||||
.getnsec3parameters = getnsec3parameters,
|
||||
.findnsec3node = findnsec3node,
|
||||
.findnsec3node = qpzone_findnsec3node,
|
||||
.setsigningtime = setsigningtime,
|
||||
.getsigningtime = getsigningtime,
|
||||
.getsize = getsize,
|
||||
|
|
|
|||
|
|
@ -479,7 +479,8 @@ dns_rdataset_towire(dns_rdataset_t *rdataset, const dns_name_t *owner_name,
|
|||
isc_result_t
|
||||
dns_rdataset_additionaldata(dns_rdataset_t *rdataset,
|
||||
const dns_name_t *owner_name,
|
||||
dns_additionaldatafunc_t add, void *arg) {
|
||||
dns_additionaldatafunc_t add, void *arg,
|
||||
size_t limit) {
|
||||
dns_rdata_t rdata = DNS_RDATA_INIT;
|
||||
isc_result_t result;
|
||||
|
||||
|
|
@ -491,6 +492,10 @@ dns_rdataset_additionaldata(dns_rdataset_t *rdataset,
|
|||
REQUIRE(DNS_RDATASET_VALID(rdataset));
|
||||
REQUIRE((rdataset->attributes & DNS_RDATASETATTR_QUESTION) == 0);
|
||||
|
||||
if (limit != 0 && dns_rdataset_count(rdataset) > limit) {
|
||||
return DNS_R_TOOMANYRECORDS;
|
||||
}
|
||||
|
||||
result = dns_rdataset_first(rdataset);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -8578,9 +8578,6 @@ rctx_answer_any(respctx_t *rctx) {
|
|||
rdataset->attributes |= DNS_RDATASETATTR_ANSWER;
|
||||
rdataset->attributes |= DNS_RDATASETATTR_CACHE;
|
||||
rdataset->trust = rctx->trust;
|
||||
|
||||
(void)dns_rdataset_additionaldata(rdataset, rctx->aname,
|
||||
check_related, rctx);
|
||||
}
|
||||
|
||||
return ISC_R_SUCCESS;
|
||||
|
|
@ -8628,7 +8625,8 @@ rctx_answer_match(respctx_t *rctx) {
|
|||
rctx->ardataset->attributes |= DNS_RDATASETATTR_CACHE;
|
||||
rctx->ardataset->trust = rctx->trust;
|
||||
(void)dns_rdataset_additionaldata(rctx->ardataset, rctx->aname,
|
||||
check_related, rctx);
|
||||
check_related, rctx,
|
||||
DNS_RDATASET_MAXADDITIONAL);
|
||||
|
||||
for (sigrdataset = ISC_LIST_HEAD(rctx->aname->list);
|
||||
sigrdataset != NULL;
|
||||
|
|
@ -8835,7 +8833,8 @@ rctx_authority_positive(respctx_t *rctx) {
|
|||
*/
|
||||
(void)dns_rdataset_additionaldata(
|
||||
rdataset, name, check_related,
|
||||
rctx);
|
||||
rctx,
|
||||
DNS_RDATASET_MAXADDITIONAL);
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -9342,8 +9341,11 @@ rctx_referral(respctx_t *rctx) {
|
|||
*/
|
||||
INSIST(rctx->ns_rdataset != NULL);
|
||||
FCTX_ATTR_SET(fctx, FCTX_ATTR_GLUING);
|
||||
/*
|
||||
* We want to append **all** the GLUE records here.
|
||||
*/
|
||||
(void)dns_rdataset_additionaldata(rctx->ns_rdataset, rctx->ns_name,
|
||||
check_related, rctx);
|
||||
check_related, rctx, 0);
|
||||
#if CHECK_FOR_GLUE_IN_ANSWER
|
||||
/*
|
||||
* Look in the answer section for "glue" that is incorrectly
|
||||
|
|
@ -9458,7 +9460,8 @@ again:
|
|||
if (CHASE(rdataset)) {
|
||||
rdataset->attributes &= ~DNS_RDATASETATTR_CHASE;
|
||||
(void)dns_rdataset_additionaldata(
|
||||
rdataset, name, check_related, rctx);
|
||||
rdataset, name, check_related, rctx,
|
||||
DNS_RDATASET_MAXADDITIONAL);
|
||||
rescan = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,6 +85,37 @@
|
|||
|
||||
#define INITIAL_DNS_MESSAGE_BUFFER_SIZE (512)
|
||||
|
||||
/*
|
||||
* The value should be small enough to not allow a server to open too
|
||||
* many streams at once. It should not be too small either because
|
||||
* the incoming data will be split into too many chunks with each of
|
||||
* them processed asynchronously.
|
||||
*/
|
||||
#define INCOMING_DATA_CHUNK_SIZE (256)
|
||||
|
||||
/*
|
||||
* Often processing a chunk does not change the number of streams. In
|
||||
* that case we can process more than once, but we still should have a
|
||||
* hard limit on that.
|
||||
*/
|
||||
#define INCOMING_DATA_MAX_CHUNKS_AT_ONCE (4)
|
||||
|
||||
/*
|
||||
* These constants define the grace period to help detect flooding clients.
|
||||
*
|
||||
* The first one defines how much data can be processed before opening
|
||||
* a first stream and received at least some useful (=DNS) data.
|
||||
*
|
||||
* The second one defines how much data from a client we read before
|
||||
* trying to drop a clients who sends not enough useful data.
|
||||
*
|
||||
* The third constant defines how many streams we agree to process
|
||||
* before checking if there was at least one DNS request received.
|
||||
*/
|
||||
#define INCOMING_DATA_INITIAL_STREAM_SIZE (1536)
|
||||
#define INCOMING_DATA_GRACE_SIZE (MAX_ALLOWED_DATA_IN_HEADERS)
|
||||
#define MAX_STREAMS_BEFORE_FIRST_REQUEST (50)
|
||||
|
||||
typedef struct isc_nm_http_response_status {
|
||||
size_t code;
|
||||
size_t content_length;
|
||||
|
|
@ -143,6 +174,7 @@ struct isc_nm_http_session {
|
|||
ISC_LIST(http_cstream_t) cstreams;
|
||||
ISC_LIST(isc_nmsocket_h2_t) sstreams;
|
||||
size_t nsstreams;
|
||||
uint64_t total_opened_sstreams;
|
||||
|
||||
isc_nmhandle_t *handle;
|
||||
isc_nmhandle_t *client_httphandle;
|
||||
|
|
@ -155,6 +187,18 @@ struct isc_nm_http_session {
|
|||
|
||||
isc__nm_http_pending_callbacks_t pending_write_callbacks;
|
||||
isc_buffer_t *pending_write_data;
|
||||
|
||||
/*
|
||||
* The statistical values below are for usage on server-side
|
||||
* only. They are meant to detect clients that are taking too many
|
||||
* resources from the server.
|
||||
*/
|
||||
uint64_t received; /* How many requests have been received. */
|
||||
uint64_t submitted; /* How many responses were submitted to send */
|
||||
uint64_t processed; /* How many responses were processed. */
|
||||
|
||||
uint64_t processed_incoming_data;
|
||||
uint64_t processed_useful_data; /* DNS data */
|
||||
};
|
||||
|
||||
typedef enum isc_http_error_responses {
|
||||
|
|
@ -177,6 +221,7 @@ typedef struct isc_http_send_req {
|
|||
void *cbarg;
|
||||
isc_buffer_t *pending_write_data;
|
||||
isc__nm_http_pending_callbacks_t pending_write_callbacks;
|
||||
uint64_t submitted;
|
||||
} isc_http_send_req_t;
|
||||
|
||||
#define HTTP_ENDPOINTS_MAGIC ISC_MAGIC('H', 'T', 'E', 'P')
|
||||
|
|
@ -189,10 +234,26 @@ static bool
|
|||
http_send_outgoing(isc_nm_http_session_t *session, isc_nmhandle_t *httphandle,
|
||||
isc_nm_cb_t cb, void *cbarg);
|
||||
|
||||
static void
|
||||
http_log_flooding_peer(isc_nm_http_session_t *session);
|
||||
|
||||
static bool
|
||||
http_is_flooding_peer(isc_nm_http_session_t *session);
|
||||
|
||||
static ssize_t
|
||||
http_process_input_data(isc_nm_http_session_t *session,
|
||||
isc_buffer_t *input_data);
|
||||
|
||||
static inline bool
|
||||
http_too_many_active_streams(isc_nm_http_session_t *session);
|
||||
|
||||
static void
|
||||
http_do_bio(isc_nm_http_session_t *session, isc_nmhandle_t *send_httphandle,
|
||||
isc_nm_cb_t send_cb, void *send_cbarg);
|
||||
|
||||
static void
|
||||
http_do_bio_async(isc_nm_http_session_t *session);
|
||||
|
||||
static void
|
||||
failed_httpstream_read_cb(isc_nmsocket_t *sock, isc_result_t result,
|
||||
isc_nm_http_session_t *session);
|
||||
|
|
@ -499,9 +560,20 @@ finish_http_session(isc_nm_http_session_t *session) {
|
|||
if (!session->closed) {
|
||||
session->closed = true;
|
||||
session->reading = false;
|
||||
isc_nm_read_stop(session->handle);
|
||||
isc__nmsocket_timer_stop(session->handle->sock);
|
||||
isc_nmhandle_close(session->handle);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free any unprocessed incoming data in order to not process
|
||||
* it during indirect calls to http_do_bio() that might happen
|
||||
* when calling the failed callbacks.
|
||||
*/
|
||||
if (session->buf != NULL) {
|
||||
isc_buffer_free(&session->buf);
|
||||
}
|
||||
|
||||
if (session->client) {
|
||||
client_call_failed_read_cb(ISC_R_UNEXPECTED, session);
|
||||
} else {
|
||||
|
|
@ -575,6 +647,7 @@ on_server_data_chunk_recv_callback(int32_t stream_id, const uint8_t *data,
|
|||
if (new_bufsize <= MAX_DNS_MESSAGE_SIZE &&
|
||||
new_bufsize <= h2->content_length)
|
||||
{
|
||||
session->processed_useful_data += len;
|
||||
isc_buffer_putmem(&h2->rbuf, data, len);
|
||||
break;
|
||||
}
|
||||
|
|
@ -623,6 +696,9 @@ call_unlink_cstream_readcb(http_cstream_t *cstream,
|
|||
isc_buffer_usedregion(cstream->rbuf, &read_data);
|
||||
cstream->read_cb(session->client_httphandle, result, &read_data,
|
||||
cstream->read_cbarg);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
isc__nmsocket_timer_restart(session->handle->sock);
|
||||
}
|
||||
put_http_cstream(session->mctx, cstream);
|
||||
}
|
||||
|
||||
|
|
@ -664,6 +740,9 @@ on_server_stream_close_callback(int32_t stream_id,
|
|||
|
||||
ISC_LIST_UNLINK(session->sstreams, sock->h2, link);
|
||||
session->nsstreams--;
|
||||
if (sock->h2->request_received) {
|
||||
session->submitted++;
|
||||
}
|
||||
|
||||
/*
|
||||
* By making a call to isc__nmsocket_prep_destroy(), we ensure that
|
||||
|
|
@ -975,6 +1054,181 @@ client_submit_request(isc_nm_http_session_t *session, http_cstream_t *stream) {
|
|||
return ISC_R_SUCCESS;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
http_process_input_data(isc_nm_http_session_t *session,
|
||||
isc_buffer_t *input_data) {
|
||||
ssize_t readlen = 0;
|
||||
ssize_t processed = 0;
|
||||
isc_region_t chunk = { 0 };
|
||||
size_t before, after;
|
||||
size_t i;
|
||||
|
||||
REQUIRE(VALID_HTTP2_SESSION(session));
|
||||
REQUIRE(input_data != NULL);
|
||||
|
||||
if (!http_session_active(session)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* For clients that initiate request themselves just process
|
||||
* everything.
|
||||
*/
|
||||
if (session->client) {
|
||||
isc_buffer_remainingregion(input_data, &chunk);
|
||||
if (chunk.length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
readlen = nghttp2_session_mem_recv(session->ngsession,
|
||||
chunk.base, chunk.length);
|
||||
|
||||
if (readlen >= 0) {
|
||||
isc_buffer_forward(input_data, readlen);
|
||||
session->processed_incoming_data += readlen;
|
||||
}
|
||||
|
||||
return readlen;
|
||||
}
|
||||
|
||||
/*
|
||||
* If no streams are created during processing, we might process
|
||||
* more than one chunk at a time. Still we should not overdo that
|
||||
* to avoid processing too much data at once as such behaviour is
|
||||
* known for trashing the memory allocator at times.
|
||||
*/
|
||||
for (before = after = session->nsstreams, i = 0;
|
||||
after <= before && i < INCOMING_DATA_MAX_CHUNKS_AT_ONCE;
|
||||
after = session->nsstreams, i++)
|
||||
{
|
||||
const uint64_t active_streams =
|
||||
(session->received - session->processed);
|
||||
|
||||
/*
|
||||
* If there are non completed send requests in flight -let's
|
||||
* not process any incoming data, as it could lead to piling
|
||||
* up too much send data in send buffers. With many clients
|
||||
* connected it can lead to excessive memory consumption on
|
||||
* the server instance.
|
||||
*/
|
||||
if (session->sending > 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have reached the maximum number of streams used, we
|
||||
* might stop processing for now, as nghttp2 will happily
|
||||
* consume as much data as possible.
|
||||
*/
|
||||
if (session->nsstreams >= session->max_concurrent_streams &&
|
||||
active_streams > 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (http_too_many_active_streams(session)) {
|
||||
break;
|
||||
}
|
||||
|
||||
isc_buffer_remainingregion(input_data, &chunk);
|
||||
if (chunk.length == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
chunk.length = ISC_MIN(chunk.length, INCOMING_DATA_CHUNK_SIZE);
|
||||
|
||||
readlen = nghttp2_session_mem_recv(session->ngsession,
|
||||
chunk.base, chunk.length);
|
||||
|
||||
if (readlen >= 0) {
|
||||
isc_buffer_forward(input_data, readlen);
|
||||
session->processed_incoming_data += readlen;
|
||||
processed += readlen;
|
||||
} else {
|
||||
isc_buffer_clear(input_data);
|
||||
return readlen;
|
||||
}
|
||||
}
|
||||
|
||||
return processed;
|
||||
}
|
||||
|
||||
static void
|
||||
http_log_flooding_peer(isc_nm_http_session_t *session) {
|
||||
const int log_level = ISC_LOG_DEBUG(1);
|
||||
if (session->handle != NULL && isc_log_wouldlog(log_level)) {
|
||||
char client_sabuf[ISC_SOCKADDR_FORMATSIZE];
|
||||
char local_sabuf[ISC_SOCKADDR_FORMATSIZE];
|
||||
|
||||
isc_sockaddr_format(&session->handle->sock->peer, client_sabuf,
|
||||
sizeof(client_sabuf));
|
||||
isc_sockaddr_format(&session->handle->sock->iface, local_sabuf,
|
||||
sizeof(local_sabuf));
|
||||
isc__nmsocket_log(session->handle->sock, log_level,
|
||||
"Dropping a flooding HTTP/2 peer "
|
||||
"%s (on %s) - processed: %" PRIu64
|
||||
" bytes, of them useful: %" PRIu64 "",
|
||||
client_sabuf, local_sabuf,
|
||||
session->processed_incoming_data,
|
||||
session->processed_useful_data);
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
http_is_flooding_peer(isc_nm_http_session_t *session) {
|
||||
if (session->client) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* A flooding client can try to open a lot of streams before
|
||||
* submitting a request. Let's drop such clients.
|
||||
*/
|
||||
if (session->received == 0 &&
|
||||
session->total_opened_sstreams > MAX_STREAMS_BEFORE_FIRST_REQUEST)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have processed enough data to open at least one stream and
|
||||
* get some useful data.
|
||||
*/
|
||||
if (session->processed_incoming_data >
|
||||
INCOMING_DATA_INITIAL_STREAM_SIZE &&
|
||||
(session->total_opened_sstreams == 0 ||
|
||||
session->processed_useful_data == 0))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (session->processed_incoming_data < INCOMING_DATA_GRACE_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* The overhead of DoH per DNS message can be minimum 160-180
|
||||
* bytes. We should allow more for extra information that can be
|
||||
* included in headers, so let's use 256 bytes. Minimum DNS
|
||||
* message size is 12 bytes. So, (256+12)/12=22. Even that can be
|
||||
* too restricting for some edge cases, but should be good enough
|
||||
* for any practical purposes. Not to mention that HTTP/2 may
|
||||
* include legitimate data that is completely useless for DNS
|
||||
* purposes...
|
||||
*
|
||||
* Anyway, at that point we should have processed enough requests
|
||||
* for such clients (if any).
|
||||
*/
|
||||
if (session->processed_useful_data == 0 ||
|
||||
(session->processed_incoming_data /
|
||||
session->processed_useful_data) > 22)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read callback from TLS socket.
|
||||
*/
|
||||
|
|
@ -984,6 +1238,7 @@ http_readcb(isc_nmhandle_t *handle ISC_ATTR_UNUSED, isc_result_t result,
|
|||
isc_nm_http_session_t *session = (isc_nm_http_session_t *)data;
|
||||
isc_nm_http_session_t *tmpsess = NULL;
|
||||
ssize_t readlen;
|
||||
isc_buffer_t input;
|
||||
|
||||
REQUIRE(VALID_HTTP2_SESSION(session));
|
||||
|
||||
|
|
@ -1001,11 +1256,17 @@ http_readcb(isc_nmhandle_t *handle ISC_ATTR_UNUSED, isc_result_t result,
|
|||
goto done;
|
||||
}
|
||||
|
||||
readlen = nghttp2_session_mem_recv(session->ngsession, region->base,
|
||||
region->length);
|
||||
isc_buffer_init(&input, region->base, region->length);
|
||||
isc_buffer_add(&input, region->length);
|
||||
|
||||
readlen = http_process_input_data(session, &input);
|
||||
if (readlen < 0) {
|
||||
failed_read_cb(ISC_R_UNEXPECTED, session);
|
||||
goto done;
|
||||
} else if (http_is_flooding_peer(session)) {
|
||||
http_log_flooding_peer(session);
|
||||
failed_read_cb(ISC_R_RANGE, session);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ((size_t)readlen < region->length) {
|
||||
|
|
@ -1017,11 +1278,12 @@ http_readcb(isc_nmhandle_t *handle ISC_ATTR_UNUSED, isc_result_t result,
|
|||
isc_buffer_putmem(session->buf, region->base + readlen,
|
||||
unread_size);
|
||||
isc_nm_read_stop(session->handle);
|
||||
http_do_bio_async(session);
|
||||
} else {
|
||||
/* We might have something to receive or send, do IO */
|
||||
http_do_bio(session, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
/* We might have something to receive or send, do IO */
|
||||
http_do_bio(session, NULL, NULL, NULL);
|
||||
|
||||
done:
|
||||
isc__nm_httpsession_detach(&tmpsess);
|
||||
}
|
||||
|
|
@ -1059,14 +1321,18 @@ http_writecb(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
|
|||
}
|
||||
|
||||
isc_buffer_free(&req->pending_write_data);
|
||||
session->processed += req->submitted;
|
||||
isc_mem_put(session->mctx, req, sizeof(*req));
|
||||
|
||||
session->sending--;
|
||||
http_do_bio(session, NULL, NULL, NULL);
|
||||
isc_nmhandle_detach(&transphandle);
|
||||
if (result != ISC_R_SUCCESS && session->sending == 0) {
|
||||
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
http_do_bio(session, NULL, NULL, NULL);
|
||||
} else {
|
||||
finish_http_session(session);
|
||||
}
|
||||
isc_nmhandle_detach(&transphandle);
|
||||
|
||||
isc__nm_httpsession_detach(&session);
|
||||
}
|
||||
|
||||
|
|
@ -1227,7 +1493,9 @@ http_send_outgoing(isc_nm_http_session_t *session, isc_nmhandle_t *httphandle,
|
|||
*send = (isc_http_send_req_t){ .pending_write_data =
|
||||
session->pending_write_data,
|
||||
.cb = cb,
|
||||
.cbarg = cbarg };
|
||||
.cbarg = cbarg,
|
||||
.submitted = session->submitted };
|
||||
session->submitted = 0;
|
||||
session->pending_write_data = NULL;
|
||||
move_pending_send_callbacks(session, send);
|
||||
|
||||
|
|
@ -1249,6 +1517,28 @@ nothing_to_send:
|
|||
return false;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
http_too_many_active_streams(isc_nm_http_session_t *session) {
|
||||
const uint64_t active_streams = session->received - session->processed;
|
||||
const uint64_t max_active_streams =
|
||||
ISC_MIN(ISC_NETMGR_MAX_STREAM_CLIENTS_PER_CONN,
|
||||
session->max_concurrent_streams);
|
||||
|
||||
if (session->client) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do not process incoming data if there are too many active DNS
|
||||
* clients (streams) per connection.
|
||||
*/
|
||||
if (active_streams >= max_active_streams) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
http_do_bio(isc_nm_http_session_t *session, isc_nmhandle_t *send_httphandle,
|
||||
isc_nm_cb_t send_cb, void *send_cbarg) {
|
||||
|
|
@ -1264,42 +1554,86 @@ http_do_bio(isc_nm_http_session_t *session, isc_nmhandle_t *send_httphandle,
|
|||
finish_http_session(session);
|
||||
}
|
||||
return;
|
||||
} else if (nghttp2_session_want_read(session->ngsession) == 0 &&
|
||||
nghttp2_session_want_write(session->ngsession) == 0 &&
|
||||
session->pending_write_data == NULL)
|
||||
{
|
||||
session->closing = true;
|
||||
}
|
||||
|
||||
if (send_cb != NULL) {
|
||||
INSIST(VALID_NMHANDLE(send_httphandle));
|
||||
(void)http_send_outgoing(session, send_httphandle, send_cb,
|
||||
send_cbarg);
|
||||
return;
|
||||
}
|
||||
|
||||
INSIST(send_httphandle == NULL);
|
||||
INSIST(send_cb == NULL);
|
||||
INSIST(send_cbarg == NULL);
|
||||
|
||||
if (session->pending_write_data != NULL && session->sending == 0) {
|
||||
(void)http_send_outgoing(session, NULL, NULL, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nghttp2_session_want_read(session->ngsession) != 0) {
|
||||
if (!session->reading) {
|
||||
/* We have not yet started
|
||||
* reading from this handle */
|
||||
/* We have not yet started reading from this handle */
|
||||
isc__nmsocket_timer_start(session->handle->sock);
|
||||
isc_nm_read(session->handle, http_readcb, session);
|
||||
session->reading = true;
|
||||
} else if (session->buf != NULL) {
|
||||
size_t remaining =
|
||||
isc_buffer_remaininglength(session->buf);
|
||||
/* Leftover data in the
|
||||
* buffer, use it */
|
||||
size_t readlen = nghttp2_session_mem_recv(
|
||||
session->ngsession,
|
||||
isc_buffer_current(session->buf), remaining);
|
||||
/* Leftover data in the buffer, use it */
|
||||
size_t remaining_after = 0;
|
||||
ssize_t readlen = 0;
|
||||
isc_nm_http_session_t *tmpsess = NULL;
|
||||
|
||||
if (readlen == remaining) {
|
||||
/*
|
||||
* Let's ensure that HTTP/2 session and its associated
|
||||
* data will not go "out of scope" too early.
|
||||
*/
|
||||
isc__nm_httpsession_attach(session, &tmpsess);
|
||||
|
||||
readlen = http_process_input_data(session,
|
||||
session->buf);
|
||||
|
||||
remaining_after =
|
||||
isc_buffer_remaininglength(session->buf);
|
||||
|
||||
if (readlen < 0) {
|
||||
failed_read_cb(ISC_R_UNEXPECTED, session);
|
||||
} else if (http_is_flooding_peer(session)) {
|
||||
http_log_flooding_peer(session);
|
||||
failed_read_cb(ISC_R_RANGE, session);
|
||||
} else if ((size_t)readlen == remaining) {
|
||||
isc_buffer_free(&session->buf);
|
||||
http_do_bio(session, NULL, NULL, NULL);
|
||||
} else if (remaining_after > 0 &&
|
||||
remaining_after < remaining)
|
||||
{
|
||||
/*
|
||||
* We have processed a part of the data, now
|
||||
* let's delay processing of whatever is left
|
||||
* here. We want it to be an async operation so
|
||||
* that we will:
|
||||
*
|
||||
* a) let other things run;
|
||||
* b) have finer grained control over how much
|
||||
* data is processed at once, because nghttp2
|
||||
* would happily consume as much data we pass to
|
||||
* it and that could overwhelm the server.
|
||||
*/
|
||||
http_do_bio_async(session);
|
||||
} else {
|
||||
isc_buffer_forward(session->buf, readlen);
|
||||
(void)http_send_outgoing(session, NULL, NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
http_do_bio(session, send_httphandle, send_cb,
|
||||
send_cbarg);
|
||||
isc__nm_httpsession_detach(&tmpsess);
|
||||
return;
|
||||
} else {
|
||||
/* Resume reading, it's
|
||||
* idempotent, wait for more
|
||||
/*
|
||||
* Resume reading, it's idempotent, wait for more
|
||||
*/
|
||||
isc__nmsocket_timer_start(session->handle->sock);
|
||||
isc_nm_read(session->handle, http_readcb, session);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -1307,20 +1641,54 @@ http_do_bio(isc_nm_http_session_t *session, isc_nmhandle_t *send_httphandle,
|
|||
isc_nm_read_stop(session->handle);
|
||||
}
|
||||
|
||||
if (send_cb != NULL) {
|
||||
INSIST(VALID_NMHANDLE(send_httphandle));
|
||||
(void)http_send_outgoing(session, send_httphandle, send_cb,
|
||||
send_cbarg);
|
||||
} else {
|
||||
INSIST(send_httphandle == NULL);
|
||||
INSIST(send_cb == NULL);
|
||||
INSIST(send_cbarg == NULL);
|
||||
(void)http_send_outgoing(session, NULL, NULL, NULL);
|
||||
/* we might have some data to send after processing */
|
||||
(void)http_send_outgoing(session, NULL, NULL, NULL);
|
||||
|
||||
if (nghttp2_session_want_read(session->ngsession) == 0 &&
|
||||
nghttp2_session_want_write(session->ngsession) == 0 &&
|
||||
session->pending_write_data == NULL)
|
||||
{
|
||||
session->closing = true;
|
||||
isc_nm_read_stop(session->handle);
|
||||
if (session->sending == 0) {
|
||||
finish_http_session(session);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
http_do_bio_async_cb(void *arg) {
|
||||
isc_nm_http_session_t *session = arg;
|
||||
|
||||
REQUIRE(VALID_HTTP2_SESSION(session));
|
||||
|
||||
if (session->handle != NULL &&
|
||||
!isc__nmsocket_closing(session->handle->sock))
|
||||
{
|
||||
http_do_bio(session, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
isc__nm_httpsession_detach(&session);
|
||||
}
|
||||
|
||||
static void
|
||||
http_do_bio_async(isc_nm_http_session_t *session) {
|
||||
isc_nm_http_session_t *tmpsess = NULL;
|
||||
|
||||
REQUIRE(VALID_HTTP2_SESSION(session));
|
||||
|
||||
if (session->handle == NULL ||
|
||||
isc__nmsocket_closing(session->handle->sock))
|
||||
{
|
||||
return;
|
||||
}
|
||||
isc__nm_httpsession_attach(session, &tmpsess);
|
||||
isc_async_run(session->handle->sock->worker->loop, http_do_bio_async_cb,
|
||||
tmpsess);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
get_http_cstream(isc_nmsocket_t *sock, http_cstream_t **streamp) {
|
||||
http_cstream_t *cstream = sock->h2->connect.cstream;
|
||||
|
|
@ -1442,6 +1810,7 @@ transport_connect_cb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
|
|||
}
|
||||
|
||||
http_transpost_tcp_nodelay(handle);
|
||||
isc__nmhandle_set_manual_timer(session->handle, true);
|
||||
|
||||
http_call_connect_cb(http_sock, session, result);
|
||||
|
||||
|
|
@ -1723,6 +2092,7 @@ server_on_begin_headers_callback(nghttp2_session *ngsession,
|
|||
session->nsstreams++;
|
||||
isc__nm_httpsession_attach(session, &socket->h2->session);
|
||||
ISC_LIST_APPEND(session->sstreams, socket->h2, link);
|
||||
session->total_opened_sstreams++;
|
||||
|
||||
nghttp2_session_set_stream_user_data(ngsession, frame->hd.stream_id,
|
||||
socket);
|
||||
|
|
@ -1782,6 +2152,8 @@ server_handle_path_header(isc_nmsocket_t *socket, const uint8_t *value,
|
|||
socket->worker->mctx, dns_value,
|
||||
dns_value_len,
|
||||
&socket->h2->query_data_len);
|
||||
socket->h2->session->processed_useful_data +=
|
||||
dns_value_len;
|
||||
} else {
|
||||
socket->h2->query_too_large = true;
|
||||
return ISC_HTTP_ERROR_PAYLOAD_TOO_LARGE;
|
||||
|
|
@ -2090,6 +2462,12 @@ server_call_cb(isc_nmsocket_t *socket, const isc_result_t result,
|
|||
handle = isc__nmhandle_get(socket, NULL, NULL);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
data = NULL;
|
||||
} else if (socket->h2->session->handle != NULL) {
|
||||
isc__nmsocket_timer_restart(socket->h2->session->handle->sock);
|
||||
}
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
socket->h2->request_received = true;
|
||||
socket->h2->session->received++;
|
||||
}
|
||||
socket->h2->cb(handle, result, data, socket->h2->cbarg);
|
||||
isc_nmhandle_detach(&handle);
|
||||
|
|
@ -2106,6 +2484,12 @@ isc__nm_http_bad_request(isc_nmhandle_t *handle) {
|
|||
REQUIRE(!sock->client);
|
||||
REQUIRE(VALID_HTTP2_SESSION(sock->h2->session));
|
||||
|
||||
if (sock->h2->response_submitted ||
|
||||
!http_session_active(sock->h2->session))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
(void)server_send_error_response(ISC_HTTP_ERROR_BAD_REQUEST,
|
||||
sock->h2->session->ngsession, sock);
|
||||
}
|
||||
|
|
@ -2492,6 +2876,8 @@ httplisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
|
|||
isc__nmsocket_attach(httpserver, &session->serversocket);
|
||||
server_send_connection_header(session);
|
||||
|
||||
isc__nmhandle_set_manual_timer(session->handle, true);
|
||||
|
||||
/* TODO H2 */
|
||||
http_do_bio(session, NULL, NULL, NULL);
|
||||
return ISC_R_SUCCESS;
|
||||
|
|
|
|||
|
|
@ -474,6 +474,7 @@ typedef struct isc_nmsocket_h2 {
|
|||
|
||||
isc_nm_http_endpoints_t *peer_endpoints;
|
||||
|
||||
bool request_received;
|
||||
bool response_submitted;
|
||||
struct {
|
||||
char *uri;
|
||||
|
|
|
|||
|
|
@ -121,6 +121,7 @@ proxystream_on_header_data_cb(const isc_result_t result,
|
|||
* the case of TCP it is disabled by default
|
||||
*/
|
||||
proxystream_read_stop(sock);
|
||||
isc__nmsocket_timer_stop(sock);
|
||||
isc__nmhandle_set_manual_timer(sock->outerhandle, false);
|
||||
|
||||
sock->proxy.header_processed = true;
|
||||
|
|
@ -775,6 +776,7 @@ isc__nm_proxystream_close(isc_nmsocket_t *sock) {
|
|||
* external references, we can close everything.
|
||||
*/
|
||||
proxystream_read_stop(sock);
|
||||
isc__nmsocket_timer_stop(sock);
|
||||
if (sock->outerhandle != NULL) {
|
||||
sock->reading = false;
|
||||
isc_nm_read_stop(sock->outerhandle);
|
||||
|
|
|
|||
|
|
@ -1009,6 +1009,7 @@ streamdns_close_direct(isc_nmsocket_t *sock) {
|
|||
|
||||
if (sock->outerhandle != NULL) {
|
||||
sock->streamdns.reading = false;
|
||||
isc__nmsocket_timer_stop(sock);
|
||||
isc_nm_read_stop(sock->outerhandle);
|
||||
isc_nmhandle_close(sock->outerhandle);
|
||||
isc_nmhandle_detach(&sock->outerhandle);
|
||||
|
|
|
|||
|
|
@ -759,7 +759,9 @@ isc__nm_tcp_read_stop(isc_nmhandle_t *handle) {
|
|||
|
||||
isc_nmsocket_t *sock = handle->sock;
|
||||
|
||||
isc__nmsocket_timer_stop(sock);
|
||||
if (!sock->manual_read_timer) {
|
||||
isc__nmsocket_timer_stop(sock);
|
||||
}
|
||||
isc__nm_stop_reading(sock);
|
||||
sock->reading = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -465,6 +465,7 @@ tls_try_handshake(isc_nmsocket_t *sock, isc_result_t *presult) {
|
|||
|
||||
isc__nmsocket_log_tls_session_reuse(sock, sock->tlsstream.tls);
|
||||
tlshandle = isc__nmhandle_get(sock, &sock->peer, &sock->iface);
|
||||
isc__nmsocket_timer_stop(sock);
|
||||
tls_read_stop(sock);
|
||||
|
||||
if (isc__nm_closing(sock->worker)) {
|
||||
|
|
@ -1154,6 +1155,10 @@ isc__nm_tls_read_stop(isc_nmhandle_t *handle) {
|
|||
|
||||
handle->sock->reading = false;
|
||||
|
||||
if (!handle->sock->manual_read_timer) {
|
||||
isc__nmsocket_timer_stop(handle->sock);
|
||||
}
|
||||
|
||||
tls_read_stop(handle->sock);
|
||||
}
|
||||
|
||||
|
|
@ -1174,6 +1179,7 @@ isc__nm_tls_close(isc_nmsocket_t *sock) {
|
|||
*/
|
||||
tls_read_stop(sock);
|
||||
if (sock->outerhandle != NULL) {
|
||||
isc__nmsocket_timer_stop(sock);
|
||||
isc_nm_read_stop(sock->outerhandle);
|
||||
isc_nmhandle_close(sock->outerhandle);
|
||||
isc_nmhandle_detach(&sock->outerhandle);
|
||||
|
|
|
|||
|
|
@ -2141,7 +2141,8 @@ addname:
|
|||
if (trdataset != NULL && dns_rdatatype_followadditional(type)) {
|
||||
if (client->additionaldepth++ < client->view->max_restarts) {
|
||||
eresult = dns_rdataset_additionaldata(
|
||||
trdataset, fname, query_additional_cb, qctx);
|
||||
trdataset, fname, query_additional_cb, qctx,
|
||||
DNS_RDATASET_MAXADDITIONAL);
|
||||
}
|
||||
client->additionaldepth--;
|
||||
}
|
||||
|
|
@ -2238,7 +2239,7 @@ regular:
|
|||
* We don't care if dns_rdataset_additionaldata() fails.
|
||||
*/
|
||||
(void)dns_rdataset_additionaldata(rdataset, name, query_additional_cb,
|
||||
qctx);
|
||||
qctx, DNS_RDATASET_MAXADDITIONAL);
|
||||
CTRACE(ISC_LOG_DEBUG(3), "query_additional: done");
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue