1 # Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
3 # Permission to use, copy, modify, and distribute this software and its
4 # documentation for any purpose with or without fee is hereby granted,
5 # provided that the above copyright notice and this permission notice
6 # appear in all copies.
8 # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
9 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
11 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
14 # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 @var default_resolver: The default resolver object
19 @type default_resolver: dns.resolver.Resolver object"""
35 import dns.reversename
37 if sys.platform == 'win32':
40 class NXDOMAIN(dns.exception.DNSException):
41 """The query name does not exist."""
44 class YXDOMAIN(dns.exception.DNSException):
45 """The query name is too long after DNAME substitution."""
48 # The definition of the Timeout exception has moved from here to the
49 # dns.exception module. We keep dns.resolver.Timeout defined for
50 # backwards compatibility.
52 Timeout = dns.exception.Timeout
54 class NoAnswer(dns.exception.DNSException):
55 """The response did not contain an answer to the question."""
58 class NoNameservers(dns.exception.DNSException):
59 """No non-broken nameservers are available to answer the query."""
62 class NotAbsolute(dns.exception.DNSException):
63 """Raised if an absolute domain name is required but a relative name
67 class NoRootSOA(dns.exception.DNSException):
68 """Raised if for some reason there is no SOA at the root name.
69 This should never happen!"""
72 class NoMetaqueries(dns.exception.DNSException):
73 """Metaqueries are not allowed."""
78 """DNS stub resolver answer
80 Instances of this class bundle up the result of a successful DNS
83 For convenience, the answer object implements much of the sequence
84 protocol, forwarding to its rrset. E.g. "for a in answer" is
85 equivalent to "for a in answer.rrset", "answer[i]" is equivalent
86 to "answer.rrset[i]", and "answer[i:j]" is equivalent to
89 Note that CNAMEs or DNAMEs in the response may mean that answer
90 node's name might not be the query name.
92 @ivar qname: The query name
93 @type qname: dns.name.Name object
94 @ivar rdtype: The query type
96 @ivar rdclass: The query class
98 @ivar response: The response message
99 @type response: dns.message.Message object
100 @ivar rrset: The answer
101 @type rrset: dns.rrset.RRset object
102 @ivar expiration: The time when the answer expires
103 @type expiration: float (seconds since the epoch)
104 @ivar canonical_name: The canonical name of the query name
105 @type canonical_name: dns.name.Name object
107 def __init__(self, qname, rdtype, rdclass, response,
108 raise_on_no_answer=True):
111 self.rdclass = rdclass
112 self.response = response
115 for count in xrange(0, 15):
117 rrset = response.find_rrset(response.answer, qname,
119 if min_ttl == -1 or rrset.ttl < min_ttl:
123 if rdtype != dns.rdatatype.CNAME:
125 crrset = response.find_rrset(response.answer,
129 if min_ttl == -1 or crrset.ttl < min_ttl:
136 if raise_on_no_answer:
138 if raise_on_no_answer:
140 if rrset is None and raise_on_no_answer:
142 self.canonical_name = qname
146 # Look for a SOA RR whose owner name is a superdomain
149 srrset = response.find_rrset(response.authority, qname,
150 rdclass, dns.rdatatype.SOA)
151 if min_ttl == -1 or srrset.ttl < min_ttl:
153 if srrset[0].minimum < min_ttl:
154 min_ttl = srrset[0].minimum
158 qname = qname.parent()
159 except dns.name.NoParent:
161 self.expiration = time.time() + min_ttl
163 def __getattr__(self, attr):
165 return self.rrset.name
167 return self.rrset.ttl
168 elif attr == 'covers':
169 return self.rrset.covers
170 elif attr == 'rdclass':
171 return self.rrset.rdclass
172 elif attr == 'rdtype':
173 return self.rrset.rdtype
175 raise AttributeError(attr)
178 return len(self.rrset)
181 return iter(self.rrset)
183 def __getitem__(self, i):
186 def __delitem__(self, i):
189 def __getslice__(self, i, j):
190 return self.rrset[i:j]
192 def __delslice__(self, i, j):
196 """Simple DNS answer cache.
198 @ivar data: A dictionary of cached data
200 @ivar cleaning_interval: The number of seconds between cleanings. The
201 default is 300 (5 minutes).
202 @type cleaning_interval: float
203 @ivar next_cleaning: The time the cache should next be cleaned (in seconds
205 @type next_cleaning: float
208 def __init__(self, cleaning_interval=300.0):
209 """Initialize a DNS cache.
211 @param cleaning_interval: the number of seconds between periodic
212 cleanings. The default is 300.0
213 @type cleaning_interval: float.
217 self.cleaning_interval = cleaning_interval
218 self.next_cleaning = time.time() + self.cleaning_interval
220 def maybe_clean(self):
221 """Clean the cache if it's time to do so."""
224 if self.next_cleaning <= now:
226 for (k, v) in self.data.iteritems():
227 if v.expiration <= now:
228 keys_to_delete.append(k)
229 for k in keys_to_delete:
232 self.next_cleaning = now + self.cleaning_interval
235 """Get the answer associated with I{key}. Returns None if
236 no answer is cached for the key.
238 @type key: (dns.name.Name, int, int) tuple whose values are the
239 query name, rdtype, and rdclass.
240 @rtype: dns.resolver.Answer object or None
244 v = self.data.get(key)
245 if v is None or v.expiration <= time.time():
249 def put(self, key, value):
250 """Associate key and value in the cache.
252 @type key: (dns.name.Name, int, int) tuple whose values are the
253 query name, rdtype, and rdclass.
254 @param value: The answer being cached
255 @type value: dns.resolver.Answer object
259 self.data[key] = value
261 def flush(self, key=None):
264 If I{key} is specified, only that item is flushed. Otherwise
265 the entire cache is flushed.
267 @param key: the key to flush
268 @type key: (dns.name.Name, int, int) tuple or None
272 if self.data.has_key(key):
276 self.next_cleaning = time.time() + self.cleaning_interval
278 class LRUCacheNode(object):
281 def __init__(self, key, value):
287 def link_before(self, node):
288 self.prev = node.prev
290 node.prev.next = self
293 def link_after(self, node):
295 self.next = node.next
296 node.next.prev = self
300 self.next.prev = self.prev
301 self.prev.next = self.next
303 class LRUCache(object):
304 """Bounded least-recently-used DNS answer cache.
306 This cache is better than the simple cache (above) if you're
307 running a web crawler or other process that does a lot of
308 resolutions. The LRUCache has a maximum number of nodes, and when
309 it is full, the least-recently used node is removed to make space
312 @ivar data: A dictionary of cached data
314 @ivar sentinel: sentinel node for circular doubly linked list of nodes
315 @type sentinel: LRUCacheNode object
316 @ivar max_size: The maximum number of nodes
320 def __init__(self, max_size=100000):
321 """Initialize a DNS cache.
323 @param max_size: The maximum number of nodes to cache; the default is 100000. Must be > 1.
327 self.set_max_size(max_size)
328 self.sentinel = LRUCacheNode(None, None)
330 def set_max_size(self, max_size):
333 self.max_size = max_size
336 """Get the answer associated with I{key}. Returns None if
337 no answer is cached for the key.
339 @type key: (dns.name.Name, int, int) tuple whose values are the
340 query name, rdtype, and rdclass.
341 @rtype: dns.resolver.Answer object or None
343 node = self.data.get(key)
346 # Unlink because we're either going to move the node to the front
347 # of the LRU list or we're going to free it.
349 if node.value.expiration <= time.time():
350 del self.data[node.key]
352 node.link_after(self.sentinel)
355 def put(self, key, value):
356 """Associate key and value in the cache.
358 @type key: (dns.name.Name, int, int) tuple whose values are the
359 query name, rdtype, and rdclass.
360 @param value: The answer being cached
361 @type value: dns.resolver.Answer object
363 node = self.data.get(key)
366 del self.data[node.key]
367 while len(self.data) >= self.max_size:
368 node = self.sentinel.prev
370 del self.data[node.key]
371 node = LRUCacheNode(key, value)
372 node.link_after(self.sentinel)
373 self.data[key] = node
375 def flush(self, key=None):
378 If I{key} is specified, only that item is flushed. Otherwise
379 the entire cache is flushed.
381 @param key: the key to flush
382 @type key: (dns.name.Name, int, int) tuple or None
385 node = self.data.get(key)
388 del self.data[node.key]
390 node = self.sentinel.next
391 while node != self.sentinel:
398 class Resolver(object):
401 @ivar domain: The domain of this host
402 @type domain: dns.name.Name object
403 @ivar nameservers: A list of nameservers to query. Each nameserver is
404 a string which contains the IP address of a nameserver.
405 @type nameservers: list of strings
406 @ivar search: The search list. If the query name is a relative name,
407 the resolver will construct an absolute query name by appending the search
408 names one by one to the query name.
409 @type search: list of dns.name.Name objects
410 @ivar port: The port to which to send queries. The default is 53.
412 @ivar timeout: The number of seconds to wait for a response from a
413 server, before timing out.
415 @ivar lifetime: The total number of seconds to spend trying to get an
416 answer to the question. If the lifetime expires, a Timeout exception
418 @type lifetime: float
419 @ivar keyring: The TSIG keyring to use. The default is None.
421 @ivar keyname: The TSIG keyname to use. The default is None.
422 @type keyname: dns.name.Name object
423 @ivar keyalgorithm: The TSIG key algorithm to use. The default is
424 dns.tsig.default_algorithm.
425 @type keyalgorithm: string
426 @ivar edns: The EDNS level to use. The default is -1, no Edns.
428 @ivar ednsflags: The EDNS flags
430 @ivar payload: The EDNS payload size. The default is 0.
432 @ivar flags: The message flags to use. The default is None (i.e. not overwritten)
434 @ivar cache: The cache to use. The default is None.
435 @type cache: dns.resolver.Cache object
437 def __init__(self, filename='/etc/resolv.conf', configure=True):
438 """Initialize a resolver instance.
440 @param filename: The filename of a configuration file in
441 standard /etc/resolv.conf format. This parameter is meaningful
442 only when I{configure} is true and the platform is POSIX.
443 @type filename: string or file object
444 @param configure: If True (the default), the resolver instance
445 is configured in the normal fashion for the operating system
446 the resolver is running on. (I.e. a /etc/resolv.conf file on
447 POSIX systems and from the registry on Windows systems.)
448 @type configure: bool"""
452 if sys.platform == 'win32':
455 self.read_resolv_conf(filename)
458 """Reset all resolver configuration to the defaults."""
460 dns.name.Name(dns.name.from_text(socket.gethostname())[1:])
461 if len(self.domain) == 0:
462 self.domain = dns.name.root
463 self.nameservers = []
470 self.keyalgorithm = dns.tsig.default_algorithm
477 def read_resolv_conf(self, f):
478 """Process f as a file in the /etc/resolv.conf format. If f is
479 a string, it is used as the name of the file to open; otherwise it
480 is treated as the file itself."""
481 if isinstance(f, str) or isinstance(f, unicode):
485 # /etc/resolv.conf doesn't exist, can't be read, etc.
486 # We'll just use the default resolver configuration.
487 self.nameservers = ['127.0.0.1']
494 if len(l) == 0 or l[0] == '#' or l[0] == ';':
499 if tokens[0] == 'nameserver':
500 self.nameservers.append(tokens[1])
501 elif tokens[0] == 'domain':
502 self.domain = dns.name.from_text(tokens[1])
503 elif tokens[0] == 'search':
504 for suffix in tokens[1:]:
505 self.search.append(dns.name.from_text(suffix))
509 if len(self.nameservers) == 0:
510 self.nameservers.append('127.0.0.1')
512 def _determine_split_char(self, entry):
514 # The windows registry irritatingly changes the list element
515 # delimiter in between ' ' and ',' (and vice-versa) in various
516 # versions of windows.
518 if entry.find(' ') >= 0:
520 elif entry.find(',') >= 0:
523 # probably a singleton; treat as a space-separated list.
527 def _config_win32_nameservers(self, nameservers):
528 """Configure a NameServer registry entry."""
529 # we call str() on nameservers to convert it from unicode to ascii
530 nameservers = str(nameservers)
531 split_char = self._determine_split_char(nameservers)
532 ns_list = nameservers.split(split_char)
534 if not ns in self.nameservers:
535 self.nameservers.append(ns)
537 def _config_win32_domain(self, domain):
538 """Configure a Domain registry entry."""
539 # we call str() on domain to convert it from unicode to ascii
540 self.domain = dns.name.from_text(str(domain))
542 def _config_win32_search(self, search):
543 """Configure a Search registry entry."""
544 # we call str() on search to convert it from unicode to ascii
546 split_char = self._determine_split_char(search)
547 search_list = search.split(split_char)
548 for s in search_list:
549 if not s in self.search:
550 self.search.append(dns.name.from_text(s))
552 def _config_win32_fromkey(self, key):
553 """Extract DNS info from a registry key."""
555 servers, rtype = _winreg.QueryValueEx(key, 'NameServer')
559 self._config_win32_nameservers(servers)
561 dom, rtype = _winreg.QueryValueEx(key, 'Domain')
563 self._config_win32_domain(dom)
568 servers, rtype = _winreg.QueryValueEx(key, 'DhcpNameServer')
572 self._config_win32_nameservers(servers)
574 dom, rtype = _winreg.QueryValueEx(key, 'DhcpDomain')
576 self._config_win32_domain(dom)
580 search, rtype = _winreg.QueryValueEx(key, 'SearchList')
584 self._config_win32_search(search)
586 def read_registry(self):
587 """Extract resolver configuration from the Windows registry."""
588 lm = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE)
593 tcp_params = _winreg.OpenKey(lm,
594 r'SYSTEM\CurrentControlSet'
595 r'\Services\Tcpip\Parameters')
597 except EnvironmentError:
599 tcp_params = _winreg.OpenKey(lm,
600 r'SYSTEM\CurrentControlSet'
601 r'\Services\VxD\MSTCP')
603 self._config_win32_fromkey(tcp_params)
607 interfaces = _winreg.OpenKey(lm,
608 r'SYSTEM\CurrentControlSet'
609 r'\Services\Tcpip\Parameters'
615 guid = _winreg.EnumKey(interfaces, i)
617 key = _winreg.OpenKey(interfaces, guid)
618 if not self._win32_is_nic_enabled(lm, guid, key):
621 self._config_win32_fromkey(key)
624 except EnvironmentError:
631 def _win32_is_nic_enabled(self, lm, guid, interface_key):
632 # Look in the Windows Registry to determine whether the network
633 # interface corresponding to the given guid is enabled.
635 # (Code contributed by Paul Marks, thanks!)
638 # This hard-coded location seems to be consistent, at least
639 # from Windows 2000 through Vista.
640 connection_key = _winreg.OpenKey(
642 r'SYSTEM\CurrentControlSet\Control\Network'
643 r'\{4D36E972-E325-11CE-BFC1-08002BE10318}'
644 r'\%s\Connection' % guid)
647 # The PnpInstanceID points to a key inside Enum
648 (pnp_id, ttype) = _winreg.QueryValueEx(
649 connection_key, 'PnpInstanceID')
651 if ttype != _winreg.REG_SZ:
654 device_key = _winreg.OpenKey(
655 lm, r'SYSTEM\CurrentControlSet\Enum\%s' % pnp_id)
658 # Get ConfigFlags for this device
659 (flags, ttype) = _winreg.QueryValueEx(
660 device_key, 'ConfigFlags')
662 if ttype != _winreg.REG_DWORD:
665 # Based on experimentation, bit 0x1 indicates that the
666 # device is disabled.
667 return not (flags & 0x1)
672 connection_key.Close()
673 except (EnvironmentError, ValueError):
674 # Pre-vista, enabled interfaces seem to have a non-empty
675 # NTEContextList; this was how dnspython detected enabled
676 # nics before the code above was contributed. We've retained
677 # the old method since we don't know if the code above works
678 # on Windows 95/98/ME.
680 (nte, ttype) = _winreg.QueryValueEx(interface_key,
682 return nte is not None
686 def _compute_timeout(self, start):
690 # Time going backwards is bad. Just give up.
693 # Time went backwards, but only a little. This can
694 # happen, e.g. under vmware with older linux kernels.
695 # Pretend it didn't happen.
697 duration = now - start
698 if duration >= self.lifetime:
700 return min(self.lifetime - duration, self.timeout)
702 def query(self, qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN,
703 tcp=False, source=None, raise_on_no_answer=True, source_port=0):
704 """Query nameservers to find the answer to the question.
706 The I{qname}, I{rdtype}, and I{rdclass} parameters may be objects
707 of the appropriate type, or strings that can be converted into objects
708 of the appropriate type. E.g. For I{rdtype} the integer 2 and the
709 the string 'NS' both mean to query for records with DNS rdata type NS.
711 @param qname: the query name
712 @type qname: dns.name.Name object or string
713 @param rdtype: the query type
714 @type rdtype: int or string
715 @param rdclass: the query class
716 @type rdclass: int or string
717 @param tcp: use TCP to make the query (default is False).
719 @param source: bind to this IP address (defaults to machine default IP).
720 @type source: IP address in dotted quad notation
721 @param raise_on_no_answer: raise NoAnswer if there's no answer
723 @type raise_on_no_answer: bool
724 @param source_port: The port from which to send the message.
726 @type source_port: int
727 @rtype: dns.resolver.Answer instance
728 @raises Timeout: no answers could be found in the specified lifetime
729 @raises NXDOMAIN: the query name does not exist
730 @raises YXDOMAIN: the query name is too long after DNAME substitution
731 @raises NoAnswer: the response did not contain an answer and
732 raise_on_no_answer is True.
733 @raises NoNameservers: no non-broken nameservers are available to
734 answer the question."""
736 if isinstance(qname, (str, unicode)):
737 qname = dns.name.from_text(qname, None)
738 if isinstance(rdtype, (str, unicode)):
739 rdtype = dns.rdatatype.from_text(rdtype)
740 if dns.rdatatype.is_metatype(rdtype):
742 if isinstance(rdclass, (str, unicode)):
743 rdclass = dns.rdataclass.from_text(rdclass)
744 if dns.rdataclass.is_metaclass(rdclass):
747 if qname.is_absolute():
748 qnames_to_try.append(qname)
751 qnames_to_try.append(qname.concatenate(dns.name.root))
753 for suffix in self.search:
754 qnames_to_try.append(qname.concatenate(suffix))
756 qnames_to_try.append(qname.concatenate(self.domain))
759 for qname in qnames_to_try:
761 answer = self.cache.get((qname, rdtype, rdclass))
762 if not answer is None:
763 if answer.rrset is None and raise_on_no_answer:
767 request = dns.message.make_query(qname, rdtype, rdclass)
768 if not self.keyname is None:
769 request.use_tsig(self.keyring, self.keyname,
770 algorithm=self.keyalgorithm)
771 request.use_edns(self.edns, self.ednsflags, self.payload)
772 if self.flags is not None:
773 request.flags = self.flags
776 # make a copy of the servers list so we can alter it later.
778 nameservers = self.nameservers[:]
780 while response is None:
781 if len(nameservers) == 0:
783 for nameserver in nameservers[:]:
784 timeout = self._compute_timeout(start)
787 response = dns.query.tcp(request, nameserver,
790 source_port=source_port)
792 response = dns.query.udp(request, nameserver,
795 source_port=source_port)
796 if response.flags & dns.flags.TC:
797 # Response truncated; retry with TCP.
798 timeout = self._compute_timeout(start)
799 response = dns.query.tcp(request, nameserver,
802 source_port=source_port)
803 except (socket.error, dns.exception.Timeout):
805 # Communication failure or timeout. Go to the
810 except dns.query.UnexpectedSource:
812 # Who knows? Keep going.
816 except dns.exception.FormError:
818 # We don't understand what this server is
819 # saying. Take it out of the mix and
822 nameservers.remove(nameserver)
827 # We're using TCP and they hung up on us.
828 # Probably they don't support TCP (though
829 # they're supposed to!). Take it out of the
832 nameservers.remove(nameserver)
835 rcode = response.rcode()
836 if rcode == dns.rcode.YXDOMAIN:
838 if rcode == dns.rcode.NOERROR or \
839 rcode == dns.rcode.NXDOMAIN:
842 # We got a response, but we're not happy with the
843 # rcode in it. Remove the server from the mix if
844 # the rcode isn't SERVFAIL.
846 if rcode != dns.rcode.SERVFAIL:
847 nameservers.remove(nameserver)
849 if not response is None:
852 # All nameservers failed!
854 if len(nameservers) > 0:
856 # But we still have servers to try. Sleep a bit
857 # so we don't pound them!
859 timeout = self._compute_timeout(start)
860 sleep_time = min(timeout, backoff)
862 time.sleep(sleep_time)
863 if response.rcode() == dns.rcode.NXDOMAIN:
869 answer = Answer(qname, rdtype, rdclass, response,
872 self.cache.put((qname, rdtype, rdclass), answer)
875 def use_tsig(self, keyring, keyname=None,
876 algorithm=dns.tsig.default_algorithm):
877 """Add a TSIG signature to the query.
879 @param keyring: The TSIG keyring to use; defaults to None.
881 @param keyname: The name of the TSIG key to use; defaults to None.
882 The key must be defined in the keyring. If a keyring is specified
883 but a keyname is not, then the key used will be the first key in the
884 keyring. Note that the order of keys in a dictionary is not defined,
885 so applications should supply a keyname when a keyring is used, unless
886 they know the keyring contains only one key.
887 @param algorithm: The TSIG key algorithm to use. The default
888 is dns.tsig.default_algorithm.
889 @type algorithm: string"""
890 self.keyring = keyring
892 self.keyname = self.keyring.keys()[0]
894 self.keyname = keyname
895 self.keyalgorithm = algorithm
897 def use_edns(self, edns, ednsflags, payload):
900 @param edns: The EDNS level to use. The default is -1, no Edns.
902 @param ednsflags: The EDNS flags
904 @param payload: The EDNS payload size. The default is 0.
905 @type payload: int"""
910 self.ednsflags = ednsflags
911 self.payload = payload
913 def set_flags(self, flags):
914 """Overrides the default flags with your own
916 @param flags: The flags to overwrite the default with
920 default_resolver = None
922 def get_default_resolver():
923 """Get the default resolver, initializing it if necessary."""
924 global default_resolver
925 if default_resolver is None:
926 default_resolver = Resolver()
927 return default_resolver
929 def query(qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN,
930 tcp=False, source=None, raise_on_no_answer=True,
932 """Query nameservers to find the answer to the question.
934 This is a convenience function that uses the default resolver
935 object to make the query.
936 @see: L{dns.resolver.Resolver.query} for more information on the
938 return get_default_resolver().query(qname, rdtype, rdclass, tcp, source,
939 raise_on_no_answer, source_port)
941 def zone_for_name(name, rdclass=dns.rdataclass.IN, tcp=False, resolver=None):
942 """Find the name of the zone which contains the specified name.
944 @param name: the query name
945 @type name: absolute dns.name.Name object or string
946 @param rdclass: The query class
948 @param tcp: use TCP to make the query (default is False).
950 @param resolver: the resolver to use
951 @type resolver: dns.resolver.Resolver object or None
952 @rtype: dns.name.Name"""
954 if isinstance(name, (str, unicode)):
955 name = dns.name.from_text(name, dns.name.root)
957 resolver = get_default_resolver()
958 if not name.is_absolute():
959 raise NotAbsolute(name)
962 answer = resolver.query(name, dns.rdatatype.SOA, rdclass, tcp)
963 if answer.rrset.name == name:
965 # otherwise we were CNAMEd or DNAMEd and need to look higher
966 except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
970 except dns.name.NoParent:
974 # Support for overriding the system resolver for all python code in the
978 _protocols_for_socktype = {
979 socket.SOCK_DGRAM : [socket.SOL_UDP],
980 socket.SOCK_STREAM : [socket.SOL_TCP],
984 _original_getaddrinfo = socket.getaddrinfo
985 _original_getnameinfo = socket.getnameinfo
986 _original_getfqdn = socket.getfqdn
987 _original_gethostbyname = socket.gethostbyname
988 _original_gethostbyname_ex = socket.gethostbyname_ex
989 _original_gethostbyaddr = socket.gethostbyaddr
991 def _getaddrinfo(host=None, service=None, family=socket.AF_UNSPEC, socktype=0,
993 if flags & (socket.AI_ADDRCONFIG|socket.AI_V4MAPPED) != 0:
994 raise NotImplementedError
995 if host is None and service is None:
996 raise socket.gaierror(socket.EAI_NONAME)
999 canonical_name = None
1001 # Is host None or a V6 address literal?
1003 canonical_name = 'localhost'
1004 if flags & socket.AI_PASSIVE != 0:
1005 v6addrs.append('::')
1006 v4addrs.append('0.0.0.0')
1008 v6addrs.append('::1')
1009 v4addrs.append('127.0.0.1')
1011 parts = host.split('%')
1016 addr = dns.ipv6.inet_aton(ahost)
1017 v6addrs.append(host)
1018 canonical_name = host
1021 # Is it a V4 address literal?
1022 addr = dns.ipv4.inet_aton(host)
1023 v4addrs.append(host)
1024 canonical_name = host
1026 if flags & socket.AI_NUMERICHOST == 0:
1029 if family == socket.AF_INET6 or family == socket.AF_UNSPEC:
1030 v6 = _resolver.query(host, dns.rdatatype.AAAA,
1031 raise_on_no_answer=False)
1032 # Note that setting host ensures we query the same name
1033 # for A as we did for AAAA.
1035 canonical_name = v6.canonical_name.to_text(True)
1036 if v6.rrset is not None:
1037 for rdata in v6.rrset:
1038 v6addrs.append(rdata.address)
1039 if family == socket.AF_INET or family == socket.AF_UNSPEC:
1040 v4 = _resolver.query(host, dns.rdatatype.A,
1041 raise_on_no_answer=False)
1043 canonical_name = v4.canonical_name.to_text(True)
1044 if v4.rrset is not None:
1045 for rdata in v4.rrset:
1046 v4addrs.append(rdata.address)
1047 except dns.resolver.NXDOMAIN:
1048 raise socket.gaierror(socket.EAI_NONAME)
1050 raise socket.gaierror(socket.EAI_SYSTEM)
1053 # Is it a port literal?
1059 if flags & socket.AI_NUMERICSERV == 0:
1061 port = socket.getservbyname(service)
1065 raise socket.gaierror(socket.EAI_NONAME)
1068 socktypes = [socket.SOCK_DGRAM, socket.SOCK_STREAM]
1070 socktypes = [socktype]
1071 if flags & socket.AI_CANONNAME != 0:
1072 cname = canonical_name
1075 if family == socket.AF_INET6 or family == socket.AF_UNSPEC:
1076 for addr in v6addrs:
1077 for socktype in socktypes:
1078 for proto in _protocols_for_socktype[socktype]:
1079 tuples.append((socket.AF_INET6, socktype, proto,
1080 cname, (addr, port, 0, 0)))
1081 if family == socket.AF_INET or family == socket.AF_UNSPEC:
1082 for addr in v4addrs:
1083 for socktype in socktypes:
1084 for proto in _protocols_for_socktype[socktype]:
1085 tuples.append((socket.AF_INET, socktype, proto,
1086 cname, (addr, port)))
1087 if len(tuples) == 0:
1088 raise socket.gaierror(socket.EAI_NONAME)
1091 def _getnameinfo(sockaddr, flags=0):
1094 if len(sockaddr) == 4:
1096 family = socket.AF_INET6
1099 family = socket.AF_INET
1100 tuples = _getaddrinfo(host, port, family, socket.SOCK_STREAM,
1103 raise socket.error('sockaddr resolved to multiple addresses')
1104 addr = tuples[0][4][0]
1105 if flags & socket.NI_DGRAM:
1109 qname = dns.reversename.from_address(addr)
1110 if flags & socket.NI_NUMERICHOST == 0:
1112 answer = _resolver.query(qname, 'PTR')
1113 hostname = answer.rrset[0].target.to_text(True)
1114 except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
1115 if flags & socket.NI_NAMEREQD:
1116 raise socket.gaierror(socket.EAI_NONAME)
1118 if scope is not None:
1119 hostname += '%' + str(scope)
1122 if scope is not None:
1123 hostname += '%' + str(scope)
1124 if flags & socket.NI_NUMERICSERV:
1127 service = socket.getservbyport(port, pname)
1128 return (hostname, service)
1130 def _getfqdn(name=None):
1132 name = socket.gethostname()
1133 return _getnameinfo(_getaddrinfo(name, 80)[0][4])[0]
1135 def _gethostbyname(name):
1136 return _gethostbyname_ex(name)[2][0]
1138 def _gethostbyname_ex(name):
1141 tuples = _getaddrinfo(name, 0, socket.AF_INET, socket.SOCK_STREAM,
1142 socket.SOL_TCP, socket.AI_CANONNAME)
1143 canonical = tuples[0][3]
1145 addresses.append(item[4][0])
1146 # XXX we just ignore aliases
1147 return (canonical, aliases, addresses)
1149 def _gethostbyaddr(ip):
1151 addr = dns.ipv6.inet_aton(ip)
1152 sockaddr = (ip, 80, 0, 0)
1153 family = socket.AF_INET6
1156 family = socket.AF_INET
1157 (name, port) = _getnameinfo(sockaddr, socket.NI_NAMEREQD)
1160 tuples = _getaddrinfo(name, 0, family, socket.SOCK_STREAM, socket.SOL_TCP,
1161 socket.AI_CANONNAME)
1162 canonical = tuples[0][3]
1164 addresses.append(item[4][0])
1165 # XXX we just ignore aliases
1166 return (canonical, aliases, addresses)
1168 def override_system_resolver(resolver=None):
1169 """Override the system resolver routines in the socket module with
1170 versions which use dnspython's resolver.
1172 This can be useful in testing situations where you want to control
1173 the resolution behavior of python code without having to change
1174 the system's resolver settings (e.g. /etc/resolv.conf).
1176 The resolver to use may be specified; if it's not, the default
1177 resolver will be used.
1179 @param resolver: the resolver to use
1180 @type resolver: dns.resolver.Resolver object or None
1182 if resolver is None:
1183 resolver = get_default_resolver()
1185 _resolver = resolver
1186 socket.getaddrinfo = _getaddrinfo
1187 socket.getnameinfo = _getnameinfo
1188 socket.getfqdn = _getfqdn
1189 socket.gethostbyname = _gethostbyname
1190 socket.gethostbyname_ex = _gethostbyname_ex
1191 socket.gethostbyaddr = _gethostbyaddr
1193 def restore_system_resolver():
1194 """Undo the effects of override_system_resolver().
1198 socket.getaddrinfo = _original_getaddrinfo
1199 socket.getnameinfo = _original_getnameinfo
1200 socket.getfqdn = _original_getfqdn
1201 socket.gethostbyname = _original_gethostbyname
1202 socket.gethostbyname_ex = _original_gethostbyname_ex
1203 socket.gethostbyaddr = _original_gethostbyaddr