traffic-taffy 0.8.1__py3-none-any.whl → 0.9__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.
- traffic_taffy/__init__.py +1 -1
- traffic_taffy/algorithms/__init__.py +14 -7
- traffic_taffy/algorithms/comparecorrelation.py +164 -0
- traffic_taffy/algorithms/comparecorrelationchanges.py +210 -0
- traffic_taffy/algorithms/compareseries.py +117 -0
- traffic_taffy/algorithms/compareslices.py +116 -0
- traffic_taffy/algorithms/statistical.py +9 -9
- traffic_taffy/compare.py +149 -159
- traffic_taffy/comparison.py +18 -4
- traffic_taffy/config.py +133 -0
- traffic_taffy/dissection.py +171 -6
- traffic_taffy/dissectmany.py +26 -16
- traffic_taffy/dissector.py +189 -77
- traffic_taffy/dissector_engine/scapy.py +41 -8
- traffic_taffy/graph.py +54 -53
- traffic_taffy/graphdata.py +13 -2
- traffic_taffy/hooks/ip2asn.py +20 -7
- traffic_taffy/hooks/labels.py +45 -0
- traffic_taffy/hooks/psl.py +21 -3
- traffic_taffy/iana/tables.msgpak +0 -0
- traffic_taffy/output/__init__.py +8 -48
- traffic_taffy/output/console.py +37 -25
- traffic_taffy/output/fsdb.py +24 -18
- traffic_taffy/reports/__init__.py +5 -0
- traffic_taffy/reports/compareslicesreport.py +85 -0
- traffic_taffy/reports/correlationchangereport.py +54 -0
- traffic_taffy/reports/correlationreport.py +42 -0
- traffic_taffy/taffy_config.py +44 -0
- traffic_taffy/tests/test_compare_results.py +22 -7
- traffic_taffy/tests/test_config.py +149 -0
- traffic_taffy/tests/test_global_config.py +33 -0
- traffic_taffy/tests/test_normalize.py +1 -0
- traffic_taffy/tests/test_pcap_dissector.py +12 -2
- traffic_taffy/tests/test_pcap_splitter.py +21 -10
- traffic_taffy/tools/cache_info.py +3 -2
- traffic_taffy/tools/compare.py +32 -24
- traffic_taffy/tools/config.py +83 -0
- traffic_taffy/tools/dissect.py +51 -59
- traffic_taffy/tools/explore.py +5 -4
- traffic_taffy/tools/export.py +28 -17
- traffic_taffy/tools/graph.py +25 -27
- {traffic_taffy-0.8.1.dist-info → traffic_taffy-0.9.dist-info}/METADATA +4 -1
- traffic_taffy-0.9.dist-info/RECORD +56 -0
- {traffic_taffy-0.8.1.dist-info → traffic_taffy-0.9.dist-info}/entry_points.txt +1 -0
- traffic_taffy/report.py +0 -12
- traffic_taffy/tests/test_dpkt_engine.py +0 -15
- traffic_taffy-0.8.1.dist-info/RECORD +0 -43
- {traffic_taffy-0.8.1.dist-info → traffic_taffy-0.9.dist-info}/WHEEL +0 -0
- {traffic_taffy-0.8.1.dist-info → traffic_taffy-0.9.dist-info}/licenses/LICENSE.txt +0 -0
@@ -1,5 +1,5 @@
|
|
1
1
|
from collections import Counter
|
2
|
-
from traffic_taffy.
|
2
|
+
from traffic_taffy.reports.compareslicesreport import CompareSlicesReport
|
3
3
|
from traffic_taffy.algorithms.statistical import ComparisonStatistical
|
4
4
|
|
5
5
|
|
@@ -10,7 +10,7 @@ def test_compare_statistical_algorithm():
|
|
10
10
|
# this should be positive when right_data is larger
|
11
11
|
expected = {
|
12
12
|
"src": {
|
13
|
-
"a":
|
13
|
+
"a": CompareSlicesReport(
|
14
14
|
total=20,
|
15
15
|
left_count=5,
|
16
16
|
right_count=15,
|
@@ -19,7 +19,7 @@ def test_compare_statistical_algorithm():
|
|
19
19
|
right_percentage=15.0 / 30.0,
|
20
20
|
delta_percentage=15.0 / 30.0 - 5.0 / 15.0,
|
21
21
|
),
|
22
|
-
"b":
|
22
|
+
"b": CompareSlicesReport(
|
23
23
|
total=-10, # only in 1
|
24
24
|
left_count=10,
|
25
25
|
right_count=0,
|
@@ -28,7 +28,7 @@ def test_compare_statistical_algorithm():
|
|
28
28
|
right_percentage=0.0,
|
29
29
|
delta_percentage=-1.0,
|
30
30
|
),
|
31
|
-
"c":
|
31
|
+
"c": CompareSlicesReport(
|
32
32
|
total=15, # only in 2
|
33
33
|
left_count=0,
|
34
34
|
right_count=15,
|
@@ -37,7 +37,7 @@ def test_compare_statistical_algorithm():
|
|
37
37
|
right_percentage=15.0 / 30.0,
|
38
38
|
delta_percentage=1.0,
|
39
39
|
),
|
40
|
-
"__NEW_VALUES__":
|
40
|
+
"__NEW_VALUES__": CompareSlicesReport(
|
41
41
|
total=2, # 1 on each side
|
42
42
|
left_count=1, # b
|
43
43
|
right_count=1, # c
|
@@ -50,6 +50,21 @@ def test_compare_statistical_algorithm():
|
|
50
50
|
}
|
51
51
|
|
52
52
|
algorithm = ComparisonStatistical() # bogus file names
|
53
|
-
report = algorithm.compare_dissections(left_data[0], right_data[0])
|
54
53
|
|
55
|
-
|
54
|
+
class FakeDissection:
|
55
|
+
def __init__(self, data):
|
56
|
+
self._data = data
|
57
|
+
|
58
|
+
@property
|
59
|
+
def data(self):
|
60
|
+
return self._data
|
61
|
+
|
62
|
+
@property
|
63
|
+
def pcap_file(self):
|
64
|
+
return "bogus"
|
65
|
+
|
66
|
+
left = FakeDissection(left_data)
|
67
|
+
right = FakeDissection(right_data)
|
68
|
+
|
69
|
+
report = algorithm.compare_dissections(iter([left, right]))
|
70
|
+
assert report[0].contents == expected
|
@@ -0,0 +1,149 @@
|
|
1
|
+
from io import StringIO
|
2
|
+
from traffic_taffy.config import Config
|
3
|
+
from argparse import Namespace
|
4
|
+
from tempfile import NamedTemporaryFile
|
5
|
+
|
6
|
+
from argparse import ArgumentParser
|
7
|
+
|
8
|
+
TESTCONFIG: str = """
|
9
|
+
name: foo
|
10
|
+
value: bar
|
11
|
+
arry:
|
12
|
+
- 1
|
13
|
+
- 2
|
14
|
+
"""
|
15
|
+
|
16
|
+
|
17
|
+
def test_loading():
|
18
|
+
contents = StringIO(TESTCONFIG)
|
19
|
+
|
20
|
+
cfg = Config()
|
21
|
+
cfg.load_stream(contents)
|
22
|
+
assert cfg["name"] == "foo"
|
23
|
+
assert cfg["arry"][0] == 1 # truly sic!
|
24
|
+
|
25
|
+
|
26
|
+
def test_namespace_loading():
|
27
|
+
cfg = Config()
|
28
|
+
|
29
|
+
arguments: Namespace = Namespace()
|
30
|
+
arguments.test_arg_one = 12
|
31
|
+
arguments.test_arg_two = {"a": "hello", "b": "world"}
|
32
|
+
|
33
|
+
cfg.load_namespace(arguments)
|
34
|
+
|
35
|
+
assert cfg["test_arg_one"] == 12
|
36
|
+
assert cfg["test_arg_two"]["b"] == "world"
|
37
|
+
|
38
|
+
|
39
|
+
def test_as_namespace():
|
40
|
+
contents = StringIO(TESTCONFIG)
|
41
|
+
|
42
|
+
cfg = Config()
|
43
|
+
cfg.load_stream(contents)
|
44
|
+
assert cfg["name"] == "foo"
|
45
|
+
assert cfg["arry"][0] == 1 # truly sic!
|
46
|
+
|
47
|
+
args = cfg.as_namespace()
|
48
|
+
|
49
|
+
assert args.name == "foo"
|
50
|
+
assert args.arry[0] == 1
|
51
|
+
|
52
|
+
|
53
|
+
def test_namespace_loading_and_mapping():
|
54
|
+
cfg = Config()
|
55
|
+
|
56
|
+
arguments: Namespace = Namespace()
|
57
|
+
arguments.test_arg_one = 12
|
58
|
+
arguments.test_arg_two = {"a": "hello", "b": "world"}
|
59
|
+
|
60
|
+
remap: dict = {"test_arg_one": "new_arg_one"}
|
61
|
+
|
62
|
+
cfg.load_namespace(arguments, mapping=remap)
|
63
|
+
|
64
|
+
assert cfg["new_arg_one"] == 12
|
65
|
+
assert cfg["test_arg_two"]["b"] == "world"
|
66
|
+
|
67
|
+
assert "test_arg_one" not in cfg
|
68
|
+
|
69
|
+
|
70
|
+
def test_config_commandline_option():
|
71
|
+
cfg = Config()
|
72
|
+
|
73
|
+
with NamedTemporaryFile("w", suffix="yml") as fileh:
|
74
|
+
fileh.write(TESTCONFIG)
|
75
|
+
fileh.flush()
|
76
|
+
|
77
|
+
cfg.read_configfile_from_arguments(
|
78
|
+
["foo", "bar", "-in-the-way", "--config", fileh.name, "--other", "-arg"]
|
79
|
+
)
|
80
|
+
|
81
|
+
assert cfg["name"] == "foo"
|
82
|
+
assert cfg["arry"][0] == 1
|
83
|
+
|
84
|
+
|
85
|
+
def test_expected_full_usage():
|
86
|
+
# Create configuration in a yaml file
|
87
|
+
with NamedTemporaryFile("w", suffix="yml") as fileh:
|
88
|
+
fileh.write("question: 'how many roads must a man walk down?'\n")
|
89
|
+
fileh.write("reference: hitchhikers\n")
|
90
|
+
fileh.write("options:\n - 1\n - 2\n - 3\n")
|
91
|
+
fileh.flush()
|
92
|
+
|
93
|
+
# set some application hard-code defaults
|
94
|
+
cfg = Config()
|
95
|
+
cfg["answer"] = 42
|
96
|
+
cfg["options"] = ["a", "b", "c"]
|
97
|
+
|
98
|
+
assert cfg == {"answer": 42, "options": ["a", "b", "c"]}
|
99
|
+
|
100
|
+
# define the arguments we want to pass (potentially overriding other variables)
|
101
|
+
passed_arguments = [
|
102
|
+
"--question",
|
103
|
+
"What do you get when you multiply six by seven?",
|
104
|
+
"--config",
|
105
|
+
fileh.name,
|
106
|
+
"-r",
|
107
|
+
"The guide",
|
108
|
+
]
|
109
|
+
|
110
|
+
# now parse these to just read the config file
|
111
|
+
cfg.read_configfile_from_arguments(passed_arguments)
|
112
|
+
|
113
|
+
# ensure the configuration has been updated from the file contents, but not CLI args
|
114
|
+
|
115
|
+
assert cfg == {
|
116
|
+
"answer": 42, # note: same
|
117
|
+
"options": [1, 2, 3], # note: overwritten
|
118
|
+
"question": "how many roads must a man walk down?", # note: same
|
119
|
+
"reference": "hitchhikers", # note: same
|
120
|
+
}
|
121
|
+
|
122
|
+
# set up the command line options
|
123
|
+
parser = ArgumentParser()
|
124
|
+
|
125
|
+
parser.add_argument("-q", "--question", default=cfg["question"], type=str)
|
126
|
+
parser.add_argument("-a", "--answer", default=cfg["answer"], type=int)
|
127
|
+
parser.add_argument(
|
128
|
+
"-o", "--options", default=cfg["options"], nargs="+", type=int
|
129
|
+
)
|
130
|
+
parser.add_argument("-r", "--reference", default=cfg["reference"], type=str)
|
131
|
+
parser.add_argument("-c", "--config", type=str)
|
132
|
+
parser.add_argument("--only-unused-argument", "--", type=str)
|
133
|
+
|
134
|
+
args = parser.parse_args(passed_arguments)
|
135
|
+
cfg.load_namespace(args)
|
136
|
+
|
137
|
+
del cfg[
|
138
|
+
"config"
|
139
|
+
] # this will always be random tmp file and we don't need to check it
|
140
|
+
assert (
|
141
|
+
cfg
|
142
|
+
== {
|
143
|
+
"answer": 42, # note: still a default
|
144
|
+
"options": [1, 2, 3], # note: from config
|
145
|
+
"question": "What do you get when you multiply six by seven?", # note: from cli
|
146
|
+
"reference": "The guide", # note: from cli
|
147
|
+
"only_unused_argument": None,
|
148
|
+
}
|
149
|
+
)
|
@@ -0,0 +1,33 @@
|
|
1
|
+
from traffic_taffy.config import Config
|
2
|
+
from traffic_taffy.taffy_config import TaffyConfig, taffy_default
|
3
|
+
|
4
|
+
|
5
|
+
def test_multi_config():
|
6
|
+
c1 = Config()
|
7
|
+
c2 = Config()
|
8
|
+
|
9
|
+
c1["foo"] = 2
|
10
|
+
c2["foo"] = 3
|
11
|
+
assert c1["foo"] == 2
|
12
|
+
|
13
|
+
|
14
|
+
def test_global_config():
|
15
|
+
c1 = TaffyConfig()
|
16
|
+
c2 = TaffyConfig()
|
17
|
+
|
18
|
+
c1["foo"] = 2
|
19
|
+
c2["foo"] = 3
|
20
|
+
assert c1["foo"] == 3
|
21
|
+
|
22
|
+
|
23
|
+
def test_defaults():
|
24
|
+
taffy_default("a", "b")
|
25
|
+
|
26
|
+
c = TaffyConfig()
|
27
|
+
assert c["a"] == "b"
|
28
|
+
|
29
|
+
c["a"] = "c" # override
|
30
|
+
assert c["a"] == "c"
|
31
|
+
|
32
|
+
taffy_default("a", "d") # ignore overrides
|
33
|
+
assert c["a"] == "c"
|
@@ -50,10 +50,20 @@ def test_dissector_simple_callback() -> None:
|
|
50
50
|
dpkt_engine.dissection.save(save_file)
|
51
51
|
|
52
52
|
# create a new one to make sure it's blank
|
53
|
+
from traffic_taffy.taffy_config import TaffyConfig
|
54
|
+
|
55
|
+
config = TaffyConfig(
|
56
|
+
{
|
57
|
+
"dissect": {
|
58
|
+
"dissection_level": PCAPDissectorLevel.COUNT_ONLY.value,
|
59
|
+
"cache_results": True,
|
60
|
+
}
|
61
|
+
}
|
62
|
+
)
|
63
|
+
|
53
64
|
pd = PCAPDissector(
|
54
65
|
base_pcap,
|
55
|
-
|
56
|
-
cache_results=True,
|
66
|
+
config,
|
57
67
|
)
|
58
68
|
|
59
69
|
pd.load()
|
@@ -4,17 +4,33 @@ import logging
|
|
4
4
|
from logging import debug
|
5
5
|
from traffic_taffy.dissector import PCAPDissector, pcap_data_merge
|
6
6
|
from traffic_taffy.dissection import Dissection
|
7
|
+
from traffic_taffy.taffy_config import TaffyConfig
|
7
8
|
from pcap_parallel import PCAPParallel
|
8
9
|
|
9
10
|
test_pkl = "/tmp/test.pcap.pkl"
|
10
11
|
|
12
|
+
default_config = TaffyConfig(
|
13
|
+
{
|
14
|
+
"dissect": {
|
15
|
+
"dissection_level": 10,
|
16
|
+
"filter": None,
|
17
|
+
"packet_count": 0,
|
18
|
+
"cache_pcap_results": False,
|
19
|
+
"bin_size": 1,
|
20
|
+
"cache_file_suffix": "taffy",
|
21
|
+
"ignore_list": [],
|
22
|
+
"layers": [],
|
23
|
+
"force_overwrite": False,
|
24
|
+
"force_load": False,
|
25
|
+
}
|
26
|
+
}
|
27
|
+
)
|
28
|
+
|
11
29
|
|
12
30
|
def buffer_callback(pcap_io_buffer):
|
13
31
|
pd = PCAPDissector(
|
14
32
|
pcap_io_buffer,
|
15
|
-
|
16
|
-
dissector_level=10,
|
17
|
-
cache_results=False,
|
33
|
+
default_config,
|
18
34
|
)
|
19
35
|
pd.load()
|
20
36
|
return pd.dissection.data
|
@@ -62,9 +78,7 @@ def test_pcap_splitter():
|
|
62
78
|
# create a bogus dissector
|
63
79
|
pd = PCAPDissector(
|
64
80
|
None,
|
65
|
-
|
66
|
-
dissector_level=10,
|
67
|
-
cache_results=False,
|
81
|
+
default_config,
|
68
82
|
)
|
69
83
|
pd.dissection = dissection
|
70
84
|
dissection.save(test_pkl)
|
@@ -75,10 +89,7 @@ def test_pcap_splitter():
|
|
75
89
|
normal_start_time = time.time()
|
76
90
|
pd = PCAPDissector(
|
77
91
|
test_pcap,
|
78
|
-
|
79
|
-
dissector_level=10,
|
80
|
-
cache_results=False,
|
81
|
-
maximum_count=maximum_count,
|
92
|
+
default_config,
|
82
93
|
)
|
83
94
|
pd.load()
|
84
95
|
data2 = pd.dissection.data
|
@@ -1,6 +1,7 @@
|
|
1
1
|
"""Loads the cached data for a file to display the results about it."""
|
2
2
|
|
3
|
-
from argparse import ArgumentParser,
|
3
|
+
from argparse import ArgumentParser, Namespace
|
4
|
+
from rich_argparse import RichHelpFormatter
|
4
5
|
from pathlib import Path
|
5
6
|
from rich import print
|
6
7
|
import logging
|
@@ -10,7 +11,7 @@ import msgpack
|
|
10
11
|
def parse_args() -> Namespace:
|
11
12
|
"""Parse the command line arguments."""
|
12
13
|
parser = ArgumentParser(
|
13
|
-
formatter_class=
|
14
|
+
formatter_class=RichHelpFormatter,
|
14
15
|
description=__doc__,
|
15
16
|
epilog="Example Usage: taffy-cache-info something.taffy",
|
16
17
|
)
|
traffic_taffy/tools/compare.py
CHANGED
@@ -1,27 +1,37 @@
|
|
1
1
|
"""Takes a set of pcap files to compare and creates a report."""
|
2
2
|
|
3
3
|
import sys
|
4
|
-
from argparse import
|
4
|
+
from argparse import Namespace
|
5
|
+
from argparse_with_config import ArgumentParserWithConfig
|
6
|
+
from rich_argparse import RichHelpFormatter
|
5
7
|
import logging
|
6
8
|
from logging import error
|
7
9
|
from traffic_taffy.output.console import Console
|
8
10
|
from traffic_taffy.output.fsdb import Fsdb
|
11
|
+
from traffic_taffy.taffy_config import TaffyConfig, taffy_default
|
9
12
|
|
10
13
|
from traffic_taffy.compare import compare_add_parseargs, get_comparison_args
|
11
14
|
from traffic_taffy.dissector import (
|
12
15
|
dissector_add_parseargs,
|
13
16
|
limitor_add_parseargs,
|
14
17
|
dissector_handle_arguments,
|
18
|
+
TTD_CFG,
|
15
19
|
)
|
16
20
|
from traffic_taffy.compare import PcapCompare
|
17
21
|
|
22
|
+
taffy_default("compare.fsdb", False)
|
18
23
|
|
19
|
-
|
24
|
+
|
25
|
+
def compare_parse_args() -> Namespace:
|
20
26
|
"""Parse the command line arguments."""
|
21
|
-
|
22
|
-
|
27
|
+
|
28
|
+
config: TaffyConfig = TaffyConfig()
|
29
|
+
|
30
|
+
parser = ArgumentParserWithConfig(
|
31
|
+
formatter_class=RichHelpFormatter,
|
23
32
|
description=__doc__,
|
24
33
|
epilog="Example Usage: taffy-compare -C file1.pcap file2.pcap",
|
34
|
+
default_config=config,
|
25
35
|
)
|
26
36
|
|
27
37
|
output_options = parser.add_argument_group("Output format")
|
@@ -29,12 +39,13 @@ def parse_args() -> Namespace:
|
|
29
39
|
"-f",
|
30
40
|
"--fsdb",
|
31
41
|
action="store_true",
|
42
|
+
config_path="compare.output_fsdb",
|
32
43
|
help="Print results in an FSDB formatted output",
|
33
44
|
)
|
34
45
|
|
35
|
-
|
36
|
-
compare_add_parseargs(
|
37
|
-
dissector_add_parseargs(parser)
|
46
|
+
limitor_add_parseargs(parser, config)
|
47
|
+
compare_add_parseargs(parser, config)
|
48
|
+
dissector_add_parseargs(parser, config)
|
38
49
|
|
39
50
|
debugging_group = parser.add_argument_group("Debugging options")
|
40
51
|
|
@@ -42,6 +53,7 @@ def parse_args() -> Namespace:
|
|
42
53
|
"--log-level",
|
43
54
|
"--ll",
|
44
55
|
default="info",
|
56
|
+
config_path="log_level",
|
45
57
|
help="Define the logging verbosity level (debug, info, warning, error, ...).",
|
46
58
|
)
|
47
59
|
|
@@ -53,15 +65,17 @@ def parse_args() -> Namespace:
|
|
53
65
|
|
54
66
|
dissector_handle_arguments(args)
|
55
67
|
|
56
|
-
return args
|
68
|
+
return parser.config, args
|
57
69
|
|
58
70
|
|
59
71
|
def main() -> None:
|
60
72
|
"""Run taffy-compare."""
|
61
|
-
args =
|
73
|
+
config, args = compare_parse_args()
|
62
74
|
|
63
75
|
# setup output options
|
64
|
-
|
76
|
+
config[TTD_CFG.KEY_DISSECTOR][TTD_CFG.FILTER_ARGUMENTS] = get_comparison_args(
|
77
|
+
config
|
78
|
+
)
|
65
79
|
|
66
80
|
# get our files to compare (maybe just one)
|
67
81
|
left = args.pcap_files.pop(0)
|
@@ -79,18 +93,7 @@ def main() -> None:
|
|
79
93
|
|
80
94
|
pc = PcapCompare(
|
81
95
|
files,
|
82
|
-
|
83
|
-
cache_file_suffix=args.cache_file_suffix,
|
84
|
-
maximum_count=printing_arguments["maximum_count"],
|
85
|
-
dissection_level=args.dissection_level,
|
86
|
-
# between_times=args.between_times, # TODO(hardaker): TBD
|
87
|
-
bin_size=args.bin_size,
|
88
|
-
ignore_list=args.ignore_list,
|
89
|
-
pcap_filter=args.filter,
|
90
|
-
layers=args.layers,
|
91
|
-
force_load=args.force_load,
|
92
|
-
force_overwrite=args.force_overwrite,
|
93
|
-
merge_files=args.merge,
|
96
|
+
config,
|
94
97
|
)
|
95
98
|
|
96
99
|
# compare the pcaps
|
@@ -101,9 +104,11 @@ def main() -> None:
|
|
101
104
|
sys.exit()
|
102
105
|
|
103
106
|
if args.fsdb:
|
104
|
-
output = Fsdb(None,
|
107
|
+
output = Fsdb(None, config[TTD_CFG.KEY_DISSECTOR][TTD_CFG.FILTER_ARGUMENTS])
|
105
108
|
else:
|
106
|
-
output = Console(
|
109
|
+
output = Console(
|
110
|
+
None, config[TTD_CFG.KEY_DISSECTOR][TTD_CFG.FILTER_ARGUMENTS]
|
111
|
+
)
|
107
112
|
|
108
113
|
for report in reports:
|
109
114
|
# output results to the console
|
@@ -120,3 +125,6 @@ def main() -> None:
|
|
120
125
|
|
121
126
|
if __name__ == "__main__":
|
122
127
|
main()
|
128
|
+
config = TaffyConfig()
|
129
|
+
if config.get("dump", False):
|
130
|
+
config.dump()
|
@@ -0,0 +1,83 @@
|
|
1
|
+
"""Performs generic dissection of a PCAP file."""
|
2
|
+
import sys
|
3
|
+
import logging
|
4
|
+
import yaml
|
5
|
+
from traffic_taffy.taffy_config import TaffyConfig, TT_CFG
|
6
|
+
from rich_argparse import RichHelpFormatter
|
7
|
+
from argparse import ArgumentParser, Namespace
|
8
|
+
|
9
|
+
# these force configuration token loading in a way ruff won't "fix"
|
10
|
+
from traffic_taffy.dissector import TTD_CFG as TTD_CFG
|
11
|
+
from traffic_taffy.compare import TTC_CFG as TTC_CFG
|
12
|
+
from traffic_taffy.graph import TTG_CFG as TTG_CFG
|
13
|
+
from traffic_taffy.tools.compare import compare_parse_args as compare_parse_args
|
14
|
+
|
15
|
+
|
16
|
+
# we try to load a number of modules, but if the missing requirements aren't available
|
17
|
+
# we don't fail here
|
18
|
+
try:
|
19
|
+
from traffic_taffy.dissector_engine.scapy import (
|
20
|
+
DissectionEngineScapy as DissectionEngineScapy,
|
21
|
+
)
|
22
|
+
except ModuleNotFoundError:
|
23
|
+
logging.debug("scapy module not loadable")
|
24
|
+
|
25
|
+
try:
|
26
|
+
from traffic_taffy.hooks.ip2asn import ip_to_asn as ip_to_asn
|
27
|
+
except ModuleNotFoundError:
|
28
|
+
logging.debug("ip2asn module not loadable")
|
29
|
+
|
30
|
+
try:
|
31
|
+
from traffic_taffy.hooks.psl import split_dns_names as split_dns_names
|
32
|
+
except ModuleNotFoundError:
|
33
|
+
logging.debug("psl module not loadable")
|
34
|
+
|
35
|
+
|
36
|
+
def main() -> None:
|
37
|
+
"""Dissect a pcap file and report contents."""
|
38
|
+
|
39
|
+
def parse_args() -> Namespace:
|
40
|
+
"""Parse the command line arguments."""
|
41
|
+
|
42
|
+
config: TaffyConfig = TaffyConfig()
|
43
|
+
config.config_option_names = ["-y", "--config"]
|
44
|
+
config[TT_CFG.LOG_LEVEL] = "info"
|
45
|
+
|
46
|
+
config.read_configfile_from_arguments(sys.argv)
|
47
|
+
|
48
|
+
parser = ArgumentParser(
|
49
|
+
formatter_class=RichHelpFormatter,
|
50
|
+
description=__doc__,
|
51
|
+
epilog="Example Usage: taffy-config > defaults.yml",
|
52
|
+
)
|
53
|
+
|
54
|
+
parser.add_argument(
|
55
|
+
"-y",
|
56
|
+
"--config",
|
57
|
+
default=None,
|
58
|
+
type=str,
|
59
|
+
help="Configuration file (YAML) to load.",
|
60
|
+
)
|
61
|
+
|
62
|
+
parser.add_argument(
|
63
|
+
"--log-level",
|
64
|
+
"--ll",
|
65
|
+
default="info",
|
66
|
+
help="Define the logging verbosity level (debug, info, warning, error, fotal, critical).",
|
67
|
+
)
|
68
|
+
|
69
|
+
args = parser.parse_args()
|
70
|
+
log_level = args.log_level.upper()
|
71
|
+
logging.basicConfig(level=log_level, format="%(levelname)-10s:\t%(message)s")
|
72
|
+
|
73
|
+
config.load_namespace(args)
|
74
|
+
return config
|
75
|
+
|
76
|
+
config = parse_args()
|
77
|
+
config.as_namespace()
|
78
|
+
|
79
|
+
print(yaml.dump(dict(config)))
|
80
|
+
|
81
|
+
|
82
|
+
if __name__ == "__main__":
|
83
|
+
main()
|