1
# Copyright (c) 2001-2006 Twisted Matrix Laboratories.
2
# See LICENSE for details.
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
12
class SecondaryAuthorityService(service.Service):
15
def __init__(self, primary, domains):
17
@param primary: The IP address of the server from which to perform
20
@param domains: A sequence of domain names for which to perform
23
self.primary = primary
24
self.domains = [SecondaryAuthority(primary, d) for d in domains]
26
def getAuthority(self):
27
return resolve.ResolverChain(self.domains)
29
def startService(self):
30
service.Service.startService(self)
31
self.calls = [task.LoopingCall(d.transfer) for d in self.domains]
33
from twisted.internet import reactor
35
# XXX Add errbacks, respect proper timeouts
36
reactor.callLater(i, c.start, 60 * 60)
39
def stopService(self):
40
service.Service.stopService(self)
45
from twisted.names.authority import FileAuthority
47
class SecondaryAuthority(common.ResolverBase):
48
"""An Authority that keeps itself updated by performing zone transfers"""
53
def __init__(self, primaryIP, domain):
54
common.ResolverBase.__init__(self)
55
self.primary = primaryIP
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
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)))
74
return FileAuthority.__dict__['_lookup'](self, name, cls, type, timeout)
76
#shouldn't we just subclass? :P
78
lookupZone = FileAuthority.__dict__['lookupZone']
80
def _cbZone(self, zone):
84
if not self.soa and rec.type == dns.SOA:
85
self.soa = (str(rec.name).lower(), rec.payload)
87
r.setdefault(str(rec.name).lower(), []).append(rec.payload)
89
def _ebZone(self, failure):
90
log.msg("Updating %s from %s failed during zone transfer" % (self.domain, self.primary))
94
self.transfer().addCallbacks(self._cbTransferred, self._ebTransferred)
96
def _cbTransferred(self, result):
97
self.transferring = False
99
def _ebTransferred(self, failure):
100
self.transferred = False
101
log.msg("Transferring %s from %s failed after zone transfer" % (self.domain, self.primary))