1PKTT(3)                            pktt 2.7                            PKTT(3)
2
3
4

NAME

6       packet.pktt - Packet trace module
7

DESCRIPTION

9       The Packet trace module is a python module that takes a trace file cre‐
10       ated by tcpdump and unpacks the contents of each packet. You can decode
11       one  packet  at  a  time, or do a search for specific packets. The main
12       difference between these modules and other tools used to  decode  trace
13       files  is  that  you  can  use  this module to completely automate your
14       tests.
15
16       How does it work? It opens the trace file and reads  one  record  at  a
17       time keeping track where each record starts. This way, very large trace
18       files can be opened without having to wait for the  file  to  load  and
19       avoid loading the whole file into memory.
20
21       Packet layers supported:
22           - ETHERNET II (RFC 894)
23           - IP layer (supports IPv4 and IPv6)
24           - UDP layer
25           - TCP layer
26           - RPC layer
27           - NFS v4.0
28           - NFS v4.1 including pNFS file layouts
29           - NFS v4.2
30           - PORTMAP v2
31           - MOUNT v3
32           - NLM v4
33

CLASSES

35   class Header(baseobj.BaseObj)
36       Base class so objects will inherit the methods providing the string
37       representation of the object and a simple debug printing and logging
38       mechanism.
39
40       Usage:
41           from baseobj import BaseObj
42
43           # Named arguments
44           x = BaseObj(a=1, b=2)
45
46           # Dictionary argument
47           x = BaseObj({'a':1, 'b':2})
48
49           # Tuple arguments: first for keys and second for the values
50           x = BaseObj(['a', 'b'], [1, 2])
51
52           # All of the above will create an object having two attributes:
53           x.a = 1 and x.b = 2
54
55           # Add attribute name, this will be the only attribute to be displayed
56           x.set_attrlist("a")
57
58           # Add list of attribute names to be displayed in that order
59           x.set_attrlist(["a", "b"])
60
61           # Set attribute with ordered display rights
62           x.set_attr("a", 1)
63           # This is the same as
64           setattr(x, "a", 1) or x.a = 1
65           x.set_attrlist("a")
66
67           # Set attribute with switch duplicate
68           # The following creates an extra attribute "switch" with
69           # the same value as attribute "a":
70           #   x.a == x.switch
71           #   x.a is x.switch
72           x.set_attr("a", 1, switch=True)
73
74           # Make the current object flat by allowing all the attributes
75           # for the new attribute to be accessed directly by the current
76           # object so the following is True:
77           #   x.d == x.c.d
78           x.set_attr("c", BaseObj(d=11, e=22), switch=True)
79
80           # Set the comparison attribute so x == x.a is True
81           x.set_eqattr("a")
82
83           # Set verbose level of object's string representation
84           x.debug_repr(level)
85
86           # Set string format for verbose level 1
87           x.set_strfmt(1, "arg1:{0}")
88           # In the above example the first positional argument is "a"
89           # so the str(x) gives "arg1:1"
90
91           # Set attribute shared by all instances
92           # If a global or shared attribute is set on one instance,
93           # all other instances will have access to it:
94           #   y = BaseObj(d=2, e=3)
95           # then the following is true
96           #   x.g == y.g
97           #   x.g is y.g
98           x.set_global("g", 5)
99
100           # Set level mask to display all debug messages matching mask
101           x.debug_level(0xFF)
102
103           # Add a debug mapping for mask 0x100
104           x.debug_map(0x100, 'opts', "OPTS: ")
105
106           # Set global indentation to 4 spaces for dprint
107           x.dindent(4)
108
109           # Set global indentation to 4 spaces for displaying objects
110           x.sindent(4)
111
112           # Set global truncation to 64 for displaying string objects
113           x.strsize(64)
114
115           # Do not display timestamp for dprint messages
116           x.tstamp(enable=False)
117
118           # Change timestamp format to include the date
119           x.tstamp(fmt="{0:date:%Y-%m-%d %H:%M:%S.%q} ")
120
121           # Get timestamp if enabled, else return an empty string
122           out = x.timestamp()
123
124           # Open log file
125           x.open_log(logfile)
126
127           # Close log file
128           x.close_log()
129
130           # Write data to log file
131           x.write_log(data)
132
133           # Format the given arguments
134           out = x.format("{0:x} - {1}", 1, "hello")
135
136           # Format the object attributes set by set_attrlist()
137           out = x.format("{0:x} - {1}")
138
139           # Print debug message only if OPTS bitmap matches the current
140           # debug level mask
141           x.dprint("OPTS", "This is an OPTS debug message")
142
143
144       Methods defined here:
145       ---------------------
146
147       __init__(self, pktt)
148       Constructor
149
150       Initialize object's private data according to the arguments given.
151       Arguments can be given as positional, named arguments or a
152       combination of both.
153
154   class Pktt(baseobj.BaseObj)
155       Packet trace object
156
157       Usage:
158           from packet.pktt import Pktt
159
160           x = Pktt("/traces/tracefile.cap")
161
162           # Iterate over all packets found in the trace file
163           for pkt in x:
164               print pkt
165
166
167       Methods defined here:
168       ---------------------
169
170       __contains__(self, expr)
171       Implement membership test operator.
172       Return true if expr matches a packet in the trace file,
173       false otherwise.
174
175       The packet is also stored in the object attribute pkt.
176
177       Examples:
178           # Find the next READ request
179           if ("NFS.argop == 25" in x):
180               print x.pkt.nfs
181
182       See match() method for more information
183
184       __del__(self)
185       Destructor
186
187       Gracefully close the tcpdump trace file if it is opened.
188
189       __getitem__(self, index)
190       Get the packet from the trace file given by the index
191       or raise IndexError.
192
193       The packet is also stored in the object attribute pkt.
194
195       Examples:
196           pkt = x[index]
197
198       __init__(self, tfile, live=False, rpc_replies=True)
199       Constructor
200
201       Initialize object's private data, note that this will not check the
202       file for existence nor will open the file to verify if it is a valid
203       tcpdump file. The tcpdump trace file will be opened the first time a
204       packet is retrieved.
205
206
207              tracefile:
208                     Name of tcpdump trace file or a list of trace file names
209                     (little or big endian format)
210
211              live:  If set to True, methods will not return if encountered <EOF>,
212                     they will keep on trying until more data is available in the
213                     file. This is useful when running tcpdump in parallel,
214                     especially when tcpdump is run with the '-C' option, in which
215                     case when <EOF> is encountered the next trace file created by
216                     tcpdump will be opened and the object will be re-initialized,
217                     all private data referencing the previous file is lost.
218
219       __iter__(self)
220       Make this object iterable.
221
222       __next__(self)
223       Get the next packet from the trace file or raise StopIteration.
224
225       The packet is also stored in the object attribute pkt.
226
227       Examples:
228           # Iterate over all packets found in the trace file using
229           # the iterable properties of the object
230           for pkt in x:
231               print pkt
232
233           # Iterate over all packets found in the trace file using it
234           # as a method and using the object variable as the packet
235           # Must use the try statement to catch StopIteration exception
236           try:
237               while (x.next()):
238                   print x.pkt
239           except StopIteration:
240               pass
241
242           # Iterate over all packets found in the trace file using it
243           # as a method and using the return value as the packet
244           # Must use the try statement to catch StopIteration exception
245           while True:
246               try:
247                   print x.next()
248               except StopIteration:
249                   break
250
251       NOTE:
252           Supports only single active iteration
253
254       clear_xid_list(self)
255       Clear list of outstanding xids
256
257       close(self)
258       Gracefully close the tcpdump trace file and cleanup attributes.
259
260       get_index(self)
261       Get current packet index
262
263       match(self, expr, maxindex=None, rewind=True, reply=False)
264       Return the packet that matches the given expression, also the packet
265       index points to the next packet after the matched packet.
266       Returns None if packet is not found and the packet index points
267       to the packet at the beginning of the search.
268
269
270              expr:  String of expressions to be evaluated
271
272              maxindex:
273                     The match fails if packet index hits this limit
274
275              rewind:
276                     Rewind to index where matching started if match fails
277
278              reply: Match RPC replies of previously matched calls as well
279
280              Examples:
281                  # Find the packet with both the ACK and SYN TCP flags set to 1
282                  pkt = x.match("TCP.flags.ACK == 1 and TCP.flags.SYN == 1")
283
284                  # Find the next NFS EXCHANGE_ID request
285                  pkt = x.match("NFS.argop == 42")
286
287                  # Find the next NFS EXCHANGE_ID or CREATE_SESSION request
288                  pkt = x.match("NFS.argop in [42,43]")
289
290                  # Find the next NFS OPEN request or reply
291                  pkt = x.match("NFS.op == 18")
292
293                  # Find all packets coming from subnet 192.168.1.0/24 using
294                  # a regular expression
295                  while x.match(r"re.search('192.168.1.*', IP.src)"):
296                      print x.pkt.tcp
297
298                  # Find packet having a GETATTR asking for FATTR4_FS_LAYOUT_TYPES(bit 62)
299                  pkt_call = x.match("NFS.attr_request & 0x4000000000000000L != 0")
300                  if pkt_call:
301                      # Find GETATTR reply
302                      xid = pkt_call.rpc.xid
303                      # Find reply where the number 62 is in the array NFS.attributes
304                      pkt_reply = x.match("RPC.xid == %d and 62 in NFS.attributes" % xid)
305
306                  # Find the next WRITE request
307                  pkt = x.match("NFS.argop == 38")
308                  if pkt:
309                      print pkt.nfs
310
311                  # Same as above, but using membership test operator instead
312                  if ("NFS.argop == 38" in x):
313                      print x.pkt.nfs
314
315                  # Get a list of all OPEN and CLOSE packets then use buffered
316                  # matching to process each OPEN and its corresponding CLOSE
317                  # at a time including both requests and replies
318                  pktlist = []
319                  while x.match("NFS.op in [4,18]"):
320                      pktlist.append(x.pkt)
321                  # Enable buffered matching
322                  x.set_pktlist(pktlist)
323                  while x.match("NFS.argop == 18"): # Find OPEN request
324                      print x.pkt
325                      index = x.get_index()
326                      # Find OPEN reply
327                      x.match("RPC.xid == %d and NFS.resop == 18" % x.pkt.rpc.xid)
328                      print x.pkt
329                      # Find corresponding CLOSE request
330                      stid = x.escape(x.pkt.NFSop.stateid.other)
331                      x.match("NFS.argop == 4 and NFS.stateid == '%s'" % stid)
332                      print x.pkt
333                      # Find CLOSE reply
334                      x.match("RPC.xid == %d and NFS.resop == 4" % x.pkt.rpc.xid)
335                      print x.pkt
336                      # Rewind to right after the OPEN request
337                      x.rewind(index)
338                  # Disable buffered matching
339                  x.set_pktlist()
340
341              See also:
342                  match_ethernet(), match_ip(), match_tcp(), match_rpc(), match_nfs()
343
344       match_nfs(self, expr)
345       Match NFS values on current packet.
346
347       In NFSv4, there is a single compound procedure with multiple
348       operations, matching becomes a little bit tricky in order to make
349       the matching expression easy to use. The NFS object's name space
350       gets converted into a flat name space for the sole purpose of
351       matching. In other words, all operation objects in array are
352       treated as being part of the NFS object's top level attributes.
353
354       Consider the following NFS object:
355           nfsobj = COMPOUND4res(
356               status=NFS4_OK,
357               tag='NFSv4_tag',
358               array = [
359                   nfs_resop4(
360                       resop=OP_SEQUENCE,
361                       opsequence=SEQUENCE4res(
362                           status=NFS4_OK,
363                           resok=SEQUENCE4resok(
364                               sessionid='sessionid',
365                               sequenceid=29,
366                               slotid=0,
367                               highest_slotid=179,
368                               target_highest_slotid=179,
369                               status_flags=0,
370                           ),
371                       ),
372                   ),
373                   nfs_resop4(
374                       resop=OP_PUTFH,
375                       opputfh = PUTFH4res(
376                           status=NFS4_OK,
377                       ),
378                   ),
379                   ...
380               ]
381           ),
382
383       The result for operation PUTFH is the second in the list:
384           putfh = nfsobj.array[1]
385
386       From this putfh object the status operation can be accessed as:
387           status = putfh.opputfh.status
388
389       or simply as (this is how the NFS object works):
390           status = putfh.status
391
392       In this example, the following match expression 'NFS.status == 0'
393       could match the top level status of the compound (nfsobj.status)
394       or the putfh status (nfsobj.array[1].status)
395
396       The following match expression 'NFS.sequenceid == 25' will also
397       match this packet as well, even though the actual expression should
398       be 'nfsobj.array[0].opsequence.resok.sequenceid == 25' or
399       simply 'nfsobj.array[0].sequenceid == 25'.
400
401       This approach makes the match expressions simpler at the expense of
402       having some ambiguities on where the actual match occurred. If a
403       match is desired on a specific operation, a more qualified name can
404       be given. In the above example, in order to match the status of the
405       PUTFH operation the match expression 'NFS.opputfh.status == 0' can
406       be used. On the other hand, consider a compound having multiple
407       PUTFH results the above match expression will always match the first
408       occurrence of PUTFH where the status is 0. There is no way to tell
409       the match engine to match the second or Nth occurrence of an
410       operation.
411
412       match_pkt(self, expr)
413       Default wrapper function to evaluate a simple string expression.
414
415       rewind(self, index=0)
416       Rewind the trace file by setting the file pointer to the start of
417       the given packet index. Returns False if unable to rewind the file,
418       e.g., when the given index is greater than the maximum number
419       of packets processed so far.
420
421       seek(self, offset, whence=0, hard=False)
422       Position the read offset correctly
423       If new position is outside the current read buffer then clear the
424       buffer so a new chunk of data will be read from the file instead
425
426       set_pktlist(self, pktlist=None)
427       Set the current packet list for buffered matching in which the
428       match method will only use this list instead of getting the next
429       packet from the packet trace file.
430       This could be used when there is a lot of matching going back
431       and forth but only on a particular set of packets.
432       See the match() method for an example of buffered matching.
433
434       show_progress(self, done=False)
435       Display progress bar if enabled and if running on correct terminal
436
437       Static methods defined here:
438       ----------------------------
439
440       escape(data)
441       Escape special characters.
442
443       Examples:
444           # Call as an instance
445           escaped_data = x.escape(data)
446
447           # Call as a class
448           escaped_data = Pktt.escape(data)
449
450       ip_tcp_dst_expr(ipaddr, port=None)
451       Return a match expression to find a packet going to ipaddr:port.
452
453       Examples:
454           # Call as an instance
455           expr = x.ip_tcp_dst_expr('192.168.1.50', 2049)
456
457           # Call as a class
458           expr = Pktt.ip_tcp_dst_expr('192.168.1.50', 2049)
459
460           # Returns "IP.dst == '192.168.1.50' and TCP.dst_port == 2049"
461           # Expression ready for x.match()
462           pkt = x.match(expr)
463
464       ip_tcp_src_expr(ipaddr, port=None)
465       Return a match expression to find a packet coming from ipaddr:port.
466
467       Examples:
468           # Call as an instance
469           expr = x.ip_tcp_src_expr('192.168.1.50', 2049)
470
471           # Call as a class
472           expr = Pktt.ip_tcp_src_expr('192.168.1.50', 2049)
473
474           # Returns "IP.src == '192.168.1.50' and TCP.src_port == 2049"
475           # Expression ready for x.match()
476           pkt = x.match(expr)
477

FUNCTIONS

479       convert_attrs(tree)
480       Convert all valid layer AST Attributes to fully qualified names.
481       Also, return the name of the correct wrapper function to be used.
482
483       NOTE:
484         The tree argument is modified so when tree is unparsed, all layer
485         attributes are expanded correctly.
486
487       get_binop(op)
488       Return the string representation of the operator AST object
489
490       get_bool(op)
491       Return the string representation of the logical operator AST object
492
493       get_op(op)
494       Return the string representation of the logical operator AST object
495
496       get_precedence(op)
497       Return the precedence of operator AST object
498
499       get_unary(op)
500       Return the string representation of the unary operator AST object
501
502       unparse(tree)
503       Older Python releases do not define ast.unparse(). Create function
504       unparse with limited functionality but enough for the matching
505       language it is needed for match(). This function runs twice as fast
506       as ast.unparse(), so always use it regardless if it is defined or
507       not on the ast module.
508

SEE ALSO

510       baseobj(3),    formatstr(3),   packet.internet.ipv4(3),   packet.inter‐
511       net.ipv6(3),        packet.link.erf(3),        packet.link.ethernet(3),
512       packet.link.sllv1(3),        packet.link.sllv2(3),       packet.pkt(3),
513       packet.record(3), packet.transport.rdmainfo(3), packet.unpack(3)
514
515

BUGS

517       No known bugs.
518

AUTHOR

520       Jorge Mora (mora@netapp.com)
521
522
523
524NFStest 3.2                      21 March 2023                         PKTT(3)
Impressum