From f77aedd6c68fc7a0914ccfd3593dec0144378c41 Mon Sep 17 00:00:00 2001 From: ZackAlfakir Date: Tue, 24 Jul 2018 10:45:29 -0400 Subject: [PATCH 1/8] Add use_json to LiveRingCapture --- src/pyshark/capture/live_ring_capture.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pyshark/capture/live_ring_capture.py b/src/pyshark/capture/live_ring_capture.py index 711e3fd4..97d55963 100644 --- a/src/pyshark/capture/live_ring_capture.py +++ b/src/pyshark/capture/live_ring_capture.py @@ -8,7 +8,7 @@ class LiveRingCapture(LiveCapture): def __init__(self, ring_file_size=1024, num_ring_files=1, ring_file_name='/tmp/pyshark.pcap', interface=None, bpf_filter=None, display_filter=None, only_summaries=False, decryption_key=None, encryption_type='wpa-pwk', decode_as=None, disable_protocol=None, - tshark_path=None, override_prefs=None, include_raw=False): + tshark_path=None, override_prefs=None, include_raw=False, use_json=False): """ Creates a new live capturer on a given interface. Does not start the actual capture itself. :param ring_file_size: Size of the ring file in kB, default is 1024 @@ -31,7 +31,7 @@ def __init__(self, ring_file_size=1024, num_ring_files=1, ring_file_name='/tmp/p super(LiveRingCapture, self).__init__(interface, bpf_filter=bpf_filter, display_filter=display_filter, only_summaries=only_summaries, decryption_key=decryption_key, encryption_type=encryption_type, tshark_path=tshark_path, decode_as=decode_as, disable_protocol=disable_protocol, - override_prefs=override_prefs, include_raw=include_raw) + override_prefs=override_prefs, include_raw=include_raw, use_json=use_json) self.ring_file_size = ring_file_size self.num_ring_files = num_ring_files From 2e847694963858ec1c3fcebdab41968db2f066d2 Mon Sep 17 00:00:00 2001 From: ZackAlfakir Date: Tue, 24 Jul 2018 10:45:58 -0400 Subject: [PATCH 2/8] Updated PipeCapture to work correctly --- src/pyshark/capture/pipe_capture.py | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/pyshark/capture/pipe_capture.py b/src/pyshark/capture/pipe_capture.py index 3ef93fe7..8b94aafa 100644 --- a/src/pyshark/capture/pipe_capture.py +++ b/src/pyshark/capture/pipe_capture.py @@ -1,10 +1,7 @@ -import trollius as asyncio -from trollius import From, Return +from pyshark.capture.live_capture import LiveCapture -from pyshark.capture.capture import Capture - -class PipeCapture(Capture): +class PipeCapture(LiveCapture): def __init__(self, pipe, display_filter=None, only_summaries=False, decryption_key=None, encryption_type='wpa-pwk', decode_as=None, disable_protocol=None, tshark_path=None, override_prefs=None, use_json=False, include_raw=False): @@ -25,7 +22,7 @@ def __init__(self, pipe, display_filter=None, only_summaries=False, :param disable_protocol: Tells tshark to remove a dissector for a specifc protocol. """ - super(PipeCapture, self).__init__(display_filter=display_filter, + super(PipeCapture, self).__init__(interface=pipe, display_filter=display_filter, only_summaries=only_summaries, decryption_key=decryption_key, encryption_type=encryption_type, @@ -39,15 +36,8 @@ def get_parameters(self, packet_count=None): Returns the special tshark parameters to be used according to the configuration of this class. """ params = super(PipeCapture, self).get_parameters(packet_count=packet_count) - params += ['-r', '-'] return params - @asyncio.coroutine - def _get_tshark_process(self, packet_count=None): - proc = yield From(super(PipeCapture, self)._get_tshark_process(packet_count=packet_count, - stdin=self._pipe)) - raise Return(proc) - def close(self): # Close pipe self._pipe.close() From 746137563678453f3645a08e24ae0f069297715a Mon Sep 17 00:00:00 2001 From: ZackAlfakir Date: Tue, 24 Jul 2018 12:04:58 -0400 Subject: [PATCH 3/8] Added Pipe Ring Capture --- src/pyshark/__init__.py | 2 + src/pyshark/capture/pipe_ring_capture.py | 80 ++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 src/pyshark/capture/pipe_ring_capture.py diff --git a/src/pyshark/__init__.py b/src/pyshark/__init__.py index a4fbb734..b6f6b37e 100644 --- a/src/pyshark/__init__.py +++ b/src/pyshark/__init__.py @@ -14,3 +14,5 @@ class UnsupportedVersionException(Exception): from pyshark.capture.file_capture import FileCapture from pyshark.capture.remote_capture import RemoteCapture from pyshark.capture.inmem_capture import InMemCapture +from pyshark.capture.pipe_capture import PipeCapture +from pyshark.capture.pipe_ring_capture import PipeRingCapture diff --git a/src/pyshark/capture/pipe_ring_capture.py b/src/pyshark/capture/pipe_ring_capture.py new file mode 100644 index 00000000..f5003104 --- /dev/null +++ b/src/pyshark/capture/pipe_ring_capture.py @@ -0,0 +1,80 @@ +from pyshark.capture.pipe_capture import PipeCapture +from pyshark.capture.capture import TSharkCrashException, TSharkVersionException +from pyshark.tshark.tshark import tshark_supports_json +import asyncio +import subprocess +import tempfile + + +class PipeRingCapture(PipeCapture): + """ + Represents a live ringbuffer capture on a network interface. + """ + + def __init__(self, pipe, ring_file_size=1024, num_ring_files=2, ring_file_name=None, + display_filter=None, only_summaries=False, decryption_key=None, + encryption_type='wpa-pwk', decode_as=None, disable_protocol=None, + tshark_path=None, override_prefs=None, include_raw=False, use_json=False): + """ + Creates a new live capturer on a given interface. Does not start the actual capture itself. + :param ring_file_size: Size of the ring file in kB, default is 1024 + :param num_ring_files: Number of ring files to keep, default is 1 + :param ring_file_name: Name of the ring file, default is /tmp/pyshark.pcap + :param interface: Name of the interface to sniff on or a list of names (str). If not given, runs on all interfaces. + :param bpf_filter: BPF filter to use on packets. + :param display_filter: Display (wireshark) filter to use. + :param only_summaries: Only produce packet summaries, much faster but includes very little information + :param decryption_key: Optional key used to encrypt and decrypt captured traffic. + :param encryption_type: Standard of encryption used in captured traffic (must be either 'WEP', 'WPA-PWD', or + 'WPA-PWK'. Defaults to WPA-PWK). + :param decode_as: A dictionary of {decode_criterion_string: decode_as_protocol} that are used to tell tshark + to decode protocols in situations it wouldn't usually, for instance {'tcp.port==8888': 'http'} would make + it attempt to decode any port 8888 traffic as HTTP. See tshark documentation for details. + :param tshark_path: Path of the tshark binary + :param override_prefs: A dictionary of tshark preferences to override, {PREFERENCE_NAME: PREFERENCE_VALUE, ...}. + :param disable_protocol: Tells tshark to remove a dissector for a specifc protocol. + """ + super(PipeRingCapture, self).__init__(pipe, display_filter=display_filter, only_summaries=only_summaries, + decryption_key=decryption_key, encryption_type=encryption_type, + tshark_path=tshark_path, decode_as=decode_as, disable_protocol=disable_protocol, + override_prefs=override_prefs, include_raw=include_raw, use_json=use_json) + + self.ring_file_size = ring_file_size + self.num_ring_files = num_ring_files + if ring_file_name is None: + self.ring_file_name = tempfile.mktemp(suffix=".pcap", prefix="pyshark_") + else: + self.ring_file_name = ring_file_name + + def get_parameters(self, packet_count=None): + """ + Returns the special tshark parameters to be used according to the configuration of this class. + """ + params = super(PipeRingCapture, self).get_parameters()[:-2] + params.extend(['-i', self._pipe]) + params += ['-b', 'filesize:' + str(self.ring_file_size), '-b', 'files:' + str(self.num_ring_files), '-w', + self.ring_file_name, '-P'] + return params + + async def _get_tshark_process(self, packet_count=None, stdin=None): + """ + Returns a new tshark process with previously-set parameters. + """ + if self.use_json: + output_type = 'json' + if not tshark_supports_json(self.tshark_path): + raise TSharkVersionException("JSON only supported on Wireshark >= 2.2.0") + else: + output_type = 'psml' if self._only_summaries else 'pdml' + parameters = [self._get_tshark_path(), '-l', '-n', '-T', output_type] + \ + self.get_parameters(packet_count=packet_count) + + self._log.debug('Creating TShark subprocess with parameters: ' + ' '.join(parameters)) + + tshark_process = await asyncio.create_subprocess_exec(*parameters, + stdout=subprocess.PIPE, + stderr=self._stderr_output(), + stdin=stdin) + self._created_new_process(parameters, tshark_process) + return tshark_process + From 25493728951617e78391d22110c8881a9f70a2c5 Mon Sep 17 00:00:00 2001 From: ZackAlfakir Date: Wed, 25 Jul 2018 16:39:45 -0400 Subject: [PATCH 4/8] Added exception to disallow display filters --- src/pyshark/capture/pipe_ring_capture.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/pyshark/capture/pipe_ring_capture.py b/src/pyshark/capture/pipe_ring_capture.py index f5003104..2f75d71a 100644 --- a/src/pyshark/capture/pipe_ring_capture.py +++ b/src/pyshark/capture/pipe_ring_capture.py @@ -6,6 +6,10 @@ import tempfile +class DisplayFilterNotAllowedException(Exception): + """Display Filters are not allowed in PipeRingCapture.""" + + class PipeRingCapture(PipeCapture): """ Represents a live ringbuffer capture on a network interface. @@ -34,6 +38,9 @@ def __init__(self, pipe, ring_file_size=1024, num_ring_files=2, ring_file_name=N :param override_prefs: A dictionary of tshark preferences to override, {PREFERENCE_NAME: PREFERENCE_VALUE, ...}. :param disable_protocol: Tells tshark to remove a dissector for a specifc protocol. """ + if display_filter is not None: + raise DisplayFilterNotAllowedException("Display Filters are not allowed in PipeRingCapture.") + super(PipeRingCapture, self).__init__(pipe, display_filter=display_filter, only_summaries=only_summaries, decryption_key=decryption_key, encryption_type=encryption_type, tshark_path=tshark_path, decode_as=decode_as, disable_protocol=disable_protocol, From 8c11c84201ff16653d34f6addb539edddb244f86 Mon Sep 17 00:00:00 2001 From: ZackAlfakir Date: Thu, 26 Jul 2018 15:28:43 -0400 Subject: [PATCH 5/8] Inherit from capture --- src/pyshark/capture/pipe_capture.py | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/pyshark/capture/pipe_capture.py b/src/pyshark/capture/pipe_capture.py index 8b94aafa..e61fc678 100644 --- a/src/pyshark/capture/pipe_capture.py +++ b/src/pyshark/capture/pipe_capture.py @@ -1,7 +1,7 @@ -from pyshark.capture.live_capture import LiveCapture +from pyshark.capture.capture import Capture -class PipeCapture(LiveCapture): +class PipeCapture(Capture): def __init__(self, pipe, display_filter=None, only_summaries=False, decryption_key=None, encryption_type='wpa-pwk', decode_as=None, disable_protocol=None, tshark_path=None, override_prefs=None, use_json=False, include_raw=False): @@ -22,7 +22,7 @@ def __init__(self, pipe, display_filter=None, only_summaries=False, :param disable_protocol: Tells tshark to remove a dissector for a specifc protocol. """ - super(PipeCapture, self).__init__(interface=pipe, display_filter=display_filter, + super(PipeCapture, self).__init__(display_filter=display_filter, only_summaries=only_summaries, decryption_key=decryption_key, encryption_type=encryption_type, @@ -36,9 +36,28 @@ def get_parameters(self, packet_count=None): Returns the special tshark parameters to be used according to the configuration of this class. """ params = super(PipeCapture, self).get_parameters(packet_count=packet_count) - return params + params.extend(['-i{}'.format(self._pipe), '-']) + return params[:-1] def close(self): # Close pipe - self._pipe.close() + # self._pipe.close() # Don't close the pipe. This should be the job of whatever is piping into it. super(PipeCapture, self).close() + + # Backwards compatibility + sniff = Capture.load_packets + + def sniff_continuously(self, packet_count=None): + """ + Captures from the set interface, returning a generator which returns packets continuously. + + Can be used as follows: + for packet in capture.sniff_continuously(); + print 'Woo, another packet:', packet + + Note: you can also call capture.apply_on_packets(packet_callback) which should have a slight performance boost. + + :param packet_count: an amount of packets to capture, then stop. + """ + # Retained for backwards compatibility and to add documentation. + return self._packets_from_tshark_sync(packet_count=packet_count) From 101afc9a329a976977f84d933c44048cc98ac648 Mon Sep 17 00:00:00 2001 From: ZackAlfakir Date: Thu, 26 Jul 2018 15:32:59 -0400 Subject: [PATCH 6/8] remove unnecessary override --- src/pyshark/capture/pipe_ring_capture.py | 25 +----------------------- 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/src/pyshark/capture/pipe_ring_capture.py b/src/pyshark/capture/pipe_ring_capture.py index 2f75d71a..bbac3920 100644 --- a/src/pyshark/capture/pipe_ring_capture.py +++ b/src/pyshark/capture/pipe_ring_capture.py @@ -40,7 +40,7 @@ def __init__(self, pipe, ring_file_size=1024, num_ring_files=2, ring_file_name=N """ if display_filter is not None: raise DisplayFilterNotAllowedException("Display Filters are not allowed in PipeRingCapture.") - + super(PipeRingCapture, self).__init__(pipe, display_filter=display_filter, only_summaries=only_summaries, decryption_key=decryption_key, encryption_type=encryption_type, tshark_path=tshark_path, decode_as=decode_as, disable_protocol=disable_protocol, @@ -62,26 +62,3 @@ def get_parameters(self, packet_count=None): params += ['-b', 'filesize:' + str(self.ring_file_size), '-b', 'files:' + str(self.num_ring_files), '-w', self.ring_file_name, '-P'] return params - - async def _get_tshark_process(self, packet_count=None, stdin=None): - """ - Returns a new tshark process with previously-set parameters. - """ - if self.use_json: - output_type = 'json' - if not tshark_supports_json(self.tshark_path): - raise TSharkVersionException("JSON only supported on Wireshark >= 2.2.0") - else: - output_type = 'psml' if self._only_summaries else 'pdml' - parameters = [self._get_tshark_path(), '-l', '-n', '-T', output_type] + \ - self.get_parameters(packet_count=packet_count) - - self._log.debug('Creating TShark subprocess with parameters: ' + ' '.join(parameters)) - - tshark_process = await asyncio.create_subprocess_exec(*parameters, - stdout=subprocess.PIPE, - stderr=self._stderr_output(), - stdin=stdin) - self._created_new_process(parameters, tshark_process) - return tshark_process - From dcb060ae3edee9b189a5e9efde2f54058b606983 Mon Sep 17 00:00:00 2001 From: ZackAlfakir Date: Mon, 6 Aug 2018 10:03:59 -0400 Subject: [PATCH 7/8] Added documentation and argument handling --- src/pyshark/capture/pipe_capture.py | 8 +++++--- src/pyshark/capture/pipe_ring_capture.py | 8 ++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/pyshark/capture/pipe_capture.py b/src/pyshark/capture/pipe_capture.py index e61fc678..3c8263f5 100644 --- a/src/pyshark/capture/pipe_capture.py +++ b/src/pyshark/capture/pipe_capture.py @@ -6,7 +6,7 @@ def __init__(self, pipe, display_filter=None, only_summaries=False, decryption_key=None, encryption_type='wpa-pwk', decode_as=None, disable_protocol=None, tshark_path=None, override_prefs=None, use_json=False, include_raw=False): """ - Receives a file-like and reads the packets from there (pcap format). + Receives a string for the filename and reads the packets from there (pcap format). Does not close the pipe. :param bpf_filter: BPF filter to use on packets. :param display_filter: Display (wireshark) filter to use. @@ -40,8 +40,10 @@ def get_parameters(self, packet_count=None): return params[:-1] def close(self): - # Close pipe - # self._pipe.close() # Don't close the pipe. This should be the job of whatever is piping into it. + """ + Closes the capture, but not the pipe. + """ + # Close the capture. super(PipeCapture, self).close() # Backwards compatibility diff --git a/src/pyshark/capture/pipe_ring_capture.py b/src/pyshark/capture/pipe_ring_capture.py index bbac3920..d539246f 100644 --- a/src/pyshark/capture/pipe_ring_capture.py +++ b/src/pyshark/capture/pipe_ring_capture.py @@ -16,9 +16,9 @@ class PipeRingCapture(PipeCapture): """ def __init__(self, pipe, ring_file_size=1024, num_ring_files=2, ring_file_name=None, - display_filter=None, only_summaries=False, decryption_key=None, + only_summaries=False, decryption_key=None, encryption_type='wpa-pwk', decode_as=None, disable_protocol=None, - tshark_path=None, override_prefs=None, include_raw=False, use_json=False): + tshark_path=None, override_prefs=None, include_raw=False, use_json=False, **kwargs): """ Creates a new live capturer on a given interface. Does not start the actual capture itself. :param ring_file_size: Size of the ring file in kB, default is 1024 @@ -38,10 +38,10 @@ def __init__(self, pipe, ring_file_size=1024, num_ring_files=2, ring_file_name=N :param override_prefs: A dictionary of tshark preferences to override, {PREFERENCE_NAME: PREFERENCE_VALUE, ...}. :param disable_protocol: Tells tshark to remove a dissector for a specifc protocol. """ - if display_filter is not None: + if "display_filter" in kwargs.keys(): raise DisplayFilterNotAllowedException("Display Filters are not allowed in PipeRingCapture.") - super(PipeRingCapture, self).__init__(pipe, display_filter=display_filter, only_summaries=only_summaries, + super(PipeRingCapture, self).__init__(pipe, display_filter=None, only_summaries=only_summaries, decryption_key=decryption_key, encryption_type=encryption_type, tshark_path=tshark_path, decode_as=decode_as, disable_protocol=disable_protocol, override_prefs=override_prefs, include_raw=include_raw, use_json=use_json) From a72b47e6e3aff3bb456ce8cef71e6b80adf335e1 Mon Sep 17 00:00:00 2001 From: ZackAlfakir Date: Tue, 28 Aug 2018 11:14:35 -0400 Subject: [PATCH 8/8] Went back to old version of accepting arguments --- src/pyshark/capture/pipe_ring_capture.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pyshark/capture/pipe_ring_capture.py b/src/pyshark/capture/pipe_ring_capture.py index d539246f..e3f20746 100644 --- a/src/pyshark/capture/pipe_ring_capture.py +++ b/src/pyshark/capture/pipe_ring_capture.py @@ -17,8 +17,8 @@ class PipeRingCapture(PipeCapture): def __init__(self, pipe, ring_file_size=1024, num_ring_files=2, ring_file_name=None, only_summaries=False, decryption_key=None, - encryption_type='wpa-pwk', decode_as=None, disable_protocol=None, - tshark_path=None, override_prefs=None, include_raw=False, use_json=False, **kwargs): + encryption_type='wpa-pwk', decode_as=None, disable_protocol=None, display_filter=None, + tshark_path=None, override_prefs=None, include_raw=False, use_json=False, eventloop=None): """ Creates a new live capturer on a given interface. Does not start the actual capture itself. :param ring_file_size: Size of the ring file in kB, default is 1024 @@ -38,13 +38,13 @@ def __init__(self, pipe, ring_file_size=1024, num_ring_files=2, ring_file_name=N :param override_prefs: A dictionary of tshark preferences to override, {PREFERENCE_NAME: PREFERENCE_VALUE, ...}. :param disable_protocol: Tells tshark to remove a dissector for a specifc protocol. """ - if "display_filter" in kwargs.keys(): + if display_filter is not None: raise DisplayFilterNotAllowedException("Display Filters are not allowed in PipeRingCapture.") super(PipeRingCapture, self).__init__(pipe, display_filter=None, only_summaries=only_summaries, decryption_key=decryption_key, encryption_type=encryption_type, tshark_path=tshark_path, decode_as=decode_as, disable_protocol=disable_protocol, - override_prefs=override_prefs, include_raw=include_raw, use_json=use_json) + override_prefs=override_prefs, include_raw=include_raw, use_json=use_json, eventloop=eventloop) self.ring_file_size = ring_file_size self.num_ring_files = num_ring_files