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

Last change on this file since 865 was 851, checked in by y_z, 16 years ago
  • sipb_xen_database -> invirt.database
  • use invirt.config in dnsserver.py
  • Property svn:executable set to *
File size: 4.7 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
9from invirt.config import structs as config
10import invirt.database
11import psycopg2
12import sqlalchemy
13import time
14
15class DatabaseAuthority(common.ResolverBase):
16    """An Authority that is loaded from a file."""
17
18    soa = None
19
20    def __init__(self, domains=None, database=None):
21        common.ResolverBase.__init__(self)
22        if database is not None:
23            invirt.database.connect(database)
24        else:
25            invirt.database.connect()
26        if domains is not None:
27            self.domains = domains
28        else:
29            self.domains = config.dns.domains
30        ns = config.dns.nameservers[0]
31        self.soa = dns.Record_SOA(mname=ns.hostname,
32                                  rname=config.dns.contact.replace('@','.',1),
33                                  serial=1, refresh=3600, retry=900,
34                                  expire=3600000, minimum=21600, ttl=3600)
35        self.ns = dns.Record_NS(name=ns.hostname, ttl=3600)
36        record = dns.Record_A(address=ns.ip, ttl=3600)
37        self.ns1 = dns.RRHeader(ns.hostname, dns.A, dns.IN,
38                                3600, record, auth=True)
39
40   
41    def _lookup(self, name, cls, type, timeout = None):
42        for i in range(3):
43            try:
44                value = self._lookup_unsafe(name, cls, type, timeout = None)
45            except (psycopg2.OperationalError, sqlalchemy.exceptions.SQLError):
46                if i == 2:
47                    raise
48                print "Reloading database"
49                time.sleep(0.5)
50                continue
51            else:
52                return value
53
54    def _lookup_unsafe(self, name, cls, type, timeout):
55        invirt.database.clear_cache()
56       
57        ttl = 900
58        name = name.lower()
59        if name in self.domains:
60            domain = name
61        else:
62            # This works because domain will remain bound after breaking out of the loop
63            for domain in self.domains:
64                if name.endswith('.'+domain):
65                    break
66            else: #Not us
67                return defer.fail(failure.Failure(dns.DomainError(name)))
68        results = []
69        authority = []
70        additional = [self.ns1]
71        authority.append(dns.RRHeader(domain, dns.NS, dns.IN,
72                                      3600, self.ns, auth=True))
73        if cls == dns.IN:
74            host = name[:-len(domain)-1]
75            if not host:
76                if type in (dns.A, dns.ALL_RECORDS):
77                    record = dns.Record_A(config.dns.nameservers[0].ip, ttl)
78                    results.append(dns.RRHeader(name, dns.A, dns.IN, 
79                                                ttl, record, auth=True))
80                elif type == dns.NS:
81                    results.append(dns.RRHeader(domain, dns.NS, dns.IN,
82                                                ttl, self.ns, auth=True))
83                    authority = []
84                elif type == dns.SOA:
85                    results.append(dns.RRHeader(domain, dns.SOA, dns.IN,
86                                                ttl, self.soa, auth=True))
87            else:
88                if host:
89                    value = invirt.database.Machine.get_by(name=host)
90                    if value is None or not value.nics:
91                        return defer.fail(failure.Failure(dns.AuthoritativeDomainError(name)))
92                    ip = value.nics[0].ip
93                    if ip is None:  #Deactivated?
94                        return defer.fail(failure.Failure(dns.AuthoritativeDomainError(name)))
95                if type in (dns.A, dns.ALL_RECORDS):
96                    record = dns.Record_A(ip, ttl)
97                    results.append(dns.RRHeader(name, dns.A, dns.IN, 
98                                                ttl, record, auth=True))
99                elif type == dns.SOA:
100                    results.append(dns.RRHeader(domain, dns.SOA, dns.IN,
101                                                ttl, self.soa, auth=True))
102            if len(results) == 0:
103                authority = []
104                additional = []
105            return defer.succeed((results, authority, additional))
106        else:
107            #Doesn't exist
108            return defer.fail(failure.Failure(dns.AuthoritativeDomainError(name)))
109
110if '__main__' == __name__:
111    resolver = DatabaseAuthority()
112
113    verbosity = 0
114    f = server.DNSServerFactory(authorities=[resolver], verbose=verbosity)
115    p = dns.DNSDatagramProtocol(f)
116    f.noisy = p.noisy = verbosity
117   
118    reactor.listenUDP(53, p)
119    reactor.listenTCP(53, f)
120    reactor.run()
Note: See TracBrowser for help on using the repository browser.