Commit 64cff61c authored by Ondřej Surý's avatar Ondřej Surý
Browse files

Add TCP timeouts system test

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
parent 2edba877
......@@ -5,3 +5,4 @@ disable=
C0116, # missing-function-docstring
R0801, # duplicate-code
C0103, # invalid-name
C0415,# import-outside-toplevel
......@@ -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
......
#!/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
############################################################################
# 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
; 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
/*
* 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;
};
; 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
#!/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
#!/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
#!/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
......@@ -892,6 +892,11 @@
./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
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment