atomicshop 2.16.24__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 CHANGED
@@ -1,4 +1,4 @@
1
1
  """Atomic Basic functions and classes to make developer life easier"""
2
2
 
3
3
  __author__ = "Den Kras"
4
- __version__ = '2.16.24'
4
+ __version__ = '2.16.26'
atomicshop/filesystem.py CHANGED
@@ -338,18 +338,20 @@ def create_directory(directory_fullpath: str):
338
338
  pathlib.Path(directory_fullpath).mkdir(parents=True, exist_ok=True)
339
339
 
340
340
 
341
- def rename_file(source_file_path: str, target_file_path: str) -> None:
341
+ def rename_file(file_path: str, new_file_name: str) -> None:
342
342
  """
343
343
  The function renames file from source to target.
344
344
 
345
- :param source_file_path: string, full path to source file.
346
- :param target_file_path: string, full path to target file.
345
+ :param file_path: string, full path to file that will be renamed.
346
+ :param new_file_name: string, new name of the file. No path should be included.
347
347
 
348
348
  :return: None
349
349
  """
350
350
 
351
+ renamed_file_path = str(Path(file_path).parent) + os.sep + new_file_name
352
+
351
353
  # Rename file.
352
- os.rename(source_file_path, target_file_path)
354
+ os.rename(file_path, renamed_file_path)
353
355
 
354
356
 
355
357
  @contextmanager
@@ -1569,7 +1571,7 @@ def backup_file(
1569
1571
  else:
1570
1572
  file_name: str = f"{file_name_no_extension}_{timestamp}{file_extension}"
1571
1573
  backup_file_path: str = str(Path(backup_directory) / file_name)
1572
- move_file(file_path, backup_directory)
1574
+ rename_file(file_path, file_name)
1573
1575
 
1574
1576
  return backup_file_path
1575
1577
  else:
@@ -48,6 +48,8 @@ TOML_TO_STATIC_CATEGORIES: dict = {
48
48
 
49
49
 
50
50
  class MainConfig:
51
+ LOGGER_NAME: str = 'network'
52
+
51
53
  SCRIPT_DIRECTORY: str = None
52
54
 
53
55
  ENGINES_DIRECTORY_PATH: str = None
@@ -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
- 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
- )
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(
@@ -1,4 +1,4 @@
1
- import os
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 mitm_server_main(config_file_path: str):
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
- # Create a logger that will log messages to file, Initiate System logger.
61
- logger_name = "system"
62
- system_logger = loggingw.create_logger(
63
- logger_name=logger_name,
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
- # General exception handler will catch all the exceptions that occurred in the threads and write it to the log.
343
- # noinspection PyBroadException
344
- try:
345
- socket_thread = threading.Thread(
346
- target=socket_wrapper_instance.loop_for_incoming_sockets,
347
- kwargs={
348
- 'reference_function_name': thread_worker_main,
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
- socket_thread.daemon = True
354
- socket_thread.start()
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
- logger_name = build_module_names(class_name)[0]
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.dns_full_logger = loggingw.create_logger(
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
- # print_api(message, logger=self.logger, logger_method='error', traceback_string=True)
257
- print_api(
258
- message, logger=self.dns_full_logger, logger_method='error', traceback_string=True)
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.dns_full_logger.info(f"QCLASS: {qclass_string}")
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.dns_full_logger.info(
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.dns_full_logger.info(message)
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.dns_full_logger.info(message)
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.dns_full_logger.info(
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.dns_full_logger.info("Closed socket to forwarding service")
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.dns_full_logger.info(f"Response IP: {dns_built_response.short()}")
546
- self.logger.info(f"Response {dns_built_response.short()}")
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.dns_full_logger, logger_method='info', oneline=True)
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.dns_full_logger, logger_method='info', oneline=True)
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.dns_full_logger.info(f"Response IP: {rr.rdata}")
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.dns_full_logger, logger_method='info', oneline=True)
579
-
580
- message = f"Response Full Details: {dns_response_parsed}"
581
- print_api(message, logger=self.dns_full_logger, logger_method='info', oneline=True)
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.dns_full_logger.info("Sending DNS response back to client...")
674
+ self.logger.info("Sending DNS response back to client...")
584
675
  main_socket_object.sendto(dns_response, client_address)
585
- self.dns_full_logger.info("DNS Response sent...")
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.dns_full_logger.info(
665
- f"Saved new known domains file: "
666
- f"{self.log_directory_path}{os.sep}{self.known_domains_filename}")
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.dns_full_logger.info(
724
- f"Saved new known IPv4 addresses file: "
725
- f"{self.log_directory_path}{os.sep}{self.known_ipv4_filename}")
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.dns_full_logger.info("==========")
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
- ('request_time_sent,tls,protocol,host,path,command,status_code,request_size_bytes,response_size_bytes,file_path,'
10
- 'process_cmd,error')
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,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: atomicshop
3
- Version: 2.16.24
3
+ Version: 2.16.26
4
4
  Summary: Atomic functions and classes to make developer life easier
5
5
  Author: Denis Kras
6
6
  License: MIT License
@@ -1,4 +1,4 @@
1
- atomicshop/__init__.py,sha256=CTmlCQGjYSV8TXiXGaZZB1S8I3hG61RNpEbQc104SF8,124
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
@@ -14,7 +14,7 @@ atomicshop/dns.py,sha256=J4yX6vCaRdL0McYWnlJ9arCDKW-yRui7Y5WyL5BoD6M,6391
14
14
  atomicshop/domains.py,sha256=Rxu6JhhMqFZRcoFs69IoEd1PtYca0lMCG6F1AomP7z4,3197
15
15
  atomicshop/emails.py,sha256=I0KyODQpIMEsNRi9YWSOL8EUPBiWyon3HRdIuSj3AEU,1410
16
16
  atomicshop/file_types.py,sha256=-0jzQMRlmU1AP9DARjk-HJm1tVE22E6ngP2mRblyEjY,763
17
- atomicshop/filesystem.py,sha256=XPrOjqxQRP3fa01QztDvuDUpiFjCYtpPUC0KhaGHxqs,60222
17
+ atomicshop/filesystem.py,sha256=ZDRRikFSUMleaUQJqxJGI5oVVH3H5qa2zeDVkZqghUE,60309
18
18
  atomicshop/functions.py,sha256=pK8hoCE9z61PtWCxQJsda7YAphrLH1wxU5x-1QJP-sY,499
19
19
  atomicshop/get_process_list.py,sha256=8cxb7gKe9sl4R6H2yMi8J6oe-RkonTvCdKjRFqi-Fs4,6075
20
20
  atomicshop/get_process_name_cmd_dll.py,sha256=CtaSp3mgxxJKCCVW8BLx6BJNx4giCklU_T7USiCEwfc,5162
@@ -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=UNvRTb3ZuFVGZpF33fvaIf0xw_VGyml2ExIwqW_uYcg,7777
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=Od1vC1ZGls0BNZiPgoRQj8Mc44UO8INJj3w1p5YQw5A,8274
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=gA8sV7hI107OnoeedCHpy8f3zcE4vAsBc44l_VTjVFo,21622
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=hplm98tz8pgJ4WHUVI9sf_oVqUM2KJ1Y2pD6EFSb8P0,1879
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=G3roqkj_gMRTkVs2kgwiQR9S7YqA-uQWraCt8FqKjlo,46375
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=M47tjC8SoXZJV2fC_OYmSNNTs-3-ZQcpaB1WmvqVCTU,33408
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=V_m1D0KpizQox3IEWp2AUcncwWy5kG25hbFrc-mBSJE,3029
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.24.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
313
- atomicshop-2.16.24.dist-info/METADATA,sha256=172BnmXPSDlG-AxPVViiY5xQNY2m7UqFq6DQ0ytD9zM,10473
314
- atomicshop-2.16.24.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
315
- atomicshop-2.16.24.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
316
- atomicshop-2.16.24.dist-info/RECORD,,
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,,