atomicshop 2.16.25__py3-none-any.whl → 2.16.26__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 +2 -0
- atomicshop/mitm/initialize_engines.py +9 -9
- atomicshop/mitm/mitm_main.py +51 -38
- atomicshop/mitm/shared_functions.py +4 -1
- atomicshop/wrappers/socketw/dns_server.py +150 -59
- atomicshop/wrappers/socketw/socket_wrapper.py +12 -0
- atomicshop/wrappers/socketw/statistics_csv.py +3 -5
- {atomicshop-2.16.25.dist-info → atomicshop-2.16.26.dist-info}/METADATA +1 -1
- {atomicshop-2.16.25.dist-info → atomicshop-2.16.26.dist-info}/RECORD +13 -13
- {atomicshop-2.16.25.dist-info → atomicshop-2.16.26.dist-info}/LICENSE.txt +0 -0
- {atomicshop-2.16.25.dist-info → atomicshop-2.16.26.dist-info}/WHEEL +0 -0
- {atomicshop-2.16.25.dist-info → atomicshop-2.16.26.dist-info}/top_level.txt +0 -0
atomicshop/__init__.py
CHANGED
atomicshop/mitm/config_static.py
CHANGED
|
@@ -63,15 +63,15 @@ class ModuleCategory:
|
|
|
63
63
|
|
|
64
64
|
def initialize_engine(self, logs_path: str, logger=None, reference_general: bool = False, **kwargs):
|
|
65
65
|
# Initiating logger for each engine by its name
|
|
66
|
-
loggingw.create_logger(
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
)
|
|
66
|
+
# loggingw.create_logger(
|
|
67
|
+
# logger_name=self.engine_name,
|
|
68
|
+
# directory_path=logs_path,
|
|
69
|
+
# add_stream=True,
|
|
70
|
+
# add_timedfile=True,
|
|
71
|
+
# formatter_streamhandler='DEFAULT',
|
|
72
|
+
# formatter_filehandler='DEFAULT',
|
|
73
|
+
# backupCount=config_static.LogRec.store_logs_for_x_days
|
|
74
|
+
# )
|
|
75
75
|
|
|
76
76
|
if not reference_general:
|
|
77
77
|
self.parser_class_object = import_first_class_name_from_file_path(
|
atomicshop/mitm/mitm_main.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import logging
|
|
2
2
|
import threading
|
|
3
3
|
import time
|
|
4
4
|
import datetime
|
|
@@ -6,6 +6,8 @@ import datetime
|
|
|
6
6
|
import atomicshop # Importing atomicshop package to get the version of the package.
|
|
7
7
|
|
|
8
8
|
from .. import filesystem, queues, dns, on_exit
|
|
9
|
+
from ..basics import tracebacks
|
|
10
|
+
from ..file_io import csvs
|
|
9
11
|
from ..permissions import permissions
|
|
10
12
|
from ..python_functions import get_current_python_version_string, check_python_version_compliance
|
|
11
13
|
from ..wrappers.socketw import socket_wrapper, dns_server, base
|
|
@@ -21,6 +23,12 @@ NETWORK_INTERFACE_IS_DYNAMIC: bool = bool()
|
|
|
21
23
|
NETWORK_INTERFACE_IPV4_ADDRESS_LIST: list[str] = list()
|
|
22
24
|
|
|
23
25
|
|
|
26
|
+
EXCEPTIONS_CSV_LOGGER_NAME: str = 'exceptions'
|
|
27
|
+
EXCEPTIONS_CSV_LOGGER_HEADER: str = 'time,exception'
|
|
28
|
+
# noinspection PyTypeChecker
|
|
29
|
+
MITM_ERROR_LOGGER: logging.Logger = None
|
|
30
|
+
|
|
31
|
+
|
|
24
32
|
def exit_cleanup():
|
|
25
33
|
if permissions.is_admin():
|
|
26
34
|
is_dns_dynamic, current_dns_gateway = dns.get_default_dns_gateway()
|
|
@@ -32,7 +40,7 @@ def exit_cleanup():
|
|
|
32
40
|
print_api("Returned default DNS gateway...", color='blue')
|
|
33
41
|
|
|
34
42
|
|
|
35
|
-
def
|
|
43
|
+
def mitm_server(config_file_path: str):
|
|
36
44
|
on_exit.register_exit_handler(exit_cleanup)
|
|
37
45
|
|
|
38
46
|
# Main function should return integer with error code, 0 is successful.
|
|
@@ -45,6 +53,16 @@ def mitm_server_main(config_file_path: str):
|
|
|
45
53
|
if result != 0:
|
|
46
54
|
return result
|
|
47
55
|
|
|
56
|
+
global MITM_ERROR_LOGGER
|
|
57
|
+
MITM_ERROR_LOGGER = loggingw.create_logger(
|
|
58
|
+
logger_name=EXCEPTIONS_CSV_LOGGER_NAME,
|
|
59
|
+
directory_path=config_static.LogRec.logs_path,
|
|
60
|
+
file_type="csv",
|
|
61
|
+
add_timedfile=True,
|
|
62
|
+
formatter_filehandler='MESSAGE',
|
|
63
|
+
header=EXCEPTIONS_CSV_LOGGER_HEADER
|
|
64
|
+
)
|
|
65
|
+
|
|
48
66
|
# Create folders.
|
|
49
67
|
filesystem.create_directory(config_static.LogRec.logs_path)
|
|
50
68
|
|
|
@@ -57,11 +75,10 @@ def mitm_server_main(config_file_path: str):
|
|
|
57
75
|
filesystem.create_directory(
|
|
58
76
|
config_static.Certificates.sni_server_certificate_from_server_socket_download_directory)
|
|
59
77
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
file_path=f"{config_static.LogRec.logs_path}{os.sep}{logger_name}.txt",
|
|
78
|
+
network_logger_name = config_static.MainConfig.LOGGER_NAME
|
|
79
|
+
network_logger = loggingw.create_logger(
|
|
80
|
+
logger_name=network_logger_name,
|
|
81
|
+
directory_path=config_static.LogRec.logs_path,
|
|
65
82
|
add_stream=True,
|
|
66
83
|
add_timedfile=True,
|
|
67
84
|
formatter_streamhandler='DEFAULT',
|
|
@@ -69,6 +86,10 @@ def mitm_server_main(config_file_path: str):
|
|
|
69
86
|
backupCount=config_static.LogRec.store_logs_for_x_days
|
|
70
87
|
)
|
|
71
88
|
|
|
89
|
+
# Initiate Listener logger, which is a child of network logger, so he uses the same settings and handlers
|
|
90
|
+
listener_logger = loggingw.get_logger_with_level(f'{network_logger_name}.listener')
|
|
91
|
+
system_logger = loggingw.get_logger_with_level(f'{network_logger_name}.system')
|
|
92
|
+
|
|
72
93
|
# Writing first log.
|
|
73
94
|
system_logger.info("======================================")
|
|
74
95
|
system_logger.info("Server Started.")
|
|
@@ -202,22 +223,6 @@ def mitm_server_main(config_file_path: str):
|
|
|
202
223
|
# Assigning all the engines domains to all time domains, that will be responsible for adding new domains.
|
|
203
224
|
config_static.Certificates.domains_all_times = list(domains_engine_list_full)
|
|
204
225
|
|
|
205
|
-
network_logger_name = "network"
|
|
206
|
-
network_logger = loggingw.create_logger(
|
|
207
|
-
logger_name=network_logger_name,
|
|
208
|
-
directory_path=config_static.LogRec.logs_path,
|
|
209
|
-
add_stream=True,
|
|
210
|
-
add_timedfile=True,
|
|
211
|
-
formatter_streamhandler='DEFAULT',
|
|
212
|
-
formatter_filehandler='DEFAULT',
|
|
213
|
-
backupCount=config_static.LogRec.store_logs_for_x_days
|
|
214
|
-
)
|
|
215
|
-
system_logger.info(f"Loaded network logger: {network_logger}")
|
|
216
|
-
|
|
217
|
-
# Initiate Listener logger, which is a child of network logger, so he uses the same settings and handlers
|
|
218
|
-
listener_logger = loggingw.get_logger_with_level(f'{network_logger_name}.listener')
|
|
219
|
-
system_logger.info(f"Loaded listener logger: {listener_logger}")
|
|
220
|
-
|
|
221
226
|
print_api("Press [Ctrl]+[C] to stop.", color='blue')
|
|
222
227
|
|
|
223
228
|
# Create request domain queue.
|
|
@@ -339,22 +344,16 @@ def mitm_server_main(config_file_path: str):
|
|
|
339
344
|
use_default_connection=True
|
|
340
345
|
)
|
|
341
346
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
'reference_function_args': (network_logger, statistics_writer, engines_list, reference_module,)
|
|
350
|
-
}
|
|
351
|
-
)
|
|
347
|
+
socket_thread = threading.Thread(
|
|
348
|
+
target=socket_wrapper_instance.loop_for_incoming_sockets,
|
|
349
|
+
kwargs={
|
|
350
|
+
'reference_function_name': thread_worker_main,
|
|
351
|
+
'reference_function_args': (network_logger, statistics_writer, engines_list, reference_module,)
|
|
352
|
+
}
|
|
353
|
+
)
|
|
352
354
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
except Exception:
|
|
356
|
-
message = f"Unhandled Exception occurred in 'loop_for_incoming_sockets' function"
|
|
357
|
-
print_api(message, error_type=True, color="red", logger=network_logger, traceback_string=True)
|
|
355
|
+
socket_thread.daemon = True
|
|
356
|
+
socket_thread.start()
|
|
358
357
|
|
|
359
358
|
# Compress recordings each day in a separate process.
|
|
360
359
|
recs_archiver_thread = threading.Thread(target=_loop_at_midnight_recs_archive)
|
|
@@ -380,3 +379,17 @@ def _loop_at_midnight_recs_archive():
|
|
|
380
379
|
previous_date = current_date
|
|
381
380
|
# Sleep for 1 minute.
|
|
382
381
|
time.sleep(60)
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
def mitm_server_main(config_file_path: str):
|
|
385
|
+
try:
|
|
386
|
+
# Main function should return integer with error code, 0 is successful.
|
|
387
|
+
return mitm_server(config_file_path)
|
|
388
|
+
except KeyboardInterrupt:
|
|
389
|
+
print_api("Server Stopped by [KeyboardInterrupt].", color='blue')
|
|
390
|
+
return 0
|
|
391
|
+
except Exception as e:
|
|
392
|
+
msg = tracebacks.get_as_string()
|
|
393
|
+
output_csv_line: str = csvs.escape_csv_line_to_string([datetime.datetime.now(), msg])
|
|
394
|
+
MITM_ERROR_LOGGER.info(output_csv_line)
|
|
395
|
+
print_api(str(e), error_type=True, color="red", traceback_string=True)
|
|
@@ -4,6 +4,8 @@ import inspect
|
|
|
4
4
|
from ..wrappers.loggingw import loggingw
|
|
5
5
|
from ..basics import dicts
|
|
6
6
|
|
|
7
|
+
from . import config_static
|
|
8
|
+
|
|
7
9
|
|
|
8
10
|
# If the string has several dot characters (".") - return the most right string after the last dot.
|
|
9
11
|
# Meaning if the class name contains several child classes like: classes.parsers.parser_something,
|
|
@@ -32,7 +34,8 @@ def create_custom_logger():
|
|
|
32
34
|
# 'f_globals' is a dictionary of all the global variables of the calling initiated class.
|
|
33
35
|
class_name = calling_frame.f_globals['__name__']
|
|
34
36
|
# Get the logger name only.
|
|
35
|
-
|
|
37
|
+
engine_logger_part = build_module_names(class_name)[0]
|
|
38
|
+
logger_name = f'{config_static.MainConfig.LOGGER_NAME}.{engine_logger_part}'
|
|
36
39
|
|
|
37
40
|
return loggingw.get_logger_with_level(logger_name)
|
|
38
41
|
|
|
@@ -5,12 +5,14 @@ import threading
|
|
|
5
5
|
import socket
|
|
6
6
|
import logging
|
|
7
7
|
from pathlib import Path
|
|
8
|
+
from typing import Literal
|
|
8
9
|
|
|
9
10
|
from ...print_api import print_api
|
|
10
11
|
from ..loggingw import loggingw
|
|
11
12
|
from ..psutilw import networks
|
|
12
13
|
from ... import queues
|
|
13
|
-
from ...basics import booleans
|
|
14
|
+
from ...basics import booleans, tracebacks
|
|
15
|
+
from ...file_io import csvs
|
|
14
16
|
|
|
15
17
|
# noinspection PyPackageRequirements
|
|
16
18
|
import dnslib
|
|
@@ -26,6 +28,115 @@ class DnsConfigurationValuesError(Exception):
|
|
|
26
28
|
pass
|
|
27
29
|
|
|
28
30
|
|
|
31
|
+
LOGGER_NAME: str = 'dns_traffic'
|
|
32
|
+
DNS_STATISTICS_HEADER: str = (
|
|
33
|
+
'timestamp,dns_type,client_ipv4,client_port,qname,qtype,qclass,header,error')
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class DnsStatisticsCSVWriter:
|
|
37
|
+
"""
|
|
38
|
+
Class to write statistics to CSV file.
|
|
39
|
+
This can be initiated at the main, and then passed to the thread worker function.
|
|
40
|
+
"""
|
|
41
|
+
def __init__(
|
|
42
|
+
self,
|
|
43
|
+
statistics_directory_path: str
|
|
44
|
+
):
|
|
45
|
+
self.csv_logger = loggingw.create_logger(
|
|
46
|
+
logger_name=LOGGER_NAME,
|
|
47
|
+
directory_path=statistics_directory_path,
|
|
48
|
+
add_timedfile=True,
|
|
49
|
+
formatter_filehandler='MESSAGE',
|
|
50
|
+
file_type='csv',
|
|
51
|
+
header=DNS_STATISTICS_HEADER
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
def write_row(
|
|
55
|
+
self,
|
|
56
|
+
client_address: tuple,
|
|
57
|
+
timestamp=None,
|
|
58
|
+
dns_type: Literal['request', 'response'] = None,
|
|
59
|
+
dns_request = None,
|
|
60
|
+
dns_response = None,
|
|
61
|
+
error: str = None,
|
|
62
|
+
):
|
|
63
|
+
if not timestamp:
|
|
64
|
+
timestamp = datetime.datetime.now()
|
|
65
|
+
|
|
66
|
+
if not dns_type:
|
|
67
|
+
if not dns_request and not dns_response:
|
|
68
|
+
raise ValueError("Either DNS Request or DNS Response must be provided.")
|
|
69
|
+
elif dns_request and dns_response:
|
|
70
|
+
raise ValueError("Either DNS Request or DNS Response must be provided. Not both.")
|
|
71
|
+
|
|
72
|
+
if dns_request:
|
|
73
|
+
dns_type = 'request'
|
|
74
|
+
elif dns_response:
|
|
75
|
+
dns_type = 'response'
|
|
76
|
+
|
|
77
|
+
if dns_type not in ['request', 'response']:
|
|
78
|
+
raise ValueError(f"DNS Type can be only 'request' or 'response'. Provided: {dns_type}")
|
|
79
|
+
|
|
80
|
+
client_ipv4, client_port = client_address
|
|
81
|
+
client_ipv4: str
|
|
82
|
+
client_port: str = str(client_port)
|
|
83
|
+
|
|
84
|
+
qname: str = str()
|
|
85
|
+
qtype: str = str()
|
|
86
|
+
qclass: str = str()
|
|
87
|
+
rr: str = str()
|
|
88
|
+
header: str = str()
|
|
89
|
+
|
|
90
|
+
if dns_request:
|
|
91
|
+
qname = str(dns_request.q.qname)[:-1]
|
|
92
|
+
qtype = dnslib.QTYPE[dns_request.q.qtype]
|
|
93
|
+
qclass = dnslib.CLASS[dns_request.q.qclass]
|
|
94
|
+
|
|
95
|
+
if dns_response:
|
|
96
|
+
qname = str(dns_response.q.qname)[:-1]
|
|
97
|
+
qtype = dnslib.QTYPE[dns_response.q.qtype]
|
|
98
|
+
qclass = dnslib.CLASS[dns_response.q.qclass]
|
|
99
|
+
rr: str = str(dns_response.rr)
|
|
100
|
+
header = str(dns_response.header)
|
|
101
|
+
|
|
102
|
+
escaped_line_string: str = csvs.escape_csv_line_to_string([
|
|
103
|
+
timestamp,
|
|
104
|
+
dns_type,
|
|
105
|
+
client_ipv4,
|
|
106
|
+
client_port,
|
|
107
|
+
qname,
|
|
108
|
+
qtype,
|
|
109
|
+
qclass,
|
|
110
|
+
rr,
|
|
111
|
+
header,
|
|
112
|
+
error
|
|
113
|
+
])
|
|
114
|
+
|
|
115
|
+
self.csv_logger.info(escaped_line_string)
|
|
116
|
+
|
|
117
|
+
def write_error(
|
|
118
|
+
self,
|
|
119
|
+
dns_type: Literal['request', 'response'],
|
|
120
|
+
error_message: str,
|
|
121
|
+
client_address: tuple
|
|
122
|
+
):
|
|
123
|
+
"""
|
|
124
|
+
Write the error message to the statistics CSV file.
|
|
125
|
+
This is used for easier execution, since most of the parameters will be empty on accept.
|
|
126
|
+
|
|
127
|
+
:param dns_type: Literal['request', 'response'], DNS request or response.
|
|
128
|
+
:param error_message: string, error message.
|
|
129
|
+
:param client_address: tuple, client address (IPv4, Port).
|
|
130
|
+
:return:
|
|
131
|
+
"""
|
|
132
|
+
|
|
133
|
+
self.write_row(
|
|
134
|
+
dns_type=dns_type,
|
|
135
|
+
client_address=client_address,
|
|
136
|
+
error=error_message
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
|
|
29
140
|
class DnsServer:
|
|
30
141
|
"""
|
|
31
142
|
DnsServer class is responsible to handle DNS Requests on port 53 based on configuration and send DNS Response back.
|
|
@@ -129,13 +240,7 @@ class DnsServer:
|
|
|
129
240
|
|
|
130
241
|
# Logger that logs all the DNS Requests and responses in DNS format. These entries will not present in
|
|
131
242
|
# network log of TCP Server module.
|
|
132
|
-
self.
|
|
133
|
-
logger_name="dns_full",
|
|
134
|
-
directory_path=self.log_directory_path,
|
|
135
|
-
add_timedfile=True,
|
|
136
|
-
formatter_filehandler='DEFAULT',
|
|
137
|
-
backupCount=backupCount_log_files_x_days
|
|
138
|
-
)
|
|
243
|
+
self.dns_statistics_csv_writer = DnsStatisticsCSVWriter(statistics_directory_path=log_directory_path)
|
|
139
244
|
|
|
140
245
|
# Check if the logger was provided, if not, create a new logger.
|
|
141
246
|
if not logger:
|
|
@@ -250,20 +355,19 @@ class DnsServer:
|
|
|
250
355
|
client_data: bytes
|
|
251
356
|
client_address: tuple
|
|
252
357
|
except ConnectionResetError:
|
|
358
|
+
traceback_string = tracebacks.get_as_string(one_line=True)
|
|
253
359
|
# This error happens when the client closes the connection before the server.
|
|
254
360
|
# This is not an error for a DNS Server, but we'll log it anyway only with the full DNS logger.
|
|
255
|
-
message = "Error: to receive DNS request, An existing connection was forcibly closed"
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
self.dns_full_logger.info("==========")
|
|
361
|
+
message = (f"Error: to receive DNS request, An existing connection was forcibly closed | "
|
|
362
|
+
f"{traceback_string}")
|
|
363
|
+
self.dns_statistics_csv_writer.write_error(
|
|
364
|
+
dns_type='request', client_address=client_address, error_message=message)
|
|
260
365
|
pass
|
|
261
366
|
continue
|
|
262
367
|
except Exception:
|
|
263
368
|
message = "Unknown Exception: to receive DNS request"
|
|
264
369
|
print_api(
|
|
265
370
|
message, logger=self.logger, logger_method='critical', traceback_string=True)
|
|
266
|
-
self.logger.info("==========")
|
|
267
371
|
pass
|
|
268
372
|
continue
|
|
269
373
|
|
|
@@ -297,26 +401,18 @@ class DnsServer:
|
|
|
297
401
|
# "dns_object.q.qname" returns only the questioned domain with "." (dot) in the end,
|
|
298
402
|
# which needs to be removed.
|
|
299
403
|
question_domain: str = str(dns_object.q.qname)[:-1]
|
|
300
|
-
self.
|
|
301
|
-
self.dns_full_logger.info(f"QTYPE: {qtype_string}")
|
|
302
|
-
self.dns_full_logger.info(f"Question Domain: {question_domain}")
|
|
404
|
+
self.dns_statistics_csv_writer.write_row(client_address=client_address, dns_request=dns_object)
|
|
303
405
|
|
|
304
406
|
message = (f"Received DNS request: {question_domain} | {qclass_string} | {qtype_string} | "
|
|
305
407
|
f"From: {client_address}.")
|
|
306
408
|
self.logger.info(message)
|
|
307
|
-
self.dns_full_logger.info(message)
|
|
308
|
-
|
|
309
|
-
self.dns_full_logger.info("--")
|
|
310
409
|
|
|
311
410
|
# Nullifying the DNS cache for current request before check.
|
|
312
411
|
dns_cached_request = False
|
|
313
412
|
# Check if the received data request from client is already in the cache
|
|
314
413
|
if client_data in self.dns_questions_to_answers_cache:
|
|
315
|
-
message = "!!! Question / Answer is already in the dictionary..."
|
|
414
|
+
# message = "!!! Question / Answer is already in the dictionary..."
|
|
316
415
|
# self.logger.info(message)
|
|
317
|
-
self.dns_full_logger.info(message)
|
|
318
|
-
|
|
319
|
-
self.dns_full_logger.info("--")
|
|
320
416
|
|
|
321
417
|
# Get the response from the cached answers list
|
|
322
418
|
dns_response = self.dns_questions_to_answers_cache[client_data]
|
|
@@ -395,7 +491,6 @@ class DnsServer:
|
|
|
395
491
|
message = f"!!! Question / Answer is in offline mode returning " \
|
|
396
492
|
f"{self.offline_route_ipv6}."
|
|
397
493
|
self.logger.info(message)
|
|
398
|
-
self.dns_full_logger.info(message)
|
|
399
494
|
|
|
400
495
|
# SRV Record type explanation:
|
|
401
496
|
# https://www.cloudflare.com/learning/dns/dns-records/dns-srv-record/
|
|
@@ -412,7 +507,6 @@ class DnsServer:
|
|
|
412
507
|
message = f"!!! Question / Answer is in offline mode returning: " \
|
|
413
508
|
f"{self.offline_srv_answer}."
|
|
414
509
|
self.logger.info(message)
|
|
415
|
-
self.dns_full_logger.info(message)
|
|
416
510
|
elif qtype_string == "ANY":
|
|
417
511
|
dns_built_response.add_answer(
|
|
418
512
|
*RR.fromZone(question_domain + " " + str(self.response_ttl) + " CNAME " +
|
|
@@ -422,7 +516,6 @@ class DnsServer:
|
|
|
422
516
|
message = f"!!! Question / Answer is in offline mode returning " \
|
|
423
517
|
f"{self.offline_route_domain}."
|
|
424
518
|
self.logger.info(message)
|
|
425
|
-
self.dns_full_logger.info(message)
|
|
426
519
|
else:
|
|
427
520
|
dns_built_response.add_answer(
|
|
428
521
|
*RR.fromZone(
|
|
@@ -433,7 +526,6 @@ class DnsServer:
|
|
|
433
526
|
message = f"!!! Question / Answer is in offline mode returning " \
|
|
434
527
|
f"{self.offline_route_ipv4}."
|
|
435
528
|
self.logger.info(message)
|
|
436
|
-
self.dns_full_logger.info(message)
|
|
437
529
|
# Values error means in most cases that you create wrong response
|
|
438
530
|
# for specific type of request.
|
|
439
531
|
except ValueError:
|
|
@@ -450,18 +542,14 @@ class DnsServer:
|
|
|
450
542
|
except Exception:
|
|
451
543
|
message = \
|
|
452
544
|
(f"Unknown exception while creating response for QTYPE: {qtype_string}. "
|
|
453
|
-
f"Response: ")
|
|
545
|
+
f"Response: \n{dns_built_response}")
|
|
454
546
|
print_api(message, logger=self.logger, logger_method='critical',
|
|
455
547
|
traceback_string=True)
|
|
456
|
-
print_api(f"{dns_built_response}", logger=self.logger, logger_method='critical',
|
|
457
|
-
traceback_string=True)
|
|
458
548
|
# Pass the exception.
|
|
459
549
|
pass
|
|
460
550
|
# Continue to the next DNS request, since there's nothing to do here right now.
|
|
461
551
|
continue
|
|
462
552
|
|
|
463
|
-
self.dns_full_logger.info("--")
|
|
464
|
-
|
|
465
553
|
# Encode the response that was built above to legit DNS Response
|
|
466
554
|
dns_response = dns_built_response.pack()
|
|
467
555
|
# If we're in online mode
|
|
@@ -476,7 +564,7 @@ class DnsServer:
|
|
|
476
564
|
# Since, it's probably going to succeed.
|
|
477
565
|
if counter > 0:
|
|
478
566
|
self.logger.info(f"Retry #: {counter}/{self.dns_service_retries}")
|
|
479
|
-
self.
|
|
567
|
+
self.logger.info(
|
|
480
568
|
f"Forwarding request. Creating UDP socket to: "
|
|
481
569
|
f"{self.forwarding_dns_service_ipv4}:"
|
|
482
570
|
f"{self.forwarding_dns_service_port}")
|
|
@@ -486,7 +574,7 @@ class DnsServer:
|
|
|
486
574
|
|
|
487
575
|
message = "Socket created, Forwarding..."
|
|
488
576
|
# self.logger.info(message)
|
|
489
|
-
self.
|
|
577
|
+
self.logger.info(message)
|
|
490
578
|
|
|
491
579
|
google_dns_ipv4_socket.sendto(client_data, (
|
|
492
580
|
self.forwarding_dns_service_ipv4,
|
|
@@ -495,7 +583,7 @@ class DnsServer:
|
|
|
495
583
|
# The script needs to wait a second or receive can hang
|
|
496
584
|
message = "Request sent to the forwarding DNS, Receiving the answer..."
|
|
497
585
|
# self.logger.info(message)
|
|
498
|
-
self.
|
|
586
|
+
self.logger.info(message)
|
|
499
587
|
|
|
500
588
|
dns_response, google_address = \
|
|
501
589
|
google_dns_ipv4_socket.recvfrom(self.buffer_size_receive)
|
|
@@ -516,7 +604,6 @@ class DnsServer:
|
|
|
516
604
|
f"Couldn't forward DNS request to: "
|
|
517
605
|
f"[{self.forwarding_dns_service_ipv4}]. "
|
|
518
606
|
f"Continuing to next request.")
|
|
519
|
-
self.dns_full_logger.info("==========")
|
|
520
607
|
|
|
521
608
|
# From here continue to the next iteration of While loop.
|
|
522
609
|
continue
|
|
@@ -529,12 +616,12 @@ class DnsServer:
|
|
|
529
616
|
if retried:
|
|
530
617
|
continue
|
|
531
618
|
|
|
532
|
-
self.
|
|
619
|
+
self.logger.info(
|
|
533
620
|
f"Answer received from: {self.forwarding_dns_service_ipv4}")
|
|
534
621
|
|
|
535
622
|
# Closing the socket to forwarding service
|
|
536
623
|
google_dns_ipv4_socket.close()
|
|
537
|
-
self.
|
|
624
|
+
self.logger.info("Closed socket to forwarding service")
|
|
538
625
|
|
|
539
626
|
# Appending current DNS Request and DNS Answer to the Cache
|
|
540
627
|
self.dns_questions_to_answers_cache.update({client_data: dns_response})
|
|
@@ -542,14 +629,15 @@ class DnsServer:
|
|
|
542
629
|
# If 'forward_to_tcp_server' it means that we built the response, and we don't need to reparse it,
|
|
543
630
|
# since we already have all the data.
|
|
544
631
|
if forward_to_tcp_server:
|
|
545
|
-
self.
|
|
546
|
-
self.
|
|
632
|
+
# self.logger.info(f"Response {dns_built_response.short()}")
|
|
633
|
+
self.dns_statistics_csv_writer.write_row(
|
|
634
|
+
client_address=client_address, dns_response=dns_built_response)
|
|
547
635
|
|
|
548
636
|
message = f"Response Details: {dns_built_response.rr}"
|
|
549
|
-
print_api(message, logger=self.
|
|
637
|
+
print_api(message, logger=self.logger, logger_method='info', oneline=True)
|
|
550
638
|
|
|
551
|
-
message = f"Response Full Details: {dns_built_response.format(prefix='', sort=True)}"
|
|
552
|
-
print_api(message, logger=self.
|
|
639
|
+
# message = f"Response Full Details: {dns_built_response.format(prefix='', sort=True)}"
|
|
640
|
+
# print_api(message, logger=self.logger, logger_method='info', oneline=True)
|
|
553
641
|
|
|
554
642
|
# Now we can turn it to false, so it won't trigger this
|
|
555
643
|
# condition next time if the response was not built
|
|
@@ -569,20 +657,23 @@ class DnsServer:
|
|
|
569
657
|
if dns_response_parsed.rr:
|
|
570
658
|
for rr in dns_response_parsed.rr:
|
|
571
659
|
if isinstance(rr.rdata, A):
|
|
572
|
-
self.
|
|
660
|
+
self.dns_statistics_csv_writer.write_row(
|
|
661
|
+
client_address=client_address, dns_response=dns_response_parsed)
|
|
662
|
+
|
|
663
|
+
self.logger.info(f"Response IP: {rr.rdata}")
|
|
573
664
|
|
|
574
665
|
# Adding the address to the list as 'str' object and not 'dnslib.dns.A'.
|
|
575
666
|
ipv4_addresses.append(str(rr.rdata))
|
|
576
667
|
|
|
577
|
-
message = f"Response Details: {dns_response_parsed.rr}"
|
|
578
|
-
print_api(message, logger=self.
|
|
579
|
-
|
|
580
|
-
message = f"Response Full Details: {dns_response_parsed}"
|
|
581
|
-
print_api(message, logger=self.
|
|
668
|
+
# message = f"Response Details: {dns_response_parsed.rr}"
|
|
669
|
+
# print_api(message, logger=self.dns_statistics_csv_writer, logger_method='info', oneline=True)
|
|
670
|
+
#
|
|
671
|
+
# message = f"Response Full Details: {dns_response_parsed}"
|
|
672
|
+
# print_api(message, logger=self.dns_statistics_csv_writer, logger_method='info', oneline=True)
|
|
582
673
|
|
|
583
|
-
self.
|
|
674
|
+
self.logger.info("Sending DNS response back to client...")
|
|
584
675
|
main_socket_object.sendto(dns_response, client_address)
|
|
585
|
-
self.
|
|
676
|
+
self.logger.info("DNS Response sent...")
|
|
586
677
|
|
|
587
678
|
# 'ipv4_addresses' list contains entries of type 'dnslib.dns.A' and not string.
|
|
588
679
|
# We'll convert each entry to string, so strings can be searched in this list.
|
|
@@ -661,9 +752,9 @@ class DnsServer:
|
|
|
661
752
|
) as output_file:
|
|
662
753
|
output_file.write(record_string_line)
|
|
663
754
|
|
|
664
|
-
self.
|
|
665
|
-
|
|
666
|
-
|
|
755
|
+
# self.logger.info(
|
|
756
|
+
# f"Saved new known domains file: "
|
|
757
|
+
# f"{self.log_directory_path}{os.sep}{self.known_domains_filename}")
|
|
667
758
|
|
|
668
759
|
# Known domain list managements EOF
|
|
669
760
|
# ==================================================================================================
|
|
@@ -720,9 +811,9 @@ class DnsServer:
|
|
|
720
811
|
) as output_file:
|
|
721
812
|
output_file.write(record_string_line)
|
|
722
813
|
|
|
723
|
-
self.
|
|
724
|
-
|
|
725
|
-
|
|
814
|
+
# self.logger.info(
|
|
815
|
+
# f"Saved new known IPv4 addresses file: "
|
|
816
|
+
# f"{self.log_directory_path}{os.sep}{self.known_ipv4_filename}")
|
|
726
817
|
|
|
727
818
|
# Known IPv4 address to domains list management EOF
|
|
728
819
|
# ==================================================================================================
|
|
@@ -743,7 +834,7 @@ class DnsServer:
|
|
|
743
834
|
# EOF Writing IPs by time.
|
|
744
835
|
# ==================================================================================================
|
|
745
836
|
|
|
746
|
-
self.
|
|
837
|
+
# self.logger.info("==========")
|
|
747
838
|
except Exception:
|
|
748
839
|
message = "Unknown Exception: to parse DNS request"
|
|
749
840
|
print_api(
|
|
@@ -5,6 +5,7 @@ from pathlib import Path
|
|
|
5
5
|
|
|
6
6
|
from ..psutilw import networks
|
|
7
7
|
from ..certauthw import certauthw
|
|
8
|
+
from ..loggingw import loggingw
|
|
8
9
|
from ...script_as_string_processor import ScriptAsStringProcessor
|
|
9
10
|
from ...permissions import permissions
|
|
10
11
|
from ... import queues, filesystem, certificates
|
|
@@ -143,6 +144,7 @@ class SocketWrapper:
|
|
|
143
144
|
:param ssh_pass: string, SSH password that will be used to connect to remote host.
|
|
144
145
|
:param ssh_script_to_execute: string, script that will be executed to get the process name on ssh remote host.
|
|
145
146
|
:param logger: logging.Logger object, logger object that will be used to log messages.
|
|
147
|
+
If not provided, logger will be created with default settings.
|
|
146
148
|
:param statistics_logs_directory: string, path to directory where daily statistics.csv files will be stored.
|
|
147
149
|
After you initialize the SocketWrapper object, you can get the statistics_writer object from it and use it
|
|
148
150
|
to write statistics to the file in a worker thread.
|
|
@@ -219,6 +221,16 @@ class SocketWrapper:
|
|
|
219
221
|
self.statistics_writer = statistics_csv.StatisticsCSVWriter(
|
|
220
222
|
statistics_directory_path=self.statistics_logs_directory)
|
|
221
223
|
|
|
224
|
+
if not self.logger:
|
|
225
|
+
self.logger = loggingw.create_logger(
|
|
226
|
+
logger_name='SocketWrapper',
|
|
227
|
+
directory_path=self.statistics_logs_directory,
|
|
228
|
+
add_stream=True,
|
|
229
|
+
add_timedfile=True,
|
|
230
|
+
formatter_streamhandler='DEFAULT',
|
|
231
|
+
formatter_filehandler='DEFAULT'
|
|
232
|
+
)
|
|
233
|
+
|
|
222
234
|
self.test_config()
|
|
223
235
|
|
|
224
236
|
def test_config(self):
|
|
@@ -5,9 +5,9 @@ from ..loggingw import loggingw
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
LOGGER_NAME: str = 'statistics'
|
|
8
|
-
STATISTICS_HEADER: str =
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
STATISTICS_HEADER: str = (
|
|
9
|
+
'request_time_sent,tls,protocol,host,path,command,status_code,request_size_bytes,response_size_bytes,file_path,'
|
|
10
|
+
'process_cmd,error')
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class StatisticsCSVWriter:
|
|
@@ -19,8 +19,6 @@ class StatisticsCSVWriter:
|
|
|
19
19
|
self,
|
|
20
20
|
statistics_directory_path: str
|
|
21
21
|
):
|
|
22
|
-
self.statistics_directory_path = statistics_directory_path
|
|
23
|
-
|
|
24
22
|
self.csv_logger = loggingw.create_logger(
|
|
25
23
|
logger_name=LOGGER_NAME,
|
|
26
24
|
directory_path=statistics_directory_path,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
atomicshop/__init__.py,sha256=
|
|
1
|
+
atomicshop/__init__.py,sha256=joVK_ueWgYu4gbqtZdDb4rswSixoXOc-sNEsTq6qwqs,124
|
|
2
2
|
atomicshop/_basics_temp.py,sha256=6cu2dd6r2dLrd1BRNcVDKTHlsHs_26Gpw8QS6v32lQ0,3699
|
|
3
3
|
atomicshop/_create_pdf_demo.py,sha256=Yi-PGZuMg0RKvQmLqVeLIZYadqEZwUm-4A9JxBl_vYA,3713
|
|
4
4
|
atomicshop/_patch_import.py,sha256=ENp55sKVJ0e6-4lBvZnpz9PQCt3Otbur7F6aXDlyje4,6334
|
|
@@ -122,15 +122,15 @@ atomicshop/file_io/tomls.py,sha256=ol8EvQPf9sryTmZUf1v55BYSUQ6ml7HVVBHpNKbsIlA,9
|
|
|
122
122
|
atomicshop/file_io/xlsxs.py,sha256=v_dyg9GD4LqgWi6wA1QuWRZ8zG4ZwB6Dz52ytdcmmmI,2184
|
|
123
123
|
atomicshop/file_io/xmls.py,sha256=zh3SuK-dNaFq2NDNhx6ivcf4GYCfGM8M10PcEwDSpxk,2104
|
|
124
124
|
atomicshop/mitm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
125
|
-
atomicshop/mitm/config_static.py,sha256=
|
|
125
|
+
atomicshop/mitm/config_static.py,sha256=ROAtbibSWSsF3BraUbhu-QO3MPIFqYY5KUKgsQbiSkk,7813
|
|
126
126
|
atomicshop/mitm/config_toml_editor.py,sha256=2p1CMcktWRR_NW-SmyDwylu63ad5e0-w1QPMa8ZLDBw,1635
|
|
127
127
|
atomicshop/mitm/connection_thread_worker.py,sha256=rfullUfMRR5YUEI45KJdGXlbOGYF89GfPkhUBoHizhM,20297
|
|
128
128
|
atomicshop/mitm/import_config.py,sha256=_nu8mgA-M4s6dZ8_QWx3x0aVb75upvsCuX_PIUg4X2w,8345
|
|
129
|
-
atomicshop/mitm/initialize_engines.py,sha256=
|
|
129
|
+
atomicshop/mitm/initialize_engines.py,sha256=VyJE8QnzlgD3QbX5inz5o6rC3zQ3is9CeTL7-B10g1w,8292
|
|
130
130
|
atomicshop/mitm/message.py,sha256=d_sm3O_aoZf87dDQP44xOMNEG-uZBN1ZecQgMCacbZs,1814
|
|
131
|
-
atomicshop/mitm/mitm_main.py,sha256=
|
|
131
|
+
atomicshop/mitm/mitm_main.py,sha256=yqVyyZvxqfu-lqsFmHGinXFGJ9TZ3ljGgJ-jU-wXJFk,21852
|
|
132
132
|
atomicshop/mitm/recs_files.py,sha256=B8fSuvYXlh50LWfwLRw_bYswreTjmdZLuHJzbDC5Gss,2930
|
|
133
|
-
atomicshop/mitm/shared_functions.py,sha256=
|
|
133
|
+
atomicshop/mitm/shared_functions.py,sha256=jjCDZVQCwQ8hf9QNMe3T8W3ISkfZo4Mm2HtXOJLZYgI,1999
|
|
134
134
|
atomicshop/mitm/statistic_analyzer.py,sha256=mBmwEe68WAjnIskGndQTRldnsAsDHuaOW0O7UXlM3Pc,26702
|
|
135
135
|
atomicshop/mitm/engines/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
136
136
|
atomicshop/mitm/engines/create_module_template.py,sha256=tRjVSm1sD6FzML71Qbuwvita0qsusdFGm8NZLsZ-XMs,4853
|
|
@@ -296,7 +296,7 @@ atomicshop/wrappers/socketw/accepter.py,sha256=hZZKVYlF3LOHQJsSIEKXZUf6QXXWm-Atq
|
|
|
296
296
|
atomicshop/wrappers/socketw/base.py,sha256=evoOIxg5Xff3THJnrVX00D5HobaOpDp6_e_gso7TJmA,2191
|
|
297
297
|
atomicshop/wrappers/socketw/certificator.py,sha256=3CpQKtcW68FSbH6LVSEZTqWBS6Yg_-3K0x4nFkId4UY,12236
|
|
298
298
|
atomicshop/wrappers/socketw/creator.py,sha256=3_OraDkw2DAWZfoSdY3svCGMOIxpjLEEY7NxWd7M5P4,9873
|
|
299
|
-
atomicshop/wrappers/socketw/dns_server.py,sha256=
|
|
299
|
+
atomicshop/wrappers/socketw/dns_server.py,sha256=r1kWeKVoiqqNb_HpZdk0Pm3Xo-NGDkCs0_0DzMmtE8o,48954
|
|
300
300
|
atomicshop/wrappers/socketw/exception_wrapper.py,sha256=B-X5SHLSUIWToihH2MKnOB1F4A81_X0DpLLfnYKYbEc,7067
|
|
301
301
|
atomicshop/wrappers/socketw/get_process.py,sha256=zKEqh98cB9UDLFhtxVpperfXsCjyIMNANHilDD06p0U,6094
|
|
302
302
|
atomicshop/wrappers/socketw/receiver.py,sha256=XVvWOoeCo3vA0O5p19ryi-hcDIyx382WNG7WzMNVeYk,9322
|
|
@@ -304,13 +304,13 @@ atomicshop/wrappers/socketw/sender.py,sha256=OcX1aeI2OBDPPfvQkiEcV4Ak22DSJVvjMGY
|
|
|
304
304
|
atomicshop/wrappers/socketw/sni.py,sha256=fVwyh3h9IqfLMnf4__bMIzcF4c-Kk9mlbDWMRXKN-ow,17155
|
|
305
305
|
atomicshop/wrappers/socketw/socket_client.py,sha256=hcHtOh43UhJAxYe7DSg4YVSJnCEKLRWKPiZ8DD8ite8,20237
|
|
306
306
|
atomicshop/wrappers/socketw/socket_server_tester.py,sha256=Qobmh4XV8ZxLUaw-eW4ESKAbeSLecCKn2OWFzMhadk0,6420
|
|
307
|
-
atomicshop/wrappers/socketw/socket_wrapper.py,sha256=
|
|
307
|
+
atomicshop/wrappers/socketw/socket_wrapper.py,sha256=VQNvR68xj0RD_v1OL19tDZf4xRskZQjrVE6piHvRXR8,33896
|
|
308
308
|
atomicshop/wrappers/socketw/ssl_base.py,sha256=kmiif84kMhBr5yjQW17p935sfjR5JKG0LxIwBA4iVvU,2275
|
|
309
|
-
atomicshop/wrappers/socketw/statistics_csv.py,sha256=
|
|
309
|
+
atomicshop/wrappers/socketw/statistics_csv.py,sha256=w1AH-zf4mBuT4euf28UKij9ihM-b1BRU9Qfby0QDdqI,2957
|
|
310
310
|
atomicshop/wrappers/winregw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
311
311
|
atomicshop/wrappers/winregw/winreg_network.py,sha256=bQ8Jql8bVGBJ0dt3VQ56lga_1LBOMLI3Km_otvvbU6c,7138
|
|
312
|
-
atomicshop-2.16.
|
|
313
|
-
atomicshop-2.16.
|
|
314
|
-
atomicshop-2.16.
|
|
315
|
-
atomicshop-2.16.
|
|
316
|
-
atomicshop-2.16.
|
|
312
|
+
atomicshop-2.16.26.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
|
|
313
|
+
atomicshop-2.16.26.dist-info/METADATA,sha256=B4rCAdBWrX5ocldHxSS8ijnIvauLJQ_de10bMYy-pto,10473
|
|
314
|
+
atomicshop-2.16.26.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
315
|
+
atomicshop-2.16.26.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
|
|
316
|
+
atomicshop-2.16.26.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|