From 70794c7b1d001ce331d4a64c77d23abcc02c541e Mon Sep 17 00:00:00 2001 From: Petr Spacek Date: Tue, 17 May 2016 17:28:36 +0200 Subject: Turn verify_host_resolvable() into a wrapper around ipapython.dnsutil The code was duplicate and less generic anyway. As a side-effect I had to re-wrap dns.exception.DNSException into a PublicError so it can be displayed to the user. DNSError is now a super class for other DNS-related errors. Errors from DNS resolver are re-raised as DNSResolverError. https://fedorahosted.org/freeipa/ticket/5710 Reviewed-By: Martin Basti --- ipalib/errors.py | 98 ++++++++++++++++++++++++++++++++++++-------------------- ipalib/util.py | 32 ++++-------------- 2 files changed, 71 insertions(+), 59 deletions(-) (limited to 'ipalib') diff --git a/ipalib/errors.py b/ipalib/errors.py index 93333c2aa..406a940e5 100644 --- a/ipalib/errors.py +++ b/ipalib/errors.py @@ -93,7 +93,9 @@ current block assignments: - **4300 - 4399** `CertificateError` and its subclasses - - **4400 - 4999** *Reserved for future use* + - **4400 - 4499** `DNSError` and (some of) its subclasses + + - **4500 - 4999** *Reserved for future use* - **5000 - 5999** `GenericError` and its subclasses @@ -1164,21 +1166,6 @@ class DefaultGroupError(ExecutionError): errno = 4018 format = _('The default users group cannot be removed') -class DNSNotARecordError(ExecutionError): - """ - **4019** Raised when a hostname is not a DNS A/AAAA record - - For example: - - >>> raise DNSNotARecordError() - Traceback (most recent call last): - ... - DNSNotARecordError: Host does not have corresponding DNS A/AAAA record - - """ - - errno = 4019 - format = _('Host does not have corresponding DNS A/AAAA record') class ManagedGroupError(ExecutionError): """ @@ -1598,24 +1585,6 @@ class DatabaseTimeout(DatabaseError): format = _('LDAP timeout') -class DNSDataMismatch(ExecutionError): - """ - **4212** Raised when an DNS query didn't return expected answer - in a configured time limit. - - For example: - - >>> raise DNSDataMismatch(expected="zone3.test. 86400 IN A 192.0.2.1", \ - got="zone3.test. 86400 IN A 192.168.1.1") - Traceback (most recent call last): - ... - DNSDataMismatch: DNS check failed: Expected {zone3.test. 86400 IN A 192.0.2.1} got {zone3.test. 86400 IN A 192.168.1.1} - """ - - errno = 4212 - format = _('DNS check failed: Expected {%(expected)s} got {%(got)s}') - - class TaskTimeout(DatabaseError): """ **4213** Raised when an LDAP task times out @@ -1833,6 +1802,67 @@ class CertificateInvalidError(CertificateError): format = _('%(name)s certificate is not valid') +class DNSError(ExecutionError): + """ + **4400** Base class for DNS execution errors (*4400 - 4499*). + These are typically wrapper exceptions around dns.exception.DNSException. + """ + + errno = 4400 + + +class DNSNotARecordError(DNSError): + """ + **4019** Raised when a hostname is not a DNS A/AAAA record + + For example: + + >>> raise DNSNotARecordError(hostname='x') + Traceback (most recent call last): + ... + DNSNotARecordError: Host 'x' does not have corresponding DNS A/AAAA record + + """ + + errno = 4019 # this exception was defined before DNSError + format = _( + 'Host \'%(hostname)s\' does not have corresponding DNS A/AAAA record') + + +class DNSDataMismatch(DNSError): + """ + **4212** Raised when an DNS query didn't return expected answer + in a configured time limit. + + For example: + + >>> raise DNSDataMismatch(expected="zone3.test. 86400 IN A 192.0.2.1", \ + got="zone3.test. 86400 IN A 192.168.1.1") + Traceback (most recent call last): + ... + DNSDataMismatch: DNS check failed: Expected {zone3.test. 86400 IN A 192.0.2.1} got {zone3.test. 86400 IN A 192.168.1.1} + """ + + errno = 4212 # this exception was defined before DNSError + format = _('DNS check failed: Expected {%(expected)s} got {%(got)s}') + + +class DNSResolverError(DNSError): + """ + **4401** Wrapper around dns.exception.DNSException. + Raised when an error occured in dns.resolver. + + For example: + >>> raise DNSResolverError(exception=ValueError("this is bad")) + Traceback (most recent call last): + ... + DNSResolverError: this is bad + """ + + errno = 4401 + format = _('%(exception)s') + + ############################################################################## # 5000 - 5999: Generic errors diff --git a/ipalib/util.py b/ipalib/util.py index 7d3a502e4..3fb46b298 100644 --- a/ipalib/util.py +++ b/ipalib/util.py @@ -42,8 +42,8 @@ from ipalib.text import _ from ipapython.ssh import SSHPublicKey from ipapython.dn import DN, RDN from ipapython.dnsutil import DNSName +from ipapython.dnsutil import resolve_ip_addresses from ipapython.graph import Graph -from ipapython.ipa_log_manager import root_logger if six.PY3: unicode = str @@ -67,30 +67,12 @@ def json_serialize(obj): def verify_host_resolvable(fqdn): - """ - See if the hostname has a DNS A/AAAA record. - """ - if not isinstance(fqdn, DNSName): - fqdn = DNSName(fqdn) - - fqdn = fqdn.make_absolute() - for rdtype in ('A', 'AAAA'): - try: - answers = resolver.query(fqdn, rdtype) - root_logger.debug( - 'IPA: found %d %s records for %s: %s' % (len(answers), - rdtype, fqdn, ' '.join(str(answer) for answer in answers)) - ) - except DNSException: - root_logger.debug( - 'IPA: DNS %s record lookup failed for %s' % - (rdtype, fqdn) - ) - continue - else: - return - # dns lookup failed in both tries - raise errors.DNSNotARecordError() + try: + if not resolve_ip_addresses(fqdn): + raise errors.DNSNotARecordError(hostname=fqdn) + except dns.exception.DNSException as ex: + # wrap DNSException in a PublicError + raise errors.DNSResolverError(exception=ex) def has_soa_or_ns_record(domain): -- cgit