Mailinglist Archive: opensuse-commit (2092 mails)

< Previous Next >
commit python-twisted-names
  • From: root@xxxxxxxxxxxxxxx (h_root)
  • Date: Thu, 02 Aug 2007 23:33:05 +0200
  • Message-id: <20070802213306.024966781B8@xxxxxxxxxxxxxxx>

Hello community,

here is the log from the commit of package python-twisted-names
checked in at Thu Aug 2 23:33:05 CEST 2007.

--------
--- python-twisted-names/python-twisted-names.changes   2006-10-26 18:35:40.000000000 +0200
+++ /mounts/work_src_done/STABLE/python-twisted-names/python-twisted-names.changes      2007-08-02 17:09:46.000000000 +0200
@@ -1,0 +2,8 @@
+Thu Aug  2 17:09:01 CEST 2007 - jmatejek@xxxxxxx
+
+- update to 0.4.0
+  * support for DNS error handling
+  * fixed DoS in UDP DNS server
+  * minor bugfixes
+
+-------------------------------------------------------------------

Old:
----
  TwistedNames-0.3.0.tar.bz2

New:
----
  TwistedNames-0.4.0.tar.bz2

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-twisted-names.spec ++++++
--- /var/tmp/diff_new_pack.x19065/_old  2007-08-02 23:32:49.000000000 +0200
+++ /var/tmp/diff_new_pack.x19065/_new  2007-08-02 23:32:49.000000000 +0200
@@ -1,7 +1,7 @@
 #
-# spec file for package python-twisted-names (Version 0.3.0)
+# spec file for package python-twisted-names (Version 0.4.0)
 #
-# Copyright (c) 2006 SUSE LINUX Products GmbH, Nuernberg, Germany.
+# Copyright (c) 2007 SUSE LINUX Products GmbH, Nuernberg, Germany.
 # This file and all modifications and additions to the pristine
 # package are under the same license as the package itself.
 #
@@ -13,7 +13,7 @@
 Name:           python-twisted-names
 BuildRequires:  python-devel python-twisted
 Summary:        Twisted Names
-Version:        0.3.0
+Version:        0.4.0
 Release:        1
 %define tarname TwistedNames
 Source:         %{tarname}-%{version}.tar.bz2
@@ -58,7 +58,12 @@
 %defattr(-,root,root)
 %doc LICENSE README NEWS
 
-%changelog -n python-twisted-names
+%changelog
+* Thu Aug 02 2007 - jmatejek@xxxxxxx
+- update to 0.4.0
+  * support for DNS error handling
+  * fixed DoS in UDP DNS server
+  * minor bugfixes
 * Thu Oct 26 2006 - jmatejek@xxxxxxx
 - update to 0.3.0
  - upgrade to Twisted 2.4 install system

++++++ TwistedNames-0.3.0.tar.bz2 -> TwistedNames-0.4.0.tar.bz2 ++++++
diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/TwistedNames-0.3.0/doc/examples/dns-service.py new/TwistedNames-0.4.0/doc/examples/dns-service.py
--- old/TwistedNames-0.3.0/doc/examples/dns-service.py  2004-07-30 14:01:15.000000000 +0200
+++ new/TwistedNames-0.4.0/doc/examples/dns-service.py  2006-12-29 06:01:40.000000000 +0100
@@ -25,7 +25,7 @@
     sys.exit(1)
 
 resolver = client.Resolver('/etc/resolv.conf')
-d = resolver.lookupService('_%s._%s.%s' % (service, proto, domain), 1)
+d = resolver.lookupService('_%s._%s.%s' % (service, proto, domain), [1])
 d.addCallbacks(printAnswer, printFailure)
 
 reactor.run()
diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/TwistedNames-0.3.0/doc/examples/gethostbyname.py new/TwistedNames-0.4.0/doc/examples/gethostbyname.py
--- old/TwistedNames-0.3.0/doc/examples/gethostbyname.py        2004-07-30 14:01:15.000000000 +0200
+++ new/TwistedNames-0.4.0/doc/examples/gethostbyname.py        2006-12-29 06:01:40.000000000 +0100
@@ -12,7 +12,7 @@
     failure.printTraceback()
     reactor.stop()
 
-gethostbyname = client.theResolver.getHostByName
-gethostbyname(sys.argv[1]).addCallbacks(gotResult, gotFailure)
+d = client.getHostByName(sys.argv[1])
+d.addCallbacks(gotResult, gotFailure)
 
 reactor.run()
diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/TwistedNames-0.3.0/doc/examples/index.html new/TwistedNames-0.4.0/doc/examples/index.html
--- old/TwistedNames-0.3.0/doc/examples/index.html      2006-05-25 03:08:23.000000000 +0200
+++ new/TwistedNames-0.4.0/doc/examples/index.html      2007-01-07 03:43:17.000000000 +0100
@@ -1,2 +1,2 @@
 <?xml version="1.0"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd";><html xmlns="http://www.w3.org/1999/xhtml" lang="en";><head><title>Twisted Documentation: Twisted Names code examples</title><link href="../howto/stylesheet.css" type="text/css" rel="stylesheet" /></head><body bgcolor="white"><h1 class="title">Twisted Names code examples</h1><div class="toc"><ol><li><a href="#auto0">DNS (Twisted Names)</a></li></ol></div><div class="content"><span></span><h2>DNS (Twisted Names)<a name="auto0"></a></h2><ul><li><a href="testdns.py">testdns.py</a></li><li><a href="dns-service.py">dns-service.py</a></li><li><a href="gethostbyname.py">gethostbyname.py</a></li></ul></div><p><a href="../howto/index.html">Index</a></p><span class="version">Version: 0.3.0</span></body></html>
\ No newline at end of file
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd";><html xmlns="http://www.w3.org/1999/xhtml" lang="en";><head><title>Twisted Documentation: Twisted Names code examples</title><link href="../howto/stylesheet.css" type="text/css" rel="stylesheet" /></head><body bgcolor="white"><h1 class="title">Twisted Names code examples</h1><div class="toc"><ol><li><a href="#auto0">DNS (Twisted Names)</a></li></ol></div><div class="content"><span></span><h2>DNS (Twisted Names)<a name="auto0"></a></h2><ul><li><a href="testdns.py">testdns.py</a></li><li><a href="dns-service.py">dns-service.py</a></li><li><a href="gethostbyname.py">gethostbyname.py</a></li></ul></div><p><a href="../howto/index.html">Index</a></p><span class="version">Version: 0.4.0</span></body></html>
\ No newline at end of file
diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/TwistedNames-0.3.0/doc/examples/testdns.py new/TwistedNames-0.4.0/doc/examples/testdns.py
--- old/TwistedNames-0.3.0/doc/examples/testdns.py      2004-07-30 14:01:15.000000000 +0200
+++ new/TwistedNames-0.4.0/doc/examples/testdns.py      2006-07-02 05:53:32.000000000 +0200
@@ -3,7 +3,7 @@
 import sys
 from twisted.names import client
 from twisted.internet import reactor
-from twisted.protocols import dns
+from twisted.names import dns
 
 r = client.Resolver('/etc/resolv.conf')
 
diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/TwistedNames-0.3.0/doc/howto/index.html new/TwistedNames-0.4.0/doc/howto/index.html
--- old/TwistedNames-0.3.0/doc/howto/index.html 2006-05-25 03:08:22.000000000 +0200
+++ new/TwistedNames-0.4.0/doc/howto/index.html 2007-01-07 03:43:17.000000000 +0100
@@ -1,2 +1,2 @@
 <?xml version="1.0"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd";><html xmlns="http://www.w3.org/1999/xhtml" lang="en";><head><title>Twisted Documentation: Twisted Names Documentation</title><link href="../howto/stylesheet.css" type="text/css" rel="stylesheet" /></head><body bgcolor="white"><h1 class="title">Twisted Names Documentation</h1><div class="toc"><ol></ol></div><div class="content"><span></span><ul class="toc"><li><a href="names.html">Names DNS library</a></li></ul></div><p><a href="../howto/index.html">Index</a></p><span class="version">Version: 0.3.0</span></body></html>
\ No newline at end of file
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd";><html xmlns="http://www.w3.org/1999/xhtml" lang="en";><head><title>Twisted Documentation: Twisted Names Documentation</title><link href="../howto/stylesheet.css" type="text/css" rel="stylesheet" /></head><body bgcolor="white"><h1 class="title">Twisted Names Documentation</h1><div class="toc"><ol></ol></div><div class="content"><span></span><ul class="toc"><li><a href="names.html">Names DNS library</a></li></ul></div><p><a href="../howto/index.html">Index</a></p><span class="version">Version: 0.4.0</span></body></html>
\ No newline at end of file
diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/TwistedNames-0.3.0/doc/howto/names.html new/TwistedNames-0.4.0/doc/howto/names.html
--- old/TwistedNames-0.3.0/doc/howto/names.html 2006-05-25 03:08:23.000000000 +0200
+++ new/TwistedNames-0.4.0/doc/howto/names.html 2007-01-07 03:43:17.000000000 +0100
@@ -3,8 +3,7 @@
 <ul><li>act as a recursive server, forwarding queries to other servers</li><li>perform local caching of recursively discovered records</li><li>act as the authoritative server for a domain</li></ul><h3>Creating a non-authoritative server<a name="auto0"></a></h3>
 The first two of these are easy, and you can create a server that performs
 them with the command <code class="shell">mktap dns --recursive
---cache</code>, or launch <code class="shell">tkmktap</code> and configure a
-dns server with it.  The result should be a file named <code>dns.tap</code>. 
+--cache</code>.  The result should be a file named <code>dns.tap</code>. 
 Now switch to a superuser account (if required by your platform to bind to
 port 53) and run <code class="shell">twistd -f dns.tap</code>.  The
 Application will run and bind to port 53.  Try performing a lookup with it,
@@ -60,4 +59,4 @@
 </p><p>Names can also read a traditional, BIND-syntax zone file.  Specify these
 with the <code>--bindzone</code> parameter.  The $GENERATE and $INCLUDE
 directives are not yet supported.
-</p></div><p><a href="../howto/index.html">Index</a></p><span class="version">Version: 0.3.0</span></body></html>
\ No newline at end of file
+</p></div><p><a href="../howto/index.html">Index</a></p><span class="version">Version: 0.4.0</span></body></html>
\ No newline at end of file
diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/TwistedNames-0.3.0/LICENSE new/TwistedNames-0.4.0/LICENSE
--- old/TwistedNames-0.3.0/LICENSE      2006-04-18 04:43:54.000000000 +0200
+++ new/TwistedNames-0.4.0/LICENSE      2006-06-03 22:59:55.000000000 +0200
@@ -6,6 +6,7 @@
 Bob Ippolito
 Canonical Limited
 Christopher Armstrong
+David Reid
 Donovan Preston
 Eric Mangold
 Itamar Shtull-Trauring
diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/TwistedNames-0.3.0/NEWS new/TwistedNames-0.4.0/NEWS
--- old/TwistedNames-0.3.0/NEWS 2006-05-22 00:28:51.000000000 +0200
+++ new/TwistedNames-0.4.0/NEWS 2007-01-06 22:50:02.000000000 +0100
@@ -1,3 +1,23 @@
+0.4.0 (2007-01-06)
+==================
+
+Features
+--------
+
+ - In the twisted.names client, DNS responses which represent errors
+   are now translated to informative exception objects, rather than
+   empty lists. This means that client requests which fail will now
+   errback their Deferreds (#2248)
+
+Fixes
+-----
+ - A major DoS vulnerability in the UDP DNS server was fixed (#1708)
+
+Misc
+----
+ - #1799, #1636, #2149, #2181
+
+
 0.3.0 (2006-05-21)
 ==================
 
diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/TwistedNames-0.3.0/README new/TwistedNames-0.4.0/README
--- old/TwistedNames-0.3.0/README       2006-05-22 00:28:51.000000000 +0200
+++ new/TwistedNames-0.4.0/README       2007-01-06 22:42:54.000000000 +0100
@@ -1,3 +1,3 @@
-Twisted Names 0.3.0
+Twisted Names 0.4.0
 
 Twisted Names depends on Twisted Core.
diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/TwistedNames-0.3.0/twisted/names/cache.py new/TwistedNames-0.4.0/twisted/names/cache.py
--- old/TwistedNames-0.3.0/twisted/names/cache.py       2006-03-17 04:29:41.000000000 +0100
+++ new/TwistedNames-0.4.0/twisted/names/cache.py       2006-07-01 18:08:17.000000000 +0200
@@ -8,7 +8,7 @@
 from zope.interface import implements
 
 from twisted.names import dns
-from twisted.python import failure, log, components
+from twisted.python import failure, log
 from twisted.internet import interfaces, defer
 
 import common
diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/TwistedNames-0.3.0/twisted/names/client.py new/TwistedNames-0.4.0/twisted/names/client.py
--- old/TwistedNames-0.3.0/twisted/names/client.py      2006-03-17 04:29:41.000000000 +0100
+++ new/TwistedNames-0.4.0/twisted/names/client.py      2006-12-29 06:01:40.000000000 +0100
@@ -1,5 +1,5 @@
 # -*- test-case-name: twisted.names.test.test_names -*-
-# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
+# Copyright (c) 2001-2006 Twisted Matrix Laboratories.
 # See LICENSE for details.
 
 
@@ -8,6 +8,13 @@
 
 API Stability: Unstable
 
+The functions exposed in this module can be used for asynchronous name
+resolution and dns queries.
+
+If you need to create a resolver with specific requirements, such as needing to
+do queries against a particular host, the L{createResolver} function will
+return an C{IResolver}.
+
 Future plans: Proper nameserver acquisition on Windows/MacOS,
 better caching, respect timeouts
 
@@ -19,13 +26,17 @@
 import os
 import errno
 
+from zope.interface import implements
+
 # Twisted imports
 from twisted.python.runtime import platform
 from twisted.internet import error, defer, protocol, interfaces
-from twisted.python import log, failure, components
-from twisted.names import dns
-from zope.interface import implements
-import common
+from twisted.python import log, failure
+from twisted.names import dns, common
+from twisted.names.error import DNSFormatError, DNSServerError, DNSNameError
+from twisted.names.error import DNSNotImplementedError, DNSQueryRefusedError
+from twisted.names.error import DNSUnknownError
+
 
 class Resolver(common.ResolverBase):
     implements(interfaces.IResolver)
@@ -44,6 +55,13 @@
     _lastResolvTime = None
     _resolvReadInterval = 60
 
+    _errormap = {
+        dns.EFORMAT: DNSFormatError,
+        dns.ESERVER: DNSServerError,
+        dns.ENAME: DNSNameError,
+        dns.ENOTIMP: DNSNotImplementedError,
+        dns.EREFUSED: DNSQueryRefusedError}
+
     def __init__(self, resolv = None, servers = None, timeout = (1, 3, 11, 45)):
         """
         Construct a resolver which will query domain name servers listed in
@@ -53,7 +71,7 @@
         for modification and re-parsed if it is noticed to have changed.
 
         @type servers: C{list} of C{(str, int)} or C{None}
-        @param servers: If not None, interpreted as a list of addresses of
+        @param servers: If not C{None}, interpreted as a list of addresses of
         domain name servers to attempt to use for this lookup.  Addresses
         should be in dotted-quad form.  If specified, overrides C{resolv}.
 
@@ -271,10 +289,23 @@
 
 
     def filterAnswers(self, message):
+        """
+        Extract results from the given message.
+
+        If the message was truncated, re-attempt the query over TCP and return
+        a Deferred which will fire with the results of that query.
+
+        If the message's result code is not L{dns.OK}, return a Failure
+        indicating the type of error which occurred.
+
+        Otherwise, return a three-tuple of lists containing the results from
+        the answers section, the authority section, and the additional section.
+        """
         if message.trunc:
             return self.queryTCP(message.queries).addCallback(self.filterAnswers)
-        else:
-            return (message.answers, message.authority, message.additional)
+        if message.rCode != dns.OK:
+            return failure.Failure(self._errormap.get(message.rCode, DNSUnknownError)(message))
+        return (message.answers, message.authority, message.additional)
 
 
     def _lookup(self, name, cls, type, timeout):
@@ -385,7 +416,27 @@
 
 
 
-def createResolver(servers = None, resolvconf = None, hosts = None):
+def createResolver(servers=None, resolvconf=None, hosts=None):
+    """
+    Create and return a Resolver.
+
+    @type servers: C{list} of C{(str, int)} or C{None}
+    @param servers: If not C{None}, interpreted as a list of addresses of
+    domain name servers to attempt to use.  Addresses should be in dotted-quad
+    form.
+
+    @type resolvconf: C{str} or C{None}
+    @param resolvconf: If not C{None}, on posix systems will be interpreted as
+    an alternate resolv.conf to use. Will do nothing on windows systems. If
+    C{None}, /etc/resolv.conf will be used.
+
+    @type hosts: C{str} or C{None}
+    @param hosts: If not C{None}, an alternate hosts file to use. If C{None}
+    on posix systems, /etc/hosts will be used. On windows, C:\windows\hosts
+    will be used.
+
+    @rtype: C{IResolver}
+    """
     from twisted.names import resolve, cache, root, hosts as hostsModule
     if platform.getType() == 'posix':
         if resolvconf is None:
@@ -406,20 +457,357 @@
     return resolve.ResolverChain(L)
 
 theResolver = None
-def _makeLookup(method):
-    def lookup(*a, **kw):
-        global theResolver
-        if theResolver is None:
-            try:
-                theResolver = createResolver()
-            except ValueError:
-                theResolver = createResolver(servers=[('127.0.0.1', 53)])
-
-        return getattr(theResolver, method)(*a, **kw)
-    return lookup
-
-for method in common.typeToMethod.values():
-    globals()[method] = _makeLookup(method)
-del method
+def getResolver():
+    """
+    Get a Resolver instance.
+
+    Create twisted.names.client.theResolver if it is C{None}, and then return
+    that value.
+
+    @rtype: C{IResolver}
+    """
+    global theResolver
+    if theResolver is None:
+        try:
+            theResolver = createResolver()
+        except ValueError:
+            theResolver = createResolver(servers=[('127.0.0.1', 53)])
+    return theResolver
+
+def getHostByName(name, timeout=None, effort=10):
+    """
+    Resolve a name to a valid ipv4 or ipv6 address.
+
+    Will errback with C{DNSQueryTimeoutError} on a timeout, C{DomainError} or
+    C{AuthoritativeDomainError} (or subclasses) on other errors.
+
+    @type name: C{str}
+    @param name: DNS name to resolve.
+
+    @type timeout: Sequence of C{int}
+    @param timeout: Number of seconds after which to reissue the query.
+    When the last timeout expires, the query is considered failed.
+
+    @type effort: C{int}
+    @param effort: How many times CNAME and NS records to follow while
+    resolving this name.
+
+    @rtype: C{Deferred}
+    """
+    return getResolver().getHostByName(name, timeout, effort)
+
+def lookupAddress(name, timeout=None):
+    """
+    Perform an A record lookup.
+
+    @type name: C{str}
+    @param name: DNS name to resolve.
+    
+    @type timeout: Sequence of C{int}
+    @param timeout: Number of seconds after which to reissue the query.
+    When the last timeout expires, the query is considered failed.
+    
+    @rtype: C{Deferred}
+    """
+    return getResolver().lookupAddress(name, timeout)
+
+def lookupIPV6Address(name, timeout=None):
+    """
+    Perform an AAAA record lookup.
+
+    @type name: C{str}
+    @param name: DNS name to resolve.
+    
+    @type timeout: Sequence of C{int}
+    @param timeout: Number of seconds after which to reissue the query.
+    When the last timeout expires, the query is considered failed.
+    
+    @rtype: C{Deferred}
+    """
+    return getResolver().lookupIPV6Address(name, timeout)
+
+def lookupAddress6(name, timeout=None):
+    """
+    Perform an A6 record lookup.
+
+    @type name: C{str}
+    @param name: DNS name to resolve.
+    
+    @type timeout: Sequence of C{int}
+    @param timeout: Number of seconds after which to reissue the query.
+    When the last timeout expires, the query is considered failed.
+    
+    @rtype: C{Deferred}
+    """
+    return getResolver().lookupAddress6(name, timeout)
+
+def lookupMailExchange(name, timeout=None):
+    """
+    Perform an MX record lookup.
+
+    @type name: C{str}
+    @param name: DNS name to resolve.
+    
+    @type timeout: Sequence of C{int}
+    @param timeout: Number of seconds after which to reissue the query.
+    When the last timeout expires, the query is considered failed.
+    
+    @rtype: C{Deferred}
+    """
+    return getResolver().lookupMailExchange(name, timeout)
+
+def lookupNameservers(name, timeout=None):
+    """
+    Perform an NS record lookup.
+
+    @type name: C{str}
+    @param name: DNS name to resolve.
+    
+    @type timeout: Sequence of C{int}
+    @param timeout: Number of seconds after which to reissue the query.
+    When the last timeout expires, the query is considered failed.
+    
+    @rtype: C{Deferred}
+    """
+    return getResolver().lookupNameservers(name, timeout)
+
+def lookupCanonicalName(name, timeout=None):
+    """
+    Perform a CNAME record lookup.
+
+    @type name: C{str}
+    @param name: DNS name to resolve.
+    
+    @type timeout: Sequence of C{int}
+    @param timeout: Number of seconds after which to reissue the query.
+    When the last timeout expires, the query is considered failed.
+    
+    @rtype: C{Deferred}
+    """
+    return getResolver().lookupCanonicalName(name, timeout)
+
+def lookupMailBox(name, timeout=None):
+    """
+    Perform an MB record lookup.
+
+    @type name: C{str}
+    @param name: DNS name to resolve.
+    
+    @type timeout: Sequence of C{int}
+    @param timeout: Number of seconds after which to reissue the query.
+    When the last timeout expires, the query is considered failed.
+    
+    @rtype: C{Deferred}
+    """
+    return getResolver().lookupMailBox(name, timeout)
+
+def lookupMailGroup(name, timeout=None):
+    """
+    Perform an MG record lookup.
+
+    @type name: C{str}
+    @param name: DNS name to resolve.
+    
+    @type timeout: Sequence of C{int}
+    @param timeout: Number of seconds after which to reissue the query.
+    When the last timeout expires, the query is considered failed.
+    
+    @rtype: C{Deferred}
+    """
+    return getResolver().lookupMailGroup(name, timeout)
+
+def lookupMailRename(name, timeout=None):
+    """
+    Perform an MR record lookup.
+
+    @type name: C{str}
+    @param name: DNS name to resolve.
+    
+    @type timeout: Sequence of C{int}
+    @param timeout: Number of seconds after which to reissue the query.
+    When the last timeout expires, the query is considered failed.
+    
+    @rtype: C{Deferred}
+    """
+    return getResolver().lookupMailRename(name, timeout)
+
+def lookupPointer(name, timeout=None):
+    """
+    Perform a PTR record lookup.
+
+    @type name: C{str}
+    @param name: DNS name to resolve.
+    
+    @type timeout: Sequence of C{int}
+    @param timeout: Number of seconds after which to reissue the query.
+    When the last timeout expires, the query is considered failed.
+    
+    @rtype: C{Deferred}
+    """
+    return getResolver().lookupPointer(name, timeout)
+
+def lookupAuthority(name, timeout=None):
+    """
+    Perform an SOA record lookup.
+
+    @type name: C{str}
+    @param name: DNS name to resolve.
+    
+    @type timeout: Sequence of C{int}
+    @param timeout: Number of seconds after which to reissue the query.
+    When the last timeout expires, the query is considered failed.
+    
+    @rtype: C{Deferred}
+    """
+    return getResolver().lookupAuthority(name, timeout)
+
+def lookupNull(name, timeout=None):
+    """
+    Perform a NULL record lookup.
+
+    @type name: C{str}
+    @param name: DNS name to resolve.
+    
+    @type timeout: Sequence of C{int}
+    @param timeout: Number of seconds after which to reissue the query.
+    When the last timeout expires, the query is considered failed.
+    
+    @rtype: C{Deferred}
+    """
+    return getResolver().lookupNull(name, timeout)
+
+def lookupWellKnownServices(name, timeout=None):
+    """
+    Perform a WKS record lookup.
+
+    @type name: C{str}
+    @param name: DNS name to resolve.
+    
+    @type timeout: Sequence of C{int}
+    @param timeout: Number of seconds after which to reissue the query.
+    When the last timeout expires, the query is considered failed.
+    
+    @rtype: C{Deferred}
+    """
+    return getResolver().lookupWellKnownServices(name, timeout)
+
+def lookupService(name, timeout=None):
+    """
+    Perform an SRV record lookup.
+
+    @type name: C{str}
+    @param name: DNS name to resolve.
+    
+    @type timeout: Sequence of C{int}
+    @param timeout: Number of seconds after which to reissue the query.
+    When the last timeout expires, the query is considered failed.
+    
+    @rtype: C{Deferred}
+    """
+    return getResolver().lookupService(name, timeout)
+
+def lookupHostInfo(name, timeout=None):
+    """
+    Perform a HINFO record lookup.
+
+    @type name: C{str}
+    @param name: DNS name to resolve.
+    
+    @type timeout: Sequence of C{int}
+    @param timeout: Number of seconds after which to reissue the query.
+    When the last timeout expires, the query is considered failed.
+    
+    @rtype: C{Deferred}
+    """
+    return getResolver().lookupHostInfo(name, timeout)
+
+def lookupMailboxInfo(name, timeout=None):
+    """
+    Perform an MINFO record lookup.
+
+    @type name: C{str}
+    @param name: DNS name to resolve.
+    
+    @type timeout: Sequence of C{int}
+    @param timeout: Number of seconds after which to reissue the query.
+    When the last timeout expires, the query is considered failed.
+    
+    @rtype: C{Deferred}
+    """
+    return getResolver().lookupMailboxInfo(name, timeout)
+
+def lookupText(name, timeout=None):
+    """
+    Perform a TXT record lookup.
+
+    @type name: C{str}
+    @param name: DNS name to resolve.
+    
+    @type timeout: Sequence of C{int}
+    @param timeout: Number of seconds after which to reissue the query.
+    When the last timeout expires, the query is considered failed.
+    
+    @rtype: C{Deferred}
+    """
+    return getResolver().lookupText(name, timeout)
+
+def lookupResponsibility(name, timeout=None):
+    """
+    Perform an RP record lookup.
+
+    @type name: C{str}
+    @param name: DNS name to resolve.
+    
+    @type timeout: Sequence of C{int}
+    @param timeout: Number of seconds after which to reissue the query.
+    When the last timeout expires, the query is considered failed.
+    
+    @rtype: C{Deferred}
+    """
+    return getResolver().lookupResponsibility(name, timeout)
+
+def lookupAFSDatabase(name, timeout=None):
+    """
+    Perform an AFSDB record lookup.
+
+    @type name: C{str}
+    @param name: DNS name to resolve.
+    
+    @type timeout: Sequence of C{int}
+    @param timeout: Number of seconds after which to reissue the query.
+    When the last timeout expires, the query is considered failed.
+    
+    @rtype: C{Deferred}
+    """
+    return getResolver().lookupAFSDatabase(name, timeout)
+
+def lookupZone(name, timeout=None):
+    """
+    Perform an AXFR record lookup.
+
+    @type name: C{str}
+    @param name: DNS name to resolve.
+    
+    @type timeout: C{int}
+    @param timeout: When this timeout expires, the query is considered failed.
+    
+    @rtype: C{Deferred}
+    """
+    # XXX: timeout here is not a list of ints, it is a single int.
+    return getResolver().lookupZone(name, timeout)
+
+def lookupAllRecords(name, timeout=None):
+    """
+    ALL_RECORD lookup.
+
+    @type name: C{str}
+    @param name: DNS name to resolve.
+    
+    @type timeout: Sequence of C{int}
+    @param timeout: Number of seconds after which to reissue the query.
+    When the last timeout expires, the query is considered failed.
+    
+    @rtype: C{Deferred}
+    """
+    return getResolver().lookupAllRecords(name, timeout)
 
-getHostByName = _makeLookup('getHostByName')
diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/TwistedNames-0.3.0/twisted/names/common.py new/TwistedNames-0.4.0/twisted/names/common.py
--- old/TwistedNames-0.3.0/twisted/names/common.py      2006-03-17 04:29:41.000000000 +0100
+++ new/TwistedNames-0.4.0/twisted/names/common.py      2006-12-29 06:01:40.000000000 +0100
@@ -29,69 +29,135 @@
         return defer.fail(NotImplementedError("ResolverBase._lookup"))
 
     def lookupAddress(self, name, timeout = None):
+        """
+        @see: twisted.names.client.lookupAddress
+        """
         return self._lookup(name, dns.IN, dns.A, timeout)
 
     def lookupIPV6Address(self, name, timeout = None):
+        """
+        @see: twisted.names.client.lookupIPV6Address
+        """
         return self._lookup(name, dns.IN, dns.AAAA, timeout)
 
     def lookupAddress6(self, name, timeout = None):
+        """
+        @see: twisted.names.client.lookupAddress6
+        """
         return self._lookup(name, dns.IN, dns.A6, timeout)
 
     def lookupMailExchange(self, name, timeout = None):
+        """
+        @see: twisted.names.client.lookupMailExchange
+        """
         return self._lookup(name, dns.IN, dns.MX, timeout)
 
     def lookupNameservers(self, name, timeout = None):
+        """
+        @see: twisted.names.client.lookupNameservers
+        """
         return self._lookup(name, dns.IN, dns.NS, timeout)
 
     def lookupCanonicalName(self, name, timeout = None):
+        """
+        @see: twisted.names.client.lookupCanonicalName
+        """
         return self._lookup(name, dns.IN, dns.CNAME, timeout)
 
     def lookupMailBox(self, name, timeout = None):
+        """
+        @see: twisted.names.client.lookupMailBox
+        """
         return self._lookup(name, dns.IN, dns.MB, timeout)
 
     def lookupMailGroup(self, name, timeout = None):
+        """
+        @see: twisted.names.client.lookupMailGroup
+        """
         return self._lookup(name, dns.IN, dns.MG, timeout)
 
     def lookupMailRename(self, name, timeout = None):
+        """
+        @see: twisted.names.client.lookupMailRename
+        """
         return self._lookup(name, dns.IN, dns.MR, timeout)
 
     def lookupPointer(self, name, timeout = None):
+        """
+        @see: twisted.names.client.lookupPointer
+        """
         return self._lookup(name, dns.IN, dns.PTR, timeout)
 
     def lookupAuthority(self, name, timeout = None):
+        """
+        @see: twisted.names.client.lookupAuthority
+        """
         return self._lookup(name, dns.IN, dns.SOA, timeout)
 
     def lookupNull(self, name, timeout = None):
+        """
+        @see: twisted.names.client.lookupNull
+        """
         return self._lookup(name, dns.IN, dns.NULL, timeout)
 
     def lookupWellKnownServices(self, name, timeout = None):
+        """
+        @see: twisted.names.client.lookupWellKnownServices
+        """
         return self._lookup(name, dns.IN, dns.WKS, timeout)
 
     def lookupService(self, name, timeout = None):
+        """
+        @see: twisted.names.client.lookupService
+        """
         return self._lookup(name, dns.IN, dns.SRV, timeout)
 
     def lookupHostInfo(self, name, timeout = None):
+        """
+        @see: twisted.names.client.lookupHostInfo
+        """
         return self._lookup(name, dns.IN, dns.HINFO, timeout)
 
     def lookupMailboxInfo(self, name, timeout = None):
+        """
+        @see: twisted.names.client.lookupMailboxInfo
+        """
         return self._lookup(name, dns.IN, dns.MINFO, timeout)
 
     def lookupText(self, name, timeout = None):
+        """
+        @see: twisted.names.client.lookupText
+        """
         return self._lookup(name, dns.IN, dns.TXT, timeout)
 
     def lookupResponsibility(self, name, timeout = None):
+        """
+        @see: twisted.names.client.lookupResponsibility
+        """
         return self._lookup(name, dns.IN, dns.RP, timeout)
 
     def lookupAFSDatabase(self, name, timeout = None):
+        """
+        @see: twisted.names.client.lookupAFSDatabase
+        """
         return self._lookup(name, dns.IN, dns.AFSDB, timeout)
 
     def lookupZone(self, name, timeout = None):
+        """
+        @see: twisted.names.client.lookupZone
+        """
         return self._lookup(name, dns.IN, dns.AXFR, timeout)
 
     def lookupAllRecords(self, name, timeout = None):
+        """
+        @see: twisted.names.client.lookupAllRecords
+        """
         return self._lookup(name, dns.IN, dns.ALL_RECORDS, timeout)
 
     def getHostByName(self, name, timeout = None, effort = 10):
+        """
+        @see: twisted.names.client.getHostByName
+        """
         # XXX - respect timeout
         return self.lookupAllRecords(name, timeout
             ).addCallback(self._cbRecords, name, effort
diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/TwistedNames-0.3.0/twisted/names/dns.py new/TwistedNames-0.4.0/twisted/names/dns.py
--- old/TwistedNames-0.3.0/twisted/names/dns.py 2006-03-17 04:29:41.000000000 +0100
+++ new/TwistedNames-0.4.0/twisted/names/dns.py 2006-12-06 04:15:37.000000000 +0100
@@ -43,7 +43,6 @@
                 return struct.unpack('H', r(2))[0]
             break
     else:
-        import warnings
         warnings.warn(
             "PyCrypto not available - proceeding with non-cryptographically "
             "secure random source",
@@ -56,55 +55,80 @@
 else:
     def randomSource(r = randpool.RandomPool().get_bytes):
         return struct.unpack('H', r(2))[0]
-from zope.interface import implements
+from zope.interface import implements, Interface
 
 
 # Twisted imports
 from twisted.internet import protocol, defer
 from twisted.python import log, failure
 from twisted.python import util as tputil
-from twisted.python import components
 
 PORT = 53
 
+(A, NS, MD, MF, CNAME, SOA, MB, MG, MR, NULL, WKS, PTR, HINFO, MINFO, MX, TXT,
+ RP, AFSDB) = range(1, 19)
+AAAA = 28
+SRV = 33
+A6 = 38
+DNAME = 39
+
 QUERY_TYPES = {
-    1:  'A',     2:  'NS',    3:  'MD',   4:   'MF',
-    5:  'CNAME', 6:  'SOA',   7:  'MB',   8:   'MG',
-    9:  'MR',    10: 'NULL',  11: 'WKS',  12:  'PTR',
-    13: 'HINFO', 14: 'MINFO', 15: 'MX',   16:  'TXT',
+    A: 'A',
+    NS: 'NS',
+    MD: 'MD',
+    MF: 'MF',
+    CNAME: 'CNAME',
+    SOA: 'SOA',
+    MB: 'MB',
+    MG: 'MG',
+    MR: 'MR',
+    NULL: 'NULL',
+    WKS: 'WKS',
+    PTR: 'PTR',
+    HINFO: 'HINFO',
+    MINFO: 'MINFO',
+    MX: 'MX',
+    TXT: 'TXT',
+    RP: 'RP',
+    AFSDB: 'AFSDB',
 
-    17: 'RP',    18: 'AFSDB',
     # 19 through 27?  Eh, I'll get to 'em.
 
-    28: 'AAAA',
-
-    33: 'SRV',
+    AAAA: 'AAAA',
+    SRV: 'SRV',
 
-    38: 'A6', 39: 'DNAME'
+    A6: 'A6',
+    DNAME: 'DNAME'
 }
 
+IXFR, AXFR, MAILB, MAILA, ALL_RECORDS = range(251, 256)
+
 # "Extended" queries (Hey, half of these are deprecated, good job)
 EXT_QUERIES = {
-    251: 'IXFR',  252: 'AXFR',       253: 'MAILB',
-    254: 'MAILA', 255: 'ALL_RECORDS'
+    IXFR: 'IXFR',
+    AXFR: 'AXFR',
+    MAILB: 'MAILB',
+    MAILA: 'MAILA',
+    ALL_RECORDS: 'ALL_RECORDS'
 }
+
 REV_TYPES = dict([
     (v, k) for (k, v) in QUERY_TYPES.items() + EXT_QUERIES.items()
 ])
-for (k, v) in REV_TYPES.items():
-    exec "%s = %d" % (k, v)
-del k, v
 
+IN, CS, CH, HS = range(1, 5)
+ANY = 255
 
 QUERY_CLASSES = {
-    1: 'IN',  2: 'CS',  3: 'CH',  4: 'HS',  255: 'ANY'
+    IN: 'IN',
+    CS: 'CS',
+    CH: 'CH',
+    HS: 'HS',
+    ANY: 'ANY'
 }
 REV_CLASSES = dict([
     (v, k) for (k, v) in QUERY_CLASSES.items()
 ])
-for (k, v) in REV_CLASSES.items():
-    exec "%s = %d" % (k, v)
-del k, v
 
 
 # Opcodes
@@ -113,22 +137,18 @@
 # Response Codes
 OK, EFORMAT, ESERVER, ENAME, ENOTIMP, EREFUSED = range(6)
 
-class IRecord(components.Interface):
+class IRecord(Interface):
     """An single entry in a zone of authority.
 
     @cvar TYPE: An indicator of what kind of record this is.
     """
 
-class DomainError(ValueError):
-    pass
 
-class AuthoritativeDomainError(ValueError):
-    pass
+# Backwards compatibility aliases - these should be deprecated or something I
+# suppose. -exarkun
+from twisted.names.error import DomainError, AuthoritativeDomainError
+from twisted.names.error import DNSQueryTimeoutError
 
-class DNSQueryTimeoutError(defer.TimeoutError):
-    def __init__(self, id):
-        self.id = id
-        defer.TimeoutError.__init__(self)
 
 def str2time(s):
     suffixes = (
@@ -154,12 +174,12 @@
     return buff
 
 
-class IEncodable(components.Interface):
+class IEncodable(Interface):
     """
     Interface for something which can be encoded to and decoded
     from a file object.
     """
-    def encode(self, strio, compDict = None):
+    def encode(strio, compDict = None):
         """
         Write a representation of this object to the given
         file object.
@@ -173,7 +193,7 @@
         compression.
         """
 
-    def decode(self, strio, length = None):
+    def decode(strio, length = None):
         """
         Reconstruct an object from data read from the given
         file object.
@@ -1085,7 +1105,19 @@
 
     def datagramReceived(self, data, addr):
         m = Message()
-        m.fromStr(data)
+        try:
+            m.fromStr(data)
+        except EOFError:
+            log.msg("Truncated packet (%d bytes) from %s" % (len(data), addr))
+            return
+        except:
+            # Nothing should trigger this, but since we're potentially
+            # invoking a lot of different decoding methods, we might as well
+            # be extra cautious.  Anything that triggers this is itself
+            # buggy.
+            log.err(failure.Failure(), "Unexpected decoding error")
+            return
+
         if m.id in self.liveMessages:
             d, canceller = self.liveMessages[m.id]
             del self.liveMessages[m.id]
diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/TwistedNames-0.3.0/twisted/names/error.py new/TwistedNames-0.4.0/twisted/names/error.py
--- old/TwistedNames-0.3.0/twisted/names/error.py       1970-01-01 01:00:00.000000000 +0100
+++ new/TwistedNames-0.4.0/twisted/names/error.py       2006-12-06 04:15:37.000000000 +0100
@@ -0,0 +1,88 @@
+# -*- test-case-name: twisted.names.test -*-
+# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
+# See LICENSE for details.
+
+"""
+Exception class definitions for Twisted Names.
+"""
+
+from twisted.internet.defer import TimeoutError
+
+
+class DomainError(ValueError):
+    """
+    Indicates a lookup failed because there were no records matching the given
+    C{name, class, type} triple.
+    """
+
+
+
+class AuthoritativeDomainError(ValueError):
+    """
+    Indicates a lookup failed for a name for which this server is authoritative
+    because there were no records matching the given C{name, class, type}
+    triple.
+    """
+
+
+
+class DNSQueryTimeoutError(TimeoutError):
+    """
+    Indicates a lookup failed due to a timeout.
+
+    @ivar id: The id of the message which timed out.
+    """
+    def __init__(self, id):
+        TimeoutError.__init__(self)
+        self.id = id
+
+
+
+class DNSFormatError(DomainError):
+    """
+    Indicates a query failed with a result of L{twisted.names.dns.EFORMAT}.
+    """
+
+
+
+class DNSServerError(DomainError):
+    """
+    Indicates a query failed with a result of L{twisted.names.dns.ESERVER}.
+    """
+
+
+
+class DNSNameError(DomainError):
+    """
+    Indicates a query failed with a result of L{twisted.names.dns.ENAME}.
+    """
+
+
+
+class DNSNotImplementedError(DomainError):
+    """
+    Indicates a query failed with a result of L{twisted.names.dns.ENOTIMP}.
+    """
+
+
+
+class DNSQueryRefusedError(DomainError):
+    """
+    Indicates a query failed with a result of L{twisted.names.dns.EREFUSED}.
+    """
+
+
+
+class DNSUnknownError(DomainError):
+    """
+    Indicates a query failed with an unknown result.
+    """
+
+
+
+__all__ = [
+    'DomainError', 'AuthoritativeDomainError', 'DNSQueryTimeoutError',
+
+    'DNSFormatError', 'DNSServerError', 'DNSNameError',
+    'DNSNotImplementedError', 'DNSQueryRefusedError',
+    'DNSUnknownError']
diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/TwistedNames-0.3.0/twisted/names/resolve.py new/TwistedNames-0.4.0/twisted/names/resolve.py
--- old/TwistedNames-0.3.0/twisted/names/resolve.py     2006-03-17 04:29:41.000000000 +0100
+++ new/TwistedNames-0.4.0/twisted/names/resolve.py     2006-07-01 18:08:17.000000000 +0200
@@ -15,7 +15,6 @@
 
 from twisted.internet import defer, interfaces
 from twisted.names import dns
-from twisted.python import components
 from zope.interface import implements
 import common
 
diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/TwistedNames-0.3.0/twisted/names/test/test_client.py new/TwistedNames-0.4.0/twisted/names/test/test_client.py
--- old/TwistedNames-0.3.0/twisted/names/test/test_client.py    1970-01-01 01:00:00.000000000 +0100
+++ new/TwistedNames-0.4.0/twisted/names/test/test_client.py    2006-12-29 06:01:40.000000000 +0100
@@ -0,0 +1,241 @@
+# -*- test-case-name: twisted.names.test.test_client -*-
+# Copyright (c) 2001-2006 Twisted Matrix Laboratories.
+# See LICENSE for details.
+
+"""
+Test cases for twisted.names.client
+"""
+
+from twisted.names import client, dns
+from twisted.trial import unittest
+from twisted.names.common import ResolverBase
+from twisted.internet import defer
+
+class FakeResolver(ResolverBase):
+    
+    def _lookup(self, name, cls, qtype, timeout):
+        """
+        The getHostByNameTest does a different type of query that requires it
+        return an A record from an ALL_RECORDS lookup, so we accomodate that
+        here.
+        """
+        if name == 'getHostByNameTest':
+            rr = dns.RRHeader(name=name, type=dns.A, cls=cls, ttl=60,
+                    payload=dns.Record_A(address='127.0.0.1', ttl=60))
+        else:
+            rr = dns.RRHeader(name=name, type=qtype, cls=cls, ttl=60)
+            
+        results = [rr]
+        authority = []
+        addtional = []
+        return defer.succeed((results, authority, addtional))
+
+class ClientTestCase(unittest.TestCase):
+
+    def setUp(self):
+        """
+        Replace the resolver with a FakeResolver
+        """
+        client.theResolver = FakeResolver()
+        self.hostname = 'example.com'
+        self.ghbntest = 'getHostByNameTest'
+
+    def tearDown(self):
+        """
+        By setting the resolver to None, it will be recreated next time a name
+        lookup is done.
+        """
+        client.theResolver = None
+
+    def checkResult(self, (results, authority, additional), qtype):
+        """
+        Verify that the result is the same query type as what is expected.
+        """
+        result = results[0]
+        self.assertEquals(str(result.name), self.hostname)
+        self.assertEquals(result.type, qtype)
+
+    def checkGetHostByName(self, result):
+        """
+        Test that the getHostByName query returns the 127.0.0.1 address.
+        """
+        self.assertEquals(result, '127.0.0.1')
+
+    def test_getHostByName(self):
+        """
+        do a getHostByName of a value that should return 127.0.0.1.
+        """
+        d = client.getHostByName(self.ghbntest)
+        d.addCallback(self.checkGetHostByName)
+        return d
+
+    def test_lookupAddress(self):
+        """
+        Do a lookup and test that the resolver will issue the correct type of
+        query type. We do this by checking that FakeResolver returns a result
+        record with the same query type as what we issued.
+        """
+        d = client.lookupAddress(self.hostname)
+        d.addCallback(self.checkResult, dns.A)
+        return d
+
+    def test_lookupIPV6Address(self):
+        """
+        See L{test_lookupAddress}
+        """
+        d = client.lookupIPV6Address(self.hostname)
+        d.addCallback(self.checkResult, dns.AAAA)
+        return d
+
+    def test_lookupAddress6(self):
+        """
+        See L{test_lookupAddress}
+        """
+        d = client.lookupAddress6(self.hostname)
+        d.addCallback(self.checkResult, dns.A6)
+        return d
+
+    def test_lookupNameservers(self):
+        """
+        See L{test_lookupAddress}
+        """
+        d = client.lookupNameservers(self.hostname)
+        d.addCallback(self.checkResult, dns.NS)
+        return d
+
+    def test_lookupCanonicalName(self):
+        """
+        See L{test_lookupAddress}
+        """
+        d = client.lookupCanonicalName(self.hostname)
+        d.addCallback(self.checkResult, dns.CNAME)
+        return d
+
+    def test_lookupAuthority(self):
+        """
+        See L{test_lookupAddress}
+        """
+        d = client.lookupAuthority(self.hostname)
+        d.addCallback(self.checkResult, dns.SOA)
+        return d
+
+    def test_lookupMailBox(self):
+        """
+        See L{test_lookupAddress}
+        """
+        d = client.lookupMailBox(self.hostname)
+        d.addCallback(self.checkResult, dns.MB)
+        return d
+
+    def test_lookupMailGroup(self):
+        """
+        See L{test_lookupAddress}
+        """
+        d = client.lookupMailGroup(self.hostname)
+        d.addCallback(self.checkResult, dns.MG)
+        return d
+
+    def test_lookupMailRename(self):
+        """
+        See L{test_lookupAddress}
+        """
+        d = client.lookupMailRename(self.hostname)
+        d.addCallback(self.checkResult, dns.MR)
+        return d
+
+    def test_lookupNull(self):
+        """
+        See L{test_lookupAddress}
+        """
+        d = client.lookupNull(self.hostname)
+        d.addCallback(self.checkResult, dns.NULL)
+        return d
+
+    def test_lookupWellKnownServices(self):
+        """
+        See L{test_lookupAddress}
+        """
+        d = client.lookupWellKnownServices(self.hostname)
+        d.addCallback(self.checkResult, dns.WKS)
+        return d
+
+    def test_lookupPointer(self):
+        """
+        See L{test_lookupAddress}
+        """
+        d = client.lookupPointer(self.hostname)
+        d.addCallback(self.checkResult, dns.PTR)
+        return d
+
+    def test_lookupHostInfo(self):
+        """
+        See L{test_lookupAddress}
+        """
+        d = client.lookupHostInfo(self.hostname)
+        d.addCallback(self.checkResult, dns.HINFO)
+        return d
+
+    def test_lookupMailboxInfo(self):
+        """
+        See L{test_lookupAddress}
+        """
+        d = client.lookupMailboxInfo(self.hostname)
+        d.addCallback(self.checkResult, dns.MINFO)
+        return d
+
+    def test_lookupMailExchange(self):
+        """
+        See L{test_lookupAddress}
+        """
+        d = client.lookupMailExchange(self.hostname)
+        d.addCallback(self.checkResult, dns.MX)
+        return d
+
+    def test_lookupText(self):
+        """
+        See L{test_lookupAddress}
+        """
+        d = client.lookupText(self.hostname)
+        d.addCallback(self.checkResult, dns.TXT)
+        return d
+
+    def test_lookupResponsibility(self):
+        """
+        See L{test_lookupAddress}
+        """
+        d = client.lookupResponsibility(self.hostname)
+        d.addCallback(self.checkResult, dns.RP)
+        return d
+
+    def test_lookupAFSDatabase(self):
+        """
+        See L{test_lookupAddress}
+        """
+        d = client.lookupAFSDatabase(self.hostname)
+        d.addCallback(self.checkResult, dns.AFSDB)
+        return d
+
+    def test_lookupService(self):
+        """
+        See L{test_lookupAddress}
+        """
+        d = client.lookupService(self.hostname)
+        d.addCallback(self.checkResult, dns.SRV)
+        return d
+
+    def test_lookupZone(self):
+        """
+        See L{test_lookupAddress}
+        """
+        d = client.lookupZone(self.hostname)
+        d.addCallback(self.checkResult, dns.AXFR)
+        return d
+
+    def test_lookupAllRecords(self):
+        """
+        See L{test_lookupAddress}
+        """
+        d = client.lookupAllRecords(self.hostname)
+        d.addCallback(self.checkResult, dns.ALL_RECORDS)
+        return d
+
diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/TwistedNames-0.3.0/twisted/names/test/test_dns.py new/TwistedNames-0.4.0/twisted/names/test/test_dns.py
--- old/TwistedNames-0.3.0/twisted/names/test/test_dns.py       2005-11-10 04:18:15.000000000 +0100
+++ new/TwistedNames-0.4.0/twisted/names/test/test_dns.py       2006-06-07 01:56:12.000000000 +0200
@@ -11,6 +11,7 @@
 except ImportError:
     from StringIO import StringIO
 
+from twisted.internet import address
 from twisted.trial import unittest
 from twisted.names import dns
 
@@ -95,7 +96,43 @@
             self.assertEquals(hk1, hk2, "%s != %s (for %s)" % (hk1,hk2,k))
 
 
-class Encoding(unittest.TestCase):
+
+class MessageTestCase(unittest.TestCase):
+    def testEmptyMessage(self):
+        """
+        Test that a message which has been truncated causes an EOFError to
+        be raised when it is parsed.
+        """
+        msg = dns.Message()
+        self.assertRaises(EOFError, msg.fromStr, '')
+
+
+    def testEmptyQuery(self):
+        """
+        Test that bytes representing an empty query message can be decoded
+        as such.
+        """
+        msg = dns.Message()
+        msg.fromStr(
+            '\x01\x00' # Message ID
+            '\x00' # answer bit, opCode nibble, auth bit, trunc bit, recursive bit
+            '\x00' # recursion bit, empty bit, empty bit, empty bit, response code nibble
+            '\x00\x00' # number of queries
+            '\x00\x00' # number of answers
+            '\x00\x00' # number of authorities
+            '\x00\x00' # number of additionals
+            )
+        self.assertEquals(msg.id, 256)
+        self.failIf(msg.answer, "Message was not supposed to be an answer.")
+        self.assertEquals(msg.opCode, dns.OP_QUERY)
+        self.failIf(msg.auth, "Message was not supposed to be authoritative.")
+        self.failIf(msg.trunc, "Message was not supposed to be truncated.")
+        self.assertEquals(msg.queries, [])
+        self.assertEquals(msg.answers, [])
+        self.assertEquals(msg.authority, [])
+        self.assertEquals(msg.additional, [])
+
+
     def testNULL(self):
         bytes = ''.join([chr(i) for i in range(256)])
         rec = dns.Record_NULL(bytes)
@@ -111,3 +148,32 @@
         self.failUnless(isinstance(msg2.answers[0].payload, dns.Record_NULL))
         self.assertEquals(msg2.answers[0].payload.payload, bytes)
 
+
+
+class TestController(object):
+    """
+    Pretend to be a DNS query processor for a DNSDatagramProtocol.
+    """
+    def __init__(self):
+        self.messages = []
+
+
+    def messageReceived(self, msg, proto, addr):
+        self.messages.append((msg, proto, addr))
+
+
+
+class DatagramProtocolTestCase(unittest.TestCase):
+    """
+    Test various aspects of DNSDatagramProtocol.
+    """
+
+    def testTruncatedPacket(self):
+        """
+        Test that when a short datagram is received, datagramReceived does
+        not raise an exception while processing it.
+        """
+        controller = TestController()
+        proto = dns.DNSDatagramProtocol(controller)
+        proto.datagramReceived('', address.IPv4Address('UDP', '127.0.0.1', 12345))
+        self.assertEquals(controller.messages, [])
diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/TwistedNames-0.3.0/twisted/names/test/test_names.py new/TwistedNames-0.4.0/twisted/names/test/test_names.py
--- old/TwistedNames-0.3.0/twisted/names/test/test_names.py     2006-04-10 05:21:33.000000000 +0200
+++ new/TwistedNames-0.4.0/twisted/names/test/test_names.py     2006-12-06 04:15:37.000000000 +0100
@@ -12,8 +12,16 @@
 from twisted.trial import unittest
 
 from twisted.internet import reactor, defer, error
+from twisted.internet.defer import succeed
 from twisted.names import client, server, common, authority, hosts, dns
 from twisted.python import failure
+from twisted.names.error import DNSFormatError, DNSServerError, DNSNameError
+from twisted.names.error import DNSNotImplementedError, DNSQueryRefusedError
+from twisted.names.error import DNSUnknownError
+from twisted.names.dns import EFORMAT, ESERVER, ENAME, ENOTIMP, EREFUSED
+from twisted.names.dns import Message
+from twisted.names.client import Resolver
+
 
 def justPayload(results):
     return [r.payload for r in results[0]]
@@ -152,8 +160,10 @@
         self.resolver = client.Resolver(servers=[('127.0.0.1', port)])
 
     def tearDown(self):
-        self.listenerTCP.loseConnection()
-        d = defer.maybeDeferred(self.listenerUDP.stopListening)
+        """Asynchronously disconnect listenerTCP, listenerUDP and resolver"""
+        d1 = self.listenerTCP.loseConnection()
+        d2 = defer.maybeDeferred(self.listenerUDP.stopListening)
+        d = defer.gatherResults([d1, d2])
         def disconnectTransport(ignored):
             if getattr(self.resolver.protocol, 'transport', None) is not None:
                 return self.resolver.protocol.transport.stopListening()
@@ -557,3 +567,87 @@
         r = client.Resolver(resolv=resolvConf)
         self.assertEquals(r.dynServers, [('127.0.0.1', 53)])
         r._parseCall.cancel()
+
+
+
+class FilterAnswersTests(unittest.TestCase):
+    """
+    Test L{twisted.names.client.Resolver.filterAnswers}'s handling of various
+    error conditions it might encounter.
+    """
+    def setUp(self):
+        # Create a resolver pointed at an invalid server - we won't be hitting
+        # the network in any of these tests.
+        self.resolver = Resolver(servers=[('0.0.0.0', 0)])
+
+
+    def test_truncatedMessage(self):
+        """
+        Test that a truncated message results in an equivalent request made via
+        TCP.
+        """
+        m = Message(trunc=True)
+        m.addQuery('example.com')
+
+        def queryTCP(queries):
+            self.assertEqual(queries, m.queries)
+            response = Message()
+            response.answers = ['answer']
+            response.authority = ['authority']
+            response.additional = ['additional']
+            return succeed(response)
+        self.resolver.queryTCP = queryTCP
+        d = self.resolver.filterAnswers(m)
+        d.addCallback(
+            self.assertEqual, (['answer'], ['authority'], ['additional']))
+        return d
+
+
+    def _rcodeTest(self, rcode, exc):
+        m = Message(rCode=rcode)
+        err = self.resolver.filterAnswers(m)
+        err.trap(exc)
+
+
+    def test_formatError(self):
+        """
+        Test that a message with a result code of C{EFORMAT} results in a
+        failure wrapped around L{DNSFormatError}.
+        """
+        return self._rcodeTest(EFORMAT, DNSFormatError)
+
+
+    def test_serverError(self):
+        """
+        Like L{test_formatError} but for C{ESERVER}/L{DNSServerError}.
+        """
+        return self._rcodeTest(ESERVER, DNSServerError)
+
+
+    def test_nameError(self):
+        """
+        Like L{test_formatError} but for C{ENAME}/L{DNSNameError}.
+        """
+        return self._rcodeTest(ENAME, DNSNameError)
+
+
+    def test_notImplementedError(self):
+        """
+        Like L{test_formatError} but for C{ENOTIMP}/L{DNSNotImplementedError}.
+        """
+        return self._rcodeTest(ENOTIMP, DNSNotImplementedError)
+
+
+    def test_refusedError(self):
+        """
+        Like L{test_formatError} but for C{EREFUSED}/L{DNSQueryRefusedError}.
+        """
+        return self._rcodeTest(EREFUSED, DNSQueryRefusedError)
+
+
+    def test_refusedError(self):
+        """
+        Like L{test_formatError} but for an unrecognized error code and
+        L{DNSUnknownError}.
+        """
+        return self._rcodeTest(EREFUSED + 1, DNSUnknownError)
diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/TwistedNames-0.3.0/twisted/names/_version.py new/TwistedNames-0.4.0/twisted/names/_version.py
--- old/TwistedNames-0.3.0/twisted/names/_version.py    2006-05-22 00:28:51.000000000 +0200
+++ new/TwistedNames-0.4.0/twisted/names/_version.py    2007-01-06 22:42:54.000000000 +0100
@@ -1,3 +1,3 @@
 # This is an auto-generated file. Use admin/change-versions to update.
 from twisted.python import versions
-version = versions.Version(__name__[:__name__.rfind('.')], 0, 3, 0)
+version = versions.Version(__name__[:__name__.rfind('.')], 0, 4, 0)


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++



Remember to have fun...

---------------------------------------------------------------------
To unsubscribe, e-mail: opensuse-commit+unsubscribe@xxxxxxxxxxxx
For additional commands, e-mail: opensuse-commit+help@xxxxxxxxxxxx

< Previous Next >
This Thread
  • No further messages