pyip-0.7/0000755024311100256300000000000010645516243012227 5ustar tijiangccuserspyip-0.7/icmp.py0000644024311100256300000002046210645253074013535 0ustar tijiangccusers# # pyip is a Python package offering assembling/disassembling of raw ip packet # including ip, udp, and icmp. Also it includes 2 utilities based on raw ip, # traceroute and ping. # # pyip is released under PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2, and is # a project inspired by 'ping' written by Jeremy Hylton. # # Author: Kenneth Jiang, kenneth.jiang@gmail.com # import inetutils import ip import array import struct ICMP_MINLEN = 8 ICMP_MASKLEN = 12 ICMP_ECHOREPLY = 0 ICMP_UNREACH = 3 ICMP_UNREACH_NET = 0 ICMP_UNREACH_HOST = 1 ICMP_UNREACH_PROTOCOL = 2 ICMP_UNREACH_PORT = 3 ICMP_UNREACH_NEEDFRAG = 4 ICMP_UNREACH_SRCFAIL = 5 ICMP_SOURCEQUENCH = 4 ICMP_REDIRECT = 5 ICMP_REDIRECT_NET = 0 ICMP_REDIRECT_HOST = 1 ICMP_REDIRECT_TOSNET = 2 ICMP_REDIRECT_TOSHOST = 3 ICMP_ECHO = 8 ICMP_TIMXCEED = 11 ICMP_TIMXCEED_INTRANS = 0 ICMP_TIMXCEED_REASS = 1 ICMP_PARAMPROB = 12 ICMP_TSTAMP = 13 ICMP_TSTAMPREPLY = 14 ICMP_IREQ = 15 ICMP_IREQREPLY = 16 ICMP_MASKREQ = 17 ICMP_MASKREPLY = 18 HDR_SIZE_IN_BYTES = 8 class Packet: """Basic ICMP packet definition. It defines fields that are common to all ICMP packets: type, code, and cksum This class also defines the method to assemble into a byte sequence ready for sending over the network """ def __init__(self, type, code): self.__type = type self.__code = code self.__cksum = 0 #cksum should be calcualted upon assemble self.__raw_packet = '' def __repr__(self): return "" % (self.get_type(), self.get_code()) def __eq__(self, other): if not isinstance(other, Packet): return 0 return self.get_code() == other.get_code() and \ self.get_type() == other.get_type() and \ self.get_cksum() == other.get_cksum() and \ self.__raw_packet == other.__raw_packet def _assemble(self, cksum): """ method to assemble into a byte sequence that is ready for being sent This method will call the virtual method _get_icmp_data from its concrete sub-class to get its payload """ packet = chr(self.get_type()) + chr(self.get_code()) + '\000\000' + self._get_icmp_data() if cksum: self.__cksum = struct.pack('H', inetutils.cksum(packet)) else: self.__cksum = '\000\000' self.__raw_packet = chr(self.get_type()) + chr(self.get_code()) + self.get_cksum() + self._get_icmp_data() # Don't need to do any byte-swapping, because idseq is # appplication defined and others are single byte values. return self.__raw_packet def _disassemble(self, buffer, cksum): type, code = ord(buffer[0]), ord(buffer[1]) # when this method is called, type and code should be set correctly already assert self.get_type() == type, "Mismatched type %d : %d" % (self.get_type(), type) assert self.get_code() == code, "Mismatched code %d : %d" % (self.get_code(), code) #only field let to puplate is cksum if cksum and 0 != inetutils.cksum(buffer): raise ValueError, "CheckSum Error!" self.__cksum = buffer[2:4] self.__raw_packet = buffer def get_type(self): return self.__type def get_code(self): return self.__code def get_cksum(self): return self.__cksum class IdAndSeqPacket(Packet): """ ICMP packet of "id + seq + data", Echo and EchoReply as examples. """ def __init__(self, type, code, id, seq, data): Packet.__init__(self, type = type, code = code) self.__id = id self.__seq = seq self.__data = data def __eq__(self, other): if not Packet.__eq__(self, other): return 0 if not isinstance(other, type(self)): return 0 return self.get_id() == other.get_id() and \ self.get_seq() == other.get_seq() and \ self.get_data() == other.get_data() def _get_icmp_data(self): return struct.pack('HH', self.get_id(), self.get_seq()) + self.get_data() def _disassemble(self, buffer, cksum): if len(buffer) < 8: raise ValueError, "Invalid ICMP Packet length: %d" % len(buffer) (self.__id, self.__seq) = struct.unpack('HH', buffer[4:8]) self.__data = buffer[8:] Packet._disassemble(self, buffer, cksum) def get_id(self): return self.__id def get_seq(self): return self.__seq def get_data(self): return self.__data class Echo(IdAndSeqPacket): def __init__(self, id=0, seq=0, data=''): IdAndSeqPacket.__init__(self, type = ICMP_ECHO, code = 0, id = id, seq = seq, data = data) def _disassemble(self, buffer, cksum): type, code = ord(buffer[0]), ord(buffer[1]) if type != ICMP_ECHO or code != 0: raise ValueError, "Invalid Echo ICMP type: %d or code: %d" % (type, code) IdAndSeqPacket._disassemble(self, buffer, cksum) class EchoReply(IdAndSeqPacket): def __init__(self, id=0, seq=0, data=''): IdAndSeqPacket.__init__(self, type = ICMP_ECHOREPLY, code = 0, id = id, seq = seq, data = data) def _disassemble(self, buffer, cksum): type, code = ord(buffer[0]), ord(buffer[1]) if type != ICMP_ECHOREPLY or code != 0: raise ValueError, "Invalid EchoReply ICMP type: %d or code: %d" % (type, code) IdAndSeqPacket._disassemble(self, buffer, cksum) class IPEmbeddedPacket(Packet): def __init__(self, type, code, embedded_ip): Packet.__init__(self, type = type, code = code) self.__unused = '\000\000\000\000' self.__embedded_ip = embedded_ip def __eq__(self, other): if not Packet.__eq__(self, other): return 0 if not isinstance(other, type(self)): return 0 return self.get_embedded_ip() == other.get_embedded_ip() def _get_icmp_data(self): assert self.__embedded_ip, "Embedded IP should not be None" return self.__unused + ip.assemble(self.get_embedded_ip()) def _disassemble(self, buffer, cksum): code = ord(buffer[1]) self.__embedded_ip = ip.disassemble(buffer[8:]) Packet._disassemble(self, buffer, cksum) def get_embedded_ip(self): return self.__embedded_ip class TimeExceeded(IPEmbeddedPacket): def __init__(self, code=0, embedded_ip=None): IPEmbeddedPacket.__init__(self, type = ICMP_TIMXCEED, code = code, embedded_ip = embedded_ip) def _disassemble(self, buffer, cksum): type = ord(buffer[0]) if type != ICMP_TIMXCEED: raise ValueError, "Invalid TimeExceeded ICMP type: %d" % type IPEmbeddedPacket._disassemble(self, buffer, cksum) class Unreachable(IPEmbeddedPacket): #Unreachable is the same with TimeExceeded except the type def __init__(self, code=0, embedded_ip=None): IPEmbeddedPacket.__init__(self, type = ICMP_UNREACH, code = code, embedded_ip = embedded_ip) def _disassemble(self, buffer, cksum): type = ord(buffer[0]) if type != ICMP_UNREACH: raise ValueError, "Invalid Unreachable ICMP type: %d" % type IPEmbeddedPacket._disassemble(self, buffer, cksum) def assemble(packet, cksum=1): return packet._assemble(cksum) def disassemble(buffer, cksum=1): type, code = ord(buffer[0]), ord(buffer[1]) if type == ICMP_ECHO: packet = Echo() elif type == ICMP_ECHOREPLY: packet = EchoReply() elif type == ICMP_TIMXCEED: packet = TimeExceeded(code = code) elif type == ICMP_UNREACH: packet = Unreachable(code = code) else: raise ValueError, "Unrecognized type: %d" % type packet._disassemble(buffer, cksum) return packet pyip-0.7/inetutils.py0000644024311100256300000000334310645253107014621 0ustar tijiangccusers# # pyip is a Python package offering assembling/disassembling of raw ip packet # including ip, udp, and icmp. Also it includes 2 utilities based on raw ip, # traceroute and ping. # # pyip is released under PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2, and is # a project inspired by 'ping' written by Jeremy Hylton. # # Author: Kenneth Jiang, kenneth.jiang@gmail.com # """Internet packet basic Simple operations like performing checksums and swapping byte orders. """ #from _ip import * import array import struct from socket import htons, ntohs def cksum(s): if len(s) & 1: s = s + '\0' words = array.array('h', s) sum = 0 for word in words: sum = sum + (word & 0xffff) hi = sum >> 16 lo = sum & 0xffff sum = hi + lo sum = sum + (sum >> 16) return (~sum) & 0xffff # Should generalize from the *h2net patterns # This python code is suboptimal because it is based on C code where # it doesn't cost much to take a raw buffer and treat a section of it # as a u_short. def gets(s): return struct.unpack('H', s)[0] & 0xffff def mks(h): return struct.pack('H', h) def iph2net(s): len = htons(gets(s[2:4])) id = htons(gets(s[4:6])) off = htons(gets(s[6:8])) return s[:2] + mks(len) + mks(id) + mks(off) + s[8:] def net2iph(s): len = ntohs(gets(s[2:4])) id = ntohs(gets(s[4:6])) off = ntohs(gets(s[6:8])) return s[:2] + mks(len) + mks(id) + mks(off) + s[8:] def udph2net(s): sp = htons(gets(s[0:2])) dp = htons(gets(s[2:4])) len = htons(gets(s[4:6])) return mks(sp) + mks(dp) + mks(len) + s[6:] def net2updh(s): sp = ntohs(gets(s[0:2])) dp = ntohs(gets(s[2:4])) len = ntohs(gets(s[4:6])) return mks(sp) + mks(dp) + mks(len) + s[6:] pyip-0.7/ip.py0000644024311100256300000001543110645253124013211 0ustar tijiangccusers# # pyip is a Python package offering assembling/disassembling of raw ip packet # including ip, udp, and icmp. Also it includes 2 utilities based on raw ip, # traceroute and ping. # # pyip is released under PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2, and is # a project inspired by 'ping' written by Jeremy Hylton. # # Author: Kenneth Jiang, kenneth.jiang@gmail.com # import inetutils import socket import struct import string import os IPVERSION = 4 IP_DF = 0x4000 IP_MF = 0x2000 IP_MAXPACKET = 65535 IPTOS_LOWDELAY = 0x10 IPTOS_THROUGHPUT = 0x08 IPTOS_RELIABILITY = 0x04 IPTOS_PREC_NETCONTROL = 0xe0 IPTOS_PREC_INTERNETCONTROL = 0xc0 IPTOS_PREC_CRITIC_ECP = 0xa0 IPTOS_PREC_FLASHOVERRIDE = 0x80 IPTOS_PREC_FLASH = 0x60 IPTOS_PREC_IMMEDIATE = 0x40 IPTOS_PREC_PRIORITY = 0x20 IPTOS_PREC_ROUTINE = 0x00 IPOPT_CONTROL = 0x00 IPOPT_RESERVED1 = 0x20 IPOPT_DEBMEAS = 0x40 IPOPT_RESERVED2 = 0x60 IPOPT_EOL = 0 IPOPT_NOP = 1 IPOPT_RR = 7 IPOPT_TS = 68 IPOPT_SECURITY = 130 IPOPT_LSRR = 131 IPOPT_SATID = 136 IPOPT_SSRR = 137 IPOPT_OPTVAL = 0 IPOPT_OLEN = 1 IPOPT_OFFSET = 2 IPOPT_MINOFF = 4 IPOPT_TS_TSONLY = 0 IPOPT_TS_TSANDADDR = 1 IPOPT_TS_PRESPEC = 2 IPOPT_SECUR_UNCLASS = 0x0000 IPOPT_SECUR_CONFID = 0xf135 IPOPT_SECUR_EFTO = 0x789a IPOPT_SECUR_MMMM = 0xbc4d IPOPT_SECUR_RESTR = 0xaf13 IPOPT_SECUR_SECRET = 0xd788 IPOPT_SECUR_TOPSECRET = 0x6bc5 MAXTTL = 255 IPFRAGTTL = 60 IPTTLDEC = 1 IP_MSS = 576 MIN_HDR_SIZE_IN_BYTES = 20 class Packet: """An IP packet. Doesn't handle IP options yet (but you have the option of adding support). """ def __init__(self, v = IPVERSION, hl = 5, tos = IPTOS_PREC_ROUTINE, len = 20, id = 0, df = 0, off = 0, ttl = 0, p = 0, sum = 0, src = None, dst = None, data = ''): self.v = v self.hl = hl # this implement punts on options self.tos = tos self.len = len # begin with header length self.id = id self.df = df self.off = off self.ttl = ttl self.p = p self.sum = sum self.src = src self.dst = dst self.data = data self.raw_packet = '' def __repr__(self): begin = "" elif len(self.data) < 10: rep = begin + "%s>" % repr(self.data) else: rep = begin + "%s>" % repr(self.data[:10] + '...') return rep def __eq__(self, other): if not isinstance(other, Packet): return 0 return self.v == other.v and \ self.hl == other.hl and \ self.tos == other.tos and \ self.len == other.len and \ self.id == other.id and \ self.df == other.df and \ self.off == other.off and \ self.ttl == other.ttl and \ self.p == other.p and \ self.sum == other.sum and \ self.src == other.src and \ self.dst == other.dst and \ self.data == other.data def _assemble(self, cksum): "Get a packet suitable for sending over an IP socket." # make sure all the data is ready assert self.src, "src needed before assembling." assert self.dst, "dst needed before assembling." self.len = self.hl * 4 + len(self.data) self.__parse_addrs() # create the packet header = struct.pack('ccHHHcc', chr((self.v & 0x0f) << 4 | (self.hl & 0x0f)), # 4bits each chr(self.tos & 0xff), self.len, self.id, (self.df & 0x01) << 14 | self.off, # what about flags? chr(self.ttl & 0xff), chr(self.p & 0xff)) if cksum: self.sum = inetutils.cksum(header + '\000\000' + self.__src + self.__dst) packet = header + struct.pack('H', self.sum) \ + self.__src + self.__dst else: packet = header + '\000\000' + self.__src + self.__dst packet = packet + self.data self.__packet = inetutils.iph2net(packet) return self.__packet def __parse_addrs(self): try: self.__src = socket.inet_aton(self.src) except ValueError: try: self.__src = socket.inet_aton(socket.gethostbyname(self.src)) except ValueError: raise ValueError, "invalid source address" try: self.__dst = socket.inet_aton(self.dst) except ValueError: try: self.__dst = socket.inet_aton(socket.gethostbyname(self.dst)) except ValueError: raise ValueError, "invalid source address" def __unparse_addrs(self): src = struct.unpack('cccc', self.src) self.src = string.joinfields(map(lambda x:str(ord(x)), src), '.') dst = struct.unpack('cccc', self.dst) self.dst = string.joinfields(map(lambda x:str(ord(x)), dst), '.') def _disassemble(self, raw_packet, cksum): # The kernel computes the checksum, even on a raw packet. packet = inetutils.net2iph(raw_packet) b1 = ord(packet[0]) self.v = (b1 >> 4) & 0x0f self.hl = b1 & 0x0f if self.v != IPVERSION: raise ValueError, "cannot handle IPv%d packets" % self.v hl = self.hl * 4 # verify the checksum self.sum = struct.unpack('H', packet[10:12])[0] & 0xffff if cksum: our_cksum = inetutils.cksum(packet[:20]) if our_cksum != 0: raise ValueError, packet # unpack the fields elts = struct.unpack('ccHHHcc', packet[:hl-10]) # struct didn't do !<> when this was written self.tos = ord(elts[1]) self.len = elts[2] & 0xffff self.id = elts[3] & 0xffff self.off = elts[4] & 0xffff self.ttl = ord(elts[5]) self.p = ord(elts[6]) self.data = packet[hl:] self.src = packet[hl-8:hl-4] self.dst = packet[hl-4:hl] self.__unparse_addrs() def assemble(packet, cksum = 0): return packet._assemble(cksum) def disassemble(buffer, cksum = 0): packet = Packet() packet._disassemble(buffer, cksum) return packet pyip-0.7/LICENSE0000644024311100256300000000453310645252762013244 0ustar tijiangccusersPYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 -------------------------------------------- 1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and the Individual or Organization ("Licensee") accessing and otherwise using this software ("Python") in source or binary form and its associated documentation. 2. Subject to the terms and conditions of this License Agreement, PSF hereby grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python alone or in any derivative version, provided, however, that PSF's License Agreement and PSF's notice of copyright, i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Python Software Foundation; All Rights Reserved" are retained in Python alone or in any derivative version prepared by Licensee. 3. In the event Licensee prepares a derivative work that is based on or incorporates Python or any part thereof, and wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in any such work a brief summary of the changes made to Python. 4. PSF is making Python available to Licensee on an "AS IS" basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 6. This License Agreement will automatically terminate upon a material breach of its terms and conditions. 7. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between PSF and Licensee. This License Agreement does not grant permission to use PSF trademarks or trade name in a trademark sense to endorse or promote products or services of Licensee, or any third party. 8. By copying, installing or otherwise using Python, Licensee agrees to be bound by the terms and conditions of this License Agreement. pyip-0.7/MANIFEST0000644024311100256300000000024410645255766013372 0ustar tijiangccusers./icmp.py ./inetutils.py ./ip.py ./LICENSE ./MANIFEST ./ping.py ./setup.py ./test ./test/icmptests.py ./test/iptests.py ./test/udptests.py ./traceroute.py ./udp.py pyip-0.7/ping.py0000644024311100256300000001325310645253134013537 0ustar tijiangccusers# # pyip is a Python package offering assembling/disassembling of raw ip packet # including ip, udp, and icmp. Also it includes 2 utilities based on raw ip, # traceroute and ping. # # pyip is released under PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2, and is # a project inspired by 'ping' written by Jeremy Hylton. # # Author: Kenneth Jiang, kenneth.jiang@gmail.com # """Ping. Round-trip delay measurement utility. Uses ICMP ECHO_REQEST messages to measure the delay between two Internet hosts. """ import icmp, ip import socket import time import select import string import os, sys TimedOut = 'TimedOut' class PingSocket: def __init__(self, addr): self.dest = (socket.gethostbyname(addr), 0) self.open_icmp_socket() def open_icmp_socket(self): self.socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP) self.socket.setblocking(1) def sendto(self, packet): self.socket.sendto(packet, self.dest) def recvfrom(self, maxbytes): return self.socket.recvfrom(maxbytes) class Pinger: def __init__(self, addr, num): self.num = num self.last = 0 self.sent = 0 self.times = {} self.deltas = [] self.sock = PingSocket(addr) self.pid = os.getpid() self.addr = addr name, aliases, ipaddr = socket.gethostbyaddr(addr) if aliases: self.destinfo = (aliases[0], ipaddr[0]) else: self.destinfo = (name, ipaddr[0]) def send_packet(self): pkt = icmp.Echo(id=self.pid, seq=self.sent, data='python pinger') buf = icmp.assemble(pkt) self.times[self.sent] = time.time() self.sock.sendto(buf) self.plen = len(buf) self.sent = self.sent + 1 def recv_packet(self, pkt, when): try: sent = self.times[pkt.get_seq()] del self.times[pkt.get_seq()] except KeyError: return # limit to ms precision delta = int((when - sent) * 1000.) self.deltas.append(delta) self.recv_output(self.plen, self.destinfo[0], self.destinfo[1], pkt.get_seq(), delta) if pkt.get_seq() > self.last: self.last = pkt.get_seq() def recv_output(self, bytes, dest, addr, seq, delta): "Place holder for subclass output/collector method" pass def ping(self): # don't wait more than 10 seconds from now for first reply self.last_arrival = time.time() while 1: if self.sent < self.num: self.send_packet() elif not self.times and self.last == self.num - 1: break else: now = time.time() if self.deltas: # Wait no more than 10 times the longest delay so far if (now - self.last_arrival) > max(self.deltas) / 100.: break else: # Wait no more than 10 seconds if (now - self.last_arrival) > 10.: break self.wait() def wait(self): start = time.time() timeout = 1.0 while 1: rd, wt, er = select.select([self.sock.socket], [], [], timeout) if rd: # okay to use time here, because select has told us # there is data and we don't care to measure the time # it takes the system to give us the packet. arrival = time.time() try: pkt, who = self.sock.recvfrom(4096) except socket.error: continue # could also use the ip module to get the payload repip = ip.disassemble(pkt) try: reply = icmp.disassemble(repip.data) except ValueError: continue if reply.get_id() == self.pid: self.recv_packet(reply, arrival) self.last_arrival = arrival timeout = (start + 1.0) - time.time() if timeout < 0: break def get_summary(self): dmin = min(self.deltas) dmax = max(self.deltas) davg = reduce(lambda x, y: x + y, self.deltas) / len(self.deltas) sent = self.num recv = sent - len(self.times.values()) loss = float(sent - recv) / float(sent) return dmin, davg, dmax, sent, recv, loss class CollectorPinger(Pinger): def __init__(self, host, num): Pinger.__init__(self, host, num) self.results = {} def recv_output(self, bytes, dest, addr, seq, delta): self.results[seq] = delta class CmdlinePinger(Pinger): def recv_output(self, bytes, dest, addr, seq, delta): print "%d bytes from %s (%s): icmp_seq=%d. time=%d. ms" % \ (bytes, dest, addr, seq, delta) def ping(self): print "PING %s" % self.destinfo[0] Pinger.ping(self) if __name__ == "__main__": try: who = sys.argv[1] except IndexError: print "ping.py host [#packets]" sys.exit(0) try: num = string.atoi(sys.argv[2]) except ValueError: print "ping.py host [#packets]" sys.exit(0) except IndexError: num = 32 p = CmdlinePinger(who, num) p.ping() summary = p.get_summary() print "---Ping statistics---" print "%d packets transmitted, %d packets received, %d%% packet loss" % \ (summary[3], summary[4], int(summary[5] * 100.)) print "round-trip (ms) min/avg/max = %d/%d/%d" % \ (summary[0], summary[1], summary[2]) pyip-0.7/PKG-INFO0000644024311100256300000000230410645516243013323 0ustar tijiangccusersMetadata-Version: 1.0 Name: pyip Version: 0.7 Summary: pyip: assemble/disassemble raw ip packet Home-page: https://sourceforge.net/projects/pyip Author: Kenneth Jiang Author-email: kenneth.jiang@gmail.com License: Standard Python License Description: pyip is a Python package offering assembling/disassembling of raw ip packet, including ip, udp, and icmp. Also it includes 2 utilities based on raw ip, traceroute and ping. The primary motivation for this project is to fill the blank in Python, i.e., handling raw ip packet. Meanwhile, the utility 'traceroute' is intended to be port of Unix 'traceroute' to Windows platform, as Windows' tracert has only very limited command line options compared with Unix 'traceroute'. Platform: any Classifier: License :: OSI Approved :: Python Software Foundation License Classifier: Intended Audience :: Developers Classifier: Development Status :: 3 - Alpha Classifier: Topic :: Internet Classifier: Topic :: System :: Networking Classifier: Programming Language :: Python Classifier: Operating System :: MacOS :: MacOS X Classifier: Operating System :: Microsoft :: Windows Classifier: Operating System :: POSIX pyip-0.7/setup.py0000644024311100256300000000307010645515676013752 0ustar tijiangccusers"""pyip: assemble/disassemble raw ip packet pyip is a Python package offering assembling/disassembling of raw ip packet, including ip, udp, and icmp. Also it includes 2 utilities based on raw ip, traceroute and ping. The primary motivation for this project is to fill the blank in Python, i.e., handling raw ip packet. Meanwhile, the utility 'traceroute' is intended to be port of Unix 'traceroute' to Windows platform, as Windows' tracert has only very limited command line options compared with Unix 'traceroute'. """ classifiers = """\ License :: OSI Approved :: Python Software Foundation License Intended Audience :: Developers Development Status :: 3 - Alpha Topic :: Internet Topic :: System :: Networking Programming Language :: Python Operating System :: MacOS :: MacOS X Operating System :: Microsoft :: Windows Operating System :: POSIX """ from distutils.core import setup import sys if sys.version_info < (2, 3): _setup = setup def setup(**kwargs): if kwargs.has_key("classifiers"): del kwargs["classifiers"] _setup(**kwargs) doclines = __doc__.split("\n") setup(name="pyip", version="0.7", maintainer="Kenneth Jiang", maintainer_email="kenneth.jiang@gmail.com", url = "https://sourceforge.net/projects/pyip", license = "Standard Python License", platforms = ["any"], py_modules = ['icmp', 'inetutils', 'ping', 'traceroute', 'udp', 'ip', ], description = doclines[0], classifiers = filter(None, classifiers.split("\n")), long_description = "\n".join(doclines[2:]), ) pyip-0.7/test/0000755024311100256300000000000010645516243013206 5ustar tijiangccuserspyip-0.7/test/icmptests.py0000644024311100256300000000433110645253241015570 0ustar tijiangccusers# # pyip is a Python package offering assembling/disassembling of raw ip packet # including ip, udp, and icmp. Also it includes 2 utilities based on raw ip, # traceroute and ping. # # pyip is released under PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2, and is # a project inspired by 'ping' written by Jeremy Hylton. # A# Author: Kenneth Jiang, kenneth.jiang@gmail.com # import sys ; sys.path.insert(0, '..') import unittest import icmp import ip class icmpSelfVerifyingTestCase(unittest.TestCase): def setUp(self): embedded = ip.Packet() embedded.src = '127.0.0.1' embedded.dst = '0.0.0.0' self.echo = icmp.Echo(1234, 1343, 'python pinger') self.echo_reply = icmp.EchoReply(1234, 1343, 'python pinger') self.time_exceeded = icmp.TimeExceeded(code = 1, embedded_ip = embedded) self.unreachable = icmp.Unreachable(code = 2, embedded_ip = embedded) def testEcho(self): buf = icmp.assemble(self.echo, cksum = 1) new = icmp.disassemble(buf, cksum = 1) self.assertEqual(self.echo, new) def testEchoNotCksum(self): buf = icmp.assemble(self.echo, cksum = 0) new = icmp.disassemble(buf, cksum = 0) self.assertEqual(self.echo, new) def testEchoReply(self): buf = icmp.assemble(self.echo_reply, cksum = 1) new = icmp.disassemble(buf, cksum = 1) self.assertEqual(self.echo_reply, new) def testEchoReplyNotCksum(self): buf = icmp.assemble(self.echo_reply, cksum = 0) new = icmp.disassemble(buf, cksum = 0) self.assertEqual(self.echo_reply, new) def testUnreachable(self): buf = icmp.assemble(self.unreachable, cksum = 1) new = icmp.disassemble(buf, cksum = 1) self.assertEqual(self.unreachable, new) def testUnreachableNotCksum(self): buf = icmp.assemble(self.unreachable, cksum = 0) new = icmp.disassemble(buf, cksum = 0) self.assertEqual(self.unreachable, new) def testTimeExceeded(self): buf = icmp.assemble(self.time_exceeded, cksum = 1) new = icmp.disassemble(buf, cksum = 1) self.assertEqual(self.time_exceeded, new) pyip-0.7/test/iptests.py0000755024311100256300000000145510645253277015270 0ustar tijiangccusers# # pyip is a Python package offering assembling/disassembling of raw ip packet # including ip, udp, and icmp. Also it includes 2 utilities based on raw ip, # traceroute and ping. # # pyip is released under PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2, and is # a project inspired by 'ping' written by Jeremy Hylton. # # Author: Kenneth Jiang, kenneth.jiang@gmail.com # import sys ; sys.path.insert(0, '..') import unittest import ip class ipSelfVerifyingTestCase(unittest.TestCase): def setUp(self): self.simple = ip.Packet() self.simple.src = '127.0.0.1' self.simple.dst = '0.0.0.0' def testSimplePacket(self): buf = ip.assemble(self.simple, 1) new = ip.disassemble(buf, 1) self.assertEqual(self.simple, new) pyip-0.7/test/udptests.py0000755024311100256300000000320410645253305015432 0ustar tijiangccusers# # pyip is a Python package offering assembling/disassembling of raw ip packet # including ip, udp, and icmp. Also it includes 2 utilities based on raw ip, # traceroute and ping. # # pyip is released under PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2, and is # a project inspired by 'ping' written by Jeremy Hylton. # # Author: Kenneth Jiang, kenneth.jiang@gmail.com # import sys ; sys.path.insert(0, '..') import unittest import udp import ip import icmp class udpSelfVerifyingTestCase(unittest.TestCase): def setUp(self): self.simple = udp.Packet() self.simple.sport = 3213 self.simple.dport = 1232 self.simple.data = "ddd" def testSimplePacket(self): buf = udp.assemble(self.simple, 1) new = udp.disassemble(buf, 1) self.assertEqual(self.simple, new) class udpInIcmpTestCase(unittest.TestCase): def setUp(self): self.pkt = 'E\xc0\x008\x84\xf1\x00\x00\xfe\x01\x91G\n\xf9OB\n\xf9@\x98\x0b\x00g\x8d\x00\x00\x00\x00E\x00\x00&\xfc\xfb\x00\x00\x01\x11\xf4\xa9\n\xf9@\x98\xcfD\xadL\x9c\xe4\x82\x9b\x00\x12m\xe0' def testUdpPortWronlyParsed(self): ip_reply = ip.disassemble(self.pkt) icmp_reply = icmp.disassemble(ip_reply.data) #ICMP is payload of IP inner_ip = icmp_reply.get_embedded_ip() self.assertEqual('10.249.64.152', inner_ip.src) self.assertEqual('207.68.173.76', inner_ip.dst) udp_in_icmp = udp.disassemble(inner_ip.data, 0) self.assertEqual(40164, udp_in_icmp.sport) self.assertEqual(33435, udp_in_icmp.dport) pyip-0.7/traceroute.py0000644024311100256300000005400010645253175014757 0ustar tijiangccusers# # pyip is a Python package offering assembling/disassembling of raw ip packet # including ip, udp, and icmp. Also it includes 2 utilities based on raw ip, # traceroute and ping. # # pyip is released under PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2, and is # a project inspired by 'ping' written by Jeremy Hylton. # # Author: Kenneth Jiang, kenneth.jiang@gmail.com # from sys import stdout import sys import ip, icmp, udp import socket import select import time import os import getopt import string #Exit code definition ERR_USAGE = 1 ERR_RESOLVE = 1 ERR_TRACE = 2 # debug level DEBUG = 0 # Exception occurred during tracing class TraceError(Exception): pass class TraceParameters: """ Class to capture command line options All parameters will be assigned default value, which can be overwritten by command line options. So it is guarantted that no invalid value will be returned for any parameter This class is designed this way so that it is detached from the way parameters are specified. So it is possible to extend it to capture GUI options for example. """ def __init__(self): self.resolve_host = 1 # IPs need to be resolved to hostname self.style_newline = 0 # Output style with new line # the following will break if the local host does not have its own name resolved # correctly. How to reliably get local host primary IP address remains unknown. self.src_addr = socket.gethostbyname(socket.gethostname()) self.first_ttl = 1 # TTL to set at the beginning self.dont_frag = 0 # Set the "don't fragment" bit self.check_sum = 0 # Checksume is not calculatd by default self.max_ttl = 30 # Max ttl to set self.def_port = 32768 + 666 # Starting port to probe self.num_probe = 3 # Number of probes for each hop self.max_wait = 5.0 # Maxium time waiting for probe result self.pause_msec = 0 # Pause (in milliseconds) between probes self.verbose = 0 # ICMP packets other than IME_EXCEEDED and UNREACHABLE won't be listed by default self.probe_with_icmp = 0 # Use ICMP ECHO packet, rather than UDP packet, to probe self.packet_len = 38 # length of probe packet self.print_help = 0 # whether '-h' is specified or not def usage(self): usage = \ """Usage: traceroute.py [ -dFhInvx ] [ -f first_ttl ] [-m max_ttl] [-p port] [-q nqueries] [ -s src_addr ] [-w waittime] [ -z pausemsecs ] host [packetlen] """ return usage def from_commandline_options(self, args): """ Factory Method. Parse command line options into TraceParameter object Return empty list upon bad command line options """ global DEBUG try: opts, args = getopt.getopt(args, 'dFhInvxf:sm:p:q:w:') except getopt.GetoptError, msg: print msg return [] for k, v in opts: if k == '-d': DEBUG = 1 elif k == '-F': self.dont_frag = 1 elif k == '-h': self.print_help = 1 elif k == '-I': self.probe_with_icmp = 1 elif k == '-n': self.resolve_host = 0 elif k == '-v': self.verbose = 1 elif k == '-x': self.check_sum = 1 elif k == '-l': self.style_newline = 1 elif k == '-f': try: first_ttl = int(v) self.first_ttl = first_ttl except ValueError: print "invalid first_ttl value", v return [] elif k == '-m': try: hops = int(v) self.max_ttl = hops except ValueError: print "invalid max_ttl value", v return [] elif k == '-p': global def_port try: port = int(v) self.def_port = port except ValueError: print "invalid port", v return [] elif k == '-q': try: n = int(v) self.num_probe = n except ValueError: print "invalid number of queries", v return [] elif k == '-s': self.src_addr = v elif k == '-w': try: w = float(v) self.max_wait = w except ValueError: print "invalid timeout", v return [] elif k == '-z': try: pause = int(v) self.pause_msec = pause except ValueError: print "invalid pausemsec value", v return [] # the optional arg at the end will be packlen if len(args) == 2: try: packet_len = int(args[1]) self.packet_len = packet_len del args[1] except ValueError: print "invalid pausemsec value", args[1] return [] return args class Probe: """ class to represent a probe, meaning a outgoing/incoming packet pair """ def __init__(self): # data for outgoing packet self.src_addr = None self.dst_addr = None self.src_port = None self.dst_port = None self.ttl = None self.dont_frag = 0 self.check_sum = 0 self.packet_len = 0 self.verbose = 0 # date for incoming packet self.gateway = None self.timestamp_sent = None self.timestamp_received = None self.dst_reached = 0 def is_dst_reached(self): """ decide if destination is reached or not from the probe result """ return self.dst_reached def sent(self): self.timestamp_sent = time.time() def get_round_trip_time(self): if not self.gateway: # We didn't hear back from gateway return "*" else: return ("%.3f" % ((self.timestamp_received - self.timestamp_sent)*1000.0)) + " ms" def probe_packet(self): """ Build the outgoing probe packet """ assert 0, "probe_packet should be implemented by Probe's subclass" def received(self, pkt, gateway): """ Upon received an incoming ICMP, determine if the packet is of our interest If it is, populate related fields, and return 1 otherwise return 0 """ assert 0, "received should be implemented by Probe's subclass" class UDPProbe(Probe): def probe_packet(self): """ Build the outgoing probe packet """ # build the packet, then set its length probe_ip = ip.Packet() probe_ip.src = self.src_addr probe_ip.dst = self.dst_addr probe_ip.p = socket.IPPROTO_UDP probe_ip.ttl = self.ttl probe_ip.df = self.dont_frag # build UPD packet as the payload of IP packet probe_udp = udp.Packet() # Because more than 1 traceroute can be running at the same time, we need to # distinguish the packets responding to this traceroute instance. We do this # by setting source port in UDP header to our process id. As ICMP will include # UDP header that triggers it in the payload, we will be able to compare the # UDP source port embedded in returned ICMP packet with our process id and # determine if the packet is of our interest. probe_udp.sport = self.src_port probe_udp.dport = self.dst_port # calculate the length of UDP data header_len = len(udp.assemble(probe_udp) + ip.assemble(probe_ip)) if self.packet_len <= header_len: raise TraceError, "packet length must be > %d" % (header_len) probe_udp.data = '\000' * (self.packet_len - header_len) probe_ip.data = udp.assemble(probe_udp) return ip.assemble(probe_ip, self.check_sum) def received(self, pkt, gateway): """ Upon received an incoming ICMP, determine if the packet is of our interest If it is, populate related fields, and return 1 otherwise return 0 """ ip_reply = ip.disassemble(pkt) if icmp.HDR_SIZE_IN_BYTES > len(ip_reply.data): return 0 #IP payload is not long enough to hold ICMP try: icmp_reply = icmp.disassemble(ip_reply.data) #ICMP is payload of IP except ValueError, msg: if DEBUG: stdout.write("Bad Packet received!") return 0 if DEBUG: stdout.write("recvfrom %s: ICMP_type: %d ICMP_code: %d" % (gateway, icmp_reply.get_type(), icmp_reply.get_code())) # 2 conditions interest us: # 1. ICMP_TIMEEXCEED, probe packet dropped by gateway in the middle, # which then send ICMP_TIMEEXCEED back to us # 2. ICMP_UNREACH, probe packet reach destination host, which (we assume) # is not listening on the port hence send ICMP_UNREACH back to us if (isinstance(icmp_reply, icmp.TimeExceeded) \ and icmp_reply.get_code() == icmp.ICMP_TIMXCEED_INTRANS) \ or isinstance(icmp_reply, icmp.Unreachable) : inner_ip = icmp_reply.get_embedded_ip() if inner_ip.src != self.src_addr or inner_ip.dst != self.dst_addr: return 0 if udp.HDR_SIZE_IN_BYTES > len(inner_ip.data): return 0 #Not enough data for UDP udp_in_icmp = udp.disassemble(inner_ip.data, 0) if udp_in_icmp.sport == self.src_port \ and udp_in_icmp.dport == self.dst_port: self.gateway = gateway self.timestamp_received = time.time() if icmp_reply.get_type() == icmp.ICMP_UNREACH: self.dst_reached = 1 return 1 if self.verbose: # In verbose mode, ICMP packets other than IME_EXCEEDED and UNREACHABLE are listed stdout.write("recvfrom %s: ICMP_type: %d ICMP_code: %d" % (gateway, icmp_reply.get_type(), icmp_reply.get_code())) return 0 class ICMPProbe(Probe): def probe_packet(self): """ Build the outgoing probe packet """ id = 0 seq = 0 probe_icmp = icmp.Echo(id, seq, '') # calculate the length of ICMP data header_len = len(icmp.assemble(probe_icmp)) if self.packet_len <= header_len: raise TraceError, "packet length must be > %d" % (header_len) data = '\000' * (self.packet_len - header_len) # I can't figure out how to determine how to distinguish the respones to different probe packet, return icmp.assemble(icmp.Echo(id, seq, data), self.check_sum) def received(self, pkt, gateway): """ Upon received an incoming ICMP, determine if the packet is of our interest If it is, populate related fields, and return 1 otherwise return 0 """ ip_reply = ip.disassemble(pkt) if icmp.HDR_SIZE_IN_BYTES > len(ip_reply.data): return 0 #IP payload is not long enough to hold ICMP icmp_reply = icmp.disassemble(ip_reply.data) #ICMP is payload of IP if DEBUG: stdout.write("recvfrom %s: ICMP_type: %d ICMP_code: %d" % (gateway, icmp_reply.get_type(), icmp_reply.get_code())) # 2 conditions interest us: # 1. ICMP_TIMEEXCEED, probe packet dropped by gateway in the middle, # which then send ICMP_TIMEEXCEED back to us # 2. ICMP_ECHOREPLY, probe packet reach destination host, if (icmp_reply.get_type() == icmp.ICMP_TIMXCEED \ and icmp_reply.get_code() == icmp.ICMP_TIMXCEED_INTRANS) \ or icmp_reply.get_type() == icmp.ICMP_ECHOREPLY: if ip.MIN_HDR_SIZE_IN_BYTES > len(icmp_reply.data): return 0 #ICMP payload is not long enough for inner IP inner_ip = ip.disassemble(icmp_reply.data) if inner_ip.src != self.src_addr or inner_ip.dst != self.dst_addr: return 0 self.gateway = gateway self.timestamp_received = time.time() if icmp_reply.get_type() == icmp.ICMP_ECHOREPLY: self.dst_reached = 1 return 1 if self.verbose: # In verbose mode, ICMP packets other than IME_EXCEEDED and UNREACHABLE are listed stdout.write("recvfrom %s: ICMP_type: %d ICMP_code: %d" % (gateway, icmp_reply.get_type(), icmp_reply.get_code())) return 0 class CommandLineReporter: """ Report tracing result on command line. This class is designed so that UI can be decoupled as much as possible, and minimize the effort to migrate this tool to GUI when needed. """ def __init__(self, resolve_host, style_newline): self.resolve_host = resolve_host self.style_newline = style_newline self.last_gateway = None def _print_host(self, host): """ print host name/address pair on console """ if self.resolve_host: try: name, aliases, ipaddrs = socket.gethostbyaddr(host) addr = ipaddrs[0] except socket.error: name = addr = host stdout.write("%s (%s)" % (name, addr)) else: stdout.write("%s" % (host)) def report_header(self, dst, max_ttl, pkt_len): """ report header """ stdout.write("traceroute to ") self._print_host(dst) stdout.write(", %d hops max, %d byte packets" % (max_ttl, pkt_len)) def report_hop(self, ttl): """ called before new hop is to be probed """ self.last_gateway = None stdout.write("\n %d " % (ttl)) def report_probe(self, probe): """ function to report this probe result """ # Sometimes (for example route is changed) different gateways respond to the same TTL probe. # If this happens, we print gateway again. We do this by saving the gateway received previously, # and compare it with the current one. If they are different, we print the gateway name/address # Also at the begining of each hop, last_gateway is set to None, which ensure gateway will be printed. if self.last_gateway != probe.gateway: self._print_host(probe.gateway) self.last_gateway = probe.gateway stdout.write(" %s " % (probe.get_round_trip_time())) if self.style_newline: stdout.write("\n") stdout.flush() def report_trail(self): stdout.write("\n") stdout.flush() def report_fatal_error(self, err_code, err_msg): stdout.write("traceroute: %s" % err_msg) sys.exit(err_code) class Tracer: """ The class to control the overall flow of tracing route. """ def __init__(self, host, params, reporter): self.params = params self.id = (os.getpid() & 0xffff) | 0x8000 self.reporter = reporter try: self.dst_addr = socket.gethostbyname(host) except: self.reporter.report_fatal_error(ERR_RESOLVE, "unknown host '%s'" % host) def _open_sockets(self): # might want to do setuid(getuid) when we're done with this self.receive_sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP) self.receive_sock.sendto("", ("localhost", 0)) # Python (2.5 so far) requires 'bind' first in order to receive ICMP packets if self.params.probe_with_icmp: self.probe_sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP) else: self.probe_sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW) #self.probe_sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, # self.packlen) self.probe_sock.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1) def _probe(self): """ return a UDPProbe or ICMPProbe instance according to if '-I' is specified """ if self.params.probe_with_icmp: probe = ICMPProbe() else: probe = UDPProbe() return probe def _waitfor_appropriate_reply(self, probe): """ Wait for the ICMP packets of our interest until time out. Packets that appear to be irrelevant will be siliently dropped (unless specified otherwise) """ BUFFER_SIZE = 4096 start = time.time() timeout = self.params.max_wait while 1: rd, wt, er = select.select([self.receive_sock], [], [], timeout) arrived = time.time() timeout = (start + self.params.max_wait) - time.time() if timeout < 0: # Timeout calculation needs revision for better accuracy return if rd: try: pkt, (who, port) = self.receive_sock.recvfrom(BUFFER_SIZE) except socket.error: continue if probe.received(pkt, who): return def _probe_packet_len(self): """ construct a fake packet and get the length """ probe = self._probe() probe.src_addr = "0.0.0.0" probe.dst_addr = "0.0.0.0" probe.src_port = 0 probe.dst_port = 0 probe.ttl = 0 probe.packet_len = self.params.packet_len return len(probe.probe_packet()) def trace(self): """ Entrance of tracing the route to host. This method will: 1. control the (nested) loop of probing using different ttl 2. create Probe object and use it to construct probing packet and parsing incoming ICMP 3. create reporter and report result 4. passing parameters to appropriate recepients """ FAKE_PORT = 0 MILLI_PER_SECOND = 1000.0 # Open sockets to send and receive packets self._open_sockets() self.reporter.report_header(self.dst_addr, self.params.max_ttl, self._probe_packet_len()) dst_reached = 0 dst_port = self.params.def_port # destination port for the first probe for ttl in range(self.params.first_ttl, self.params.max_ttl+1): if dst_reached: return self.reporter.report_hop(ttl) for i in range(self.params.num_probe): dst_port += 1 # Each probe dst_port is increased by 1, so that the ICMP packet # corresponding to this probe can be differentiated from others # construct a new Probe and set parameters probe = self._probe() probe.src_addr = self.params.src_addr probe.dst_addr = self.dst_addr probe.ttl = ttl probe.src_port = self.id # src_port is set to this pid so that the replying ICMP packets of # this process can be differentiated from other traceroute process # running at the same time probe.dst_port = dst_port probe.dont_frag = self.params.dont_frag probe.packet_len = self.params.packet_len pkt = probe.probe_packet() ret = self.probe_sock.sendto(pkt, (self.dst_addr, FAKE_PORT)) if DEBUG: stdout.write("\nsendto %s: %d bytes, ret = %d\n" % (self.dst_addr, len(pkt), ret)) probe.sent() self._waitfor_appropriate_reply(probe) dst_reached = probe.is_dst_reached() self.reporter.report_probe(probe) time.sleep(self.params.pause_msec * MILLI_PER_SECOND) self.reporter.report_trail() def main(): import sys params = TraceParameters() host = params.from_commandline_options(sys.argv[1:]) rptr = CommandLineReporter(params.resolve_host, params.style_newline) if params.print_help or len(host) != 1: rptr.report_fatal_error(ERR_USAGE, params.usage()) try: t = Tracer(host[0], params, rptr) t.trace() except TraceError, err_msg: rptr.report_fatal_error(ERR_TRACE, err_msg) if __name__ == "__main__": main() pyip-0.7/udp.py0000644024311100256300000000460610645253210013367 0ustar tijiangccusers# # pyip is a Python package offering assembling/disassembling of raw ip packet # including ip, udp, and icmp. Also it includes 2 utilities based on raw ip, # traceroute and ping. # # pyip is released under PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2, and is # a project inspired by 'ping' written by Jeremy Hylton. # # Author: Kenneth Jiang, kenneth.jiang@gmail.com # import inetutils import struct import string HDR_SIZE_IN_BYTES = 8 class Packet: def __init__(self, sport = 0, dport = 0, ulen = 8, sum = 0, data = ''): self.sport = sport self.dport = dport self.ulen = ulen self.sum = sum self.data = data def __repr__(self): begin = "%d len=%d " % (self.sport, self.dport, self.ulen) if self.ulen == 8: rep = begin + "\'\'>" elif self.ulen < 18: rep = begin + "%s>" % repr(self.data) else: rep = begin + "%s>" % repr(self.data[:10] + '...') return rep def __eq__(self, other): if not isinstance(other, Packet): return 0 return self.sport == other.sport and \ self.dport == other.dport and \ self.ulen == other.ulen and \ self.sum == other.sum and \ self.data == other.data def _assemble(self, cksum=1): self.ulen = 8 + len(self.data) begin = struct.pack('HHH', self.sport, self.dport, self.ulen) packet = begin + '\000\000' + self.data if cksum: self.sum = inetutils.cksum(packet) packet = begin + struct.pack('H', self.sum) + self.data self.__packet = inetutils.udph2net(packet) return self.__packet def _disassemble(self, raw_packet, cksum=1): packet = inetutils.net2updh(raw_packet) if cksum and packet[6:8] != '\000\000': our_cksum = inetutils.cksum(packet) if our_cksum != 0: raise ValueError, packet elts = map(lambda x:x & 0xffff, struct.unpack('HHHH', packet[:8])) [self.sport, self.dport, self.ulen, self.sum] = elts self.data = packet[8:] def assemble(packet, cksum=1): return packet._assemble(cksum) def disassemble(buffer, cksum=1): packet = Packet() packet._disassemble(buffer, cksum) return packet