From: Anthony B. <ant...@us...> - 2002-03-19 10:30:37
|
Update of /cvsroot/pydns/pydns/DNS In directory usw-pr-cvs1:/tmp/cvs-serv29678/DNS Modified Files: Base.py Lib.py Log Message: first round of major bits and pieces. The major stuff here (summarised from my local, off-net CVS server :/ this will cause some oddities with the tests/testPackers.py: a large slab of unit tests for the packer and unpacker code in DNS.Lib DNS/Lib.py: placeholder for addSRV. added 'klass' to addA, make it the same as the other A* records. made addTXT check for being passed a string, turn it into a length 1 list. explicitly check for adding a string of length > 255 (prohibited). a bunch of cleanups from a first pass with pychecker new code for pack/unpack. the bitwise stuff uses struct, for a smallish (disappointly small, actually) improvement, while addr2bin is much much faster now. DNS/Base.py: added DiscoverNameServers. This automatically does the right thing on unix/ win32. No idea how MacOS handles this. *sigh* Incompatible change: Don't use ParseResolvConf on non-unix, use this function, instead! a bunch of cleanups from a first pass with pychecker Index: Base.py =================================================================== RCS file: /cvsroot/pydns/pydns/DNS/Base.py,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -d -r1.7 -r1.8 *** Base.py 7 Dec 2001 21:48:34 -0000 1.7 --- Base.py 19 Mar 2002 10:30:33 -0000 1.8 *************** *** 6,20 **** This code is covered by the standard Python License. """ - import sys - import getopt import socket import string ! import DNS,DNS.Lib,DNS.Type,DNS.Class,DNS.Opcode ! #import asyncore ! defaults= { 'protocol':'udp', 'port':53, 'opcode':DNS.Opcode.QUERY, ! 'qtype':DNS.Type.A, 'rd':1, 'timing':1, 'timeout': 30 } defaults['server']=[] --- 6,21 ---- This code is covered by the standard Python License. + + Base functionality. Request and Response classes, that sort of thing. """ import socket import string ! import Lib,Type,Class,Opcode ! import asyncore ! from DNS import Error as DNSError ! defaults= { 'protocol':'udp', 'port':53, 'opcode':Opcode.QUERY, ! 'qtype':Type.A, 'rd':1, 'timing':1, 'timeout': 30 } defaults['server']=[] *************** *** 22,247 **** def ParseResolvConf(resolv_path="/etc/resolv.conf"): "parses the /etc/resolv.conf file and sets defaults for name servers" - import string, os global defaults - if os.name=="nt": - from win32dns import RegistryResolve - defaults['server']=RegistryResolve() - return - # else lines=open(resolv_path).readlines() for line in lines: ! line = string.strip(line) ! if not line or line[0]==';' or line[0]=='#': ! continue ! fields=string.split(line) ! if fields[0]=='domain': ! defaults['domain']=fields[1] ! if fields[0]=='search': ! pass ! if fields[0]=='options': ! pass ! if fields[0]=='sortlist': ! pass ! if fields[0]=='nameserver': ! defaults['server'].append(fields[1]) class DnsRequest: def __init__(self,*name,**args): ! self.donefunc=None ! self.async=None ! self.defaults = {} ! self.argparse(name,args) ! self.defaults = self.args def argparse(self,name,args): ! if not name and self.defaults.has_key('name'): ! args['name'] = self.defaults['name'] ! if type(name) is type(""): ! args['name']=name ! else: ! if len(name) == 1: ! if name[0]: ! args['name']=name[0] ! for i in defaults.keys(): ! if not args.has_key(i): ! if self.defaults.has_key(i): ! args[i]=self.defaults[i] ! else: ! args[i]=defaults[i] ! if type(args['server']) == type(''): ! args['server'] = [args['server']] ! self.args=args def socketInit(self,a,b): ! import socket ! self.s = socket.socket(a,b) def processUDPReply(self): ! import time,select ! if self.args['timeout'] > 0: ! r,w,e = select.select([self.s],[],[],self.args['timeout']) ! if not len(r): ! raise DNS.Error, 'Timeout' ! self.reply = self.s.recv(1024) ! self.time_finish=time.time() ! self.args['server']=self.ns ! return self.processReply() def processTCPReply(self): ! import time ! self.f = self.s.makefile('r') ! header = self.f.read(2) ! if len(header) < 2: ! raise DNS.Error,'EOF' ! count = DNS.Lib.unpack16bit(header) ! self.reply = self.f.read(count) ! if len(self.reply) != count: ! raise DNS.Error,'incomplete reply' ! self.time_finish=time.time() ! self.args['server']=self.ns ! return self.processReply() def processReply(self): ! import time ! self.args['elapsed']=(self.time_finish-self.time_start)*1000 ! u = DNS.Lib.Munpacker(self.reply) ! r=DNS.Lib.DnsResult(u,self.args) ! r.args=self.args ! #self.args=None # mark this DnsRequest object as used. ! return r ! #### TODO TODO TODO #### ! if protocol == 'tcp' and qtype == DNS.Type.AXFR: ! while 1: ! header = f.read(2) ! if len(header) < 2: ! print '========== EOF ==========' ! break ! count = DNS.Lib.unpack16bit(header) ! if not count: ! print '========== ZERO COUNT ==========' ! break ! print '========== NEXT ==========' ! reply = f.read(count) ! if len(reply) != count: ! print '*** Incomplete reply ***' ! break ! u = DNS.Lib.Munpacker(reply) ! DNS.Lib.dumpM(u) def conn(self): ! self.s.connect((self.ns,self.port)) def req(self,*name,**args): ! import time,sys ! self.argparse(name,args) ! #if not self.args: ! # raise DNS.Error,'reinitialize request before reuse' ! protocol = self.args['protocol'] ! self.port = self.args['port'] ! opcode = self.args['opcode'] ! rd = self.args['rd'] ! server=self.args['server'] ! if type(self.args['qtype']) == type('foo'): ! try: ! qtype = eval(string.upper(self.args['qtype']), DNS.Type.__dict__) ! except (NameError,SyntaxError): ! raise DNS.Error,'unknown query type' ! else: ! qtype=self.args['qtype'] ! if not self.args.has_key('name'): ! print self.args ! raise DNS.Error,'nothing to lookup' ! qname = self.args['name'] ! if qtype == DNS.Type.AXFR: ! print 'Query type AXFR, protocol forced to TCP' ! protocol = 'tcp' ! #print 'QTYPE %d(%s)' % (qtype, DNS.Type.typestr(qtype)) ! m = DNS.Lib.Mpacker() ! m.addHeader(0, ! 0, opcode, 0, 0, rd, 0, 0, 0, ! 1, 0, 0, 0) ! m.addQuestion(qname, qtype, DNS.Class.IN) ! self.request = m.getbuf() ! if protocol == 'udp': ! self.response=None ! self.socketInit(socket.AF_INET, socket.SOCK_DGRAM) ! for self.ns in server: ! try: ! #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 ! break ! if not self.response: ! if not self.async: ! raise DNS.Error,'no working nameservers found' ! else: ! 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(DNS.Lib.pack16bit(len(self.request)) + self.request) ! self.s.shutdown(1) ! self.response=self.processTCPReply() ! except socket.error: ! continue ! break ! if not self.response: ! raise DNS.Error,'no working nameservers found' ! if not self.async: ! return self.response ! #class DnsAsyncRequest(DnsRequest,asyncore.dispatcher_with_send): ! class DnsAsyncRequest(DnsRequest): def __init__(self,*name,**args): ! if args.has_key('done') and args['done']: ! self.donefunc=args['done'] ! else: ! self.donefunc=self.showResult ! self.realinit(name,args) ! self.async=1 def conn(self): ! import time ! self.connect(self.ns,self.port) ! self.time_start=time.time() ! if self.args.has_key('start') and self.args['start']: ! asyncore.dispatcher.go(self) def socketInit(self,a,b): ! self.create_socket(a,b) ! asyncore.dispatcher.__init__(self) ! self.s=self def handle_read(self): ! if self.args['protocol'] == 'udp': ! self.response=self.processUDPReply() ! if self.donefunc: ! apply(self.donefunc,(self,)) def handle_connect(self): ! self.send(self.request) def handle_write(self): ! pass def showResult(self,*s): ! self.response.show() # # $Log$ ! # Revision 1.7 2001/12/07 21:48:34 stroeder ! # Module __doc__ string instead of comment lines. ! # ! # Revision 1.6 2001/12/07 21:47:33 stroeder ! # ParseResolvConf(): # ! # Assign line = string.strip(line) to avoid IndexError with parsing lines only ! # containing white-space chars. # ! # Key word parameter resolv_path for specifying path name of resolv.conf. # ! # Merge checking for empty lines and comments into one if-statement. # # Revision 1.5 2001/08/09 09:22:28 anthonybaxter --- 23,268 ---- def ParseResolvConf(resolv_path="/etc/resolv.conf"): "parses the /etc/resolv.conf file and sets defaults for name servers" global defaults lines=open(resolv_path).readlines() for line in lines: ! line = string.strip(line) ! if not line or line[0]==';' or line[0]=='#': ! continue ! fields=string.split(line) ! if fields[0]=='domain': ! defaults['domain']=fields[1] ! if fields[0]=='search': ! pass ! if fields[0]=='options': ! pass ! if fields[0]=='sortlist': ! pass ! if fields[0]=='nameserver': ! defaults['server'].append(fields[1]) ! ! def DiscoverNameServers(): ! import sys ! if sys.platform in ('win32', 'nt'): ! import win32dns ! defaults['server']=win32dns.RegistryResolve() ! else: ! return ParseResolvConf() class DnsRequest: + """ high level Request object """ def __init__(self,*name,**args): ! self.donefunc=None ! self.async=None ! self.defaults = {} ! self.argparse(name,args) ! self.defaults = self.args def argparse(self,name,args): ! if not name and self.defaults.has_key('name'): ! args['name'] = self.defaults['name'] ! if type(name) is type(""): ! args['name']=name ! else: ! if len(name) == 1: ! if name[0]: ! args['name']=name[0] ! for i in defaults.keys(): ! if not args.has_key(i): ! if self.defaults.has_key(i): ! args[i]=self.defaults[i] ! else: ! args[i]=defaults[i] ! if type(args['server']) == type(''): ! args['server'] = [args['server']] ! self.args=args def socketInit(self,a,b): ! self.s = socket.socket(a,b) def processUDPReply(self): ! import time,select ! if self.args['timeout'] > 0: ! r,w,e = select.select([self.s],[],[],self.args['timeout']) ! if not len(r): ! raise DNSError, 'Timeout' ! self.reply = self.s.recv(1024) ! self.time_finish=time.time() ! self.args['server']=self.ns ! return self.processReply() def processTCPReply(self): ! import time ! self.f = self.s.makefile('r') ! header = self.f.read(2) ! if len(header) < 2: ! raise DNSError,'EOF' ! count = Lib.unpack16bit(header) ! self.reply = self.f.read(count) ! if len(self.reply) != count: ! raise DNSError,'incomplete reply' ! self.time_finish=time.time() ! self.args['server']=self.ns ! return self.processReply() def processReply(self): ! self.args['elapsed']=(self.time_finish-self.time_start)*1000 ! u = Lib.Munpacker(self.reply) ! r=Lib.DnsResult(u,self.args) ! r.args=self.args ! #self.args=None # mark this DnsRequest object as used. ! return r ! #### TODO TODO TODO #### ! # if protocol == 'tcp' and qtype == Type.AXFR: ! # while 1: ! # header = f.read(2) ! # if len(header) < 2: ! # print '========== EOF ==========' ! # break ! # count = Lib.unpack16bit(header) ! # if not count: ! # print '========== ZERO COUNT ==========' ! # break ! # print '========== NEXT ==========' ! # reply = f.read(count) ! # if len(reply) != count: ! # print '*** Incomplete reply ***' ! # break ! # u = Lib.Munpacker(reply) ! # Lib.dumpM(u) def conn(self): ! self.s.connect((self.ns,self.port)) def req(self,*name,**args): ! " needs a refactoring " ! import time ! self.argparse(name,args) ! #if not self.args: ! # raise DNSError,'reinitialize request before reuse' ! protocol = self.args['protocol'] ! self.port = self.args['port'] ! opcode = self.args['opcode'] ! rd = self.args['rd'] ! server=self.args['server'] ! if type(self.args['qtype']) == type('foo'): ! try: ! qtype = eval(string.upper(self.args['qtype']),Type.__dict__) ! except (NameError,SyntaxError): ! raise DNSError,'unknown query type' ! else: ! qtype=self.args['qtype'] ! if not self.args.has_key('name'): ! print self.args ! raise DNSError,'nothing to lookup' ! qname = self.args['name'] ! if qtype == Type.AXFR: ! print 'Query type AXFR, protocol forced to TCP' ! protocol = 'tcp' ! #print 'QTYPE %d(%s)' % (qtype, Type.typestr(qtype)) ! m = Lib.Mpacker() ! m.addHeader(0, ! 0, opcode, 0, 0, rd, 0, 0, 0, ! 1, 0, 0, 0) ! m.addQuestion(qname, qtype, Class.IN) ! self.request = m.getbuf() ! if protocol == 'udp': ! self.response=None ! self.socketInit(socket.AF_INET, socket.SOCK_DGRAM) ! for self.ns in server: ! try: ! #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 ! break ! if not self.response: ! if not self.async: ! raise DNSError,'no working nameservers found' ! else: ! 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 ! break ! if not self.response: ! raise DNSError,'no working nameservers found' ! if not self.async: ! return self.response ! else: ! return None ! #class DnsAsyncRequest(DnsRequest): ! class DnsAsyncRequest(DnsRequest,asyncore.dispatcher_with_send): ! " an asynchronous request object. out of date, probably broken " def __init__(self,*name,**args): ! DnsRequest.__init__(self, *name, **args) ! # XXX todo ! if args.has_key('done') and args['done']: ! self.donefunc=args['done'] ! else: ! self.donefunc=self.showResult ! #self.realinit(name,args) # XXX todo ! self.async=1 def conn(self): ! import time ! self.connect((self.ns,self.port)) ! self.time_start=time.time() ! if self.args.has_key('start') and self.args['start']: ! asyncore.dispatcher.go(self) def socketInit(self,a,b): ! self.create_socket(a,b) ! asyncore.dispatcher.__init__(self) ! self.s=self def handle_read(self): ! if self.args['protocol'] == 'udp': ! self.response=self.processUDPReply() ! if self.donefunc: ! apply(self.donefunc,(self,)) def handle_connect(self): ! self.send(self.request) def handle_write(self): ! pass def showResult(self,*s): ! self.response.show() # # $Log$ ! # Revision 1.8 2002/03/19 10:30:33 anthonybaxter ! # first round of major bits and pieces. The major stuff here (summarised ! # from my local, off-net CVS server :/ this will cause some oddities with ! # the # ! # tests/testPackers.py: ! # a large slab of unit tests for the packer and unpacker code in DNS.Lib # ! # DNS/Lib.py: ! # placeholder for addSRV. ! # added 'klass' to addA, make it the same as the other A* records. ! # made addTXT check for being passed a string, turn it into a length 1 list. ! # explicitly check for adding a string of length > 255 (prohibited). ! # a bunch of cleanups from a first pass with pychecker ! # new code for pack/unpack. the bitwise stuff uses struct, for a smallish ! # (disappointly small, actually) improvement, while addr2bin is much ! # much faster now. # ! # DNS/Base.py: ! # added DiscoverNameServers. This automatically does the right thing ! # on unix/ win32. No idea how MacOS handles this. *sigh* ! # Incompatible change: Don't use ParseResolvConf on non-unix, use this ! # function, instead! ! # a bunch of cleanups from a first pass with pychecker # # Revision 1.5 2001/08/09 09:22:28 anthonybaxter Index: Lib.py =================================================================== RCS file: /cvsroot/pydns/pydns/DNS/Lib.py,v retrieving revision 1.8 retrieving revision 1.9 diff -C2 -d -r1.8 -r1.9 *** Lib.py 9 Aug 2001 09:08:55 -0000 1.8 --- Lib.py 19 Mar 2002 10:30:33 -0000 1.9 *************** *** 1,2 **** --- 1,5 ---- + """ + Library code. Largely this is packers and unpackers for various types. + """ # Domain Name Server (DNS) interface # *************** *** 20,60 **** # ------------------------------------------------------------------------ [...1212 lines suppressed...] + # + # DNS/Lib.py: + # placeholder for addSRV. + # added 'klass' to addA, make it the same as the other A* records. + # made addTXT check for being passed a string, turn it into a length 1 list. + # explicitly check for adding a string of length > 255 (prohibited). + # a bunch of cleanups from a first pass with pychecker + # new code for pack/unpack. the bitwise stuff uses struct, for a smallish + # (disappointly small, actually) improvement, while addr2bin is much + # much faster now. + # + # DNS/Base.py: + # added DiscoverNameServers. This automatically does the right thing + # on unix/ win32. No idea how MacOS handles this. *sigh* + # Incompatible change: Don't use ParseResolvConf on non-unix, use this + # function, instead! + # a bunch of cleanups from a first pass with pychecker + # # Revision 1.8 2001/08/09 09:08:55 anthonybaxter # added identifying header to top of each file |