]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Add TCP timeouts system test
authorOndřej Surý <ondrej@sury.org>
Wed, 17 Mar 2021 11:20:40 +0000 (12:20 +0100)
committerOndřej Surý <ondrej@sury.org>
Thu, 18 Mar 2021 15:37:57 +0000 (16:37 +0100)
The system tests were missing a test that would test tcp-initial-timeout
and tcp-idle-timeout.

This commit adds new "timeouts" system test that adds:

  * Test that waits longer than tcp-initial-timeout and then checks
    whether the socket was closed

  * Test that sends and receives DNS message then waits longer than
    tcp-initial-timeout but shorter time than tcp-idle-timeout than
    sends DNS message again than waits longer than tcp-idle-timeout
    and checks whether the socket was closed

  * Similar test, but bursting 25 DNS messages than waiting longer than
    tcp-initial-timeout and shorter than tcp-idle-timeout than do second
    25 DNS message burst

  * Check whether transfer longer than tcp-initial-timeout succeeds

.pylintrc
bin/tests/system/Makefile.am
bin/tests/system/timeouts/clean.sh [new file with mode: 0644]
bin/tests/system/timeouts/conftest.py [new file with mode: 0644]
bin/tests/system/timeouts/ns1/example.db [new file with mode: 0644]
bin/tests/system/timeouts/ns1/named.conf.in [new file with mode: 0644]
bin/tests/system/timeouts/ns1/root.db [new file with mode: 0644]
bin/tests/system/timeouts/prereq.sh [new file with mode: 0644]
bin/tests/system/timeouts/setup.sh [new file with mode: 0644]
bin/tests/system/timeouts/tests-tcp.py [new file with mode: 0644]
util/copyrights

index 750e50e37cb4e7451df81fc1b38b616fc434b832..178a06a801dd67f02674a76d5b6815f876635b00 100644 (file)
--- a/.pylintrc
+++ b/.pylintrc
@@ -5,3 +5,4 @@ disable=
     C0116, # missing-function-docstring
     R0801, # duplicate-code
     C0103, # invalid-name
+    C0415,# import-outside-toplevel
index a407716c04df142f94ae019120772782277d15ae..d5e18c3f3fda0378ba55356ba8655b97c15a3ae9 100644 (file)
@@ -201,7 +201,7 @@ if HAVE_PYTHON
 TESTS += kasp tcp pipelined
 
 if HAVE_PYMOD_DNS
-TESTS += qmin cookie
+TESTS += qmin cookie timeouts
 
 if HAVE_PERLMOD_NET_DNS
 TESTS += dnssec
diff --git a/bin/tests/system/timeouts/clean.sh b/bin/tests/system/timeouts/clean.sh
new file mode 100644 (file)
index 0000000..b177285
--- /dev/null
@@ -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 -rf ./.cache ./__pycache__
+rm -f ./ns*/large.db
diff --git a/bin/tests/system/timeouts/conftest.py b/bin/tests/system/timeouts/conftest.py
new file mode 100644 (file)
index 0000000..368fe9c
--- /dev/null
@@ -0,0 +1,59 @@
+############################################################################
+# 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="need 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="need 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 --git a/bin/tests/system/timeouts/ns1/example.db b/bin/tests/system/timeouts/ns1/example.db
new file mode 100644 (file)
index 0000000..310a31b
--- /dev/null
@@ -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 --git a/bin/tests/system/timeouts/ns1/named.conf.in b/bin/tests/system/timeouts/ns1/named.conf.in
new file mode 100644 (file)
index 0000000..7923524
--- /dev/null
@@ -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 http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+include "../../common/rndc.key";
+
+controls {
+       inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
+
+options {
+       query-source address 10.53.0.1;
+       notify-source 10.53.0.1;
+       transfer-source 10.53.0.1;
+       port @PORT@;
+       pid-file "named.pid";
+       listen-on { 10.53.0.1; };
+       listen-on-v6 { none; };
+       recursion no;
+       notify 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 --git a/bin/tests/system/timeouts/ns1/root.db b/bin/tests/system/timeouts/ns1/root.db
new file mode 100644 (file)
index 0000000..2c481ea
--- /dev/null
@@ -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 --git a/bin/tests/system/timeouts/prereq.sh b/bin/tests/system/timeouts/prereq.sh
new file mode 100644 (file)
index 0000000..9f4e7cd
--- /dev/null
@@ -0,0 +1,28 @@
+#!/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
+
+if test -n "$PYTHON"
+then
+    if $PYTHON -c "from dns.query import send_tcp" 2> /dev/null
+    then
+        :
+    else
+        echo_i "This test requires 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 --git a/bin/tests/system/timeouts/setup.sh b/bin/tests/system/timeouts/setup.sh
new file mode 100644 (file)
index 0000000..2af68a2
--- /dev/null
@@ -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 the transfer takes longer than
+# 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 --git a/bin/tests/system/timeouts/tests-tcp.py b/bin/tests/system/timeouts/tests-tcp.py
new file mode 100644 (file)
index 0000000..03f69da
--- /dev/null
@@ -0,0 +1,161 @@
+#!/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 second, 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 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(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
+        (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)
+        assert soa is not None
+
+        # Pull DNS message from 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
index 06feaf151ba9087709299f673cdfd558c0c9ad84..aef7cbfb8c06c7aa911d096d5c01399a0392fa65 100644 (file)
 ./bin/tests/system/testsock.pl                 PERL    2000,2001,2004,2007,2010,2011,2012,2013,2016,2018,2019,2020,2021
 ./bin/tests/system/testsock6.pl                        PERL    2010,2012,2014,2016,2018,2019,2020,2021
 ./bin/tests/system/testsummary.sh              SH      2018,2019,2020,2021
+./bin/tests/system/timeouts/clean.sh           SH      2021
+./bin/tests/system/timeouts/conftest.py                PYTHON  2021
+./bin/tests/system/timeouts/prereq.sh          SH      2021
+./bin/tests/system/timeouts/setup.sh           SH      2021
+./bin/tests/system/timeouts/tests-tcp.py       PYTHON-BIN      2021
 ./bin/tests/system/tkey/clean.sh               SH      2001,2004,2007,2011,2012,2013,2014,2015,2016,2018,2019,2020,2021
 ./bin/tests/system/tkey/keycreate.c            C       2001,2004,2005,2007,2009,2011,2012,2014,2015,2016,2017,2018,2019,2020,2021
 ./bin/tests/system/tkey/keydelete.c            C       2001,2004,2005,2007,2009,2010,2011,2014,2015,2016,2017,2018,2019,2020,2021