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) stable-security; urgency=high
+
+  * SECURITY UPDATE: Modify DNS/Base.py to randomize both Transaction ID
+    (TID) and source port (Closes: #490217)
+  * References
+  * CVE-2008-1447 DNS source port guessable
+
+ -- Scott Kitterman <[EMAIL PROTECTED]>  Sat, 26 Jul 2008 01:33:00 -0400
+
 python-dns (2.3.0-5.1) unstable; urgency=low
 
   * Non-maintainer upload.
only in patch2:
unchanged:
--- python-dns-2.3.0.orig/DNS/Base.py
+++ python-dns-2.3.0/DNS/Base.py
@@ -12,6 +12,11 @@
 import socket, string, types, time
 import Type,Class,Opcode
 import asyncore
+try:
+  from random import SystemRandom
+  random = SystemRandom()
+except:
+  import random
 
 class DNSError(Exception): pass
 
@@ -58,6 +63,7 @@
         self.defaults = {}
         self.argparse(name,args)
         self.defaults = self.args
+        self.tid = 0
 
     def argparse(self,name,args):
         if not name and self.defaults.has_key('name'):
@@ -87,7 +93,7 @@
             r,w,e = select.select([self.s],[],[],self.args['timeout'])
             if not len(r):
                 raise DNSError, 'Timeout'
-        self.reply = self.s.recv(1024)
+        (self.reply, self.from_address) = self.s.recvfrom(65535)
         self.time_finish=time.time()
         self.args['server']=self.ns
         return self.processReply()
@@ -133,7 +139,19 @@
 #                u = Lib.Munpacker(reply)
 #                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()
+
     def conn(self):
+        # Source is source port we'll take a reply from.
+        self.getSource()
         self.s.connect((self.ns,self.port))
 
     def req(self,*name,**args):
@@ -144,6 +162,7 @@
         #    raise DNSError,'reinitialize request before reuse'
         protocol = self.args['protocol']
         self.port = self.args['port']
+        self.tid = random.randint(0,65535)
         opcode = self.args['opcode']
         rd = self.args['rd']
         server=self.args['server']
@@ -164,7 +183,7 @@
         #print 'QTYPE %d(%s)' % (qtype, Type.typestr(qtype))
         m = Lib.Mpacker()
         # jesus. keywords and default args would be good. TODO.
-        m.addHeader(0,
+        m.addHeader(self.tid,
               0, opcode, 0, 0, rd, 0, 0, 0,
               1, 0, 0, 0)
         m.addQuestion(qname, qtype, Class.IN)
@@ -184,34 +203,52 @@
         self.socketInit(socket.AF_INET, socket.SOCK_DGRAM)
         for self.ns in server:
             try:
-                # TODO. Handle timeouts &c correctly (RFC)
-                #self.s.connect((self.ns, self.port))
-                self.conn()
-                self.time_start=time.time()
-                if not self.async:
-                    self.s.send(self.request)
-                    self.response=self.processUDPReply()
-            #except socket.error:
-            except None:
-                continue
+                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()
+                    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()
+                        self.response = r
+                        # FIXME: check waiting async queries
+                #except socket.error:
+                except None:
+                    continue
+            finally:
+                self.s.close()
             break
         if not self.response:
             if not self.async:
-                raise DNSError,'no working nameservers found'
+                raise DNSError,('no working nameservers found')
 
     def sendTCPRequest(self, server):
         " do the work of sending a TCP request "
         self.response=None
         for self.ns in server:
             try:
-                self.socketInit(socket.AF_INET, socket.SOCK_STREAM)
-                self.time_start=time.time()
-                self.conn()
-                self.s.send(Lib.pack16bit(len(self.request))+self.request)
-                self.s.shutdown(1)
-                self.response=self.processTCPReply()
-            except socket.error:
-                continue
+                try:
+                    # TODO. Handle timeouts &c correctly (RFC)
+                    self.socketInit(socket.AF_INET, socket.SOCK_STREAM)
+                    self.time_start=time.time()
+                    self.conn()
+                    self.s.setblocking(0)
+                    self.s.sendall(Lib.pack16bit(len(self.request))+self.request)
+                    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'
@@ -230,6 +267,8 @@
         self.async=1
     def conn(self):
         import time
+        # Source is source port we'll take a reply from.
+        self.getSource()
         self.connect((self.ns,self.port))
         self.time_start=time.time()
         if self.args.has_key('start') and self.args['start']:

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



Reply via email to