source: trunk/packages/sipb-xen-dns/code/dnsserver.py @ 650

Last change on this file since 650 was 650, checked in by broder, 17 years ago

Empty the authority and additional sections to prevent infinite loops if there
is no response

  • Property svn:executable set to *
File size: 4.3 KB
RevLine 
[181]1#!/usr/bin/python
2from twisted.internet import reactor
3from twisted.names import server
4from twisted.names import dns
5from twisted.names import common
6from twisted.internet import defer
7from twisted.python import failure
8
9import sipb_xen_database
[302]10import psycopg2
11import sqlalchemy
12import time
[181]13
14class DatabaseAuthority(common.ResolverBase):
15    """An Authority that is loaded from a file."""
16
17    soa = None
18
[505]19    def __init__(self, domains, database=None):
[181]20        common.ResolverBase.__init__(self)
21        if database is not None:
22            sipb_xen_database.connect(database)
[505]23        self.domains = domains
[181]24        self.soa = dns.Record_SOA(mname='sipb-xen-dev.mit.edu', 
25                                  rname='sipb-xen.mit.edu',
26                                  serial=1, refresh=3600, retry=900,
27                                  expire=3600000, minimum=21600, ttl=3600)
[582]28        self.ns = dns.Record_NS(name='ns1.xvm.mit.edu', ttl=3600)
[645]29        record = dns.Record_A(address='18.181.0.62', ttl=3600)
30        self.ns1 = dns.RRHeader('ns1.xvm.mit.edu', dns.A, dns.IN,
31                                3600, record, auth=True)
32
[582]33   
[181]34    def _lookup(self, name, cls, type, timeout = None):
[302]35        for i in range(3):
36            try:
37                value = self._lookup_unsafe(name, cls, type, timeout = None)
38            except (psycopg2.OperationalError, sqlalchemy.exceptions.SQLError):
39                if i == 2:
40                    raise
41                print "Reloading database"
42                time.sleep(0.5)
43                continue
44            else:
45                return value
46
47    def _lookup_unsafe(self, name, cls, type, timeout):
[300]48        sipb_xen_database.clear_cache()
[582]49       
50        ttl = 900
[646]51        name = name.lower()
52        if name in self.domains:
53            domain = name
[505]54        else:
[582]55            # This works because domain will remain bound after breaking out of the loop
[505]56            for domain in self.domains:
[646]57                if name.endswith('.'+domain):
[505]58                    break
[508]59            else: #Not us
[505]60                return defer.fail(failure.Failure(dns.DomainError(name)))
[181]61        results = []
62        authority = []
[645]63        additional = [self.ns1]
[541]64        authority.append(dns.RRHeader(domain, dns.NS, dns.IN,
[582]65                                      3600, self.ns, auth=True))
66        if cls == dns.IN:
67            if type in (dns.A, dns.ALL_RECORDS):
68                host = name[:-len(domain)-1]
69                if not host:
[643]70                    record = dns.Record_A('18.181.0.62', ttl)
71                    results.append(dns.RRHeader(name, dns.A, dns.IN, 
[582]72                                                ttl, record, auth=True))
73                else:
74                    value = sipb_xen_database.Machine.get_by(name=host)
75                    if value is None or not value.nics:
76                        return defer.fail(failure.Failure(dns.AuthoritativeDomainError(name)))
77                    ip = value.nics[0].ip
78                    if ip is None:  #Deactivated?
79                        return defer.fail(failure.Failure(dns.AuthoritativeDomainError(name)))
80                    record = dns.Record_A(ip, ttl)
81                    results.append(dns.RRHeader(name, dns.A, dns.IN, 
82                                                ttl, record, auth=True))
83            elif type == dns.NS:
84                results.append(dns.RRHeader(domain, dns.NS, dns.IN,
85                                            ttl, self.ns, auth=True))
86                authority = []
87            elif type == dns.SOA:
88                results.append(dns.RRHeader(domain, dns.SOA, dns.IN,
89                                            ttl, self.soa, auth=True))
[650]90            if len(results) == 0:
91                authority = []
92                additional = []
[582]93            return defer.succeed((results, authority, additional))
94        else:
95            #Doesn't exist
96            return defer.fail(failure.Failure(dns.AuthoritativeDomainError(name)))
[181]97
98if '__main__' == __name__:
[505]99    resolver = DatabaseAuthority(['servers.csail.mit.edu',
100                                  'xvm.mit.edu'],
[181]101                                 'postgres://sipb-xen@sipb-xen-dev/sipb_xen')
102
103    verbosity = 0
104    f = server.DNSServerFactory(authorities=[resolver], verbose=verbosity)
105    p = dns.DNSDatagramProtocol(f)
106    f.noisy = p.noisy = verbosity
107   
108    reactor.listenUDP(53, p)
109    reactor.listenTCP(53, f)
110    reactor.run()
Note: See TracBrowser for help on using the repository browser.