server.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  1. # -*- test-case-name: twisted.names.test.test_names,twisted.names.test.test_server -*-
  2. # Copyright (c) Twisted Matrix Laboratories.
  3. # See LICENSE for details.
  4. """
  5. Async DNS server
  6. Future plans:
  7. - Better config file format maybe
  8. - Make sure to differentiate between different classes
  9. - notice truncation bit
  10. Important: No additional processing is done on some of the record types.
  11. This violates the most basic RFC and is just plain annoying
  12. for resolvers to deal with. Fix it.
  13. @author: Jp Calderone
  14. """
  15. from __future__ import division, absolute_import
  16. import time
  17. from twisted.internet import protocol
  18. from twisted.names import dns, resolve
  19. from twisted.python import log
  20. class DNSServerFactory(protocol.ServerFactory):
  21. """
  22. Server factory and tracker for L{DNSProtocol} connections. This class also
  23. provides records for responses to DNS queries.
  24. @ivar cache: A L{Cache<twisted.names.cache.CacheResolver>} instance whose
  25. C{cacheResult} method is called when a response is received from one of
  26. C{clients}. Defaults to L{None} if no caches are specified. See
  27. C{caches} of L{__init__} for more details.
  28. @type cache: L{Cache<twisted.names.cache.CacheResolver>} or L{None}
  29. @ivar canRecurse: A flag indicating whether this server is capable of
  30. performing recursive DNS resolution.
  31. @type canRecurse: L{bool}
  32. @ivar resolver: A L{resolve.ResolverChain} containing an ordered list of
  33. C{authorities}, C{caches} and C{clients} to which queries will be
  34. dispatched.
  35. @type resolver: L{resolve.ResolverChain}
  36. @ivar verbose: See L{__init__}
  37. @ivar connections: A list of all the connected L{DNSProtocol} instances
  38. using this object as their controller.
  39. @type connections: C{list} of L{DNSProtocol} instances
  40. @ivar protocol: A callable used for building a DNS stream protocol. Called
  41. by L{DNSServerFactory.buildProtocol} and passed the L{DNSServerFactory}
  42. instance as the one and only positional argument. Defaults to
  43. L{dns.DNSProtocol}.
  44. @type protocol: L{IProtocolFactory} constructor
  45. @ivar _messageFactory: A response message constructor with an initializer
  46. signature matching L{dns.Message.__init__}.
  47. @type _messageFactory: C{callable}
  48. """
  49. protocol = dns.DNSProtocol
  50. cache = None
  51. _messageFactory = dns.Message
  52. def __init__(self, authorities=None, caches=None, clients=None, verbose=0):
  53. """
  54. @param authorities: Resolvers which provide authoritative answers.
  55. @type authorities: L{list} of L{IResolver} providers
  56. @param caches: Resolvers which provide cached non-authoritative
  57. answers. The first cache instance is assigned to
  58. C{DNSServerFactory.cache} and its C{cacheResult} method will be
  59. called when a response is received from one of C{clients}.
  60. @type caches: L{list} of L{Cache<twisted.names.cache.CacheResolver>} instances
  61. @param clients: Resolvers which are capable of performing recursive DNS
  62. lookups.
  63. @type clients: L{list} of L{IResolver} providers
  64. @param verbose: An integer controlling the verbosity of logging of
  65. queries and responses. Default is C{0} which means no logging. Set
  66. to C{2} to enable logging of full query and response messages.
  67. @type verbose: L{int}
  68. """
  69. resolvers = []
  70. if authorities is not None:
  71. resolvers.extend(authorities)
  72. if caches is not None:
  73. resolvers.extend(caches)
  74. if clients is not None:
  75. resolvers.extend(clients)
  76. self.canRecurse = not not clients
  77. self.resolver = resolve.ResolverChain(resolvers)
  78. self.verbose = verbose
  79. if caches:
  80. self.cache = caches[-1]
  81. self.connections = []
  82. def _verboseLog(self, *args, **kwargs):
  83. """
  84. Log a message only if verbose logging is enabled.
  85. @param args: Positional arguments which will be passed to C{log.msg}
  86. @param kwargs: Keyword arguments which will be passed to C{log.msg}
  87. """
  88. if self.verbose > 0:
  89. log.msg(*args, **kwargs)
  90. def buildProtocol(self, addr):
  91. p = self.protocol(self)
  92. p.factory = self
  93. return p
  94. def connectionMade(self, protocol):
  95. """
  96. Track a newly connected L{DNSProtocol}.
  97. @param protocol: The protocol instance to be tracked.
  98. @type protocol: L{dns.DNSProtocol}
  99. """
  100. self.connections.append(protocol)
  101. def connectionLost(self, protocol):
  102. """
  103. Stop tracking a no-longer connected L{DNSProtocol}.
  104. @param protocol: The tracked protocol instance to be which has been
  105. lost.
  106. @type protocol: L{dns.DNSProtocol}
  107. """
  108. self.connections.remove(protocol)
  109. def sendReply(self, protocol, message, address):
  110. """
  111. Send a response C{message} to a given C{address} via the supplied
  112. C{protocol}.
  113. Message payload will be logged if C{DNSServerFactory.verbose} is C{>1}.
  114. @param protocol: The DNS protocol instance to which to send the message.
  115. @type protocol: L{dns.DNSDatagramProtocol} or L{dns.DNSProtocol}
  116. @param message: The DNS message to be sent.
  117. @type message: L{dns.Message}
  118. @param address: The address to which the message will be sent or L{None}
  119. if C{protocol} is a stream protocol.
  120. @type address: L{tuple} or L{None}
  121. """
  122. if self.verbose > 1:
  123. s = ' '.join([str(a.payload) for a in message.answers])
  124. auth = ' '.join([str(a.payload) for a in message.authority])
  125. add = ' '.join([str(a.payload) for a in message.additional])
  126. if not s:
  127. log.msg("Replying with no answers")
  128. else:
  129. log.msg("Answers are " + s)
  130. log.msg("Authority is " + auth)
  131. log.msg("Additional is " + add)
  132. if address is None:
  133. protocol.writeMessage(message)
  134. else:
  135. protocol.writeMessage(message, address)
  136. self._verboseLog(
  137. "Processed query in %0.3f seconds" % (
  138. time.time() - message.timeReceived))
  139. def _responseFromMessage(self, message, rCode=dns.OK,
  140. answers=None, authority=None, additional=None):
  141. """
  142. Generate a L{Message} instance suitable for use as the response to
  143. C{message}.
  144. C{queries} will be copied from the request to the response.
  145. C{rCode}, C{answers}, C{authority} and C{additional} will be assigned to
  146. the response, if supplied.
  147. The C{recAv} flag will be set on the response if the C{canRecurse} flag
  148. on this L{DNSServerFactory} is set to L{True}.
  149. The C{auth} flag will be set on the response if *any* of the supplied
  150. C{answers} have their C{auth} flag set to L{True}.
  151. The response will have the same C{maxSize} as the request.
  152. Additionally, the response will have a C{timeReceived} attribute whose
  153. value is that of the original request and the
  154. @see: L{dns._responseFromMessage}
  155. @param message: The request message
  156. @type message: L{Message}
  157. @param rCode: The response code which will be assigned to the response.
  158. @type message: L{int}
  159. @param answers: An optional list of answer records which will be
  160. assigned to the response.
  161. @type answers: L{list} of L{dns.RRHeader}
  162. @param authority: An optional list of authority records which will be
  163. assigned to the response.
  164. @type authority: L{list} of L{dns.RRHeader}
  165. @param additional: An optional list of additional records which will be
  166. assigned to the response.
  167. @type additional: L{list} of L{dns.RRHeader}
  168. @return: A response L{Message} instance.
  169. @rtype: L{Message}
  170. """
  171. if answers is None:
  172. answers = []
  173. if authority is None:
  174. authority = []
  175. if additional is None:
  176. additional = []
  177. authoritativeAnswer = False
  178. for x in answers:
  179. if x.isAuthoritative():
  180. authoritativeAnswer = True
  181. break
  182. response = dns._responseFromMessage(
  183. responseConstructor=self._messageFactory,
  184. message=message,
  185. recAv=self.canRecurse,
  186. rCode=rCode,
  187. auth=authoritativeAnswer
  188. )
  189. # XXX: Timereceived is a hack which probably shouldn't be tacked onto
  190. # the message. Use getattr here so that we don't have to set the
  191. # timereceived on every message in the tests. See #6957.
  192. response.timeReceived = getattr(message, 'timeReceived', None)
  193. # XXX: This is another hack. dns.Message.decode sets maxSize=0 which
  194. # means that responses are never truncated. I'll maintain that behaviour
  195. # here until #6949 is resolved.
  196. response.maxSize = message.maxSize
  197. response.answers = answers
  198. response.authority = authority
  199. response.additional = additional
  200. return response
  201. def gotResolverResponse(self, response, protocol, message, address):
  202. """
  203. A callback used by L{DNSServerFactory.handleQuery} for handling the
  204. deferred response from C{self.resolver.query}.
  205. Constructs a response message by combining the original query message
  206. with the resolved answer, authority and additional records.
  207. Marks the response message as authoritative if any of the resolved
  208. answers are found to be authoritative.
  209. The resolved answers count will be logged if C{DNSServerFactory.verbose}
  210. is C{>1}.
  211. @param response: Answer records, authority records and additional records
  212. @type response: L{tuple} of L{list} of L{dns.RRHeader} instances
  213. @param protocol: The DNS protocol instance to which to send a response
  214. message.
  215. @type protocol: L{dns.DNSDatagramProtocol} or L{dns.DNSProtocol}
  216. @param message: The original DNS query message for which a response
  217. message will be constructed.
  218. @type message: L{dns.Message}
  219. @param address: The address to which the response message will be sent
  220. or L{None} if C{protocol} is a stream protocol.
  221. @type address: L{tuple} or L{None}
  222. """
  223. ans, auth, add = response
  224. response = self._responseFromMessage(
  225. message=message, rCode=dns.OK,
  226. answers=ans, authority=auth, additional=add)
  227. self.sendReply(protocol, response, address)
  228. l = len(ans) + len(auth) + len(add)
  229. self._verboseLog("Lookup found %d record%s" % (l, l != 1 and "s" or ""))
  230. if self.cache and l:
  231. self.cache.cacheResult(
  232. message.queries[0], (ans, auth, add)
  233. )
  234. def gotResolverError(self, failure, protocol, message, address):
  235. """
  236. A callback used by L{DNSServerFactory.handleQuery} for handling deferred
  237. errors from C{self.resolver.query}.
  238. Constructs a response message from the original query message by
  239. assigning a suitable error code to C{rCode}.
  240. An error message will be logged if C{DNSServerFactory.verbose} is C{>1}.
  241. @param failure: The reason for the failed resolution (as reported by
  242. C{self.resolver.query}).
  243. @type failure: L{Failure<twisted.python.failure.Failure>}
  244. @param protocol: The DNS protocol instance to which to send a response
  245. message.
  246. @type protocol: L{dns.DNSDatagramProtocol} or L{dns.DNSProtocol}
  247. @param message: The original DNS query message for which a response
  248. message will be constructed.
  249. @type message: L{dns.Message}
  250. @param address: The address to which the response message will be sent
  251. or L{None} if C{protocol} is a stream protocol.
  252. @type address: L{tuple} or L{None}
  253. """
  254. if failure.check(dns.DomainError, dns.AuthoritativeDomainError):
  255. rCode = dns.ENAME
  256. else:
  257. rCode = dns.ESERVER
  258. log.err(failure)
  259. response = self._responseFromMessage(message=message, rCode=rCode)
  260. self.sendReply(protocol, response, address)
  261. self._verboseLog("Lookup failed")
  262. def handleQuery(self, message, protocol, address):
  263. """
  264. Called by L{DNSServerFactory.messageReceived} when a query message is
  265. received.
  266. Takes the first query from the received message and dispatches it to
  267. C{self.resolver.query}.
  268. Adds callbacks L{DNSServerFactory.gotResolverResponse} and
  269. L{DNSServerFactory.gotResolverError} to the resulting deferred.
  270. Note: Multiple queries in a single message are not supported because
  271. there is no standard way to respond with multiple rCodes, auth,
  272. etc. This is consistent with other DNS server implementations. See
  273. U{http://tools.ietf.org/html/draft-ietf-dnsext-edns1-03} for a proposed
  274. solution.
  275. @param protocol: The DNS protocol instance to which to send a response
  276. message.
  277. @type protocol: L{dns.DNSDatagramProtocol} or L{dns.DNSProtocol}
  278. @param message: The original DNS query message for which a response
  279. message will be constructed.
  280. @type message: L{dns.Message}
  281. @param address: The address to which the response message will be sent
  282. or L{None} if C{protocol} is a stream protocol.
  283. @type address: L{tuple} or L{None}
  284. @return: A C{deferred} which fires with the resolved result or error of
  285. the first query in C{message}.
  286. @rtype: L{Deferred<twisted.internet.defer.Deferred>}
  287. """
  288. query = message.queries[0]
  289. return self.resolver.query(query).addCallback(
  290. self.gotResolverResponse, protocol, message, address
  291. ).addErrback(
  292. self.gotResolverError, protocol, message, address
  293. )
  294. def handleInverseQuery(self, message, protocol, address):
  295. """
  296. Called by L{DNSServerFactory.messageReceived} when an inverse query
  297. message is received.
  298. Replies with a I{Not Implemented} error by default.
  299. An error message will be logged if C{DNSServerFactory.verbose} is C{>1}.
  300. Override in a subclass.
  301. @param protocol: The DNS protocol instance to which to send a response
  302. message.
  303. @type protocol: L{dns.DNSDatagramProtocol} or L{dns.DNSProtocol}
  304. @param message: The original DNS query message for which a response
  305. message will be constructed.
  306. @type message: L{dns.Message}
  307. @param address: The address to which the response message will be sent
  308. or L{None} if C{protocol} is a stream protocol.
  309. @type address: L{tuple} or L{None}
  310. """
  311. message.rCode = dns.ENOTIMP
  312. self.sendReply(protocol, message, address)
  313. self._verboseLog("Inverse query from %r" % (address,))
  314. def handleStatus(self, message, protocol, address):
  315. """
  316. Called by L{DNSServerFactory.messageReceived} when a status message is
  317. received.
  318. Replies with a I{Not Implemented} error by default.
  319. An error message will be logged if C{DNSServerFactory.verbose} is C{>1}.
  320. Override in a subclass.
  321. @param protocol: The DNS protocol instance to which to send a response
  322. message.
  323. @type protocol: L{dns.DNSDatagramProtocol} or L{dns.DNSProtocol}
  324. @param message: The original DNS query message for which a response
  325. message will be constructed.
  326. @type message: L{dns.Message}
  327. @param address: The address to which the response message will be sent
  328. or L{None} if C{protocol} is a stream protocol.
  329. @type address: L{tuple} or L{None}
  330. """
  331. message.rCode = dns.ENOTIMP
  332. self.sendReply(protocol, message, address)
  333. self._verboseLog("Status request from %r" % (address,))
  334. def handleNotify(self, message, protocol, address):
  335. """
  336. Called by L{DNSServerFactory.messageReceived} when a notify message is
  337. received.
  338. Replies with a I{Not Implemented} error by default.
  339. An error message will be logged if C{DNSServerFactory.verbose} is C{>1}.
  340. Override in a subclass.
  341. @param protocol: The DNS protocol instance to which to send a response
  342. message.
  343. @type protocol: L{dns.DNSDatagramProtocol} or L{dns.DNSProtocol}
  344. @param message: The original DNS query message for which a response
  345. message will be constructed.
  346. @type message: L{dns.Message}
  347. @param address: The address to which the response message will be sent
  348. or L{None} if C{protocol} is a stream protocol.
  349. @type address: L{tuple} or L{None}
  350. """
  351. message.rCode = dns.ENOTIMP
  352. self.sendReply(protocol, message, address)
  353. self._verboseLog("Notify message from %r" % (address,))
  354. def handleOther(self, message, protocol, address):
  355. """
  356. Called by L{DNSServerFactory.messageReceived} when a message with
  357. unrecognised I{OPCODE} is received.
  358. Replies with a I{Not Implemented} error by default.
  359. An error message will be logged if C{DNSServerFactory.verbose} is C{>1}.
  360. Override in a subclass.
  361. @param protocol: The DNS protocol instance to which to send a response
  362. message.
  363. @type protocol: L{dns.DNSDatagramProtocol} or L{dns.DNSProtocol}
  364. @param message: The original DNS query message for which a response
  365. message will be constructed.
  366. @type message: L{dns.Message}
  367. @param address: The address to which the response message will be sent
  368. or L{None} if C{protocol} is a stream protocol.
  369. @type address: L{tuple} or L{None}
  370. """
  371. message.rCode = dns.ENOTIMP
  372. self.sendReply(protocol, message, address)
  373. self._verboseLog(
  374. "Unknown op code (%d) from %r" % (message.opCode, address))
  375. def messageReceived(self, message, proto, address=None):
  376. """
  377. L{DNSServerFactory.messageReceived} is called by protocols which are
  378. under the control of this L{DNSServerFactory} whenever they receive a
  379. DNS query message or an unexpected / duplicate / late DNS response
  380. message.
  381. L{DNSServerFactory.allowQuery} is called with the received message,
  382. protocol and origin address. If it returns L{False}, a C{dns.EREFUSED}
  383. response is sent back to the client.
  384. Otherwise the received message is dispatched to one of
  385. L{DNSServerFactory.handleQuery}, L{DNSServerFactory.handleInverseQuery},
  386. L{DNSServerFactory.handleStatus}, L{DNSServerFactory.handleNotify}, or
  387. L{DNSServerFactory.handleOther} depending on the I{OPCODE} of the
  388. received message.
  389. If C{DNSServerFactory.verbose} is C{>0} all received messages will be
  390. logged in more or less detail depending on the value of C{verbose}.
  391. @param message: The DNS message that was received.
  392. @type message: L{dns.Message}
  393. @param proto: The DNS protocol instance which received the message
  394. @type proto: L{dns.DNSDatagramProtocol} or L{dns.DNSProtocol}
  395. @param address: The address from which the message was received. Only
  396. provided for messages received by datagram protocols. The origin of
  397. Messages received from stream protocols can be gleaned from the
  398. protocol C{transport} attribute.
  399. @type address: L{tuple} or L{None}
  400. """
  401. message.timeReceived = time.time()
  402. if self.verbose:
  403. if self.verbose > 1:
  404. s = ' '.join([str(q) for q in message.queries])
  405. else:
  406. s = ' '.join([dns.QUERY_TYPES.get(q.type, 'UNKNOWN')
  407. for q in message.queries])
  408. if not len(s):
  409. log.msg(
  410. "Empty query from %r" % (
  411. (address or proto.transport.getPeer()),))
  412. else:
  413. log.msg(
  414. "%s query from %r" % (
  415. s, address or proto.transport.getPeer()))
  416. if not self.allowQuery(message, proto, address):
  417. message.rCode = dns.EREFUSED
  418. self.sendReply(proto, message, address)
  419. elif message.opCode == dns.OP_QUERY:
  420. self.handleQuery(message, proto, address)
  421. elif message.opCode == dns.OP_INVERSE:
  422. self.handleInverseQuery(message, proto, address)
  423. elif message.opCode == dns.OP_STATUS:
  424. self.handleStatus(message, proto, address)
  425. elif message.opCode == dns.OP_NOTIFY:
  426. self.handleNotify(message, proto, address)
  427. else:
  428. self.handleOther(message, proto, address)
  429. def allowQuery(self, message, protocol, address):
  430. """
  431. Called by L{DNSServerFactory.messageReceived} to decide whether to
  432. process a received message or to reply with C{dns.EREFUSED}.
  433. This default implementation permits anything but empty queries.
  434. Override in a subclass to implement alternative policies.
  435. @param message: The DNS message that was received.
  436. @type message: L{dns.Message}
  437. @param protocol: The DNS protocol instance which received the message
  438. @type protocol: L{dns.DNSDatagramProtocol} or L{dns.DNSProtocol}
  439. @param address: The address from which the message was received. Only
  440. provided for messages received by datagram protocols. The origin of
  441. Messages received from stream protocols can be gleaned from the
  442. protocol C{transport} attribute.
  443. @type address: L{tuple} or L{None}
  444. @return: L{True} if the received message contained one or more queries,
  445. else L{False}.
  446. @rtype: L{bool}
  447. """
  448. return len(message.queries)