Add query timeout for dns-rfc2136 plugin (#8268)

* Add timeout to DNS query function calls

* Modify tests to account for new timeout variable

* Add change to CHANGELOG

* Add `dns.exception.Timeout` to exception handler

* Move changelog to 1.10.0
This commit is contained in:
osirisinferi 2020-10-09 22:13:46 +02:00 committed by GitHub
parent 631c88b209
commit 725870d558
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 19 additions and 14 deletions

View file

@ -18,6 +18,7 @@ from certbot.plugins import dns_common
logger = logging.getLogger(__name__)
DEFAULT_NETWORK_TIMEOUT = 45
@zope.interface.implementer(interfaces.IAuthenticator)
@zope.interface.provider(interfaces.IPluginFactory)
@ -91,13 +92,15 @@ class _RFC2136Client(object):
"""
Encapsulates all communication with the target DNS server.
"""
def __init__(self, server, port, key_name, key_secret, key_algorithm):
def __init__(self, server, port, key_name, key_secret, key_algorithm,
timeout=DEFAULT_NETWORK_TIMEOUT):
self.server = server
self.port = port
self.keyring = dns.tsigkeyring.from_text({
key_name: key_secret
})
self.algorithm = key_algorithm
self._default_timeout = timeout
def add_txt_record(self, record_name, record_content, record_ttl):
"""
@ -122,7 +125,7 @@ class _RFC2136Client(object):
update.add(rel, record_ttl, dns.rdatatype.TXT, record_content)
try:
response = dns.query.tcp(update, self.server, port=self.port)
response = dns.query.tcp(update, self.server, self._default_timeout, self.port)
except Exception as e:
raise errors.PluginError('Encountered error adding TXT record: {0}'
.format(e))
@ -157,7 +160,7 @@ class _RFC2136Client(object):
update.delete(rel, dns.rdatatype.TXT, record_content)
try:
response = dns.query.tcp(update, self.server, port=self.port)
response = dns.query.tcp(update, self.server, self._default_timeout, self.port)
except Exception as e:
raise errors.PluginError('Encountered error deleting TXT record: {0}'
.format(e))
@ -207,10 +210,10 @@ class _RFC2136Client(object):
try:
try:
response = dns.query.tcp(request, self.server, port=self.port)
except OSError as e:
response = dns.query.tcp(request, self.server, self._default_timeout, self.port)
except (OSError, dns.exception.Timeout) as e:
logger.debug('TCP query failed, fallback to UDP: %s', e)
response = dns.query.udp(request, self.server, port=self.port)
response = dns.query.udp(request, self.server, self._default_timeout, self.port)
rcode = response.rcode()
# Authoritative Answer bit should be set

View file

@ -21,7 +21,7 @@ PORT = 53
NAME = 'a-tsig-key.'
SECRET = 'SSB3b25kZXIgd2hvIHdpbGwgYm90aGVyIHRvIGRlY29kZSB0aGlzIHRleHQK'
VALID_CONFIG = {"rfc2136_server": SERVER, "rfc2136_name": NAME, "rfc2136_secret": SECRET}
TIMEOUT = 45
class AuthenticatorTest(test_util.TempDirTestCase, dns_test_common.BaseAuthenticatorTest):
@ -78,7 +78,8 @@ class RFC2136ClientTest(unittest.TestCase):
def setUp(self):
from certbot_dns_rfc2136._internal.dns_rfc2136 import _RFC2136Client
self.rfc2136_client = _RFC2136Client(SERVER, PORT, NAME, SECRET, dns.tsig.HMAC_MD5)
self.rfc2136_client = _RFC2136Client(SERVER, PORT, NAME, SECRET, dns.tsig.HMAC_MD5,
TIMEOUT)
@mock.patch("dns.query.tcp")
def test_add_txt_record(self, query_mock):
@ -88,7 +89,7 @@ class RFC2136ClientTest(unittest.TestCase):
self.rfc2136_client.add_txt_record("bar", "baz", 42)
query_mock.assert_called_with(mock.ANY, SERVER, port=PORT)
query_mock.assert_called_with(mock.ANY, SERVER, TIMEOUT, PORT)
self.assertTrue("bar. 42 IN TXT \"baz\"" in str(query_mock.call_args[0][0]))
@mock.patch("dns.query.tcp")
@ -121,7 +122,7 @@ class RFC2136ClientTest(unittest.TestCase):
self.rfc2136_client.del_txt_record("bar", "baz")
query_mock.assert_called_with(mock.ANY, SERVER, port=PORT)
query_mock.assert_called_with(mock.ANY, SERVER, TIMEOUT, PORT)
self.assertTrue("bar. 0 NONE TXT \"baz\"" in str(query_mock.call_args[0][0]))
@mock.patch("dns.query.tcp")
@ -173,7 +174,7 @@ class RFC2136ClientTest(unittest.TestCase):
# _query_soa | pylint: disable=protected-access
result = self.rfc2136_client._query_soa(DOMAIN)
query_mock.assert_called_with(mock.ANY, SERVER, port=PORT)
query_mock.assert_called_with(mock.ANY, SERVER, TIMEOUT, PORT)
self.assertTrue(result)
@mock.patch("dns.query.tcp")
@ -183,7 +184,7 @@ class RFC2136ClientTest(unittest.TestCase):
# _query_soa | pylint: disable=protected-access
result = self.rfc2136_client._query_soa(DOMAIN)
query_mock.assert_called_with(mock.ANY, SERVER, port=PORT)
query_mock.assert_called_with(mock.ANY, SERVER, TIMEOUT, PORT)
self.assertFalse(result)
@mock.patch("dns.query.tcp")
@ -206,8 +207,8 @@ class RFC2136ClientTest(unittest.TestCase):
# _query_soa | pylint: disable=protected-access
result = self.rfc2136_client._query_soa(DOMAIN)
tcp_mock.assert_called_with(mock.ANY, SERVER, port=PORT)
udp_mock.assert_called_with(mock.ANY, SERVER, port=PORT)
tcp_mock.assert_called_with(mock.ANY, SERVER, TIMEOUT, PORT)
udp_mock.assert_called_with(mock.ANY, SERVER, TIMEOUT, PORT)
self.assertTrue(result)

View file

@ -6,6 +6,7 @@ Certbot adheres to [Semantic Versioning](https://semver.org/).
### Added
* Added timeout to DNS query function calls for dns-rfc2136 plugin.
*
### Changed