Submitted By: Douglas R. Reno Date: 2021-03-24 Initial Package Version: 9.16.13 Origin: Upstream (PR #4819, #4832, #4811, and #4833) Upstream Status: Applied Description: Fixes several regressions in BIND 9.16.13. One of them, the TCP timeout regression, has been present since at least 9.16.11. This patch fixes those, but does introduce a couple of intermittent failures due to some queries sometimes taking a few milliseconds longer than expected. No regressions found during actual usage. diff -Naurp bind-9.16.13.orig/bin/named/server.c bind-9.16.13/bin/named/server.c --- bind-9.16.13.orig/bin/named/server.c 2021-03-11 07:20:59.000000000 -0600 +++ bind-9.16.13/bin/named/server.c 2021-03-24 18:58:13.105185509 -0500 @@ -166,7 +166,18 @@ #define EXCLBUFFERS 4096 #endif /* TUNE_LARGE */ -#define MAX_TCP_TIMEOUT 65535 +/* RFC7828 defines timeout at a 16-bit value specified in units of 100 + * milliseconds, so the maximum and minimum advertised and keepalive + * timeouts are capped by the data type (it's ~109 minutes). + */ +#define MIN_INITIAL_TIMEOUT UINT32_C(2500) /* 2.5 seconds */ +#define MAX_INITIAL_TIMEOUT UINT32_C(120000) /* 2 minutes */ +#define MIN_IDLE_TIMEOUT UINT32_C(100) /* 0.1 seconds */ +#define MAX_IDLE_TIMEOUT UINT32_C(120000) /* 2 minutes */ +#define MIN_KEEPALIVE_TIMEOUT UINT32_C(100) /* 0.1 seconds */ +#define MAX_KEEPALIVE_TIMEOUT UINT32_C(UINT16_MAX * 100) +#define MIN_ADVERTISED_TIMEOUT UINT32_C(0) /* No minimum */ +#define MAX_ADVERTISED_TIMEOUT UINT32_C(UINT16_MAX * 100) /*% * Check an operation for failure. Assumes that the function @@ -8315,7 +8326,7 @@ load_configuration(const char *filename, unsigned int maxsocks; uint32_t softquota = 0; uint32_t max; - unsigned int initial, idle, keepalive, advertised; + uint64_t initial, idle, keepalive, advertised; dns_aclenv_t *env = ns_interfacemgr_getaclenv(named_g_server->interfacemgr); @@ -8572,62 +8583,67 @@ load_configuration(const char *filename, obj = NULL; result = named_config_get(maps, "tcp-initial-timeout", &obj); INSIST(result == ISC_R_SUCCESS); - initial = cfg_obj_asuint32(obj); - if (initial > 1200) { + initial = cfg_obj_asuint32(obj) * 100; + if (initial > MAX_INITIAL_TIMEOUT) { cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING, "tcp-initial-timeout value is out of range: " - "lowering to 1200"); - initial = 1200; - } else if (initial < 25) { + "lowering to %" PRIu32, + MAX_INITIAL_TIMEOUT / 100); + initial = MAX_INITIAL_TIMEOUT; + } else if (initial < MAX_INITIAL_TIMEOUT) { cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING, "tcp-initial-timeout value is out of range: " - "raising to 25"); - initial = 25; + "raising to %" PRIu32, + MIN_INITIAL_TIMEOUT / 100); + initial = MIN_INITIAL_TIMEOUT; } obj = NULL; result = named_config_get(maps, "tcp-idle-timeout", &obj); INSIST(result == ISC_R_SUCCESS); - idle = cfg_obj_asuint32(obj); - if (idle > 1200) { + idle = cfg_obj_asuint32(obj) * 100; + if (idle > MAX_IDLE_TIMEOUT) { cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING, "tcp-idle-timeout value is out of range: " - "lowering to 1200"); - idle = 1200; - } else if (idle < 1) { + "lowering to %" PRIu32, + MAX_IDLE_TIMEOUT / 100); + idle = MAX_IDLE_TIMEOUT; + } else if (idle < MIN_IDLE_TIMEOUT) { cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING, "tcp-idle-timeout value is out of range: " - "raising to 1"); - idle = 1; + "raising to %" PRIu32, + MIN_IDLE_TIMEOUT / 100); + idle = MIN_IDLE_TIMEOUT; } obj = NULL; result = named_config_get(maps, "tcp-keepalive-timeout", &obj); INSIST(result == ISC_R_SUCCESS); - keepalive = cfg_obj_asuint32(obj); - if (keepalive > MAX_TCP_TIMEOUT) { + keepalive = cfg_obj_asuint32(obj) * 100; + if (keepalive > MAX_KEEPALIVE_TIMEOUT) { cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING, "tcp-keepalive-timeout value is out of range: " - "lowering to %u", - MAX_TCP_TIMEOUT); - keepalive = MAX_TCP_TIMEOUT; - } else if (keepalive < 1) { + "lowering to %", PRIu32, + MAX_KEEPALIVE_TIMEOUT / 100); + keepalive = MAX_KEEPALIVE_TIMEOUT; + } else if (keepalive < MIN_KEEPALIVE_TIMEOUT) { cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING, "tcp-keepalive-timeout value is out of range: " - "raising to 1"); - keepalive = 1; + "raising to %" PRIu32, + MIN_KEEPALIVE_TIMEOUT / 100); + keepalive = MIN_KEEPALIVE_TIMEOUT; } obj = NULL; result = named_config_get(maps, "tcp-advertised-timeout", &obj); INSIST(result == ISC_R_SUCCESS); - advertised = cfg_obj_asuint32(obj); - if (advertised > MAX_TCP_TIMEOUT) { + advertised = cfg_obj_asuint32(obj) * 100; + if (advertised > MAX_ADVERTISED_TIMEOUT) { cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING, "tcp-advertized-timeout value is out of range: " - "lowering to %u", - MAX_TCP_TIMEOUT); - advertised = MAX_TCP_TIMEOUT; + "lowering to %" PRIu32, + MAX_ADVERTISED_TIMEOUT / 100); + advertised = MAX_ADVERTISED_TIMEOUT; } isc_nm_settimeouts(named_g_nm, initial, idle, keepalive, advertised); @@ -14755,6 +14771,12 @@ named_server_dnssec(named_server_t *serv switch (result) { case ISC_R_SUCCESS: + /* + * Rekey after checkds command because the next key + * event may have changed. + */ + dns_zone_rekey(zone, false); + if (use_keyid) { char tagbuf[6]; snprintf(tagbuf, sizeof(tagbuf), "%u", keyid); @@ -14799,6 +14821,12 @@ named_server_dnssec(named_server_t *serv switch (result) { case ISC_R_SUCCESS: + /* + * Rekey after rollover command because the next key + * event may have changed. + */ + dns_zone_rekey(zone, false); + if (use_keyid) { char tagbuf[6]; snprintf(tagbuf, sizeof(tagbuf), "%u", keyid); @@ -15895,7 +15923,7 @@ isc_result_t named_server_tcptimeouts(isc_lex_t *lex, isc_buffer_t **text) { char *ptr; isc_result_t result = ISC_R_SUCCESS; - unsigned int initial, idle, keepalive, advertised; + uint32_t initial, idle, keepalive, advertised; char msg[128]; /* Skip the command name. */ @@ -15911,10 +15939,11 @@ named_server_tcptimeouts(isc_lex_t *lex, ptr = next_token(lex, NULL); if (ptr != NULL) { CHECK(isc_parse_uint32(&initial, ptr, 10)); - if (initial > 1200) { + initial *= 100; + if (initial > MAX_INITIAL_TIMEOUT) { CHECK(ISC_R_RANGE); } - if (initial < 25) { + if (initial < MIN_INITIAL_TIMEOUT) { CHECK(ISC_R_RANGE); } @@ -15923,10 +15952,11 @@ named_server_tcptimeouts(isc_lex_t *lex, return (ISC_R_UNEXPECTEDEND); } CHECK(isc_parse_uint32(&idle, ptr, 10)); - if (idle > 1200) { + idle *= 100; + if (idle > MAX_IDLE_TIMEOUT) { CHECK(ISC_R_RANGE); } - if (idle < 1) { + if (idle < MIN_IDLE_TIMEOUT) { CHECK(ISC_R_RANGE); } @@ -15935,10 +15965,11 @@ named_server_tcptimeouts(isc_lex_t *lex, return (ISC_R_UNEXPECTEDEND); } CHECK(isc_parse_uint32(&keepalive, ptr, 10)); - if (keepalive > MAX_TCP_TIMEOUT) { + keepalive *= 100; + if (keepalive > MAX_KEEPALIVE_TIMEOUT) { CHECK(ISC_R_RANGE); } - if (keepalive < 1) { + if (keepalive < MIN_KEEPALIVE_TIMEOUT) { CHECK(ISC_R_RANGE); } @@ -15947,7 +15978,8 @@ named_server_tcptimeouts(isc_lex_t *lex, return (ISC_R_UNEXPECTEDEND); } CHECK(isc_parse_uint32(&advertised, ptr, 10)); - if (advertised > MAX_TCP_TIMEOUT) { + advertised *= 100; + if (advertised > MAX_ADVERTISED_TIMEOUT) { CHECK(ISC_R_RANGE); } @@ -15960,13 +15992,13 @@ named_server_tcptimeouts(isc_lex_t *lex, isc_task_endexclusive(named_g_server->task); } - snprintf(msg, sizeof(msg), "tcp-initial-timeout=%u\n", initial); + snprintf(msg, sizeof(msg), "tcp-initial-timeout=%u\n", initial / 100); CHECK(putstr(text, msg)); - snprintf(msg, sizeof(msg), "tcp-idle-timeout=%u\n", idle); + snprintf(msg, sizeof(msg), "tcp-idle-timeout=%u\n", idle / 100); CHECK(putstr(text, msg)); - snprintf(msg, sizeof(msg), "tcp-keepalive-timeout=%u\n", keepalive); + snprintf(msg, sizeof(msg), "tcp-keepalive-timeout=%u\n", keepalive / 100); CHECK(putstr(text, msg)); - snprintf(msg, sizeof(msg), "tcp-advertised-timeout=%u", advertised); + snprintf(msg, sizeof(msg), "tcp-advertised-timeout=%u", advertised / 100); CHECK(putstr(text, msg)); cleanup: diff -Naurp bind-9.16.13.orig/bin/tests/system/checkzone/zones/good-cds-unsigned.db bind-9.16.13/bin/tests/system/checkzone/zones/good-cds-unsigned.db --- bind-9.16.13.orig/bin/tests/system/checkzone/zones/good-cds-unsigned.db 1969-12-31 18:00:00.000000000 -0600 +++ bind-9.16.13/bin/tests/system/checkzone/zones/good-cds-unsigned.db 2021-03-24 18:32:46.588860526 -0500 @@ -0,0 +1,4 @@ +example. 0 SOA . . 0 0 0 0 0 +example. 0 NS . +example. 0 CDS 0 0 0 00 +example. 0 CDNSKEY 0 3 0 AA== diff -Naurp bind-9.16.13.orig/bin/tests/system/conf.sh.common bind-9.16.13/bin/tests/system/conf.sh.common --- bind-9.16.13.orig/bin/tests/system/conf.sh.common 2021-03-11 07:20:59.000000000 -0600 +++ bind-9.16.13/bin/tests/system/conf.sh.common 2021-03-24 13:54:38.652733911 -0500 @@ -129,6 +129,7 @@ statistics \ statschannel \ stub \ synthfromdnssec \ +timeouts \ tcp \ tools \ tsig \ diff -Naurp bind-9.16.13.orig/bin/tests/system/kasp/ns3/template2.db.in bind-9.16.13/bin/tests/system/kasp/ns3/template2.db.in --- bind-9.16.13.orig/bin/tests/system/kasp/ns3/template2.db.in 2021-03-11 07:20:59.000000000 -0600 +++ bind-9.16.13/bin/tests/system/kasp/ns3/template2.db.in 2021-03-24 18:43:47.610400868 -0500 @@ -20,6 +20,6 @@ $TTL 300 ns3 A 10.53.0.3 a A 10.0.0.11 -b A 10.0.0.2 -c A 10.0.0.3 -d A 10.0.0.4 +b A 10.0.0.22 +c A 10.0.0.33 +d A 10.0.0.44 diff -Naurp bind-9.16.13.orig/bin/tests/system/kasp/tests.sh bind-9.16.13/bin/tests/system/kasp/tests.sh --- bind-9.16.13.orig/bin/tests/system/kasp/tests.sh 2021-03-11 07:20:59.000000000 -0600 +++ bind-9.16.13/bin/tests/system/kasp/tests.sh 2021-03-24 19:12:02.145796479 -0500 @@ -1227,25 +1227,6 @@ check_cdslog() { status=$((status+ret)) } -# -# Utility to call after 'rndc dnssec -checkds|-rollover'. -# -_loadkeys_on() { - _server=$1 - _dir=$2 - _zone=$3 - - nextpart $_dir/named.run > /dev/null - rndccmd $_server loadkeys $_zone in $_view > rndc.dnssec.loadkeys.out.$_zone.$n - - if [ "${DYNAMIC}" = "yes" ]; then - wait_for_log 20 "zone ${_zone}/IN: next key event" $_dir/named.run || return 1 - else - # inline-signing zone adds "(signed)" - wait_for_log 20 "zone ${_zone}/IN (signed): next key event" $_dir/named.run || return 1 - fi -} - # Tell named that the DS for the key in given zone has been seen in the # parent (this does not actually has to be true, we just issue the command # to make named believe it can continue with the rollover). @@ -1275,10 +1256,6 @@ rndc_checkds() { rndccmd $_server dnssec -checkds $_keycmd $_whencmd $_what $_zone in $_view > rndc.dnssec.checkds.out.$_zone.$n || log_error "rndc dnssec -checkds${_keycmd}${_whencmd} ${_what} zone ${_zone} failed" - if [ "$ret" -eq 0 ]; then - _loadkeys_on $_server $_dir $_zone || log_error "loadkeys zone ${_zone} failed ($n)" - fi - test "$ret" -eq 0 || echo_i "failed" status=$((status+ret)) } @@ -1303,8 +1280,6 @@ rndc_rollover() { rndccmd $_server dnssec -rollover -key $_keyid $_whencmd $_zone in $_view > rndc.dnssec.rollover.out.$_zone.$n || log_error "rndc dnssec -rollover (key ${_keyid} when ${_when}) zone ${_zone} failed" - _loadkeys_on $_server $_dir $_zone || log_error "loadkeys zone ${_zone} failed ($n)" - test "$ret" -eq 0 || echo_i "failed" status=$((status+ret)) } @@ -1358,22 +1333,29 @@ cp "${DIR}/template2.db.in" "${DIR}/${ZO rndccmd 10.53.0.3 reload "$ZONE" > /dev/null || log_error "rndc reload zone ${ZONE} failed" update_is_signed() { - dig_with_opts "a.${ZONE}" "@${SERVER}" A > "dig.out.$DIR.test$n.a" || return 1 - grep "status: NOERROR" "dig.out.$DIR.test$n.a" > /dev/null || return 1 - grep "a.${ZONE}\..*${DEFAULT_TTL}.*IN.*A.*10\.0\.0\.11" "dig.out.$DIR.test$n.a" > /dev/null || return 1 - lines=$(get_keys_which_signed A "dig.out.$DIR.test$n.a" | wc -l) - test "$lines" -eq 1 || return 1 - get_keys_which_signed A "dig.out.$DIR.test$n.a" | grep "^${KEY_ID}$" > /dev/null || return 1 + ip_a = $1 + ip_d = $2 - dig_with_opts "d.${ZONE}" "@${SERVER}" A > "dig.out.$DIR.test$n".d || return 1 - grep "status: NOERROR" "dig.out.$DIR.test$n".d > /dev/null || return 1 - grep "d.${ZONE}\..*${DEFAULT_TTL}.*IN.*A.*10\.0\.0\.4" "dig.out.$DIR.test$n".d > /dev/null || return 1 - lines=$(get_keys_which_signed A "dig.out.$DIR.test$n".d | wc -l) - test "$lines" -eq 1 || return 1 - get_keys_which_signed A "dig.out.$DIR.test$n".d | grep "^${KEY_ID}$" > /dev/null || return 1 + if [ "$ip_a" != "-" ]; then + dig_with_opts "a.${ZONE}" "@${SERVER}" A > "dig.out.$DIR.test$n.a" || return 1 + grep "status: NOERROR" "dig.out.$DIR.test$n.a" > /dev/null || return 1 + grep "a.${ZONE}\..*${DEFAULT_TTL}.*IN.*A.*${ip_a}" "dig.out.$DIR.test$n.a" > /dev/null | return 1 + lines=$(get_keys_which_signed A "dig.out.$DIR.test$n.a" | wc -l) + test "$lines" -eq 1 || return 1 + get_keys_which_signed A "dig.out.$DIR.test$n.a" | grep "^${KEY_ID}$" > /dev/null || return 1 + fi + + if [ "$ip_d" != "-" ]; then + dig_with_opts "d.${ZONE}" "@${SERVER}" A > "dig.out.$DIR.test$n.d" || return 1 + grep "status: NOERROR" "dig.out.$DIR.test$n".d > /dev/null || return 1 + grep "d.${ZONE}\..*${DEFAULT_TTL}.*IN.*A.*${ip_d}" "dig.out.$DIR.test$n".d > /dev/null || return 1 + lines=$(get_keys_which_signed A "dig.out.$DIR.test$n".d | wc -l) + test "$lines" -eq 1 || return 1 + get_keys_which_signed A "dig.out.$DIR.test$n".d | grep "^${KEY_ID}$" > /dev/null || return 1 + fi } -retry_quiet 10 update_is_signed || ret=1 +retry_quiet 10 update_is_signed "10.0.0.11" "10.0.0.44" || ret=1 test "$ret" -eq 0 || echo_i "failed" status=$((status+ret)) @@ -1401,12 +1383,42 @@ ret=0 echo zone ${ZONE} echo server 10.53.0.3 "$PORT" echo update del "a.${ZONE}" 300 A 10.0.0.1 -echo update add "a.${ZONE}" 300 A 10.0.0.11 +echo update add "a.${ZONE}" 300 A 10.0.0.101 echo update add "d.${ZONE}" 300 A 10.0.0.4 echo send ) | $NSUPDATE -retry_quiet 10 update_is_signed || ret=1 +retry_quiet 10 update_is_signed "10.0.0.101" "10.0.0.4" || ret=1 +test "$ret" -wq 0 || echo_i "failed" +status=$((status+ret)) + +# Update zone with nsupdate (reverting the above change) +n=$((n+1)) +echo_i "nsupdate zone and check that new record is signed for ${ZONE} ($n)" +ret=0 +( +echo zone ${ZONE} +echo server 10.53.0.3 "$PORT" +echo update add "a.${ZONE}" 300 A 10.0.0.1 +echo update del "a.${ZONE}" 300 A 10.0.0.101 +echo update del "d.${ZONE}" 300 A 10.0.0.4 +echo send +) | $NSUPDATE + +retry_quiet 10 update_is_signed "10.0.0.1" "-" || ret=1 +test "$ret" -eq 0 || echo_i "failed" +status=$((status+ret)) + +# Update zone with freeze/thaw +n=$((n+1)) +echo_i "modify zone file and check that new record is signed for zone ${ZONE} ($n)" +ret=0 +rndccmd 10.53.0.3 freeze "$ZONE" > /dev/null || log_error "rndc freeze zone ${ZONE} failed" +sleep 1 +echo "d.${ZONE}. 300 A 10.0.0.44" >> "${DIR}/${ZONE}.db" +rndccmd 10.53.0.3 thaw "$ZONE" > /dev/null || log_error "rndc thaw zone ${ZONE} failed" + +retry_quiet 10 update_is_signed "10.0.0.1" "10.0.0.44" || ret=1 test "$ret" -eq 0 || echo_i "failed" status=$((status+ret)) @@ -1495,17 +1507,24 @@ dnssec_verify basefile=$(key_get KEY1 BASEFILE) +_wait_for_metadata() { + _expr = $1 + _file = $2 + grep "$_expr" $_file > /dev/null || return 1 + return 0 +} + n=$((n+1)) echo_i "checkds publish correctly sets DSPublish for zone $ZONE ($n)" rndc_checkds "$SERVER" "$DIR" "-" "20190102121314" "published" "$ZONE" -grep "DSPublish: 20190102121314" "${basefile}.state" > /dev/null || log_error "DSPublish not set in ${basefile}" +retry_quiet 3 _wait_for_metadata "DSPublish: 20190102121314" "${basefile}.state" || log_error "bad DSPublish in ${basefile}.state" test "$ret" -eq 0 || echo_i "failed" status=$((status+ret)) n=$((n+1)) echo_i "checkds withdraw correctly sets DSRemoved for zone $ZONE ($n)" rndc_checkds "$SERVER" "$DIR" "-" "20200102121314" "withdrawn" "$ZONE" -grep "DSRemoved: 20200102121314" "${basefile}.state" > /dev/null || log_error "DSRemoved not set in ${basefile}" +retry_quiet 3 _wait_for_metadata "DSRemoved: 20200102121314" "${basefile}.state" || log_error "bad DSRemoved in ${basefile}.state" test "$ret" -eq 0 || echo_i "failed" status=$((status+ret)) @@ -1573,8 +1592,8 @@ status=$((status+ret)) n=$((n+1)) echo_i "checkds withdrawn does not set DSRemoved for zone $ZONE (multiple KSK) ($n)" rndc_checkds "$SERVER" "$DIR" "-" "20190102121314" "withdrawn" "$ZONE" -grep "DSRemoved:" "${basefile1}.state" > /dev/null && log_error "DSPublish incorrectly set in ${basefile1}" -grep "DSRemoved:" "${basefile2}.state" > /dev/null && log_error "DSPublish incorrectly set in ${basefile2}" +grep "DSRemoved:" "${basefile1}.state" > /dev/null && log_error "DSRemoved incorrectly set in ${basefile1}" +grep "DSRemoved:" "${basefile2}.state" > /dev/null && log_error "DSRemoved incorrectly set in ${basefile2}" test "$ret" -eq 0 || echo_i "failed" status=$((status+ret)) @@ -1597,7 +1616,7 @@ status=$((status+ret)) n=$((n+1)) echo_i "checkds published -key correctly sets DSPublish for key $(key_get KEY1 ID) zone $ZONE (multiple KSK) ($n)" rndc_checkds "$SERVER" "$DIR" KEY1 "20190102121314" "published" "$ZONE" -grep "DSPublish: 20190102121314" "${basefile1}.state" > /dev/null || log_error "DSPublish not set in ${basefile1}" +retry_quiet 3 _wait_for_metadata "DSPublish: 20190102121314" "${basefile1}.state" || log_error "bad DSPublish in ${basefile1}.state" grep "DSPublish:" "${basefile2}.state" > /dev/null && log_error "DSPublish incorrectly set in ${basefile2}" test "$ret" -eq 0 || echo_i "failed" status=$((status+ret)) @@ -1605,8 +1624,8 @@ status=$((status+ret)) n=$((n+1)) echo_i "checkds withdrawn -key correctly sets DSRemoved for key $(key_get KEY2 ID) zone $ZONE (multiple KSK) ($n)" rndc_checkds "$SERVER" "$DIR" KEY2 "20200102121314" "withdrawn" "$ZONE" -grep "DSRemoved: 20200102121314" "${basefile2}.state" > /dev/null || log_error "DSRemoved not set in ${basefile2}" grep "DSRemoved:" "${basefile1}.state" > /dev/null && log_error "DSPublish incorrectly set in ${basefile1}" +retry_quiet 3 _wait_for_metadata "DSRemoved: 20200102121314" "${basefile2}.state" || log_error "bad DSRemoved in ${basefile2}.state" test "$ret" -eq 0 || echo_i "failed" status=$((status+ret)) @@ -1645,14 +1664,14 @@ basefile=$(key_get KEY1 BASEFILE) n=$((n+1)) echo_i "checkds publish correctly sets DSPublish for zone $ZONE ($n)" rndc_checkds "$SERVER" "$DIR" "-" "20190102121314" "published" "$ZONE" -grep "DSPublish: 20190102121314" "${basefile}.state" > /dev/null || log_error "DSPublish not set in ${basefile}" +retry_quiet 3 _wait_for_metadata "DSPublish: 20190102121314" "${basefile}.state" || log_error "bad DSPublish in ${basefile}.state" test "$ret" -eq 0 || echo_i "failed" status=$((status+ret)) n=$((n+1)) echo_i "checkds withdraw correctly sets DSRemoved for zone $ZONE ($n)" rndc_checkds "$SERVER" "$DIR" "-" "20200102121314" "withdrawn" "$ZONE" -grep "DSRemoved: 20200102121314" "${basefile}.state" > /dev/null || log_error "DSRemoved not set in ${basefile}" +retry_quiet 3 _wait_for_metadata "DSRemoved: 20200102121314" "${basefile}.state" || log_error "bad DSRemoved in ${basefile}.state" test "$ret" -eq 0 || echo_i "failed" status=$((status+ret)) @@ -3045,13 +3064,10 @@ check_apex check_subdomain dnssec_verify -check_next_key_event() { +_check_next_key_event() { _expect=$1 - n=$((n+1)) - echo_i "check next key event for zone ${ZONE} ($n)" - ret=0 - grep "zone ${ZONE}.*: next key event in .* seconds" "${DIR}/named.run" > "keyevent.out.$ZONE.test$n" || log_error "no next key event for zone ${ZONE}" + grep "zone ${ZONE}.*: next key event in .* seconds" "${DIR}/named.run" > "keyevent.out.$ZONE.test$n" || return 1 # Get the latest next key event. if [ "${DYNAMIC}" = "yes" ]; then @@ -3066,11 +3082,21 @@ check_next_key_event() { _expectmin=$((_expect-next_key_event_threshold)) _expectmax=$((_expect+next_key_event_threshold)) - test $_expectmin -le "$_time" || log_error "bad next key event time ${_time} for zone ${ZONE} (expect ${_expect})" - test $_expectmax -ge "$_time" || log_error "bad next key event time ${_time} for zone ${ZONE} (expect ${_expect})" + test $_expectmin -le "$_time" || return 1 + test $_expectmax -ge "$_time" || return 1 + + return 0 +} + +check_next_key_event() { + n=$((n+1)) + echo_i "check next key event for zone ${ZONE} ($n)" + ret=0 + retry_quiet 3 _check_next_key_event $1 || log_error "bad next key event time for zone ${ZONE} (expect ${_expect})" test "$ret" -eq 0 || echo_i "failed" status=$((status+ret)) + } # Next key event is when the DNSKEY RRset becomes OMNIPRESENT: DNSKEY TTL plus @@ -4825,8 +4851,6 @@ check_next_key_event 93600 set_zone "step2.going-insecure.kasp" set_policy "none" "2" "7200" set_server "ns6" "10.53.0.6" -# Expect a CDS/CDNSKEY Delete Record. -set_cdsdelete # The DS is long enough removed from the zone to be considered HIDDEN. # This means the DNSKEY and the KSK signatures can be removed. @@ -4895,8 +4919,6 @@ set_zone "step2.going-insecure-dynamic.k set_dynamic set_policy "none" "2" "7200" set_server "ns6" "10.53.0.6" -# Expect a CDS/CDNSKEY Delete Record. -set_cdsdelete # The DS is long enough removed from the zone to be considered HIDDEN. # This means the DNSKEY and the KSK signatures can be removed. diff -Naurp bind-9.16.13.orig/bin/tests/system/timeouts/clean.sh bind-9.16.13/bin/tests/system/timeouts/clean.sh --- bind-9.16.13.orig/bin/tests/system/timeouts/clean.sh 1969-12-31 18:00:00.000000000 -0600 +++ bind-9.16.13/bin/tests/system/timeouts/clean.sh 2021-03-24 13:28:05.657322239 -0500 @@ -0,0 +1,19 @@ +#!/bin/sh +# +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# 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. + +rm -f ./ns*/managed-keys.bind* +rm -f ./ns*/named.conf +rm -f ./ns*/named.lock +rm -f ./ns*/named.memstats +rm -f ./ns*/named.run* +rm -f ./ns*/named.stats +rm -f ./.cache ./__pycache__ +rm -f ./ns*/large.db diff -Naurp bind-9.16.13.orig/bin/tests/system/timeouts/conftest.py bind-9.16.13/bin/tests/system/timeouts/conftest.py --- bind-9.16.13.orig/bin/tests/system/timeouts/conftest.py 1969-12-31 18:00:00.000000000 -0600 +++ bind-9.16.13/bin/tests/system/timeouts/conftest.py 2021-03-24 13:33:42.084634206 -0500 @@ -0,0 +1,56 @@ +############################################################################### +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# 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. +############################################################################### + +import os +import pytest + +def pytest_configure(config): + config.addinivalue_line( + "markers", "dnspython: mark tests that need dnspython to function" + ) + config.addinivalue_line( + "markers", "dnspython2: mark tests that need dnspython >= 2.0.0" + ) + +def pytest_collection_modifyitems(config, items): + # pylint: disable=unused-argument,unused-import,too-many-branches + # pylint: disable=import-outside-toplevel + + # Test for dnspython module + skip_dnspython = pytest.mark.skip( + reason="needs dnspython module to run") + try: + import dns.query # noqa: F401 + except ModuleNotFoundError: + for item in items: + if "dnspython" in item.keywords: + item.add_marker(skip_dnspython) + + # Test for dnspython >= 2.0.0 module + skip_dnspython2 = pytest.mark.skip( + reason="needs dnspython >= 2.0.0 module to run") + try: + from dns.query import send_tcp # noqa: F401 + except ImportError: + for item in items: + if "dnspython2" in item.keywords: + item.add_marker(skip_dnspython2) + +@pytest.fixture +def port(request): + # pylint: disable=unused-argument + env_port = os.getenv("PORT") + if port is None: + env_port = 5300 + else: + env_port = int(env_port) + + return env_port diff -Naurp bind-9.16.13.orig/bin/tests/system/timeouts/ns1/example.db bind-9.16.13/bin/tests/system/timeouts/ns1/example.db --- bind-9.16.13.orig/bin/tests/system/timeouts/ns1/example.db 1969-12-31 18:00:00.000000000 -0600 +++ bind-9.16.13/bin/tests/system/timeouts/ns1/example.db 2021-03-24 13:17:29.265376523 -0500 @@ -0,0 +1,23 @@ +; Copyright (C) Internet Systems Consortium, Inc. ("ISC") +; +; 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 http://mozilla.org/MPL/2.0/. +; +; See the COPYRIGHT file distributed with this work for additional +; information regarding copyright ownership. + +$TTL 300 ; 5 minutes +@ SOA mname1. . ( + 2000062101 ; serial + 20 ; refresh (20 seconds) + 20 ; retry (20 seconds) + 1814400 ; expire (3 weeks) + 3600 ; minimum (1 hour) + ) + NS ns1 +ns1 A 10.53.0.1 +@ A 10.53.0.1 +a A 10.53.0.1 +b A 10.53.0.1 +$INCLUDE large.db diff -Naurp bind-9.16.13.orig/bin/tests/system/timeouts/ns1/named.conf.in bind-9.16.13/bin/tests/system/timeouts/ns1/named.conf.in --- bind-9.16.13.orig/bin/tests/system/timeouts/ns1/named.conf.in 1969-12-31 18:00:00.000000000 -0600 +++ bind-9.16.13/bin/tests/system/timeouts/ns1/named.conf.in 2021-03-24 13:22:19.190784057 -0500 @@ -0,0 +1,41 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * 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/rncd.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 no; + tcp-initial-timeout 20; + tcp-idle-timeout 50; +}; + +zone "." { + type primary; + file "root.db"; +}; + +zone "example." { + type primary; + file "example.db"; + check-integrity no; +}; diff -Naurp bind-9.16.13.orig/bin/tests/system/timeouts/ns1/root.db bind-9.16.13/bin/tests/system/timeouts/ns1/root.db --- bind-9.16.13.orig/bin/tests/system/timeouts/ns1/root.db 1969-12-31 18:00:00.000000000 -0600 +++ bind-9.16.13/bin/tests/system/timeouts/ns1/root.db 2021-03-24 13:26:22.050100676 -0500 @@ -0,0 +1,22 @@ +; Copyright (C) Internet Systems Consortium, Inc. ("ISC") +; +; 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 http://mozilla.org/MPL/2.0/. +; +; See the COPYRIGHT file distributed with this work for additional +; information regarding copyright ownership. + +$TTL 300 +. IN SOA gson.isc.org. a.root.servers.nil. ( + 2000042100 ; serial + 600 ; refresh + 600 ; retry + 1200 ; expire + 600 ; minimum + ) +. NS a.root-servers.nil. +a.root-servers.nil. A 10.53.0.1 + +example. NS ns1.example. +ns1.example. A 10.53.0.1 diff -Naurp bind-9.16.13.orig/bin/tests/system/timeouts/prereq.sh bind-9.16.13/bin/tests/system/timeouts/prereq.sh --- bind-9.16.13.orig/bin/tests/system/timeouts/prereq.sh 1969-12-31 18:00:00.000000000 -0600 +++ bind-9.16.13/bin/tests/system/timeouts/prereq.sh 2021-03-24 13:36:29.588234047 -0500 @@ -0,0 +1,29 @@ +#!/bin/sh +# +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# 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. + +SYSTEMTESTTOP=.. +. $SYSTEMTESTTOP/conf.sh + +if test -n "$PYTHON" +then + if $PYTHON -c "from dns.query import send_tcp" 2> /dev/null + then + : + else + echo_i "This test requres the dnspython >= 2.0.0 module." >&2 + exit 1 + fi +else + echo_i "This test requires Python and the dnspython module." >&2 + exit 1 +fi + +exit 0 diff -Naurp bind-9.16.13.orig/bin/tests/system/timeouts/setup.sh bind-9.16.13/bin/tests/system/timeouts/setup.sh --- bind-9.16.13.orig/bin/tests/system/timeouts/setup.sh 1969-12-31 18:00:00.000000000 -0600 +++ bind-9.16.13/bin/tests/system/timeouts/setup.sh 2021-03-24 13:39:28.608708842 -0500 @@ -0,0 +1,23 @@ +#!/bin/sh +# +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# 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. + +. ../conf.sh + +copy_setports ns1/named.conf.in ns1/named.conf + +# +# Generate a large enough zone, so that the transfer takes longer than the +# tcp-initial-timeout interval. +# +$PYTHON -c " +for a in range(150000): + print('%s IN NS a' & (a)) + print('%s IN NS b' % (a))" > ns1/large.db diff -Naurp bind-9.16.13.orig/bin/tests/system/timeouts/tests-tcp.py bind-9.16.13/bin/tests/system/timeouts/tests-tcp.py --- bind-9.16.13.orig/bin/tests/system/timeouts/tests-tcp.py 1969-12-31 18:00:00.000000000 -0600 +++ bind-9.16.13/bin/tests/system/timeouts/tests-tcp.py 2021-03-24 13:54:23.057872113 -0500 @@ -0,0 +1,142 @@ +#!/usr/bin/python3 +############################################################################### +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# 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. +############################################################################### + +# pylint: disable=unused-variable + +import socket +import time + +import pytest + +TIMEOUT = 10 + +def create_msg(qname, qtype): + import dns.message + msg = dns.message.make_query(qname, qtype, want_dnssec=True, + use_edns=0, payload=4096) + + return msg + +def timeout(): + return time.time() + TIMEOUT + +@pytest.mark.dnspython +@pytest.mark.dnspython2 +def test_initial_timeout(port): + # The initial timeout is 2.5 seconds, so this should timeout. + import dns.query + + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: + sock.connect(("10.53.0.1", port)) + + time.sleep(3) + + msg = create_msg("example.", "A") + + with pytest.raises(EOFError): + try: + (sbytes, stime) = dns.query.send_tcp(sock, msg, timeout()) + (response, rtime) = dns.query.receive_tcp(sock, timeout()) + except ConnectionResetError as e: + raise EOFError from e + +@pytest.mark.dnspython +@pytest.mark.dnspython2 +def test_idle_timeout(port): + # The idle timeout is 5 seconds, so sending the second message must fail + import dns.rcode + + msg = create_msg("example.", "A") + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: + sock.connect(("10.53.0.1", port)) + + time.sleep(1) + + (sbytes, stime) = dns.query.send_tcp(sock, msg, timeout()) + (response, rtime) = dns.query.receive_tcp(sock, timeout()) + + time.sleep(3) + + (sbytes, stime) = dns.query.send_tcp(sock, msg, timeout()) + (response, rtime) = dns.query.receive_tcp(sock, timeout()) + + time.sleep(6) + + with pytest.raises(EOFError): + try: + (sbytes, stime) = dns.query.send_tcp(sock, msg, timeout()) + (response, rtime) = dns.query.receive_tcp(sock, timeout()) + except ConnectionResetError as e: + raise EOFError from e + +@pytest.mark.dnspython +@pytest.mark.dnspython2 +def test_pipelining_timeout(port): + # The pipelining should only timeout after the last message is received + import dns.query + + msg = create_msg("example.", "A") + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: + sock.connect(("10.53.0.1", port)) + + time.sleep(1) + + # Send and receive 25 DNS queries + for n in range(25): + (sbytes, stime) = dns.query.send_tcp(sock, msg, timeout()) + for n in range(25): + (response, rtime) = dns.query.receive_tcp(sock, timeout()) + + time.sleep(3) + + # Send and receieve 25 more + for n in range(25): + (sbytes, stime) = dns.query.send_tcp(sock, msg, timeout()) + for n in range(25): + (response, rtime) = dns.query.receive_tcp(sock, timeout()) + + time.sleep(6) + + with pytest.raises(EOFError): + try: + (sbytes, stime) = dns.query.send_tcp(sock, msg, timeout()) + (response, rtime) = dns.query.receive_tcp(sock, timeout()) + except ConnectionResetError as e: + raise EOFError from e + +@pytest.mark.dnspython +@pytest.mark.dnspython2 +def test_long_axfr(port): + # The timers should not fire during AXFR, thus the connection should not close abruptly. + import dns.query + import dns.rdataclass + import dns.rdatatype + + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: + sock.connect(("10.53.0.1", port)) + + name = dns.name.from_text("example.") + msg = create_msg("example.", "AXFR") + (sbytes, stime) = dns.query.send_tcp(sock, msg, timeout()) + + # Receive the initial DNS message with SOA + (respose, rtime) = dns.query.receive_tcp(sock, timeout(), one_rr_per_rrset=True) + soa = response.get_rrset(dns.message.ANSWER, name, dns.rdataclass.IN, dns.rdatatype.SOA) + assert soa is not None + + # Pull DNS messages from the wire until the second SOA is received + while True: + (response, rtime) = dns.query.receive_tcp(sock, timeout(), one_rr_per_rrset=True) + soa = response.get_rrset(dns.message.ANSWER, name, dns.rdataclass.IN, dns.rdatatype.SOA) + if soa is not None: + break + assert soa is not None diff -Naurp bind-9.16.13.orig/lib/dns/zone.c bind-9.16.13/lib/dns/zone.c --- bind-9.16.13.orig/lib/dns/zone.c 2021-03-11 07:20:59.000000000 -0600 +++ bind-9.16.13/lib/dns/zone.c 2021-03-24 19:22:32.093569642 -0500 @@ -1806,11 +1806,6 @@ dns_zone_isdynamic(dns_zone_t *zone, boo return (true); } - /* Kasp zones are always dynamic. */ - if (dns_zone_use_kasp(zone)) { - return (true); - } - /* If !ignore_freeze, we need check whether updates are disabled. */ if (zone->type == dns_zone_master && (!zone->update_disabled || ignore_freeze) && @@ -2059,8 +2054,8 @@ zone_load(dns_zone_t *zone, unsigned int is_dynamic = dns_zone_isdynamic(zone, false); if (zone->db != NULL && is_dynamic) { /* - * This is a slave, stub, dynamically updated, or kasp enabled - * zone being reloaded. Do nothing - the database we already + * This is a slave, stub, or dynamically updated zone being + * reloaded. Do nothing - the database we already * have is guaranteed to be up-to-date. */ if (zone->type == dns_zone_master && !hasraw) { @@ -2372,6 +2367,16 @@ dns_zone_loadandthaw(dns_zone_t *zone) { if (inline_raw(zone)) { result = zone_load(zone->secure, DNS_ZONELOADFLAG_THAW, false); } else { + /* + * When thawing a zone, we don't know what changes + * have been made. If we do DNSSEC maintenance on this + * zone, schedule a full sign for this zone. + */ + if (zone->type == dns_zone_master && + DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_MAINTAIN)) + { + DNS_ZONEKEY_SETOPTION(zone, DNS_ZONEKEY_FULLSIGN); + } result = zone_load(zone, DNS_ZONELOADFLAG_THAW, false); } @@ -19942,7 +19947,12 @@ zone_rekey(dns_zone_t *zone) { } if (result == ISC_R_SUCCESS) { - bool insecure = dns_zone_secure_to_insecure(zone, false); + /* + * Publish CDS/CDNSKEY DELETE records if the zone is + * transitioning from secure to insecure. + */ + bool cds_delete = dns_zone_secure_to_insecure(zone, false); + isc_stdtime_t when; /* * Only update DNSKEY TTL if we have a policy. @@ -19979,9 +19989,37 @@ zone_rekey(dns_zone_t *zone) { goto failure; } + if (cds_delete) { + /* + * Only publish CDS/CDNSKEY DELETE records if there is + * a KSK that can be used to verify the RRset. This + * means there must be a key with the KSK role that is + * published and is used for signing. + */ + cds_delete = false; + for (key = ISC_LIST_HEAD(dnskeys); key != NULL; + key = ISC_LIST_NEXT(key, link)) { + dst_key_t *dstk = key->key; + bool ksk = false; + (void)dst_key_getbool(dstk, DST_BOOL_KSK, &ksk); + if (!ksk) { + continue; + } + + if (dst_key_haskasp(dstk) && + dst_key_is_published(dstk, now, &when) && + dst_key_is_signing(dstk, DST_BOOL_KSK, now, + &when)) + { + cds_delete = true; + break; + } + } + } + result = dns_dnssec_syncdelete(&cdsset, &cdnskeyset, &zone->origin, zone->rdclass, - ttl, &diff, mctx, insecure); + ttl, &diff, mctx, cds_delete); if (result != ISC_R_SUCCESS) { dnssec_log(zone, ISC_LOG_ERROR, "zone_rekey:couldn't update CDS/CDNSKEY " @@ -20343,6 +20381,7 @@ dns_zone_cdscheck(dns_zone_t *zone, dns_ unsigned char buffer[DNS_DS_BUFFERSIZE]; unsigned char algorithms[256]; unsigned int i; + bool empty = false; enum { notexpected = 0, expected = 1, found = 2 }; @@ -20378,14 +20417,8 @@ dns_zone_cdscheck(dns_zone_t *zone, dns_ result = dns_db_findrdataset(db, node, version, dns_rdatatype_dnskey, dns_rdatatype_none, 0, &dnskey, NULL); if (result == ISC_R_NOTFOUND) { - if (dns_rdataset_isassociated(&cds)) { - result = DNS_R_BADCDS; - } else { - result = DNS_R_BADCDNSKEY; - } - goto failure; - } - if (result != ISC_R_SUCCESS) { + empty = true; + } else if (result != ISC_R_SUCCESS) { goto failure; } @@ -20415,6 +20448,11 @@ dns_zone_cdscheck(dns_zone_t *zone, dns_ delete = true; continue; } + if (empty) { + result = DNS_R_BADCDS; + goto failure; + } + CHECK(dns_rdata_tostruct(&crdata, &structcds, NULL)); if (algorithms[structcds.algorithm] == 0) { algorithms[structcds.algorithm] = expected; @@ -20482,6 +20520,12 @@ dns_zone_cdscheck(dns_zone_t *zone, dns_ delete = true; continue; } + + if (empty) { + result = DNS_R_BADCDNSKEY; + goto failure; + } + CHECK(dns_rdata_tostruct(&crdata, &structcdnskey, NULL)); if (algorithms[structcdnskey.algorithm] == 0) { diff -Naurp bind-9.16.13.orig/lib/isc/include/isc/netmgr.h bind-9.16.13/lib/isc/include/isc/netmgr.h --- bind-9.16.13.orig/lib/isc/include/isc/netmgr.h 2021-03-11 07:20:59.000000000 -0600 +++ bind-9.16.13/lib/isc/include/isc/netmgr.h 2021-03-24 13:56:31.852673248 -0500 @@ -162,9 +162,11 @@ isc_nmhandle_setdata(isc_nmhandle_t *han void isc_nmhandle_settimeout(isc_nmhandle_t *handle, uint32_t timeout); +void +isc_nmhandle_cleartimeout(isc_nmhandle_t *handle); /*%< - * Set the read/recv timeout for the socket connected to 'handle' - * to 'timeout', and reset the timer. + * Set/clear the read/recv timeout for the socket connected to 'handle' + * to 'timeout' (in milliseconds), and reset the timer. * * When this is called on a 'wrapper' socket handle (for example, * a TCPDNS socket wrapping a TCP connection), the timer is set for @@ -431,10 +433,10 @@ void isc_nm_settimeouts(isc_nm_t *mgr, uint32_t init, uint32_t idle, uint32_t keepalive, uint32_t advertised); /*%< - * Sets the initial, idle, and keepalive timeout values to use for - * TCP connections, and the timeout value to advertise in responses using + * Sets the initial, idle, and keepalive timeout values (in milliseconds) to use + * for TCP connections, and the timeout value to advertise in responses using * the EDNS TCP Keepalive option (which should ordinarily be the same - * as 'keepalive'), in tenths of seconds. + * as 'keepalive'). * * Requires: * \li 'mgr' is a valid netmgr. @@ -445,7 +447,7 @@ isc_nm_gettimeouts(isc_nm_t *mgr, uint32 uint32_t *keepalive, uint32_t *advertised); /*%< * Gets the initial, idle, keepalive, or advertised timeout values, - * in tenths of seconds. + * in milliseconds. * * Any integer pointer parameter not set to NULL will be updated to * contain the corresponding timeout value. diff -Naurp bind-9.16.13.orig/lib/isc/netmgr/netmgr.c bind-9.16.13/lib/isc/netmgr/netmgr.c --- bind-9.16.13.orig/lib/isc/netmgr/netmgr.c 2021-03-11 07:20:59.000000000 -0600 +++ bind-9.16.13/lib/isc/netmgr/netmgr.c 2021-03-24 19:17:56.338568481 -0500 @@ -509,10 +509,10 @@ isc_nm_settimeouts(isc_nm_t *mgr, uint32 uint32_t keepalive, uint32_t advertised) { REQUIRE(VALID_NM(mgr)); - atomic_store(&mgr->init, init * 100); - atomic_store(&mgr->idle, idle * 100); - atomic_store(&mgr->keepalive, keepalive * 100); - atomic_store(&mgr->advertised, advertised * 100); + atomic_store(&mgr->init, init); + atomic_store(&mgr->idle, idle); + atomic_store(&mgr->keepalive, keepalive); + atomic_store(&mgr->advertised, advertised); } void @@ -521,19 +521,19 @@ isc_nm_gettimeouts(isc_nm_t *mgr, uint32 REQUIRE(VALID_NM(mgr)); if (initial != NULL) { - *initial = atomic_load(&mgr->init) / 100; + *initial = atomic_load(&mgr->init); } if (idle != NULL) { - *idle = atomic_load(&mgr->idle) / 100; + *idle = atomic_load(&mgr->idle); } if (keepalive != NULL) { - *keepalive = atomic_load(&mgr->keepalive) / 100; + *keepalive = atomic_load(&mgr->keepalive); } if (advertised != NULL) { - *advertised = atomic_load(&mgr->advertised) / 100; + *advertised = atomic_load(&mgr->advertised); } } @@ -1537,26 +1537,388 @@ isc_nmhandle_setdata(isc_nmhandle_t *han } void -isc_nmhandle_settimeout(isc_nmhandle_t *handle, uint32_t timeout) { - REQUIRE(VALID_NMHANDLE(handle)); +isc__nm_alloc_dnsbuf(isc_nmsocket_t *sock, size_t len) { + REQUIRE(len <= NM_BIG_BUF); - switch (handle->sock->type) { - case isc_nm_udpsocket: - isc__nm_udp_settimeout(handle, timeout); + if (sock->buf == NULL) { + // We don't have the buffer at all! + size_t alloc_len = len < NM_REG_BUF ? NM_REG_BUF : NM_BIG_BUF; + sock->buf = isc_mem_allocate(sock->mgr->mctx, alloc_len); + sock->buf_size = alloc_len; + } else { + // We have the buffer but it's too small + sock->buf = isc_mem_reallocate(sock->mgr->mctx, sock->buf, + NM_BIG_BUF); + sock->buf_size = NM_BIG_BUF; + } +} + +void +isc__nm_failed_send_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req, + isc_result_t eresult) { + REQUIRE(VALID_NMSOCK(sock)); + REQUIRE(VALID_UVREQ(req)); + + if (req->cb.send != NULL) { + isc__nm_sendcb(sock, req, eresult, true); + } else { + isc__nm_uvreq_put(&req, sock); + } +} + +void +isc__nm_failed_accept_cb(isc_nmsocket_t *sock, isc_result_t eresult) { + REQUIRE(sock->accepting); + REQUIRE(sock->server); + + /* + * Detach the quota early to make room for other connections; + * otherwise it'd be detached later asynchronously, and clog + * the quota unnecessarily. + */ + if (sock->quota != NULL) { + isc_quota_detach(&sock->quota); + } + + isc__nmsocket_detach(&sock->server); + + sock->accepting = false; + + switch (eresult) { + case ISC_R_NOTCONNECTED: + // IGNORE: The client disconnected before we could accept. break; + default: + isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_NETMGR, ISC_LOG_ERROR, + "Accepting TCP connection failed: %s", + isc_result_totext(eresult)); + } +} + +void +isc__nm_failed_connect_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req, + isc_result_t eresult) { + REQUIRE(VALID_NMSOCK(sock)); + REQUIRE(VALID_UVREQ(req)); + REQUIRE(sock->tid == isc_nm_tid()); + REQUIRE(atomic_load(&sock->connecting)); + REQUIRE(req->cb.connect != NULL); + + atomic_store(&sock->connecting, false); + + isc__nmsocket_clearcb(sock); + + isc__nm_connectcb(sock, req, eresult); + + isc__nmsocket_prep_destroy(sock); +} + +void +isc__nm_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result) { + REQUIRE(VALID_NMSOCK(sock)); + switch (sock->type) { + case isc_nm_udpsocket: + isc__nm_udp_failed_read_cb(sock, result); + return; case isc_nm_tcpsocket: - isc__nm_tcp_settimeout(handle, timeout); - break; + isc__nm_tcp_failed_read_cb(sock, result); + return; + case isc_nm_tcpdnssocket: + isc__nm_tcpdns_failed_read_cb(sock, result); + return; + case isc_nm_tlsdnssocket: + isc__nm_tlsdns_failed_read_cb(sock, result); + return; + default: + INSIST(0); + ISC_UNREACHABLE(); + } +} + +static void +isc__nmsocket_readtimeout_cb(uv_timer_t *timer) { + isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)timer); + + REQUIRE(VALID_NMSOCK(sock)); + REQUIRE(sock->tid == isc_nm_tid()); + REQUIRE(sock->reading); + + isc__nm_failed_read_cb(sock, ISC_R_TIMEDOUT); +} + +void +isc__nmsocket_timer_restart(isc_nmsocket_t *sock) { + REQUIRE(VALID_NMSOCK(sock)); + + if (sock->read_timeout == 0) { + return; + } + + int r = uv_timer_start(&sock->timer, isc__nmsocket_readtimeout_cb, + sock->read_timeout, 0); + RUNTIME_CHECK(r == 0); +} + +void +isc__nmsocket_timer_start(isc_nmsocket_t *sock) { + REQUIRE(VALID_NMSOCK(sock)); + + if (uv_is_active((uv_handle_t *)&sock->timer)) { + return; + } + + isc__nmsocket_timer_restart(sock); +} + +void +isc__nmsocket_timer_stop(isc_nmsocket_t *sock) { + REQUIRE(VALID_NMSOCK(sock)); + + if (!uv_is_active((uv_handle_t *)&sock->timer)) { + return; + } + + int r = uv_timer_stop(&sock->timer); + RUNTIME_CHECK(r == 0); +} + +isc__nm_uvreq_t * +isc__nm_get_read_req(isc_nmsocket_t *sock, isc_sockaddr_t *sockaddr) { + isc__nm_uvreq_t *req = NULL; + + req = isc__nm_uvreq_get(sock->mgr, sock); + req->cb.recv = sock->recv_cb; + req->cbarg = sock->recv_cbarg; + + if (atomic_load(&sock->client)) { + isc_nmhandle_attach(sock->statichandle, &req->handle); + } else { + req->handle = isc__nmhandle_get(sock, sockaddr, NULL); + } + + return req; +} + +/*%< + * Allocator for read operations. Limited to size 2^16. + * + * Note this doesn't actually allocate anything, it just assigns the + * worker's receive buffer to a socket, and marks it as "in use". + */ +void +isc__nm_alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf) { + isc_nmsocket_t *sock = uv_handle_get_data(handle); + isc__networker_t *worker = NULL; + + REQUIRE(VALID_NMSOCK(sock)); + REQUIRE(isc__nm_in_netthread()); + + switch (sock->type) { + case isc_nm_udpsocket: + REQUIRE(size <= ISC_NETMGR_RECVBUF_SIZE); + size = ISC_NETMGR_RECVBUF_SIZE; + break; case isc_nm_tcpdnssocket: - isc__nm_tcpdns_settimeout(handle, timeout); break; case isc_nm_tlsdnssocket: - isc__nm_tlsdns_settimeout(handle, timeout); + /* + * We need to limit the individual chunks to be read, so the + * BIO_write() will always succeed and the consumed before the + * next readcb is called. + */ + if (size >= ISC_NETMGR_TLSBUF_SIZE) { + size = ISC_NETMGR_TLSBUF_SIZE; + } break; default: INSIST(0); ISC_UNREACHABLE(); } + + worker = &sock->mgr->workers[sock->tid]; + INSIST(!worker->recvbuf_inuse); + + buf->base = worker->recvbuf; + buf->len = size; + worker->recvbuf_inuse = true; +} + +void +isc__nm_start_reading(isc_nmsocket_t *sock) { + int r; + + if (sock->reading) { + return; + } + + switch (sock->type) { + case isc_nm_udpsocket: + r = uv_udp_recv_start(&sock->uv_handle.udp, isc__nm_alloc_cb, + isc__nm_udp_read_cb); + break; + case isc_nm_tcpdnssocket: + r = uv_read_start(&sock->uv_handle.stream, isc__nm_alloc_cb, + isc__nm_tcpdns_read_cb); + break; + case isc_nm_tlsdnssocket: + r = uv_read_start(&sock->uv_handle.stream, isc__nm_alloc_cb, + isc__nm_tlsdns_read_cb); + break; + default: + INSIST(0); + ISC_UNREACHABLE(); + } + RUNTIME_CHECK(r == 0); + sock->reading = true; +} + +void +isc__nm_stop_reading(isc_nmsocket_t *sock) { + int r; + + if (!sock->reading) { + return; + } + + switch(sock->type) { + case isc_nm_udpsocket: + r = uv_udp_recv_stop(&sock->uv_handle.udp); + break; + case isc_nm_tcpdnssocket: + case isc_nm_tlsdnssocket: + r = uv_read_stop(&sock->uv_handle.stream); + break; + default: + INSIST(0); + ISC_UNREACHABLE(); + } + RUNTIME_CHECK(r == 0); + sock->reading = false; +} + +bool +isc__nm_inactive(isc_nmsocket_t *sock) { + return(!isc__nmsocket_active(sock) || atomic_load(&sock->closing) || + atomic_load(&sock->mgr->closing) || + (sock->server != NULL && !isc__nmsocket_active(sock->server))); +} + +static isc_result_t +processbuffer(isc_nmsocket_t *sock) { + switch(sock->type) { + case isc_nm_tcpdnssocket: + return (isc__nm_tcpdns_processbuffer(sock)); + case isc_nm_tlsdnssocket: + return (isc__nm_tcpdns_processbuffer(sock)); + default: + INSIST(0); + ISC_UNREACHABLE(); + } +} + +/* + * Process a DNS message. + * + * If we only have an incomplete DNS message, we don't touch any + * timers. If we do have a full message, reset the timer. + * + * Stop reading if this is a client socket, or if the server socket + * has been set to sequential mode, or the number of queries we are + * processing simultaneously has reached the clients-per-connection + * limit. In this case, we'll be called again by resume_processing() + * later. + */ +void +isc__nm_process_sock_buffer(isc_nmsocket_t *sock) { + for (;;) { + int_fast32_t ah = atomic_load(&sock->ah); + isc_result_t result = processbuffer(sock); + switch(result) { + case ISC_R_NOMORE: + /* + * Don't reset the timer until we have + * a full DNS message. + */ + isc__nm_start_reading(sock); + /* + * Start the timer only if there are no externally used + * active handles, there's always one active handle + * attached internally to sock->recv_handle in + * accept_connection() + */ + if (ah == 1) { + isc__nmsocket_timer_start(sock); + } + return; + case ISC_R_CANCELED: + isc__nmsocket_timer_stop(sock); + isc__nm_stop_reading(sock); + return; + case ISC_R_SUCCESS: + /* + * Stop the timer on the successful message read, this + * also allows to restart the timer when we have no more + * data. + */ + isc__nmsocket_timer_stop(sock); + + if (atomic_load(&sock->client) || + atomic_load(&sock->sequential) || + ah >= STREAM_CLIENTS_PER_CONN) + { + isc__nm_stop_reading(sock); + return; + } + break; + default: + INSIST(0); + } + } +} + +void +isc__nm_resume_processing(void *arg) { + isc_nmsocket_t *sock = (isc_nmsocket_t *)arg; + + REQUIRE(VALID_NMSOCK(sock)); + REQUIRE(sock->tid == isc_nm_tid()); + REQUIRE(!atomic_load(&sock->client)); + + if (isc__nm_inactive(sock)) { + return; + } + + isc__nm_process_sock_buffer(sock); +} + +void +isc_nmhandle_cleartimeout(isc_nmhandle_t *handle) { + REQUIRE(VALID_NMHANDLE(handle)); + REQUIRE(VALID_NMSOCK(handle->sock)); + + switch (handle->sock->type) { + default: + handle->sock->read_timeout = 0; + + if (uv_is_active((uv_handle_t *)&handle->sock->timer)) { + isc__nmsocket_timer_stop(handle->sock); + } + } +} + +void +isc_nmhandle_settimeout(isc_nmhandle_t *handle, uint32_t timeout) { + REQUIRE(VALID_NMHANDLE(handle)); + REQUIRE(VALID_NMSOCK(handle->sock)); + + switch(handle->sock->type) { + default: + handle->sock->read_timeout = timeout; + if (uv_is_active((uv_handle_t *)&handle->sock->timer)) { + isc__nmsocket_timer_restart(handle->sock); + } + } } void * @@ -1865,22 +2227,23 @@ isc__nm_async_readcb(isc__networker_t *w void isc__nm_sendcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq, - isc_result_t eresult) { + isc_result_t eresult, bool async) { REQUIRE(VALID_NMSOCK(sock)); REQUIRE(VALID_UVREQ(uvreq)); REQUIRE(VALID_NMHANDLE(uvreq->handle)); - if (eresult == ISC_R_SUCCESS) { + if (!async) { isc__netievent_sendcb_t ievent = { .sock = sock, .req = uvreq, .result = eresult }; isc__nm_async_sendcb(NULL, (isc__netievent_t *)&ievent); - } else { - isc__netievent_sendcb_t *ievent = isc__nm_get_netievent_sendcb( - sock->mgr, sock, uvreq, eresult); - isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid], - (isc__netievent_t *)ievent); + return; } + + isc__netievent_sendcb_t *ievent = + isc__nm_get_netievent_sendcb(sock->mgr, sock, uvreq, eresult); + isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid], + (isc__netievent_t *)ievent); } void diff -Naurp bind-9.16.13.orig/lib/isc/netmgr/netmgr-int.h bind-9.16.13/lib/isc/netmgr/netmgr-int.h --- bind-9.16.13.orig/lib/isc/netmgr/netmgr-int.h 2021-03-11 07:20:59.000000000 -0600 +++ bind-9.16.13/lib/isc/netmgr/netmgr-int.h 2021-03-24 19:16:08.938294736 -0500 @@ -39,6 +39,8 @@ #define ISC_NETMGR_TID_UNKNOWN -1 +#define ISC_NETMGR_TLSBUF_SIZE 65536 + #if !defined(WIN32) /* * New versions of libuv support recvmmsg on unices. @@ -670,6 +672,12 @@ enum { STATID_ACTIVE = 10 }; +typedef void (*isc_nm_closehandlecb_t)(void* arg); +/*%< + * Opaque callback function, used for isc_nmhandle 'reset' and 'free' + * callbacks. + */ + struct isc_nmsocket { /*% Unlocked, RO */ int magic; @@ -892,7 +900,7 @@ struct isc_nmsocket { * as the argument whenever a handle's references drop * to zero, after its reset callback has been called. */ - isc_nm_opaquecb_t closehandle_cb; + isc_nm_closehandlecb_t closehandle_cb; isc_nmhandle_t *recv_handle; isc_nm_recv_cb_t recv_cb; @@ -1031,6 +1039,16 @@ isc__nmsocket_clearcb(isc_nmsocket_t *so */ void +isc__nmsocket_timer_stop(isc_nmsocket_t *sock); +void +isc__nmsocket_timer_start(isc_nmsocket_t *sock); +void +isc__nmsocket_timer_restart(isc_nmsocket_t *sock); +/*%< + * Start/stop/restart the read timeout on the socket + */ + +void isc__nm_connectcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq, isc_result_t eresult); void @@ -1054,7 +1072,7 @@ isc__nm_async_readcb(isc__networker_t *w void isc__nm_sendcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq, - isc_result_t eresult); + isc_result_t eresult, bool async); void isc__nm_async_sendcb(isc__networker_t *worker, isc__netievent_t *ev0); /*%< @@ -1110,7 +1128,7 @@ isc__nm_udp_stoplistening(isc_nmsocket_t void isc__nm_udp_settimeout(isc_nmhandle_t *handle, uint32_t timeout); /*%< - * Set the recv timeout for the UDP socket associated with 'handle'. + * Set or clear the recv timeout for the UDP socket associated with 'handle'. */ void @@ -1431,7 +1449,7 @@ isc__nm_socket_dontfrag(uv_os_sock_t fd, isc_result_t isc__nm_socket_connectiontimeout(uv_os_sock_t fd, int timeout_ms); /*%< - * Set the connection timeout in miliseconds, on non-Linux platforms, + * Set the connection timeout in milliseconds, on non-Linux platforms, * the minimum value must be at least 1000 (1 second). */ @@ -1542,3 +1560,59 @@ NETIEVENT_DECL(pause); NETIEVENT_DECL(resume); NETIEVENT_DECL(shutdown); NETIEVENT_DECL(stop); + +void +isc__nm_udp_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result); +void +isc__nm_tcp_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result); +void +isc__nm_tcpdns_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result); +void +isc__nm_tlsdns_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result); + +isc_result_t +isc__nm_tcpdns_processbuffer(isc_nmsocket_t *sock); +isc_result_t +isc__nm_tlsdns_processbuffer(isc_nmsocket_t *sock); + +isc__nm_uvreq_t * +isc__nm_get_read_req(isc_nmsocket_t *sock, isc_sockaddr_t *sockaddr); + +void +isc__nm_alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf); + +void +isc__nm_udp_read_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf, + const struct sockaddr *addr, unsigned flags); + +void +isc__nm_tcpdns_read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf); +void +isc__nm_tlsdns_read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf); + +void +isc__nm_start_reading(isc_nmsocket_t *sock); +void +isc__nm_stop_reading(isc_nmsocket_t *sock); +void +isc__nm_process_sock_buffer(isc_nmsocket_t *sock); +void +isc__nm_resume_processing(void *arg); +bool +isc__nm_inactive(isc_nmsocket_t *sock); + +void +isc__nm_alloc_dnsbuf(isc_nmsocket_t *sock, size_t len); + +void +isc__nm_failed_send_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req, + isc_result_t eresult); +void +isc__nm_failed_accept_cb(isc_nmsocket_t *sock, isc_result_t eresult); +void +isc__nm_failed_connect_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req, + isc_result_t eresult); +void +isc__nm_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result); + +#define STREAM_CLIENTS_PER_CONN 23 diff -Naurp bind-9.16.13.orig/lib/isc/netmgr/tcp.c bind-9.16.13/lib/isc/netmgr/tcp.c --- bind-9.16.13.orig/lib/isc/netmgr/tcp.c 2021-03-11 07:20:59.000000000 -0600 +++ bind-9.16.13/lib/isc/netmgr/tcp.c 2021-03-24 16:53:03.113961690 -0500 @@ -87,9 +87,6 @@ static void stop_tcp_child(isc_nmsocket_t *sock); static void -start_sock_timer(isc_nmsocket_t *sock); - -static void start_reading(isc_nmsocket_t *sock); static void @@ -716,6 +713,11 @@ destroy: } } +void +isc__nm_tcp_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result) { + failed_read_cb(sock, result); +} + static void failed_send_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req, isc_result_t eresult) { @@ -723,7 +725,7 @@ failed_send_cb(isc_nmsocket_t *sock, isc REQUIRE(VALID_UVREQ(req)); if (req->cb.send != NULL) { - isc__nm_sendcb(sock, req, eresult); + isc__nm_sendcb(sock, req, eresult, true); } else { isc__nm_uvreq_put(&req, sock); } @@ -742,35 +744,6 @@ get_read_req(isc_nmsocket_t *sock) { } static void -readtimeout_cb(uv_timer_t *timer) { - isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)timer); - - REQUIRE(VALID_NMSOCK(sock)); - REQUIRE(sock->tid == isc_nm_tid()); - REQUIRE(sock->reading); - - /* - * Timeout; stop reading and process whatever we have. - */ - failed_read_cb(sock, ISC_R_TIMEDOUT); -} - -static void -start_sock_timer(isc_nmsocket_t *sock) { - if (sock->read_timeout > 0) { - int r = uv_timer_start(&sock->timer, readtimeout_cb, - sock->read_timeout, 0); - REQUIRE(r == 0); - } -} - -static void -stop_sock_timer(isc_nmsocket_t *sock) { - int r = uv_timer_stop(&sock->timer); - REQUIRE(r == 0); -} - -static void start_reading(isc_nmsocket_t *sock) { if (sock->reading) { return; @@ -779,8 +752,6 @@ start_reading(isc_nmsocket_t *sock) { int r = uv_read_start(&sock->uv_handle.stream, tcp_alloc_cb, read_cb); REQUIRE(r == 0); sock->reading = true; - - start_sock_timer(sock); } static void @@ -793,7 +764,7 @@ stop_reading(isc_nmsocket_t *sock) { REQUIRE(r == 0); sock->reading = false; - stop_sock_timer(sock); + isc__nmsocket_timer_stop(sock); } void @@ -876,6 +847,7 @@ isc__nm_async_tcpstartread(isc__networke } start_reading(sock); + isc__nmsocket_timer_start(sock); } void @@ -994,7 +966,7 @@ read_cb(uv_stream_t *stream, ssize_t nre /* The readcb could have paused the reading */ if (sock->reading) { /* The timer will be updated */ - start_sock_timer(sock); + isc__nmsocket_timer_restart(sock); } free: @@ -1196,7 +1168,7 @@ tcp_send_cb(uv_write_t *req, int status) return; } - isc__nm_sendcb(sock, uvreq, ISC_R_SUCCESS); + isc__nm_sendcb(sock, uvreq, ISC_R_SUCCESS, false); } /* @@ -1476,20 +1448,6 @@ isc__nm_async_tcpcancel(isc__networker_t failed_read_cb(sock, ISC_R_EOF); } -void -isc__nm_tcp_settimeout(isc_nmhandle_t *handle, uint32_t timeout) { - isc_nmsocket_t *sock = NULL; - - REQUIRE(VALID_NMHANDLE(handle)); - - sock = handle->sock; - - sock->read_timeout = timeout; - if (uv_is_active((uv_handle_t *)&sock->timer)) { - start_sock_timer(sock); - } -} - int_fast32_t isc__nm_tcp_listener_nactive(isc_nmsocket_t *listener) { int_fast32_t nactive; diff -Naurp bind-9.16.13.orig/lib/isc/netmgr/tcpdns.c bind-9.16.13/lib/isc/netmgr/tcpdns.c --- bind-9.16.13.orig/lib/isc/netmgr/tcpdns.c 2021-03-11 07:20:59.000000000 -0600 +++ bind-9.16.13/lib/isc/netmgr/tcpdns.c 2021-03-24 19:20:13.340595846 -0500 @@ -34,7 +34,6 @@ #include "netmgr-int.h" #include "uv-compat.h" -#define TCPDNS_CLIENTS_PER_CONN 23 /*%< * * Maximum number of simultaneous handles in flight supported for a single @@ -57,20 +56,12 @@ can_log_tcpdns_quota(void) { return (false); } -static void -tcpdns_alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf); - -static void -resume_processing(void *arg); - static isc_result_t tcpdns_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req); static void tcpdns_close_direct(isc_nmsocket_t *sock); -static isc_result_t -tcpdns_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req); static void tcpdns_connect_cb(uv_connect_t *uvreq, int status); @@ -78,9 +69,6 @@ static void tcpdns_connection_cb(uv_stream_t *server, int status); static void -read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf); - -static void tcpdns_close_cb(uv_handle_t *uvhandle); static isc_result_t @@ -90,100 +78,10 @@ static void quota_accept_cb(isc_quota_t *quota, void *sock0); static void -failed_accept_cb(isc_nmsocket_t *sock, isc_result_t eresult); - -static void -failed_send_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req, - isc_result_t eresult); - -static void stop_tcpdns_parent(isc_nmsocket_t *sock); static void stop_tcpdns_child(isc_nmsocket_t *sock); -static void -start_sock_timer(isc_nmsocket_t *sock); - -static void -process_sock_buffer(isc_nmsocket_t *sock); - -static void -stop_reading(isc_nmsocket_t *sock); - -static isc__nm_uvreq_t * -get_read_req(isc_nmsocket_t *sock); - -static inline void -alloc_dnsbuf(isc_nmsocket_t *sock, size_t len) { - REQUIRE(len <= NM_BIG_BUF); - - if (sock->buf == NULL) { - /* We don't have the buffer at all */ - size_t alloc_len = len < NM_REG_BUF ? NM_REG_BUF : NM_BIG_BUF; - sock->buf = isc_mem_allocate(sock->mgr->mctx, alloc_len); - sock->buf_size = alloc_len; - } else { - /* We have the buffer but it's too small */ - sock->buf = isc_mem_reallocate(sock->mgr->mctx, sock->buf, - NM_BIG_BUF); - sock->buf_size = NM_BIG_BUF; - } -} - -static bool -inactive(isc_nmsocket_t *sock) { - return (!isc__nmsocket_active(sock) || atomic_load(&sock->closing) || - atomic_load(&sock->mgr->closing) || - (sock->server != NULL && !isc__nmsocket_active(sock->server))); -} - -static void -failed_accept_cb(isc_nmsocket_t *sock, isc_result_t eresult) { - REQUIRE(sock->accepting); - REQUIRE(sock->server); - - /* - * Detach the quota early to make room for other connections; - * otherwise it'd be detached later asynchronously, and clog - * the quota unnecessarily. - */ - if (sock->quota != NULL) { - isc_quota_detach(&sock->quota); - } - - isc__nmsocket_detach(&sock->server); - - sock->accepting = false; - - switch (eresult) { - case ISC_R_NOTCONNECTED: - /* IGNORE: The client disconnected before we could accept */ - break; - default: - isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, - ISC_LOGMODULE_NETMGR, ISC_LOG_ERROR, - "Accepting TCP connection failed: %s", - isc_result_totext(eresult)); - } -} - -static void -failed_connect_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req, - isc_result_t eresult) { - REQUIRE(VALID_NMSOCK(sock)); - REQUIRE(VALID_UVREQ(req)); - REQUIRE(sock->tid == isc_nm_tid()); - REQUIRE(atomic_load(&sock->connecting)); - REQUIRE(req->cb.connect != NULL); - - atomic_store(&sock->connecting, false); - - isc__nmsocket_clearcb(sock); - isc__nm_connectcb(sock, req, eresult); - - isc__nmsocket_prep_destroy(sock); -} - static isc_result_t tcpdns_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { isc__networker_t *worker = NULL; @@ -331,7 +229,7 @@ tcpdns_connect_cb(uv_connect_t *uvreq, i return; error: - failed_connect_cb(sock, req, result); + isc__nm_failed_connect_cb(sock, req, result); } isc_result_t @@ -648,7 +546,7 @@ tcpdns_connection_cb(uv_stream_t *server REQUIRE(VALID_NMSOCK(ssock)); REQUIRE(ssock->tid == isc_nm_tid()); - if (inactive(ssock)) { + if (isc__nm_inactive(ssock)) { result = ISC_R_CANCELED; goto done; } @@ -725,12 +623,13 @@ isc__nm_async_tcpdnsstop(isc__networker_ } } -static void -failed_read_cb(isc_nmsocket_t *sock, isc_result_t result) { +void +isc__nm_tcpdns_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result) { REQUIRE(VALID_NMSOCK(sock)); REQUIRE(result != ISC_R_SUCCESS); - stop_reading(sock); + isc__nmsocket_timer_stop(sock); + isc__nm_stop_reading(sock); if (!sock->recv_read) { goto destroy; @@ -738,7 +637,7 @@ failed_read_cb(isc_nmsocket_t *sock, isc sock->recv_read = false; if (sock->recv_cb != NULL) { - isc__nm_uvreq_t *req = get_read_req(sock); + isc__nm_uvreq_t *req = isc__nm_get_read_req(sock, NULL); isc__nmsocket_clearcb(sock); isc__nm_readcb(sock, req, result); } @@ -753,96 +652,6 @@ destroy: } } -static void -failed_send_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req, - isc_result_t eresult) { - REQUIRE(VALID_NMSOCK(sock)); - REQUIRE(VALID_UVREQ(req)); - - if (req->cb.send != NULL) { - isc__nm_sendcb(sock, req, eresult); - } else { - isc__nm_uvreq_put(&req, sock); - } -} - -static isc__nm_uvreq_t * -get_read_req(isc_nmsocket_t *sock) { - isc__nm_uvreq_t *req = NULL; - - req = isc__nm_uvreq_get(sock->mgr, sock); - req->cb.recv = sock->recv_cb; - req->cbarg = sock->recv_cbarg; - - if (atomic_load(&sock->client)) { - isc_nmhandle_attach(sock->statichandle, &req->handle); - } else { - req->handle = isc__nmhandle_get(sock, NULL, NULL); - } - - return (req); -} - -static void -readtimeout_cb(uv_timer_t *timer) { - isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)timer); - - REQUIRE(VALID_NMSOCK(sock)); - REQUIRE(sock->tid == isc_nm_tid()); - REQUIRE(sock->reading); - - /* - * Timeout; stop reading and process whatever we have. - */ - - failed_read_cb(sock, ISC_R_TIMEDOUT); -} - -static void -start_sock_timer(isc_nmsocket_t *sock) { - if (sock->read_timeout > 0) { - int r = uv_timer_start(&sock->timer, readtimeout_cb, - sock->read_timeout, 0); - RUNTIME_CHECK(r == 0); - } -} - -static void -stop_sock_timer(isc_nmsocket_t *sock) { - int r = uv_timer_stop(&sock->timer); - RUNTIME_CHECK(r == 0); -} - -static void -start_reading(isc_nmsocket_t *sock) { - int r; - - if (sock->reading) { - return; - } - - r = uv_read_start(&sock->uv_handle.stream, tcpdns_alloc_cb, read_cb); - RUNTIME_CHECK(r == 0); - sock->reading = true; - - start_sock_timer(sock); -} - -static void -stop_reading(isc_nmsocket_t *sock) { - int r; - - if (!sock->reading) { - return; - } - - r = uv_read_stop(&sock->uv_handle.stream); - RUNTIME_CHECK(r == 0); - sock->reading = false; - - stop_sock_timer(sock); -} - void isc__nm_tcpdns_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) { REQUIRE(VALID_NMHANDLE(handle)); @@ -880,31 +689,6 @@ isc__nm_tcpdns_read(isc_nmhandle_t *hand return; } -/*%< - * Allocator for TCP read operations. Limited to size 2^16. - * - * Note this doesn't actually allocate anything, it just assigns the - * worker's receive buffer to a socket, and marks it as "in use". - */ -static void -tcpdns_alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf) { - isc_nmsocket_t *sock = uv_handle_get_data(handle); - isc__networker_t *worker = NULL; - - UNUSED(size); - - REQUIRE(VALID_NMSOCK(sock)); - REQUIRE(sock->type == isc_nm_tcpdnssocket); - REQUIRE(isc__nm_in_netthread()); - - worker = &sock->mgr->workers[sock->tid]; - INSIST(!worker->recvbuf_inuse); - - buf->base = worker->recvbuf; - buf->len = size; - worker->recvbuf_inuse = true; -} - void isc__nm_async_tcpdnsread(isc__networker_t *worker, isc__netievent_t *ev0) { isc__netievent_tcpdnsread_t *ievent = @@ -916,13 +700,13 @@ isc__nm_async_tcpdnsread(isc__networker_ REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->tid == isc_nm_tid()); - if (inactive(sock)) { + if (isc__nm_inactive(sock)) { sock->reading = true; - failed_read_cb(sock, ISC_R_CANCELED); + isc__nm_failed_read_cb(sock, ISC_R_CANCELED); return; } - process_sock_buffer(sock); + isc__nm_process_sock_buffer(sock); } /* @@ -934,8 +718,8 @@ isc__nm_async_tcpdnsread(isc__networker_ * * The caller will need to unreference the handle. */ -static isc_result_t -processbuffer(isc_nmsocket_t *sock) { +isc_result_t +isc__nm_tcpdns_processbuffer(isc_nmsocket_t *sock) { size_t len; isc__nm_uvreq_t *req = NULL; isc_nmhandle_t *handle = NULL; @@ -943,7 +727,7 @@ processbuffer(isc_nmsocket_t *sock) { REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->tid == isc_nm_tid()); - if (inactive(sock)) { + if (isc__nm_inactive(sock)) { return (ISC_R_CANCELED); } @@ -964,7 +748,7 @@ processbuffer(isc_nmsocket_t *sock) { return (ISC_R_NOMORE); } - req = get_read_req(sock); + req = isc__nm_get_read_req(sock, NULL); REQUIRE(VALID_UVREQ(req)); /* @@ -1008,8 +792,9 @@ processbuffer(isc_nmsocket_t *sock) { return (ISC_R_SUCCESS); } -static void -read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { +void +isc__nm_tcpdns_read_cb(uv_stream_t *stream, ssize_t nread, + const uv_buf_t *buf) { isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)stream); uint8_t *base = NULL; size_t len; @@ -1019,8 +804,8 @@ read_cb(uv_stream_t *stream, ssize_t nre REQUIRE(sock->reading); REQUIRE(buf != NULL); - if (inactive(sock)) { - failed_read_cb(sock, ISC_R_CANCELED); + if (isc__nm_inactive(sock)) { + isc__nm_failed_read_cb(sock, ISC_R_CANCELED); goto free; } @@ -1030,8 +815,7 @@ read_cb(uv_stream_t *stream, ssize_t nre sock->statsindex[STATID_RECVFAIL]); } - failed_read_cb(sock, isc__nm_uverr2result(nread)); - + isc__nm_failed_read_cb(sock, isc__nm_uverr2result(nread)); goto free; } @@ -1048,7 +832,7 @@ read_cb(uv_stream_t *stream, ssize_t nre */ if (sock->buf_len + len > sock->buf_size) { - alloc_dnsbuf(sock, sock->buf_len + len); + isc__nm_alloc_dnsbuf(sock, sock->buf_len + len); } memmove(sock->buf + sock->buf_len, base, len); sock->buf_len += len; @@ -1057,7 +841,7 @@ read_cb(uv_stream_t *stream, ssize_t nre sock->read_timeout = atomic_load(&sock->mgr->idle); } - process_sock_buffer(sock); + isc__nm_process_sock_buffer(sock); free: isc__nm_free_uvbuf(sock, buf); } @@ -1119,7 +903,7 @@ accept_connection(isc_nmsocket_t *ssock, REQUIRE(VALID_NMSOCK(ssock)); REQUIRE(ssock->tid == isc_nm_tid()); - if (inactive(ssock)) { + if (isc__nm_inactive(ssock)) { if (quota != NULL) { isc_quota_detach("a); } @@ -1201,7 +985,7 @@ accept_connection(isc_nmsocket_t *ssock, csock->read_timeout = atomic_load(&csock->mgr->init); - csock->closehandle_cb = resume_processing; + csock->closehandle_cb = isc__nm_resume_processing; /* * We need to keep the handle alive until we fail to read or connection @@ -1209,7 +993,7 @@ accept_connection(isc_nmsocket_t *ssock, * prep_destroy()->tcpdns_close_direct(). */ isc_nmhandle_attach(handle, &csock->recv_handle); - start_reading(csock); + isc__nm_process_sock_buffer(csock); /* * The initial timer has been set, update the read timeout for the next @@ -1232,7 +1016,7 @@ failure: atomic_store(&csock->active, false); - failed_accept_cb(csock, result); + isc__nm_failed_accept_cb(csock, result); isc__nmsocket_prep_destroy(csock); @@ -1280,11 +1064,12 @@ tcpdns_send_cb(uv_write_t *req, int stat if (status < 0) { isc__nm_incstats(sock->mgr, sock->statsindex[STATID_SENDFAIL]); - failed_send_cb(sock, uvreq, isc__nm_uverr2result(status)); + isc__nm_failed_send_cb(sock, uvreq, + isc__nm_uverr2result(status)); return; } - isc__nm_sendcb(sock, uvreq, ISC_R_SUCCESS); + isc__nm_sendcb(sock, uvreq, ISC_R_SUCCESS, false); } /* @@ -1292,48 +1077,70 @@ tcpdns_send_cb(uv_write_t *req, int stat */ void isc__nm_async_tcpdnssend(isc__networker_t *worker, isc__netievent_t *ev0) { - isc_result_t result; isc__netievent_tcpdnssend_t *ievent = (isc__netievent_tcpdnssend_t *)ev0; + + REQUIRE(ievent->sock->type == isc_nm_tcpdnssocket); + REQUIRE(ievent->sock->tid == isc_nm_tid()); + REQUIRE(VALID_NMSOCK(ievent->sock)); + REQUIRE(VALID_UVREQ(ievent->req)); + REQUIRE(ievent->sock->tid == isc_nm_tid()); + + isc_result_t result; isc_nmsocket_t *sock = ievent->sock; isc__nm_uvreq_t *uvreq = ievent->req; + uv_buf_t bufs[2] = { { .base = uvreq->tcplen, .len = 2 }, + { .base = uvreq->uvbuf.base, + .len = uvreq->uvbuf.len } }; + int nbufs = 2; + int r; UNUSED(worker); - REQUIRE(sock->type == isc_nm_tcpdnssocket); - REQUIRE(sock->tid == isc_nm_tid()); - - result = tcpdns_send_direct(sock, uvreq); - if (result != ISC_R_SUCCESS) { - isc__nm_incstats(sock->mgr, sock->statsindex[STATID_SENDFAIL]); - failed_send_cb(sock, uvreq, result); - } -} - -static isc_result_t -tcpdns_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { - int r; + if (isc__nm_inactive(sock)) { + result = ISC_R_CANCELED; + goto fail; + } + + r = uv_try_write(&sock->uv_handle.stream, bufs, nbufs); + + if (r == (int)(bufs[0].len + bufs[1].len)) { + // Wrote everything + isc__nm_sendcb(sock, uvreq, ISC_R_SUCCESS, true); + return; + } + + if (r == 1) { + // Partial write of DNSMSG length + bufs[0].base = uvreq->tcplen + 1; + bufs[0].len = 1; + } else if (r > 0) { + // Partial write of DNSMSG + nbufs = 1; + bufs[0].base = uvreq->uvbuf.base + (r - 2); + bufs[0].len = uvreq->uvbuf.len - (r - 2); + } else if (r == UV_ENOSYS || r == UV_EAGAIN) { + // uv_try_write not supported, send asynchronously + } else { + // Error sending data + result = isc__nm_uverr2result(r); + goto fail; + } - REQUIRE(VALID_NMSOCK(sock)); - REQUIRE(VALID_UVREQ(req)); - REQUIRE(sock->tid == isc_nm_tid()); - REQUIRE(sock->type == isc_nm_tcpdnssocket); - - uv_buf_t bufs[2] = { { .base = req->tcplen, .len = 2 }, - { .base = req->uvbuf.base, - .len = req->uvbuf.len } }; - - if (inactive(sock)) { - return (ISC_R_CANCELED); - } - - r = uv_write(&req->uv_req.write, &sock->uv_handle.stream, bufs, 2, + r = uv_write(&uvreq->uv_req.write, &sock->uv_handle.stream, bufs, nbufs, tcpdns_send_cb); if (r < 0) { - return (isc__nm_uverr2result(r)); + result = isc__nm_uverr2result(r); + goto fail; } - return (ISC_R_SUCCESS); + return; + +fail: + if (result != ISC_R_SUCCESS) { + isc__nm_incstats(sock->mgr, sock->statsindex[STATID_SENDFAIL]); + isc__nm_failed_send_cb(sock, uvreq, result); + } } static void @@ -1462,7 +1269,8 @@ tcpdns_close_direct(isc_nmsocket_t *sock isc_nmhandle_detach(&sock->recv_handle); } - stop_reading(sock); + isc__nmsocket_timer_stop(sock); + isc__nm_stop_reading(sock); uv_close((uv_handle_t *)&sock->timer, timer_close_cb); } @@ -1524,7 +1332,7 @@ isc__nm_tcpdns_shutdown(isc_nmsocket_t * } if (sock->statichandle) { - failed_read_cb(sock, ISC_R_CANCELED); + isc__nm_failed_read_cb(sock, ISC_R_CANCELED); return; } @@ -1564,22 +1372,7 @@ isc__nm_async_tcpdnscancel(isc__networke REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->tid == isc_nm_tid()); - failed_read_cb(sock, ISC_R_EOF); -} - -void -isc__nm_tcpdns_settimeout(isc_nmhandle_t *handle, uint32_t timeout) { - isc_nmsocket_t *sock = NULL; - - REQUIRE(VALID_NMHANDLE(handle)); - REQUIRE(VALID_NMSOCK(handle->sock)); - - sock = handle->sock; - - sock->read_timeout = timeout; - if (uv_is_active((uv_handle_t *)&sock->timer)) { - start_sock_timer(sock); - } + isc__nm_failed_read_cb(sock, ISC_R_EOF); } void @@ -1601,7 +1394,8 @@ isc_nm_tcpdns_sequential(isc_nmhandle_t * is released. */ - stop_reading(sock); + isc__nmsocket_timer_stop(sock); + isc__nm_stop_reading(sock); atomic_store(&sock->sequential, true); } @@ -1617,65 +1411,3 @@ isc_nm_tcpdns_keepalive(isc_nmhandle_t * atomic_store(&sock->keepalive, value); } - -static void -process_sock_buffer(isc_nmsocket_t *sock) { - /* - * 1. When process_buffer receives incomplete DNS message, - * we don't touch any timers - * - * 2. When we receive at least one full DNS message, we stop the timers - * until resume_processing calls this function again and restarts the - * reading and the timers - */ - - /* - * Process a DNS messages. Stop if this is client socket, or the server - * socket has been set to sequential mode or the number of queries we - * are processing simultaneously have reached the clients-per-connection - * limit. - */ - for (;;) { - isc_result_t result = processbuffer(sock); - switch (result) { - case ISC_R_NOMORE: - start_reading(sock); - return; - case ISC_R_CANCELED: - stop_reading(sock); - return; - case ISC_R_SUCCESS: - if (atomic_load(&sock->client) || - atomic_load(&sock->sequential) || - atomic_load(&sock->ah) >= TCPDNS_CLIENTS_PER_CONN) - { - stop_reading(sock); - return; - } - break; - default: - INSIST(0); - } - } -} - -static void -resume_processing(void *arg) { - isc_nmsocket_t *sock = (isc_nmsocket_t *)arg; - - REQUIRE(VALID_NMSOCK(sock)); - REQUIRE(sock->tid == isc_nm_tid()); - REQUIRE(sock->type == isc_nm_tcpdnssocket); - REQUIRE(!atomic_load(&sock->client)); - - if (inactive(sock)) { - return; - } - - if (atomic_load(&sock->ah) == 0) { - /* Nothing is active; sockets can timeout now */ - start_sock_timer(sock); - } - - process_sock_buffer(sock); -} diff -Naurp bind-9.16.13.orig/lib/isc/netmgr/tlsdns.c bind-9.16.13/lib/isc/netmgr/tlsdns.c --- bind-9.16.13.orig/lib/isc/netmgr/tlsdns.c 2021-03-11 07:20:59.000000000 -0600 +++ bind-9.16.13/lib/isc/netmgr/tlsdns.c 2021-03-24 18:19:35.695416811 -0500 @@ -35,9 +35,6 @@ #include "openssl_shim.h" #include "uv-compat.h" -#define TLS_BUF_SIZE 65536 - -#define TLSDNS_CLIENTS_PER_CONN 23 /*%< * * Maximum number of simultaneous handles in flight supported for a single @@ -50,12 +47,6 @@ static atomic_uint_fast32_t last_tlsdnsq static void tls_error(isc_nmsocket_t *sock, isc_result_t result); -static void -tlsdns_alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf); - -static void -resume_processing(void *arg); - static isc_result_t tlsdns_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req); @@ -71,9 +62,6 @@ static void tlsdns_connection_cb(uv_stream_t *server, int status); static void -read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf); - -static void tlsdns_close_cb(uv_handle_t *uvhandle); static isc_result_t @@ -83,33 +71,11 @@ static void quota_accept_cb(isc_quota_t *quota, void *sock0); static void -failed_accept_cb(isc_nmsocket_t *sock, isc_result_t eresult); - -static void -failed_send_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req, - isc_result_t eresult); - -static void stop_tlsdns_parent(isc_nmsocket_t *sock); static void stop_tlsdns_child(isc_nmsocket_t *sock); static void -start_reading(isc_nmsocket_t *sock); - -static void -stop_reading(isc_nmsocket_t *sock); - -static void -start_sock_timer(isc_nmsocket_t *sock); - -static void -process_sock_buffer(isc_nmsocket_t *sock); - -static isc__nm_uvreq_t * -get_read_req(isc_nmsocket_t *sock); - -static void async_tlsdns_cycle(isc_nmsocket_t *sock) __attribute__((unused)); static isc_result_t @@ -128,78 +94,6 @@ can_log_tlsdns_quota(void) { return (false); } -static inline void -alloc_dnsbuf(isc_nmsocket_t *sock, size_t len) { - REQUIRE(len <= NM_BIG_BUF); - - if (sock->buf == NULL) { - /* We don't have the buffer at all */ - size_t alloc_len = len < NM_REG_BUF ? NM_REG_BUF : NM_BIG_BUF; - sock->buf = isc_mem_allocate(sock->mgr->mctx, alloc_len); - sock->buf_size = alloc_len; - } else { - /* We have the buffer but it's too small */ - sock->buf = isc_mem_reallocate(sock->mgr->mctx, sock->buf, - NM_BIG_BUF); - sock->buf_size = NM_BIG_BUF; - } -} - -static bool -inactive(isc_nmsocket_t *sock) { - return (!isc__nmsocket_active(sock) || atomic_load(&sock->closing) || - atomic_load(&sock->mgr->closing) || - (sock->server != NULL && !isc__nmsocket_active(sock->server))); -} - -static void -failed_accept_cb(isc_nmsocket_t *sock, isc_result_t eresult) { - REQUIRE(sock->accepting); - REQUIRE(sock->server); - - /* - * Detach the quota early to make room for other connections; - * otherwise it'd be detached later asynchronously, and clog - * the quota unnecessarily. - */ - if (sock->quota != NULL) { - isc_quota_detach(&sock->quota); - } - - isc__nmsocket_detach(&sock->server); - - sock->accepting = false; - - switch (eresult) { - case ISC_R_NOTCONNECTED: - /* IGNORE: The client disconnected before we could accept */ - break; - default: - isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, - ISC_LOGMODULE_NETMGR, ISC_LOG_ERROR, - "Accepting TCP connection failed: %s", - isc_result_totext(eresult)); - } -} - -static void -failed_connect_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req, - isc_result_t eresult) { - REQUIRE(VALID_NMSOCK(sock)); - REQUIRE(VALID_UVREQ(req)); - REQUIRE(sock->tid == isc_nm_tid()); - REQUIRE(atomic_load(&sock->connecting)); - REQUIRE(req->cb.connect != NULL); - - atomic_store(&sock->connecting, false); - - isc__nmsocket_clearcb(sock); - - isc__nm_connectcb(sock, req, eresult); - - isc__nmsocket_prep_destroy(sock); -} - static isc_result_t tlsdns_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { isc__networker_t *worker = NULL; @@ -344,12 +238,12 @@ tlsdns_connect_cb(uv_connect_t *uvreq, i /* * */ - r = BIO_new_bio_pair(&sock->tls.ssl_wbio, TLS_BUF_SIZE, - &sock->tls.app_rbio, TLS_BUF_SIZE); + r = BIO_new_bio_pair(&sock->tls.ssl_wbio, ISC_NETMGR_TLSBUF_SIZE, + &sock->tls.app_rbio, ISC_NETMGR_TLSBUF_SIZE); RUNTIME_CHECK(r == 1); - r = BIO_new_bio_pair(&sock->tls.ssl_rbio, TLS_BUF_SIZE, - &sock->tls.app_wbio, TLS_BUF_SIZE); + r = BIO_new_bio_pair(&sock->tls.ssl_rbio, ISC_NETMGR_TLSBUF_SIZE, + &sock->tls.app_wbio, ISC_NETMGR_TLSBUF_SIZE); RUNTIME_CHECK(r == 1); #if HAVE_SSL_SET0_RBIO && HAVE_SSL_SET0_WBIO @@ -372,7 +266,8 @@ tlsdns_connect_cb(uv_connect_t *uvreq, i sock->tls.pending_req = req; - start_reading(sock); + isc__nm_process_sock_buffer(sock); + result = tls_cycle(sock); if (result != ISC_R_SUCCESS) { goto error; @@ -381,7 +276,7 @@ tlsdns_connect_cb(uv_connect_t *uvreq, i return; error: - failed_connect_cb(sock, req, result); + isc__nm_failed_connect_cb(sock, req, result); } isc_result_t @@ -704,7 +599,7 @@ tlsdns_connection_cb(uv_stream_t *server REQUIRE(VALID_NMSOCK(ssock)); REQUIRE(ssock->tid == isc_nm_tid()); - if (inactive(ssock)) { + if (isc__nm_inactive(ssock)) { result = ISC_R_CANCELED; goto done; } @@ -856,17 +751,18 @@ isc__nm_async_tlsdnsstop(isc__networker_ } } -static void -failed_read_cb(isc_nmsocket_t *sock, isc_result_t result) { +void +isc__nm_tlsdns_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result) { REQUIRE(VALID_NMSOCK(sock)); REQUIRE(result != ISC_R_SUCCESS); - stop_reading(sock); + isc__nmsocket_timer_stop(sock); + isc__nm_stop_reading(sock); if (sock->tls.pending_req) { isc__nm_uvreq_t *req = sock->tls.pending_req; sock->tls.pending_req = NULL; - failed_connect_cb(sock, req, ISC_R_CANCELED); + isc__nm_failed_connect_cb(sock, req, ISC_R_CANCELED); } if (!sock->recv_read) { @@ -875,7 +771,7 @@ failed_read_cb(isc_nmsocket_t *sock, isc sock->recv_read = false; if (sock->recv_cb != NULL) { - isc__nm_uvreq_t *req = get_read_req(sock); + isc__nm_uvreq_t *req = isc__nm_get_read_req(sock, NULL); isc__nmsocket_clearcb(sock); isc__nm_readcb(sock, req, result); } @@ -890,96 +786,6 @@ destroy: } } -static void -failed_send_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req, - isc_result_t eresult) { - REQUIRE(VALID_NMSOCK(sock)); - REQUIRE(VALID_UVREQ(req)); - - if (req->cb.send != NULL) { - isc__nm_sendcb(sock, req, eresult); - } else { - isc__nm_uvreq_put(&req, sock); - } -} - -static isc__nm_uvreq_t * -get_read_req(isc_nmsocket_t *sock) { - isc__nm_uvreq_t *req = NULL; - - req = isc__nm_uvreq_get(sock->mgr, sock); - req->cb.recv = sock->recv_cb; - req->cbarg = sock->recv_cbarg; - - if (atomic_load(&sock->client)) { - isc_nmhandle_attach(sock->statichandle, &req->handle); - } else { - req->handle = isc__nmhandle_get(sock, NULL, NULL); - } - - return (req); -} - -static void -readtimeout_cb(uv_timer_t *timer) { - isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)timer); - - REQUIRE(VALID_NMSOCK(sock)); - REQUIRE(sock->tid == isc_nm_tid()); - REQUIRE(sock->reading); - - /* - * Timeout; stop reading and process whatever we have. - */ - - failed_read_cb(sock, ISC_R_TIMEDOUT); -} - -static void -start_sock_timer(isc_nmsocket_t *sock) { - if (sock->read_timeout > 0) { - int r = uv_timer_start(&sock->timer, readtimeout_cb, - sock->read_timeout, 0); - RUNTIME_CHECK(r == 0); - } -} - -static void -stop_sock_timer(isc_nmsocket_t *sock) { - int r = uv_timer_stop(&sock->timer); - RUNTIME_CHECK(r == 0); -} - -static void -start_reading(isc_nmsocket_t *sock) { - int r; - - if (sock->reading) { - return; - } - - r = uv_read_start(&sock->uv_handle.stream, tlsdns_alloc_cb, read_cb); - RUNTIME_CHECK(r == 0); - sock->reading = true; - - start_sock_timer(sock); -} - -static void -stop_reading(isc_nmsocket_t *sock) { - int r; - - if (!sock->reading) { - return; - } - - r = uv_read_stop(&sock->uv_handle.stream); - RUNTIME_CHECK(r == 0); - sock->reading = false; - - stop_sock_timer(sock); -} - void isc__nm_tlsdns_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) { REQUIRE(VALID_NMHANDLE(handle)); @@ -1017,38 +823,6 @@ isc__nm_tlsdns_read(isc_nmhandle_t *hand return; } -/*%< - * Allocator for TCP read operations. Limited to size 2^16. - * - * Note this doesn't actually allocate anything, it just assigns the - * worker's receive buffer to a socket, and marks it as "in use". - */ -static void -tlsdns_alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf) { - isc_nmsocket_t *sock = uv_handle_get_data(handle); - isc__networker_t *worker = NULL; - - REQUIRE(VALID_NMSOCK(sock)); - REQUIRE(sock->type == isc_nm_tlsdnssocket); - REQUIRE(isc__nm_in_netthread()); - - /* - * We need to limit the individual chunks to be read, so the BIO_write() - * will always succeed and the consumed before the next readcb is - * called. - */ - if (size >= TLS_BUF_SIZE) { - size = TLS_BUF_SIZE; - } - - worker = &sock->mgr->workers[sock->tid]; - INSIST(!worker->recvbuf_inuse); - - buf->base = worker->recvbuf; - buf->len = size; - worker->recvbuf_inuse = true; -} - void isc__nm_async_tlsdnsread(isc__networker_t *worker, isc__netievent_t *ev0) { isc__netievent_tlsdnsread_t *ievent = @@ -1061,16 +835,15 @@ isc__nm_async_tlsdnsread(isc__networker_ REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->tid == isc_nm_tid()); - if (inactive(sock)) { + if (isc__nm_inactive(sock)) { sock->reading = true; - failed_read_cb(sock, ISC_R_CANCELED); + isc__nm_failed_read_cb(sock, ISC_R_CANCELED); return; } result = tls_cycle(sock); if (result != ISC_R_SUCCESS) { - stop_reading(sock); - failed_read_cb(sock, result); + isc__nm_failed_read_cb(sock, result); } } @@ -1083,8 +856,8 @@ isc__nm_async_tlsdnsread(isc__networker_ * * The caller will need to unreference the handle. */ -static isc_result_t -processbuffer(isc_nmsocket_t *sock) { +isc_result_t +isc__nm_tlsdns_processbuffer(isc_nmsocket_t *sock) { size_t len; isc__nm_uvreq_t *req = NULL; isc_nmhandle_t *handle = NULL; @@ -1092,7 +865,7 @@ processbuffer(isc_nmsocket_t *sock) { REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->tid == isc_nm_tid()); - if (inactive(sock)) { + if (isc__nm_inactive(sock)) { return (ISC_R_CANCELED); } @@ -1113,7 +886,7 @@ processbuffer(isc_nmsocket_t *sock) { return (ISC_R_NOMORE); } - req = get_read_req(sock); + req = isc__nm_get_read_req(sock, NULL); REQUIRE(VALID_UVREQ(req)); /* @@ -1170,12 +943,13 @@ tls_cycle_input(isc_nmsocket_t *sock) { (void)SSL_peek(sock->tls.ssl, &(char){ '\0' }, 0); int pending = SSL_pending(sock->tls.ssl); - if (pending > TLS_BUF_SIZE) { - pending = TLS_BUF_SIZE; + if (pending > ISC_NETMGR_TLSBUF_SIZE) { + pending = ISC_NETMGR_TLSBUF_SIZE; } if ((sock->buf_len + pending) > sock->buf_size) { - alloc_dnsbuf(sock, sock->buf_len + pending); + isc__nm_alloc_dnsbuf(sock, + sock->buf_len + pending); } len = 0; @@ -1184,7 +958,7 @@ tls_cycle_input(isc_nmsocket_t *sock) { sock->buf_size - sock->buf_len, &len); if (rv != 1) { /* Process what's in the buffer so far */ - process_sock_buffer(sock); + isc__nm_process_sock_buffer(sock); /* FIXME: Should we call failed_read_cb()? */ break; @@ -1194,7 +968,7 @@ tls_cycle_input(isc_nmsocket_t *sock) { sock->buf_len += len; - process_sock_buffer(sock); + isc__nm_process_sock_buffer(sock); } } else if (!SSL_is_init_finished(sock->tls.ssl)) { if (SSL_is_server(sock->tls.ssl)) { @@ -1216,7 +990,7 @@ tls_cycle_input(isc_nmsocket_t *sock) { if (sock->tls.state == TLS_STATE_NONE && !SSL_is_init_finished(sock->tls.ssl)) { sock->tls.state = TLS_STATE_HANDSHAKE; - start_reading(sock); + isc__nm_process_sock_buffer(sock); } /* else continue reading */ break; @@ -1269,10 +1043,9 @@ static void tls_error(isc_nmsocket_t *sock, isc_result_t result) { switch (sock->tls.state) { case TLS_STATE_HANDSHAKE: - stop_reading(sock); - break; case TLS_STATE_IO: - stop_reading(sock); + isc__nmsocket_timer_stop(sock); + isc__nm_stop_reading(sock); break; case TLS_STATE_ERROR: return; @@ -1336,8 +1109,8 @@ tls_cycle_output(isc_nmsocket_t *sock) { break; } - if (pending > TLS_BUF_SIZE) { - pending = TLS_BUF_SIZE; + if (pending > ISC_NETMGR_TLSBUF_SIZE) { + pending = ISC_NETMGR_TLSBUF_SIZE; } sock->tls.senddata.base = isc_mem_get(sock->mgr->mctx, pending); @@ -1468,8 +1241,9 @@ isc__nm_async_tlsdnscycle(isc__networker } } -static void -read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { +void +isc__nm_tlsdns_read_cb(uv_stream_t *stream, ssize_t nread, + const uv_buf_t *buf) { isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)stream); size_t len; isc_result_t result; @@ -1480,8 +1254,8 @@ read_cb(uv_stream_t *stream, ssize_t nre REQUIRE(sock->reading); REQUIRE(buf != NULL); - if (inactive(sock)) { - failed_read_cb(sock, ISC_R_CANCELED); + if (isc__nm_inactive(sock)) { + isc__nm_failed_read_cb(sock, ISC_R_CANCELED); goto free; } @@ -1491,7 +1265,7 @@ read_cb(uv_stream_t *stream, ssize_t nre sock->statsindex[STATID_RECVFAIL]); } - failed_read_cb(sock, isc__nm_uverr2result(nread)); + isc__nm_failed_read_cb(sock, isc__nm_uverr2result(nread)); goto free; } @@ -1506,13 +1280,13 @@ read_cb(uv_stream_t *stream, ssize_t nre rv = BIO_write_ex(sock->tls.app_wbio, buf->base, (size_t)nread, &len); if (rv <= 0 || (size_t)nread != len) { - failed_read_cb(sock, ISC_R_TLSERROR); + isc__nm_failed_read_cb(sock, ISC_R_TLSERROR); goto free; } result = tls_cycle(sock); if (result != ISC_R_SUCCESS) { - failed_read_cb(sock, result); + isc__nm_failed_read_cb(sock, result); } free: async_tlsdns_cycle(sock); @@ -1576,7 +1350,7 @@ accept_connection(isc_nmsocket_t *ssock, REQUIRE(VALID_NMSOCK(ssock)); REQUIRE(ssock->tid == isc_nm_tid()); - if (inactive(ssock)) { + if (isc__nm_inactive(ssock)) { if (quota != NULL) { isc_quota_detach("a); } @@ -1669,12 +1443,12 @@ accept_connection(isc_nmsocket_t *ssock, RUNTIME_CHECK(csock->tls.ssl != NULL); - r = BIO_new_bio_pair(&csock->tls.ssl_wbio, TLS_BUF_SIZE, - &csock->tls.app_rbio, TLS_BUF_SIZE); + r = BIO_new_bio_pair(&csock->tls.ssl_wbio, ISC_NETMGR_TLSBUF_SIZE, + &csock->tls.app_rbio, ISC_NETMGR_TLSBUF_SIZE); RUNTIME_CHECK(r == 1); - r = BIO_new_bio_pair(&csock->tls.ssl_rbio, TLS_BUF_SIZE, - &csock->tls.app_wbio, TLS_BUF_SIZE); + r = BIO_new_bio_pair(&csock->tls.ssl_rbio, ISC_NETMGR_TLSBUF_SIZE, + &csock->tls.app_wbio, ISC_NETMGR_TLSBUF_SIZE); RUNTIME_CHECK(r == 1); #if HAVE_SSL_SET0_RBIO && HAVE_SSL_SET0_WBIO @@ -1700,7 +1474,7 @@ accept_connection(isc_nmsocket_t *ssock, csock->read_timeout = atomic_load(&csock->mgr->init); - csock->closehandle_cb = resume_processing; + csock->closehandle_cb = isc__nm_resume_processing; /* * We need to keep the handle alive until we fail to read or connection @@ -1719,7 +1493,7 @@ accept_connection(isc_nmsocket_t *ssock, isc_nmhandle_detach(&handle); - start_reading(csock); + isc__nm_process_sock_buffer(csock); /* * sock is now attached to the handle. @@ -1731,7 +1505,7 @@ accept_connection(isc_nmsocket_t *ssock, failure: atomic_store(&csock->active, false); - failed_accept_cb(csock, result); + isc__nm_failed_accept_cb(csock, result); isc__nmsocket_prep_destroy(csock); @@ -1787,7 +1561,7 @@ isc__nm_async_tlsdnssend(isc__networker_ result = tlsdns_send_direct(sock, uvreq); if (result != ISC_R_SUCCESS) { isc__nm_incstats(sock->mgr, sock->statsindex[STATID_SENDFAIL]); - failed_send_cb(sock, uvreq, result); + isc__nm_failed_send_cb(sock, uvreq, result); } } @@ -1818,7 +1592,7 @@ tlsdns_send_direct(isc_nmsocket_t *sock, return (result); } - if (inactive(sock)) { + if (isc__nm_inactive(sock)) { return (ISC_R_CANCELED); } @@ -1842,7 +1616,7 @@ tlsdns_send_direct(isc_nmsocket_t *sock, /* SSL_write_ex() doesn't do partial writes */ INSIST(sendlen == bytes); - isc__nm_sendcb(sock, req, ISC_R_SUCCESS); + isc__nm_sendcb(sock, req, ISC_R_SUCCESS, true); async_tlsdns_cycle(sock); return (ISC_R_SUCCESS); } @@ -2012,7 +1786,8 @@ tlsdns_close_direct(isc_nmsocket_t *sock isc_nmhandle_detach(&sock->recv_handle); } - stop_reading(sock); + isc__nmsocket_timer_stop(sock); + isc__nm_stop_reading(sock); uv_close((uv_handle_t *)&sock->timer, timer_close_cb); } @@ -2076,11 +1851,11 @@ isc__nm_tlsdns_shutdown(isc_nmsocket_t * if (sock->tls.pending_req) { isc__nm_uvreq_t *req = sock->tls.pending_req; sock->tls.pending_req = NULL; - failed_connect_cb(sock, req, ISC_R_CANCELED); + isc__nm_failed_connect_cb(sock, req, ISC_R_CANCELED); } if (sock->statichandle) { - failed_read_cb(sock, ISC_R_CANCELED); + isc__nm_failed_read_cb(sock, ISC_R_CANCELED); return; } @@ -2120,22 +1895,7 @@ isc__nm_async_tlsdnscancel(isc__networke REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->tid == isc_nm_tid()); - failed_read_cb(sock, ISC_R_EOF); -} - -void -isc__nm_tlsdns_settimeout(isc_nmhandle_t *handle, uint32_t timeout) { - isc_nmsocket_t *sock = NULL; - - REQUIRE(VALID_NMHANDLE(handle)); - REQUIRE(VALID_NMSOCK(handle->sock)); - - sock = handle->sock; - - sock->read_timeout = timeout; - if (uv_is_active((uv_handle_t *)&sock->timer)) { - start_sock_timer(sock); - } + isc__nm_failed_read_cb(sock, ISC_R_EOF); } void @@ -2157,7 +1917,8 @@ isc_nm_tlsdns_sequential(isc_nmhandle_t * is released. */ - stop_reading(sock); + isc__nmsocket_timer_stop(sock); + isc__nm_stop_reading(sock); atomic_store(&sock->sequential, true); } @@ -2173,65 +1934,3 @@ isc_nm_tlsdns_keepalive(isc_nmhandle_t * atomic_store(&sock->keepalive, value); } - -static void -process_sock_buffer(isc_nmsocket_t *sock) { - /* - * 1. When process_buffer receives incomplete DNS message, - * we don't touch any timers - * - * 2. When we receive at least one full DNS message, we stop the timers - * until resume_processing calls this function again and restarts the - * reading and the timers - */ - - /* - * Process a DNS messages. Stop if this is client socket, or the server - * socket has been set to sequential mode or the number of queries we - * are processing simultaneously have reached the clients-per-connection - * limit. - */ - for (;;) { - isc_result_t result = processbuffer(sock); - switch (result) { - case ISC_R_NOMORE: - start_reading(sock); - return; - case ISC_R_CANCELED: - stop_reading(sock); - return; - case ISC_R_SUCCESS: - if (atomic_load(&sock->client) || - atomic_load(&sock->sequential) || - atomic_load(&sock->ah) >= TLSDNS_CLIENTS_PER_CONN) - { - stop_reading(sock); - return; - } - break; - default: - INSIST(0); - } - } -} - -static void -resume_processing(void *arg) { - isc_nmsocket_t *sock = (isc_nmsocket_t *)arg; - - REQUIRE(VALID_NMSOCK(sock)); - REQUIRE(sock->tid == isc_nm_tid()); - REQUIRE(sock->type == isc_nm_tlsdnssocket); - REQUIRE(!atomic_load(&sock->client)); - - if (inactive(sock)) { - return; - } - - if (atomic_load(&sock->ah) == 0) { - /* Nothing is active; sockets can timeout now */ - start_sock_timer(sock); - } - - process_sock_buffer(sock); -} diff -Naurp bind-9.16.13.orig/lib/isc/netmgr/udp.c bind-9.16.13/lib/isc/netmgr/udp.c --- bind-9.16.13.orig/lib/isc/netmgr/udp.c 2021-03-11 07:20:59.000000000 -0600 +++ bind-9.16.13/lib/isc/netmgr/udp.c 2021-03-24 19:19:28.001922739 -0500 @@ -51,32 +51,10 @@ static void udp_close_direct(isc_nmsocket_t *sock); static void -failed_read_cb(isc_nmsocket_t *sock, isc_result_t result); - -static void -failed_send_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req, - isc_result_t eresult); - -static void stop_udp_parent(isc_nmsocket_t *sock); static void stop_udp_child(isc_nmsocket_t *sock); -static void -start_reading(isc_nmsocket_t *sock); -static void -stop_reading(isc_nmsocket_t *sock); - -static isc__nm_uvreq_t * -get_read_req(isc_nmsocket_t *sock, isc_sockaddr_t *sockaddr); - -static bool -inactive(isc_nmsocket_t *sock) { - return (!isc__nmsocket_active(sock) || - atomic_load(&sock->mgr->closing) || - (sock->server != NULL && !isc__nmsocket_active(sock->server))); -} - static uv_os_sock_t isc__nm_udp_lb_socket(sa_family_t sa_family) { isc_result_t result; @@ -192,32 +170,6 @@ isc_nm_listenudp(isc_nm_t *mgr, isc_nmif return (result); } -/*%< - * Allocator for UDP recv operations. Limited to size 20 * (2^16 + 2), - * which allows enough space for recvmmsg() to get multiple messages at - * a time. - * - * Note this doesn't actually allocate anything, it just assigns the - * worker's receive buffer to a socket, and marks it as "in use". - */ -static void -udp_alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf) { - isc_nmsocket_t *sock = uv_handle_get_data(handle); - isc__networker_t *worker = NULL; - - REQUIRE(VALID_NMSOCK(sock)); - REQUIRE(sock->type == isc_nm_udpsocket); - REQUIRE(isc__nm_in_netthread()); - REQUIRE(size <= ISC_NETMGR_RECVBUF_SIZE); - - worker = &sock->mgr->workers[sock->tid]; - INSIST(!worker->recvbuf_inuse); - - buf->base = worker->recvbuf; - buf->len = ISC_NETMGR_RECVBUF_SIZE; - worker->recvbuf_inuse = true; -} - /* * Asynchronous 'udplisten' call handler: start listening on a UDP socket. */ @@ -306,7 +258,8 @@ isc__nm_async_udplisten(isc__networker_t uv_send_buffer_size(&sock->uv_handle.handle, &(int){ ISC_SEND_BUFFER_SIZE }); #endif - r = uv_udp_recv_start(&sock->uv_handle.udp, udp_alloc_cb, udp_recv_cb); + r = uv_udp_recv_start(&sock->uv_handle.udp, isc__nm_alloc_cb, + udp_recv_cb); if (r != 0) { isc__nm_incstats(sock->mgr, sock->statsindex[STATID_BINDFAIL]); goto done; @@ -430,7 +383,7 @@ udp_recv_cb(uv_udp_t *handle, ssize_t nr * we can free the buffer and bail. */ if (addr == NULL) { - failed_read_cb(sock, ISC_R_EOF); + isc__nm_failed_read_cb(sock, ISC_R_EOF); goto free; } @@ -438,19 +391,19 @@ udp_recv_cb(uv_udp_t *handle, ssize_t nr * - If the socket is no longer active. */ if (!isc__nmsocket_active(sock)) { - failed_read_cb(sock, ISC_R_CANCELED); + isc__nm_failed_read_cb(sock, ISC_R_CANCELED); goto free; } if (nrecv < 0) { - failed_read_cb(sock, isc__nm_uverr2result(nrecv)); + isc__nm_failed_read_cb(sock, isc__nm_uverr2result(nrecv)); goto free; } result = isc_sockaddr_fromsockaddr(&sockaddr, addr); RUNTIME_CHECK(result == ISC_R_SUCCESS); - req = get_read_req(sock, &sockaddr); + req = isc__nm_get_read_req(sock, &sockaddr); /* * The callback will be called synchronously, because result is @@ -570,15 +523,15 @@ isc__nm_async_udpsend(isc__networker_t * REQUIRE(sock->tid == isc_nm_tid()); UNUSED(worker); - if (inactive(sock)) { - failed_send_cb(sock, uvreq, ISC_R_CANCELED); + if (isc__nm_inactive(sock)) { + isc__nm_failed_send_cb(sock, uvreq, ISC_R_CANCELED); return; } result = udp_send_direct(sock, uvreq, &ievent->peer); if (result != ISC_R_SUCCESS) { isc__nm_incstats(sock->mgr, sock->statsindex[STATID_SENDFAIL]); - failed_send_cb(sock, uvreq, result); + isc__nm_failed_send_cb(sock, uvreq, result); } } @@ -596,7 +549,7 @@ udp_send_cb(uv_udp_send_t *req, int stat isc__nm_incstats(sock->mgr, sock->statsindex[STATID_SENDFAIL]); } - isc__nm_sendcb(sock, uvreq, result); + isc__nm_sendcb(sock, uvreq, result, false); } /* @@ -614,7 +567,7 @@ udp_send_direct(isc_nmsocket_t *sock, is REQUIRE(sock->tid == isc_nm_tid()); REQUIRE(sock->type == isc_nm_udpsocket); - if (inactive(sock)) { + if (isc__nm_inactive(sock)) { return (ISC_R_CANCELED); } @@ -839,9 +792,9 @@ isc_nm_udpconnect(isc_nm_t *mgr, isc_nmi return (result); } -static void -udp_read_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf, - const struct sockaddr *addr, unsigned flags) { +void +isc__nm_udp_read_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf, + const struct sockaddr *addr, unsigned flags) { isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)handle); REQUIRE(VALID_NMSOCK(sock)); @@ -854,17 +807,17 @@ udp_read_cb(uv_udp_t *handle, ssize_t nr * does not. */ if (!sock->parent) { - stop_reading(sock); + isc__nm_stop_reading(sock); } } -static void -failed_read_cb(isc_nmsocket_t *sock, isc_result_t result) { +void +isc__nm_udp_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result) { REQUIRE(VALID_NMSOCK(sock)); REQUIRE(result != ISC_R_SUCCESS); if (atomic_load(&sock->client)) { - stop_reading(sock); + isc__nm_stop_reading(sock); if (!sock->recv_read) { goto destroy; @@ -872,7 +825,7 @@ failed_read_cb(isc_nmsocket_t *sock, isc sock->recv_read = false; if (sock->recv_cb != NULL) { - isc__nm_uvreq_t *req = get_read_req(sock, NULL); + isc__nm_uvreq_t *req = isc__nm_get_read_req(sock, NULL); isc__nmsocket_clearcb(sock); isc__nm_readcb(sock, req, result); } @@ -895,55 +848,11 @@ failed_read_cb(isc_nmsocket_t *sock, isc sock->recv_read = false; if (sock->recv_cb != NULL) { - isc__nm_uvreq_t *req = get_read_req(sock, NULL); + isc__nm_uvreq_t *req = isc__nm_get_read_req(sock, NULL); isc__nm_readcb(sock, req, result); } } -static void -failed_send_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req, - isc_result_t eresult) { - REQUIRE(VALID_NMSOCK(sock)); - REQUIRE(VALID_UVREQ(req)); - - if (req->cb.send != NULL) { - isc__nm_sendcb(sock, req, eresult); - } else { - isc__nm_uvreq_put(&req, sock); - } -} - -static isc__nm_uvreq_t * -get_read_req(isc_nmsocket_t *sock, isc_sockaddr_t *sockaddr) { - isc__nm_uvreq_t *req = NULL; - - req = isc__nm_uvreq_get(sock->mgr, sock); - req->cb.recv = sock->recv_cb; - req->cbarg = sock->recv_cbarg; - - if (atomic_load(&sock->client)) { - isc_nmhandle_attach(sock->statichandle, &req->handle); - } else { - req->handle = isc__nmhandle_get(sock, sockaddr, NULL); - } - - return req; -} - -static void -readtimeout_cb(uv_timer_t *handle) { - isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)handle); - - REQUIRE(VALID_NMSOCK(sock)); - REQUIRE(sock->tid == isc_nm_tid()); - REQUIRE(sock->reading); - - /* - * Timeout; stop reading and process whatever we have. - */ - failed_read_cb(sock, ISC_R_TIMEDOUT); -} - /* * Asynchronous 'udpread' call handler: start or resume reading on a * socket; pause reading and call the 'recv' callback after each @@ -959,55 +868,14 @@ isc__nm_async_udpread(isc__networker_t * REQUIRE(VALID_NMSOCK(sock)); REQUIRE(sock->tid == isc_nm_tid()); - if (inactive(sock)) { + if (isc__nm_inactive(sock)) { sock->reading = true; - failed_read_cb(sock, ISC_R_CANCELED); + isc__nm_failed_read_cb(sock, ISC_R_CANCELED); return; } - start_reading(sock); -} - -static void -start_sock_timer(isc_nmsocket_t *sock) { - if (sock->read_timeout > 0) { - int r = uv_timer_start(&sock->timer, readtimeout_cb, - sock->read_timeout, 0); - REQUIRE(r == 0); - } -} - -static void -stop_sock_timer(isc_nmsocket_t *sock) { - int r = uv_timer_stop(&sock->timer); - REQUIRE(r == 0); -} - -static void -start_reading(isc_nmsocket_t *sock) { - if (sock->reading) { - return; - } - - int r = uv_udp_recv_start(&sock->uv_handle.udp, udp_alloc_cb, - udp_read_cb); - REQUIRE(r == 0); - sock->reading = true; - - start_sock_timer(sock); -} - -static void -stop_reading(isc_nmsocket_t *sock) { - if (!sock->reading) { - return; - } - - int r = uv_udp_recv_stop(&sock->uv_handle.udp); - REQUIRE(r == 0); - sock->reading = false; - - stop_sock_timer(sock); + isc__nm_start_reading(sock); + isc__nmsocket_timer_start(sock); } void @@ -1217,7 +1085,7 @@ isc__nm_udp_shutdown(isc_nmsocket_t *soc * interested in the callback. */ if (sock->statichandle) { - failed_read_cb(sock, ISC_R_CANCELED); + isc__nm_failed_read_cb(sock, ISC_R_CANCELED); return; } @@ -1261,18 +1129,5 @@ isc__nm_async_udpcancel(isc__networker_t REQUIRE(sock->tid == isc_nm_tid()); REQUIRE(atomic_load(&sock->client)); - failed_read_cb(sock, ISC_R_EOF); -} - -void -isc__nm_udp_settimeout(isc_nmhandle_t *handle, uint32_t timeout) { - REQUIRE(VALID_NMHANDLE(handle)); - REQUIRE(VALID_NMSOCK(handle->sock)); - - isc_nmsocket_t *sock = handle->sock; - - sock->read_timeout = timeout; - if (uv_is_active((uv_handle_t *)&sock->timer)) { - start_sock_timer(sock); - } + isc__nm_failed_read_cb(sock, ISC_R_EOF); } diff -Naurp bind-9.16.13.orig/lib/isc/tests/Kyuafile bind-9.16.13/lib/isc/tests/Kyuafile --- bind-9.16.13.orig/lib/isc/tests/Kyuafile 2021-03-11 07:20:59.000000000 -0600 +++ bind-9.16.13/lib/isc/tests/Kyuafile 2021-03-24 18:29:30.987855915 -0500 @@ -29,4 +29,3 @@ tap_test_program{name='task_test'} tap_test_program{name='taskpool_test'} tap_test_program{name='time_test'} tap_test_program{name='timer_test'} -tap_test_program{name='tlsdns_test'} diff -Naurp bind-9.16.13.orig/lib/isc/tests/tcpdns_test.c bind-9.16.13/lib/isc/tests/tcpdns_test.c --- bind-9.16.13.orig/lib/isc/tests/tcpdns_test.c 2021-03-11 07:20:59.000000000 -0600 +++ bind-9.16.13/lib/isc/tests/tcpdns_test.c 2021-03-24 18:29:48.070679159 -0500 @@ -242,7 +242,6 @@ nm_setup(void **state) { for (size_t i = 0; i < MAX_NM; i++) { nm[i] = isc_nm_start(test_mctx, nworkers); assert_non_null(nm[i]); - isc_nm_settimeouts(nm[i], 1000, 1000, 1000, 1000); } *state = nm; diff -Naurp bind-9.16.13.orig/lib/isc/tests/tlsdns_test.c bind-9.16.13/lib/isc/tests/tlsdns_test.c --- bind-9.16.13.orig/lib/isc/tests/tlsdns_test.c 2021-03-11 07:20:59.000000000 -0600 +++ bind-9.16.13/lib/isc/tests/tlsdns_test.c 2021-03-24 18:30:00.226553698 -0500 @@ -249,7 +249,6 @@ nm_setup(void **state) { for (size_t i = 0; i < MAX_NM; i++) { nm[i] = isc_nm_start(test_mctx, nworkers); assert_non_null(nm[i]); - isc_nm_settimeouts(nm[i], 1000, 1000, 1000, 1000); } *state = nm; diff -Naurp bind-9.16.13.orig/lib/isc/win32/libisc.def.in bind-9.16.13/lib/isc/win32/libisc.def.in --- bind-9.16.13.orig/lib/isc/win32/libisc.def.in 2021-03-11 07:20:59.000000000 -0600 +++ bind-9.16.13/lib/isc/win32/libisc.def.in 2021-03-24 18:30:19.265357737 -0500 @@ -450,6 +450,7 @@ isc_netaddr_unspec isc_netscope_pton isc__nmhandle_attach isc__nmhandle_detach +isc_nmhandle_cleartimeout isc_nmhandle_getdata isc_nmhandle_getextra isc_nmhandle_is_stream diff -Naurp bind-9.16.13.orig/lib/ns/client.c bind-9.16.13/lib/ns/client.c --- bind-9.16.13.orig/lib/ns/client.c 2021-03-11 07:20:59.000000000 -0600 +++ bind-9.16.13/lib/ns/client.c 2021-03-24 18:30:54.679994833 -0500 @@ -1037,6 +1037,7 @@ no_nsid: isc_nm_gettimeouts(isc_nmhandle_netmgr(client->handle), NULL, NULL, NULL, &adv); + adv /= 100; /* units of 100 milliseconds */ isc_buffer_init(&buf, advtimo, sizeof(advtimo)); isc_buffer_putuint16(&buf, (uint16_t)adv); ednsopts[count].code = DNS_OPT_TCP_KEEPALIVE; diff -Naurp bind-9.16.13.orig/.pylintrc bind-9.16.13/.pylintrc --- bind-9.16.13.orig/.pylintrc 2021-03-11 07:20:59.000000000 -0600 +++ bind-9.16.13/.pylintrc 2021-03-24 18:31:23.344702559 -0500 @@ -5,3 +5,4 @@ disable= C0116, # missing-function-docstring R0801, # duplicate-code C0103, # invalid-name + C0415, # import-outside-toplevel