~certify-web-dev/twisted/certify-trunk

« back to all changes in this revision

Viewing changes to twisted/names/server.py

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2007-01-17 14:52:35 UTC
  • mfrom: (1.1.5 upstream) (2.1.2 etch)
  • Revision ID: james.westby@ubuntu.com-20070117145235-btmig6qfmqfen0om
Tags: 2.5.0-0ubuntu1
New upstream version, compatible with python2.5.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- test-case-name: twisted.names.test.test_names -*-
 
2
# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
 
3
# See LICENSE for details.
 
4
 
 
5
 
 
6
"""
 
7
Async DNS server
 
8
 
 
9
API Stability: Unstable
 
10
 
 
11
Future plans:
 
12
    - Better config file format maybe
 
13
    - Make sure to differentiate between different classes
 
14
    - notice truncation bit
 
15
 
 
16
Important: No additional processing is done on some of the record types.
 
17
This violates the most basic RFC and is just plain annoying
 
18
for resolvers to deal with.  Fix it.
 
19
 
 
20
@author: U{Jp Calderone <mailto:exarkun@twistedmatrix.com>}
 
21
"""
 
22
 
 
23
from __future__ import nested_scopes
 
24
import time
 
25
 
 
26
# Twisted imports
 
27
from twisted.internet import protocol
 
28
from twisted.names import dns
 
29
from twisted.python import log
 
30
 
 
31
import resolve
 
32
 
 
33
class DNSServerFactory(protocol.ServerFactory):
 
34
    protocol = dns.DNSProtocol
 
35
    cache = None
 
36
 
 
37
    def __init__(self, authorities = None, caches = None, clients = None, verbose = 0):
 
38
        resolvers = []
 
39
        if authorities is not None:
 
40
            resolvers.extend(authorities)
 
41
        if caches is not None:
 
42
            resolvers.extend(caches)
 
43
        if clients is not None:
 
44
            resolvers.extend(clients)
 
45
 
 
46
        self.canRecurse = not not clients
 
47
        self.resolver = resolve.ResolverChain(resolvers)
 
48
        self.verbose = verbose
 
49
        if caches:
 
50
            self.cache = caches[-1]
 
51
 
 
52
 
 
53
    def buildProtocol(self, addr):
 
54
        p = self.protocol(self)
 
55
        p.factory = self
 
56
        return p
 
57
 
 
58
    def connectionMade(self, protocol):
 
59
        pass
 
60
 
 
61
 
 
62
    def sendReply(self, protocol, message, address):
 
63
        if self.verbose > 1:
 
64
            s = ' '.join([str(a.payload) for a in message.answers])
 
65
            auth = ' '.join([str(a.payload) for a in message.authority])
 
66
            add = ' '.join([str(a.payload) for a in message.additional])
 
67
            if not s:
 
68
                log.msg("Replying with no answers")
 
69
            else:
 
70
                log.msg("Answers are " + s)
 
71
                log.msg("Authority is " + auth)
 
72
                log.msg("Additional is " + add)
 
73
 
 
74
        if address is None:
 
75
            protocol.writeMessage(message)
 
76
        else:
 
77
            protocol.writeMessage(message, address)
 
78
 
 
79
        if self.verbose > 1:
 
80
            log.msg("Processed query in %0.3f seconds" % (time.time() - message.timeReceived))
 
81
 
 
82
 
 
83
    def gotResolverResponse(self, (ans, auth, add), protocol, message, address):
 
84
        message.rCode = dns.OK
 
85
        message.answers = ans
 
86
        for x in ans:
 
87
            if x.isAuthoritative():
 
88
                message.auth = 1
 
89
                break
 
90
        message.authority = auth
 
91
        message.additional = add
 
92
        self.sendReply(protocol, message, address)
 
93
 
 
94
        l = len(ans) + len(auth) + len(add)
 
95
        if self.verbose:
 
96
            log.msg("Lookup found %d record%s" % (l, l != 1 and "s" or ""))
 
97
 
 
98
        if self.cache and l:
 
99
            self.cache.cacheResult(
 
100
                message.queries[0], (ans, auth, add)
 
101
            )
 
102
 
 
103
 
 
104
    def gotResolverError(self, failure, protocol, message, address):
 
105
        if failure.check(dns.DomainError, dns.AuthoritativeDomainError):
 
106
            message.rCode = dns.ENAME
 
107
        else:
 
108
            message.rCode = dns.ESERVER
 
109
            log.err(failure)
 
110
 
 
111
        self.sendReply(protocol, message, address)
 
112
        if self.verbose:
 
113
            log.msg("Lookup failed")
 
114
 
 
115
 
 
116
    def handleQuery(self, message, protocol, address):
 
117
        # Discard all but the first query!  HOO-AAH HOOOOO-AAAAH
 
118
        # (no other servers implement multi-query messages, so we won't either)
 
119
        query = message.queries[0]
 
120
 
 
121
        return self.resolver.query(query).addCallback(
 
122
            self.gotResolverResponse, protocol, message, address
 
123
        ).addErrback(
 
124
            self.gotResolverError, protocol, message, address
 
125
        )
 
126
 
 
127
 
 
128
    def handleInverseQuery(self, message, protocol, address):
 
129
        message.rCode = dns.ENOTIMP
 
130
        self.sendReply(protocol, message, address)
 
131
        if self.verbose:
 
132
            log.msg("Inverse query from %r" % (address,))
 
133
 
 
134
 
 
135
    def handleStatus(self, message, protocol, address):
 
136
        message.rCode = dns.ENOTIMP
 
137
        self.sendReply(protocol, message, address)
 
138
        if self.verbose:
 
139
            log.msg("Status request from %r" % (address,))
 
140
 
 
141
 
 
142
    def handleNotify(self, message, protocol, address):
 
143
        message.rCode = dns.ENOTIMP
 
144
        self.sendReply(protocol, message, address)
 
145
        if self.verbose:
 
146
            log.msg("Notify message from %r" % (address,))
 
147
 
 
148
 
 
149
    def handleOther(self, message, protocol, address):
 
150
        message.rCode = dns.ENOTIMP
 
151
        self.sendReply(protocol, message, address)
 
152
        if self.verbose:
 
153
            log.msg("Unknown op code (%d) from %r" % (message.opCode, address))
 
154
 
 
155
 
 
156
    def messageReceived(self, message, proto, address = None):
 
157
        message.timeReceived = time.time()
 
158
 
 
159
        if self.verbose:
 
160
            if self.verbose > 1:
 
161
                s = ' '.join([str(q) for q in message.queries])
 
162
            elif self.verbose > 0:
 
163
                s = ' '.join([dns.QUERY_TYPES.get(q.type, 'UNKNOWN') for q in message.queries])
 
164
 
 
165
            if not len(s):
 
166
                log.msg("Empty query from %r" % ((address or proto.transport.getPeer()),))
 
167
            else:
 
168
                log.msg("%s query from %r" % (s, address or proto.transport.getPeer()))
 
169
 
 
170
        message.recAv = self.canRecurse
 
171
        message.answer = 1
 
172
 
 
173
        if not self.allowQuery(message, proto, address):
 
174
            message.rCode = dns.EREFUSED
 
175
            self.sendReply(proto, message, address)
 
176
        elif message.opCode == dns.OP_QUERY:
 
177
            self.handleQuery(message, proto, address)
 
178
        elif message.opCode == dns.OP_INVERSE:
 
179
            self.handleInverseQuery(message, proto, address)
 
180
        elif message.opCode == dns.OP_STATUS:
 
181
            self.handleStatus(message, proto, address)
 
182
        elif message.opCode == dns.OP_NOTIFY:
 
183
            self.handleNotify(message, proto, address)
 
184
        else:
 
185
            self.handleOther(message, proto, address)
 
186
 
 
187
 
 
188
    def allowQuery(self, message, protocol, address):
 
189
        # Allow anything but empty queries
 
190
        return len(message.queries)