| OLD | NEW |
| (Empty) |
| 1 # Copyright (c) 2001-2006 Twisted Matrix Laboratories. | |
| 2 # See LICENSE for details. | |
| 3 | |
| 4 from twisted.internet import task, defer | |
| 5 from twisted.names import dns | |
| 6 from twisted.names import common | |
| 7 from twisted.names import client | |
| 8 from twisted.names import resolve | |
| 9 from twisted.python import log, failure | |
| 10 from twisted.application import service | |
| 11 | |
| 12 class SecondaryAuthorityService(service.Service): | |
| 13 calls = None | |
| 14 | |
| 15 def __init__(self, primary, domains): | |
| 16 """ | |
| 17 @param primary: The IP address of the server from which to perform | |
| 18 zone transfers. | |
| 19 | |
| 20 @param domains: A sequence of domain names for which to perform | |
| 21 zone transfers. | |
| 22 """ | |
| 23 self.primary = primary | |
| 24 self.domains = [SecondaryAuthority(primary, d) for d in domains] | |
| 25 | |
| 26 def getAuthority(self): | |
| 27 return resolve.ResolverChain(self.domains) | |
| 28 | |
| 29 def startService(self): | |
| 30 service.Service.startService(self) | |
| 31 self.calls = [task.LoopingCall(d.transfer) for d in self.domains] | |
| 32 i = 0 | |
| 33 from twisted.internet import reactor | |
| 34 for c in self.calls: | |
| 35 # XXX Add errbacks, respect proper timeouts | |
| 36 reactor.callLater(i, c.start, 60 * 60) | |
| 37 i += 1 | |
| 38 | |
| 39 def stopService(self): | |
| 40 service.Service.stopService(self) | |
| 41 for c in self.calls: | |
| 42 c.stop() | |
| 43 | |
| 44 | |
| 45 from twisted.names.authority import FileAuthority | |
| 46 | |
| 47 class SecondaryAuthority(common.ResolverBase): | |
| 48 """An Authority that keeps itself updated by performing zone transfers""" | |
| 49 | |
| 50 transferring = False | |
| 51 | |
| 52 soa = records = None | |
| 53 def __init__(self, primaryIP, domain): | |
| 54 common.ResolverBase.__init__(self) | |
| 55 self.primary = primaryIP | |
| 56 self.domain = domain | |
| 57 | |
| 58 def transfer(self): | |
| 59 if self.transferring: | |
| 60 return | |
| 61 self.transfering = True | |
| 62 return client.Resolver(servers=[(self.primary, dns.PORT)] | |
| 63 ).lookupZone(self.domain | |
| 64 ).addCallback(self._cbZone | |
| 65 ).addErrback(self._ebZone | |
| 66 ) | |
| 67 | |
| 68 | |
| 69 def _lookup(self, name, cls, type, timeout=None): | |
| 70 if not self.soa or not self.records: | |
| 71 return defer.fail(failure.Failure(dns.DomainError(name))) | |
| 72 | |
| 73 | |
| 74 return FileAuthority.__dict__['_lookup'](self, name, cls, type, timeout) | |
| 75 | |
| 76 #shouldn't we just subclass? :P | |
| 77 | |
| 78 lookupZone = FileAuthority.__dict__['lookupZone'] | |
| 79 | |
| 80 def _cbZone(self, zone): | |
| 81 ans, _, _ = zone | |
| 82 self.records = r = {} | |
| 83 for rec in ans: | |
| 84 if not self.soa and rec.type == dns.SOA: | |
| 85 self.soa = (str(rec.name).lower(), rec.payload) | |
| 86 else: | |
| 87 r.setdefault(str(rec.name).lower(), []).append(rec.payload) | |
| 88 | |
| 89 def _ebZone(self, failure): | |
| 90 log.msg("Updating %s from %s failed during zone transfer" % (self.domain
, self.primary)) | |
| 91 log.err(failure) | |
| 92 | |
| 93 def update(self): | |
| 94 self.transfer().addCallbacks(self._cbTransferred, self._ebTransferred) | |
| 95 | |
| 96 def _cbTransferred(self, result): | |
| 97 self.transferring = False | |
| 98 | |
| 99 def _ebTransferred(self, failure): | |
| 100 self.transferred = False | |
| 101 log.msg("Transferring %s from %s failed after zone transfer" % (self.dom
ain, self.primary)) | |
| 102 log.err(failure) | |
| OLD | NEW |