diff --git a/CHANGES b/CHANGES index 300653d2c1..98caae8e1f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +6156. [bug] Reimplement the maximum and idle timeouts for incoming + zone tranfers. [GL #4004] + 6155. [bug] Treat ISC_R_INVALIDPROTO as a networking error in the dispatch code to avoid retrying with the same server. [GL #4005]< diff --git a/bin/named/main.c b/bin/named/main.c index 5372b902fd..d134215207 100644 --- a/bin/named/main.c +++ b/bin/named/main.c @@ -133,6 +133,9 @@ static bool nonearest = false; static bool nosoa = false; static bool notcp = false; static bool sigvalinsecs = false; +static bool transferinsecs = false; +static bool transferslowly = false; +static bool transferstuck = false; /* * -4 and -6 @@ -765,6 +768,12 @@ parse_T_opt(char *option) { } } else if (!strcmp(option, "sigvalinsecs")) { sigvalinsecs = true; + } else if (!strcmp(option, "transferinsecs")) { + transferinsecs = true; + } else if (!strcmp(option, "transferslowly")) { + transferslowly = true; + } else if (!strcmp(option, "transferstuck")) { + transferstuck = true; } else if (!strncmp(option, "tat=", 4)) { named_g_tat_interval = atoi(option + 4); } else { @@ -1311,6 +1320,15 @@ setup(void) { if (sigvalinsecs) { ns_server_setoption(sctx, NS_SERVER_SIGVALINSECS, true); } + if (transferinsecs) { + ns_server_setoption(sctx, NS_SERVER_TRANSFERINSECS, true); + } + if (transferslowly) { + ns_server_setoption(sctx, NS_SERVER_TRANSFERSLOWLY, true); + } + if (transferstuck) { + ns_server_setoption(sctx, NS_SERVER_TRANSFERSTUCK, true); + } } static void diff --git a/bin/named/zoneconf.c b/bin/named/zoneconf.c index 470069ac8d..6fa7b07c82 100644 --- a/bin/named/zoneconf.c +++ b/bin/named/zoneconf.c @@ -905,6 +905,8 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, int seconds; dns_ttl_t maxttl = 0; /* unlimited */ dns_zone_t *mayberaw = (raw != NULL) ? raw : zone; + bool transferinsecs = ns_server_getoption(named_g_server->sctx, + NS_SERVER_TRANSFERINSECS); i = 0; if (zconfig != NULL) { @@ -1312,12 +1314,16 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, obj = NULL; result = named_config_get(maps, "max-transfer-time-out", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); - dns_zone_setmaxxfrout(zone, cfg_obj_asuint32(obj) * 60); + dns_zone_setmaxxfrout( + zone, transferinsecs ? cfg_obj_asuint32(obj) + : cfg_obj_asuint32(obj) * 60); obj = NULL; result = named_config_get(maps, "max-transfer-idle-out", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); - dns_zone_setidleout(zone, cfg_obj_asuint32(obj) * 60); + dns_zone_setidleout(zone, transferinsecs + ? cfg_obj_asuint32(obj) + : cfg_obj_asuint32(obj) * 60); obj = NULL; result = named_config_get(maps, "max-journal-size", &obj); @@ -1913,12 +1919,16 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, obj = NULL; result = named_config_get(maps, "max-transfer-time-in", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); - dns_zone_setmaxxfrin(mayberaw, cfg_obj_asuint32(obj) * 60); + dns_zone_setmaxxfrin( + mayberaw, transferinsecs ? cfg_obj_asuint32(obj) + : cfg_obj_asuint32(obj) * 60); obj = NULL; result = named_config_get(maps, "max-transfer-idle-in", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); - dns_zone_setidlein(mayberaw, cfg_obj_asuint32(obj) * 60); + dns_zone_setidlein(mayberaw, + transferinsecs ? cfg_obj_asuint32(obj) + : cfg_obj_asuint32(obj) * 60); obj = NULL; result = named_config_get(maps, "max-refresh-time", &obj); diff --git a/bin/tests/system/xfer/clean.sh b/bin/tests/system/xfer/clean.sh index bf5016e8f9..effdda8a92 100644 --- a/bin/tests/system/xfer/clean.sh +++ b/bin/tests/system/xfer/clean.sh @@ -38,3 +38,4 @@ rm -f ns6/*.db ns6/*.bk ns6/*.jnl rm -f ns7/*.db ns7/*.bk ns7/*.jnl rm -f ns8/large.db ns8/small.db rm -f stats.* +rm -f wait_for_message.* diff --git a/bin/tests/system/xfer/ns1/axfr-max-idle-time.db b/bin/tests/system/xfer/ns1/axfr-max-idle-time.db new file mode 100644 index 0000000000..252925f8dc --- /dev/null +++ b/bin/tests/system/xfer/ns1/axfr-max-idle-time.db @@ -0,0 +1,15 @@ +; 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. + +$TTL 3600 +@ IN SOA . . 0 0 0 0 0 +@ IN NS . +$GENERATE 1-5000 host$ TXT data-$ diff --git a/bin/tests/system/xfer/ns1/axfr-max-transfer-time.db b/bin/tests/system/xfer/ns1/axfr-max-transfer-time.db new file mode 100644 index 0000000000..252925f8dc --- /dev/null +++ b/bin/tests/system/xfer/ns1/axfr-max-transfer-time.db @@ -0,0 +1,15 @@ +; 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. + +$TTL 3600 +@ IN SOA . . 0 0 0 0 0 +@ IN NS . +$GENERATE 1-5000 host$ TXT data-$ diff --git a/bin/tests/system/xfer/ns1/named.conf.in b/bin/tests/system/xfer/ns1/named1.conf.in similarity index 88% rename from bin/tests/system/xfer/ns1/named.conf.in rename to bin/tests/system/xfer/ns1/named1.conf.in index 26bca1943e..6777f5bb8d 100644 --- a/bin/tests/system/xfer/ns1/named.conf.in +++ b/bin/tests/system/xfer/ns1/named1.conf.in @@ -45,6 +45,16 @@ zone "edns-expire" { file "edns-expire.db"; }; +zone "axfr-max-transfer-time" { + type primary; + file "axfr-max-transfer-time.db"; +}; + +zone "axfr-max-idle-time" { + type primary; + file "axfr-max-idle-time.db"; +}; + zone "axfr-too-big" { type primary; file "axfr-too-big.db"; diff --git a/bin/tests/system/xfer/ns1/named2.conf.in b/bin/tests/system/xfer/ns1/named2.conf.in new file mode 100644 index 0000000000..434743d101 --- /dev/null +++ b/bin/tests/system/xfer/ns1/named2.conf.in @@ -0,0 +1,40 @@ +/* + * 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. + */ + +include "../../common/rndc.key"; + +controls { + inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; +}; + +options { + query-source address 10.53.0.1; + notify-source 10.53.0.1; + transfer-source 10.53.0.1; + port @PORT@; + pid-file "named.pid"; + listen-on { 10.53.0.1; }; + listen-on-v6 { none; }; + recursion no; + notify yes; +}; + +zone "." { + type primary; + file "root.db"; +}; + +zone "axfr-max-transfer-time" { + type primary; + file "axfr-max-transfer-time.db"; +}; diff --git a/bin/tests/system/xfer/ns1/named3.conf.in b/bin/tests/system/xfer/ns1/named3.conf.in new file mode 100644 index 0000000000..4f6344c697 --- /dev/null +++ b/bin/tests/system/xfer/ns1/named3.conf.in @@ -0,0 +1,40 @@ +/* + * 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. + */ + +include "../../common/rndc.key"; + +controls { + inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; +}; + +options { + query-source address 10.53.0.1; + notify-source 10.53.0.1; + transfer-source 10.53.0.1; + port @PORT@; + pid-file "named.pid"; + listen-on { 10.53.0.1; }; + listen-on-v6 { none; }; + recursion no; + notify yes; +}; + +zone "." { + type primary; + file "root.db"; +}; + +zone "axfr-max-idle-time" { + type primary; + file "axfr-max-idle-time.db"; +}; diff --git a/bin/tests/system/xfer/ns6/named.args b/bin/tests/system/xfer/ns6/named.args new file mode 100644 index 0000000000..2be062bbdd --- /dev/null +++ b/bin/tests/system/xfer/ns6/named.args @@ -0,0 +1 @@ +-D xfer-ns6 -X named.lock -m record -c named.conf -d 99 -g -U 4 -T maxcachesize=2097152 -T transferinsecs diff --git a/bin/tests/system/xfer/ns6/named.conf.in b/bin/tests/system/xfer/ns6/named.conf.in index 636400cfce..d5b8710896 100644 --- a/bin/tests/system/xfer/ns6/named.conf.in +++ b/bin/tests/system/xfer/ns6/named.conf.in @@ -29,6 +29,7 @@ options { notify yes; ixfr-from-differences primary; check-integrity no; + tcp-idle-timeout 600; }; zone "." { @@ -54,6 +55,20 @@ zone "edns-expire" { file "edns-expire.bk"; }; +zone "axfr-max-transfer-time" { + type secondary; + max-transfer-time-in 1; # this is tested as seconds, when used with '-T transferinsecs' + primaries { 10.53.0.1; }; + file "axfr-max-transfer-time.bk"; +}; + +zone "axfr-max-idle-time" { + type secondary; + max-transfer-idle-in 50; # this is tested as seconds, when used with '-T transferinsecs' + primaries { 10.53.0.1; }; + file "axfr-max-idle-time.bk"; +}; + zone "axfr-too-big" { type secondary; max-records 30; diff --git a/bin/tests/system/xfer/setup.sh b/bin/tests/system/xfer/setup.sh index 092d798799..ff64d8fbdd 100644 --- a/bin/tests/system/xfer/setup.sh +++ b/bin/tests/system/xfer/setup.sh @@ -23,7 +23,7 @@ $SHELL ${TOP_SRCDIR}/bin/tests/system/genzone.sh 7 >ns7/primary2.db cp -f ns4/root.db.in ns4/root.db $PERL -e 'for ($i=0;$i<10000;$i++){ printf("x%u 0 in a 10.53.0.1\n", $i);}' >> ns4/root.db -copy_setports ns1/named.conf.in ns1/named.conf +copy_setports ns1/named1.conf.in ns1/named.conf copy_setports ns2/named.conf.in ns2/named.conf copy_setports ns3/named.conf.in ns3/named.conf copy_setports ns6/named.conf.in ns6/named.conf diff --git a/bin/tests/system/xfer/tests.sh b/bin/tests/system/xfer/tests.sh index 25cb9857d6..5891de70ba 100755 --- a/bin/tests/system/xfer/tests.sh +++ b/bin/tests/system/xfer/tests.sh @@ -15,6 +15,7 @@ DIGOPTS="+tcp +noadd +nosea +nostat +noquest +nocomm +nocmd -p ${PORT}" RNDCCMD="$RNDC -c ../common/rndc.conf -p ${CONTROLPORT} -s" +NS_PARAMS="-X named.lock -m record -c named.conf -d 99 -g -U 4 -T maxcachesize=2097152" status=0 n=0 @@ -580,5 +581,45 @@ grep "10.53.0.3#${EXTRAPORT1} (primary): query 'primary/SOA/IN' approved" ns6/na if test $tmp != 0 ; then echo_i "failed"; fi status=$((status+tmp)) +wait_for_message() ( + nextpartpeek ns6/named.run > wait_for_message.$n + grep -F "$1" wait_for_message.$n >/dev/null +) + +nextpart ns6/named.run > /dev/null + +n=$((n+1)) +echo_i "test max-transfer-time-in with 1 second timeout ($n)" +stop_server ns1 +copy_setports ns1/named2.conf.in ns1/named.conf +start_server --noclean --restart --port ${PORT} ns1 -- "-D xfer-ns1 $NS_PARAMS -T transferinsecs -T transferslowly" +sleep 1 +$RNDCCMD 10.53.0.6 retransfer axfr-max-transfer-time 2>&1 | sed 's/^/ns6 /' | cat_i +tmp=0 +retry_quiet 10 wait_for_message "maximum transfer time exceeded: timed out" || tmp=1 +status=$((status+tmp)) + +nextpart ns6/named.run > /dev/null + +n=$((n+1)) +echo_i "test max-transfer-idle-in with 50 seconds timeout ($n)" +stop_server ns1 +copy_setports ns1/named3.conf.in ns1/named.conf +start_server --noclean --restart --port ${PORT} ns1 -- "-D xfer-ns1 $NS_PARAMS -T transferinsecs -T transferstuck" +sleep 1 +start=`date +%s` +$RNDCCMD 10.53.0.6 retransfer axfr-max-idle-time 2>&1 | sed 's/^/ns6 /' | cat_i +tmp=0 +retry_quiet 60 wait_for_message "maximum idle time exceeded: timed out" || tmp=1 +if [ $tmp -eq 0 ]; then + now=`date +%s` + diff=$((now - start)) + # we expect a timeout in 50 seconds + test $diff -lt 50 && tmp=1 + test $diff -ge 59 && tmp=1 + if test $tmp != 0 ; then echo_i "unexpected diff value: ${diff}"; fi +fi +status=$((status+tmp)) + echo_i "exit status: $status" [ $status -eq 0 ] || exit 1 diff --git a/doc/arm/reference.rst b/doc/arm/reference.rst index 43a347a798..bc10c6d33a 100644 --- a/doc/arm/reference.rst +++ b/doc/arm/reference.rst @@ -3377,6 +3377,12 @@ options apply to zone transfers. terminated. The default is 60 minutes (1 hour). The maximum value is 28 days (40320 minutes). + .. note:: The inbound zone transfers are also affected by + ``tcp-idle-timeout``, the ``max-transfer-idle-in`` will close the + inbound zone transfer if there was no complete AXFR or no complete + IXFR chunk. The ``tcp-idle-timeout`` will close the connection if + there's no progress on the TCP level. + .. namedconf:statement:: max-transfer-time-out :tags: transfer :short: Specifies the number of minutes after which outbound zone transfers are terminated. diff --git a/doc/notes/notes-current.rst b/doc/notes/notes-current.rst index 0d0ada857e..e404945b43 100644 --- a/doc/notes/notes-current.rst +++ b/doc/notes/notes-current.rst @@ -45,6 +45,12 @@ Bug Fixes libuv, treat it as a network failure, mark the server as broken and don't try again. :gl:`#4005` +- The :any:`max-transfer-time-in` and :any:`max-transfer-idle-in` options + were not implemented when the BIND 9 networking stack was refactored + in 9.16. The missing functionality has been re-implemented and + incoming zone transfers now time out properly when not progressing. + :gl:`#4004` + Known Issues ~~~~~~~~~~~~ diff --git a/lib/dns/include/dns/xfrin.h b/lib/dns/include/dns/xfrin.h index 24ed327de7..2d956a38b2 100644 --- a/lib/dns/include/dns/xfrin.h +++ b/lib/dns/include/dns/xfrin.h @@ -27,6 +27,7 @@ ***/ #include +#include #include #include diff --git a/lib/dns/xfrin.c b/lib/dns/xfrin.c index 063423b665..46e39bf34e 100644 --- a/lib/dns/xfrin.c +++ b/lib/dns/xfrin.c @@ -177,6 +177,9 @@ struct dns_xfrin { unsigned char *firstsoa_data; isc_tlsctx_cache_t *tlsctx_cache; + + isc_timer_t *max_time_timer; + isc_timer_t *max_idle_timer; }; #define XFRIN_MAGIC ISC_MAGIC('X', 'f', 'r', 'I') @@ -237,6 +240,10 @@ xfrin_recv_done(isc_result_t result, isc_region_t *region, void *arg); static void xfrin_destroy(dns_xfrin_t *xfr); +static void +xfrin_timedout(void *); +static void +xfrin_idledout(void *); static void xfrin_fail(dns_xfrin_t *xfr, isc_result_t result, const char *msg); static isc_result_t @@ -693,6 +700,7 @@ dns_xfrin_create(dns_zone_t *zone, dns_rdatatype_t xfrtype, REQUIRE(isc_sockaddr_getport(primaryaddr) != 0); REQUIRE(zone != NULL); REQUIRE(dns_zone_getview(zone) != NULL); + REQUIRE(dns_zone_gettid(zone) == isc_tid()); (void)dns_zone_getdb(zone, &db); @@ -734,9 +742,24 @@ dns_xfrin_create(dns_zone_t *zone, dns_rdatatype_t xfrtype, return (result); } +static void +xfrin_timedout(void *xfr) { + REQUIRE(VALID_XFRIN(xfr)); + + xfrin_fail(xfr, ISC_R_TIMEDOUT, "maximum transfer time exceeded"); +} + +static void +xfrin_idledout(void *xfr) { + REQUIRE(VALID_XFRIN(xfr)); + + xfrin_fail(xfr, ISC_R_TIMEDOUT, "maximum idle time exceeded"); +} + void dns_xfrin_shutdown(dns_xfrin_t *xfr) { REQUIRE(VALID_XFRIN(xfr)); + REQUIRE(dns_zone_gettid(xfr->zone) == isc_tid()); xfrin_fail(xfr, ISC_R_CANCELED, "shut down"); } @@ -787,6 +810,9 @@ xfrin_fail(dns_xfrin_t *xfr, isc_result_t result, const char *msg) { if (atomic_compare_exchange_strong(&xfr->shuttingdown, &(bool){ false }, true)) { + isc_timer_stop(xfr->max_time_timer); + isc_timer_stop(xfr->max_idle_timer); + if (result != DNS_R_UPTODATE && result != DNS_R_TOOMANYRECORDS) { xfrin_log(xfr, ISC_LOG_ERROR, "%s: %s", msg, @@ -826,13 +852,16 @@ xfrin_create(isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db, dns_xfrin_t *xfr = NULL; xfr = isc_mem_get(mctx, sizeof(*xfr)); - *xfr = (dns_xfrin_t){ .shutdown_result = ISC_R_UNSET, - .rdclass = rdclass, - .reqtype = reqtype, - .maxrecords = dns_zone_getmaxrecords(zone), - .primaryaddr = *primaryaddr, - .sourceaddr = *sourceaddr, - .firstsoa = DNS_RDATA_INIT }; + *xfr = (dns_xfrin_t){ + .shutdown_result = ISC_R_UNSET, + .rdclass = rdclass, + .reqtype = reqtype, + .maxrecords = dns_zone_getmaxrecords(zone), + .primaryaddr = *primaryaddr, + .sourceaddr = *sourceaddr, + .firstsoa = DNS_RDATA_INIT, + .magic = XFRIN_MAGIC, + }; isc_mem_attach(mctx, &xfr->mctx); dns_zone_iattach(zone, &xfr->zone); @@ -876,7 +905,10 @@ xfrin_create(isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db, isc_tlsctx_cache_attach(tlsctx_cache, &xfr->tlsctx_cache); - xfr->magic = XFRIN_MAGIC; + isc_timer_create(dns_zone_getloop(zone), xfrin_timedout, xfr, + &xfr->max_time_timer); + isc_timer_create(dns_zone_getloop(zone), xfrin_idledout, xfr, + &xfr->max_idle_timer); *xfrp = xfr; } @@ -884,6 +916,7 @@ xfrin_create(isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db, static isc_result_t xfrin_start(dns_xfrin_t *xfr) { isc_result_t result = ISC_R_FAILURE; + isc_interval_t interval; dns_xfrin_ref(xfr); @@ -910,6 +943,14 @@ xfrin_start(dns_xfrin_t *xfr) { &xfr->primaryaddr, &xfr->disp)); } + /* Set the maximum timer */ + isc_interval_set(&interval, dns_zone_getmaxxfrin(xfr->zone), 0); + isc_timer_start(xfr->max_time_timer, isc_timertype_once, &interval); + + /* Set the idle timer */ + isc_interval_set(&interval, dns_zone_getidlein(xfr->zone), 0); + isc_timer_start(xfr->max_idle_timer, isc_timertype_once, &interval); + /* * XXX: timeouts are hard-coded to 30 seconds; this needs to be * configurable. @@ -919,6 +960,7 @@ xfrin_start(dns_xfrin_t *xfr) { xfr->tlsctx_cache, xfrin_connect_done, xfrin_send_done, xfrin_recv_done, xfr, &xfr->id, &xfr->dispentry)); CHECK(dns_dispatch_connect(xfr->dispentry)); + return (ISC_R_SUCCESS); failure: @@ -1213,6 +1255,9 @@ xfrin_recv_done(isc_result_t result, isc_region_t *region, void *arg) { result = ISC_R_SHUTTINGDOWN; } + /* Stop the idle timer */ + isc_timer_stop(xfr->max_idle_timer); + CHECK(result); xfrin_log(xfr, ISC_LOG_DEBUG(7), "received %u bytes", region->length); @@ -1464,6 +1509,7 @@ xfrin_recv_done(isc_result_t result, isc_region_t *region, void *arg) { } atomic_store(&xfr->shuttingdown, true); + isc_timer_stop(xfr->max_time_timer); xfr->shutdown_result = ISC_R_SUCCESS; break; default: @@ -1472,6 +1518,11 @@ xfrin_recv_done(isc_result_t result, isc_region_t *region, void *arg) { */ dns_message_detach(&msg); dns_dispatch_getnext(xfr->dispentry); + + isc_interval_t interval; + isc_interval_set(&interval, dns_zone_getidlein(xfr->zone), 0); + isc_timer_start(xfr->max_idle_timer, isc_timertype_once, + &interval); return; } @@ -1491,6 +1542,7 @@ xfrin_destroy(dns_xfrin_t *xfr) { uint64_t msecs, persec; REQUIRE(VALID_XFRIN(xfr)); + REQUIRE(dns_zone_gettid(xfr->zone) == isc_tid()); /* Safe-guards */ REQUIRE(atomic_load(&xfr->shuttingdown)); @@ -1596,6 +1648,9 @@ xfrin_destroy(dns_xfrin_t *xfr) { isc_tlsctx_cache_detach(&xfr->tlsctx_cache); } + isc_timer_destroy(&xfr->max_idle_timer); + isc_timer_destroy(&xfr->max_time_timer); + isc_mem_putanddetach(&xfr->mctx, xfr, sizeof(*xfr)); } diff --git a/lib/ns/include/ns/server.h b/lib/ns/include/ns/server.h index 41e8fc0d03..8dc8b1cf3e 100644 --- a/lib/ns/include/ns/server.h +++ b/lib/ns/include/ns/server.h @@ -32,20 +32,23 @@ #include -#define NS_SERVER_LOGQUERIES 0x00000001U /*%< log queries */ -#define NS_SERVER_NOAA 0x00000002U /*%< -T noaa */ -#define NS_SERVER_NOSOA 0x00000004U /*%< -T nosoa */ -#define NS_SERVER_NONEAREST 0x00000008U /*%< -T nonearest */ -#define NS_SERVER_NOEDNS 0x00000020U /*%< -T noedns */ -#define NS_SERVER_DROPEDNS 0x00000040U /*%< -T dropedns */ -#define NS_SERVER_NOTCP 0x00000080U /*%< -T notcp */ -#define NS_SERVER_DISABLE4 0x00000100U /*%< -6 */ -#define NS_SERVER_DISABLE6 0x00000200U /*%< -4 */ -#define NS_SERVER_FIXEDLOCAL 0x00000400U /*%< -T fixedlocal */ -#define NS_SERVER_SIGVALINSECS 0x00000800U /*%< -T sigvalinsecs */ -#define NS_SERVER_EDNSFORMERR 0x00001000U /*%< -T ednsformerr (STD13) */ -#define NS_SERVER_EDNSNOTIMP 0x00002000U /*%< -T ednsnotimp */ -#define NS_SERVER_EDNSREFUSED 0x00004000U /*%< -T ednsrefused */ +#define NS_SERVER_LOGQUERIES 0x00000001U /*%< log queries */ +#define NS_SERVER_NOAA 0x00000002U /*%< -T noaa */ +#define NS_SERVER_NOSOA 0x00000004U /*%< -T nosoa */ +#define NS_SERVER_NONEAREST 0x00000008U /*%< -T nonearest */ +#define NS_SERVER_NOEDNS 0x00000020U /*%< -T noedns */ +#define NS_SERVER_DROPEDNS 0x00000040U /*%< -T dropedns */ +#define NS_SERVER_NOTCP 0x00000080U /*%< -T notcp */ +#define NS_SERVER_DISABLE4 0x00000100U /*%< -6 */ +#define NS_SERVER_DISABLE6 0x00000200U /*%< -4 */ +#define NS_SERVER_FIXEDLOCAL 0x00000400U /*%< -T fixedlocal */ +#define NS_SERVER_SIGVALINSECS 0x00000800U /*%< -T sigvalinsecs */ +#define NS_SERVER_EDNSFORMERR 0x00001000U /*%< -T ednsformerr (STD13) */ +#define NS_SERVER_EDNSNOTIMP 0x00002000U /*%< -T ednsnotimp */ +#define NS_SERVER_EDNSREFUSED 0x00004000U /*%< -T ednsrefused */ +#define NS_SERVER_TRANSFERINSECS 0x00008000U /*%< -T transferinsecs */ +#define NS_SERVER_TRANSFERSLOWLY 0x00010000U /*%< -T transferslowly */ +#define NS_SERVER_TRANSFERSTUCK 0x00020000U /*%< -T transferstuck */ /*% * Type for callback function to get hostname. diff --git a/lib/ns/xfrout.c b/lib/ns/xfrout.c index 041c6a109f..b782a29654 100644 --- a/lib/ns/xfrout.c +++ b/lib/ns/xfrout.c @@ -1534,6 +1534,22 @@ sendstream(xfrout_ctx_t *xfr) { xfrout_log(xfr, ISC_LOG_DEBUG(8), "sending TCP message of %d bytes", used.length); + /* System test helper options to simulate network issues. */ + if (ns_server_getoption(xfr->client->manager->sctx, + NS_SERVER_TRANSFERSLOWLY)) + { + /* Sleep for a bit over a second. */ + select(0, NULL, NULL, NULL, + &(struct timeval){ 1, 1000 }); + } + if (ns_server_getoption(xfr->client->manager->sctx, + NS_SERVER_TRANSFERSTUCK)) + { + /* Sleep for a bit over a minute. */ + select(0, NULL, NULL, NULL, + &(struct timeval){ 60, 1000 }); + } + isc_nmhandle_attach(xfr->client->handle, &xfr->client->sendhandle); if (xfr->idletime > 0) { @@ -1546,6 +1562,23 @@ sendstream(xfrout_ctx_t *xfr) { xfr->cbytes = used.length; } else { xfrout_log(xfr, ISC_LOG_DEBUG(8), "sending IXFR UDP response"); + + /* System test helper options to simulate network issues. */ + if (ns_server_getoption(xfr->client->manager->sctx, + NS_SERVER_TRANSFERSLOWLY)) + { + /* Sleep for a bit over a second. */ + select(0, NULL, NULL, NULL, + &(struct timeval){ 1, 1000 }); + } + if (ns_server_getoption(xfr->client->manager->sctx, + NS_SERVER_TRANSFERSTUCK)) + { + /* Sleep for a bit over a minute. */ + select(0, NULL, NULL, NULL, + &(struct timeval){ 60, 1000 }); + } + ns_client_send(xfr->client); xfr->stream->methods->pause(xfr->stream); isc_nmhandle_detach(&xfr->client->reqhandle);