diff --git a/client/certbot-dns-ipa.in b/client/certbot-dns-ipa.in index 65ab4f73a..d0baa7e27 100755 --- a/client/certbot-dns-ipa.in +++ b/client/certbot-dns-ipa.in @@ -20,7 +20,6 @@ dnsrecord_del commands. import os import sys -from dns import resolver from ipalib import api, errors from ipapython import dnsutil @@ -37,7 +36,7 @@ else: validation_domain = f'_acme-challenge.{certbot_domain}' fqdn = dnsutil.DNSName(validation_domain).make_absolute() -zone = dnsutil.DNSName(resolver.zone_for_name(fqdn)) +zone = dnsutil.DNSName(dnsutil.zone_for_name(fqdn)) name = fqdn.relativize(zone) try: diff --git a/ipaclient/discovery.py b/ipaclient/discovery.py index c322e9712..fb344a34a 100644 --- a/ipaclient/discovery.py +++ b/ipaclient/discovery.py @@ -24,11 +24,11 @@ import socket import six -from dns import resolver, rdatatype +from dns import rdatatype from dns.exception import DNSException from ipalib import errors from ipalib.util import validate_domain_name -from ipapython.dnsutil import query_srv +from ipapython.dnsutil import query_srv, resolve from ipaplatform.paths import paths from ipapython.ipautil import valid_ip, realm_to_suffix @@ -562,7 +562,7 @@ class IPADiscovery: logger.debug("Search DNS for TXT record of %s", qname) try: - answers = resolver.query(qname, rdatatype.TXT) + answers = resolve(qname, rdatatype.TXT) except DNSException as e: logger.debug("DNS record not found: %s", e.__class__.__name__) answers = [] diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py index 5b4caa09a..960e25e06 100644 --- a/ipaclient/install/client.py +++ b/ipaclient/install/client.py @@ -53,7 +53,7 @@ from ipaplatform import services from ipaplatform.constants import constants from ipaplatform.paths import paths from ipaplatform.tasks import tasks -from ipapython import certdb, kernel_keyring, ipaldap, ipautil +from ipapython import certdb, kernel_keyring, ipaldap, ipautil, dnsutil from ipapython.admintool import ScriptError from ipapython.dn import DN from ipapython.install import typing @@ -1440,7 +1440,7 @@ def verify_dns_update(fqdn, ips): logger.debug('DNS resolver: Query: %s IN %s', fqdn, dns.rdatatype.to_text(record_type)) try: - answers = dns.resolver.query(fqdn, record_type) + answers = dnsutil.resolve(fqdn, record_type) except (dns.resolver.NoAnswer, dns.resolver.NXDOMAIN): logger.debug('DNS resolver: No record.') except dns.resolver.NoNameservers: @@ -1460,10 +1460,9 @@ def verify_dns_update(fqdn, ips): missing_reverse = [str(ip) for ip in ips] for ip in ips: ip_str = str(ip) - addr = dns.reversename.from_address(ip_str) - logger.debug('DNS resolver: Query: %s IN PTR', addr) + logger.debug('DNS resolver: Query: %s IN PTR', ip_str) try: - answers = dns.resolver.query(addr, dns.rdatatype.PTR) + answers = dnsutil.resolve_address(ip_str) except (dns.resolver.NoAnswer, dns.resolver.NXDOMAIN): logger.debug('DNS resolver: No record.') except dns.resolver.NoNameservers: diff --git a/ipalib/util.py b/ipalib/util.py index 1e60543f1..e3a510fc7 100644 --- a/ipalib/util.py +++ b/ipalib/util.py @@ -42,7 +42,7 @@ import struct import subprocess import netaddr -from dns import resolver, rdatatype +from dns import rdatatype from dns.exception import DNSException from dns.resolver import NXDOMAIN from netaddr.core import AddrFormatError @@ -67,8 +67,12 @@ from ipaplatform.constants import constants from ipaplatform.paths import paths 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.dnsutil import ( + DNSName, + DNSResolver, + resolve, + resolve_ip_addresses, +) from ipapython.admintool import ScriptError if sys.version_info >= (3, 2): @@ -117,13 +121,13 @@ def has_soa_or_ns_record(domain): Returns True or False. """ try: - resolver.query(domain, rdatatype.SOA) + resolve(domain, rdatatype.SOA) soa_record_found = True except DNSException: soa_record_found = False try: - resolver.query(domain, rdatatype.NS) + resolve(domain, rdatatype.NS) ns_record_found = True except DNSException: ns_record_found = False @@ -797,7 +801,7 @@ def _resolve_record(owner, rtype, nameserver_ip=None, edns0=False, assert isinstance(nameserver_ip, str) or nameserver_ip is None assert isinstance(rtype, str) - res = dns.resolver.Resolver() + res = DNSResolver() if nameserver_ip: res.nameservers = [nameserver_ip] res.lifetime = timeout @@ -815,7 +819,7 @@ def _resolve_record(owner, rtype, nameserver_ip=None, edns0=False, elif edns0: res.use_edns(0, 0, 4096) - return res.query(owner, rtype) + return res.resolve(owner, rtype) def _validate_edns0_forwarder(owner, rtype, ip_addr, timeout=10): @@ -985,7 +989,7 @@ def detect_dns_zone_realm_type(api, domain): kerberos_record_name = kerberos_prefix + domain_suffix try: - result = resolver.query(kerberos_record_name, rdatatype.TXT) + result = resolve(kerberos_record_name, rdatatype.TXT) answer = result.response.answer # IPA domain will have only one _kerberos TXT record @@ -1012,7 +1016,7 @@ def detect_dns_zone_realm_type(api, domain): try: # The presence of this record is enough, return foreign in such case - resolver.query(ad_specific_record_name, rdatatype.SRV) + resolve(ad_specific_record_name, rdatatype.SRV) except DNSException: # If we could not detect type with certainty, return unknown return 'unknown' diff --git a/ipapython/dnsutil.py b/ipapython/dnsutil.py index aec1ec231..7c4ef7ace 100644 --- a/ipapython/dnsutil.py +++ b/ipapython/dnsutil.py @@ -27,6 +27,7 @@ import dns.exception import dns.resolver import dns.rdataclass import dns.rdatatype +import dns.reversename import six @@ -39,6 +40,85 @@ if six.PY3: logger = logging.getLogger(__name__) +ipa_resolver = None + + +def get_ipa_resolver(): + global ipa_resolver + if ipa_resolver is None: + ipa_resolver = DNSResolver() + return ipa_resolver + + +def resolve(*args, **kwargs): + return get_ipa_resolver().resolve(*args, **kwargs) + + +def resolve_address(*args, **kwargs): + return get_ipa_resolver().resolve_address(*args, **kwargs) + + +def zone_for_name(*args, **kwargs): + if "resolver" not in kwargs: + kwargs["resolver"] = get_ipa_resolver() + + return dns.resolver.zone_for_name(*args, **kwargs) + + +def reset_default_resolver(): + """Re-initialize ipa resolver. + """ + global ipa_resolver + ipa_resolver = DNSResolver() + + +class DNSResolver(dns.resolver.Resolver): + """DNS stub resolver compatible with both dnspython < 2.0.0 + and dnspython >= 2.0.0. + + Set `use_search_by_default` attribute to `True`, which + determines the default for whether the search list configured + in the system's resolver configuration is used for relative + names, and whether the resolver's domain may be added to relative + names. + + Increase the default lifetime which determines the number of seconds + to spend trying to get an answer to the question. dnspython 2.0.0 + changes this to 5sec, while the previous one was 30sec. + """ + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.reset_ipa_defaults() + self.resolve = getattr(super(), "resolve", self.query) + self.resolve_address = getattr( + super(), + "resolve_address", + self._resolve_address + ) + + def reset_ipa_defaults(self): + self.use_search_by_default = True + # the default is 5sec + self.lifetime = 15 + + def reset(self): + super().reset() + self.reset_ipa_defaults() + + def _resolve_address(self, ip_address, *args, **kwargs): + """Query nameservers for PTR records. + + :param ip_address: IPv4 or IPv6 address + :type ip_address: str + """ + return resolve( + dns.reversename.from_address(ip_address), + rdtype=dns.rdatatype.PTR, + *args, + **kwargs, + ) + + class DNSZoneAlreadyExists(dns.exception.DNSException): supp_kwargs = {'zone', 'ns'} fmt = (u"DNS zone {zone} already exists in DNS " @@ -321,7 +401,7 @@ def resolve_rrsets(fqdn, rdtypes): rrsets = [] for rdtype in rdtypes: try: - answer = dns.resolver.query(fqdn, rdtype) + answer = resolve(fqdn, rdtype) logger.debug('found %d %s records for %s: %s', len(answer), rdtype, @@ -363,7 +443,7 @@ def check_zone_overlap(zone, raise_on_error=True): return try: - containing_zone = dns.resolver.zone_for_name(zone) + containing_zone = zone_for_name(zone) except dns.exception.DNSException as e: msg = ("DNS check for domain %s failed: %s." % (zone, e)) if raise_on_error: @@ -374,7 +454,7 @@ def check_zone_overlap(zone, raise_on_error=True): if containing_zone == zone: try: - ns = [ans.to_text() for ans in dns.resolver.query(zone, 'NS')] + ns = [ans.to_text() for ans in resolve(zone, 'NS')] except dns.exception.DNSException as e: logger.debug("Failed to resolve nameserver(s) for domain %s: %s", zone, e) @@ -463,6 +543,8 @@ def query_srv(qname, resolver=None, **kwargs): :return: list of dns.rdtypes.IN.SRV.SRV instances """ if resolver is None: - resolver = dns.resolver - answer = resolver.query(qname, rdtype=dns.rdatatype.SRV, **kwargs) + resolve_f = resolve + else: + resolve_f = getattr(resolver, "resolve", resolver.query) + answer = resolve_f(qname, rdtype=dns.rdatatype.SRV, **kwargs) return sort_prio_weight(answer) diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py index 424dff7d0..c35f5200f 100644 --- a/ipapython/ipautil.py +++ b/ipapython/ipautil.py @@ -43,9 +43,6 @@ import locale import collections import urllib -from dns import resolver, reversename -from dns.exception import DNSException - import six from six.moves import input @@ -1112,22 +1109,6 @@ def check_port_bindable(port, socket_type=socket.SOCK_STREAM): s.close() -def reverse_record_exists(ip_address): - """ - Checks if IP address have some reverse record somewhere. - Does not care where it points. - - Returns True/False - """ - reverse = reversename.from_address(str(ip_address)) - try: - resolver.query(reverse, "PTR") - except DNSException: - # really don't care what exception, PTR is simply unresolvable - return False - return True - - def config_replace_variables(filepath, replacevars=dict(), appendvars=dict(), removevars=None): """ diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py index b27548144..10a2583e5 100644 --- a/ipaserver/install/bindinstance.py +++ b/ipaserver/install/bindinstance.py @@ -30,9 +30,9 @@ import shutil import sys import time -import dns.resolver import ldap import six +from dns.exception import DNSException from ipaserver.dns_data_management import ( IPASystemRecords, @@ -320,10 +320,15 @@ def read_reverse_zone(default, ip_address, allow_zone_overlap=False): def get_auto_reverse_zones(ip_addresses, allow_zone_overlap=False): auto_zones = [] for ip in ip_addresses: - if ipautil.reverse_record_exists(ip): + try: + dnsutil.resolve_address(str(ip)) + except DNSException: + pass + else: # PTR exist there is no reason to create reverse zone logger.info("Reverse record for IP address %s already exists", ip) continue + default_reverse = get_reverse_zone_default(ip) if not allow_zone_overlap: try: @@ -1131,7 +1136,7 @@ class BindInstance(service.Service): else: # python DNS might have global resolver cached in this variable # we have to re-initialize it because resolv.conf has changed - dns.resolver.reset_default_resolver() + dnsutil.reset_default_resolver() def __generate_rndc_key(self): installutils.check_entropy() diff --git a/ipaserver/install/dns.py b/ipaserver/install/dns.py index 132d89f22..f7d793e1d 100644 --- a/ipaserver/install/dns.py +++ b/ipaserver/install/dns.py @@ -12,13 +12,9 @@ from __future__ import print_function import enum import logging import os - -# absolute import is necessary because IPA module dns clashes with python-dns -from dns import resolver -import six - import sys +import six from subprocess import CalledProcessError from ipalib import api @@ -294,7 +290,7 @@ def install_check(standalone, api, replica, options, hostname): if not options.forwarders: options.forwarders = [] if options.auto_forwarders: - options.forwarders += resolver.get_default_resolver().nameservers + options.forwarders += dnsutil.get_ipa_resolver().nameservers elif standalone or not replica: options.forwarders = read_dns_forwarders() diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py index a3274d579..a46acf9f5 100644 --- a/ipaserver/install/installutils.py +++ b/ipaserver/install/installutils.py @@ -38,7 +38,7 @@ from contextlib import contextmanager from configparser import ConfigParser as SafeConfigParser from configparser import NoOptionError -from dns import resolver, rdatatype +from dns import rdatatype from dns.exception import DNSException import ldap import six @@ -53,6 +53,7 @@ from ipalib.constants import MAXHOSTNAMELEN from ipalib.util import validate_hostname from ipalib import api, errors, x509 from ipapython.dn import DN +from ipapython.dnsutil import resolve, get_ipa_resolver from ipaserver.install import certs, service, sysupgrade from ipaplatform import services from ipaplatform.paths import paths @@ -187,7 +188,7 @@ def verify_fqdn(host_name, no_host_dns=False, local_hostname=True): # Verify this is NOT a CNAME try: logger.debug('Check if %s is not a CNAME', host_name) - resolver.query(host_name, rdatatype.CNAME) + resolve(host_name, rdatatype.CNAME) raise HostReverseLookupError("The IPA Server Hostname cannot be a CNAME, only A and AAAA names are allowed.") except DNSException: pass @@ -284,11 +285,13 @@ def read_ip_addresses(): def read_dns_forwarders(): addrs = [] if ipautil.user_input("Do you want to configure DNS forwarders?", True): - print("Following DNS servers are configured in /etc/resolv.conf: %s" % - ", ".join(resolver.get_default_resolver().nameservers)) + print( + "Following DNS servers are configured in /etc/resolv.conf: %s" + % ", ".join(get_ipa_resolver().nameservers) + ) if ipautil.user_input("Do you want to configure these servers as DNS " "forwarders?", True): - addrs = resolver.default_resolver.nameservers[:] + addrs = get_ipa_resolver().nameservers[:] print("All DNS servers from /etc/resolv.conf were added. You can " "enter additional addresses now:") while True: diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py index 2990f4382..c6c438a04 100644 --- a/ipaserver/install/server/replicainstall.py +++ b/ipaserver/install/server/replicainstall.py @@ -9,8 +9,6 @@ import logging import dns.exception as dnsexception import dns.name as dnsname -import dns.resolver as dnsresolver -import dns.reversename as dnsreversename import os import shutil import socket @@ -28,6 +26,7 @@ from ipalib.install import certstore, sysrestore from ipalib.install.kinit import kinit_keytab from ipapython import ipaldap, ipautil from ipapython.dn import DN +from ipapython.dnsutil import DNSResolver from ipapython.admintool import ScriptError from ipapython.ipachangeconf import IPAChangeConf from ipaplatform import services @@ -289,7 +288,7 @@ def check_dns_resolution(host_name, dns_servers): logger.error( 'Could not resolve any DNS server hostname: %s', dns_servers) return False - resolver = dnsresolver.Resolver() + resolver = DNSResolver() resolver.nameservers = server_ips logger.debug('Search DNS server %s (%s) for %s', @@ -299,7 +298,7 @@ def check_dns_resolution(host_name, dns_servers): addresses = set() for rtype in 'A', 'AAAA': try: - result = resolver.query(host_name, rtype) + result = resolver.resolve(host_name, rtype) except dnsexception.DNSException: rrset = [] else: @@ -327,8 +326,7 @@ def check_dns_resolution(host_name, dns_servers): checked.add(address) try: logger.debug('Check reverse address %s (%s)', address, host_name) - revname = dnsreversename.from_address(address) - rrset = resolver.query(revname, 'PTR').rrset + rrset = resolver.resolve_address(address).rrset except Exception as e: logger.debug('Check failed: %s %s', type(e).__name__, e) logger.error( diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py index e8eb5ce53..0b8712113 100644 --- a/ipaserver/plugins/cert.py +++ b/ipaserver/plugins/cert.py @@ -1193,7 +1193,7 @@ def _san_ip_update_reachable(reachable, dnsname, cname_depth): """ fqdn = dnsutil.DNSName(dnsname).make_absolute() try: - zone = dnsutil.DNSName(resolver.zone_for_name(fqdn)) + zone = dnsutil.DNSName(dnsutil.zone_for_name(fqdn)) except resolver.NoNameservers: return # if there's no zone, there are no records name = fqdn.relativize(zone) @@ -1227,7 +1227,7 @@ def _ip_ptr_records(ip): """ rname = dnsutil.DNSName(reversename.from_address(ip)) try: - zone = dnsutil.DNSName(resolver.zone_for_name(rname)) + zone = dnsutil.DNSName(dnsutil.zone_for_name(rname)) name = rname.relativize(zone) result = api.Command['dnsrecord_show'](zone, name)['result'] except resolver.NoNameservers: diff --git a/ipaserver/plugins/dns.py b/ipaserver/plugins/dns.py index 275e3433e..919402db1 100644 --- a/ipaserver/plugins/dns.py +++ b/ipaserver/plugins/dns.py @@ -79,9 +79,15 @@ from ipalib.util import (normalize_zonemgr, from ipaplatform import services from ipapython.dn import DN from ipapython.ipautil import CheckedIPAddress -from ipapython.dnsutil import check_zone_overlap, DNSZoneAlreadyExists -from ipapython.dnsutil import DNSName -from ipapython.dnsutil import related_to_auto_empty_zone +from ipapython.dnsutil import ( + check_zone_overlap, + DNSName, + DNSResolver, + DNSZoneAlreadyExists, + related_to_auto_empty_zone, + resolve, + zone_for_name, +) from ipaserver.dns_data_management import ( IPASystemRecords, IPADomainIsNotManagedByIPAError, @@ -542,7 +548,7 @@ def get_reverse_zone(ipaddr): ip = netaddr.IPAddress(str(ipaddr)) revdns = DNSName(unicode(ip.reverse_dns)) try: - revzone = DNSName(dns.resolver.zone_for_name(revdns)) + revzone = DNSName(zone_for_name(revdns)) except dns.resolver.NoNameservers: raise errors.NotFound( reason=_( @@ -3363,7 +3369,7 @@ class dnsrecord(LDAPObject): :raises errors.DNSDataMismatch: if data in DNS and LDAP doesn't match :raises dns.exception.DNSException: if DNS resolution failed ''' - resolver = dns.resolver.Resolver() + resolver = DNSResolver() resolver.set_flags(0) # disable recursion (for NS RR checks) max_attempts = int(self.api.env['wait_for_dns']) warn_attempts = max_attempts // 2 @@ -3379,9 +3385,9 @@ class dnsrecord(LDAPObject): log_fn = logger.warning attempt += 1 try: - dns_answer = resolver.query(dns_name, rdtype, - dns.rdataclass.IN, - raise_on_no_answer=False) + dns_answer = resolver.resolve(dns_name, rdtype, + dns.rdataclass.IN, + raise_on_no_answer=False) dns_rrset = None if rdtype == _NS: # NS records can be in Authority section (sometimes) @@ -4303,7 +4309,7 @@ class dnsforwardzone(DNSZoneBase): ipa_dns_ip = None for rdtype in (dns.rdatatype.A, dns.rdatatype.AAAA): try: - ans = dns.resolver.query(ipa_dns_masters[0], rdtype) + ans = resolve(ipa_dns_masters[0], rdtype) except dns.exception.DNSException: continue else: diff --git a/ipaserver/plugins/host.py b/ipaserver/plugins/host.py index e6e42b3ea..766d232db 100644 --- a/ipaserver/plugins/host.py +++ b/ipaserver/plugins/host.py @@ -22,8 +22,6 @@ from __future__ import absolute_import import logging -import dns.resolver - import six from ipalib import api, errors, util @@ -64,7 +62,7 @@ from ipapython.ipautil import ( CheckedIPAddress, TMP_PWD_ENTROPY_BITS ) -from ipapython.dnsutil import DNSName +from ipapython.dnsutil import DNSName, zone_for_name from ipapython.ssh import SSHPublicKey from ipapython.dn import DN from ipapython import kerberos @@ -826,7 +824,7 @@ class host_del(LDAPDelete): if updatedns: # Remove A, AAAA, SSHFP and PTR records of the host fqdn_dnsname = DNSName(fqdn).make_absolute() - zone = DNSName(dns.resolver.zone_for_name(fqdn_dnsname)) + zone = DNSName(zone_for_name(fqdn_dnsname)) relative_hostname = fqdn_dnsname.relativize(zone) # Get all resources for this host diff --git a/ipatests/pytest_ipa/integration/tasks.py b/ipatests/pytest_ipa/integration/tasks.py index 21b196933..fceac1b62 100755 --- a/ipatests/pytest_ipa/integration/tasks.py +++ b/ipatests/pytest_ipa/integration/tasks.py @@ -49,6 +49,7 @@ from cryptography.hazmat.backends import default_backend from ipapython import certdb from ipapython import ipautil +from ipapython.dnsutil import DNSResolver from ipaplatform.paths import paths from ipaplatform.services import knownservices from ipapython.dn import DN @@ -1436,7 +1437,7 @@ def resolve_record(nameserver, query, rtype="SOA", retry=True, timeout=100): :timeout: max period of time while method will try to resolve query (requires retry=True) """ - res = dns.resolver.Resolver() + res = DNSResolver() res.nameservers = [nameserver] res.lifetime = 10 # wait max 10 seconds for reply @@ -1444,7 +1445,7 @@ def resolve_record(nameserver, query, rtype="SOA", retry=True, timeout=100): while time.time() < wait_until: try: - ans = res.query(query, rtype) + ans = res.resolve(query, rtype) return ans except dns.exception.DNSException: if not retry: diff --git a/ipatests/test_integration/test_dns_locations.py b/ipatests/test_integration/test_dns_locations.py index 1337418b1..aa662abd3 100644 --- a/ipatests/test_integration/test_dns_locations.py +++ b/ipatests/test_integration/test_dns_locations.py @@ -12,7 +12,7 @@ import dns.rdataclass from ipatests.test_integration.base import IntegrationTest from ipatests.pytest_ipa.integration import tasks -from ipapython.dnsutil import DNSName +from ipapython.dnsutil import DNSName, DNSResolver from ipalib.constants import IPA_CA_RECORD logger = logging.getLogger(__name__) @@ -45,14 +45,14 @@ IPA_CA_A_REC = ( def resolve_records_from_server(rname, rtype, nameserver): error = None - res = dns.resolver.Resolver() + res = DNSResolver() res.nameservers = [nameserver] res.lifetime = 30 logger.info("Query: %s %s, nameserver %s", rname, rtype, nameserver) # lets try to query 3x for _i in range(3): try: - ans = res.query(rname, rtype) + ans = res.resolve(rname, rtype) logger.info("Answer: %s", ans.rrset) return ans.rrset except (dns.resolver.NXDOMAIN, dns.resolver.Timeout) as e: diff --git a/ipatests/test_integration/test_dnssec.py b/ipatests/test_integration/test_dnssec.py index ccaa7f9b5..62ed62efc 100644 --- a/ipatests/test_integration/test_dnssec.py +++ b/ipatests/test_integration/test_dnssec.py @@ -10,13 +10,13 @@ import subprocess import time import dns.dnssec -import dns.resolver import dns.name from ipatests.test_integration.base import IntegrationTest from ipatests.pytest_ipa.integration import tasks from ipatests.pytest_ipa.integration.firewall import Firewall from ipaplatform.paths import paths +from ipapython.dnsutil import DNSResolver logger = logging.getLogger(__name__) @@ -33,7 +33,7 @@ example3_test_zone = "example3.test." def resolve_with_dnssec(nameserver, query, rtype="SOA"): - res = dns.resolver.Resolver() + res = DNSResolver() res.nameservers = [nameserver] res.lifetime = 10 # wait max 10 seconds for reply # enable Authenticated Data + Checking Disabled flags @@ -42,7 +42,7 @@ def resolve_with_dnssec(nameserver, query, rtype="SOA"): # enable EDNS v0 + enable DNSSEC-Ok flag res.use_edns(0, dns.flags.DO, 0) - ans = res.query(query, rtype) + ans = res.resolve(query, rtype) return ans