traffic-taffy 0.2__py3-none-any.whl → 0.3.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,222 @@
1
+ import sys
2
+ import logging
3
+ from logging import info, debug
4
+ from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
5
+ from PyQt6.QtWidgets import QPushButton, QVBoxLayout, QLineEdit, QTextEdit, QWidget, QApplication, QLabel
6
+ from traffic_taffy.dissector import (
7
+ PCAPDissectorType,
8
+ dissector_add_parseargs,
9
+ limitor_add_parseargs,
10
+ PCAPDissector,
11
+ check_dissector_level,
12
+ )
13
+ from traffic_taffy.compare import PcapCompare
14
+
15
+ # https://stackoverflow.com/questions/32476006/how-to-make-an-expandable-collapsable-section-widget-in-qt
16
+
17
+ # class Widget(QWidget):
18
+ # def __init__(self):
19
+ # super().__init__()
20
+ # self.__initUi()
21
+
22
+ # def __initUi(self):
23
+ # addBtn = QPushButton('Add')
24
+ # addBtn.clicked.connect(self.__add)
25
+ # self.__foldableListWidget = FoldableListWidget()
26
+ # lay = QVBoxLayout()
27
+ # lay.addWidget(addBtn)
28
+ # lay.addWidget(self.__foldableListWidget)
29
+ # self.setLayout(lay)
30
+
31
+ # def __add(self):
32
+ # foldedItem = QLabel("folded")
33
+ # # foldedItem.setPlaceholderText('Input...')
34
+
35
+ # sublist = FoldableListWidget()
36
+ # subitem1 = QLabel("main item")
37
+ # subitem2 = QLabel("sub item")
38
+ # sublist.setFoldableListWidgetItem(subitem1, subitem2)
39
+
40
+ # self.__foldableListWidget.setFoldableListWidgetItem(foldedItem, sublist)
41
+
42
+
43
+ from PyQt6.QtWidgets import (QPushButton, QDialog, QTreeWidget,
44
+ QTreeWidgetItem, QVBoxLayout,
45
+ QHBoxLayout, QFrame, QLabel,
46
+ QApplication)
47
+
48
+ class SectionExpandButton(QPushButton):
49
+ """a QPushbutton that can expand or collapse its section
50
+ """
51
+ def __init__(self, item, text = "", parent = None):
52
+ super().__init__(text, parent)
53
+ self.section = item
54
+ self.clicked.connect(self.on_clicked)
55
+
56
+ def on_clicked(self):
57
+ """toggle expand/collapse of section by clicking
58
+ """
59
+ if self.section.isExpanded():
60
+ self.section.setExpanded(False)
61
+ else:
62
+ self.section.setExpanded(True)
63
+
64
+
65
+ class TaffyExplorer(QDialog):
66
+ """Explore PCAP files by comparison slices"""
67
+ def __init__(self, args):
68
+ super().__init__()
69
+ self.tree = QTreeWidget()
70
+ self.tree.setHeaderHidden(True)
71
+ self.mainLayout = QVBoxLayout()
72
+ self.mainLayout.addWidget(self.tree)
73
+ self.setLayout(self.mainLayout)
74
+ self.tree.setIndentation(0)
75
+
76
+ self.sections = []
77
+ self.define_sections()
78
+ self.add_sections()
79
+
80
+ self.plusone = QPushButton("Add one")
81
+ self.mainLayout.addWidget(self.plusone)
82
+ self.plusone.clicked.connect(self.addone)
83
+
84
+ self.args = args
85
+
86
+ def addone(self):
87
+ print("here")
88
+ self.add_section("new item", QLabel("one thing"))
89
+
90
+ def add_section(self, title, widget):
91
+ button1 = self.add_button(title)
92
+ section1 = self.add_widget(button1, widget)
93
+ button1.addChild(section1)
94
+
95
+ def add_sections(self):
96
+ """adds a collapsible sections for every
97
+ (title, widget) tuple in self.sections
98
+ """
99
+ #self.tree.clear()
100
+ for (title, widget) in self.sections:
101
+ self.add_section(title, widget)
102
+
103
+ def define_sections(self):
104
+ """reimplement this to define all your sections
105
+ and add them as (title, widget) tuples to self.sections
106
+ """
107
+ widget = QFrame(self.tree)
108
+ layout = QHBoxLayout(widget)
109
+ layout.addWidget(QLabel("Bla"))
110
+ layout.addWidget(QLabel("Blubb"))
111
+ title = "Section 1"
112
+ self.sections.append((title, widget))
113
+
114
+ def add_button(self, title):
115
+ """creates a QTreeWidgetItem containing a button
116
+ to expand or collapse its section
117
+ """
118
+ item = QTreeWidgetItem()
119
+ self.tree.addTopLevelItem(item)
120
+ self.tree.setItemWidget(item, 0, SectionExpandButton(item, text = title))
121
+ return item
122
+
123
+ def add_widget(self, button, widget):
124
+ """creates a QWidgetItem containing the widget,
125
+ as child of the button-QWidgetItem
126
+ """
127
+ section = QTreeWidgetItem(button)
128
+ section.setDisabled(True)
129
+ self.tree.setItemWidget(section, 0, widget)
130
+ return section
131
+
132
+ def create_comparison(self):
133
+ self.pc = PcapCompare(
134
+ self.args.pcap_files,
135
+ maximum_count=self.args.packet_count,
136
+ print_threshold=float(self.args.print_threshold) / 100.0,
137
+ print_minimum_count=self.args.minimum_count,
138
+ print_match_string=self.args.match_string,
139
+ only_positive=self.args.only_positive,
140
+ only_negative=self.args.only_negative,
141
+ cache_results=self.args.cache_pcap_results,
142
+ dissection_level=self.args.dissection_level,
143
+ between_times=self.args.between_times,
144
+ )
145
+
146
+ # compare the pcaps
147
+ self.pcap_data = list(self.pc.load_pcaps())
148
+
149
+ def show_comparison(self, pcap_one, timestamp_one, pcap_two, timestamp_two):
150
+
151
+
152
+
153
+ def parse_args():
154
+ "Parse the command line arguments."
155
+ parser = ArgumentParser(
156
+ formatter_class=ArgumentDefaultsHelpFormatter,
157
+ description=__doc__,
158
+ epilog="Exmaple Usage: ",
159
+ )
160
+
161
+ limiting_parser = limitor_add_parseargs(parser)
162
+
163
+ limiting_parser.add_argument(
164
+ "-t",
165
+ "--print-threshold",
166
+ default=0.0,
167
+ type=float,
168
+ help="Don't print results with abs(percent) less than this threshold",
169
+ )
170
+
171
+ limiting_parser.add_argument(
172
+ "-P", "--only-positive", action="store_true", help="Only show positive entries"
173
+ )
174
+
175
+ limiting_parser.add_argument(
176
+ "-N", "--only-negative", action="store_true", help="Only show negative entries"
177
+ )
178
+
179
+ limiting_parser.add_argument(
180
+ "-T",
181
+ "--between-times",
182
+ nargs=2,
183
+ type=int,
184
+ help="For single files, only display results between these timestamps",
185
+ )
186
+
187
+ dissector_add_parseargs(parser)
188
+
189
+ debugging_group = parser.add_argument_group("Debugging options")
190
+
191
+ debugging_group.add_argument(
192
+ "--log-level",
193
+ "--ll",
194
+ default="info",
195
+ help="Define the logging verbosity level (debug, info, warning, error, ...).",
196
+ )
197
+
198
+ parser.add_argument("pcap_files", type=str, nargs="*", help="PCAP files to analyze")
199
+
200
+ args = parser.parse_args()
201
+ log_level = args.log_level.upper()
202
+ logging.basicConfig(level=log_level, format="%(levelname)-10s:\t%(message)s")
203
+
204
+ check_dissector_level(args.dissection_level)
205
+
206
+ return args
207
+
208
+
209
+ def main():
210
+ args = parse_args()
211
+
212
+ app = QApplication(sys.argv)
213
+ window = TaffyExplorer(args)
214
+ window.create_comparison()
215
+ window.show()
216
+ sys.exit(app.exec())
217
+
218
+
219
+
220
+ if __name__ == "__main__":
221
+ main()
222
+
traffic_taffy/graph.py CHANGED
@@ -26,14 +26,6 @@ def parse_args():
26
26
  epilog="Exmaple Usage: ",
27
27
  )
28
28
 
29
- parser.add_argument(
30
- "-g",
31
- "--graph-elements",
32
- default=None,
33
- type=str,
34
- help="Graph these particular elements; the default is packet counts",
35
- )
36
-
37
29
  parser.add_argument(
38
30
  "-o",
39
31
  "--output-file",
@@ -49,14 +41,6 @@ def parse_args():
49
41
  help="Define verbosity level (debug, info, warning, error, fotal, critical).",
50
42
  )
51
43
 
52
- parser.add_argument(
53
- "-b",
54
- "--bin-size",
55
- type=int,
56
- default=1,
57
- help="Bin results into this many seconds",
58
- )
59
-
60
44
  parser.add_argument(
61
45
  "-i",
62
46
  "--interactive",
@@ -3,10 +3,11 @@
3
3
  import io
4
4
  import os
5
5
  import multiprocessing
6
+ from traffic_taffy.dissector import PCAPDissector
6
7
  from typing import List
7
8
  import dpkt
8
9
  from concurrent.futures import ProcessPoolExecutor, Future
9
- from logging import debug
10
+ from logging import debug, info
10
11
 
11
12
 
12
13
  class PCAPSplitter:
@@ -26,6 +27,7 @@ class PCAPSplitter:
26
27
  self.split_size: int = split_size
27
28
  self.maximum_count: int = maximum_count
28
29
  self.pcap_filter: str | None = pcap_filter
30
+ self.maximum_cores = maximum_cores
29
31
 
30
32
  self.header: bytes = None
31
33
  self.buffer: bytes = None
@@ -38,29 +40,46 @@ class PCAPSplitter:
38
40
  if not os.path.exists(self.pcap_file):
39
41
  raise ValueError(f"failed to find pcap file '{self.pcap_file}'")
40
42
 
41
- if not self.split_size:
42
- cores = multiprocessing.cpu_count()
43
- if maximum_cores and cores > maximum_cores:
44
- cores = maximum_cores
43
+ def set_split_size(self):
44
+ "Attempt to calculate a reasonable split size"
45
+ if self.split_size:
46
+ info(f"split size already set to {self.split_size}")
47
+ return self.split_size
45
48
 
46
- if self.maximum_count:
47
- # not ideal math, but better than nothing
48
- self.split_size = int(self.maximum_count / cores)
49
+ cores = multiprocessing.cpu_count()
50
+ if self.maximum_cores and cores > self.maximum_cores:
51
+ cores = self.maximum_cores
52
+
53
+ if self.maximum_count and self.maximum_count > 0:
54
+ # not ideal math, but better than nothing
55
+ self.split_size = int(self.maximum_count / cores)
56
+ else:
57
+ if isinstance(self.our_data, io.BufferedReader):
58
+ # raw uncompressed file
59
+ divide_size = 1200
49
60
  else:
50
- # even worse math and assumes generally large packets
51
- stats = os.stat(self.pcap_file)
52
- file_size = stats.st_size
53
- self.split_size = int(file_size / 1200 / cores)
61
+ # likely a compressed file
62
+ divide_size = 5000
63
+
64
+ # even worse math and assumes generally large packets
65
+ stats = os.stat(self.pcap_file)
66
+ file_size = stats.st_size
67
+ self.split_size = int(file_size / divide_size / cores)
68
+ debug(
69
+ f"split info: {file_size=}, {divide_size=}, {cores=}, {self.split_size=}"
70
+ )
54
71
 
55
- # even 1000 is kinda silly to split, but is better than nothing
56
- self.split_size = min(self.split_size, 1000)
57
- debug(f"setting PCAPSplitter split size to {self.split_size} for {cores}")
72
+ # even 1000 is kinda silly to split, but is better than nothing
73
+ self.split_size = max(self.split_size, 1000)
74
+ debug(f"setting PCAPSplitter split size to {self.split_size} for {cores} cores")
58
75
 
59
76
  def split(self) -> List[io.BytesIO] | List[Future]:
60
77
  "Does the actual reading and splitting"
61
78
  # open one for the dpkt reader and one for us independently
62
- self.our_data = open(self.pcap_file, "rb")
63
- self.dpkt_data = open(self.pcap_file, "rb")
79
+ self.our_data = PCAPDissector.open_maybe_compressed(self.pcap_file)
80
+ self.dpkt_data = PCAPDissector.open_maybe_compressed(self.pcap_file)
81
+
82
+ self.set_split_size()
64
83
 
65
84
  # read the first 24 bytes which is the pcap header
66
85
  self.header = self.our_data.read(24)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: traffic-taffy
3
- Version: 0.2
3
+ Version: 0.3.5
4
4
  Summary: A tool for doing differential analysis of pcap files
5
5
  Home-page: https://github.com/hardaker/traffic-taffy
6
6
  Author: Wes Hardaker
@@ -9,6 +9,11 @@ Classifier: Programming Language :: Python :: 3
9
9
  Classifier: Operating System :: OS Independent
10
10
  Requires-Python: >=3.7
11
11
  Description-Content-Type: text/markdown
12
+ Requires-Dist: pandas
13
+ Requires-Dist: rich
14
+ Requires-Dist: seaborn
15
+ Requires-Dist: scapy
16
+ Requires-Dist: dpkt
12
17
 
13
18
  # Traffic Analysis of Fluctuating Flows (TAFFy)
14
19
 
@@ -0,0 +1,21 @@
1
+ pcap_compare/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ pcap_compare/cache_info.py,sha256=22Fs5fNU_GzWwcAua_XfEFswRmlM8TmTbHXe2CYKQDE,1468
3
+ pcap_compare/compare.py,sha256=xVRNmCsdUp1mEZub0SN2CW7osOZMgJuW__Cj9UA2DRE,9169
4
+ pcap_compare/dissectmany.py,sha256=dxxChV0Qq9LeoPXiS0cCIEKFtO_RJwHxwOoPOZ3rwU8,681
5
+ pcap_compare/dissector.py,sha256=iEZzLHJ7HubM3-UbZR461irXkZcpM8u_Aoa7GzWUMEY,17571
6
+ pcap_compare/dissectorresults.py,sha256=LKoyX04Qjc6B7RnqtJgIWsyVnselJ9CygLkMAp3lhw0,647
7
+ pcap_compare/graph.py,sha256=cioVq9JYNRVqzlRJSKLveGnGSEL9FkXDUyp-Y7osSkM,5935
8
+ traffic_taffy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ traffic_taffy/cache_info.py,sha256=zpuuJcPzJzyma37YJE4FwKSaOBAmzImDj0Khdn2x1FI,1623
10
+ traffic_taffy/compare.py,sha256=-PvazIzp1ABvtZpjb1tjG9KAcnZYO_PU29FJpDNwPus,11654
11
+ traffic_taffy/dissectmany.py,sha256=QCqnIhtMMIqHXPVg4KOIcUYaIyaDR_DCIKLoD41E1C0,2528
12
+ traffic_taffy/dissector.py,sha256=M75VGvrv2M1NOJ2JkDaxemlxZWr10WswXN2sOTbcX9I,22085
13
+ traffic_taffy/dissectorresults.py,sha256=LKoyX04Qjc6B7RnqtJgIWsyVnselJ9CygLkMAp3lhw0,647
14
+ traffic_taffy/explore.py,sha256=QaRqr4UdpO72yxWMfg-WK9YkhQTXZwLzWX6K2qg18d0,6808
15
+ traffic_taffy/graph.py,sha256=GZsuppEbMeJA9mr3OH-n5ba5sNT7l35P3Qv-eh1MR3E,6221
16
+ traffic_taffy/pcap_splitter.py,sha256=qDZ0Nd81fIteQRVElyKsD1ncBi4lg07cmx8KPl_q3rY,4585
17
+ traffic_taffy-0.3.5.dist-info/METADATA,sha256=sA9UeWzu1nJyFxcNOXFJ6dJNFDeGA48URLd4TpwrTx0,985
18
+ traffic_taffy-0.3.5.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
19
+ traffic_taffy-0.3.5.dist-info/entry_points.txt,sha256=xabsmMHgr0Pek8ccdQoW6iAKqljueozDZW-q1hJ79eU,194
20
+ traffic_taffy-0.3.5.dist-info/top_level.txt,sha256=wjeQaxXSKqUzrRtfbUlbSn8SoaL4VC73yudFAEtnIuo,14
21
+ traffic_taffy-0.3.5.dist-info/RECORD,,
@@ -1,13 +0,0 @@
1
- traffic_taffy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- traffic_taffy/cache_info.py,sha256=tmPmMJFhz74FDxLoqnQgki5qsUtoJBzkzk3w0ZAen0c,1369
3
- traffic_taffy/compare.py,sha256=SW-wT8y9jnWg9Hx3Fa-XdutHasjF-DjfhCIl3DQgoBM,9074
4
- traffic_taffy/dissectmany.py,sha256=ZsWKR9eid_Ft-HMLvl-Zy2jyofMeZTzqI8Dl0gZ5AWU,2530
5
- traffic_taffy/dissector.py,sha256=iwSUPQujI37h3EM17tic4zmk0GTZe8Xrp7Ov13t51k8,20064
6
- traffic_taffy/dissectorresults.py,sha256=LKoyX04Qjc6B7RnqtJgIWsyVnselJ9CygLkMAp3lhw0,647
7
- traffic_taffy/graph.py,sha256=gpf_64XBH9rM7uLQhYA3p0PTButfiUvcmY5SNLnq4IA,6569
8
- traffic_taffy/pcap_splitter.py,sha256=HKz7QOnekqxUut58TMPK3-dQmP98NIhL7Ii6ofFnxYY,3868
9
- traffic_taffy-0.2.dist-info/METADATA,sha256=tzkA86g8DlpwNMUuoSBl3Y4tzqNBjv0FROdqTawVUBc,877
10
- traffic_taffy-0.2.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
11
- traffic_taffy-0.2.dist-info/entry_points.txt,sha256=xabsmMHgr0Pek8ccdQoW6iAKqljueozDZW-q1hJ79eU,194
12
- traffic_taffy-0.2.dist-info/top_level.txt,sha256=wjeQaxXSKqUzrRtfbUlbSn8SoaL4VC73yudFAEtnIuo,14
13
- traffic_taffy-0.2.dist-info/RECORD,,