Here is a debdiff for Etch.  In addition to fixing this regression, I also 
switched DNS/Base.py to use the upstream fix for the DNS cache poisoning 
problem.  Their fix is more robust.  If you'd rather just deal with this 
exact problem, drop the changes in DNS/Base.py.  The fix for this problem is 
the one liner in DNS/Lib.py.

Scott K

diff -u python-dns-2.3.0/DNS/Base.py python-dns-2.3.0/DNS/Base.py
--- python-dns-2.3.0/DNS/Base.py
+++ python-dns-2.3.0/DNS/Base.py
@@ -140,16 +140,15 @@
 #                Lib.dumpM(u)
 
     def getSource(self):
-        # Get random source port to avoid DNS cache poisoning attack.
-        try:
-            source = random.randint(1024,65535)
-            self.s.bind(('', source))
-        except socket.error, msg: 
-            # Error 98, 'Address already in use'
-            if msg[0] == 98:
-                self.getSource()
-            else:
-                raise
+        "Pick random source port to avoid DNS cache poisoning attack."
+        while True:
+            try:
+                source_port = random.randint(1024,65535)
+                self.s.bind(('', source_port))
+                break
+            except socket.error, msg: 
+                # Error 98, 'Address already in use'
+                if msg[0] != 98: raise
 
     def conn(self):
         # Source is source port we'll take a reply from.
@@ -207,25 +206,25 @@
             try:
                 try:
                     # TODO. Handle timeouts &c correctly (RFC)
-                    #self.s.connect((self.ns, self.port))
-                    self.conn()
-                    self.s.setblocking(0)
                     self.time_start=time.time()
+                    self.conn()
                     if not self.async:
                         self.s.send(self.request)
                         r=self.processUDPReply()
-                        # Since we bind to the source port, we don't need to check that
-                        # here, but do make sure it's actually a DNS request that the packet
-                        # is in reply to.
-                        while r.header['id'] != self.tid or self.from_address[1] != 53:
-                          r=self.processUDPReply()
+                        # Since we bind to the source port and connect to the
+                        # destination port, we don't need to check that here,
+                        # but do make sure it's actually a DNS request that the
+                        # packet is in reply to.
+                        while r.header['id'] != self.tid        \
+                                or self.from_address[1] != self.port:
+                            r=self.processUDPReply()
                         self.response = r
                         # FIXME: check waiting async queries
-                #except socket.error:
-                except None:
-                    continue
-            finally:
-                self.s.close()
+                finally:
+                    if not self.async:
+                        self.s.close()
+            except socket.error:
+                continue
             break
         if not self.response:
             if not self.async:
@@ -241,19 +240,21 @@
                     self.socketInit(socket.AF_INET, socket.SOCK_STREAM)
                     self.time_start=time.time()
                     self.conn()
+                    buf = Lib.pack16bit(len(self.request))+self.request
+                    # Keep server from making sendall hang
                     self.s.setblocking(0)
-                    self.s.sendall(Lib.pack16bit(len(self.request))+self.request)
+                    # FIXME: throws WOULDBLOCK if request too large to fit in
+                    # system buffer
+                    self.s.sendall(buf)
                     self.s.shutdown(socket.SHUT_WR)
                     r=self.processTCPReply()
-                    if r.header['id'] != self.tid: continue
-                    self.response = r
-                except socket.error:
-                    continue
-            finally:
-                self.s.close()
-            break
-        if not self.response:
-            raise DNSError,'no working nameservers found'
+                    if r.header['id'] == self.tid:
+                        self.response = r
+                        break
+                finally:
+                    self.s.close()
+            except socket.error:
+                continue
 
 #class DnsAsyncRequest(DnsRequest):
 class DnsAsyncRequest(DnsRequest,asyncore.dispatcher_with_send):
diff -u python-dns-2.3.0/debian/changelog python-dns-2.3.0/debian/changelog
--- python-dns-2.3.0/debian/changelog
+++ python-dns-2.3.0/debian/changelog
@@ -1,3 +1,12 @@
+python-dns (2.3.0-5.2+etch2) stable-security; urgency=medium
+
+  * Non-maintainer upload by the security team;
+  * Modify DNS/Lib.py so unicode DNS names don't cause a crash
+    (Closes: #499277)
+  * Update DNS/Base.py changes for #490217 to more robust upstream fix
+
+ -- Scott Kitterman <[EMAIL PROTECTED]>  Wed, 17 Sep 2008 14:01:41 -0400
+
 python-dns (2.3.0-5.2+etch1) stable-security; urgency=high
 
   * Non-maintainer upload by the security team; thanks to Scott Kitterman
only in patch2:
unchanged:
--- python-dns-2.3.0.orig/DNS/Lib.py
+++ python-dns-2.3.0/DNS/Lib.py
@@ -99,6 +99,7 @@
         list = []
         for label in string.splitfields(name, '.'):
             if label:
+                label = label.encode('utf8')
                 if len(label) > 63:
                     raise PackError, 'label too long'
                 list.append(label)

Attachment: signature.asc
Description: This is a digitally signed message part.

Reply via email to