atomicshop 3.3.28__py3-none-any.whl → 3.10.0__py3-none-any.whl

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

Potentially problematic release.


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

Files changed (99) hide show
  1. atomicshop/__init__.py +1 -1
  2. atomicshop/a_mains/get_local_tcp_ports.py +85 -0
  3. atomicshop/a_mains/install_ca_certificate.py +172 -0
  4. atomicshop/a_mains/process_from_port.py +119 -0
  5. atomicshop/a_mains/set_default_dns_gateway.py +90 -0
  6. atomicshop/basics/strings.py +1 -1
  7. atomicshop/certificates.py +2 -2
  8. atomicshop/dns.py +26 -28
  9. atomicshop/etws/traces/trace_tcp.py +1 -2
  10. atomicshop/mitm/centered_settings.py +133 -0
  11. atomicshop/mitm/config_static.py +18 -43
  12. atomicshop/mitm/connection_thread_worker.py +376 -162
  13. atomicshop/mitm/engines/__parent/recorder___parent.py +1 -1
  14. atomicshop/mitm/engines/__parent/requester___parent.py +1 -1
  15. atomicshop/mitm/engines/__parent/responder___parent.py +15 -2
  16. atomicshop/mitm/engines/create_module_template.py +1 -2
  17. atomicshop/mitm/import_config.py +79 -88
  18. atomicshop/mitm/initialize_engines.py +1 -2
  19. atomicshop/mitm/message.py +5 -4
  20. atomicshop/mitm/mitm_main.py +222 -121
  21. atomicshop/mitm/recs_files.py +61 -5
  22. atomicshop/mitm/ssh_tester.py +82 -0
  23. atomicshop/networks.py +108 -93
  24. atomicshop/package_mains_processor.py +84 -0
  25. atomicshop/permissions/ubuntu_permissions.py +47 -0
  26. atomicshop/print_api.py +3 -5
  27. atomicshop/python_functions.py +23 -108
  28. atomicshop/speech_recognize.py +8 -0
  29. atomicshop/ssh_remote.py +115 -51
  30. atomicshop/web.py +20 -7
  31. atomicshop/web_apis/google_llm.py +22 -14
  32. atomicshop/wrappers/ctyping/msi_windows_installer/cabs.py +2 -1
  33. atomicshop/wrappers/ctyping/msi_windows_installer/extract_msi_main.py +2 -1
  34. atomicshop/wrappers/dockerw/dockerw.py +2 -2
  35. atomicshop/wrappers/factw/install/pre_install_and_install_before_restart.py +5 -5
  36. atomicshop/wrappers/githubw.py +175 -63
  37. atomicshop/wrappers/loggingw/handlers.py +1 -1
  38. atomicshop/wrappers/loggingw/loggingw.py +17 -1
  39. atomicshop/wrappers/netshw.py +124 -3
  40. atomicshop/wrappers/playwrightw/scenarios.py +1 -1
  41. atomicshop/wrappers/powershell_networking.py +80 -0
  42. atomicshop/wrappers/psutilw/psutil_networks.py +9 -0
  43. atomicshop/wrappers/pywin32w/win_event_log/fetch.py +174 -0
  44. atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_create.py +3 -105
  45. atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_terminate.py +3 -57
  46. atomicshop/wrappers/pywin32w/wmis/win32_networkadapterconfiguration.py +12 -27
  47. atomicshop/wrappers/pywin32w/wmis/win32networkadapter.py +15 -9
  48. atomicshop/wrappers/socketw/certificator.py +19 -9
  49. atomicshop/wrappers/socketw/creator.py +30 -7
  50. atomicshop/wrappers/socketw/dns_server.py +6 -6
  51. atomicshop/wrappers/socketw/exception_wrapper.py +3 -3
  52. atomicshop/wrappers/socketw/process_getter.py +86 -0
  53. atomicshop/wrappers/socketw/receiver.py +29 -9
  54. atomicshop/wrappers/socketw/sender.py +10 -9
  55. atomicshop/wrappers/socketw/sni.py +23 -6
  56. atomicshop/wrappers/socketw/{base.py → socket_base.py} +33 -1
  57. atomicshop/wrappers/socketw/socket_client.py +6 -8
  58. atomicshop/wrappers/socketw/socket_wrapper.py +82 -21
  59. atomicshop/wrappers/socketw/ssl_base.py +6 -2
  60. atomicshop/wrappers/win_auditw.py +189 -0
  61. {atomicshop-3.3.28.dist-info → atomicshop-3.10.0.dist-info}/METADATA +25 -30
  62. {atomicshop-3.3.28.dist-info → atomicshop-3.10.0.dist-info}/RECORD +74 -88
  63. atomicshop/_basics_temp.py +0 -101
  64. atomicshop/a_installs/ubuntu/docker_rootless.py +0 -11
  65. atomicshop/a_installs/ubuntu/docker_sudo.py +0 -11
  66. atomicshop/addons/a_setup_scripts/install_psycopg2_ubuntu.sh +0 -3
  67. atomicshop/addons/package_setup/CreateWheel.cmd +0 -7
  68. atomicshop/addons/package_setup/Setup in Edit mode.cmd +0 -6
  69. atomicshop/addons/package_setup/Setup.cmd +0 -7
  70. atomicshop/archiver/__init__.py +0 -0
  71. atomicshop/archiver/_search_in_zip.py +0 -189
  72. atomicshop/archiver/search_in_archive.py +0 -284
  73. atomicshop/archiver/sevenz_app_w.py +0 -86
  74. atomicshop/archiver/sevenzs.py +0 -73
  75. atomicshop/archiver/shutils.py +0 -34
  76. atomicshop/archiver/zips.py +0 -353
  77. atomicshop/file_types.py +0 -24
  78. atomicshop/pbtkmultifile_argparse.py +0 -88
  79. atomicshop/script_as_string_processor.py +0 -42
  80. atomicshop/ssh_scripts/process_from_ipv4.py +0 -37
  81. atomicshop/ssh_scripts/process_from_port.py +0 -27
  82. atomicshop/wrappers/_process_wrapper_curl.py +0 -27
  83. atomicshop/wrappers/_process_wrapper_tar.py +0 -21
  84. atomicshop/wrappers/dockerw/install_docker.py +0 -449
  85. atomicshop/wrappers/ffmpegw.py +0 -125
  86. atomicshop/wrappers/process_wrapper_pbtk.py +0 -16
  87. atomicshop/wrappers/socketw/get_process.py +0 -123
  88. /atomicshop/{addons → a_mains/addons}/PlayWrightCodegen.cmd +0 -0
  89. /atomicshop/{addons → a_mains/addons}/ScriptExecution.cmd +0 -0
  90. /atomicshop/{addons → a_mains/addons}/inits/init_to_import_all_modules.py +0 -0
  91. /atomicshop/{addons → a_mains/addons}/process_list/ReadMe.txt +0 -0
  92. /atomicshop/{addons → a_mains/addons}/process_list/compile.cmd +0 -0
  93. /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.dll +0 -0
  94. /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.exp +0 -0
  95. /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.lib +0 -0
  96. /atomicshop/{addons → a_mains/addons}/process_list/process_list.cpp +0 -0
  97. {atomicshop-3.3.28.dist-info → atomicshop-3.10.0.dist-info}/WHEEL +0 -0
  98. {atomicshop-3.3.28.dist-info → atomicshop-3.10.0.dist-info}/licenses/LICENSE.txt +0 -0
  99. {atomicshop-3.3.28.dist-info → atomicshop-3.10.0.dist-info}/top_level.txt +0 -0
@@ -11,10 +11,11 @@ import atomicshop # Importing atomicshop package to get the version of the pac
11
11
 
12
12
  from .. import filesystem, on_exit, print_api, networks, dns
13
13
  from ..permissions import permissions
14
- from ..python_functions import get_current_python_version_string, check_python_version_compliance
15
- from ..wrappers.socketw import socket_wrapper, dns_server, base, statistics_csv
14
+ from .. import python_functions
15
+ from ..wrappers.socketw import socket_wrapper, dns_server, statistics_csv
16
16
  from ..wrappers.loggingw import loggingw
17
17
  from ..wrappers.ctyping import win_console
18
+ from ..wrappers import netshw
18
19
  from ..basics import multiprocesses
19
20
 
20
21
  from .connection_thread_worker import thread_worker_main
@@ -36,6 +37,7 @@ class NetworkSettings:
36
37
 
37
38
  def __init__(
38
39
  self,
40
+ name: str | None = None,
39
41
  description: str | None = None,
40
42
  interface_index: int | None = None,
41
43
  is_dynamic: bool = False,
@@ -46,7 +48,7 @@ class NetworkSettings:
46
48
  default_gateways: list[str] = None,
47
49
  dns_gateways: list[str] = None
48
50
  ):
49
-
51
+ self.name: str | None = name
50
52
  self.description: str | None = description
51
53
  self.interface_index: int | None = interface_index
52
54
  self.is_dynamic: bool = is_dynamic
@@ -60,8 +62,6 @@ class NetworkSettings:
60
62
 
61
63
  # Global variables for setting the network interface to external IPs (eg: 192.168.0.1)
62
64
  NETWORK_INTERFACE_SETTINGS: NetworkSettings = NetworkSettings()
63
- CURRENT_IPV4S: list[str] = list()
64
- CURRENT_IPV4_MASKS: list[str] = list()
65
65
  IPS_TO_ASSIGN: list[str] = list()
66
66
  MASKS_TO_ASSIGN: list[str] = list()
67
67
 
@@ -96,45 +96,37 @@ except win_console.NotWindowsConsoleError:
96
96
  pass
97
97
 
98
98
 
99
+ # noinspection PyUnusedLocal
99
100
  def _graceful_shutdown(signum, frame):
100
101
  exit_cleanup()
101
102
 
102
103
 
103
104
  def exit_cleanup():
104
- if config_static.ENGINES_LIST[0].is_localhost:
105
- if permissions.is_admin() and IS_SET_DNS_GATEWAY:
106
- is_dns_dynamic, current_dns_gateway = dns.get_default_dns_gateway()
107
- status_string = 'Dynamic' if is_dns_dynamic else 'Static'
108
- print_api.print_api(f'Current DNS Gateway: {status_string}, {current_dns_gateway}')
109
-
110
- if is_dns_dynamic != NETWORK_INTERFACE_IS_DYNAMIC or \
111
- (not is_dns_dynamic and current_dns_gateway != NETWORK_INTERFACE_IPV4_ADDRESS_LIST):
112
- if NETWORK_INTERFACE_IS_DYNAMIC:
113
- dns.set_connection_dns_gateway_dynamic(use_default_connection=True)
114
- else:
115
- dns.set_connection_dns_gateway_static(
116
- dns_servers=NETWORK_INTERFACE_IPV4_ADDRESS_LIST, use_default_connection=True)
117
-
118
- print_api.print_api("Returned default DNS gateway...", color='blue')
119
- else:
120
- # Get current network interface state.
121
- default_network_adapter_config, default_network_adapter, default_adapter_info = networks.get_wmi_network_adapter_configuration(
122
- use_default_interface=True, get_info_from_network_config=True)
105
+ if not config_static.MainConfig.is_localhost:
106
+ # Remove all the virtual IPs from the interface.
107
+ current_virtual_ips: list[str] = networks.get_interface_ips_powershell(NETWORK_INTERFACE_SETTINGS.name, "virtual")
108
+ for ip in current_virtual_ips:
109
+ netshw.remove_virtual_ip(NETWORK_INTERFACE_SETTINGS.name, ip)
123
110
 
124
- if NETWORK_INTERFACE_SETTINGS.is_dynamic:
125
- # If the network interface was dynamic before the script started, we will return it to dynamic.
126
- networks.set_dynamic_ip_for_adapter(default_network_adapter_config)
127
- else:
128
- networks.set_static_ip_for_adapter(
129
- default_network_adapter,
130
- ips=NETWORK_INTERFACE_SETTINGS.ipv4s,
131
- masks=NETWORK_INTERFACE_SETTINGS.ipv4_subnet_masks,
132
- gateways=NETWORK_INTERFACE_SETTINGS.default_gateways,
133
- dns_gateways=NETWORK_INTERFACE_SETTINGS.dns_gateways
134
- )
111
+ netshw.disable_dhcp_static_coexistence(interface_name=NETWORK_INTERFACE_SETTINGS.name)
135
112
 
136
113
  print_api.print_api("Returned network adapter settings...", color='blue')
137
114
 
115
+ if permissions.is_admin() and IS_SET_DNS_GATEWAY:
116
+ is_dns_dynamic, current_dns_gateway = dns.get_default_dns_gateway()
117
+ status_string = 'Dynamic' if is_dns_dynamic else 'Static'
118
+ print_api.print_api(f'Current DNS Gateway: {status_string}, {current_dns_gateway}')
119
+
120
+ if is_dns_dynamic != NETWORK_INTERFACE_IS_DYNAMIC or \
121
+ (not is_dns_dynamic and current_dns_gateway != NETWORK_INTERFACE_IPV4_ADDRESS_LIST):
122
+ if NETWORK_INTERFACE_IS_DYNAMIC:
123
+ dns.set_interface_dns_gateway_dynamic(interface_name=NETWORK_INTERFACE_SETTINGS.name)
124
+ else:
125
+ dns.set_interface_dns_gateway_static(
126
+ dns_servers=NETWORK_INTERFACE_IPV4_ADDRESS_LIST, interface_name=NETWORK_INTERFACE_SETTINGS.name)
127
+
128
+ print_api.print_api("Returned default DNS gateway...", color='blue')
129
+
138
130
  # The process will not be executed if there was an exception in the beginning.
139
131
  if RECS_PROCESS_INSTANCE is not None:
140
132
  print_api.print_api(f'Recs archive process alive: {RECS_PROCESS_INSTANCE.is_alive()}')
@@ -161,7 +153,7 @@ def startup_output(system_logger, script_version: str):
161
153
  # Writing first log.
162
154
  system_logger.info("======================================")
163
155
  system_logger.info("Server Started.")
164
- system_logger.info(f"Python Version: {get_current_python_version_string()}")
156
+ system_logger.info(f"Python Version: {python_functions.get_python_version_string()}")
165
157
  system_logger.info(f"Script Version: {script_version}")
166
158
  system_logger.info(f"Atomic Workshop Version: {atomicshop.__version__}")
167
159
  system_logger.info(f"Log folder: {config_static.LogRec.logs_path}")
@@ -198,6 +190,7 @@ def startup_output(system_logger, script_version: str):
198
190
  # Printing the parsers using "start=1" for index to start counting from "1" and not "0"
199
191
  system_logger.info("Imported engine info.")
200
192
  print_api.print_api(f"[*] Found Engines:", logger=system_logger)
193
+ print_api.print_api( f"-------------------------", logger=system_logger)
201
194
 
202
195
  if not config_static.ENGINES_LIST:
203
196
  message = \
@@ -212,7 +205,6 @@ def startup_output(system_logger, script_version: str):
212
205
  f"{engine.responder_class_object.__name__}, "
213
206
  f"{engine.recorder_class_object.__name__}")
214
207
  print_api.print_api(message, logger=system_logger)
215
- print_api.print_api(f"[*] Name: {engine.engine_name}", logger=system_logger)
216
208
  print_api.print_api(f"[*] Domains: {list(engine.domain_target_dict.keys())}", logger=system_logger)
217
209
  dns_targets: list = list()
218
210
  for domain, ip_port in engine.domain_target_dict.items():
@@ -223,9 +215,11 @@ def startup_output(system_logger, script_version: str):
223
215
  print_api.print_api(f"[*] Connect Ports to IPs: {list(engine.on_port_connect.values())}", logger=system_logger)
224
216
  print_api.print_api(f"[*] Connect Ports to IPs Targets: {list(engine.port_target_dict.values())}", logger=system_logger)
225
217
 
218
+ print_api.print_api("-------------------------", logger=system_logger)
219
+
226
220
  # print_api.print_api(f"[*] TCP Listening Interfaces: {engine.tcp_listening_address_list}", logger=system_logger)
227
221
 
228
- if config_static.DNSServer.enable:
222
+ if config_static.DNSServer.is_enabled:
229
223
  print_api.print_api("DNS Server is enabled.", logger=system_logger)
230
224
 
231
225
  # If engines were found and dns is set to route by the engine domains.
@@ -249,13 +243,42 @@ def startup_output(system_logger, script_version: str):
249
243
  else:
250
244
  print_api.print_api("DNS Server is disabled.", logger=system_logger, color="yellow")
251
245
 
252
- if config_static.TCPServer.enable:
246
+ if config_static.TCPServer.is_enabled:
253
247
  print_api.print_api("TCP Server is enabled.", logger=system_logger)
254
248
  else:
255
249
  print_api.print_api("TCP Server is disabled.", logger=system_logger, color="yellow")
256
250
 
251
+ if config_static.MainConfig.is_localhost:
252
+ selected_net_interface: str = config_static.MainConfig.network_interface
253
+ else:
254
+ selected_net_interface: str = NETWORK_INTERFACE_SETTINGS.name
255
+ print_api.print_api(f"Selected Network Interface: {selected_net_interface}", logger=system_logger)
256
+
257
+ print_api.print_api(f"Listening DNS address: {config_static.DNSServer.listening_address}", logger=system_logger)
257
258
 
258
- def get_ipv4s_for_tcp_server():
259
+
260
+ def _get_interface_name() -> str | None:
261
+ if config_static.MainConfig.network_interface == '':
262
+ interface_name: str = networks.get_default_interface_name()
263
+ if interface_name == '':
264
+ print_api.print_api(
265
+ "Default network interface not found.",
266
+ error_type=True, color="red")
267
+ return None
268
+ else:
269
+ current_network_interface_names: list[str] = networks.list_network_interfaces()
270
+ if config_static.MainConfig.network_interface not in current_network_interface_names:
271
+ print_api.print_api(
272
+ f"Not found Network interface with the name: {config_static.MainConfig.network_interface}",
273
+ error_type=True, color="red")
274
+ return None
275
+ else:
276
+ interface_name = config_static.MainConfig.network_interface
277
+
278
+ return interface_name
279
+
280
+
281
+ def get_ipv4s_for_tcp_server() -> int:
259
282
  """
260
283
  Function to get the IPv4 addresses for the default network adapter to set them to the adapter.
261
284
  """
@@ -268,48 +291,82 @@ def get_ipv4s_for_tcp_server():
268
291
  ports_to_create_ips_for += list(engine.on_port_connect.keys())
269
292
 
270
293
  engine_ips: list[str] = list()
271
- # Check if we need the localhost ips (12.0.0.1) or external local ips (192.168.0.100).
272
- if config_static.ENGINES_LIST[0].is_localhost:
273
- create_ips: int = len(domains_to_create_ips_for) + len(ports_to_create_ips_for)
294
+ create_ips: int = len(domains_to_create_ips_for) + len(ports_to_create_ips_for)
274
295
 
275
- # Generate the list of localhost ips.
276
- for i in range(create_ips):
277
- engine_ips.append(f"127.0.0.{i+1}")
278
- else:
279
- # Get current network interface state.
280
- default_network_adapter_config, default_network_adapter, default_adapter_info = networks.get_wmi_network_adapter_configuration(
281
- use_default_interface=True, get_info_from_network_config=True)
282
-
283
- global NETWORK_INTERFACE_SETTINGS
284
- NETWORK_INTERFACE_SETTINGS = NetworkSettings(
285
- description=default_adapter_info['description'],
286
- interface_index=default_adapter_info['interface_index'],
287
- is_dynamic=default_adapter_info['is_dynamic'],
288
- ipv4s=default_adapter_info['ipv4s'],
289
- ipv6s=default_adapter_info['ipv6s'],
290
- ipv4_subnet_masks=default_adapter_info['ipv4_subnet_masks'],
291
- ipv6_prefixes=default_adapter_info['ipv6_prefixes'],
292
- default_gateways=default_adapter_info['default_gateways'],
293
- dns_gateways=default_adapter_info['dns_gateways']
294
- )
296
+ # Get network interface name.
297
+ interface_name: str = _get_interface_name()
298
+ if interface_name is None:
299
+ return 1
300
+
301
+ # Get selected network interface virtual IPs from previous runs.
302
+ # We still need network interface settings for DNS gateway assignment for the network interface doesn't matter in localhost mode or not.
303
+ current_virtual_ips: list[str] = networks.get_interface_ips_powershell(interface_name, "virtual")
304
+
305
+ if current_virtual_ips:
306
+ print_api.print_api(
307
+ f"Removing previous virtual IPs from interface [{interface_name}]: {current_virtual_ips}",
308
+ color="blue")
309
+
310
+ if not permissions.is_admin():
311
+ print_api.print_api(
312
+ f"Administrator permissions are required to remove virtual IPs from interface.",
313
+ error_type=True, color="red")
314
+ return 1
315
+ # Remove all the virtual IPs from the interface.
316
+ for ip in current_virtual_ips:
317
+ netshw.remove_virtual_ip(interface_name, ip)
318
+
319
+ network_adapter_config, network_adapter, adapter_info = networks.get_wmi_network_adapter_configuration(
320
+ interface_name=interface_name,
321
+ get_info_from_network_config=True)
322
+
323
+ global NETWORK_INTERFACE_SETTINGS
324
+ NETWORK_INTERFACE_SETTINGS = NetworkSettings(
325
+ name=adapter_info['name'],
326
+ description=adapter_info['description'],
327
+ interface_index=adapter_info['interface_index'],
328
+ is_dynamic=adapter_info['is_dynamic'],
329
+ ipv4s=adapter_info['ipv4s'],
330
+ ipv6s=adapter_info['ipv6s'],
331
+ ipv4_subnet_masks=adapter_info['ipv4_subnet_masks'],
332
+ ipv6_prefixes=adapter_info['ipv6_prefixes'],
333
+ default_gateways=adapter_info['default_gateways'],
334
+ dns_gateways=adapter_info['dns_gateways']
335
+ )
295
336
 
296
- # Adding IP addresses to the default network adapter.
297
- current_ipv4s: list[str] = default_adapter_info['ipv4s']
298
- current_ips_count: int = len(current_ipv4s)
337
+ # Check if we need the localhost ips (12.0.0.1) or external local ips (192.168.0.100).
338
+ if config_static.MainConfig.is_localhost:
339
+ # Generate the list of localhost ips. We will start from 127.0.0.2 and end with 127.0.0.2(create_ips + 1)
340
+ for i in range(2, create_ips + 2):
341
+ engine_ips.append(f"127.0.0.{i}")
299
342
 
300
- # If the number of currently assigned IPs is smaller than the number of IPs to create,
301
- # subtract the current IPs count from the number of IPs to create, to create only what is missing.
302
- create_ips: int = len(domains_to_create_ips_for)
303
- if current_ips_count <= create_ips:
304
- create_ips -= current_ips_count
343
+ # If the current default DNS gateway ipv4 is inside the engine_ips, then we will remove it and add the next in line.
344
+ if config_static.MainConfig.default_localhost_dns_gateway_ipv4 in engine_ips:
345
+ engine_ips.remove(config_static.MainConfig.default_localhost_dns_gateway_ipv4)
346
+ engine_ips.append(f"127.0.0.{create_ips + 2}")
305
347
 
348
+ dns_listening_ipv4: str = config_static.MainConfig.default_localhost_dns_gateway_ipv4
349
+ else:
306
350
  # Generate the IPs for the domains.
307
- global CURRENT_IPV4S, CURRENT_IPV4_MASKS, IPS_TO_ASSIGN, MASKS_TO_ASSIGN
308
- CURRENT_IPV4S, CURRENT_IPV4_MASKS, IPS_TO_ASSIGN, MASKS_TO_ASSIGN = networks.add_virtual_ips_to_default_adapter_by_current_setting(
351
+ global IPS_TO_ASSIGN, MASKS_TO_ASSIGN
352
+ assignment_result: tuple | None = networks.add_virtual_ips_to_network_interface(
353
+ interface_name=interface_name,
309
354
  number_of_ips=create_ips,
310
355
  simulate_only=True)
311
356
 
312
- engine_ips += CURRENT_IPV4S + IPS_TO_ASSIGN
357
+ if assignment_result is None:
358
+ return 1
359
+
360
+ IPS_TO_ASSIGN, MASKS_TO_ASSIGN = assignment_result
361
+
362
+ engine_ips += IPS_TO_ASSIGN
363
+ dns_listening_ipv4: str = NETWORK_INTERFACE_SETTINGS.ipv4s[0]
364
+
365
+ # Assign DNS listening address.
366
+ if config_static.DNSServer.listening_ipv4 != '':
367
+ config_static.DNSServer.listening_address = f"{config_static.DNSServer.listening_ipv4}:{str(config_static.DNSServer.listening_port)}"
368
+ else:
369
+ config_static.DNSServer.listening_address = f"{dns_listening_ipv4}:{str(config_static.DNSServer.listening_port)}"
313
370
 
314
371
  # Add the ips to engines.
315
372
  for engine in config_static.ENGINES_LIST:
@@ -322,23 +379,31 @@ def get_ipv4s_for_tcp_server():
322
379
  if port in ports_to_create_ips_for:
323
380
  engine.port_target_dict[port]['ip'] = engine_ips.pop(0)
324
381
 
382
+ return 0
325
383
 
326
- def mitm_server(config_file_path: str, script_version: str):
384
+
385
+ def mitm_server(config_file_path: str, script_version: str) -> int:
327
386
  on_exit.register_exit_handler(exit_cleanup, at_exit=False, kill_signal=False)
328
387
 
329
- # Main function should return integer with error code, 0 is successful.
330
- # Since listening server is infinite, this will not be reached.
331
- # After modules import - we check for python version.
332
- if not check_python_version_compliance(minor_version='3.12'):
388
+ python_version: str = python_functions.get_python_version_string()
389
+ print_api.print_api(f"[*] Python Version: {python_version}")
390
+
391
+ compliance_message: str | None = python_functions.check_python_version_compliance(min_ver=(3,13), max_ver=(3,13,99))
392
+ if compliance_message is not None:
393
+ print_api.print_api(f"[!] {compliance_message}", error_type=True, color="red")
333
394
  return 1
334
395
 
396
+ print_api.print_api("[*] Version Check PASSED.", color="green")
397
+
335
398
  # Import the configuration file.
336
- result = config_static.load_config(config_file_path, print_kwargs=dict(stdout=False))
337
- if result != 0:
338
- return result
399
+ rc: int = config_static.load_config(config_file_path, print_kwargs=dict(stdout=False))
400
+ if rc != 0:
401
+ return rc
339
402
 
340
403
  # Get the IPs that will be set for the adapter and fill the engine configuration with the IPs.
341
- get_ipv4s_for_tcp_server()
404
+ rc: int = get_ipv4s_for_tcp_server()
405
+ if rc != 0:
406
+ return rc
342
407
 
343
408
  global MITM_ERROR_LOGGER
344
409
  MITM_ERROR_LOGGER = loggingw.ExceptionCsvLogger(
@@ -410,7 +475,7 @@ def mitm_server(config_file_path: str, script_version: str):
410
475
  is_ready_multiprocessing_event_list: list[multiprocessing.Event] = list()
411
476
 
412
477
  # === Initialize TCP Server ====================================================================================
413
- if config_static.TCPServer.enable:
478
+ if config_static.TCPServer.is_enabled:
414
479
  # Get the default network adapter configuration and set the one from config.
415
480
  # We set the virtual IPs in the network adapter here, so the server multiprocessing processes can listen on them.
416
481
  setting_result: int = _add_virtual_ips_set_default_dns_gateway(system_logger)
@@ -502,6 +567,8 @@ def mitm_server(config_file_path: str, script_version: str):
502
567
  exceptions_logger_queue=EXCEPTIONS_CSV_LOGGER_QUEUE,
503
568
  forwarding_dns_service_ipv4_list___only_for_localhost=[config_static.DNSServer.forwarding_dns_service_ipv4],
504
569
  skip_extension_id_list=config_static.SkipExtensions.SKIP_EXTENSION_ID_LIST,
570
+ enable_sslkeylogfile_env_to_client_ssl_context=config_static.Certificates.enable_sslkeylogfile_env_to_client_ssl_context,
571
+ sslkeylog_file_path=config_static.Certificates.sslkeylog_file_path,
505
572
  print_kwargs=dict(stdout=False)
506
573
  )
507
574
 
@@ -534,7 +601,7 @@ def mitm_server(config_file_path: str, script_version: str):
534
601
  # === EOF Initialize TCP Server ====================================================================================
535
602
 
536
603
  # === Initialize DNS module ========================================================================================
537
- if config_static.DNSServer.enable:
604
+ if config_static.DNSServer.is_enabled:
538
605
  # noinspection PyTypeHints
539
606
  is_dns_process_ready: multiprocessing.Event = multiprocessing.Event()
540
607
 
@@ -549,7 +616,7 @@ def mitm_server(config_file_path: str, script_version: str):
549
616
  resolve_regular_pass_thru=config_static.DNSServer.resolve_regular_pass_thru,
550
617
  resolve_all_domains_to_ipv4=(
551
618
  config_static.DNSServer.resolve_all_domains_to_ipv4_enable, config_static.DNSServer.target_ipv4),
552
- offline_mode=config_static.MainConfig.offline,
619
+ offline_mode=config_static.MainConfig.is_offline,
553
620
  cache_timeout_minutes=config_static.DNSServer.cache_timeout_minutes,
554
621
  logging_queue=NETWORK_LOGGER_QUEUE,
555
622
  logger_name=network_logger_name,
@@ -571,7 +638,7 @@ def mitm_server(config_file_path: str, script_version: str):
571
638
  return 1
572
639
  # === EOF Initialize DNS module ====================================================================================
573
640
 
574
- if config_static.DNSServer.enable or config_static.TCPServer.enable:
641
+ if config_static.DNSServer.is_enabled or config_static.TCPServer.is_enabled:
575
642
  print_api.print_api("The Server is Ready for Operation!", color="green", logger=system_logger)
576
643
  print_api.print_api("Press [Ctrl]+[C] to stop.", color='blue', logger=system_logger)
577
644
 
@@ -591,6 +658,8 @@ def mitm_server(config_file_path: str, script_version: str):
591
658
 
592
659
  time.sleep(1)
593
660
 
661
+ return 0
662
+
594
663
 
595
664
  # noinspection PyTypeHints
596
665
  def _create_tcp_server_process(
@@ -694,48 +763,59 @@ def _add_virtual_ips_set_default_dns_gateway(system_logger: logging.Logger) -> i
694
763
  # This setting is needed only for the dns gateways configurations from the main config on localhost.
695
764
  set_local_dns_gateway: bool = False
696
765
  # Set the default gateway if specified.
697
- if config_static.DNSServer.set_default_dns_gateway:
698
- dns_gateway_server_list = config_static.DNSServer.set_default_dns_gateway
766
+ if config_static.MainConfig.set_default_dns_gateway:
767
+ dns_gateway_server_list = config_static.MainConfig.set_default_dns_gateway
699
768
  set_local_dns_gateway = True
700
- elif config_static.DNSServer.set_default_dns_gateway_to_localhost:
701
- dns_gateway_server_list = [base.LOCALHOST_IPV4]
769
+ elif config_static.MainConfig.set_default_dns_gateway_to_localhost:
770
+ dns_gateway_server_list = [config_static.MainConfig.default_localhost_dns_gateway_ipv4]
702
771
  set_local_dns_gateway = True
703
- elif config_static.DNSServer.set_default_dns_gateway_to_default_interface_ipv4:
704
- dns_gateway_server_list = [base.DEFAULT_IPV4]
772
+ elif config_static.MainConfig.set_default_dns_gateway_to_network_interface_ipv4:
773
+ dns_gateway_server_list = [NETWORK_INTERFACE_SETTINGS.ipv4s[0]]
705
774
  set_local_dns_gateway = True
706
775
  else:
707
776
  dns_gateway_server_list = NETWORK_INTERFACE_SETTINGS.dns_gateways
708
777
 
709
- if config_static.ENGINES_LIST[0].is_localhost:
710
- if set_local_dns_gateway:
711
- global IS_SET_DNS_GATEWAY
712
- IS_SET_DNS_GATEWAY = True
713
-
714
- # Get current network interface state.
715
- global NETWORK_INTERFACE_IS_DYNAMIC, NETWORK_INTERFACE_IPV4_ADDRESS_LIST
716
- NETWORK_INTERFACE_IS_DYNAMIC, NETWORK_INTERFACE_IPV4_ADDRESS_LIST = dns.get_default_dns_gateway()
717
-
718
- # Set the DNS gateway to the specified one only if the DNS gateway is dynamic, or it is static but different
719
- # from the one specified in the configuration file.
720
- if (NETWORK_INTERFACE_IS_DYNAMIC or (not NETWORK_INTERFACE_IS_DYNAMIC and
721
- NETWORK_INTERFACE_IPV4_ADDRESS_LIST != dns_gateway_server_list)):
722
- try:
723
- dns.set_connection_dns_gateway_static(
724
- dns_servers=dns_gateway_server_list,
725
- use_default_connection=True
726
- )
727
- except PermissionError as e:
728
- print_api.print_api(e, error_type=True, color="red", logger=system_logger)
729
- # Wait for the message to be printed and saved to file.
730
- time.sleep(1)
731
- # network_logger_queue_listener.stop()
732
- return 1
733
- else:
778
+ if set_local_dns_gateway:
779
+ global IS_SET_DNS_GATEWAY
780
+ IS_SET_DNS_GATEWAY = True
781
+
782
+ # Get current network interface state.
783
+ global NETWORK_INTERFACE_IS_DYNAMIC, NETWORK_INTERFACE_IPV4_ADDRESS_LIST
784
+ NETWORK_INTERFACE_IS_DYNAMIC, NETWORK_INTERFACE_IPV4_ADDRESS_LIST = dns.get_default_dns_gateway()
785
+
786
+ # Set the DNS gateway to the specified one only if the DNS gateway is dynamic, or it is static but different
787
+ # from the one specified in the configuration file.
788
+ if (NETWORK_INTERFACE_IS_DYNAMIC or (not NETWORK_INTERFACE_IS_DYNAMIC and
789
+ NETWORK_INTERFACE_IPV4_ADDRESS_LIST != dns_gateway_server_list)):
790
+ try:
791
+ dns.set_interface_dns_gateway_static(
792
+ interface_name=NETWORK_INTERFACE_SETTINGS.name,
793
+ dns_servers=dns_gateway_server_list
794
+ )
795
+ except PermissionError as e:
796
+ print_api.print_api(e, error_type=True, color="red", logger=system_logger)
797
+ # Wait for the message to be printed and saved to file.
798
+ time.sleep(1)
799
+ # network_logger_queue_listener.stop()
800
+ return 1
801
+
802
+ if not config_static.MainConfig.is_localhost:
734
803
  # Change the adapter settings and add the virtual IPs.
735
804
  try:
736
- networks.add_virtual_ips_to_default_adapter_by_current_setting(
737
- virtual_ipv4s_to_add=IPS_TO_ASSIGN, virtual_ipv4_masks_to_add=MASKS_TO_ASSIGN,
738
- dns_gateways=dns_gateway_server_list)
805
+ networks.add_virtual_ips_to_network_interface(
806
+ interface_name=NETWORK_INTERFACE_SETTINGS.name,
807
+ virtual_ipv4s_to_add=IPS_TO_ASSIGN,
808
+ virtual_ipv4_masks_to_add=MASKS_TO_ASSIGN,
809
+ verbose=True,
810
+ logger=system_logger
811
+ )
812
+
813
+ for engine in config_static.ENGINES_LIST:
814
+ bindable_test_dict: dict = engine.domain_target_dict | engine.port_target_dict
815
+ for port_or_domain_name, ip_port_dict in bindable_test_dict.items():
816
+ print_api.print_api(f"Checking that virtual IP is bindable: {ip_port_dict['ip']}:{ip_port_dict['port']}", logger=system_logger)
817
+ networks.wait_for_ip_bindable_socket(ip_port_dict['ip'], port=int(ip_port_dict['port']), timeout=15)
818
+ print_api.print_api("BIND test successful for all virtual IPs.", logger=system_logger)
739
819
  except (PermissionError, TimeoutError) as e:
740
820
  print_api.print_api(e, error_type=True, color="red", logger=system_logger)
741
821
  # Wait for the message to be printed and saved to file.
@@ -773,7 +853,28 @@ def _loop_at_midnight_recs_archive(network_logger_name):
773
853
 
774
854
 
775
855
  def mitm_server_main(config_file_path: str, script_version: str):
856
+ # This is for Linux and macOS.
857
+ signal.signal(signal.SIGTERM, _graceful_shutdown)
776
858
  signal.signal(signal.SIGINT, _graceful_shutdown)
859
+ # This is for Windows.
860
+ """
861
+ Example:
862
+ script = (Path(__file__).resolve().parent / "ServerTCPWithDNS.py").resolve()
863
+ p = subprocess.Popen(
864
+ [sys.executable, "-u", str(script)],
865
+ creationflags=subprocess.CREATE_NEW_PROCESS_GROUP,
866
+ # inherit console; do NOT use CREATE_NEW_CONSOLE
867
+ )
868
+ time.sleep(30)
869
+ p.send_signal(signal.CTRL_BREAK_EVENT)
870
+ try:
871
+ p.wait(timeout=5)
872
+ except subprocess.TimeoutExpired:
873
+ print("Graceful interrupt timed out; terminating")
874
+ p.terminate()
875
+ p.wait()
876
+ """
877
+ signal.signal(signal.SIGBREAK, _graceful_shutdown)
777
878
 
778
879
  try:
779
880
  # Main function should return integer with error code, 0 is successful.
@@ -2,8 +2,9 @@ import datetime
2
2
  import os
3
3
  import multiprocessing
4
4
  import logging
5
+ import zipfile
6
+ import shutil
5
7
 
6
- from ..archiver import zips
7
8
  from .. import filesystem, print_api
8
9
  from .. wrappers.loggingw import consts, loggingw
9
10
 
@@ -13,6 +14,40 @@ REC_FILE_DATE_TIME_FORMAT: str = f'{consts.DEFAULT_ROTATING_SUFFIXES_FROM_WHEN["
13
14
  REC_FILE_DATE_FORMAT: str = REC_FILE_DATE_TIME_FORMAT.split('_')[0]
14
15
 
15
16
 
17
+ def archive(
18
+ directory_path: str,
19
+ include_root_directory: bool = True,
20
+ ) -> str:
21
+ """
22
+ Function archives the directory.
23
+ :param directory_path: string, full path to the directory.
24
+ :param include_root_directory: boolean, default is 'True'.
25
+ 'True': The root directory will be included in the archive.
26
+ 'False': The root directory will not be included in the archive.
27
+ True is usually the case in most archiving utilities.
28
+ :return: string, full path to the archived file.
29
+ """
30
+
31
+ # This is commonly used and supported by most ZIP utilities.
32
+ compression_method = zipfile.ZIP_DEFLATED
33
+
34
+ archive_path: str = directory_path + '.zip'
35
+ with zipfile.ZipFile(archive_path, 'w', compression_method) as zip_object:
36
+ for root, _, files in os.walk(directory_path):
37
+ for file in files:
38
+ file_path = os.path.join(root, file)
39
+
40
+ # If including the root directory, use the relative path from the parent directory of the root
41
+ if include_root_directory:
42
+ arcname = os.path.relpath(file_path, os.path.dirname(directory_path))
43
+ else:
44
+ arcname = os.path.relpath(file_path, directory_path)
45
+
46
+ zip_object.write(file_path, arcname)
47
+
48
+ return archive_path
49
+
50
+
16
51
  def recs_archiver(
17
52
  recs_directory: str,
18
53
  logging_queue: multiprocessing.Queue,
@@ -69,6 +104,8 @@ def recs_archiver(
69
104
  try:
70
105
  archived_files: list = list()
71
106
  for directory_path, all_recs_files in file_list_per_directory:
107
+ print_api.print_api(f"Archiving recs files in directory: {directory_path.path}",
108
+ logger=rec_packer_logger_with_queue_handler, color='blue')
72
109
  for recs_atomic_path in all_recs_files:
73
110
  # We don't need to archive today's files.
74
111
  if today_date_string == recs_atomic_path.datetime_string:
@@ -82,10 +119,29 @@ def recs_archiver(
82
119
  # Archive directories.
83
120
  archive_directories: list = filesystem.get_paths_from_directory(
84
121
  directory_path.path, get_directory=True, recursive=False)
85
- for archive_directory in archive_directories:
86
- archived_file: str = zips.archive_directory(
87
- archive_directory.path, remove_original=True, include_root_directory=True)
88
- archived_files.append(archived_file)
122
+
123
+ if not archive_directories:
124
+ print_api.print_api(
125
+ f"No directories to archive in: {directory_path.path}",
126
+ color='blue',
127
+ logger=rec_packer_logger_with_queue_handler
128
+ )
129
+ else:
130
+ total_archived_files: int = 0
131
+ for archive_directory in archive_directories:
132
+ files_to_archive: list = filesystem.get_paths_from_directory(
133
+ directory_path=archive_directory.path, get_file=True, recursive=False)
134
+ total_archived_files += len(files_to_archive)
135
+ archived_file: str = archive(archive_directory.path, include_root_directory=True)
136
+ # Remove the original directory after archiving.
137
+ shutil.rmtree(archive_directory.path, ignore_errors=True)
138
+ archived_files.append(archived_file)
139
+
140
+ print_api.print_api(
141
+ f'Archived: 'f'Directories: {len(archive_directories)} | '
142
+ f'Total Files: {total_archived_files} | In: {directory_path.path}',
143
+ logger=rec_packer_logger_with_queue_handler, color='blue')
144
+ print_api.print_api(f'Archived files: {archived_files}', logger=rec_packer_logger_with_queue_handler)
89
145
 
90
146
  finalize_output_queue.put(None)
91
147