1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 """DNS stub resolver.
17
18 @var default_resolver: The default resolver object
19 @type default_resolver: dns.resolver.Resolver object"""
20
21 import socket
22 import sys
23 import time
24
25 import dns.exception
26 import dns.flags
27 import dns.ipv4
28 import dns.ipv6
29 import dns.message
30 import dns.name
31 import dns.query
32 import dns.rcode
33 import dns.rdataclass
34 import dns.rdatatype
35 import dns.reversename
36
37 if sys.platform == 'win32':
38 import _winreg
39
40 -class NXDOMAIN(dns.exception.DNSException):
41 """The query name does not exist."""
42 pass
43
44
45
46
47
48 Timeout = dns.exception.Timeout
49
50 -class NoAnswer(dns.exception.DNSException):
51 """The response did not contain an answer to the question."""
52 pass
53
55 """No non-broken nameservers are available to answer the query."""
56 pass
57
59 """Raised if an absolute domain name is required but a relative name
60 was provided."""
61 pass
62
64 """Raised if for some reason there is no SOA at the root name.
65 This should never happen!"""
66 pass
67
71
73 """DNS stub resolver answer
74
75 Instances of this class bundle up the result of a successful DNS
76 resolution.
77
78 For convenience, the answer object implements much of the sequence
79 protocol, forwarding to its rrset. E.g. "for a in answer" is
80 equivalent to "for a in answer.rrset", "answer[i]" is equivalent
81 to "answer.rrset[i]", and "answer[i:j]" is equivalent to
82 "answer.rrset[i:j]".
83
84 Note that CNAMEs or DNAMEs in the response may mean that answer
85 node's name might not be the query name.
86
87 @ivar qname: The query name
88 @type qname: dns.name.Name object
89 @ivar rdtype: The query type
90 @type rdtype: int
91 @ivar rdclass: The query class
92 @type rdclass: int
93 @ivar response: The response message
94 @type response: dns.message.Message object
95 @ivar rrset: The answer
96 @type rrset: dns.rrset.RRset object
97 @ivar expiration: The time when the answer expires
98 @type expiration: float (seconds since the epoch)
99 @ivar canonical_name: The canonical name of the query name
100 @type canonical_name: dns.name.Name object
101 """
102 - def __init__(self, qname, rdtype, rdclass, response,
103 raise_on_no_answer=True):
104 self.qname = qname
105 self.rdtype = rdtype
106 self.rdclass = rdclass
107 self.response = response
108 min_ttl = -1
109 rrset = None
110 for count in range(0, 15):
111 try:
112 rrset = response.find_rrset(response.answer, qname,
113 rdclass, rdtype)
114 if min_ttl == -1 or rrset.ttl < min_ttl:
115 min_ttl = rrset.ttl
116 break
117 except KeyError:
118 if rdtype != dns.rdatatype.CNAME:
119 try:
120 crrset = response.find_rrset(response.answer,
121 qname,
122 rdclass,
123 dns.rdatatype.CNAME)
124 if min_ttl == -1 or crrset.ttl < min_ttl:
125 min_ttl = crrset.ttl
126 for rd in crrset:
127 qname = rd.target
128 break
129 continue
130 except KeyError:
131 if raise_on_no_answer:
132 raise NoAnswer
133 if raise_on_no_answer:
134 raise NoAnswer
135 if rrset is None and raise_on_no_answer:
136 raise NoAnswer
137 self.canonical_name = qname
138 self.rrset = rrset
139 if rrset is None:
140 while 1:
141
142
143 try:
144 srrset = response.find_rrset(response.authority, qname,
145 rdclass, dns.rdatatype.SOA)
146 if min_ttl == -1 or srrset.ttl < min_ttl:
147 min_ttl = srrset.ttl
148 if srrset[0].minimum < min_ttl:
149 min_ttl = srrset[0].minimum
150 break
151 except KeyError:
152 try:
153 qname = qname.parent()
154 except dns.name.NoParent:
155 break
156 self.expiration = time.time() + min_ttl
157
159 if attr == 'name':
160 return self.rrset.name
161 elif attr == 'ttl':
162 return self.rrset.ttl
163 elif attr == 'covers':
164 return self.rrset.covers
165 elif attr == 'rdclass':
166 return self.rrset.rdclass
167 elif attr == 'rdtype':
168 return self.rrset.rdtype
169 else:
170 raise AttributeError(attr)
171
173 return len(self.rrset)
174
176 return iter(self.rrset)
177
180
183
185 return self.rrset[i:j]
186
189
191 """Simple DNS answer cache.
192
193 @ivar data: A dictionary of cached data
194 @type data: dict
195 @ivar cleaning_interval: The number of seconds between cleanings. The
196 default is 300 (5 minutes).
197 @type cleaning_interval: float
198 @ivar next_cleaning: The time the cache should next be cleaned (in seconds
199 since the epoch.)
200 @type next_cleaning: float
201 """
202
203 - def __init__(self, cleaning_interval=300.0):
204 """Initialize a DNS cache.
205
206 @param cleaning_interval: the number of seconds between periodic
207 cleanings. The default is 300.0
208 @type cleaning_interval: float.
209 """
210
211 self.data = {}
212 self.cleaning_interval = cleaning_interval
213 self.next_cleaning = time.time() + self.cleaning_interval
214
216 """Clean the cache if it's time to do so."""
217
218 now = time.time()
219 if self.next_cleaning <= now:
220 keys_to_delete = []
221 for (k, v) in self.data.items():
222 if v.expiration <= now:
223 keys_to_delete.append(k)
224 for k in keys_to_delete:
225 del self.data[k]
226 now = time.time()
227 self.next_cleaning = now + self.cleaning_interval
228
229 - def get(self, key):
230 """Get the answer associated with I{key}. Returns None if
231 no answer is cached for the key.
232 @param key: the key
233 @type key: (dns.name.Name, int, int) tuple whose values are the
234 query name, rdtype, and rdclass.
235 @rtype: dns.resolver.Answer object or None
236 """
237
238 self.maybe_clean()
239 v = self.data.get(key)
240 if v is None or v.expiration <= time.time():
241 return None
242 return v
243
244 - def put(self, key, value):
245 """Associate key and value in the cache.
246 @param key: the key
247 @type key: (dns.name.Name, int, int) tuple whose values are the
248 query name, rdtype, and rdclass.
249 @param value: The answer being cached
250 @type value: dns.resolver.Answer object
251 """
252
253 self.maybe_clean()
254 self.data[key] = value
255
256 - def flush(self, key=None):
257 """Flush the cache.
258
259 If I{key} is specified, only that item is flushed. Otherwise
260 the entire cache is flushed.
261
262 @param key: the key to flush
263 @type key: (dns.name.Name, int, int) tuple or None
264 """
265
266 if not key is None:
267 if key in self.data:
268 del self.data[key]
269 else:
270 self.data = {}
271 self.next_cleaning = time.time() + self.cleaning_interval
272
274 """LRUCache node.
275 """
277 self.key = key
278 self.value = value
279 self.prev = self
280 self.next = self
281
287
293
295 self.next.prev = self.prev
296 self.prev.next = self.next
297
299 """Bounded least-recently-used DNS answer cache.
300
301 This cache is better than the simple cache (above) if you're
302 running a web crawler or other process that does a lot of
303 resolutions. The LRUCache has a maximum number of nodes, and when
304 it is full, the least-recently used node is removed to make space
305 for a new one.
306
307 @ivar data: A dictionary of cached data
308 @type data: dict
309 @ivar sentinel: sentinel node for circular doubly linked list of nodes
310 @type sentinel: LRUCacheNode object
311 @ivar max_size: The maximum number of nodes
312 @type max_size: int
313 """
314
316 """Initialize a DNS cache.
317
318 @param max_size: The maximum number of nodes to cache; the default is 100000. Must be > 1.
319 @type max_size: int
320 """
321 self.data = {}
322 self.set_max_size(max_size)
323 self.sentinel = LRUCacheNode(None, None)
324
326 if max_size < 1:
327 max_size = 1
328 self.max_size = max_size
329
330 - def get(self, key):
331 """Get the answer associated with I{key}. Returns None if
332 no answer is cached for the key.
333 @param key: the key
334 @type key: (dns.name.Name, int, int) tuple whose values are the
335 query name, rdtype, and rdclass.
336 @rtype: dns.resolver.Answer object or None
337 """
338 node = self.data.get(key)
339 if node is None:
340 return None
341
342
343 node.unlink()
344 if node.value.expiration <= time.time():
345 del self.data[node.key]
346 return None
347 node.link_after(self.sentinel)
348 return node.value
349
350 - def put(self, key, value):
351 """Associate key and value in the cache.
352 @param key: the key
353 @type key: (dns.name.Name, int, int) tuple whose values are the
354 query name, rdtype, and rdclass.
355 @param value: The answer being cached
356 @type value: dns.resolver.Answer object
357 """
358 node = self.data.get(key)
359 if not node is None:
360 node.unlink()
361 del self.data[node.key]
362 while len(self.data) >= self.max_size:
363 node = self.sentinel.prev
364 node.unlink()
365 del self.data[node.key]
366 node = LRUCacheNode(key, value)
367 node.link_after(self.sentinel)
368 self.data[key] = node
369
370 - def flush(self, key=None):
371 """Flush the cache.
372
373 If I{key} is specified, only that item is flushed. Otherwise
374 the entire cache is flushed.
375
376 @param key: the key to flush
377 @type key: (dns.name.Name, int, int) tuple or None
378 """
379 if not key is None:
380 node = self.data.get(key)
381 if not node is None:
382 node.unlink()
383 del self.data[node.key]
384 else:
385 node = self.sentinel.next
386 while node != self.sentinel:
387 next = node.next
388 node.prev = None
389 node.next = None
390 node = next
391 self.data = {}
392
394 """DNS stub resolver
395
396 @ivar domain: The domain of this host
397 @type domain: dns.name.Name object
398 @ivar nameservers: A list of nameservers to query. Each nameserver is
399 a string which contains the IP address of a nameserver.
400 @type nameservers: list of strings
401 @ivar search: The search list. If the query name is a relative name,
402 the resolver will construct an absolute query name by appending the search
403 names one by one to the query name.
404 @type search: list of dns.name.Name objects
405 @ivar port: The port to which to send queries. The default is 53.
406 @type port: int
407 @ivar timeout: The number of seconds to wait for a response from a
408 server, before timing out.
409 @type timeout: float
410 @ivar lifetime: The total number of seconds to spend trying to get an
411 answer to the question. If the lifetime expires, a Timeout exception
412 will occur.
413 @type lifetime: float
414 @ivar keyring: The TSIG keyring to use. The default is None.
415 @type keyring: dict
416 @ivar keyname: The TSIG keyname to use. The default is None.
417 @type keyname: dns.name.Name object
418 @ivar keyalgorithm: The TSIG key algorithm to use. The default is
419 dns.tsig.default_algorithm.
420 @type keyalgorithm: string
421 @ivar edns: The EDNS level to use. The default is -1, no Edns.
422 @type edns: int
423 @ivar ednsflags: The EDNS flags
424 @type ednsflags: int
425 @ivar payload: The EDNS payload size. The default is 0.
426 @type payload: int
427 @ivar cache: The cache to use. The default is None.
428 @type cache: dns.resolver.Cache object
429 """
430 - def __init__(self, filename='/etc/resolv.conf', configure=True):
431 """Initialize a resolver instance.
432
433 @param filename: The filename of a configuration file in
434 standard /etc/resolv.conf format. This parameter is meaningful
435 only when I{configure} is true and the platform is POSIX.
436 @type filename: string or file object
437 @param configure: If True (the default), the resolver instance
438 is configured in the normal fashion for the operating system
439 the resolver is running on. (I.e. a /etc/resolv.conf file on
440 POSIX systems and from the registry on Windows systems.)
441 @type configure: bool"""
442
443 self.reset()
444 if configure:
445 if sys.platform == 'win32':
446 self.read_registry()
447 elif filename:
448 self.read_resolv_conf(filename)
449
451 """Reset all resolver configuration to the defaults."""
452 self.domain = \
453 dns.name.Name(dns.name.from_text(socket.gethostname())[1:])
454 if len(self.domain) == 0:
455 self.domain = dns.name.root
456 self.nameservers = []
457 self.search = []
458 self.port = 53
459 self.timeout = 2.0
460 self.lifetime = 30.0
461 self.keyring = None
462 self.keyname = None
463 self.keyalgorithm = dns.tsig.default_algorithm
464 self.edns = -1
465 self.ednsflags = 0
466 self.payload = 0
467 self.cache = None
468
470 """Process f as a file in the /etc/resolv.conf format. If f is
471 a string, it is used as the name of the file to open; otherwise it
472 is treated as the file itself."""
473 if isinstance(f, str):
474 try:
475 f = open(f, 'r')
476 except IOError:
477
478
479 self.nameservers = ['127.0.0.1']
480 return
481 want_close = True
482 else:
483 want_close = False
484 try:
485 for l in f:
486 if len(l) == 0 or l[0] == '#' or l[0] == ';':
487 continue
488 tokens = l.split()
489 if len(tokens) == 0:
490 continue
491 if tokens[0] == 'nameserver':
492 self.nameservers.append(tokens[1])
493 elif tokens[0] == 'domain':
494 self.domain = dns.name.from_text(tokens[1])
495 elif tokens[0] == 'search':
496 for suffix in tokens[1:]:
497 self.search.append(dns.name.from_text(suffix))
498 finally:
499 if want_close:
500 f.close()
501 if len(self.nameservers) == 0:
502 self.nameservers.append('127.0.0.1')
503
505
506
507
508
509
510 if entry.find(' ') >= 0:
511 split_char = ' '
512 elif entry.find(',') >= 0:
513 split_char = ','
514 else:
515
516 split_char = ' '
517 return split_char
518
520 """Configure a NameServer registry entry."""
521 split_char = self._determine_split_char(nameservers)
522 ns_list = nameservers.split(split_char)
523 for ns in ns_list:
524 if not ns in self.nameservers:
525 self.nameservers.append(ns)
526
527 - def _config_win32_domain(self, domain):
528 """Configure a Domain registry entry."""
529 self.domain = dns.name.from_text(domain)
530
532 """Configure a Search registry entry."""
533 split_char = self._determine_split_char(search)
534 search_list = search.split(split_char)
535 for s in search_list:
536 if not s in self.search:
537 self.search.append(dns.name.from_text(s))
538
540 """Extract DNS info from a registry key."""
541 try:
542 servers, rtype = _winreg.QueryValueEx(key, 'NameServer')
543 except WindowsError:
544 servers = None
545 if servers:
546 self._config_win32_nameservers(servers)
547 try:
548 dom, rtype = _winreg.QueryValueEx(key, 'Domain')
549 if dom:
550 self._config_win32_domain(dom)
551 except WindowsError:
552 pass
553 else:
554 try:
555 servers, rtype = _winreg.QueryValueEx(key, 'DhcpNameServer')
556 except WindowsError:
557 servers = None
558 if servers:
559 self._config_win32_nameservers(servers)
560 try:
561 dom, rtype = _winreg.QueryValueEx(key, 'DhcpDomain')
562 if dom:
563 self._config_win32_domain(dom)
564 except WindowsError:
565 pass
566 try:
567 search, rtype = _winreg.QueryValueEx(key, 'SearchList')
568 except WindowsError:
569 search = None
570 if search:
571 self._config_win32_search(search)
572
574 """Extract resolver configuration from the Windows registry."""
575 lm = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE)
576 want_scan = False
577 try:
578 try:
579
580 tcp_params = _winreg.OpenKey(lm,
581 r'SYSTEM\CurrentControlSet'
582 r'\Services\Tcpip\Parameters')
583 want_scan = True
584 except EnvironmentError:
585
586 tcp_params = _winreg.OpenKey(lm,
587 r'SYSTEM\CurrentControlSet'
588 r'\Services\VxD\MSTCP')
589 try:
590 self._config_win32_fromkey(tcp_params)
591 finally:
592 tcp_params.Close()
593 if want_scan:
594 interfaces = _winreg.OpenKey(lm,
595 r'SYSTEM\CurrentControlSet'
596 r'\Services\Tcpip\Parameters'
597 r'\Interfaces')
598 try:
599 i = 0
600 while True:
601 try:
602 guid = _winreg.EnumKey(interfaces, i)
603 i += 1
604 key = _winreg.OpenKey(interfaces, guid)
605 if not self._win32_is_nic_enabled(lm, guid, key):
606 continue
607 try:
608 self._config_win32_fromkey(key)
609 finally:
610 key.Close()
611 except EnvironmentError:
612 break
613 finally:
614 interfaces.Close()
615 finally:
616 lm.Close()
617
619
620
621
622
623
624 try:
625
626
627 connection_key = _winreg.OpenKey(
628 lm,
629 r'SYSTEM\CurrentControlSet\Control\Network'
630 r'\{4D36E972-E325-11CE-BFC1-08002BE10318}'
631 r'\%s\Connection' % guid)
632
633 try:
634
635 (pnp_id, ttype) = _winreg.QueryValueEx(
636 connection_key, 'PnpInstanceID')
637
638 if ttype != _winreg.REG_SZ:
639 raise ValueError
640
641 device_key = _winreg.OpenKey(
642 lm, r'SYSTEM\CurrentControlSet\Enum\%s' % pnp_id)
643
644 try:
645
646 (flags, ttype) = _winreg.QueryValueEx(
647 device_key, 'ConfigFlags')
648
649 if ttype != _winreg.REG_DWORD:
650 raise ValueError
651
652
653
654 return not (flags & 0x1)
655
656 finally:
657 device_key.Close()
658 finally:
659 connection_key.Close()
660 except (EnvironmentError, ValueError):
661
662
663
664
665
666 try:
667 (nte, ttype) = _winreg.QueryValueEx(interface_key,
668 'NTEContextList')
669 return nte is not None
670 except WindowsError:
671 return False
672
674 now = time.time()
675 if now < start:
676 if start - now > 1:
677
678 raise Timeout
679 else:
680
681
682
683 now = start
684 duration = now - start
685 if duration >= self.lifetime:
686 raise Timeout
687 return min(self.lifetime - duration, self.timeout)
688
691 """Query nameservers to find the answer to the question.
692
693 The I{qname}, I{rdtype}, and I{rdclass} parameters may be objects
694 of the appropriate type, or strings that can be converted into objects
695 of the appropriate type. E.g. For I{rdtype} the integer 2 and the
696 the string 'NS' both mean to query for records with DNS rdata type NS.
697
698 @param qname: the query name
699 @type qname: dns.name.Name object or string
700 @param rdtype: the query type
701 @type rdtype: int or string
702 @param rdclass: the query class
703 @type rdclass: int or string
704 @param tcp: use TCP to make the query (default is False).
705 @type tcp: bool
706 @param source: bind to this IP address (defaults to machine default IP).
707 @type source: IP address in dotted quad notation
708 @param raise_on_no_answer: raise NoAnswer if there's no answer
709 (defaults is True).
710 @type raise_on_no_answer: bool
711 @param source_port: The port from which to send the message.
712 The default is 0.
713 @type source_port: int
714 @rtype: dns.resolver.Answer instance
715 @raises Timeout: no answers could be found in the specified lifetime
716 @raises NXDOMAIN: the query name does not exist
717 @raises NoAnswer: the response did not contain an answer and
718 raise_on_no_answer is True.
719 @raises NoNameservers: no non-broken nameservers are available to
720 answer the question."""
721
722 if isinstance(qname, str):
723 qname = dns.name.from_text(qname, None)
724 if isinstance(rdtype, str):
725 rdtype = dns.rdatatype.from_text(rdtype)
726 if dns.rdatatype.is_metatype(rdtype):
727 raise NoMetaqueries
728 if isinstance(rdclass, str):
729 rdclass = dns.rdataclass.from_text(rdclass)
730 if dns.rdataclass.is_metaclass(rdclass):
731 raise NoMetaqueries
732 qnames_to_try = []
733 if qname.is_absolute():
734 qnames_to_try.append(qname)
735 else:
736 if len(qname) > 1:
737 qnames_to_try.append(qname.concatenate(dns.name.root))
738 if self.search:
739 for suffix in self.search:
740 qnames_to_try.append(qname.concatenate(suffix))
741 else:
742 qnames_to_try.append(qname.concatenate(self.domain))
743 all_nxdomain = True
744 start = time.time()
745 for qname in qnames_to_try:
746 if self.cache:
747 answer = self.cache.get((qname, rdtype, rdclass))
748 if not answer is None:
749 if answer.rrset is None and raise_on_no_answer:
750 raise NoAnswer
751 else:
752 return answer
753 request = dns.message.make_query(qname, rdtype, rdclass)
754 if not self.keyname is None:
755 request.use_tsig(self.keyring, self.keyname,
756 algorithm=self.keyalgorithm)
757 request.use_edns(self.edns, self.ednsflags, self.payload)
758 response = None
759
760
761
762 nameservers = self.nameservers[:]
763 backoff = 0.10
764 while response is None:
765 if len(nameservers) == 0:
766 raise NoNameservers
767 for nameserver in nameservers[:]:
768 timeout = self._compute_timeout(start)
769 try:
770 if tcp:
771 response = dns.query.tcp(request, nameserver,
772 timeout, self.port,
773 source=source,
774 source_port=source_port)
775 else:
776 response = dns.query.udp(request, nameserver,
777 timeout, self.port,
778 source=source,
779 source_port=source_port)
780 if response.flags & dns.flags.TC:
781
782 timeout = self._compute_timeout(start)
783 response = dns.query.tcp(request, nameserver,
784 timeout, self.port,
785 source=source,
786 source_port=source_port)
787
788 except (socket.error, dns.exception.Timeout):
789
790
791
792
793 response = None
794 continue
795 except dns.query.UnexpectedSource:
796
797
798
799 response = None
800 continue
801 except dns.exception.FormError:
802
803
804
805
806
807 nameservers.remove(nameserver)
808 response = None
809 continue
810 except EOFError:
811
812
813
814
815
816
817 nameservers.remove(nameserver)
818 response = None
819 continue
820 rcode = response.rcode()
821 if rcode == dns.rcode.NOERROR or \
822 rcode == dns.rcode.NXDOMAIN:
823 break
824
825
826
827
828
829 if rcode != dns.rcode.SERVFAIL:
830 nameservers.remove(nameserver)
831 response = None
832 if not response is None:
833 break
834
835
836
837 if len(nameservers) > 0:
838
839
840
841
842 timeout = self._compute_timeout(start)
843 sleep_time = min(timeout, backoff)
844 backoff *= 2
845 time.sleep(sleep_time)
846 if response.rcode() == dns.rcode.NXDOMAIN:
847 continue
848 all_nxdomain = False
849 break
850 if all_nxdomain:
851 raise NXDOMAIN
852 answer = Answer(qname, rdtype, rdclass, response,
853 raise_on_no_answer)
854 if self.cache:
855 self.cache.put((qname, rdtype, rdclass), answer)
856 return answer
857
860 """Add a TSIG signature to the query.
861
862 @param keyring: The TSIG keyring to use; defaults to None.
863 @type keyring: dict
864 @param keyname: The name of the TSIG key to use; defaults to None.
865 The key must be defined in the keyring. If a keyring is specified
866 but a keyname is not, then the key used will be the first key in the
867 keyring. Note that the order of keys in a dictionary is not defined,
868 so applications should supply a keyname when a keyring is used, unless
869 they know the keyring contains only one key.
870 @param algorithm: The TSIG key algorithm to use. The default
871 is dns.tsig.default_algorithm.
872 @type algorithm: string"""
873 self.keyring = keyring
874 if keyname is None:
875 self.keyname = next(iter(self.keyring.keys()))
876 else:
877 self.keyname = keyname
878 self.keyalgorithm = algorithm
879
880 - def use_edns(self, edns, ednsflags, payload):
881 """Configure Edns.
882
883 @param edns: The EDNS level to use. The default is -1, no Edns.
884 @type edns: int
885 @param ednsflags: The EDNS flags
886 @type ednsflags: int
887 @param payload: The EDNS payload size. The default is 0.
888 @type payload: int"""
889
890 if edns is None:
891 edns = -1
892 self.edns = edns
893 self.ednsflags = ednsflags
894 self.payload = payload
895
896 default_resolver = None
897
904
908 """Query nameservers to find the answer to the question.
909
910 This is a convenience function that uses the default resolver
911 object to make the query.
912 @see: L{dns.resolver.Resolver.query} for more information on the
913 parameters."""
914 return get_default_resolver().query(qname, rdtype, rdclass, tcp, source,
915 raise_on_no_answer, source_port)
916
948
949
950
951
952
953
954 _protocols_for_socktype = {
955 socket.SOCK_DGRAM : [socket.SOL_UDP],
956 socket.SOCK_STREAM : [socket.SOL_TCP],
957 }
958
959 _resolver = None
960 _original_getaddrinfo = socket.getaddrinfo
961 _original_getnameinfo = socket.getnameinfo
962 _original_getfqdn = socket.getfqdn
963 _original_gethostbyname = socket.gethostbyname
964 _original_gethostbyname_ex = socket.gethostbyname_ex
965 _original_gethostbyaddr = socket.gethostbyaddr
966
967 -def _getaddrinfo(host=None, service=None, family=socket.AF_UNSPEC, socktype=0,
968 proto=0, flags=0):
969 if flags & (socket.AI_ADDRCONFIG|socket.AI_V4MAPPED) != 0:
970 raise NotImplementedError
971 if host is None and service is None:
972 raise socket.gaierror(socket.EAI_NONAME)
973 v6addrs = []
974 v4addrs = []
975 canonical_name = None
976 try:
977
978 if host is None:
979 canonical_name = 'localhost'
980 if flags & socket.AI_PASSIVE != 0:
981 v6addrs.append('::')
982 v4addrs.append('0.0.0.0')
983 else:
984 v6addrs.append('::1')
985 v4addrs.append('127.0.0.1')
986 else:
987 parts = host.split('%')
988 if len(parts) == 2:
989 ahost = parts[0]
990 else:
991 ahost = host
992 addr = dns.ipv6.inet_aton(ahost)
993 v6addrs.append(host)
994 canonical_name = host
995 except:
996 try:
997
998 addr = dns.ipv4.inet_aton(host)
999 v4addrs.append(host)
1000 canonical_name = host
1001 except:
1002 if flags & socket.AI_NUMERICHOST == 0:
1003 try:
1004 qname = None
1005 if family == socket.AF_INET6 or family == socket.AF_UNSPEC:
1006 v6 = _resolver.query(host, dns.rdatatype.AAAA,
1007 raise_on_no_answer=False)
1008
1009
1010 host = v6.qname
1011 canonical_name = v6.canonical_name.to_text(True)
1012 if v6.rrset is not None:
1013 for rdata in v6.rrset:
1014 v6addrs.append(rdata.address)
1015 if family == socket.AF_INET or family == socket.AF_UNSPEC:
1016 v4 = _resolver.query(host, dns.rdatatype.A,
1017 raise_on_no_answer=False)
1018 host = v4.qname
1019 canonical_name = v4.canonical_name.to_text(True)
1020 if v4.rrset is not None:
1021 for rdata in v4.rrset:
1022 v4addrs.append(rdata.address)
1023 except dns.resolver.NXDOMAIN:
1024 raise socket.gaierror(socket.EAI_NONAME)
1025 except:
1026 raise socket.gaierror(socket.EAI_SYSTEM)
1027 port = None
1028 try:
1029
1030 if service is None:
1031 port = 0
1032 else:
1033 port = int(service)
1034 except:
1035 if flags & socket.AI_NUMERICSERV == 0:
1036 try:
1037 port = socket.getservbyname(service)
1038 except:
1039 pass
1040 if port is None:
1041 raise socket.gaierror(socket.EAI_NONAME)
1042 tuples = []
1043 if socktype == 0:
1044 socktypes = [socket.SOCK_DGRAM, socket.SOCK_STREAM]
1045 else:
1046 socktypes = [socktype]
1047 if flags & socket.AI_CANONNAME != 0:
1048 cname = canonical_name
1049 else:
1050 cname = ''
1051 if family == socket.AF_INET6 or family == socket.AF_UNSPEC:
1052 for addr in v6addrs:
1053 for socktype in socktypes:
1054 for proto in _protocols_for_socktype[socktype]:
1055 tuples.append((socket.AF_INET6, socktype, proto,
1056 cname, (addr, port, 0, 0)))
1057 if family == socket.AF_INET or family == socket.AF_UNSPEC:
1058 for addr in v4addrs:
1059 for socktype in socktypes:
1060 for proto in _protocols_for_socktype[socktype]:
1061 tuples.append((socket.AF_INET, socktype, proto,
1062 cname, (addr, port)))
1063 if len(tuples) == 0:
1064 raise socket.gaierror(socket.EAI_NONAME)
1065 return tuples
1066
1105
1110
1113
1115 aliases = []
1116 addresses = []
1117 tuples = _getaddrinfo(name, 0, socket.AF_INET, socket.SOCK_STREAM,
1118 socket.SOL_TCP, socket.AI_CANONNAME)
1119 canonical = tuples[0][3]
1120 for item in tuples:
1121 addresses.append(item[4][0])
1122
1123 return (canonical, aliases, addresses)
1124
1126 try:
1127 addr = dns.ipv6.inet_aton(ip)
1128 sockaddr = (ip, 80, 0, 0)
1129 family = socket.AF_INET6
1130 except:
1131 sockaddr = (ip, 80)
1132 family = socket.AF_INET
1133 (name, port) = _getnameinfo(sockaddr, socket.NI_NAMEREQD)
1134 aliases = []
1135 addresses = []
1136 tuples = _getaddrinfo(name, 0, family, socket.SOCK_STREAM, socket.SOL_TCP,
1137 socket.AI_CANONNAME)
1138 canonical = tuples[0][3]
1139 for item in tuples:
1140 addresses.append(item[4][0])
1141
1142 return (canonical, aliases, addresses)
1143
1145 """Override the system resolver routines in the socket module with
1146 versions which use dnspython's resolver.
1147
1148 This can be useful in testing situations where you want to control
1149 the resolution behavior of python code without having to change
1150 the system's resolver settings (e.g. /etc/resolv.conf).
1151
1152 The resolver to use may be specified; if it's not, the default
1153 resolver will be used.
1154
1155 @param resolver: the resolver to use
1156 @type resolver: dns.resolver.Resolver object or None
1157 """
1158 if resolver is None:
1159 resolver = get_default_resolver()
1160 global _resolver
1161 _resolver = resolver
1162 socket.getaddrinfo = _getaddrinfo
1163 socket.getnameinfo = _getnameinfo
1164 socket.getfqdn = _getfqdn
1165 socket.gethostbyname = _gethostbyname
1166 socket.gethostbyname_ex = _gethostbyname_ex
1167 socket.gethostbyaddr = _gethostbyaddr
1168
1180