bind9/bin/tests/system/timeouts/tests-tcp.py
Ondřej Surý 94a32eaf29 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
2021-03-18 15:16:13 +01:00

161 lines
4.9 KiB
Python

#!/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