Skip to content

Commit 01caa3b

Browse files
committed
Autodetect presence of pcap-converter for conversion, expliciet --tshark argument for using tshark even if pcap-converter is present
1 parent e72cb10 commit 01caa3b

File tree

1 file changed

+61
-22
lines changed

1 file changed

+61
-22
lines changed

src/main.py

+61-22
Original file line numberDiff line numberDiff line change
@@ -14,36 +14,45 @@
1414
from attack import Attack, Fingerprint
1515
from analysis import infer_target, extract_attack_vectors, compute_summary
1616
from util import parquet_files_to_view, FileType, determine_filetype, determine_source_filetype, \
17-
print_logo, parse_config
17+
print_logo, parse_config, is_executable_present
1818
from graphs import create_line_graph, create_bar_graph
1919

2020
DOCKERIZED: bool = 'DISSECTOR_DOCKER' in os.environ
2121

2222

2323
def parse_arguments() -> Namespace:
2424
parser = ArgumentParser()
25-
parser.add_argument('-f', '--file', type=Path, help='Path to Flow / PCAP file(s)', nargs='+', required=True,
26-
dest='files')
27-
parser.add_argument('--summary', action='store_true', help='Optional: print fingerprint without source addresses')
28-
parser.add_argument('-r', action='store_true', help='Optional: use experimental Rust pcap-converter')
29-
parser.add_argument('--output', type=Path, help='Path to directory in which to save the fingerprint '
30-
f'(default {"/data" if DOCKERIZED else "."}/fingerprints)',
31-
default=Path('/data/fingerprints') if DOCKERIZED else Path('./fingerprints'))
32-
parser.add_argument('--config', type=Path, help='Path to DDoS-DB and/or MISP config file (default /etc/config.ini)',
33-
default=Path('/etc/config.ini'))
34-
parser.add_argument('--nprocesses', dest='n', type=int, help='Number of processes used to concurrently read PCAPs '
35-
'(default is the number of CPU cores)',
36-
default=os.cpu_count())
25+
parser.add_argument('-f', '--file', type=Path, nargs='+', required=True, dest='files',
26+
help='Path to Flow / PCAP file(s)')
27+
parser.add_argument('--summary', action='store_true',
28+
help='Optional: print fingerprint without source addresses')
29+
# parser.add_argument('-r', action='store_true', help='Optional: use experimental Rust pcap-converter')
30+
parser.add_argument('--output', type=Path,
31+
default=Path('/data/fingerprints') if DOCKERIZED else Path('./fingerprints'),
32+
help='Path to directory in which to save the fingerprint '
33+
f'(default: {"/data" if DOCKERIZED else "."}/fingerprints)')
34+
parser.add_argument('--config', type=Path, default=Path('/etc/config.ini'),
35+
help='Path to DDoS-DB and/or MISP config file (default: /etc/config.ini)')
36+
parser.add_argument('--nprocesses', dest='n', type=int, default=os.cpu_count(),
37+
help='Number of processes used to read and process PCAPs '
38+
f'(default: number of CPU cores ({os.cpu_count()}))')
3739
parser.add_argument('--target', type=str, dest='target',
38-
help='Optional: target IP address of this attack (subnet currently unsupported)')
39-
parser.add_argument('--ddosdb', action='store_true', help='Optional: directly upload fingerprint to DDoS-DB')
40-
parser.add_argument('--misp', action='store_true', help='Optional: directly upload fingerprint to MISP')
40+
help='Optional: Specify target IP address of this attack (subnet currently unsupported)')
41+
parser.add_argument('--ddosdb', action='store_true',
42+
help='Optional: Directly upload fingerprint to DDoS-DB')
43+
parser.add_argument('--misp', action='store_true',
44+
help='Optional: Directly upload fingerprint to MISP')
4145
parser.add_argument('--graph', action='store_true',
4246
help='Optional: Create graphs of the attack, stored alongside the fingerprint')
43-
parser.add_argument('--noverify', action='store_true', help="Optional: Don't verify TLS certificates")
44-
parser.add_argument('--debug', action='store_true', help='Optional: show debug messages')
45-
parser.add_argument('--show-target', action='store_true', help='Optional: Do NOT anonymize the target IP address '
46-
'/ network in the fingerprint')
47+
parser.add_argument('--noverify', action='store_true',
48+
help="Optional: Do not verify TLS certificates (accept self-signed certificates)")
49+
parser.add_argument('--show-target', action='store_true',
50+
help='Optional: Do NOT anonymize the target IP address/network in the fingerprint')
51+
parser.add_argument('--tshark', action='store_true',
52+
help='Optional: Force use of tshark/tcpdump over pcap-converter, even if it is present')
53+
parser.add_argument('--debug', action='store_true',
54+
help='Optional: Show debug messages')
55+
4756
return parser.parse_args()
4857

4958

@@ -65,6 +74,32 @@ def parse_arguments() -> Namespace:
6574

6675
filetype = determine_filetype(args.files)
6776

77+
# Determine which of pcap-converter, tcpdump, tshark or nfdump are installed
78+
pcap_converter_ok = is_executable_present('pcap-converter')
79+
tcpdump_ok = is_executable_present('tcpdump')
80+
tshark_ok = is_executable_present('tshark')
81+
nfdump_ok = is_executable_present('nfdump')
82+
83+
# Error out early if one of the required executables (for the specified file type) is not present
84+
if filetype == FileType.PCAP and args.tshark and not tshark_ok:
85+
LOGGER.error("Use of tshark requested, but tshark cannot be found. Is it installed properly?")
86+
exit(1)
87+
88+
if filetype == FileType.PCAP and args.tshark and not tcpdump_ok:
89+
LOGGER.error("Use of tshark requested, but tcpdump is needed as well and cannot be found. Is it installed properly?")
90+
exit(1)
91+
92+
if filetype == FileType.PCAP and not args.tshark and not pcap_converter_ok and (not tshark_ok or not tcpdump_ok):
93+
tshark=' nor tshark' if not tshark_ok else ''
94+
tcpdump=' nor tcpdump' if not tcpdump_ok else ''
95+
LOGGER.error(f"Pcap file supplied, but neither pcap-converter{tshark}{tcpdump} can be found.")
96+
LOGGER.error(f"Please ensure that either pcap-converter OR tcpdump and tshark are installed")
97+
exit(1)
98+
99+
if filetype == FileType.FLOW and not nfdump_ok:
100+
LOGGER.error("Flow file supplied, but nfdump cannot be found. Is it installed properly?")
101+
exit(1)
102+
68103
start = time.time()
69104
if filetype == FileType.PQT:
70105
# If parquet files: check all contain data from either pcap or flow, but not both
@@ -79,8 +114,12 @@ def parse_arguments() -> Namespace:
79114
pqt_files = [str(f) for f in args.files]
80115
else:
81116
# Convert the file(s) to parquet
82-
dst_dir = tempfile.gettempdir() if DOCKERIZED else f"{os.getcwd()}/parquet"
83-
pqt_files = read_files(args.files, dst_dir=dst_dir, filetype=filetype, nr_processes=args.n, rust_converter=args.r)
117+
dst_dir = Path(tempfile.gettempdir()) if DOCKERIZED else Path(f"{os.getcwd()}/parquet")
118+
pqt_files = read_files(args.files,
119+
dst_dir=dst_dir,
120+
filetype=filetype,
121+
nr_processes=args.n,
122+
rust_converter=pcap_converter_ok and not args.tshark)
84123
duration = time.time()-start
85124
LOGGER.info(f"Conversion took {duration:.2f}s")
86125
LOGGER.debug(pqt_files)

0 commit comments

Comments
 (0)