From 260b4c02cf3540e4a71b22f573958da24d89c7a2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= <ondrej@isc.org>
Date: Wed, 9 Feb 2022 12:46:29 +0100
Subject: [PATCH] Add TCP write timeout system test

Extend the timeouts system test that bursts the queries for large TXT
record and never read any responses back filling up the server TCP write
buffer.  The test should work with the default wmem_max value on
Linux (208k).

(cherry picked from commit b735182ae0912759f5576557ade7660f4ea9c949)
Conflict: NA
Reference: https://gitlab.isc.org/isc-projects/bind9/-/commit/260b4c02cf3540e4a71b22f573958da24d89c7a2
---
 bin/tests/system/timeouts/setup.sh     |  5 ++++
 bin/tests/system/timeouts/tests-tcp.py | 36 +++++++++++++++++++++++---
 2 files changed, 38 insertions(+), 3 deletions(-)

diff --git a/bin/tests/system/timeouts/setup.sh b/bin/tests/system/timeouts/setup.sh
index 2e8fd6a6ba..c4019d2a27 100644
--- a/bin/tests/system/timeouts/setup.sh
+++ b/bin/tests/system/timeouts/setup.sh
@@ -20,6 +20,11 @@ copy_setports ns1/named.conf.in ns1/named.conf
 # tcp-initial-timeout interval
 #
 $PYTHON -c "
+print('large IN TXT', end=' ')
+for a in range(128):
+    print('\"%s\"' % ('A' * 240), end=' ')
+print('')
+
 for a in range(150000):
     print('%s IN NS a' % (a))
     print('%s IN NS b' % (a))" > ns1/large.db
diff --git a/bin/tests/system/timeouts/tests-tcp.py b/bin/tests/system/timeouts/tests-tcp.py
index 2c5e99cc1c..e1f19608c8 100644
--- a/bin/tests/system/timeouts/tests-tcp.py
+++ b/bin/tests/system/timeouts/tests-tcp.py
@@ -51,7 +51,7 @@ def test_initial_timeout(port):
             try:
                 (sbytes, stime) = dns.query.send_tcp(sock, msg, timeout())
                 (response, rtime) = dns.query.receive_tcp(sock, timeout())
-            except ConnectionResetError as e:
+            except ConnectionError as e:
                 raise EOFError from e
 
 
@@ -83,7 +83,7 @@ def test_idle_timeout(port):
             try:
                 (sbytes, stime) = dns.query.send_tcp(sock, msg, timeout())
                 (response, rtime) = dns.query.receive_tcp(sock, timeout())
-            except ConnectionResetError as e:
+            except ConnectionError as e:
                 raise EOFError from e
 
 
@@ -152,7 +152,7 @@ def test_pipelining_timeout(port):
             try:
                 (sbytes, stime) = dns.query.send_tcp(sock, msg, timeout())
                 (response, rtime) = dns.query.receive_tcp(sock, timeout())
-            except ConnectionResetError as e:
+            except ConnectionError as e:
                 raise EOFError from e
 
 
@@ -190,3 +190,33 @@ def test_long_axfr(port):
             if soa is not None:
                 break
         assert soa is not None
+
+
+@pytest.mark.dnspython
+@pytest.mark.dnspython2
+def test_send_timeout(port):
+    import dns.query
+
+    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
+        sock.connect(("10.53.0.1", port))
+
+        # Send and receive single large RDATA over TCP
+        msg = create_msg("large.example.", "TXT")
+        (sbytes, stime) = dns.query.send_tcp(sock, msg, timeout())
+        (response, rtime) = dns.query.receive_tcp(sock, timeout())
+
+        # Send and receive 28 large (~32k) DNS queries that should
+        # fill the default maximum 208k TCP send buffer
+        for n in range(28):
+            (sbytes, stime) = dns.query.send_tcp(sock, msg, timeout())
+
+        # configure idle interval is 5 seconds, sleep 6 to make sure we are
+        # above the interval
+        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 ConnectionError as e:
+                raise EOFError from e
-- 
2.23.0

