atomicshop 2.21.1__py3-none-any.whl → 3.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of atomicshop might be problematic. Click here for more details.

Files changed (29) hide show
  1. atomicshop/__init__.py +1 -1
  2. atomicshop/basics/multiprocesses.py +228 -30
  3. atomicshop/dns.py +2 -0
  4. atomicshop/mitm/config_static.py +2 -1
  5. atomicshop/mitm/engines/create_module_template.py +2 -7
  6. atomicshop/mitm/import_config.py +36 -44
  7. atomicshop/mitm/initialize_engines.py +9 -24
  8. atomicshop/mitm/mitm_main.py +187 -59
  9. atomicshop/networks.py +448 -0
  10. atomicshop/wrappers/ctyping/setup_device.py +466 -0
  11. atomicshop/wrappers/dockerw/dockerw.py +17 -21
  12. atomicshop/wrappers/mongodbw/mongodbw.py +1 -0
  13. atomicshop/wrappers/psutilw/{networks.py → psutil_networks.py} +3 -1
  14. atomicshop/wrappers/pywin32w/wmis/msft_netipaddress.py +76 -0
  15. atomicshop/wrappers/pywin32w/wmis/win32_networkadapterconfiguration.py +262 -0
  16. atomicshop/wrappers/pywin32w/wmis/win32networkadapter.py +51 -82
  17. atomicshop/wrappers/pywin32w/wmis/wmi_helpers.py +235 -0
  18. atomicshop/wrappers/socketw/accepter.py +15 -1
  19. atomicshop/wrappers/socketw/creator.py +7 -1
  20. atomicshop/wrappers/socketw/dns_server.py +33 -39
  21. atomicshop/wrappers/socketw/exception_wrapper.py +20 -11
  22. atomicshop/wrappers/socketw/socket_wrapper.py +29 -78
  23. atomicshop/wrappers/winregw/winreg_network.py +20 -0
  24. {atomicshop-2.21.1.dist-info → atomicshop-3.0.1.dist-info}/METADATA +2 -1
  25. {atomicshop-2.21.1.dist-info → atomicshop-3.0.1.dist-info}/RECORD +28 -24
  26. atomicshop/wrappers/pywin32w/wmis/helpers.py +0 -131
  27. {atomicshop-2.21.1.dist-info → atomicshop-3.0.1.dist-info}/LICENSE.txt +0 -0
  28. {atomicshop-2.21.1.dist-info → atomicshop-3.0.1.dist-info}/WHEEL +0 -0
  29. {atomicshop-2.21.1.dist-info → atomicshop-3.0.1.dist-info}/top_level.txt +0 -0
@@ -2,12 +2,21 @@ from . import exception_wrapper
2
2
 
3
3
 
4
4
  @exception_wrapper.connection_exception_decorator
5
- def accept_connection(socket_object, domain_from_dns_server, print_kwargs: dict = None):
5
+ def accept_connection(
6
+ socket_object,
7
+ domain_from_dns_server: str = None,
8
+ print_kwargs: dict = None
9
+ ):
6
10
  """
7
11
  Accept connection from client.
8
12
  This function is wrapped with exception wrapper.
9
13
  After you execute the function, you can get the error message if there was any with:
10
14
  error_message = accept_connection.message
15
+
16
+ :param socket_object: The socket object to accept the connection on.
17
+ :param domain_from_dns_server: The domain that will be printed to console on logger, needed for the decorator.
18
+ If not provided, the TCP data will be used.
19
+ :param print_kwargs: Additional arguments for the print_api function, needed for the decorator.
11
20
  """
12
21
 
13
22
  client_socket = None
@@ -33,6 +42,11 @@ def accept_connection_with_error(
33
42
  domain_from_dns_server,
34
43
  print_kwargs: dict = None
35
44
  ):
45
+ """
46
+ :param socket_object: The socket object to accept the connection on.
47
+ :param domain_from_dns_server: The domain that will be printed to console on logger.
48
+ :param print_kwargs: Additional arguments for the print_api function.
49
+ """
36
50
  client_socket, client_address_tuple = accept_connection(
37
51
  socket_object, domain_from_dns_server, print_kwargs=print_kwargs)
38
52
  error_message = accept_connection.message
@@ -151,13 +151,19 @@ def create_server_ssl_context___load_certificate_and_key(certificate_file_path:
151
151
  def wrap_socket_with_ssl_context_server(
152
152
  socket_object,
153
153
  ssl_context,
154
- domain_from_dns_server,
154
+ domain_from_dns_server: str = None,
155
155
  print_kwargs: dict = None
156
156
  ):
157
157
  """
158
158
  This function is wrapped with exception wrapper.
159
159
  After you execute the function, you can get the error message if there was any with:
160
160
  error_message = wrap_socket_with_ssl_context_server.message
161
+
162
+ :param socket_object: The socket object to accept the connection on.
163
+ :param ssl_context: The SSL context to wrap the socket with.
164
+ :param domain_from_dns_server: The domain that will be printed to console on logger, needed for the decorator.
165
+ If not provided, the TCP data will be used.
166
+ :param print_kwargs: Additional arguments for the print_api function, needed for the decorator.
161
167
  """
162
168
 
163
169
  # Wrapping the server socket with SSL context. This should happen right after setting up the raw socket.
@@ -5,12 +5,12 @@ import threading
5
5
  import socket
6
6
  import logging
7
7
  from pathlib import Path
8
- from typing import Literal
8
+ from typing import Literal, Optional
9
9
  import multiprocessing
10
10
 
11
11
  from ...print_api import print_api
12
12
  from ..loggingw import loggingw
13
- from ..psutilw import networks
13
+ from ..psutilw import psutil_networks
14
14
  from ...basics import booleans, tracebacks
15
15
  from ...file_io import csvs
16
16
 
@@ -153,7 +153,6 @@ class DnsServer:
153
153
  resolve_regular_pass_thru: bool = False,
154
154
  resolve_all_domains_to_ipv4: tuple[bool, str] = (False, '127.0.0.1'),
155
155
  offline_mode: bool = False,
156
- request_domain_queue: multiprocessing.Queue = None,
157
156
  buffer_size_receive: int = 8192,
158
157
  response_ttl: int = 60,
159
158
  dns_service_retries: int = 5,
@@ -183,7 +182,6 @@ class DnsServer:
183
182
  :param resolve_all_domains_to_ipv4: tuple(boolean to enable the feature, string IPv4 of the target).
184
183
  True, the DNS Server will route all domains to the specified IPv4.
185
184
  :param offline_mode: bool: If the DNS Server should work in offline mode.
186
- :param request_domain_queue: multiprocessing Queue to pass all the requested domains that hit the DNS
187
185
  :param buffer_size_receive: int: Buffer size of the connection while receiving messages.
188
186
  :param response_ttl: int, Time to live of the DNS Response that will be returned. Default is 60 seconds.
189
187
  :param dns_service_retries: int, How many times the request will be sent to forwarded DNS Service on errors:
@@ -208,7 +206,6 @@ class DnsServer:
208
206
  self.resolve_regular_pass_thru: bool = resolve_regular_pass_thru
209
207
  self.resolve_all_domains_to_ipv4: tuple[bool, str] = resolve_all_domains_to_ipv4
210
208
  self.offline_mode: bool = offline_mode
211
- self.request_domain_queue: multiprocessing.Queue = request_domain_queue
212
209
  self.buffer_size_receive: int = buffer_size_receive
213
210
  self.response_ttl: int = response_ttl
214
211
  self.dns_service_retries: int = dns_service_retries
@@ -229,17 +226,13 @@ class DnsServer:
229
226
  self.resolve_all_domains_to_ipv4_enable: bool
230
227
  self.resolve_all_domains_target: str
231
228
 
232
- self.intercept_domain_list: list = list()
229
+ self.intercept_domain_dict: dict = dict()
233
230
  for engine in self.engine_list:
234
231
  # If the engine is not a reference engine.
235
232
  if engine.engine_name != '__reference_general':
236
233
  # Get the domains from the engine.
237
- self.intercept_domain_list.extend(engine.domain_list)
238
234
 
239
- # If the engine has no_sni section enabled, get the domains from it.
240
- if engine.no_sni.serve_domain_on_address_enable:
241
- for domain, ip_address in engine.no_sni.serve_domain_on_address_dict.items():
242
- self.intercept_domain_list.append(domain)
235
+ self.intercept_domain_dict.update(engine.domain_target_dict)
243
236
 
244
237
  # Settings for static DNS Responses in offline mode.
245
238
  self.offline_route_ipv4: str = '10.10.10.10'
@@ -310,7 +303,7 @@ class DnsServer:
310
303
  raise DnsConfigurationValuesError(e)
311
304
 
312
305
  ips_ports: list[str] = [f'{self.listening_interface}:{self.listening_port}']
313
- port_in_use = networks.get_processes_using_port_list(ips_ports)
306
+ port_in_use = psutil_networks.get_processes_using_port_list(ips_ports)
314
307
  if port_in_use:
315
308
  error_messages: list = list()
316
309
  for port, process_info in port_in_use.items():
@@ -357,7 +350,7 @@ class DnsServer:
357
350
  message = "Routing engine domains to the specified IPv4 targets."
358
351
  print_api(message, logger=self.logger)
359
352
 
360
- message = f"Current all engines domains: {self.intercept_domain_list}"
353
+ message = f"Current all engines domains: {list(self.intercept_domain_dict.keys())}"
361
354
  print_api(message, logger=self.logger, color='blue')
362
355
 
363
356
  if self.resolve_all_domains_to_ipv4_enable:
@@ -473,7 +466,7 @@ class DnsServer:
473
466
  if self.resolve_by_engine_enable:
474
467
  # If current query domain (+ subdomains) CONTAIN any of the domains from modules config
475
468
  # files and current request contains "A" (IPv4) record.
476
- if any(x in question_domain for x in self.intercept_domain_list):
469
+ if any(x in question_domain for x in self.intercept_domain_dict.keys()):
477
470
  # If incoming domain contains any of the 'engine_domains' then domain will
478
471
  # be forwarded to our TCP Server.
479
472
  forward_to_tcp_server = True
@@ -498,32 +491,14 @@ class DnsServer:
498
491
  if forward_to_tcp_server:
499
492
  if self.resolve_by_engine_enable:
500
493
  for engine in self.engine_list:
501
- # Check if the incoming domain contain any of the domains in the list.
502
- if any(x in question_domain for x in engine.domain_list):
503
- # Get the target IP address from the engine.
504
- resolved_target_ipv4 = engine.dns_target
505
-
506
- if engine.no_sni.get_from_dns:
507
- # If the request is forwarded to TCP server, then we'll put the domain in the domain queue.
508
- # self.request_domain_queue.put(question_domain)
509
- self.request_domain_queue.put(question_domain)
510
-
494
+ resolved_target_ipv4 = get_target_ip_from_engine(question_domain, engine.domain_target_dict)
495
+ # If the domain was found in the current engine's domain list, we can stop the loop.
496
+ if resolved_target_ipv4:
511
497
  break
512
-
513
- if engine.no_sni.serve_domain_on_address_enable:
514
- if question_domain in engine.no_sni.serve_domain_on_address_dict:
515
- ip_port_address: str = engine.no_sni.serve_domain_on_address_dict[question_domain]
516
- target_ip = ip_port_address.split(':')[0]
517
- resolved_target_ipv4 = target_ip
518
- break
519
-
520
- if self.resolve_all_domains_to_ipv4_enable:
498
+ elif self.resolve_all_domains_to_ipv4_enable:
521
499
  # Assign the target IPv4 address to the resolved target IPv4 variable.
522
500
  resolved_target_ipv4 = self.resolve_all_domains_target
523
501
 
524
- # Put the domain in the domain queue.
525
- self.request_domain_queue.put(question_domain)
526
-
527
502
  # Make DNS response that will refer TCP traffic to our server
528
503
  dns_built_response = DNSRecord(
529
504
  # dns_object.header,
@@ -913,6 +888,27 @@ class DnsServer:
913
888
  continue
914
889
 
915
890
 
891
+ def get_target_ip_from_engine(
892
+ target_domain: str,
893
+ engine_domain_target_dict: dict
894
+ ) -> Optional[str]:
895
+ """
896
+ Get the target IP address from the engine.
897
+
898
+ :param target_domain: str: The domain to return the target IP address for.
899
+ :param engine_domain_target_dict: dict: The dictionary of domains and their target IPs.
900
+
901
+ :return: str: The target IP address.
902
+ """
903
+ # Iterate through the list of engines.
904
+ for domain, target_ip_port in engine_domain_target_dict.items():
905
+ if domain in target_domain:
906
+ # Get the target IP address from the engine.
907
+ return target_ip_port['ip']
908
+
909
+ return None
910
+
911
+
916
912
  # noinspection PyPep8Naming
917
913
  def start_dns_server_multiprocessing_worker(
918
914
  listening_address: str,
@@ -925,7 +921,6 @@ def start_dns_server_multiprocessing_worker(
925
921
  resolve_all_domains_to_ipv4: tuple[bool, str],
926
922
  offline_mode: bool,
927
923
  cache_timeout_minutes: int,
928
- request_domain_queue: multiprocessing.Queue,
929
924
  logging_queue: multiprocessing.Queue,
930
925
  logger_name: str
931
926
  ):
@@ -945,7 +940,6 @@ def start_dns_server_multiprocessing_worker(
945
940
  resolve_all_domains_to_ipv4=resolve_all_domains_to_ipv4,
946
941
  offline_mode=offline_mode,
947
942
  cache_timeout_minutes=cache_timeout_minutes,
948
- request_domain_queue=request_domain_queue,
949
943
  logging_queue=logging_queue,
950
944
  logger_name=logger_name
951
945
  )
@@ -954,4 +948,4 @@ def start_dns_server_multiprocessing_worker(
954
948
  time.sleep(1)
955
949
  return 1
956
950
 
957
- dns_server_instance.start()
951
+ dns_server_instance.start()
@@ -14,7 +14,13 @@ def connection_exception_decorator(function_name):
14
14
  args, kwargs = get_target_function_default_args_and_combine_with_current(function_name, *args, **kwargs)
15
15
 
16
16
  wrapper_handle_connection_exceptions.message = None
17
- port = kwargs['socket_object'].getsockname()[1]
17
+ listen_ipv4, port = kwargs['socket_object'].getsockname()
18
+
19
+ domain_from_dns_server = kwargs['domain_from_dns_server']
20
+ if not domain_from_dns_server:
21
+ # If the domain is not passed, we will use the TCP data.
22
+ # This is needed for the decorator to work properly.
23
+ domain_from_dns_server = listen_ipv4
18
24
 
19
25
  try:
20
26
  # Since our 'kwargs' has already all the needed arguments, we don't need 'args'.
@@ -24,12 +30,12 @@ def connection_exception_decorator(function_name):
24
30
  # After that second exception will be "pass"-ed. This is an exception inside an exception handling.
25
31
  # Looks like was introduced in Python 3 in PEP 3134.
26
32
  except ConnectionAbortedError:
27
- message = f"Socket Accept: {kwargs['domain_from_dns_server']}:{port}: " \
33
+ message = f"Socket Accept: {domain_from_dns_server}:{port}: " \
28
34
  f"* Established connection was aborted by software on the host..."
29
35
  wrapper_handle_connection_exceptions.message = message
30
36
  print_api(message, logger_method='error', traceback_string=True, oneline=True, **kwargs['print_kwargs'])
31
37
  except ConnectionResetError:
32
- message = f"Socket Accept: {kwargs['domain_from_dns_server']}:{port}: " \
38
+ message = f"Socket Accept: {domain_from_dns_server}:{port}: " \
33
39
  f"* An existing connection was forcibly closed by the remote host..."
34
40
  wrapper_handle_connection_exceptions.message = message
35
41
  print_api(message, logger_method='error', traceback_string=True, oneline=True, **kwargs['print_kwargs'])
@@ -43,10 +49,11 @@ def connection_exception_decorator(function_name):
43
49
  wrapper_handle_connection_exceptions.message = message
44
50
  try:
45
51
  message = \
46
- f"Socket Accept: {kwargs['domain_from_dns_server']}:{port}: {message}"
52
+ f"Socket Accept: {domain_from_dns_server}:{port}: {message}"
47
53
  wrapper_handle_connection_exceptions.message = message
48
54
  print_api(message, error_type=True, logger_method='error', oneline=True, **kwargs['print_kwargs'])
49
- except Exception:
55
+ except Exception as e:
56
+ _ = e
50
57
  message = f"Socket Accept: port {port}: {message}"
51
58
  wrapper_handle_connection_exceptions.message = message
52
59
  print_api(message, logger_method='error', traceback_string=True, oneline=True, **kwargs['print_kwargs'])
@@ -57,10 +64,11 @@ def connection_exception_decorator(function_name):
57
64
  wrapper_handle_connection_exceptions.message = message
58
65
  try:
59
66
  message = \
60
- f"Socket Accept: {kwargs['domain_from_dns_server']}:{port}: {message}"
67
+ f"Socket Accept: {domain_from_dns_server}:{port}: {message}"
61
68
  wrapper_handle_connection_exceptions.message = message
62
69
  print_api(message, logger_method='error', oneline=True, **kwargs['print_kwargs'])
63
- except Exception:
70
+ except Exception as e:
71
+ _ = e
64
72
  message = f"Socket Accept: port {port}: {message}"
65
73
  wrapper_handle_connection_exceptions.message = message
66
74
  print_api(message, logger_method='error', traceback_string=True, oneline=True, **kwargs['print_kwargs'])
@@ -91,20 +99,21 @@ def connection_exception_decorator(function_name):
91
99
  message = f'ssl.SSLError:{exception_object}'
92
100
  wrapper_handle_connection_exceptions.message = message
93
101
  message = \
94
- f"Socket Accept: {kwargs['domain_from_dns_server']}:{port}: {message}"
102
+ f"Socket Accept: {domain_from_dns_server}:{port}: {message}"
95
103
  wrapper_handle_connection_exceptions.message = message
96
104
  print_api(message, logger_method='error', oneline=True, **kwargs['print_kwargs'])
97
105
  pass
98
106
  except FileNotFoundError:
99
107
  message = "'SSLSocket.accept()' crashed: 'FileNotFoundError'. Some problem with SSL during Handshake - " \
100
108
  "Could be certificate, client, or server."
101
- message = f"Socket Accept: {kwargs['domain_from_dns_server']}:{port}: {message}"
109
+ message = f"Socket Accept: {domain_from_dns_server}:{port}: {message}"
102
110
  wrapper_handle_connection_exceptions.message = message
103
111
  print_api(message, logger_method='error', traceback_string=True, oneline=True, **kwargs['print_kwargs'])
104
112
  pass
105
- except Exception:
113
+ except Exception as e:
114
+ _ = e
106
115
  message = "Undocumented exception on accept."
107
- message = f"Socket Accept: {kwargs['domain_from_dns_server']}:{port}: {message}"
116
+ message = f"Socket Accept: {domain_from_dns_server}:{port}: {message}"
108
117
  wrapper_handle_connection_exceptions.message = message
109
118
  print_api(message, logger_method='error', traceback_string=True, oneline=True, **kwargs['print_kwargs'])
110
119
  pass
@@ -4,11 +4,9 @@ from typing import Literal, Union
4
4
  from pathlib import Path
5
5
  import logging
6
6
  import socket
7
- import multiprocessing
8
- import queue
9
7
 
10
8
  from ...mitm import initialize_engines
11
- from ..psutilw import networks
9
+ from ..psutilw import psutil_networks
12
10
  from ..certauthw import certauthw
13
11
  from ..loggingw import loggingw
14
12
  from ...script_as_string_processor import ScriptAsStringProcessor
@@ -69,7 +67,6 @@ class SocketWrapper:
69
67
  logger: logging.Logger = None,
70
68
  exceptions_logger: loggingw.ExceptionCsvLogger = None,
71
69
  statistics_logs_directory: str = None,
72
- request_domain_from_dns_server_queue: multiprocessing.Queue = None,
73
70
  no_engine_usage_enable: bool = False,
74
71
  no_engines_listening_address_list: list[str] = None,
75
72
  engines_list: list[initialize_engines.ModuleCategory] = None
@@ -162,10 +159,6 @@ class SocketWrapper:
162
159
 
163
160
  statistics_writer: statistics_csv.StatisticsCSVWriter object, there is a logger object that
164
161
  will be used to write the statistics file.
165
- :param request_domain_from_dns_server_queue: multiprocessing queue that will be used
166
- to get the domain name that was requested from the DNS server (atomicshop.wrappers.socketw.dns_server).
167
- This is used to get the domain name that got to the DNS server and set it to the socket in case SNI
168
- was empty (in the SNIHandler class to set the 'server_hostname' for the socket).
169
162
  :param no_engine_usage_enable: boolean, if True, 'engines_list' will be used to listen on the addresses,
170
163
  but the "no_engines_listening_address_list" parameter will be used instead.
171
164
  :param no_engines_listening_address_list: list, of ips+ports that will be listened on.
@@ -215,23 +208,10 @@ class SocketWrapper:
215
208
  self.statistics_logs_directory: str = statistics_logs_directory
216
209
  self.forwarding_dns_service_ipv4_list___only_for_localhost = (
217
210
  forwarding_dns_service_ipv4_list___only_for_localhost)
218
- self.request_domain_from_dns_server_queue: multiprocessing.Queue = request_domain_from_dns_server_queue
219
211
  self.no_engine_usage_enable: bool = no_engine_usage_enable
220
212
  self.no_engines_listening_address_list: list[str] = no_engines_listening_address_list
221
213
  self.engines_list: list[initialize_engines.ModuleCategory] = engines_list
222
214
 
223
- # dictionary of engines that will be used to find the engine name. Example:
224
- # [{'this_is_engine_name': ['example.com', 'example.org']},
225
- # {'this_is_engine_name2': ['example2.com', 'example2.org']}]
226
- self.engines_domains: dict = dict()
227
- for engine in self.engines_list:
228
- self.engines_domains[engine.engine_name] = engine.domain_list
229
-
230
- if engine.no_sni.serve_domain_on_address_enable:
231
- for domain, ip_port_address in engine.no_sni.serve_domain_on_address_dict.items():
232
- if domain not in self.engines_domains[engine.engine_name]:
233
- self.engines_domains[engine.engine_name].append(domain)
234
-
235
215
  self.socket_object = None
236
216
 
237
217
  # Server certificate file path that will be loaded into SSL Context.
@@ -351,12 +331,13 @@ class SocketWrapper:
351
331
  listening_check_list: list = list()
352
332
  if self.engines_list:
353
333
  for engine in self.engines_list:
354
- for address in engine.tcp_listening_address_list:
334
+ for _, ip_port_dict in engine.domain_target_dict.items():
335
+ address: str = f"{ip_port_dict['ip']}:{ip_port_dict['port']}"
355
336
  if address not in listening_check_list:
356
337
  listening_check_list.append(address)
357
338
  else:
358
339
  listening_check_list = self.no_engines_listening_address_list
359
- port_in_use = networks.get_processes_using_port_list(listening_check_list)
340
+ port_in_use = psutil_networks.get_processes_using_port_list(listening_check_list)
360
341
  if port_in_use:
361
342
  error_messages: list = list()
362
343
  for port, process_info in port_in_use.items():
@@ -447,9 +428,9 @@ class SocketWrapper:
447
428
  if not self.no_engine_usage_enable:
448
429
  for engine in self.engines_list:
449
430
  # Start all the regular listening interfaces.
450
- for address in engine.tcp_listening_address_list:
451
- ip_address, port_str = address.split(':')
452
- port = int(port_str)
431
+ for domain, ip_port_dict in engine.domain_target_dict.items():
432
+ ip_address: str = ip_port_dict['ip']
433
+ port = int(ip_port_dict['port'])
453
434
  socket_by_port = self.create_socket_ipv4_tcp(ip_address, port)
454
435
  threading.Thread(
455
436
  target=self.listening_socket_loop,
@@ -458,20 +439,6 @@ class SocketWrapper:
458
439
  name=f"acceptor-{engine.engine_name}-{ip_address}:{port}",
459
440
  daemon=True
460
441
  ).start()
461
-
462
- # Start all the interfaces configured in the no_sni section.
463
- if engine.no_sni.serve_domain_on_address_enable:
464
- for domain, ip_port_address in engine.no_sni.serve_domain_on_address_dict.items():
465
- ip_address, port_str = ip_port_address.split(':')
466
- port = int(port_str)
467
- socket_by_port = self.create_socket_ipv4_tcp(ip_address, port)
468
- threading.Thread(
469
- target=self.listening_socket_loop,
470
- args=(socket_by_port, engine, reference_function_name,
471
- reference_function_args, pass_function_reference_to_thread),
472
- name=f"acceptor-{engine.engine_name}-{ip_address}:{port}",
473
- daemon=True
474
- ).start()
475
442
  else:
476
443
  # If no engines were passed, we will use the listening addresses from the configuration.
477
444
  for address in self.no_engines_listening_address_list:
@@ -540,33 +507,21 @@ class SocketWrapper:
540
507
  readable, writable, exceptional = select.select(listening_sockets, [], [])
541
508
  listening_socket_object = readable[0]
542
509
 
543
- # Get the domain queue. Tried using "Queue.Queue" object, but it stomped the SSL Sockets
544
- # from accepting connections.
545
- domain_from_dns_server = None
546
- if self.request_domain_from_dns_server_queue is not None:
547
- # domain_from_dns_server = self.request_domain_from_dns_server_queue.get()
548
- if engine.no_sni.get_from_dns:
549
- domain_from_dns_server = self.request_domain_from_dns_server_queue.get()
550
-
551
- if engine.no_sni.serve_domain_on_address_enable:
552
- # try:
553
- # domain_from_dns_server = self.request_domain_from_dns_server_queue.get_nowait()
554
- # except queue.Empty:
555
- # domain_from_dns_server = engine.no_sni['domain']
556
-
557
- listening_ip, listening_port = listening_socket_object.getsockname()
558
- for domain, ip_port_address in engine.no_sni.serve_domain_on_address_dict.items():
559
- ip_address: str = ip_port_address.split(':')[0]
560
- if ip_address == listening_ip:
561
- domain_from_dns_server = domain
562
- break
563
-
564
- self.logger.info(f"Requested domain from DNS Server: {domain_from_dns_server}")
510
+ listening_ip, listening_port = listening_socket_object.getsockname()
511
+
512
+ domain_from_engine = None
513
+ for engine in self.engines_list:
514
+ for domain, ip_port_dict in engine.domain_target_dict.items():
515
+ if ip_port_dict['ip'] == listening_ip:
516
+ domain_from_engine = domain
517
+ break
518
+
519
+ self.logger.info(f"NO SNI requested domain setting: {domain_from_engine}")
565
520
 
566
521
  # Wait from any connection on "accept()".
567
522
  # 'client_socket' is socket or ssl socket, 'client_address' is a tuple (ip_address, port).
568
523
  client_socket, client_address, accept_error_message = accepter.accept_connection_with_error(
569
- listening_socket_object, domain_from_dns_server=domain_from_dns_server,
524
+ listening_socket_object, domain_from_dns_server=domain_from_engine,
570
525
  print_kwargs={'logger': self.logger})
571
526
 
572
527
  # This is the earliest stage to ask for process name.
@@ -585,7 +540,7 @@ class SocketWrapper:
585
540
 
586
541
  source_ip: str = client_address[0]
587
542
  source_hostname: str = socket.gethostbyaddr(source_ip)[0]
588
- engine_name: str = get_engine_name(domain_from_dns_server, self.engines_domains)
543
+ engine_name: str = get_engine_name(domain_from_engine, self.engines_list)
589
544
  dest_port: int = listening_socket_object.getsockname()[1]
590
545
 
591
546
  # If 'accept()' function worked well, SSL worked well, then 'client_socket' won't be empty.
@@ -625,7 +580,7 @@ class SocketWrapper:
625
580
  custom_server_certificate_usage=self.custom_server_certificate_usage,
626
581
  custom_server_certificate_path=self.custom_server_certificate_path,
627
582
  custom_private_key_path=self.custom_private_key_path,
628
- domain_from_dns_server=domain_from_dns_server,
583
+ domain_from_dns_server=domain_from_engine,
629
584
  forwarding_dns_service_ipv4_list___only_for_localhost=(
630
585
  self.forwarding_dns_service_ipv4_list___only_for_localhost),
631
586
  tls=is_tls,
@@ -643,7 +598,7 @@ class SocketWrapper:
643
598
  if engine_name == '':
644
599
  sni_hostname: str = ssl_client_socket.server_hostname
645
600
  if sni_hostname:
646
- engine_name = get_engine_name(sni_hostname, self.engines_domains)
601
+ engine_name = get_engine_name(sni_hostname, self.engines_list)
647
602
 
648
603
  if accept_error_message:
649
604
  # Write statistics after wrap is there was an error.
@@ -653,7 +608,7 @@ class SocketWrapper:
653
608
  source_ip=source_ip,
654
609
  error_message=accept_error_message,
655
610
  dest_port=str(dest_port),
656
- host=domain_from_dns_server,
611
+ host=domain_from_engine,
657
612
  process_name=process_name)
658
613
 
659
614
  continue
@@ -668,7 +623,7 @@ class SocketWrapper:
668
623
  client_socket = None
669
624
  client_socket = ssl_client_socket
670
625
  thread_args = \
671
- ((client_socket, process_name, is_tls, tls_type, tls_version, domain_from_dns_server) +
626
+ ((client_socket, process_name, is_tls, tls_type, tls_version, domain_from_engine) +
672
627
  reference_function_args)
673
628
  # If 'pass_function_reference_to_thread' was set to 'False', execute the callable passed function
674
629
  # as is.
@@ -691,7 +646,7 @@ class SocketWrapper:
691
646
  source_ip=source_ip,
692
647
  error_message=accept_error_message,
693
648
  dest_port=str(dest_port),
694
- host=domain_from_dns_server,
649
+ host=domain_from_engine,
695
650
  process_name=process_name)
696
651
  except Exception as e:
697
652
  self.exceptions_logger.write(e)
@@ -729,20 +684,16 @@ def before_socket_thread_worker(
729
684
  exceptions_logger.write(e)
730
685
 
731
686
 
732
- def get_engine_name(domain: str, engines_domains: dict):
687
+ def get_engine_name(domain: str, engine_list: list):
733
688
  """
734
689
  Function that will get the engine name from the domain name.
735
690
  :param domain: string, domain name.
736
- :param engines_domains: dictionary, dictionary that contains the engine names and domains. Example:
737
- [
738
- {'this_is_engine_name': ['example.com', 'example.org']},
739
- {'this_is_engine_name2': ['example2.com', 'example2.org']}
740
- ]
691
+ :param engine_list: list that contains the engine names and domains.
741
692
  :return: string, engine name.
742
693
  """
743
694
 
744
- for engine_name, engine_domain_list in engines_domains.items():
745
- if any(engine_domain in domain for engine_domain in engine_domain_list):
746
- return engine_name
695
+ for engine in engine_list:
696
+ if domain in engine.domain_target_dict:
697
+ return engine.engine_name
747
698
 
748
699
  return ''
@@ -205,3 +205,23 @@ def get_default_dns_gateway() -> tuple[bool, list[str]]:
205
205
 
206
206
  # noinspection PyTypeChecker
207
207
  return function_result
208
+
209
+
210
+ def change_metric_of_network_adapter(
211
+ adapter_guid: str,
212
+ metric: int
213
+ ) -> None:
214
+ """
215
+ Change the metric of a network adapter.
216
+ After you set new metric you need to restart the network adapter for the changes to take effect.
217
+
218
+ :param adapter_guid: str, GUID of the network adapter.
219
+ :param metric: int, new metric value.
220
+ :return: None
221
+ """
222
+
223
+ reg_path = fr"SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\{adapter_guid}"
224
+
225
+ with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, reg_path, 0, winreg.KEY_SET_VALUE) as key:
226
+ winreg.SetValueEx(key, "UseAutomaticMetric", 0, winreg.REG_DWORD, 0)
227
+ winreg.SetValueEx(key, "InterfaceMetric", 0, winreg.REG_DWORD, metric)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: atomicshop
3
- Version: 2.21.1
3
+ Version: 3.0.1
4
4
  Summary: Atomic functions and classes to make developer life easier
5
5
  Author: Denis Kras
6
6
  License: MIT License
@@ -41,6 +41,7 @@ Requires-Dist: docker
41
41
  Requires-Dist: flask-socketio
42
42
  Requires-Dist: google-api-python-client
43
43
  Requires-Dist: google-generativeai
44
+ Requires-Dist: icmplib
44
45
  Requires-Dist: numpy
45
46
  Requires-Dist: olefile
46
47
  Requires-Dist: openpyxl