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

Last change on this file since 650 was 650, checked in by broder, 16 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
Line 
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
10import psycopg2
11import sqlalchemy
12import time
13
14class DatabaseAuthority(common.ResolverBase):
15    """An Authority that is loaded from a file."""
16
17    soa = None
18
19    def __init__(self, domains, database=None):
20        common.ResolverBase.__init__(self)
21        if database is not None:
22            sipb_xen_database.connect(database)
23        self.domains = domains
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)
28        self.ns = dns.Record_NS(name='ns1.xvm.mit.edu', ttl=3600)
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
33   
34    def _lookup(self, name, cls, type, timeout = None):
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):
48        sipb_xen_database.clear_cache()
49       
50        ttl = 900
51        name = name.lower()
52        if name in self.domains:
53            domain = name
54        else:
55            # This works because domain will remain bound after breaking out of the loop
56            for domain in self.domains:
57                if name.endswith('.'+domain):
58                    break
59            else: #Not us
60                return defer.fail(failure.Failure(dns.DomainError(name)))
61        results = []
62        authority = []
63        additional = [self.ns1]
64        authority.append(dns.RRHeader(domain, dns.NS, dns.IN,
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:
70                    record = dns.Record_A('18.181.0.62', ttl)
71                    results.append(dns.RRHeader(name, dns.A, dns.IN, 
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))
90            if len(results) == 0:
91                authority = []
92                additional = []
93            return defer.succeed((results, authority, additional))
94        else:
95            #Doesn't exist
96            return defer.fail(failure.Failure(dns.AuthoritativeDomainError(name)))
97
98if '__main__' == __name__:
99    resolver = DatabaseAuthority(['servers.csail.mit.edu',
100                                  'xvm.mit.edu'],
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.