packet.pktt man page
packet.pktt — Packet trace module
The Packet trace module is a python module that takes a trace file created by tcpdump and unpacks the contents of each packet. You can decode one packet at a time, or do a search for specific packets. The main difference between these modules and other tools used to decode trace files is that you can use this module to completely automate your tests.
How does it work? It opens the trace file and reads one record at a time keeping track where each record starts. This way, very large trace files can be opened without having to wait for the file to load and avoid loading the whole file into memory.
Packet layers supported:
- ETHERNET II (RFC 894)
- IP layer (supports IPv4 and IPv6)
- UDP layer
- TCP layer
- RPC layer
- NFS v4.0
- NFS v4.1 including pNFS file layouts
- NFS v4.2
- PORTMAP v2
- MOUNT v3
- NLM v4
Methods defined here: --------------------- __init__(self, pktt)
class Pktt(baseobj.BaseObj, packet.unpack.Unpack)
Packet trace object Usage: from packet.pktt import Pktt x = Pktt("/traces/tracefile.cap") # Iterate over all packets found in the trace file for pkt in x: print pkt Methods defined here: --------------------- __contains__(self, expr) Implement membership test operator. Return true if expr matches a packet in the trace file, false otherwise. The packet is also stored in the object attribute pkt. Examples: # Find the next READ request if ("NFS.argop == 25" in x): print x.pkt.nfs See match() method for more information __del__(self) Destructor Gracefully close the tcpdump trace file if it is opened. __getitem__(self, index) Get the packet from the trace file given by the index or raise IndexError. The packet is also stored in the object attribute pkt. Examples: pkt = x[index] __init__(self, tfile, live=False, state=True) Constructor Initialize object's private data, note that this will not check the file for existence nor will open the file to verify if it is a valid tcpdump file. The tcpdump trace file will be opened the first time a packet is retrieved.
tracefile: Name of tcpdump trace file or a list of trace file names (little or big endian format) live: If set to True, methods will not return if encountered <EOF>, they will keep on trying until more data is available in the file. This is useful when running tcpdump in parallel, especially when tcpdump is run with the '-C' option, in which case when <EOF> is encountered the next trace file created by tcpdump will be opened and the object will be re-initialized, all private data referencing the previous file is lost.__iter__(self) Make this object iterable. clear_xid_list(self) Clear list of outstanding xids get_index(self) Get current packet index match(self, expr, maxindex=None, rewind=True, reply=False) Return the packet that matches the given expression, also the packet index points to the next packet after the matched packet. Returns None if packet is not found and the packet index points to the packet at the beginning of the search.
expr: String of expressions to be evaluated maxindex: The match fails if packet index hits this limit rewind: Rewind to index where matching started if match fails reply: Match RPC replies of previously matched calls as wellExamples: # Find the packet with both the ACK and SYN TCP flags set to 1 pkt = x.match("TCP.flags.ACK == 1 and TCP.flags.SYN == 1") # Find the next NFS EXCHANGE_ID request pkt = x.match("NFS.argop == 42") # Find the next NFS EXCHANGE_ID or CREATE_SESSION request pkt = x.match("NFS.argop in [42,43]") # Find the next NFS OPEN request or reply pkt = x.match("NFS.op == 18") # Find all packets coming from subnet 192.168.1.0/24 using # a regular expression while x.match(r"IP.src == re('192.168.1.*')"): print x.pkt.tcp # Find packet having a GETATTR asking for FATTR4_FS_LAYOUT_TYPES(bit 62) pkt_call = x.match("NFS.attr_request & 0x4000000000000000L != 0") if pkt_call: # Find GETATTR reply xid = pkt_call.rpc.xid # Find reply where the number 62 is in the array NFS.attributes pkt_reply = x.match("RPC.xid == %d and 62 in NFS.attributes" % xid) # Find the next WRITE request pkt = x.match("NFS.argop == 38") if pkt: print pkt.nfs # Same as above, but using membership test operator instead if ("NFS.argop == 38" in x): print x.pkt.nfs # Get a list of all OPEN and CLOSE packets then use buffered # matching to process each OPEN and its corresponding CLOSE # at a time including both requests and replies pktlist =  while x.match("NFS.op in [4,18]"): pktlist.append(x.pkt) # Enable buffered matching x.set_pktlist(pktlist) while x.match("NFS.argop == 18"): # Find OPEN request print x.pkt index = x.get_index() # Find OPEN reply x.match("RPC.xid == %d and NFS.resop == 18" % x.pkt.rpc.xid) print x.pkt # Find corresponding CLOSE request stid = x.escape(x.pkt.NFSop.stateid.other) x.match("NFS.argop == 4 and NFS.stateid == '%s'" % stid) print x.pkt # Find CLOSE reply x.match("RPC.xid == %d and NFS.resop == 4" % x.pkt.rpc.xid) print x.pkt # Rewind to right after the OPEN request x.rewind(index) # Disable buffered matching x.set_pktlist() See also: match_ethernet(), match_ip(), match_tcp(), match_rpc(), match_nfs()match_nfs(self, uargs) Match NFS values on current packet. In NFSv4, there is a single compound procedure with multiple operations, matching becomes a little bit tricky in order to make the matching expression easy to use. The NFS object's name space gets converted into a flat name space for the sole purpose of matching. In other words, all operation objects in array are treated as being part of the NFS object's top level attributes. Consider the following NFS object: nfsobj = COMPOUND4res( status=NFS4_OK, tag='NFSv4_tag', array = [ nfs_resop4( resop=OP_SEQUENCE, opsequence=SEQUENCE4res( status=NFS4_OK, resok=SEQUENCE4resok( sessionid='sessionid', sequenceid=29, slotid=0, highest_slotid=179, target_highest_slotid=179, status_flags=0, ), ), ), nfs_resop4( resop=OP_PUTFH, opputfh = PUTFH4res( status=NFS4_OK, ), ), ... ] ), The result for operation PUTFH is the second in the list: putfh = nfsobj.array From this putfh object the status operation can be accessed as: status = putfh.opputfh.status or simply as (this is how the NFS object works): status = putfh.status In this example, the following match expression 'NFS.status == 0' could match the top level status of the compound (nfsobj.status) or the putfh status (nfsobj.array.status) The following match expression 'NFS.sequenceid == 25' will also match this packet as well, even though the actual expression should be 'nfsobj.array.opsequence.resok.sequenceid == 25' or simply 'nfsobj.array.sequenceid == 25'. This approach makes the match expressions simpler at the expense of having some ambiguities on where the actual match occurred. If a match is desired on a specific operation, a more qualified name can be given. In the above example, in order to match the status of the PUTFH operation the match expression 'NFS.opputfh.status == 0' can be used. On the other hand, consider a compound having multiple PUTFH results the above match expression will always match the first occurrence of PUTFH where the status is 0. There is no way to tell the match engine to match the second or Nth occurrence of an operation. next(self) Get the next packet from the trace file or raise StopIteration. The packet is also stored in the object attribute pkt. Examples: # Iterate over all packets found in the trace file using # the iterable properties of the object for pkt in x: print pkt # Iterate over all packets found in the trace file using it # as a method and using the object variable as the packet # Must use the try statement to catch StopIteration exception try: while (x.next()): print x.pkt except StopIteration: pass # Iterate over all packets found in the trace file using it # as a method and using the return value as the packet # Must use the try statement to catch StopIteration exception while True: try: print x.next() except StopIteration: break NOTE: Supports only single active iteration rewind(self, index=0) Rewind the trace file by setting the file pointer to the start of the given packet index. Returns False if unable to rewind the file, e.g., when the given index is greater than the maximum number of packets processed so far. seek(self, offset, whence=0, hard=False) Position the read offset correctly If new position is outside the current read buffer then clear the buffer so a new chunk of data will be read from the file instead set_pktlist(self, pktlist=None) Set the current packet list for buffered matching in which the match method will only use this list instead of getting the next packet from the packet trace file. This could be used when there is a lot of matching going back and forth but only on a particular set of packets. See the match() method for an example of buffered matching. show_progress(self, done=False) Display progress bar if enabled and if running on correct terminal Static methods defined here: ---------------------------- escape(data) Escape special characters. Examples: # Call as an instance escaped_data = x.escape(data) # Call as a class escaped_data = Pktt.escape(data) ip_tcp_dst_expr(ipaddr, port) Return a match expression to find a packet going to ipaddr:port. Examples: # Call as an instance expr = x.ip_tcp_dst_expr('192.168.1.50', 2049) # Call as a class expr = Pktt.ip_tcp_dst_expr('192.168.1.50', 2049) # Returns "IP.dst == '192.168.1.50' and TCP.dst_port == 2049" # Expression ready for x.match() pkt = x.match(expr) ip_tcp_src_expr(ipaddr, port) Return a match expression to find a packet coming from ipaddr:port. Examples: # Call as an instance expr = x.ip_tcp_src_expr('192.168.1.50', 2049) # Call as a class expr = Pktt.ip_tcp_src_expr('192.168.1.50', 2049) # Returns "IP.src == '192.168.1.50' and TCP.src_port == 2049" # Expression ready for x.match() pkt = x.match(expr)
baseobj(3), formatstr(3), packet.link.ethernet(3), packet.pkt(3), packet.record(3), packet.unpack(3)
No known bugs.
Jorge Mora (email@example.com)
nfstest_file(1), nfstest.host(3), nfstest_pkt(1), nfstest_xid(1).