@@ -1278,35 +1278,48 @@ def _write_header(self, pkt):
1278
1278
self .f .flush ()
1279
1279
1280
1280
def write (self , pkt ):
1281
- """accepts either a single packet or a list of packets to be
1282
- written to the dumpfile
1281
+ """
1282
+ Writes a Packet or bytes to a pcap file.
1283
1283
1284
+ :param pkt: Packet(s) to write (one record for each Packet), or raw
1285
+ bytes to write (as one record).
1286
+ :type pkt: iterable[Packet], Packet or bytes
1284
1287
"""
1285
1288
if isinstance (pkt , bytes ):
1286
1289
if not self .header_present :
1287
1290
self ._write_header (pkt )
1288
1291
self ._write_packet (pkt )
1289
1292
else :
1290
1293
pkt = pkt .__iter__ ()
1291
- if not self .header_present :
1292
- try :
1293
- p = next (pkt )
1294
- except (StopIteration , RuntimeError ):
1295
- self ._write_header (None )
1296
- return
1297
- self ._write_header (p )
1298
- self ._write_packet (p )
1299
1294
for p in pkt :
1295
+ if not self .header_present :
1296
+ self ._write_header (p )
1300
1297
self ._write_packet (p )
1301
1298
1302
- def _write_packet (self , packet , sec = None , usec = None , caplen = None , wirelen = None ): # noqa: E501
1303
- """writes a single packet to the pcap file
1299
+ def _write_packet (self , packet , sec = None , usec = None , caplen = None ,
1300
+ wirelen = None ):
1301
+ """
1302
+ Writes a single packet to the pcap file.
1303
+
1304
+ :param packet: bytes for a single packet
1305
+ :type packet: bytes
1306
+ :param sec: time the packet was captured, in seconds since epoch. If
1307
+ not supplied, defaults to now.
1308
+ :type sec: int or long
1309
+ :param usec: If ``nano=True``, then number of nanoseconds after the
1310
+ second that the packet was captured. If ``nano=False``,
1311
+ then the number of microseconds after the second the
1312
+ packet was captured
1313
+ :type usec: int or long
1314
+ :param caplen: The length of the packet in the capture file. If not
1315
+ specified, uses ``len(packet)``.
1316
+ :type caplen: int
1317
+ :param wirelen: The length of the packet on the wire. If not
1318
+ specified, uses ``caplen``.
1319
+ :type wirelen: int
1320
+ :returns: None
1321
+ :rtype: None
1304
1322
"""
1305
- if isinstance (packet , tuple ):
1306
- for pkt in packet :
1307
- self ._write_packet (pkt , sec = sec , usec = usec , caplen = caplen ,
1308
- wirelen = wirelen )
1309
- return
1310
1323
if caplen is None :
1311
1324
caplen = len (packet )
1312
1325
if wirelen is None :
@@ -1316,9 +1329,13 @@ def _write_packet(self, packet, sec=None, usec=None, caplen=None, wirelen=None):
1316
1329
it = int (t )
1317
1330
if sec is None :
1318
1331
sec = it
1319
- if usec is None :
1320
- usec = int (round ((t - it ) * (1000000000 if self .nano else 1000000 ))) # noqa: E501
1321
- self .f .write (struct .pack (self .endian + "IIII" , sec , usec , caplen , wirelen )) # noqa: E501
1332
+ usec = int (round ((t - it ) *
1333
+ (1000000000 if self .nano else 1000000 )))
1334
+ elif usec is None :
1335
+ usec = 0
1336
+
1337
+ self .f .write (struct .pack (self .endian + "IIII" ,
1338
+ sec , usec , caplen , wirelen ))
1322
1339
self .f .write (packet )
1323
1340
if self .sync :
1324
1341
self .f .flush ()
@@ -1327,6 +1344,8 @@ def flush(self):
1327
1344
return self .f .flush ()
1328
1345
1329
1346
def close (self ):
1347
+ if not self .header_present :
1348
+ self ._write_header (None )
1330
1349
return self .f .close ()
1331
1350
1332
1351
def __enter__ (self ):
@@ -1341,8 +1360,6 @@ class PcapWriter(RawPcapWriter):
1341
1360
"""A stream PCAP writer with more control than wrpcap()"""
1342
1361
1343
1362
def _write_header (self , pkt ):
1344
- if isinstance (pkt , tuple ) and pkt :
1345
- pkt = pkt [0 ]
1346
1363
if self .linktype is None :
1347
1364
try :
1348
1365
self .linktype = conf .l2types [pkt .__class__ ]
@@ -1351,17 +1368,51 @@ def _write_header(self, pkt):
1351
1368
self .linktype = DLT_EN10MB
1352
1369
RawPcapWriter ._write_header (self , pkt )
1353
1370
1354
- def _write_packet (self , packet ):
1355
- if isinstance (packet , tuple ):
1356
- for pkt in packet :
1357
- self ._write_packet (pkt )
1358
- return
1359
- sec = int (packet .time )
1360
- usec = int (round ((packet .time - sec ) * (1000000000 if self .nano else 1000000 ))) # noqa: E501
1371
+ def _write_packet (self , packet , sec = None , usec = None , caplen = None ,
1372
+ wirelen = None ):
1373
+ """
1374
+ Writes a single packet to the pcap file.
1375
+
1376
+ :param packet: Packet, or bytes for a single packet
1377
+ :type packet: Packet or bytes
1378
+ :param sec: time the packet was captured, in seconds since epoch. If
1379
+ not supplied, defaults to now.
1380
+ :type sec: int or long
1381
+ :param usec: If ``nano=True``, then number of nanoseconds after the
1382
+ second that the packet was captured. If ``nano=False``,
1383
+ then the number of microseconds after the second the
1384
+ packet was captured. If ``sec`` is not specified,
1385
+ this value is ignored.
1386
+ :type usec: int or long
1387
+ :param caplen: The length of the packet in the capture file. If not
1388
+ specified, uses ``len(raw(packet))``.
1389
+ :type caplen: int
1390
+ :param wirelen: The length of the packet on the wire. If not
1391
+ specified, tries ``packet.wirelen``, otherwise uses
1392
+ ``caplen``.
1393
+ :type wirelen: int
1394
+ :returns: None
1395
+ :rtype: None
1396
+ """
1397
+ if hasattr (packet , "time" ):
1398
+ if sec is None :
1399
+ sec = int (packet .time )
1400
+ usec = int (round ((packet .time - sec ) *
1401
+ (1000000000 if self .nano else 1000000 )))
1402
+ if usec is None :
1403
+ usec = 0
1404
+
1361
1405
rawpkt = raw (packet )
1362
- caplen = len (rawpkt )
1363
- RawPcapWriter ._write_packet (self , rawpkt , sec = sec , usec = usec , caplen = caplen , # noqa: E501
1364
- wirelen = packet .wirelen or caplen )
1406
+ caplen = len (rawpkt ) if caplen is None else caplen
1407
+
1408
+ if wirelen is None :
1409
+ if hasattr (packet , "wirelen" ):
1410
+ wirelen = packet .wirelen
1411
+ if wirelen is None :
1412
+ wirelen = caplen
1413
+
1414
+ RawPcapWriter ._write_packet (
1415
+ self , rawpkt , sec = sec , usec = usec , caplen = caplen , wirelen = wirelen )
1365
1416
1366
1417
1367
1418
@conf .commands .register
@@ -1390,21 +1441,35 @@ def import_hexcap():
1390
1441
1391
1442
1392
1443
@conf .commands .register
1393
- def wireshark (pktlist ):
1394
- """Run wireshark on a list of packets"""
1395
- tcpdump (pktlist , prog = conf .prog .wireshark )
1444
+ def wireshark (pktlist , wait = False , ** kwargs ):
1445
+ """
1446
+ Runs Wireshark on a list of packets.
1447
+
1448
+ See :func:`tcpdump` for more parameter description.
1449
+
1450
+ Note: this defaults to wait=False, to run Wireshark in the background.
1451
+ """
1452
+ return tcpdump (pktlist , prog = conf .prog .wireshark , wait = wait , ** kwargs )
1396
1453
1397
1454
1398
1455
@conf .commands .register
1399
- def tdecode (pktlist ):
1400
- """Run tshark -V on a list of packets"""
1401
- tcpdump (pktlist , prog = conf .prog .tshark , args = ["-V" ])
1456
+ def tdecode (pktlist , args = None , ** kwargs ):
1457
+ """
1458
+ Run tshark on a list of packets.
1459
+
1460
+ :param args: If not specified, defaults to ``tshark -V``.
1461
+
1462
+ See :func:`tcpdump` for more parameters.
1463
+ """
1464
+ if args is None :
1465
+ args = ["-V" ]
1466
+ return tcpdump (pktlist , prog = conf .prog .tshark , args = args , ** kwargs )
1402
1467
1403
1468
1404
1469
@conf .commands .register
1405
1470
def tcpdump (pktlist , dump = False , getfd = False , args = None ,
1406
1471
prog = None , getproc = False , quiet = False , use_tempfile = None ,
1407
- read_stdin_opts = None ):
1472
+ read_stdin_opts = None , linktype = None , wait = True ):
1408
1473
"""Run tcpdump or tshark on a list of packets.
1409
1474
1410
1475
When using ``tcpdump`` on OSX (``prog == conf.prog.tcpdump``), this uses a
@@ -1444,6 +1509,13 @@ def tcpdump(pktlist, dump=False, getfd=False, args=None,
1444
1509
``tcpdump`` on OSX.
1445
1510
read_stdin_opts: When set, a list of arguments needed to capture from stdin.
1446
1511
Otherwise, attempts to guess.
1512
+ linktype: If a Packet (or list) is passed in the ``pktlist`` argument,
1513
+ set the ``linktype`` parameter on ``wrpcap``. If ``pktlist`` is a
1514
+ path to a pcap file, then this option will have no effect.
1515
+ wait: If True (default), waits for the process to terminate before returning
1516
+ to Scapy. If False, the process will be detached to the background. If
1517
+ dump, getproc or getfd is True, these have the same effect as
1518
+ ``wait=False``.
1447
1519
1448
1520
Examples:
1449
1521
@@ -1485,9 +1557,16 @@ def tcpdump(pktlist, dump=False, getfd=False, args=None,
1485
1557
elif isinstance (prog , six .string_types ):
1486
1558
_prog_name = "{}()" .format (prog )
1487
1559
prog = [prog ]
1560
+ else :
1561
+ raise ValueError ("prog must be a string" )
1488
1562
1489
1563
# Build Popen arguments
1490
- args = args if args is not None else []
1564
+ if args is None :
1565
+ args = []
1566
+ else :
1567
+ # Make a copy of args
1568
+ args = list (args )
1569
+
1491
1570
stdout = subprocess .PIPE if dump or getfd else None
1492
1571
stderr = open (os .devnull ) if quiet else None
1493
1572
@@ -1502,6 +1581,9 @@ def tcpdump(pktlist, dump=False, getfd=False, args=None,
1502
1581
read_stdin_opts = ["-ki" , "-" ]
1503
1582
else :
1504
1583
read_stdin_opts = ["-r" , "-" ]
1584
+ else :
1585
+ # Make a copy of read_stdin_opts
1586
+ read_stdin_opts = list (read_stdin_opts )
1505
1587
1506
1588
if pktlist is None :
1507
1589
# sniff
@@ -1524,7 +1606,7 @@ def tcpdump(pktlist, dump=False, getfd=False, args=None,
1524
1606
try :
1525
1607
tmpfile .writelines (iter (lambda : pktlist .read (1048576 ), b"" ))
1526
1608
except AttributeError :
1527
- wrpcap (tmpfile , pktlist )
1609
+ wrpcap (tmpfile , pktlist , linktype = linktype )
1528
1610
else :
1529
1611
tmpfile .close ()
1530
1612
with ContextManagerSubprocess (_prog_name , prog [0 ]):
@@ -1545,7 +1627,7 @@ def tcpdump(pktlist, dump=False, getfd=False, args=None,
1545
1627
try :
1546
1628
proc .stdin .writelines (iter (lambda : pktlist .read (1048576 ), b"" ))
1547
1629
except AttributeError :
1548
- wrpcap (proc .stdin , pktlist )
1630
+ wrpcap (proc .stdin , pktlist , linktype = linktype )
1549
1631
except UnboundLocalError :
1550
1632
raise IOError ("%s died unexpectedly !" % prog )
1551
1633
else :
@@ -1556,7 +1638,8 @@ def tcpdump(pktlist, dump=False, getfd=False, args=None,
1556
1638
return proc
1557
1639
if getfd :
1558
1640
return proc .stdout
1559
- proc .wait ()
1641
+ if wait :
1642
+ proc .wait ()
1560
1643
1561
1644
1562
1645
@conf .commands .register
0 commit comments