atomicshop 2.21.1__py3-none-any.whl → 3.0.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 (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 +30 -26
  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.0.dist-info}/METADATA +2 -1
  25. {atomicshop-2.21.1.dist-info → atomicshop-3.0.0.dist-info}/RECORD +28 -24
  26. atomicshop/wrappers/pywin32w/wmis/helpers.py +0 -131
  27. {atomicshop-2.21.1.dist-info → atomicshop-3.0.0.dist-info}/LICENSE.txt +0 -0
  28. {atomicshop-2.21.1.dist-info → atomicshop-3.0.0.dist-info}/WHEEL +0 -0
  29. {atomicshop-2.21.1.dist-info → atomicshop-3.0.0.dist-info}/top_level.txt +0 -0
atomicshop/networks.py ADDED
@@ -0,0 +1,448 @@
1
+ import socket
2
+ import time
3
+ from typing import Union
4
+ import os
5
+
6
+ from icmplib import ping
7
+ from icmplib.models import Host
8
+ from win32com.client import CDispatch
9
+
10
+ from .wrappers.pywin32w.wmis import win32networkadapter, win32_networkadapterconfiguration, wmi_helpers, msft_netipaddress
11
+ from .wrappers.ctyping import setup_device
12
+ from .wrappers.winregw import winreg_network
13
+
14
+
15
+ MICROSOFT_LOOPBACK_DEVICE_NAME: str = 'Microsoft KM-TEST Loopback Adapter'
16
+ MICROSOFT_LOOPBACK_DEVICE_INF_PATH = os.path.join(os.environ["WINDIR"], "INF", "netloop.inf")
17
+ MICROSOFT_LOOPBACK_DEVICE_HARDWARE_ID = "*MSLOOP"
18
+ GUID_DEVCLASS_NET: str = '{4d36e972-e325-11ce-bfc1-08002be10318}'
19
+
20
+
21
+ def is_ip_alive(ip_address: str, timeout: int = 1) -> bool:
22
+ """
23
+ Returns True if icmplib.models.Host.is_alive returns True.
24
+ """
25
+
26
+ host_object: Host = ping(ip_address, count=1, timeout=timeout)
27
+
28
+ return host_object.is_alive
29
+
30
+
31
+ def get_default_internet_ipv4() -> str:
32
+ """
33
+ Get the default IPv4 address of the interface that is being used for internet.
34
+ :return: string, default IPv4 address.
35
+ """
36
+
37
+ return socket.gethostbyname(socket.gethostname())
38
+
39
+ def get_default_internet_ipv4_by_connect(target: str = "8.8.8.8") -> str:
40
+ with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
41
+ s.connect((target, 80)) # no packet sent; OS just chooses a route
42
+ return s.getsockname()[0] # local address of that route
43
+
44
+
45
+ def get_default_internet_interface_name() -> str:
46
+ """
47
+ Get the default network interface name that is being used for internet.
48
+ :return: string, default network interface name.
49
+ """
50
+
51
+ return socket.gethostname()
52
+
53
+
54
+ def get_microsoft_loopback_device_network_configuration(
55
+ wmi_instance: CDispatch = None,
56
+ timeout: int = 1,
57
+ ) -> Union[
58
+ tuple[CDispatch, str],
59
+ tuple[None, None]
60
+ ]:
61
+ """
62
+ Get the WMI Win32_NetworkAdapterConfiguration object of the Microsoft Loopback device.
63
+
64
+ :param wmi_instance: WMI instance. You can get it from:
65
+ wrappers.pywin32s.wmis.wmi_helpers.get_wmi_instance()
66
+ If not specified the default WMI instance will be used '.'.
67
+ :param timeout: int, timeout in seconds. Default is 1 second.
68
+ :return: tuple(Win32_NetworkAdapterConfiguration, Win32_NetworkAdapter.PNPDeviceID)
69
+ If the adapter is not found, it will return (None, None).
70
+ """
71
+
72
+ if not wmi_instance:
73
+ wmi_instance, _ = wmi_helpers.get_wmi_instance()
74
+
75
+ for _ in range(timeout):
76
+ adapter: CDispatch = win32networkadapter.get_network_adapter_by_device_name(
77
+ MICROSOFT_LOOPBACK_DEVICE_NAME, wmi_instance)
78
+ if not adapter:
79
+ # noinspection PyTypeChecker
80
+ network_config = None
81
+ else:
82
+ network_config: CDispatch = win32_networkadapterconfiguration.get_network_configuration_by_adapter(
83
+ adapter, wmi_instance=wmi_instance)
84
+
85
+ if network_config:
86
+ return network_config, adapter.PNPDeviceID
87
+ time.sleep(1)
88
+
89
+ return None, None
90
+
91
+
92
+ def create_microsoft_loopback_device():
93
+ """
94
+ Create a Microsoft Loopback device using the setupapi.dll.
95
+ """
96
+ setup_device.add_device(
97
+ class_guid=GUID_DEVCLASS_NET,
98
+ friendly_name=MICROSOFT_LOOPBACK_DEVICE_NAME,
99
+ hardware_ids=MICROSOFT_LOOPBACK_DEVICE_HARDWARE_ID,
100
+ inf_path=MICROSOFT_LOOPBACK_DEVICE_INF_PATH,
101
+ force_install=True,
102
+ quiet=True,
103
+ existing_ok=True
104
+ )
105
+
106
+
107
+ def get_create_microsoft_loopback_device_network_configuration(
108
+ wmi_instance: CDispatch = None
109
+ ) -> Union[
110
+ tuple[CDispatch, str],
111
+ tuple[None, None]
112
+ ]:
113
+ """
114
+ Get the WMI Win32_NetworkAdapterConfiguration object of the Microsoft Loopback device.
115
+ If it does not exist, create it.
116
+
117
+ :param wmi_instance: WMI instance. You can get it from:
118
+ wrappers.pywin32s.wmis.wmi_helpers.get_wmi_instance()
119
+ If not specified the default WMI instance will be used '.'.
120
+ :return: tuple(Win32_NetworkAdapterConfiguration, Win32_NetworkAdapter.PNPDeviceID)
121
+ If the adapter is not found, it will return (None, None).
122
+ """
123
+
124
+ if not wmi_instance:
125
+ wmi_instance, _ = wmi_helpers.get_wmi_instance()
126
+
127
+ network_config, pnp_device_id = get_microsoft_loopback_device_network_configuration(wmi_instance=wmi_instance)
128
+
129
+ if network_config:
130
+ return network_config, pnp_device_id
131
+
132
+ create_microsoft_loopback_device()
133
+
134
+ network_config, pnp_device_id = get_microsoft_loopback_device_network_configuration(
135
+ wmi_instance=wmi_instance, timeout=20)
136
+
137
+ return network_config, pnp_device_id
138
+
139
+
140
+ def remove_microsoft_loopback_device(
141
+ pnp_device_id: str
142
+ ) -> bool:
143
+ """
144
+ Remove the Microsoft Loopback device using the setupapi.dll.
145
+
146
+ :param pnp_device_id: string, PNPDeviceID of the device to remove.
147
+ :return: bool, True if the device was removed successfully.
148
+ """
149
+ return setup_device.remove_device(
150
+ pnp_device_id=pnp_device_id,
151
+ class_guid=GUID_DEVCLASS_NET
152
+ )
153
+
154
+
155
+ def change_interface_metric_restart_device(
156
+ network_config: CDispatch,
157
+ metric: int = 9999,
158
+ wmi_instance: CDispatch = None
159
+ ):
160
+ """
161
+ Change the interface metric and restart the device.
162
+ You can check the metric in CMD with:
163
+ route print
164
+
165
+ :param network_config: CDispatch, Win32_NetworkAdapterConfiguration object.
166
+ :param metric: int, new metric value.
167
+ :param wmi_instance: WMI instance. You can get it from:
168
+ wrappers.pywin32s.wmis.wmi_helpers.get_wmi_instance()
169
+ """
170
+
171
+ if not wmi_instance:
172
+ wmi_instance, _ = wmi_helpers.get_wmi_instance()
173
+
174
+ # 1) Registry tweak
175
+ guid = network_config.SettingID
176
+ winreg_network.change_metric_of_network_adapter(adapter_guid=guid, metric=metric)
177
+
178
+ # 2) Bounce the NIC so TCP/IP re‑reads the new metric
179
+ idx = network_config.Index
180
+ adapter = wmi_instance.ExecQuery(f"SELECT * FROM Win32_NetworkAdapter WHERE Index={idx}")[0]
181
+
182
+ adapter.ExecMethod_("Disable")
183
+ time.sleep(1.0)
184
+ adapter.ExecMethod_("Enable")
185
+
186
+
187
+ def get_wmi_network_adapter_configuration(
188
+ use_default_interface: bool = False,
189
+ connection_name: str = None,
190
+ mac_address: str = None,
191
+ wmi_instance: CDispatch = None,
192
+ get_info_from_network_config: bool = True
193
+ ) -> tuple:
194
+ """
195
+ Get the WMI network configuration for a network adapter.
196
+ :param use_default_interface: bool, if True, the default network interface will be used.
197
+ This is the adapter that your internet is being used from.
198
+ :param connection_name: string, adapter name as shown in the network settings.
199
+ :param mac_address: string, MAC address of the adapter. Format: '00:00:00:00:00:00'.
200
+ :param wmi_instance: WMI instance. You can get it from:
201
+ wrappers.pywin32s.wmis.wmi_helpers.get_wmi_instance()
202
+ or default will be used.
203
+ :param get_info_from_network_config: bool, if True, the function will return the network configuration info
204
+ on the third position of the tuple. On False, it will return an empty dictionary.
205
+ :return: tuple(Win32_NetworkAdapterConfiguration, Win32_NetworkAdapter, dict)
206
+ """
207
+
208
+ wmi_network_config, wmi_network_adapter = win32_networkadapterconfiguration.get_adapter_network_configuration(
209
+ use_default_interface=use_default_interface,
210
+ connection_name=connection_name,
211
+ mac_address=mac_address,
212
+ wmi_instance=wmi_instance
213
+ )
214
+
215
+ if get_info_from_network_config:
216
+ adapter_info: dict = win32_networkadapterconfiguration.get_info_from_network_config(wmi_network_config)
217
+ else:
218
+ adapter_info: dict = {}
219
+
220
+ return wmi_network_config, wmi_network_adapter, adapter_info
221
+
222
+
223
+ def generate_unused_ipv4_addresses_by_vlan(
224
+ vlan: str,
225
+ number_of_ips: int,
226
+ skip_ips: list[str] = None
227
+ ) -> list[str]:
228
+ """
229
+ Generate a list of unused IPv4 addresses in the given VLAN.
230
+
231
+ :param vlan: string, VLAN in the format '192.168.0'.
232
+ :param number_of_ips: int, number of IPs to generate.
233
+ :param skip_ips: list of strings, IPs to skip.
234
+ :return: list of strings, free IPv4 addresses.
235
+ """
236
+
237
+ generated_ips: list[str] = []
238
+ counter: int = 1
239
+ for i in range(number_of_ips):
240
+ # Create the IP address.
241
+ while True:
242
+ ip_address = f"{vlan}.{counter}"
243
+ counter += 1
244
+ is_ip_in_use: bool = is_ip_alive(ip_address)
245
+ if not is_ip_in_use and not ip_address in skip_ips:
246
+ # print("[+] Found IP to assign: ", ip_address)
247
+ generated_ips.append(ip_address)
248
+ break
249
+ else:
250
+ # print(f"[!] IP {ip_address} is already in use or assigned to the adapter.")
251
+ continue
252
+
253
+ return generated_ips
254
+
255
+
256
+ def generate_unused_ipv4_addresses_from_ip(
257
+ ip_address: str,
258
+ mask: str,
259
+ number_of_ips: int,
260
+ skip_ips: list[str] = None
261
+ ) -> tuple[list[str], list[str]]:
262
+ """
263
+ Generate a list of unused IPv4 addresses in the given VLAN.
264
+
265
+ :param ip_address: string, IP address, example: '192.168.0.1'.
266
+ This address will be a part of skip_ips list, even if an empty list is passed.
267
+ :param mask: string, subnet mask, example: '255.255.255.0'.
268
+ :param number_of_ips: int, number of IPs to generate.
269
+ :param skip_ips: list of strings, IPs to skip.
270
+ :return: list of strings, unused IPv4 addresses.
271
+ """
272
+
273
+ if not skip_ips:
274
+ skip_ips = []
275
+
276
+ # Add the IP address to the list of IPs to skip.
277
+ if ip_address not in skip_ips:
278
+ skip_ips = [ip_address] + skip_ips
279
+
280
+ # Get the VLAN of the default IPv4 address.
281
+ default_vlan: str = ip_address.rsplit(".", 1)[0]
282
+
283
+
284
+ # Find IPs to assign.
285
+ generated_ips: list[str] = generate_unused_ipv4_addresses_by_vlan(
286
+ vlan=default_vlan, number_of_ips=number_of_ips, skip_ips=skip_ips)
287
+
288
+ # Add subnet masks to the IPs to assign.
289
+ masks_for_ips: list[str] = []
290
+ for ip_address in generated_ips:
291
+ print(f"[+] Found IP to assign: {ip_address}")
292
+ masks_for_ips.append(mask)
293
+
294
+ return generated_ips, masks_for_ips
295
+
296
+
297
+ def set_dynamic_ip_for_adapter(
298
+ network_config: CDispatch,
299
+ reset_dns: bool = True,
300
+ reset_wins: bool = True
301
+ ):
302
+ """
303
+ Set the IP address of the network adapter to dynamic from DHCP.
304
+ :param network_config: CDispatch, Win32_NetworkAdapterConfiguration object.
305
+ :param reset_dns: bool, if True, the DNS servers will be reset to automatic.
306
+ :param reset_wins: bool, if True, the WINS servers will be reset to automatic.
307
+ """
308
+
309
+ win32_networkadapterconfiguration.set_dynamic_ip(
310
+ nic_cfg=network_config, reset_dns=reset_dns, reset_wins=reset_wins)
311
+
312
+
313
+ def set_static_ip_for_adapter(
314
+ network_config: CDispatch,
315
+ ips: list[str],
316
+ masks: list[str],
317
+ gateways: list[str] = None,
318
+ dns_gateways: list[str] = None,
319
+ availability_wait_seconds: int = 0
320
+ ):
321
+ """
322
+ Set the IP address of the network adapter to static.
323
+ :param network_config: CDispatch, Win32_NetworkAdapterConfiguration object.
324
+ :param ips: list of strings, IP addresses to assign.
325
+ :param masks: list of strings, subnet masks to assign.
326
+ :param gateways: list of strings, default gateways to assign.
327
+ :param dns_gateways: list of strings, DNS servers to assign.
328
+ :param availability_wait_seconds: int, seconds to wait for the adapter to be available after setting the IP address.
329
+ """
330
+
331
+ win32_networkadapterconfiguration.set_static_ips(
332
+ network_config=network_config,
333
+ ips=ips,
334
+ masks=masks,
335
+ gateways=gateways,
336
+ dns_gateways=dns_gateways,
337
+ availability_wait_seconds=availability_wait_seconds
338
+ )
339
+
340
+
341
+ def add_virtual_ips_to_default_adapter_by_current_setting(
342
+ number_of_ips: int = 0,
343
+ virtual_ipv4s_to_add: list[str] = None,
344
+ virtual_ipv4_masks_to_add: list[str] = None,
345
+ set_virtual_ips_skip_as_source: bool = True,
346
+ gateways: list[str] | None = None,
347
+ dns_gateways: list[str] | None = None,
348
+ availability_wait_seconds: int = 15,
349
+ simulate_only: bool = False,
350
+ locator: CDispatch = None,
351
+ ) -> tuple[list[str], list[str], list[str], list[str]]:
352
+ """
353
+ Add virtual IP addresses to the default network adapter.
354
+ The adapter will set to static IP and DNS gateway, instead of dynamic DHCP.
355
+ The first IPv4 address of the network_config will be used as VLAN and the unused IP addresses
356
+ will be generated from it. Unused addresses decided by pinging them.
357
+ Same for the subnet mask.
358
+
359
+ :param number_of_ips: int, number of IPs to generate in addition to the IPv4s that already exist in the adapter.
360
+ Or you add the IPs and masks to the adapter with the parameters virtual_ipv4s_to_add and virtual_ipv4_masks_to_add.
361
+
362
+ :param virtual_ipv4s_to_add: list of strings, Add this IPv4 addresses to the current IPs of the adapter.
363
+ :param virtual_ipv4_masks_to_add: list of strings, Add this subnet masks to the current subnet masks of the adapter.
364
+ Or you generate the IPs and masks by specifying the number_of_ips parameter.
365
+
366
+ :param set_virtual_ips_skip_as_source: bool, if True, the SkipAsSource flag will be set for the virtual IPs.
367
+ This is needed to avoid the endless accept() loop.
368
+ :param gateways: list of strings, default IPv4 gateways to assign.
369
+ None: The already existing gateways in the adapter will be used.
370
+ []: No gateways will be assigned.
371
+ :param dns_gateways: list of strings, IPv4 DNS servers to assign.
372
+ None: The already existing DNS servers in the adapter will be used.
373
+ []: No DNS servers will be assigned.
374
+ :param availability_wait_seconds: int, seconds to wait for the adapter to be available after setting the IP address.
375
+ :param simulate_only: bool, if True, the function will only prepare the ip addresses and return them without changing anything.
376
+ :param locator: CDispatch, WMI locator object. If not specified, it will be created.
377
+
378
+ :return: tuple of lists, (current_ipv4s, current_ipv4_masks, ips_to_assign, masks_to_assign)
379
+ """
380
+
381
+ if virtual_ipv4s_to_add and not virtual_ipv4_masks_to_add:
382
+ raise ValueError("If you specify virtual_ipv4s_to_add, you must also specify virtual_ipv4_masks_to_add.")
383
+ if virtual_ipv4_masks_to_add and not virtual_ipv4s_to_add:
384
+ raise ValueError("If you specify virtual_ipv4_masks_to_add, you must also specify virtual_ipv4s_to_add.")
385
+
386
+ if virtual_ipv4s_to_add and len(virtual_ipv4s_to_add) != len(virtual_ipv4_masks_to_add):
387
+ raise ValueError("If you specify virtual_ipv4s_to_add, the number of IPs must be equal to the number of masks.")
388
+
389
+ if number_of_ips > 0 and (virtual_ipv4s_to_add or virtual_ipv4_masks_to_add):
390
+ raise ValueError("If you specify number_of_ips, you cannot specify virtual_ipv4s_to_add or virtual_ipv4_masks_to_add.")
391
+
392
+ # Connect to WMi.
393
+ wmi_civ2_instance, locator = wmi_helpers.get_wmi_instance(locator=locator)
394
+
395
+ # initial_default_ipv4: str = socket.gethostbyname(socket.gethostname())
396
+
397
+ # Get the default network adapter configuration.
398
+ default_network_adapter_config, default_network_adapter, default_adapter_info = get_wmi_network_adapter_configuration(
399
+ use_default_interface=True, wmi_instance=wmi_civ2_instance, get_info_from_network_config=True)
400
+
401
+ current_ipv4s: list[str] = default_adapter_info['ipv4s']
402
+ current_ipv4_masks: list[str] = default_adapter_info['ipv4_subnet_masks']
403
+
404
+ # print(f"Current IPs: {current_ipv4s}")
405
+ # current_ips_count: int = len(current_ipv4s)
406
+
407
+ if number_of_ips > 0:
408
+ ips_to_assign, masks_to_assign = generate_unused_ipv4_addresses_from_ip(
409
+ ip_address=current_ipv4s[0],
410
+ mask=current_ipv4_masks[0],
411
+ number_of_ips=number_of_ips,
412
+ skip_ips=current_ipv4s
413
+ )
414
+ elif virtual_ipv4s_to_add and virtual_ipv4_masks_to_add:
415
+ ips_to_assign = virtual_ipv4s_to_add
416
+ masks_to_assign = virtual_ipv4_masks_to_add
417
+ else:
418
+ ips_to_assign = []
419
+ masks_to_assign = []
420
+
421
+ if not simulate_only:
422
+ # Final list of IPs to assign.
423
+ ips: list[str] = current_ipv4s + ips_to_assign
424
+ masks: list[str] = current_ipv4_masks + masks_to_assign
425
+
426
+ # ---------- IP assignment --------------------------------------------
427
+ if ips != current_ipv4s:
428
+ # print("[+] Setting static IPv4 addresses …")
429
+ if gateways is None:
430
+ gateways = default_adapter_info['default_gateways']
431
+
432
+ if dns_gateways is None:
433
+ dns_gateways = default_adapter_info['dns_gateways']
434
+
435
+ win32_networkadapterconfiguration.set_static_ips(
436
+ default_network_adapter_config, ips=ips, masks=masks,
437
+ gateways=gateways, dns_gateways=dns_gateways,
438
+ availability_wait_seconds=availability_wait_seconds)
439
+
440
+ if set_virtual_ips_skip_as_source:
441
+ wmi_standard_cimv2_instance, _ = wmi_helpers.get_wmi_instance(
442
+ namespace='root\\StandardCimv2', wmi_instance=wmi_civ2_instance, locator=locator)
443
+ msft_netipaddress.set_skip_as_source(ips_to_assign, enable=True, wmi_instance=wmi_standard_cimv2_instance)
444
+ else:
445
+ # print("[!] No new IPs to assign.")
446
+ pass
447
+
448
+ return current_ipv4s, current_ipv4_masks, ips_to_assign, masks_to_assign