atomicshop 2.20.7__py3-none-any.whl → 2.21.0__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/mitm/config_static.py +27 -20
- atomicshop/mitm/connection_thread_worker.py +25 -20
- atomicshop/mitm/engines/create_module_template.py +11 -5
- atomicshop/mitm/engines/create_module_template_main_example.py +13 -0
- atomicshop/mitm/import_config.py +174 -22
- atomicshop/mitm/initialize_engines.py +49 -66
- atomicshop/mitm/mitm_main.py +118 -148
- atomicshop/wrappers/socketw/dns_server.py +92 -68
- atomicshop/wrappers/socketw/socket_client.py +1 -1
- atomicshop/wrappers/socketw/socket_wrapper.py +138 -38
- {atomicshop-2.20.7.dist-info → atomicshop-2.21.0.dist-info}/METADATA +1 -1
- {atomicshop-2.20.7.dist-info → atomicshop-2.21.0.dist-info}/RECORD +16 -16
- atomicshop/mitm/engines/create_module_template_example.py +0 -13
- {atomicshop-2.20.7.dist-info → atomicshop-2.21.0.dist-info}/LICENSE.txt +0 -0
- {atomicshop-2.20.7.dist-info → atomicshop-2.21.0.dist-info}/WHEEL +0 -0
- {atomicshop-2.20.7.dist-info → atomicshop-2.21.0.dist-info}/top_level.txt +0 -0
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import os
|
|
2
|
-
import sys
|
|
3
2
|
from pathlib import Path
|
|
4
3
|
|
|
5
4
|
from ..file_io import tomls
|
|
@@ -8,12 +7,24 @@ from .engines.__reference_general import parser___reference_general, responder__
|
|
|
8
7
|
recorder___reference_general
|
|
9
8
|
|
|
10
9
|
|
|
10
|
+
class NoSNI:
|
|
11
|
+
def __init__(self):
|
|
12
|
+
self.get_from_dns: bool = False
|
|
13
|
+
self.serve_domain_on_address_enable: bool = False
|
|
14
|
+
self.serve_domain_on_address_dict: dict = dict()
|
|
15
|
+
|
|
16
|
+
|
|
11
17
|
class ModuleCategory:
|
|
12
18
|
def __init__(self, script_directory: str):
|
|
13
|
-
self.domain_list: list = list()
|
|
14
19
|
self.engine_name: str = str()
|
|
15
20
|
self.script_directory: str = script_directory
|
|
16
21
|
|
|
22
|
+
self.domain_list: list = list()
|
|
23
|
+
self.dns_target: str = str()
|
|
24
|
+
self.tcp_listening_address_list: list = list()
|
|
25
|
+
self.mtls: dict = dict()
|
|
26
|
+
self.no_sni: NoSNI = NoSNI()
|
|
27
|
+
|
|
17
28
|
self.parser_file_path: str = str()
|
|
18
29
|
self.responder_file_path: str = str()
|
|
19
30
|
self.recorder_file_path: str = str()
|
|
@@ -22,11 +33,6 @@ class ModuleCategory:
|
|
|
22
33
|
self.responder_class_object: str = str()
|
|
23
34
|
self.recorder_class_object: str = str()
|
|
24
35
|
|
|
25
|
-
# The instance of the recorder class that will be initiated once in the script start
|
|
26
|
-
self.responder_instance = None
|
|
27
|
-
|
|
28
|
-
self.mtls: dict = dict()
|
|
29
|
-
|
|
30
36
|
def fill_engine_fields_from_general_reference(self, engines_fullpath: str):
|
|
31
37
|
# Reference module variables.
|
|
32
38
|
self.engine_name = '__reference_general'
|
|
@@ -44,8 +50,24 @@ class ModuleCategory:
|
|
|
44
50
|
self.engine_name = Path(engine_directory_path).name
|
|
45
51
|
|
|
46
52
|
# Getting the parameters from engine config file
|
|
47
|
-
self.domain_list = configuration_data['domains']
|
|
48
|
-
self.
|
|
53
|
+
self.domain_list = configuration_data['engine']['domains']
|
|
54
|
+
self.dns_target = configuration_data['engine']['dns_target']
|
|
55
|
+
self.tcp_listening_address_list = configuration_data['engine']['tcp_listening_address_list']
|
|
56
|
+
|
|
57
|
+
if 'mtls' in configuration_data:
|
|
58
|
+
self.mtls = configuration_data['mtls']
|
|
59
|
+
|
|
60
|
+
self.no_sni.get_from_dns = bool(configuration_data['no_sni']['get_from_dns'])
|
|
61
|
+
|
|
62
|
+
for enable_bool, address_list in configuration_data['no_sni']['serve_domain_on_address'].items():
|
|
63
|
+
if enable_bool in ['0', '1']:
|
|
64
|
+
self.no_sni.serve_domain_on_address_enable = bool(int(enable_bool))
|
|
65
|
+
else:
|
|
66
|
+
raise ValueError(f"Error: no_sni -> serve_domain_on_address -> key must be 0 or 1.")
|
|
67
|
+
|
|
68
|
+
for address in address_list:
|
|
69
|
+
for domain, address_ip_port in address.items():
|
|
70
|
+
self.no_sni.serve_domain_on_address_dict = {domain: address_ip_port}
|
|
49
71
|
|
|
50
72
|
# If there's module configuration file, but no domains in it, there's no point to continue.
|
|
51
73
|
# Since, each engine is based on domains.
|
|
@@ -67,60 +89,36 @@ class ModuleCategory:
|
|
|
67
89
|
for subdomain, file_name in self.mtls.items():
|
|
68
90
|
self.mtls[subdomain] = f'{engine_directory_path}{os.sep}{file_name}'
|
|
69
91
|
|
|
70
|
-
def initialize_engine(self,
|
|
71
|
-
# Initiating logger for each engine by its name
|
|
72
|
-
# loggingw.create_logger(
|
|
73
|
-
# logger_name=self.engine_name,
|
|
74
|
-
# directory_path=logs_path,
|
|
75
|
-
# add_stream=True,
|
|
76
|
-
# add_timedfile_with_internal_queue=True,
|
|
77
|
-
# formatter_streamhandler='DEFAULT',
|
|
78
|
-
# formatter_filehandler='DEFAULT',
|
|
79
|
-
# backupCount=config_static.LogRec.store_logs_for_x_days
|
|
80
|
-
# )
|
|
81
|
-
|
|
92
|
+
def initialize_engine(self, reference_general: bool = False):
|
|
82
93
|
if not reference_general:
|
|
83
94
|
self.parser_class_object = import_first_class_name_from_file_path(
|
|
84
|
-
self.script_directory, self.parser_file_path
|
|
95
|
+
self.script_directory, self.parser_file_path)
|
|
85
96
|
self.responder_class_object = import_first_class_name_from_file_path(
|
|
86
|
-
self.script_directory, self.responder_file_path
|
|
97
|
+
self.script_directory, self.responder_file_path)
|
|
87
98
|
self.recorder_class_object = import_first_class_name_from_file_path(
|
|
88
|
-
self.script_directory, self.recorder_file_path
|
|
99
|
+
self.script_directory, self.recorder_file_path)
|
|
89
100
|
else:
|
|
90
101
|
self.parser_class_object = parser___reference_general.ParserGeneral
|
|
91
102
|
self.responder_class_object = responder___reference_general.ResponderGeneral
|
|
92
103
|
self.recorder_class_object = recorder___reference_general.RecorderGeneral
|
|
93
104
|
|
|
94
|
-
try:
|
|
95
|
-
# Since we're using responder to aggregate requests to build responses based on several
|
|
96
|
-
# requests, we need to initiate responder's class only once in the beginning and assign
|
|
97
|
-
# this instance to a variable that will be called later per domain.
|
|
98
|
-
self.responder_instance = self.responder_class_object()
|
|
99
|
-
except Exception as exception_object:
|
|
100
|
-
logger.error_exception(f"Exception while initializing responder: {exception_object}")
|
|
101
|
-
sys.exit()
|
|
102
105
|
|
|
103
|
-
|
|
104
|
-
# Assigning external class object by message domain received from client. If the domain is not in the list,
|
|
105
|
-
# the reference general module will be assigned.
|
|
106
106
|
def assign_class_by_domain(
|
|
107
|
-
engines_usage: bool,
|
|
108
107
|
engines_list: list,
|
|
109
108
|
message_domain_name: str,
|
|
110
|
-
reference_module
|
|
111
|
-
logger=None
|
|
109
|
+
reference_module
|
|
112
110
|
):
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
mtls_data: dict = dict()
|
|
111
|
+
"""
|
|
112
|
+
Assigning external class object by message domain received from client. If the domain is not in the list,
|
|
113
|
+
the reference general module will be assigned.
|
|
114
|
+
"""
|
|
118
115
|
|
|
119
116
|
# In case SNI came empty in the request from client, then there's no point in iterating through engine domains.
|
|
117
|
+
module = None
|
|
120
118
|
if message_domain_name:
|
|
121
|
-
# If
|
|
119
|
+
# If engine/s exit, the engines_list will not be empty, then we'll iterate through the list of engines
|
|
122
120
|
# to find the domain in the list of domains of the engine.
|
|
123
|
-
if
|
|
121
|
+
if engines_list:
|
|
124
122
|
# Checking if current domain is in engines' domain list to activate domain specific engine
|
|
125
123
|
for function_module in engines_list:
|
|
126
124
|
# The list: matches_list = ["domain1.com", "domain2.com", "domain3.com"]
|
|
@@ -132,18 +130,8 @@ def assign_class_by_domain(
|
|
|
132
130
|
# in the list of strings: if any(a_string in x for x in matches_list):
|
|
133
131
|
# In this case list is the same and string: a_string = domain
|
|
134
132
|
if any(x in message_domain_name for x in function_module.domain_list):
|
|
135
|
-
# Assigning
|
|
136
|
-
|
|
137
|
-
function_recorder = function_module.recorder_class_object
|
|
138
|
-
# Since the responder is being initiated only once, we're assigning only the instance
|
|
139
|
-
function_responder = function_module.responder_instance
|
|
140
|
-
mtls_data = function_module.mtls
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
logger.info(f"Assigned Modules for [{message_domain_name}]: "
|
|
144
|
-
f"{function_module.parser_class_object.__name__}, "
|
|
145
|
-
f"{function_module.responder_class_object.__name__}, "
|
|
146
|
-
f"{function_module.recorder_class_object.__name__}")
|
|
133
|
+
# Assigning module by current engine of the domain
|
|
134
|
+
module = function_module
|
|
147
135
|
|
|
148
136
|
# If the domain was found in the current list of class domains, we can stop the loop
|
|
149
137
|
break
|
|
@@ -152,12 +140,7 @@ def assign_class_by_domain(
|
|
|
152
140
|
# It's enough to check only parser, since responder and recorder also will be empty.
|
|
153
141
|
# This section is also relevant if SNI came empty in the request from the client and no domain was passed by the
|
|
154
142
|
# DNS Server.
|
|
155
|
-
if not
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
# Since the responder is being initiated only once, we're assigning only the instance
|
|
160
|
-
function_responder = reference_module.responder_instance
|
|
161
|
-
|
|
162
|
-
# Return all the initiated modules
|
|
163
|
-
return function_parser, function_responder, function_recorder, mtls_data
|
|
143
|
+
if not module:
|
|
144
|
+
module = reference_module
|
|
145
|
+
|
|
146
|
+
return module
|
atomicshop/mitm/mitm_main.py
CHANGED
|
@@ -77,57 +77,10 @@ def exit_cleanup():
|
|
|
77
77
|
process.join()
|
|
78
78
|
|
|
79
79
|
|
|
80
|
-
def
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
# Since listening server is infinite, this will not be reached.
|
|
85
|
-
# After modules import - we check for python version.
|
|
86
|
-
if not check_python_version_compliance(minor_version='3.12'):
|
|
87
|
-
return 1
|
|
88
|
-
|
|
89
|
-
# Import the configuration file.
|
|
90
|
-
result = config_static.load_config(config_file_path)
|
|
91
|
-
if result != 0:
|
|
92
|
-
return result
|
|
93
|
-
|
|
94
|
-
global MITM_ERROR_LOGGER
|
|
95
|
-
MITM_ERROR_LOGGER = loggingw.ExceptionCsvLogger(
|
|
96
|
-
logger_name=EXCEPTIONS_CSV_LOGGER_NAME, directory_path=config_static.LogRec.logs_path)
|
|
97
|
-
|
|
98
|
-
# Create folders.
|
|
99
|
-
filesystem.create_directory(config_static.LogRec.logs_path)
|
|
100
|
-
|
|
101
|
-
if config_static.LogRec.enable_request_response_recordings_in_logs:
|
|
102
|
-
filesystem.create_directory(config_static.LogRec.recordings_path)
|
|
103
|
-
# Compress recordings of the previous days if there are any.
|
|
104
|
-
global RECS_PROCESS_INSTANCE
|
|
105
|
-
RECS_PROCESS_INSTANCE = recs_files.recs_archiver_in_process(config_static.LogRec.recordings_path)
|
|
106
|
-
|
|
107
|
-
if config_static.Certificates.sni_get_server_certificate_from_server_socket:
|
|
108
|
-
filesystem.create_directory(
|
|
109
|
-
config_static.Certificates.sni_server_certificate_from_server_socket_download_directory)
|
|
110
|
-
|
|
111
|
-
network_logger_name = config_static.MainConfig.LOGGER_NAME
|
|
112
|
-
|
|
113
|
-
_ = loggingw.create_logger(
|
|
114
|
-
get_queue_listener=True,
|
|
115
|
-
log_queue=NETWORK_LOGGER_QUEUE,
|
|
116
|
-
file_path=f'{config_static.LogRec.logs_path}{os.sep}{network_logger_name}.txt',
|
|
117
|
-
add_stream=True,
|
|
118
|
-
add_timedfile=True,
|
|
119
|
-
formatter_streamhandler='DEFAULT',
|
|
120
|
-
formatter_filehandler='DEFAULT',
|
|
121
|
-
backupCount=config_static.LogRec.store_logs_for_x_days)
|
|
122
|
-
|
|
123
|
-
network_logger_with_queue_handler = loggingw.create_logger(
|
|
124
|
-
logger_name=network_logger_name,
|
|
125
|
-
add_queue_handler=True,
|
|
126
|
-
log_queue=NETWORK_LOGGER_QUEUE)
|
|
127
|
-
|
|
128
|
-
# Initiate Listener logger, which is a child of network logger, so he uses the same settings and handlers
|
|
129
|
-
listener_logger = loggingw.get_logger_with_level(f'{network_logger_name}.listener')
|
|
130
|
-
system_logger = loggingw.get_logger_with_level(f'{network_logger_name}.system')
|
|
80
|
+
def startup_output(system_logger, script_version: str):
|
|
81
|
+
"""
|
|
82
|
+
The function outputs the startup information to the console.
|
|
83
|
+
"""
|
|
131
84
|
|
|
132
85
|
# Writing first log.
|
|
133
86
|
system_logger.info("======================================")
|
|
@@ -140,8 +93,6 @@ def mitm_server(config_file_path: str, script_version: str):
|
|
|
140
93
|
system_logger.info(f"Recordings folder for Requests/Responses: {config_static.LogRec.recordings_path}")
|
|
141
94
|
system_logger.info(f"Loaded system logger: {system_logger}")
|
|
142
95
|
|
|
143
|
-
system_logger.info(f"TCP Server Target IP: {config_static.DNSServer.target_tcp_server_ipv4}")
|
|
144
|
-
|
|
145
96
|
# Some 'config.ini' settings logging ===========================================================================
|
|
146
97
|
if config_static.Certificates.default_server_certificate_usage:
|
|
147
98
|
system_logger.info(
|
|
@@ -167,40 +118,17 @@ def mitm_server(config_file_path: str, script_version: str):
|
|
|
167
118
|
system_logger.info(f"Custom Certificate Private Key Path wasn't provided in [advanced] section. "
|
|
168
119
|
f"Assuming the private key is inside the certificate file.")
|
|
169
120
|
|
|
170
|
-
# === Importing engine modules =================================================================================
|
|
171
|
-
system_logger.info("Importing engine modules.")
|
|
172
|
-
|
|
173
|
-
# Get full paths of all the 'engine_config.ini' files.
|
|
174
|
-
engine_config_path_list = filesystem.get_paths_from_directory(
|
|
175
|
-
directory_path=config_static.MainConfig.ENGINES_DIRECTORY_PATH,
|
|
176
|
-
get_file=True,
|
|
177
|
-
file_name_check_pattern=config_static.MainConfig.ENGINE_CONFIG_FILE_NAME)
|
|
178
|
-
|
|
179
|
-
# Iterate through all the 'engine_config.ini' file paths.
|
|
180
|
-
domains_engine_list_full: list = list()
|
|
181
|
-
engines_list: list = list()
|
|
182
|
-
for engine_config_path in engine_config_path_list:
|
|
183
|
-
# Initialize engine.
|
|
184
|
-
current_module = ModuleCategory(config_static.MainConfig.SCRIPT_DIRECTORY)
|
|
185
|
-
current_module.fill_engine_fields_from_config(engine_config_path.path)
|
|
186
|
-
current_module.initialize_engine(logs_path=config_static.LogRec.logs_path,
|
|
187
|
-
logger=system_logger)
|
|
188
|
-
|
|
189
|
-
# Extending the full engine domain list with this list.
|
|
190
|
-
domains_engine_list_full.extend(current_module.domain_list)
|
|
191
|
-
# Append the object to the engines list
|
|
192
|
-
engines_list.append(current_module)
|
|
193
|
-
# === EOF Importing engine modules =============================================================================
|
|
194
|
-
# ==== Initialize Reference Module =============================================================================
|
|
195
|
-
reference_module = ModuleCategory(config_static.MainConfig.SCRIPT_DIRECTORY)
|
|
196
|
-
reference_module.fill_engine_fields_from_general_reference(config_static.MainConfig.ENGINES_DIRECTORY_PATH)
|
|
197
|
-
reference_module.initialize_engine(logs_path=config_static.LogRec.logs_path,
|
|
198
|
-
logger=system_logger, stdout=False, reference_general=True)
|
|
199
|
-
# === EOF Initialize Reference Module ==========================================================================
|
|
200
121
|
# === Engine logging ===========================================================================================
|
|
201
122
|
# Printing the parsers using "start=1" for index to start counting from "1" and not "0"
|
|
123
|
+
system_logger.info("Imported engine info.")
|
|
202
124
|
print_api.print_api(f"[*] Found Engines:", logger=system_logger)
|
|
203
|
-
|
|
125
|
+
|
|
126
|
+
if not config_static.ENGINES_LIST:
|
|
127
|
+
message = \
|
|
128
|
+
f"No engines found, the TCP server will use general response engine for all the input domains."
|
|
129
|
+
print_api.print_api(message, color="blue", logger=system_logger)
|
|
130
|
+
|
|
131
|
+
for index, engine in enumerate(config_static.ENGINES_LIST, start=1):
|
|
204
132
|
message = f"[*] {index}: {engine.engine_name} | {engine.domain_list}"
|
|
205
133
|
print_api.print_api(message, logger=system_logger)
|
|
206
134
|
|
|
@@ -208,31 +136,36 @@ def mitm_server(config_file_path: str, script_version: str):
|
|
|
208
136
|
f"{engine.responder_class_object.__name__}, "
|
|
209
137
|
f"{engine.recorder_class_object.__name__}")
|
|
210
138
|
print_api.print_api(message, logger=system_logger)
|
|
139
|
+
print_api.print_api(f"[*] Name: {engine.engine_name}", logger=system_logger)
|
|
140
|
+
print_api.print_api(f"[*] Domains: {engine.domain_list}", logger=system_logger)
|
|
141
|
+
print_api.print_api(f"[*] DNS Target: {engine.dns_target}", logger=system_logger)
|
|
142
|
+
print_api.print_api(f"[*] TCP Listening Interfaces: {engine.tcp_listening_address_list}", logger=system_logger)
|
|
143
|
+
|
|
144
|
+
if engine.no_sni.get_from_dns:
|
|
145
|
+
print_api.print_api(f"[*] No SNI setting: Will fetch from DNS Server", logger=system_logger)
|
|
146
|
+
if engine.no_sni.serve_domain_on_address_enable:
|
|
147
|
+
print_api.print_api(
|
|
148
|
+
f"[*] No SNI setting: The DNS Server will send the domains to interfaces [{engine.no_sni.serve_domain_on_address_dict}]",
|
|
149
|
+
logger=system_logger)
|
|
211
150
|
|
|
212
151
|
if config_static.DNSServer.enable:
|
|
213
152
|
print_api.print_api("DNS Server is enabled.", logger=system_logger)
|
|
214
153
|
|
|
215
154
|
# If engines were found and dns is set to route by the engine domains.
|
|
216
|
-
if
|
|
155
|
+
if config_static.ENGINES_LIST and config_static.DNSServer.resolve_by_engine:
|
|
217
156
|
print_api.print_api(
|
|
218
157
|
"Engine domains will be routed by the DNS server to Built-in TCP Server.", logger=system_logger)
|
|
219
158
|
# If engines were found, but the dns isn't set to route to engines.
|
|
220
|
-
elif
|
|
221
|
-
message = f"[*]
|
|
159
|
+
elif config_static.ENGINES_LIST and not config_static.DNSServer.resolve_by_engine:
|
|
160
|
+
message = f"[*] Engines found, but the DNS routing is set not to use them for routing."
|
|
222
161
|
print_api.print_api(message, color="yellow", logger=system_logger)
|
|
223
|
-
elif not engines_list and config_static.DNSServer.resolve_to_tcp_server_only_engine_domains:
|
|
224
|
-
error_message = (
|
|
225
|
-
f"No engines were found in: [{config_static.MainConfig.ENGINES_DIRECTORY_PATH}]\n"
|
|
226
|
-
f"But the DNS routing is set to use them for routing.\n"
|
|
227
|
-
f"Please check your DNS configuration in the 'config.ini' file.")
|
|
228
|
-
print_api.print_api(error_message, color="red")
|
|
229
|
-
return 1
|
|
230
162
|
|
|
231
|
-
if config_static.DNSServer.
|
|
163
|
+
if config_static.DNSServer.resolve_all_domains_to_ipv4_enable:
|
|
232
164
|
print_api.print_api(
|
|
233
|
-
"All domains will be routed by the DNS server to Built-in TCP Server.",
|
|
165
|
+
f"All domains will be routed by the DNS server to Built-in TCP Server: [{config_static.DNSServer.target_ipv4}]",
|
|
166
|
+
color="blue", logger=system_logger)
|
|
234
167
|
|
|
235
|
-
if config_static.DNSServer.
|
|
168
|
+
if config_static.DNSServer.resolve_regular_pass_thru:
|
|
236
169
|
print_api.print_api(
|
|
237
170
|
"Regular DNS resolving is enabled. Built-in TCP server will not be routed to",
|
|
238
171
|
logger=system_logger, color="yellow")
|
|
@@ -241,51 +174,84 @@ def mitm_server(config_file_path: str, script_version: str):
|
|
|
241
174
|
|
|
242
175
|
if config_static.TCPServer.enable:
|
|
243
176
|
print_api.print_api("TCP Server is enabled.", logger=system_logger)
|
|
244
|
-
|
|
245
|
-
if engines_list and not config_static.TCPServer.engines_usage:
|
|
246
|
-
message = \
|
|
247
|
-
f"Engines found, but the TCP server is set not to use them for processing. General responses only."
|
|
248
|
-
print_api.print_api(message, color="yellow", logger=system_logger)
|
|
249
|
-
elif engines_list and config_static.TCPServer.engines_usage:
|
|
250
|
-
message = f"Engines found, and the TCP server is set to use them for processing."
|
|
251
|
-
print_api.print_api(message, logger=system_logger)
|
|
252
|
-
elif not engines_list and config_static.TCPServer.engines_usage:
|
|
253
|
-
error_message = (
|
|
254
|
-
f"No engines were found in: [{config_static.MainConfig.ENGINES_DIRECTORY_PATH}]\n"
|
|
255
|
-
f"But the TCP server is set to use them for processing.\n"
|
|
256
|
-
f"Please check your TCP configuration in the 'config.ini' file.")
|
|
257
|
-
print_api.print_api(error_message, color="red")
|
|
258
|
-
return 1
|
|
259
177
|
else:
|
|
260
178
|
print_api.print_api("TCP Server is disabled.", logger=system_logger, color="yellow")
|
|
261
179
|
|
|
262
|
-
# === EOF Engine Logging =======================================================================================
|
|
263
180
|
|
|
264
|
-
|
|
265
|
-
|
|
181
|
+
def mitm_server(config_file_path: str, script_version: str):
|
|
182
|
+
on_exit.register_exit_handler(exit_cleanup, at_exit=False, kill_signal=False)
|
|
183
|
+
|
|
184
|
+
# Main function should return integer with error code, 0 is successful.
|
|
185
|
+
# Since listening server is infinite, this will not be reached.
|
|
186
|
+
# After modules import - we check for python version.
|
|
187
|
+
if not check_python_version_compliance(minor_version='3.12'):
|
|
188
|
+
return 1
|
|
189
|
+
|
|
190
|
+
# Import the configuration file.
|
|
191
|
+
result = config_static.load_config(config_file_path)
|
|
192
|
+
if result != 0:
|
|
193
|
+
return result
|
|
194
|
+
|
|
195
|
+
global MITM_ERROR_LOGGER
|
|
196
|
+
MITM_ERROR_LOGGER = loggingw.ExceptionCsvLogger(
|
|
197
|
+
logger_name=EXCEPTIONS_CSV_LOGGER_NAME, directory_path=config_static.LogRec.logs_path)
|
|
198
|
+
|
|
199
|
+
# Create folders.
|
|
200
|
+
filesystem.create_directory(config_static.LogRec.logs_path)
|
|
201
|
+
|
|
202
|
+
if config_static.LogRec.enable_request_response_recordings_in_logs:
|
|
203
|
+
filesystem.create_directory(config_static.LogRec.recordings_path)
|
|
204
|
+
# Compress recordings of the previous days if there are any.
|
|
205
|
+
global RECS_PROCESS_INSTANCE
|
|
206
|
+
RECS_PROCESS_INSTANCE = recs_files.recs_archiver_in_process(config_static.LogRec.recordings_path)
|
|
207
|
+
|
|
208
|
+
if config_static.Certificates.sni_get_server_certificate_from_server_socket:
|
|
209
|
+
filesystem.create_directory(
|
|
210
|
+
config_static.Certificates.sni_server_certificate_from_server_socket_download_directory)
|
|
211
|
+
|
|
212
|
+
network_logger_name = config_static.MainConfig.LOGGER_NAME
|
|
213
|
+
|
|
214
|
+
# If we exit the function, we need to stop the listener: network_logger_queue_listener.stop()
|
|
215
|
+
network_logger_queue_listener = loggingw.create_logger(
|
|
216
|
+
get_queue_listener=True,
|
|
217
|
+
log_queue=NETWORK_LOGGER_QUEUE,
|
|
218
|
+
file_path=f'{config_static.LogRec.logs_path}{os.sep}{network_logger_name}.txt',
|
|
219
|
+
add_stream=True,
|
|
220
|
+
add_timedfile=True,
|
|
221
|
+
formatter_streamhandler='DEFAULT',
|
|
222
|
+
formatter_filehandler='DEFAULT',
|
|
223
|
+
backupCount=config_static.LogRec.store_logs_for_x_days)
|
|
224
|
+
|
|
225
|
+
network_logger_with_queue_handler = loggingw.create_logger(
|
|
226
|
+
logger_name=network_logger_name,
|
|
227
|
+
add_queue_handler=True,
|
|
228
|
+
log_queue=NETWORK_LOGGER_QUEUE)
|
|
229
|
+
|
|
230
|
+
# Initiate Listener logger, which is a child of network logger, so he uses the same settings and handlers
|
|
231
|
+
listener_logger = loggingw.get_logger_with_level(f'{network_logger_name}.listener')
|
|
232
|
+
system_logger = loggingw.get_logger_with_level(f'{network_logger_name}.system')
|
|
233
|
+
|
|
234
|
+
# Logging Startup information.
|
|
235
|
+
startup_output(system_logger, script_version)
|
|
266
236
|
|
|
267
237
|
print_api.print_api("Press [Ctrl]+[C] to stop.", color='blue')
|
|
268
238
|
|
|
269
239
|
# === Initialize DNS module ====================================================================================
|
|
270
240
|
if config_static.DNSServer.enable:
|
|
271
241
|
dns_process = multiprocessing.Process(
|
|
272
|
-
# dns_process = threading.Thread(
|
|
273
242
|
target=dns_server.start_dns_server_multiprocessing_worker,
|
|
274
243
|
kwargs={
|
|
275
|
-
'
|
|
276
|
-
'listening_port' :config_static.DNSServer.listening_port,
|
|
244
|
+
'listening_address': config_static.DNSServer.listening_address,
|
|
277
245
|
'log_directory_path': config_static.LogRec.logs_path,
|
|
278
246
|
'backupCount_log_files_x_days': config_static.LogRec.store_logs_for_x_days,
|
|
279
247
|
'forwarding_dns_service_ipv4': config_static.DNSServer.forwarding_dns_service_ipv4,
|
|
280
|
-
'
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
'
|
|
284
|
-
'
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
'resolve_to_tcp_server_all_domains': config_static.DNSServer.resolve_to_tcp_server_all_domains,
|
|
288
|
-
'resolve_regular': config_static.DNSServer.resolve_regular,
|
|
248
|
+
'forwarding_dns_service_port': config_static.DNSServer.forwarding_dns_service_port,
|
|
249
|
+
'resolve_by_engine': (
|
|
250
|
+
config_static.DNSServer.resolve_by_engine, config_static.ENGINES_LIST),
|
|
251
|
+
'resolve_regular_pass_thru': config_static.DNSServer.resolve_regular_pass_thru,
|
|
252
|
+
'resolve_all_domains_to_ipv4': (
|
|
253
|
+
config_static.DNSServer.resolve_all_domains_to_ipv4_enable, config_static.DNSServer.target_ipv4),
|
|
254
|
+
'offline_mode': config_static.MainConfig.offline,
|
|
289
255
|
'cache_timeout_minutes': config_static.DNSServer.cache_timeout_minutes,
|
|
290
256
|
'request_domain_queue': DOMAIN_QUEUE,
|
|
291
257
|
'logging_queue': NETWORK_LOGGER_QUEUE,
|
|
@@ -307,6 +273,7 @@ def mitm_server(config_file_path: str, script_version: str):
|
|
|
307
273
|
print_api.print_api(message, error_type=True, color="red", logger=system_logger)
|
|
308
274
|
# Wait for the message to be printed and saved to file.
|
|
309
275
|
time.sleep(1)
|
|
276
|
+
network_logger_queue_listener.stop()
|
|
310
277
|
return 1
|
|
311
278
|
|
|
312
279
|
# Now we can check if the process wasn't terminated after the check.
|
|
@@ -319,6 +286,7 @@ def mitm_server(config_file_path: str, script_version: str):
|
|
|
319
286
|
print_api.print_api(message, error_type=True, color="red", logger=system_logger)
|
|
320
287
|
# Wait for the message to be printed and saved to file.
|
|
321
288
|
time.sleep(1)
|
|
289
|
+
network_logger_queue_listener.stop()
|
|
322
290
|
return 1
|
|
323
291
|
|
|
324
292
|
time.sleep(1)
|
|
@@ -327,13 +295,8 @@ def mitm_server(config_file_path: str, script_version: str):
|
|
|
327
295
|
# === EOF Initialize DNS module ================================================================================
|
|
328
296
|
# === Initialize TCP Server ====================================================================================
|
|
329
297
|
if config_static.TCPServer.enable:
|
|
330
|
-
engines_domains: dict = dict()
|
|
331
|
-
for engine in engines_list:
|
|
332
|
-
engines_domains[engine.engine_name] = engine.domain_list
|
|
333
|
-
|
|
334
298
|
try:
|
|
335
299
|
socket_wrapper_instance = socket_wrapper.SocketWrapper(
|
|
336
|
-
listening_address_list=config_static.TCPServer.listening_address_list,
|
|
337
300
|
ca_certificate_name=config_static.MainConfig.ca_certificate_name,
|
|
338
301
|
ca_certificate_filepath=config_static.MainConfig.ca_certificate_filepath,
|
|
339
302
|
ca_certificate_crt_filepath=config_static.MainConfig.ca_certificate_crt_filepath,
|
|
@@ -366,27 +329,26 @@ def mitm_server(config_file_path: str, script_version: str):
|
|
|
366
329
|
logger=listener_logger,
|
|
367
330
|
exceptions_logger=MITM_ERROR_LOGGER,
|
|
368
331
|
statistics_logs_directory=config_static.LogRec.logs_path,
|
|
369
|
-
forwarding_dns_service_ipv4_list___only_for_localhost=
|
|
370
|
-
config_static.TCPServer.forwarding_dns_service_ipv4_list___only_for_localhost),
|
|
332
|
+
forwarding_dns_service_ipv4_list___only_for_localhost=[config_static.DNSServer.forwarding_dns_service_ipv4],
|
|
371
333
|
skip_extension_id_list=config_static.SkipExtensions.SKIP_EXTENSION_ID_LIST,
|
|
372
334
|
request_domain_from_dns_server_queue=DOMAIN_QUEUE,
|
|
373
|
-
|
|
335
|
+
no_engine_usage_enable=config_static.TCPServer.no_engines_usage_to_listen_addresses_enable,
|
|
336
|
+
no_engines_listening_address_list=config_static.TCPServer.no_engines_listening_address_list,
|
|
337
|
+
engines_list=config_static.ENGINES_LIST
|
|
374
338
|
)
|
|
375
339
|
except socket_wrapper.SocketWrapperPortInUseError as e:
|
|
376
340
|
print_api.print_api(e, error_type=True, color="red", logger=system_logger)
|
|
377
341
|
# Wait for the message to be printed and saved to file.
|
|
378
342
|
time.sleep(1)
|
|
343
|
+
network_logger_queue_listener.stop()
|
|
379
344
|
return 1
|
|
380
345
|
except socket_wrapper.SocketWrapperConfigurationValuesError as e:
|
|
381
346
|
print_api.print_api(e, error_type=True, color="red", logger=system_logger, logger_method='critical')
|
|
382
347
|
# Wait for the message to be printed and saved to file.
|
|
383
348
|
time.sleep(1)
|
|
349
|
+
network_logger_queue_listener.stop()
|
|
384
350
|
return 1
|
|
385
351
|
|
|
386
|
-
statistics_writer = socket_wrapper_instance.statistics_writer
|
|
387
|
-
|
|
388
|
-
socket_wrapper_instance.create_tcp_listening_socket_list()
|
|
389
|
-
|
|
390
352
|
# Before we start the loop. we can set the default gateway if specified.
|
|
391
353
|
set_dns_gateway = False
|
|
392
354
|
dns_gateway_server_list = list()
|
|
@@ -421,19 +383,27 @@ def mitm_server(config_file_path: str, script_version: str):
|
|
|
421
383
|
print_api.print_api(e, error_type=True, color="red", logger=system_logger)
|
|
422
384
|
# Wait for the message to be printed and saved to file.
|
|
423
385
|
time.sleep(1)
|
|
386
|
+
network_logger_queue_listener.stop()
|
|
424
387
|
return 1
|
|
425
388
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
},
|
|
432
|
-
name="accepting_loop"
|
|
389
|
+
statistics_writer = socket_wrapper_instance.statistics_writer
|
|
390
|
+
|
|
391
|
+
socket_wrapper_instance.start_listening_sockets(
|
|
392
|
+
reference_function_name=thread_worker_main,
|
|
393
|
+
reference_function_args=(network_logger_with_queue_handler, statistics_writer, config_static.ENGINES_LIST, config_static.REFERENCE_MODULE)
|
|
433
394
|
)
|
|
434
395
|
|
|
435
|
-
socket_thread
|
|
436
|
-
|
|
396
|
+
# socket_thread = threading.Thread(
|
|
397
|
+
# target=socket_wrapper_instance.loop_for_incoming_sockets,
|
|
398
|
+
# kwargs={
|
|
399
|
+
# 'reference_function_name': thread_worker_main,
|
|
400
|
+
# 'reference_function_args': (network_logger_with_queue_handler, statistics_writer, engines_list, reference_module,)
|
|
401
|
+
# },
|
|
402
|
+
# name="accepting_loop"
|
|
403
|
+
# )
|
|
404
|
+
#
|
|
405
|
+
# socket_thread.daemon = True
|
|
406
|
+
# socket_thread.start()
|
|
437
407
|
|
|
438
408
|
# Compress recordings each day in a separate process.
|
|
439
409
|
recs_archiver_thread = threading.Thread(target=_loop_at_midnight_recs_archive)
|