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,11 @@
+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)
+ - CVE-2008-1447 DNS source port guessable
+
+ -- Scott Kitterman <[EMAIL PROTECTED]> Sat, 26 Jul 2008 21:46: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,21 @@
# 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()
+ else:
+ raise
+
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 +164,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 +185,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 +205,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 +269,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']:
signature.asc
Description: This is a digitally signed message part.

