atomicshop 2.15.13__py3-none-any.whl → 2.16.1__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.
Potentially problematic release.
This version of atomicshop might be problematic. Click here for more details.
- atomicshop/__init__.py +1 -1
- atomicshop/a_installs/ubuntu/pycharm.py +7 -0
- atomicshop/a_installs/win/pycharm.py +2 -2
- atomicshop/{addons/mains/install_wsl_ubuntu_lts_admin.py → a_installs/win/wsl_ubuntu_lts.py} +1 -0
- atomicshop/{addons/mains → a_mains}/FACT/update_extract.py +3 -2
- atomicshop/a_mains/dns_gateway_setting.py +11 -0
- atomicshop/basics/booleans.py +14 -5
- atomicshop/dns.py +104 -0
- atomicshop/file_io/docxs.py +8 -0
- atomicshop/file_io/tomls.py +133 -0
- atomicshop/filesystem.py +5 -4
- atomicshop/get_process_list.py +3 -3
- atomicshop/mitm/config_static.py +195 -0
- atomicshop/mitm/config_toml_editor.py +55 -0
- atomicshop/mitm/connection_thread_worker.py +54 -90
- atomicshop/mitm/import_config.py +148 -139
- atomicshop/mitm/initialize_engines.py +7 -2
- atomicshop/mitm/initialize_mitm_server.py +162 -107
- atomicshop/mitm/shared_functions.py +0 -1
- atomicshop/mitm/statistic_analyzer.py +13 -1
- atomicshop/mitm/statistic_analyzer_helper/moving_average_helper.py +54 -14
- atomicshop/permissions/__init__.py +0 -0
- atomicshop/permissions/permissions.py +22 -0
- atomicshop/{permissions.py → permissions/ubuntu_permissions.py} +4 -54
- atomicshop/permissions/win_permissions.py +33 -0
- atomicshop/script_as_string_processor.py +5 -1
- atomicshop/wrappers/cryptographyw.py +3 -3
- atomicshop/wrappers/dockerw/install_docker.py +6 -5
- atomicshop/wrappers/elasticsearchw/install_elastic.py +2 -1
- atomicshop/wrappers/factw/install/pre_install_and_install_before_restart.py +5 -4
- atomicshop/wrappers/mongodbw/install_mongodb.py +2 -1
- atomicshop/wrappers/msiw.py +2 -3
- atomicshop/wrappers/psutilw/networks.py +25 -1
- atomicshop/wrappers/pycharmw/__init__.py +0 -0
- atomicshop/wrappers/pycharmw/ubuntu.py +38 -0
- atomicshop/wrappers/{pycharmw.py → pycharmw/win.py} +2 -2
- atomicshop/wrappers/pywin32w/wmis/__init__.py +0 -0
- atomicshop/wrappers/pywin32w/wmis/helpers.py +127 -0
- atomicshop/wrappers/pywin32w/wmis/win32networkadapter.py +167 -0
- atomicshop/wrappers/socketw/accepter.py +8 -8
- atomicshop/wrappers/socketw/base.py +13 -0
- atomicshop/wrappers/socketw/certificator.py +202 -149
- atomicshop/wrappers/socketw/creator.py +15 -35
- atomicshop/wrappers/socketw/dns_server.py +155 -102
- atomicshop/wrappers/socketw/exception_wrapper.py +8 -27
- atomicshop/wrappers/socketw/get_process.py +115 -95
- atomicshop/wrappers/socketw/sni.py +298 -164
- atomicshop/wrappers/socketw/socket_client.py +5 -12
- atomicshop/wrappers/socketw/socket_server_tester.py +1 -1
- atomicshop/wrappers/socketw/socket_wrapper.py +328 -72
- atomicshop/wrappers/socketw/statistics_csv.py +94 -16
- atomicshop/wrappers/ubuntu_terminal.py +6 -6
- atomicshop/wrappers/wslw.py +1 -0
- {atomicshop-2.15.13.dist-info → atomicshop-2.16.1.dist-info}/METADATA +1 -1
- {atomicshop-2.15.13.dist-info → atomicshop-2.16.1.dist-info}/RECORD +63 -54
- atomicshop/addons/mains/__pycache__/install_fibratus_windows.cpython-312.pyc +0 -0
- atomicshop/addons/mains/__pycache__/msi_unpacker.cpython-312.pyc +0 -0
- atomicshop/mitm/config_editor.py +0 -37
- /atomicshop/{addons/mains/install_docker_rootless_ubuntu.py → a_installs/ubuntu/docker_rootless.py} +0 -0
- /atomicshop/{addons/mains/install_docker_ubuntu_main_sudo.py → a_installs/ubuntu/docker_sudo.py} +0 -0
- /atomicshop/{addons/mains/install_elastic_search_and_kibana_ubuntu.py → a_installs/ubuntu/elastic_search_and_kibana.py} +0 -0
- /atomicshop/{addons/mains → a_mains}/FACT/factw_fact_extractor_docker_image_main_sudo.py +0 -0
- /atomicshop/wrappers/pywin32w/{wmi_win32process.py → wmis/win32process.py} +0 -0
- {atomicshop-2.15.13.dist-info → atomicshop-2.16.1.dist-info}/LICENSE.txt +0 -0
- {atomicshop-2.15.13.dist-info → atomicshop-2.16.1.dist-info}/WHEEL +0 -0
- {atomicshop-2.15.13.dist-info → atomicshop-2.16.1.dist-info}/top_level.txt +0 -0
|
@@ -1,53 +1,57 @@
|
|
|
1
1
|
import os
|
|
2
|
-
import sys
|
|
3
2
|
import threading
|
|
4
3
|
import time
|
|
5
4
|
|
|
6
|
-
# Importing atomicshop package to get the version of the package.
|
|
7
|
-
import atomicshop
|
|
5
|
+
import atomicshop # Importing atomicshop package to get the version of the package.
|
|
8
6
|
|
|
9
|
-
from
|
|
10
|
-
from
|
|
11
|
-
from .connection_thread_worker import thread_worker_main
|
|
12
|
-
from .. import filesystem, queues
|
|
7
|
+
from .. import filesystem, queues, dns, on_exit
|
|
8
|
+
from ..permissions import permissions
|
|
13
9
|
from ..python_functions import get_current_python_version_string, check_python_version_compliance
|
|
14
|
-
from ..wrappers.socketw
|
|
15
|
-
from ..wrappers.socketw import dns_server
|
|
16
|
-
from ..wrappers.psutilw import networks
|
|
17
|
-
from ..basics import dicts_nested
|
|
10
|
+
from ..wrappers.socketw import socket_wrapper, dns_server, base
|
|
18
11
|
from ..wrappers.loggingw import loggingw
|
|
19
12
|
from ..print_api import print_api
|
|
20
13
|
|
|
14
|
+
from .initialize_engines import ModuleCategory
|
|
15
|
+
from .connection_thread_worker import thread_worker_main
|
|
16
|
+
from . import config_static
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def exit_cleanup():
|
|
20
|
+
if config_static.DNSServer.set_default_dns_gateway:
|
|
21
|
+
is_dns_dynamic, current_dns_gateway = dns.get_default_dns_gateway()
|
|
22
|
+
print_api(f'Current DNS Gateway: {current_dns_gateway}')
|
|
21
23
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
if current_dns_gateway == config_static.DNSServer.set_default_dns_gateway and not is_dns_dynamic:
|
|
25
|
+
if permissions.is_admin():
|
|
26
|
+
dns.set_connection_dns_gateway_dynamic(use_default_connection=True)
|
|
27
|
+
print_api("Returned default DNS gateway...", color='blue')
|
|
24
28
|
|
|
25
29
|
|
|
26
|
-
def initialize_mitm_server(
|
|
30
|
+
def initialize_mitm_server(config_file_path: str):
|
|
31
|
+
on_exit.register_exit_handler(exit_cleanup)
|
|
32
|
+
|
|
27
33
|
# Main function should return integer with error code, 0 is successful.
|
|
28
34
|
# Since listening server is infinite, this will not be reached.
|
|
29
35
|
# After modules import - we check for python version.
|
|
30
36
|
check_python_version_compliance(minimum_version='3.11')
|
|
31
37
|
|
|
32
|
-
#
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
config_importer.open()
|
|
37
|
-
config = config_importer.config
|
|
38
|
+
# Import the configuration file.
|
|
39
|
+
result = config_static.load_config(config_file_path)
|
|
40
|
+
if result != 0:
|
|
41
|
+
return result
|
|
38
42
|
|
|
39
43
|
# Create folders.
|
|
40
|
-
filesystem.create_directory(
|
|
41
|
-
filesystem.create_directory(
|
|
42
|
-
if
|
|
44
|
+
filesystem.create_directory(config_static.Log.logs_path)
|
|
45
|
+
filesystem.create_directory(config_static.Recorder.recordings_path)
|
|
46
|
+
if config_static.Certificates.sni_get_server_certificate_from_server_socket:
|
|
43
47
|
filesystem.create_directory(
|
|
44
|
-
|
|
48
|
+
config_static.Certificates.sni_server_certificate_from_server_socket_download_directory)
|
|
45
49
|
|
|
46
50
|
# Create a logger that will log messages to file, Initiate System logger.
|
|
47
51
|
logger_name = "system"
|
|
48
52
|
system_logger = loggingw.create_logger(
|
|
49
53
|
logger_name=logger_name,
|
|
50
|
-
file_path=f"{
|
|
54
|
+
file_path=f"{config_static.Log.logs_path}{os.sep}{logger_name}.txt",
|
|
51
55
|
add_stream=True,
|
|
52
56
|
add_timedfile=True,
|
|
53
57
|
formatter_streamhandler='DEFAULT',
|
|
@@ -56,44 +60,37 @@ def initialize_mitm_server(config_static):
|
|
|
56
60
|
|
|
57
61
|
# Writing first log.
|
|
58
62
|
system_logger.info("======================================")
|
|
59
|
-
|
|
60
|
-
if config_importer.admin_rights is not None:
|
|
61
|
-
if not config_importer.admin_rights:
|
|
62
|
-
system_logger.error("User continued with errors on Command Line harvesting for system processes.")
|
|
63
|
-
|
|
64
63
|
system_logger.info("Server Started.")
|
|
65
64
|
system_logger.info(f"Python Version: {get_current_python_version_string()}")
|
|
66
65
|
system_logger.info(f"Script Version: {config_static.SCRIPT_VERSION}")
|
|
67
66
|
system_logger.info(f"Atomic Workshop Version: {atomicshop.__version__}")
|
|
68
|
-
system_logger.info(f"
|
|
69
|
-
system_logger.info(f"
|
|
70
|
-
system_logger.info(f"Recordings folder for Requests/Responses: {config['recorder']['recordings_path']}")
|
|
67
|
+
system_logger.info(f"Log folder: {config_static.Log.logs_path}")
|
|
68
|
+
system_logger.info(f"Recordings folder for Requests/Responses: {config_static.Recorder.recordings_path}")
|
|
71
69
|
system_logger.info(f"Loaded system logger: {system_logger}")
|
|
72
70
|
|
|
73
|
-
system_logger.info(f"TCP Server Target IP: {
|
|
71
|
+
system_logger.info(f"TCP Server Target IP: {config_static.DNSServer.target_tcp_server_ipv4}")
|
|
74
72
|
|
|
75
73
|
# Some 'config.ini' settings logging ===========================================================================
|
|
76
|
-
if
|
|
74
|
+
if config_static.Certificates.default_server_certificate_usage:
|
|
77
75
|
system_logger.info(
|
|
78
76
|
f"Default server certificate usage enabled, if no SNI available: "
|
|
79
|
-
f"{config_static.
|
|
80
|
-
f"{os.sep}{config_static.CONFIG_EXTENDED['certificates']['default_server_certificate_name']}.pem")
|
|
77
|
+
f"{config_static.MainConfig.default_server_certificate_filepath}")
|
|
81
78
|
|
|
82
|
-
if
|
|
79
|
+
if config_static.Certificates.sni_server_certificates_cache_directory:
|
|
83
80
|
system_logger.info(
|
|
84
81
|
f"SNI function certificates creation enabled. Certificates cache: "
|
|
85
|
-
f"{
|
|
82
|
+
f"{config_static.Certificates.sni_server_certificates_cache_directory}")
|
|
86
83
|
else:
|
|
87
84
|
system_logger.info(f"SNI function certificates creation disabled.")
|
|
88
85
|
|
|
89
|
-
if
|
|
86
|
+
if config_static.Certificates.custom_server_certificate_usage:
|
|
90
87
|
system_logger.info(f"Custom server certificate usage is enabled.")
|
|
91
|
-
system_logger.info(f"Custom Certificate Path: {
|
|
88
|
+
system_logger.info(f"Custom Certificate Path: {config_static.Certificates.custom_server_certificate_path}")
|
|
92
89
|
|
|
93
90
|
# If 'custom_private_key_path' field was populated.
|
|
94
|
-
if
|
|
91
|
+
if config_static.Certificates.custom_private_key_path:
|
|
95
92
|
system_logger.info(
|
|
96
|
-
f"Custom Certificate Private Key Path: {
|
|
93
|
+
f"Custom Certificate Private Key Path: {config_static.Certificates.custom_private_key_path}")
|
|
97
94
|
else:
|
|
98
95
|
system_logger.info(f"Custom Certificate Private Key Path wasn't provided in [advanced] section. "
|
|
99
96
|
f"Assuming the private key is inside the certificate file.")
|
|
@@ -103,17 +100,17 @@ def initialize_mitm_server(config_static):
|
|
|
103
100
|
|
|
104
101
|
# Get full paths of all the 'engine_config.ini' files.
|
|
105
102
|
engine_config_path_list = filesystem.get_file_paths_from_directory(
|
|
106
|
-
directory_path=config_static.ENGINES_DIRECTORY_PATH,
|
|
107
|
-
file_name_check_pattern=config_static.ENGINE_CONFIG_FILE_NAME)
|
|
103
|
+
directory_path=config_static.MainConfig.ENGINES_DIRECTORY_PATH,
|
|
104
|
+
file_name_check_pattern=config_static.MainConfig.ENGINE_CONFIG_FILE_NAME)
|
|
108
105
|
|
|
109
106
|
# Iterate through all the 'engine_config.ini' file paths.
|
|
110
107
|
domains_engine_list_full: list = list()
|
|
111
108
|
engines_list: list = list()
|
|
112
109
|
for engine_config_path in engine_config_path_list:
|
|
113
110
|
# Initialize engine.
|
|
114
|
-
current_module = ModuleCategory(config_static.
|
|
111
|
+
current_module = ModuleCategory(config_static.MainConfig.SCRIPT_DIRECTORY)
|
|
115
112
|
current_module.fill_engine_fields_from_config(engine_config_path)
|
|
116
|
-
current_module.initialize_engine(logs_path=
|
|
113
|
+
current_module.initialize_engine(logs_path=config_static.Log.logs_path,
|
|
117
114
|
logger=system_logger)
|
|
118
115
|
|
|
119
116
|
# Extending the full engine domain list with this list.
|
|
@@ -122,9 +119,9 @@ def initialize_mitm_server(config_static):
|
|
|
122
119
|
engines_list.append(current_module)
|
|
123
120
|
# === EOF Importing engine modules =============================================================================
|
|
124
121
|
# ==== Initialize Reference Module =============================================================================
|
|
125
|
-
reference_module = ModuleCategory(config_static.
|
|
126
|
-
reference_module.fill_engine_fields_from_general_reference(config_static.ENGINES_DIRECTORY_PATH)
|
|
127
|
-
reference_module.initialize_engine(logs_path=
|
|
122
|
+
reference_module = ModuleCategory(config_static.MainConfig.SCRIPT_DIRECTORY)
|
|
123
|
+
reference_module.fill_engine_fields_from_general_reference(config_static.MainConfig.ENGINES_DIRECTORY_PATH)
|
|
124
|
+
reference_module.initialize_engine(logs_path=config_static.Log.logs_path,
|
|
128
125
|
logger=system_logger, stdout=False, reference_general=True)
|
|
129
126
|
# === EOF Initialize Reference Module ==========================================================================
|
|
130
127
|
# === Engine logging ===========================================================================================
|
|
@@ -139,41 +136,41 @@ def initialize_mitm_server(config_static):
|
|
|
139
136
|
f"{engine.recorder_class_object.__name__}")
|
|
140
137
|
print_api(message, logger=system_logger)
|
|
141
138
|
|
|
142
|
-
if
|
|
139
|
+
if config_static.DNSServer.enable:
|
|
143
140
|
print_api("DNS Server is enabled.", logger=system_logger)
|
|
144
141
|
|
|
145
142
|
# If engines were found and dns is set to route by the engine domains.
|
|
146
|
-
if engines_list and
|
|
143
|
+
if engines_list and config_static.DNSServer.resolve_to_tcp_server_only_engine_domains:
|
|
147
144
|
print_api("Engine domains will be routed by the DNS server to Built-in TCP Server.", logger=system_logger)
|
|
148
145
|
# If engines were found, but the dns isn't set to route to engines.
|
|
149
|
-
elif engines_list and not
|
|
146
|
+
elif engines_list and not config_static.DNSServer.resolve_to_tcp_server_only_engine_domains:
|
|
150
147
|
message = f"[*] Engine domains found, but the DNS routing is set not to use them for routing."
|
|
151
148
|
print_api(message, color="yellow", logger=system_logger)
|
|
152
|
-
elif not engines_list and
|
|
149
|
+
elif not engines_list and config_static.DNSServer.resolve_to_tcp_server_only_engine_domains:
|
|
153
150
|
raise ValueError("No engines were found, but the DNS routing is set to use them for routing.\n"
|
|
154
151
|
"Please check your DNS configuration in the 'config.ini' file.")
|
|
155
152
|
|
|
156
|
-
if
|
|
153
|
+
if config_static.DNSServer.resolve_to_tcp_server_all_domains:
|
|
157
154
|
print_api("All domains will be routed by the DNS server to Built-in TCP Server.", logger=system_logger)
|
|
158
155
|
|
|
159
|
-
if
|
|
156
|
+
if config_static.DNSServer.resolve_regular:
|
|
160
157
|
print_api(
|
|
161
158
|
"Regular DNS resolving is enabled. Built-in TCP server will not be routed to",
|
|
162
159
|
logger=system_logger, color="yellow")
|
|
163
160
|
else:
|
|
164
161
|
print_api("DNS Server is disabled.", logger=system_logger, color="yellow")
|
|
165
162
|
|
|
166
|
-
if
|
|
163
|
+
if config_static.TCPServer.enable:
|
|
167
164
|
print_api("TCP Server is enabled.", logger=system_logger)
|
|
168
165
|
|
|
169
|
-
if engines_list and not
|
|
166
|
+
if engines_list and not config_static.TCPServer.engines_usage:
|
|
170
167
|
message = \
|
|
171
168
|
f"Engines found, but the TCP server is set not to use them for processing. General responses only."
|
|
172
169
|
print_api(message, color="yellow", logger=system_logger)
|
|
173
|
-
elif engines_list and
|
|
170
|
+
elif engines_list and config_static.TCPServer.engines_usage:
|
|
174
171
|
message = f"Engines found, and the TCP server is set to use them for processing."
|
|
175
172
|
print_api(message, logger=system_logger)
|
|
176
|
-
elif not engines_list and
|
|
173
|
+
elif not engines_list and config_static.TCPServer.engines_usage:
|
|
177
174
|
raise ValueError("No engines were found, but the TCP server is set to use them for processing.\n"
|
|
178
175
|
"Please check your TCP configuration in the 'config.ini' file.")
|
|
179
176
|
else:
|
|
@@ -182,22 +179,12 @@ def initialize_mitm_server(config_static):
|
|
|
182
179
|
# === EOF Engine Logging =======================================================================================
|
|
183
180
|
|
|
184
181
|
# Assigning all the engines domains to all time domains, that will be responsible for adding new domains.
|
|
185
|
-
config_static.
|
|
186
|
-
|
|
187
|
-
# Creating Statistics logger.
|
|
188
|
-
statistics_logger = loggingw.create_logger(
|
|
189
|
-
logger_name="statistics",
|
|
190
|
-
directory_path=config['log']['logs_path'],
|
|
191
|
-
add_timedfile=True,
|
|
192
|
-
formatter_filehandler='MESSAGE',
|
|
193
|
-
file_type='csv',
|
|
194
|
-
header=STATISTICS_HEADER
|
|
195
|
-
)
|
|
182
|
+
config_static.Certificates.domains_all_times = list(domains_engine_list_full)
|
|
196
183
|
|
|
197
184
|
network_logger_name = "network"
|
|
198
185
|
network_logger = loggingw.create_logger(
|
|
199
186
|
logger_name=network_logger_name,
|
|
200
|
-
directory_path=
|
|
187
|
+
directory_path=config_static.Log.logs_path,
|
|
201
188
|
add_stream=True,
|
|
202
189
|
add_timedfile=True,
|
|
203
190
|
formatter_streamhandler='DEFAULT',
|
|
@@ -209,60 +196,128 @@ def initialize_mitm_server(config_static):
|
|
|
209
196
|
listener_logger = loggingw.get_logger_with_level(f'{network_logger_name}.listener')
|
|
210
197
|
system_logger.info(f"Loaded listener logger: {listener_logger}")
|
|
211
198
|
|
|
199
|
+
print_api("Press [Ctrl]+[C] to stop.", color='blue')
|
|
200
|
+
|
|
212
201
|
# Create request domain queue.
|
|
213
202
|
domain_queue = queues.NonBlockQueue()
|
|
214
203
|
|
|
215
204
|
# === Initialize DNS module ====================================================================================
|
|
216
|
-
if
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
205
|
+
if config_static.DNSServer.enable:
|
|
206
|
+
try:
|
|
207
|
+
dns_server_instance = dns_server.DnsServer(
|
|
208
|
+
listening_interface=config_static.DNSServer.listening_interface,
|
|
209
|
+
listening_port=config_static.DNSServer.listening_port,
|
|
210
|
+
forwarding_dns_service_ipv4=config_static.DNSServer.forwarding_dns_service_ipv4,
|
|
211
|
+
tcp_target_server_ipv4=config_static.DNSServer.target_tcp_server_ipv4,
|
|
212
|
+
# Passing the engine domain list to DNS server to work with.
|
|
213
|
+
# 'list' function re-initializes the current list, or else it will be the same instance object.
|
|
214
|
+
tcp_resolve_domain_list=list(config_static.Certificates.domains_all_times),
|
|
215
|
+
log_directory_path=config_static.Log.logs_path,
|
|
216
|
+
offline_mode=config_static.DNSServer.offline_mode,
|
|
217
|
+
resolve_to_tcp_server_only_tcp_resolve_domains=(
|
|
218
|
+
config_static.DNSServer.resolve_to_tcp_server_only_engine_domains),
|
|
219
|
+
resolve_to_tcp_server_all_domains=config_static.DNSServer.resolve_to_tcp_server_all_domains,
|
|
220
|
+
resolve_regular=config_static.DNSServer.resolve_regular,
|
|
221
|
+
cache_timeout_minutes=config_static.DNSServer.cache_timeout_minutes,
|
|
222
|
+
request_domain_queue=domain_queue
|
|
223
|
+
)
|
|
224
|
+
except (dns_server.DnsPortInUseError, dns_server.DnsConfigurationValuesError) as e:
|
|
225
|
+
print_api(e, error_type=True, color="red", logger=system_logger)
|
|
224
226
|
# Wait for the message to be printed and saved to file.
|
|
225
227
|
time.sleep(1)
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
# before executing TCP sockets and after executing 'network' logger.
|
|
229
|
-
dns_server_instance = dns_server.DnsServer(config)
|
|
230
|
-
# Passing the engine domain list to DNS server to work with.
|
|
231
|
-
# 'list' function re-initializes the current list, or else it will be the same instance object.
|
|
232
|
-
dns_server_instance.domain_list = list(domains_engine_list_full)
|
|
228
|
+
return 1
|
|
233
229
|
|
|
234
|
-
dns_server_instance.request_domain_queue = domain_queue
|
|
235
|
-
# Initiate the thread.
|
|
236
230
|
dns_thread = threading.Thread(target=dns_server_instance.start)
|
|
237
231
|
dns_thread.daemon = True
|
|
238
232
|
dns_thread.start()
|
|
239
233
|
|
|
240
234
|
# === EOF Initialize DNS module ================================================================================
|
|
241
235
|
# === Initialize TCP Server ====================================================================================
|
|
242
|
-
if
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
236
|
+
if config_static.TCPServer.enable:
|
|
237
|
+
try:
|
|
238
|
+
socket_wrapper_instance = socket_wrapper.SocketWrapper(
|
|
239
|
+
listening_interface=config_static.TCPServer.listening_interface,
|
|
240
|
+
listening_port_list=config_static.TCPServer.listening_port_list,
|
|
241
|
+
ca_certificate_name=config_static.MainConfig.ca_certificate_name,
|
|
242
|
+
ca_certificate_filepath=config_static.MainConfig.ca_certificate_filepath,
|
|
243
|
+
default_server_certificate_usage=config_static.Certificates.default_server_certificate_usage,
|
|
244
|
+
default_server_certificate_name=config_static.MainConfig.default_server_certificate_name,
|
|
245
|
+
default_certificate_domain_list=config_static.Certificates.domains_all_times,
|
|
246
|
+
default_server_certificate_directory=config_static.MainConfig.SCRIPT_DIRECTORY,
|
|
247
|
+
sni_use_default_callback_function=True,
|
|
248
|
+
sni_use_default_callback_function_extended=True,
|
|
249
|
+
sni_add_new_domains_to_default_server_certificate=(
|
|
250
|
+
config_static.Certificates.sni_add_new_domains_to_default_server_certificate),
|
|
251
|
+
sni_create_server_certificate_for_each_domain=(
|
|
252
|
+
config_static.Certificates.sni_create_server_certificate_for_each_domain),
|
|
253
|
+
sni_server_certificates_cache_directory=(
|
|
254
|
+
config_static.Certificates.sni_server_certificates_cache_directory),
|
|
255
|
+
sni_get_server_certificate_from_server_socket=(
|
|
256
|
+
config_static.Certificates.sni_get_server_certificate_from_server_socket),
|
|
257
|
+
sni_server_certificate_from_server_socket_download_directory=(
|
|
258
|
+
config_static.Certificates.sni_server_certificate_from_server_socket_download_directory),
|
|
259
|
+
custom_server_certificate_usage=config_static.Certificates.custom_server_certificate_usage,
|
|
260
|
+
custom_server_certificate_path=config_static.Certificates.custom_server_certificate_path,
|
|
261
|
+
custom_private_key_path=config_static.Certificates.custom_private_key_path,
|
|
262
|
+
get_process_name=config_static.ProcessName.get_process_name,
|
|
263
|
+
ssh_user=config_static.ProcessName.ssh_user,
|
|
264
|
+
ssh_pass=config_static.ProcessName.ssh_pass,
|
|
265
|
+
ssh_script_to_execute=config_static.ProcessName.ssh_script_to_execute,
|
|
266
|
+
logger=listener_logger,
|
|
267
|
+
statistics_logs_directory=config_static.Log.logs_path,
|
|
268
|
+
forwarding_dns_service_ipv4_list___only_for_localhost=(
|
|
269
|
+
config_static.TCPServer.forwarding_dns_service_ipv4_list___only_for_localhost),
|
|
270
|
+
skip_extension_id_list=config_static.SkipExtensions.SKIP_EXTENSION_ID_LIST
|
|
271
|
+
)
|
|
272
|
+
except socket_wrapper.SocketWrapperPortInUseError as e:
|
|
273
|
+
print_api(e, error_type=True, color="red", logger=system_logger)
|
|
248
274
|
# Wait for the message to be printed and saved to file.
|
|
249
275
|
time.sleep(1)
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
276
|
+
return 1
|
|
277
|
+
|
|
278
|
+
statistics_writer = socket_wrapper_instance.statistics_writer
|
|
279
|
+
|
|
280
|
+
socket_wrapper_instance.create_tcp_listening_socket_list()
|
|
281
|
+
|
|
282
|
+
socket_wrapper_instance.requested_domain_from_dns_server = domain_queue
|
|
283
|
+
|
|
284
|
+
# Before we start the loop. we can set the default gateway if specified.
|
|
285
|
+
set_dns_gateway = False
|
|
286
|
+
dns_gateway_server_list = list()
|
|
287
|
+
if config_static.DNSServer.set_default_dns_gateway:
|
|
288
|
+
dns_gateway_server_list = config_static.DNSServer.set_default_dns_gateway
|
|
289
|
+
set_dns_gateway = True
|
|
290
|
+
elif config_static.DNSServer.set_default_dns_gateway_to_localhost:
|
|
291
|
+
dns_gateway_server_list = [base.LOCALHOST_IPV4]
|
|
292
|
+
set_dns_gateway = True
|
|
293
|
+
elif config_static.DNSServer.set_default_dns_gateway_to_default_interface_ipv4:
|
|
294
|
+
dns_gateway_server_list = [base.DEFAULT_IPV4]
|
|
295
|
+
set_dns_gateway = True
|
|
296
|
+
|
|
297
|
+
if set_dns_gateway:
|
|
298
|
+
# noinspection PyTypeChecker
|
|
299
|
+
dns.set_connection_dns_gateway_static(
|
|
300
|
+
dns_servers=dns_gateway_server_list,
|
|
301
|
+
use_default_connection=True
|
|
302
|
+
)
|
|
259
303
|
|
|
260
304
|
# General exception handler will catch all the exceptions that occurred in the threads and write it to the log.
|
|
305
|
+
# noinspection PyBroadException
|
|
261
306
|
try:
|
|
262
|
-
|
|
263
|
-
|
|
307
|
+
socket_thread = threading.Thread(
|
|
308
|
+
target=socket_wrapper_instance.loop_for_incoming_sockets,
|
|
309
|
+
kwargs={
|
|
310
|
+
'reference_function_name': thread_worker_main,
|
|
311
|
+
'reference_function_args': (network_logger, statistics_writer, engines_list, reference_module,)
|
|
312
|
+
}
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
socket_thread.daemon = True
|
|
316
|
+
socket_thread.start()
|
|
264
317
|
except Exception:
|
|
265
318
|
message = f"Unhandled Exception occurred in 'loop_for_incoming_sockets' function"
|
|
266
319
|
print_api(message, error_type=True, color="red", logger=network_logger, traceback_string=True, oneline=True)
|
|
267
320
|
|
|
268
|
-
|
|
321
|
+
# This is needed for Keyboard Exception.
|
|
322
|
+
while True:
|
|
323
|
+
time.sleep(1)
|
|
@@ -346,6 +346,7 @@ def analyze(main_file_path: str):
|
|
|
346
346
|
|
|
347
347
|
def deviation_calculator_by_moving_average_main(
|
|
348
348
|
statistics_file_directory: str,
|
|
349
|
+
by_type: Literal['host', 'url'],
|
|
349
350
|
moving_average_window_days: int,
|
|
350
351
|
top_bottom_deviation_percentage: float,
|
|
351
352
|
get_deviation_for_last_day_only: bool = False,
|
|
@@ -359,6 +360,9 @@ def deviation_calculator_by_moving_average_main(
|
|
|
359
360
|
:param statistics_file_directory: string, the directory where 'statistics.csv' file resides.
|
|
360
361
|
Also, all the rotated files like: statistics_2021-01-01.csv, statistics_2021-01-02.csv, etc.
|
|
361
362
|
These will be analyzed in the order of the date in the file name.
|
|
363
|
+
:param by_type: string, 'host' or 'url'. The type of the deviation calculation.
|
|
364
|
+
'host' will calculate the deviation by the host name. Example: maps.google.com, yahoo.com, etc.
|
|
365
|
+
'url' will calculate the deviation by the URL. Example: maps.google.com/maps, yahoo.com/news, etc.
|
|
362
366
|
:param moving_average_window_days: integer, the moving average window days.
|
|
363
367
|
:param top_bottom_deviation_percentage: float, the top bottom deviation percentage. Example: 0.1 for 10%.
|
|
364
368
|
:param get_deviation_for_last_day_only: bool, if True, only the last day will be analyzed.
|
|
@@ -402,6 +406,9 @@ def deviation_calculator_by_moving_average_main(
|
|
|
402
406
|
if output_file_type not in ['json', 'csv']:
|
|
403
407
|
raise ValueError(f'output_file_type must be "json" or "csv", not [{output_file_type}]')
|
|
404
408
|
|
|
409
|
+
if by_type not in ['host', 'url']:
|
|
410
|
+
raise ValueError(f'by_type must be "host" or "url", not [{by_type}]')
|
|
411
|
+
|
|
405
412
|
statistics_file_path: str = f'{statistics_file_directory}{os.sep}{STATISTICS_FILE_NAME}'
|
|
406
413
|
|
|
407
414
|
def convert_data_value_to_string(value_key: str, list_index: int) -> None:
|
|
@@ -413,6 +420,7 @@ def deviation_calculator_by_moving_average_main(
|
|
|
413
420
|
|
|
414
421
|
deviation_list = moving_average_helper.calculate_moving_average(
|
|
415
422
|
statistics_file_path,
|
|
423
|
+
by_type,
|
|
416
424
|
moving_average_window_days,
|
|
417
425
|
top_bottom_deviation_percentage,
|
|
418
426
|
get_deviation_for_last_day_only
|
|
@@ -436,7 +444,11 @@ def deviation_calculator_by_moving_average_main(
|
|
|
436
444
|
'value': deviation.get('value', None),
|
|
437
445
|
'ma_value': deviation.get('ma_value', None),
|
|
438
446
|
'deviation_percentage': deviation.get('deviation_percentage', None),
|
|
439
|
-
'total_entries_averaged': total_entries_averaged
|
|
447
|
+
'total_entries_averaged': total_entries_averaged,
|
|
448
|
+
'median_request_size': deviation.get('median_request_size', None),
|
|
449
|
+
'median_response_size': deviation.get('median_response_size', None),
|
|
450
|
+
'mm_request_size': deviation.get('mm_request_size', None),
|
|
451
|
+
'mm_response_size': deviation.get('mm_response_size', None),
|
|
440
452
|
})
|
|
441
453
|
|
|
442
454
|
deviation_list = summary_deviation_list
|
|
@@ -4,10 +4,12 @@ from typing import Literal
|
|
|
4
4
|
from ...print_api import print_api
|
|
5
5
|
from ...wrappers.loggingw import reading, consts
|
|
6
6
|
from ...file_io import csvs
|
|
7
|
+
from ... import urls
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
def calculate_moving_average(
|
|
10
11
|
file_path: str,
|
|
12
|
+
by_type: Literal['host', 'url'],
|
|
11
13
|
moving_average_window_days,
|
|
12
14
|
top_bottom_deviation_percentage: float,
|
|
13
15
|
get_deviation_for_last_day_only: bool = False,
|
|
@@ -17,6 +19,7 @@ def calculate_moving_average(
|
|
|
17
19
|
This function calculates the moving average of the daily statistics.
|
|
18
20
|
|
|
19
21
|
:param file_path: string, the path to the 'statistics.csv' file.
|
|
22
|
+
:param by_type: string, the type to calculate the moving average by. Can be 'host' or 'url'.
|
|
20
23
|
:param moving_average_window_days: integer, the window size for the moving average.
|
|
21
24
|
:param top_bottom_deviation_percentage: float, the percentage of deviation from the moving average to the top or
|
|
22
25
|
bottom.
|
|
@@ -65,8 +68,7 @@ def calculate_moving_average(
|
|
|
65
68
|
|
|
66
69
|
# Get the data dictionary from the statistics content.
|
|
67
70
|
statistics_content[date_string]['statistics_daily'] = compute_statistics_from_content(
|
|
68
|
-
statistics_content[date_string]['content_no_errors']
|
|
69
|
-
)
|
|
71
|
+
statistics_content[date_string]['content_no_errors'], by_type)
|
|
70
72
|
|
|
71
73
|
moving_average_dict: dict = compute_moving_averages_from_average_statistics(
|
|
72
74
|
statistics_content,
|
|
@@ -106,19 +108,36 @@ def get_content_without_errors(content: list) -> list:
|
|
|
106
108
|
return traffic_statistics_without_errors
|
|
107
109
|
|
|
108
110
|
|
|
109
|
-
def get_data_dict_from_statistics_content(
|
|
111
|
+
def get_data_dict_from_statistics_content(
|
|
112
|
+
content: list,
|
|
113
|
+
by_type: Literal['host', 'url']
|
|
114
|
+
) -> dict:
|
|
110
115
|
"""
|
|
111
116
|
This function gets the data dictionary from the 'statistics.csv' file content.
|
|
112
117
|
|
|
113
118
|
:param content: list, the content list.
|
|
119
|
+
:param by_type: string, the type to calculate the moving average by. Can be 'host' or 'url'.
|
|
114
120
|
:return: dict, the data dictionary.
|
|
115
121
|
"""
|
|
116
122
|
|
|
117
123
|
hosts_requests_responses: dict = {}
|
|
118
124
|
for line in content:
|
|
125
|
+
if by_type == 'host':
|
|
126
|
+
type_to_check: str = line['host']
|
|
127
|
+
elif by_type == 'url':
|
|
128
|
+
# Combine host and path to URL.
|
|
129
|
+
type_to_check: str = line['host'] + line['path']
|
|
130
|
+
# Remove the parameters from the URL.
|
|
131
|
+
url_parsed = urls.url_parser(type_to_check)
|
|
132
|
+
type_to_check = url_parsed['path']
|
|
133
|
+
# Remove the last slash from the URL.
|
|
134
|
+
type_to_check = type_to_check.removesuffix('/')
|
|
135
|
+
else:
|
|
136
|
+
raise ValueError(f'Invalid by_type: {by_type}')
|
|
137
|
+
|
|
119
138
|
# If subdomain is not in the dictionary, add it.
|
|
120
|
-
if
|
|
121
|
-
hosts_requests_responses[
|
|
139
|
+
if type_to_check not in hosts_requests_responses:
|
|
140
|
+
hosts_requests_responses[type_to_check] = {
|
|
122
141
|
'request_sizes': [],
|
|
123
142
|
'response_sizes': []
|
|
124
143
|
}
|
|
@@ -132,8 +151,8 @@ def get_data_dict_from_statistics_content(content: list) -> dict:
|
|
|
132
151
|
if response_size_bytes == '':
|
|
133
152
|
response_size_bytes = '0'
|
|
134
153
|
|
|
135
|
-
hosts_requests_responses[
|
|
136
|
-
hosts_requests_responses[
|
|
154
|
+
hosts_requests_responses[type_to_check]['request_sizes'].append(int(request_size_bytes))
|
|
155
|
+
hosts_requests_responses[type_to_check]['response_sizes'].append(int(response_size_bytes))
|
|
137
156
|
except ValueError:
|
|
138
157
|
print_api(line, color='yellow')
|
|
139
158
|
raise
|
|
@@ -163,18 +182,22 @@ def compute_statistics_from_data_dict(data_dict: dict):
|
|
|
163
182
|
data_dict[host]['median_response_size'] = median_response_size
|
|
164
183
|
|
|
165
184
|
|
|
166
|
-
def compute_statistics_from_content(
|
|
185
|
+
def compute_statistics_from_content(
|
|
186
|
+
content: list,
|
|
187
|
+
by_type: Literal['host', 'url']
|
|
188
|
+
):
|
|
167
189
|
"""
|
|
168
190
|
This function computes the statistics from the 'statistics.csv' file content.
|
|
169
191
|
|
|
170
192
|
:param content: list, the content list.
|
|
193
|
+
:param by_type: string, the type to calculate the moving average by. Can be 'host' or 'url'.
|
|
171
194
|
:return: dict, the statistics dictionary.
|
|
172
195
|
"""
|
|
173
196
|
|
|
174
|
-
|
|
175
|
-
compute_statistics_from_data_dict(
|
|
197
|
+
requests_responses: dict = get_data_dict_from_statistics_content(content, by_type)
|
|
198
|
+
compute_statistics_from_data_dict(requests_responses)
|
|
176
199
|
|
|
177
|
-
return
|
|
200
|
+
return requests_responses
|
|
178
201
|
|
|
179
202
|
|
|
180
203
|
def compute_moving_averages_from_average_statistics(
|
|
@@ -200,12 +223,15 @@ def compute_moving_averages_from_average_statistics(
|
|
|
200
223
|
list(average_statistics_dict.values()))[current_day-moving_average_window_days:current_day]
|
|
201
224
|
|
|
202
225
|
# Compute the moving averages.
|
|
203
|
-
moving_average[day] = compute_average_for_current_day_from_past_x_days(
|
|
226
|
+
moving_average[day] = compute_average_for_current_day_from_past_x_days(
|
|
227
|
+
last_x_window_days_content_list)
|
|
204
228
|
|
|
205
229
|
return moving_average
|
|
206
230
|
|
|
207
231
|
|
|
208
|
-
def compute_average_for_current_day_from_past_x_days(
|
|
232
|
+
def compute_average_for_current_day_from_past_x_days(
|
|
233
|
+
previous_days_content_list: list
|
|
234
|
+
) -> dict:
|
|
209
235
|
"""
|
|
210
236
|
This function computes the average for the current day from the past x days.
|
|
211
237
|
|
|
@@ -222,11 +248,15 @@ def compute_average_for_current_day_from_past_x_days(previous_days_content_list:
|
|
|
222
248
|
'counts': [],
|
|
223
249
|
'avg_request_sizes': [],
|
|
224
250
|
'avg_response_sizes': [],
|
|
251
|
+
'median_request_sizes': [],
|
|
252
|
+
'median_response_sizes': []
|
|
225
253
|
}
|
|
226
254
|
|
|
227
255
|
moving_average[host]['counts'].append(int(host_dict['count']))
|
|
228
256
|
moving_average[host]['avg_request_sizes'].append(float(host_dict['avg_request_size']))
|
|
229
257
|
moving_average[host]['avg_response_sizes'].append(float(host_dict['avg_response_size']))
|
|
258
|
+
moving_average[host]['median_request_sizes'].append(float(host_dict['median_request_size']))
|
|
259
|
+
moving_average[host]['median_response_sizes'].append(float(host_dict['median_response_size']))
|
|
230
260
|
|
|
231
261
|
# Compute the moving average.
|
|
232
262
|
moving_average_results: dict = {}
|
|
@@ -234,14 +264,20 @@ def compute_average_for_current_day_from_past_x_days(previous_days_content_list:
|
|
|
234
264
|
ma_count = statistics.mean(host_dict['counts'])
|
|
235
265
|
ma_request_size = statistics.mean(host_dict['avg_request_sizes'])
|
|
236
266
|
ma_response_size = statistics.mean(host_dict['avg_response_sizes'])
|
|
267
|
+
mm_request_size = statistics.median(host_dict['median_request_sizes'])
|
|
268
|
+
mm_response_size = statistics.median(host_dict['median_response_sizes'])
|
|
237
269
|
|
|
238
270
|
moving_average_results[host] = {
|
|
239
271
|
'ma_count': ma_count,
|
|
240
272
|
'ma_request_size': ma_request_size,
|
|
241
273
|
'ma_response_size': ma_response_size,
|
|
274
|
+
'mm_request_size': mm_request_size,
|
|
275
|
+
'mm_response_size': mm_response_size,
|
|
242
276
|
'counts': host_dict['counts'],
|
|
243
277
|
'avg_request_sizes': host_dict['avg_request_sizes'],
|
|
244
|
-
'avg_response_sizes': host_dict['avg_response_sizes']
|
|
278
|
+
'avg_response_sizes': host_dict['avg_response_sizes'],
|
|
279
|
+
'median_request_sizes': host_dict['median_request_sizes'],
|
|
280
|
+
'median_response_sizes': host_dict['median_response_sizes']
|
|
245
281
|
}
|
|
246
282
|
|
|
247
283
|
return moving_average_results
|
|
@@ -303,6 +339,10 @@ def find_deviation_from_moving_average(
|
|
|
303
339
|
'ma_value_checked': check_type_moving_above,
|
|
304
340
|
'deviation_percentage': deviation_percentage,
|
|
305
341
|
'deviation_type': deviation_type,
|
|
342
|
+
'median_request_size': day_statistics_content_dict['median_request_size'],
|
|
343
|
+
'median_response_size': day_statistics_content_dict['median_response_size'],
|
|
344
|
+
'mm_request_size': moving_averages_dict[host]['mm_request_size'],
|
|
345
|
+
'mm_response_size': moving_averages_dict[host]['mm_response_size'],
|
|
306
346
|
'data': day_statistics_content_dict,
|
|
307
347
|
'ma_data': moving_averages_dict[host]
|
|
308
348
|
})
|
|
File without changes
|