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