atomicshop 2.15.11__py3-none-any.whl → 3.10.5__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.
Files changed (221) hide show
  1. atomicshop/__init__.py +1 -1
  2. atomicshop/{addons/mains → a_mains}/FACT/update_extract.py +3 -2
  3. atomicshop/a_mains/dns_gateway_setting.py +11 -0
  4. atomicshop/a_mains/get_local_tcp_ports.py +85 -0
  5. atomicshop/a_mains/github_wrapper.py +11 -0
  6. atomicshop/a_mains/install_ca_certificate.py +172 -0
  7. atomicshop/a_mains/process_from_port.py +119 -0
  8. atomicshop/a_mains/set_default_dns_gateway.py +90 -0
  9. atomicshop/a_mains/update_config_toml.py +38 -0
  10. atomicshop/basics/ansi_escape_codes.py +3 -1
  11. atomicshop/basics/argparse_template.py +2 -0
  12. atomicshop/basics/booleans.py +27 -30
  13. atomicshop/basics/bytes_arrays.py +43 -0
  14. atomicshop/basics/classes.py +149 -1
  15. atomicshop/basics/enums.py +2 -2
  16. atomicshop/basics/exceptions.py +5 -1
  17. atomicshop/basics/list_of_classes.py +29 -0
  18. atomicshop/basics/multiprocesses.py +374 -50
  19. atomicshop/basics/strings.py +72 -3
  20. atomicshop/basics/threads.py +14 -0
  21. atomicshop/basics/tracebacks.py +13 -3
  22. atomicshop/certificates.py +153 -52
  23. atomicshop/config_init.py +11 -6
  24. atomicshop/console_user_response.py +7 -14
  25. atomicshop/consoles.py +9 -0
  26. atomicshop/datetimes.py +1 -1
  27. atomicshop/diff_check.py +3 -3
  28. atomicshop/dns.py +128 -3
  29. atomicshop/etws/_pywintrace_fix.py +17 -0
  30. atomicshop/etws/trace.py +40 -42
  31. atomicshop/etws/traces/trace_dns.py +56 -44
  32. atomicshop/etws/traces/trace_tcp.py +130 -0
  33. atomicshop/file_io/csvs.py +27 -5
  34. atomicshop/file_io/docxs.py +34 -17
  35. atomicshop/file_io/file_io.py +31 -17
  36. atomicshop/file_io/jsons.py +49 -0
  37. atomicshop/file_io/tomls.py +139 -0
  38. atomicshop/filesystem.py +616 -291
  39. atomicshop/get_process_list.py +3 -3
  40. atomicshop/http_parse.py +149 -93
  41. atomicshop/ip_addresses.py +6 -1
  42. atomicshop/mitm/centered_settings.py +132 -0
  43. atomicshop/mitm/config_static.py +207 -0
  44. atomicshop/mitm/config_toml_editor.py +55 -0
  45. atomicshop/mitm/connection_thread_worker.py +875 -357
  46. atomicshop/mitm/engines/__parent/parser___parent.py +4 -17
  47. atomicshop/mitm/engines/__parent/recorder___parent.py +108 -51
  48. atomicshop/mitm/engines/__parent/requester___parent.py +116 -0
  49. atomicshop/mitm/engines/__parent/responder___parent.py +75 -114
  50. atomicshop/mitm/engines/__reference_general/parser___reference_general.py +10 -7
  51. atomicshop/mitm/engines/__reference_general/recorder___reference_general.py +5 -5
  52. atomicshop/mitm/engines/__reference_general/requester___reference_general.py +47 -0
  53. atomicshop/mitm/engines/__reference_general/responder___reference_general.py +95 -13
  54. atomicshop/mitm/engines/create_module_template.py +58 -14
  55. atomicshop/mitm/import_config.py +359 -139
  56. atomicshop/mitm/initialize_engines.py +160 -80
  57. atomicshop/mitm/message.py +64 -23
  58. atomicshop/mitm/mitm_main.py +892 -0
  59. atomicshop/mitm/recs_files.py +183 -0
  60. atomicshop/mitm/shared_functions.py +4 -10
  61. atomicshop/mitm/ssh_tester.py +82 -0
  62. atomicshop/mitm/statistic_analyzer.py +136 -40
  63. atomicshop/mitm/statistic_analyzer_helper/moving_average_helper.py +265 -83
  64. atomicshop/monitor/checks/dns.py +1 -1
  65. atomicshop/networks.py +671 -0
  66. atomicshop/on_exit.py +39 -9
  67. atomicshop/package_mains_processor.py +84 -0
  68. atomicshop/permissions/permissions.py +22 -0
  69. atomicshop/permissions/ubuntu_permissions.py +239 -0
  70. atomicshop/permissions/win_permissions.py +33 -0
  71. atomicshop/print_api.py +24 -42
  72. atomicshop/process.py +24 -6
  73. atomicshop/process_poller/process_pool.py +0 -1
  74. atomicshop/process_poller/simple_process_pool.py +204 -5
  75. atomicshop/python_file_patcher.py +1 -1
  76. atomicshop/python_functions.py +27 -75
  77. atomicshop/speech_recognize.py +8 -0
  78. atomicshop/ssh_remote.py +158 -172
  79. atomicshop/system_resource_monitor.py +61 -47
  80. atomicshop/system_resources.py +8 -8
  81. atomicshop/tempfiles.py +1 -2
  82. atomicshop/urls.py +6 -0
  83. atomicshop/venvs.py +28 -0
  84. atomicshop/versioning.py +27 -0
  85. atomicshop/web.py +98 -27
  86. atomicshop/web_apis/google_custom_search.py +44 -0
  87. atomicshop/web_apis/google_llm.py +188 -0
  88. atomicshop/websocket_parse.py +450 -0
  89. atomicshop/wrappers/certauthw/certauth.py +1 -0
  90. atomicshop/wrappers/cryptographyw.py +29 -8
  91. atomicshop/wrappers/ctyping/etw_winapi/const.py +97 -47
  92. atomicshop/wrappers/ctyping/etw_winapi/etw_functions.py +178 -49
  93. atomicshop/wrappers/ctyping/file_details_winapi.py +67 -0
  94. atomicshop/wrappers/ctyping/msi_windows_installer/cabs.py +2 -1
  95. atomicshop/wrappers/ctyping/msi_windows_installer/extract_msi_main.py +2 -2
  96. atomicshop/wrappers/ctyping/setup_device.py +466 -0
  97. atomicshop/wrappers/ctyping/win_console.py +39 -0
  98. atomicshop/wrappers/dockerw/dockerw.py +113 -2
  99. atomicshop/wrappers/elasticsearchw/config_basic.py +0 -12
  100. atomicshop/wrappers/elasticsearchw/elastic_infra.py +75 -0
  101. atomicshop/wrappers/elasticsearchw/elasticsearchw.py +2 -20
  102. atomicshop/wrappers/factw/get_file_data.py +12 -5
  103. atomicshop/wrappers/factw/install/install_after_restart.py +89 -5
  104. atomicshop/wrappers/factw/install/pre_install_and_install_before_restart.py +20 -14
  105. atomicshop/wrappers/githubw.py +537 -54
  106. atomicshop/wrappers/loggingw/consts.py +1 -1
  107. atomicshop/wrappers/loggingw/filters.py +23 -0
  108. atomicshop/wrappers/loggingw/formatters.py +12 -0
  109. atomicshop/wrappers/loggingw/handlers.py +214 -107
  110. atomicshop/wrappers/loggingw/loggers.py +19 -0
  111. atomicshop/wrappers/loggingw/loggingw.py +860 -22
  112. atomicshop/wrappers/loggingw/reading.py +134 -112
  113. atomicshop/wrappers/mongodbw/mongo_infra.py +31 -0
  114. atomicshop/wrappers/mongodbw/mongodbw.py +1324 -36
  115. atomicshop/wrappers/netshw.py +271 -0
  116. atomicshop/wrappers/playwrightw/engine.py +34 -19
  117. atomicshop/wrappers/playwrightw/infra.py +5 -0
  118. atomicshop/wrappers/playwrightw/javascript.py +7 -3
  119. atomicshop/wrappers/playwrightw/keyboard.py +14 -0
  120. atomicshop/wrappers/playwrightw/scenarios.py +172 -5
  121. atomicshop/wrappers/playwrightw/waits.py +9 -7
  122. atomicshop/wrappers/powershell_networking.py +80 -0
  123. atomicshop/wrappers/psutilw/processes.py +37 -1
  124. atomicshop/wrappers/psutilw/psutil_networks.py +85 -0
  125. atomicshop/wrappers/pyopensslw.py +9 -2
  126. atomicshop/wrappers/pywin32w/cert_store.py +116 -0
  127. atomicshop/wrappers/pywin32w/win_event_log/fetch.py +174 -0
  128. atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_create.py +3 -105
  129. atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_terminate.py +3 -57
  130. atomicshop/wrappers/pywin32w/wmis/msft_netipaddress.py +113 -0
  131. atomicshop/wrappers/pywin32w/wmis/win32_networkadapterconfiguration.py +259 -0
  132. atomicshop/wrappers/pywin32w/wmis/win32networkadapter.py +112 -0
  133. atomicshop/wrappers/pywin32w/wmis/wmi_helpers.py +236 -0
  134. atomicshop/wrappers/socketw/accepter.py +21 -7
  135. atomicshop/wrappers/socketw/certificator.py +216 -150
  136. atomicshop/wrappers/socketw/creator.py +190 -50
  137. atomicshop/wrappers/socketw/dns_server.py +491 -182
  138. atomicshop/wrappers/socketw/exception_wrapper.py +45 -52
  139. atomicshop/wrappers/socketw/process_getter.py +86 -0
  140. atomicshop/wrappers/socketw/receiver.py +144 -102
  141. atomicshop/wrappers/socketw/sender.py +65 -35
  142. atomicshop/wrappers/socketw/sni.py +334 -165
  143. atomicshop/wrappers/socketw/socket_base.py +134 -0
  144. atomicshop/wrappers/socketw/socket_client.py +137 -95
  145. atomicshop/wrappers/socketw/socket_server_tester.py +11 -7
  146. atomicshop/wrappers/socketw/socket_wrapper.py +717 -116
  147. atomicshop/wrappers/socketw/ssl_base.py +15 -14
  148. atomicshop/wrappers/socketw/statistics_csv.py +148 -17
  149. atomicshop/wrappers/sysmonw.py +1 -1
  150. atomicshop/wrappers/ubuntu_terminal.py +65 -26
  151. atomicshop/wrappers/win_auditw.py +189 -0
  152. atomicshop/wrappers/winregw/__init__.py +0 -0
  153. atomicshop/wrappers/winregw/winreg_installed_software.py +58 -0
  154. atomicshop/wrappers/winregw/winreg_network.py +232 -0
  155. {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info}/METADATA +31 -51
  156. atomicshop-3.10.5.dist-info/RECORD +306 -0
  157. {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info}/WHEEL +1 -1
  158. atomicshop/_basics_temp.py +0 -101
  159. atomicshop/a_installs/win/fibratus.py +0 -9
  160. atomicshop/a_installs/win/mongodb.py +0 -9
  161. atomicshop/a_installs/win/pycharm.py +0 -9
  162. atomicshop/addons/a_setup_scripts/install_psycopg2_ubuntu.sh +0 -3
  163. atomicshop/addons/a_setup_scripts/install_pywintrace_0.3.cmd +0 -2
  164. atomicshop/addons/mains/__pycache__/install_fibratus_windows.cpython-312.pyc +0 -0
  165. atomicshop/addons/mains/__pycache__/msi_unpacker.cpython-312.pyc +0 -0
  166. atomicshop/addons/mains/install_docker_rootless_ubuntu.py +0 -11
  167. atomicshop/addons/mains/install_docker_ubuntu_main_sudo.py +0 -11
  168. atomicshop/addons/mains/install_elastic_search_and_kibana_ubuntu.py +0 -10
  169. atomicshop/addons/mains/install_wsl_ubuntu_lts_admin.py +0 -9
  170. atomicshop/addons/package_setup/CreateWheel.cmd +0 -7
  171. atomicshop/addons/package_setup/Setup in Edit mode.cmd +0 -6
  172. atomicshop/addons/package_setup/Setup.cmd +0 -7
  173. atomicshop/archiver/_search_in_zip.py +0 -189
  174. atomicshop/archiver/archiver.py +0 -34
  175. atomicshop/archiver/search_in_archive.py +0 -250
  176. atomicshop/archiver/sevenz_app_w.py +0 -86
  177. atomicshop/archiver/sevenzs.py +0 -44
  178. atomicshop/archiver/zips.py +0 -293
  179. atomicshop/file_types.py +0 -24
  180. atomicshop/mitm/config_editor.py +0 -37
  181. atomicshop/mitm/engines/create_module_template_example.py +0 -13
  182. atomicshop/mitm/initialize_mitm_server.py +0 -268
  183. atomicshop/pbtkmultifile_argparse.py +0 -88
  184. atomicshop/permissions.py +0 -151
  185. atomicshop/script_as_string_processor.py +0 -38
  186. atomicshop/ssh_scripts/process_from_ipv4.py +0 -37
  187. atomicshop/ssh_scripts/process_from_port.py +0 -27
  188. atomicshop/wrappers/_process_wrapper_curl.py +0 -27
  189. atomicshop/wrappers/_process_wrapper_tar.py +0 -21
  190. atomicshop/wrappers/dockerw/install_docker.py +0 -209
  191. atomicshop/wrappers/elasticsearchw/infrastructure.py +0 -265
  192. atomicshop/wrappers/elasticsearchw/install_elastic.py +0 -232
  193. atomicshop/wrappers/ffmpegw.py +0 -125
  194. atomicshop/wrappers/fibratusw/install.py +0 -81
  195. atomicshop/wrappers/mongodbw/infrastructure.py +0 -53
  196. atomicshop/wrappers/mongodbw/install_mongodb.py +0 -190
  197. atomicshop/wrappers/msiw.py +0 -149
  198. atomicshop/wrappers/nodejsw/install_nodejs.py +0 -139
  199. atomicshop/wrappers/process_wrapper_pbtk.py +0 -16
  200. atomicshop/wrappers/psutilw/networks.py +0 -45
  201. atomicshop/wrappers/pycharmw.py +0 -81
  202. atomicshop/wrappers/socketw/base.py +0 -59
  203. atomicshop/wrappers/socketw/get_process.py +0 -107
  204. atomicshop/wrappers/wslw.py +0 -191
  205. atomicshop-2.15.11.dist-info/RECORD +0 -302
  206. /atomicshop/{addons/mains → a_mains}/FACT/factw_fact_extractor_docker_image_main_sudo.py +0 -0
  207. /atomicshop/{addons → a_mains/addons}/PlayWrightCodegen.cmd +0 -0
  208. /atomicshop/{addons → a_mains/addons}/ScriptExecution.cmd +0 -0
  209. /atomicshop/{addons → a_mains/addons}/inits/init_to_import_all_modules.py +0 -0
  210. /atomicshop/{addons → a_mains/addons}/process_list/ReadMe.txt +0 -0
  211. /atomicshop/{addons → a_mains/addons}/process_list/compile.cmd +0 -0
  212. /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.dll +0 -0
  213. /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.exp +0 -0
  214. /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.lib +0 -0
  215. /atomicshop/{addons → a_mains/addons}/process_list/process_list.cpp +0 -0
  216. /atomicshop/{archiver → permissions}/__init__.py +0 -0
  217. /atomicshop/{wrappers/fibratusw → web_apis}/__init__.py +0 -0
  218. /atomicshop/wrappers/{nodejsw → pywin32w/wmis}/__init__.py +0 -0
  219. /atomicshop/wrappers/pywin32w/{wmi_win32process.py → wmis/win32process.py} +0 -0
  220. {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info/licenses}/LICENSE.txt +0 -0
  221. {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,5 @@
1
- import subprocess
2
-
3
1
  from .. import subscribe
4
- from .....print_api import print_api
2
+ from .... import win_auditw
5
3
 
6
4
 
7
5
  LOG_CHANNEL: str = 'Security'
@@ -27,7 +25,7 @@ class ProcessTerminateSubscriber(subscribe.EventLogSubscriber):
27
25
 
28
26
  def start(self):
29
27
  """Start the subscription process."""
30
- enable_audit_process_termination()
28
+ win_auditw.enable_audit_process_termination()
31
29
 
32
30
  super().start()
33
31
 
@@ -48,56 +46,4 @@ class ProcessTerminateSubscriber(subscribe.EventLogSubscriber):
48
46
 
49
47
  data['ProcessIdInt'] = int(data['ProcessId'], 16)
50
48
 
51
- return data
52
-
53
-
54
- def enable_audit_process_termination(print_kwargs: dict = None):
55
- """
56
- Enable the 'Audit Process Termination' policy.
57
-
58
- :param print_kwargs: Optional keyword arguments for the print function.
59
- """
60
- if is_audit_process_termination_enabled():
61
- print_api("Audit Process Termination is already enabled.", color='yellow', **(print_kwargs or {}))
62
- return
63
-
64
- audit_policy_command = [
65
- "auditpol", "/set", "/subcategory:Process Termination", "/success:enable", "/failure:enable"
66
- ]
67
- try:
68
- subprocess.run(audit_policy_command, check=True)
69
- print_api("Successfully enabled 'Audit Process Termination'.", color='green', **(print_kwargs or {}))
70
- except subprocess.CalledProcessError as e:
71
- print_api(f"Failed to enable 'Audit Process Termination': {e}", error_type=True, color='red', **(print_kwargs or {}))
72
- raise e
73
-
74
-
75
- def is_audit_process_termination_enabled(print_kwargs: dict = None) -> bool:
76
- """
77
- Check if the 'Audit Process Termination' policy is enabled.
78
-
79
- :param print_kwargs: Optional keyword arguments for the print function.
80
- """
81
- # Command to check the "Audit Process Creation" policy
82
- audit_policy_check_command = [
83
- "auditpol", "/get", "/subcategory:Process Termination"
84
- ]
85
- try:
86
- result = subprocess.run(audit_policy_check_command, check=True, capture_output=True, text=True)
87
- output = result.stdout
88
- # print_api(output) # Print the output for inspection
89
-
90
- if "Process Termination" in output and "Success and Failure" in output:
91
- # print_api(
92
- # "'Audit Process Termination' is enabled for both success and failure.",
93
- # color='green', **(print_kwargs or {}))
94
- return True
95
- else:
96
- # print_api(output, **(print_kwargs or {}))
97
- # print_api(
98
- # "'Audit Process Termination' is not fully enabled. Check the output above for details.",
99
- # color='yellow', **(print_kwargs or {}))
100
- return False
101
- except subprocess.CalledProcessError as e:
102
- print_api(f"Failed to check 'Audit Process Termination': {e}", color='red', error_type=True, **(print_kwargs or {}))
103
- return False
49
+ return data
@@ -0,0 +1,113 @@
1
+ from typing import Optional
2
+
3
+ from win32com.client import CDispatch
4
+
5
+ from . import wmi_helpers
6
+
7
+
8
+ def set_skip_as_source(
9
+ ip_addresses: list[str],
10
+ enable: bool = True,
11
+ wmi_instance: CDispatch = None
12
+ ) -> None:
13
+ """
14
+ Toggle SkipAsSource for every address in *ip_addrs*.
15
+
16
+ Parameters
17
+ ----------
18
+ ip_addresses : list/tuple/iterable of str
19
+ One or more literal IP strings, e.g. "192.168.157.3"
20
+ enable : bool
21
+ True → behave like Set‑NetIPAddress ‑SkipAsSource $true
22
+ False → behave like Set‑NetIPAddress ‑SkipAsSource $false
23
+ wmi_instance : CDispatch
24
+ WMI instance to use. If not provided, a new one will be created.
25
+ 'root\\StandardCimv2'
26
+
27
+ ================
28
+
29
+ Explanation.
30
+ When you add extra IPv4 addresses to the same NIC, Windows treats them all as “first‑class” unless you tell it otherwise.
31
+ Because the two new addresses (192.168.157.3 and .4) are numerically lower than the original one (.129), the TCP/IP stack now prefers one of those lower addresses as the default source for any socket whose program didn’t bind an explicit local IP.
32
+
33
+ What that looks like on the wire
34
+ Client sends SYN → 192.168.157.3 (or .4).
35
+ – Server replies with SYN/ACK ←192.168.157.3 → handshake completes, HTTP works.
36
+
37
+ Client sends SYN → 192.168.157.129.
38
+ – Stack still picks .3 as its favourite and answers SYN/ACK ← 192.168.157.3.
39
+ – Client discards the packet (wrong IP), retransmits the SYN, your code’s accept() wakes up again, and you see an “infinite accept loop”.
40
+
41
+ The flag that fixes it: SkipAsSource
42
+ Tell Windows not to use the extra addresses unless an application asks for them.
43
+
44
+ PowerShell.
45
+ # One‑off: mark the addresses you already added
46
+ Get-NetIPAddress -IPAddress 192.168.157.3 | Set-NetIPAddress -SkipAsSource $true
47
+ Get-NetIPAddress -IPAddress 192.168.157.4 | Set-NetIPAddress -SkipAsSource $true
48
+
49
+ # —OR— add new addresses the right way from the start
50
+ New-NetIPAddress -InterfaceAlias "Ethernet0" `
51
+ -IPAddress 192.168.157.3 `
52
+ -PrefixLength 24 `
53
+ -SkipAsSource $true
54
+ SkipAsSource = $true keeps the address fully routable for incoming traffic and lets programs bind to it explicitly.
55
+
56
+ Windows will never choose that address as the source of an outgoing packet unless the program bound the socket to it.
57
+
58
+ After you flip the flag (no reboot required) the three‑way handshake is symmetrical again and the endless accept() loop disappears.
59
+ """
60
+
61
+ if not wmi_instance:
62
+ wmi_instance, _ = wmi_helpers.get_wmi_instance(namespace='root\\StandardCimv2')
63
+
64
+ for ip in ip_addresses:
65
+ query = f"SELECT * FROM MSFT_NetIPAddress WHERE IPAddress='{ip}'"
66
+ matches = wmi_instance.ExecQuery(query)
67
+ if not matches:
68
+ print(f"[!] {ip}: no such address found")
69
+ continue
70
+
71
+ for obj in matches: # usually just one
72
+ if bool(obj.SkipAsSource) == enable:
73
+ print(f"[=] {ip}: SkipAsSource already {enable}")
74
+ continue
75
+
76
+ obj.SkipAsSource = enable
77
+ obj.Put_() # commit the change
78
+ print(f"[+] {ip}: SkipAsSource set to {enable}")
79
+
80
+
81
+ def is_skip_as_source(
82
+ ip_address: str,
83
+ wmi_instance: CDispatch = None
84
+ ) -> Optional[bool]:
85
+ """
86
+ Check whether *ip_address* currently has SkipAsSource set.
87
+
88
+ Returns
89
+ -------
90
+ True – the flag is enabled
91
+ False – the flag is disabled
92
+ None – no MSFT_NetIPAddress object matches the IP (not present)
93
+
94
+ Notes
95
+ -----
96
+ * Works for both IPv4/IPv6.
97
+ * Uses the same Win32 CIM class (root\\StandardCimv2 › MSFT_NetIPAddress).
98
+ * You can pass an existing `wmi_instance` to avoid reconnecting in tight loops.
99
+ """
100
+ # Get a WMI connection if the caller didn’t hand us one
101
+ if not wmi_instance:
102
+ wmi_instance, _ = wmi_helpers.get_wmi_instance(namespace='root\\StandardCimv2')
103
+
104
+ query = f"SELECT SkipAsSource FROM MSFT_NetIPAddress WHERE IPAddress='{ip_address}'"
105
+ matches = wmi_instance.ExecQuery(query)
106
+
107
+ if not matches: # address not configured on this host/NIC
108
+ return None
109
+
110
+ # There should be only one entry per literal IP, but handle duplicates sanely
111
+ # Return True if *any* matching record has SkipAsSource = True,
112
+ # otherwise False (all are False).
113
+ return any(bool(obj.SkipAsSource) for obj in matches)
@@ -0,0 +1,259 @@
1
+ from typing import Union
2
+ import socket
3
+ import time
4
+
5
+ from win32com.client import CDispatch
6
+ import pywintypes
7
+
8
+ from . import wmi_helpers, win32networkadapter
9
+ from .... import ip_addresses
10
+
11
+
12
+ def get_network_configuration_by_adapter(
13
+ adapter: CDispatch,
14
+ wmi_instance: CDispatch = None
15
+ ) -> Union[CDispatch, None]:
16
+ """
17
+ Get the network configuration for a specific adapter index.
18
+
19
+ :param adapter: CDispatch, Win32_NetworkAdapter object.
20
+ :param wmi_instance: WMI instance. You can get it from:
21
+ wmi_helpers.get_wmi_instance()
22
+ :return: Win32_NetworkAdapterConfiguration object.
23
+ """
24
+
25
+ network_config: CDispatch = wmi_instance.ExecQuery(
26
+ f"SELECT * FROM Win32_NetworkAdapterConfiguration WHERE Index={adapter.Index}")[0]
27
+
28
+ return network_config
29
+
30
+
31
+ def get_adapter_network_configuration(
32
+ interface_name: str = None,
33
+ mac_address: str = None,
34
+ wmi_instance: CDispatch = None
35
+ ) -> tuple:
36
+ """
37
+ Get the WMI network configuration for a network adapter.
38
+ :param interface_name: string, adapter name as shown in the network settings.
39
+ :param mac_address: string, MAC address of the adapter. Format: '00:00:00:00:00:00'.
40
+ :param wmi_instance: WMI instance. You can get it from:
41
+ wrappers.pywin32s.wmis.wmi_helpers.get_wmi_instance()
42
+ or default will be used.
43
+ :return: tuple(Win32_NetworkAdapterConfiguration, Win32_NetworkAdapter)
44
+ """
45
+
46
+ if not wmi_instance:
47
+ wmi_instance, _ = wmi_helpers.get_wmi_instance()
48
+
49
+ adapters = win32networkadapter.list_network_adapters(wmi_instance)
50
+
51
+ if interface_name is None and mac_address is None:
52
+ raise ValueError("Either 'interface_name' or 'mac_address' must be provided.")
53
+ elif interface_name and mac_address:
54
+ raise ValueError("Only one of 'interface_name' or 'mac_address' must be provided.")
55
+
56
+ current_adapter = None
57
+ if interface_name:
58
+ for adapter in adapters:
59
+ if interface_name == adapter.NetConnectionID:
60
+ current_adapter = adapter
61
+ break
62
+
63
+ if not current_adapter:
64
+ raise wmi_helpers.WMINetworkAdapterNotFoundError(f"Adapter with interface name '{interface_name}' not found.")
65
+ elif mac_address:
66
+ for adapter in adapters:
67
+ if mac_address == adapter.MACAddress:
68
+ current_adapter = adapter
69
+ break
70
+
71
+ if current_adapter is None:
72
+ raise wmi_helpers.WMINetworkAdapterNotFoundError(f"Adapter with MAC address '{mac_address}' not found.")
73
+
74
+ # Query the network adapter configurations
75
+ query = f"SELECT * FROM Win32_NetworkAdapterConfiguration WHERE Index='{current_adapter.DeviceID}'"
76
+ adapter_configs = wmi_instance.ExecQuery(query)
77
+
78
+ # Check if the adapter exists
79
+ if len(adapter_configs) == 0:
80
+ raise wmi_helpers.WMINetworkAdapterNotFoundError(f"Adapter with interface name '{interface_name}' not found.")
81
+
82
+ return adapter_configs[0], current_adapter
83
+
84
+
85
+ def set_static_ips(
86
+ network_config: CDispatch, # Win32_NetworkAdapterConfiguration (CDispatch)
87
+ ips: list[str], # ["192.168.157.3", ...]
88
+ masks: list[str], # ["255.255.255.0", ...]
89
+ gateways: list[str] = None,
90
+ dns_gateways: list[str] = None,
91
+ availability_wait_seconds: int = 0
92
+ ) -> None:
93
+ """
94
+ • network_config – Win32_NetworkAdapterConfiguration instance for the target NIC
95
+ (you already have it from GetObject / WMI query).
96
+ • ips – list of IPv4 strings.
97
+ • masks – matching subnet‑mask list (same length as ipv4).
98
+ • gateways – list of default gateways (optional).
99
+ • dns_gateways – list of DNS servers (optional).
100
+ • availability_wait_seconds – seconds to wait for the adapter to become available.
101
+ 0 means no wait.
102
+
103
+ Raises RuntimeError if Windows reports anything other than success (0 / 1)
104
+ or "object already exists" (22) for each operation.
105
+
106
+ ==========
107
+
108
+ Example:
109
+ cfg = wmi_instance.Get("Win32_NetworkAdapterConfiguration.Index=12") # your adapter
110
+ set_static_ips(
111
+ cfg,
112
+ ipv4=["192.168.157.129", "192.168.157.3", "192.168.157.4"],
113
+ masks=["255.255.255.0"] * 3,
114
+ # gateways=["192.168.157.2"],
115
+ # dns_gateways=["8.8.8.8", "1.1.1.1"]
116
+ )
117
+ """
118
+
119
+ initial_default_ipv4: str = socket.gethostbyname(socket.gethostname())
120
+
121
+ # -------------------- IPv4 via EnableStatic ----------------------------
122
+ if not masks or len(ips) != len(masks):
123
+ raise ValueError("ipv4 and masks must be lists of equal length")
124
+
125
+ # # refresh the instance – state may have changed after the previous call
126
+ # network_config = network_config.Path_.GetObject_()
127
+
128
+ try:
129
+ in_params = network_config.Methods_("EnableStatic").InParameters.SpawnInstance_()
130
+ except pywintypes.com_error as e:
131
+ if e.excepinfo[1] == 'SWbemMethodSet' and 'Not found' in e.excepinfo[2]:
132
+ raise RuntimeError(f"Probably the adapter is already set to static non-DHCP.\n"
133
+ f"Failed to get [EnableStatic] method parameters: {e}\n")
134
+ else:
135
+ raise
136
+
137
+ in_params.IPAddress = ips
138
+ in_params.SubnetMask = masks
139
+
140
+ rc = network_config.ExecMethod_("EnableStatic", in_params).Properties_('ReturnValue').Value
141
+ if rc not in (0, 1): # 0 = reboot required, 1 = OK
142
+ raise RuntimeError(f"EnableStatic (IPv4) failed, code {rc}")
143
+
144
+ # -------------------- Default Gateway via SetGateways -------------------
145
+ if gateways:
146
+ gateway_metrics = [1] * len(gateways)
147
+ in_params = network_config.Methods_("SetGateways").InParameters.SpawnInstance_()
148
+ in_params.DefaultIPGateway = gateways
149
+ in_params.GatewayCostMetric = [int(m) for m in gateway_metrics]
150
+
151
+ rc = network_config.ExecMethod_("SetGateways", in_params) \
152
+ .Properties_('ReturnValue').Value
153
+ if rc not in (0, 1):
154
+ raise RuntimeError(f"SetGateways failed, code {rc}")
155
+
156
+ # -------------------- DNS via SetDNSServerSearchOrder ------------------
157
+ if dns_gateways:
158
+ in_params = network_config.Methods_("SetDNSServerSearchOrder").InParameters.SpawnInstance_()
159
+ in_params.DNSServerSearchOrder = dns_gateways
160
+
161
+ rc = network_config.ExecMethod_("SetDNSServerSearchOrder", in_params).Properties_('ReturnValue').Value
162
+ if rc not in (0, 1):
163
+ raise RuntimeError(f"SetDNSServerSearchOrder failed, code {rc}")
164
+
165
+ # -------------------- Wait for the adapter to become available -----------
166
+ if availability_wait_seconds > 0:
167
+ count = 0
168
+ while count < 15:
169
+ current_default_ipv4: str = socket.gethostbyname(socket.gethostname())
170
+ if current_default_ipv4 == initial_default_ipv4:
171
+ # print(f"[+] Adapter is available: {current_default_ipv4}")
172
+ break
173
+ else:
174
+ # print(f"[!] Adapter is not available yet: [{current_default_ipv4}]")
175
+ count += 1
176
+
177
+ time.sleep(1)
178
+
179
+
180
+ def set_dynamic_ip(
181
+ nic_cfg,
182
+ reset_dns: bool = True,
183
+ reset_wins: bool = True
184
+ ) -> None:
185
+ """
186
+ Switch the adapter represented by *nic_cfg* (a Win32_NetworkAdapterConfiguration
187
+ COM object) to DHCP.
188
+
189
+ Parameters
190
+ ----------
191
+ nic_cfg : CDispatch
192
+ The adapter’s Win32_NetworkAdapterConfiguration instance (IPEnabled = TRUE).
193
+ reset_dns : bool, default True
194
+ Also clear any static DNS servers (calls SetDNSServerSearchOrder(None)).
195
+ reset_wins : bool, default True
196
+ Also clear any static WINS servers (calls SetWINSServer(None, None)).
197
+
198
+ Raises
199
+ ------
200
+ RuntimeError
201
+ If any WMI call returns a status other than 0 (“Success”) or 1 (“Restart required”).
202
+ """
203
+
204
+ # 1) Turn on DHCP for IPv4
205
+ wmi_helpers.call_method(nic_cfg, 'EnableDHCP')
206
+
207
+ # 2) Clear static gateways (otherwise Windows keeps using them)
208
+ wmi_helpers.call_method(nic_cfg, 'SetGateways', ([], [])) # empty SAFEARRAY → remove gateways
209
+
210
+ # 3) Optional: reset DNS
211
+ if reset_dns:
212
+ wmi_helpers.call_method(nic_cfg, 'SetDNSServerSearchOrder', None) # None = DHCP-provided DNS
213
+
214
+ # 4) Optional: reset WINS
215
+ if reset_wins:
216
+ wmi_helpers.call_method(nic_cfg, 'SetWINSServer', ("", ""))
217
+
218
+
219
+ def get_info_from_network_config(
220
+ network_config: CDispatch
221
+ ) -> dict:
222
+ """
223
+ Collect information about adapter that currently carries the default route.
224
+
225
+ :param network_config: CDispatch, Win32_NetworkAdapterConfiguration object.
226
+ :return: dict of the default adapter.
227
+ """
228
+
229
+ def _split_ips(config):
230
+ """Split IPAddress[] into separate v4 / v6 lists."""
231
+ current_ipv4s: list[str] = []
232
+ current_ipv4_masks: list[str] = []
233
+ current_ipv6s: list[str] = []
234
+ current_ipv6_prefixes: list[int] = []
235
+ for address_index, ip_address in enumerate(config.IPAddress):
236
+ if ip_addresses.is_ip_address(ip_address, 'ipv4'):
237
+ current_ipv4s.append(ip_address)
238
+ current_ipv4_masks.append(config.IPSubnet[address_index])
239
+ elif ip_addresses.is_ip_address(ip_address, 'ipv6'):
240
+ current_ipv6s.append(ip_address)
241
+ current_ipv6_prefixes.append(int(config.IPSubnet[address_index]))
242
+
243
+ return current_ipv4s, current_ipv6s, current_ipv4_masks, current_ipv6_prefixes
244
+
245
+ ipv4s, ipv6s, ipv4subnets, ipv6prefixes = _split_ips(network_config)
246
+ adapter = {
247
+ "caption": network_config.Caption,
248
+ "description": network_config.Description,
249
+ "interface_index": network_config.InterfaceIndex,
250
+ "is_dynamic": bool(network_config.DHCPEnabled),
251
+ "ipv4s": ipv4s,
252
+ "ipv6s": ipv6s,
253
+ "ipv4_subnet_masks": ipv4subnets,
254
+ "ipv6_prefixes": ipv6prefixes,
255
+ "default_gateways": list(network_config.DefaultIPGateway or []),
256
+ "dns_gateways": list(network_config.DNSServerSearchOrder or []),
257
+ }
258
+
259
+ return adapter
@@ -0,0 +1,112 @@
1
+ from logging import Logger
2
+ from typing import Union
3
+
4
+ from win32com.client import CDispatch
5
+
6
+ from . import wmi_helpers, win32_networkadapterconfiguration
7
+ from ...psutilw import psutil_networks
8
+ from ....print_api import print_api
9
+
10
+
11
+ def list_network_adapters(wmi_instance: CDispatch = None) -> list[CDispatch]:
12
+ """
13
+ List all network adapters on the system, from the Win32_NetworkAdapter class.
14
+
15
+ :param wmi_instance: WMI instance. You can get it from:
16
+ wmi_helpers.get_wmi_instance()
17
+ :return: list of Win32_NetworkAdapter objects.
18
+ """
19
+
20
+ if not wmi_instance:
21
+ wmi_instance, _ = wmi_helpers.get_wmi_instance()
22
+
23
+ # Query all network adapters
24
+ adapters: list[CDispatch] = list(wmi_instance.ExecQuery("SELECT * FROM Win32_NetworkAdapter"))
25
+
26
+ # Print adapter descriptions
27
+ # for adapter in adapters:
28
+ # print(f"Description: {adapter.Description}, IPEnabled: {adapter.IPEnabled}")
29
+ return adapters
30
+
31
+
32
+ def get_network_adapter_by_device_name(
33
+ device_name: str,
34
+ wmi_instance: CDispatch = None
35
+ ) -> Union[CDispatch, None]:
36
+ """
37
+ Get a network adapter by its name.
38
+
39
+ :param device_name: string, adapter name as shown in the network settings.
40
+ :param wmi_instance: WMI instance. You can get it from:
41
+ wmi_helpers.get_wmi_instance()
42
+ :return: Win32_NetworkAdapter object.
43
+ """
44
+
45
+ if not wmi_instance:
46
+ wmi_instance, _ = wmi_helpers.get_wmi_instance()
47
+
48
+ query: str = (
49
+ "SELECT * FROM Win32_NetworkAdapter "
50
+ f"WHERE Name LIKE '{device_name}'")
51
+ adapters: list[CDispatch] = list(wmi_instance.ExecQuery(query))
52
+ if not adapters:
53
+ return None
54
+
55
+ return adapters[0]
56
+
57
+
58
+ def get_default_network_adapter(wmi_instance: CDispatch = None):
59
+ """
60
+ Get the default network adapter.
61
+
62
+ :param wmi_instance: WMI instance. You can get it from:
63
+ wmi_helpers.get_wmi_instance()
64
+ :return:
65
+ """
66
+
67
+ if not wmi_instance:
68
+ wmi_instance, _ = wmi_helpers.get_wmi_instance()
69
+
70
+ default_connection_name_dict: dict = psutil_networks.get_default_connection_name()
71
+ # Get the first key from the dictionary.
72
+ default_connection_name: str = list(default_connection_name_dict.keys())[0]
73
+ adapters: list[CDispatch] = list_network_adapters(wmi_instance)
74
+
75
+ for adapter in adapters:
76
+ if default_connection_name == adapter.NetConnectionID:
77
+ return adapter
78
+
79
+ raise wmi_helpers.WMINetworkAdapterNotFoundError("Default network adapter not found.")
80
+
81
+
82
+ def set_dns_server(
83
+ dns_servers: Union[list[str], None],
84
+ interface_name: str = None,
85
+ mac_address: str = None,
86
+ verbose: bool = False,
87
+ logger: Logger = None
88
+ ):
89
+ """
90
+ Set the DNS servers for a network adapter.
91
+ :param dns_servers: list of strings, DNS server IPv4 addresses.
92
+ None, if you want to remove the DNS servers and make the interface to obtain them automatically from DHCP.
93
+ list[str], if you want to set the DNS servers manually to the list of strings.
94
+ :param interface_name: string, network interface name as shown in the network settings.
95
+ :param mac_address: string, MAC address of the adapter. Format: '00:00:00:00:00:00'.
96
+
97
+ :param verbose: bool, if True, print verbose output.
98
+ :param logger: Logger object, if provided, will log the output instead of printing.
99
+ :return:
100
+ """
101
+
102
+ adapter_config, current_adapter = win32_networkadapterconfiguration.get_adapter_network_configuration(
103
+ interface_name=interface_name, mac_address=mac_address)
104
+
105
+ if verbose:
106
+ message = (
107
+ f"Adapter [{current_adapter.Description}], Connection name [{current_adapter.NetConnectionID}]\n"
108
+ f"Setting DNS servers to {dns_servers}")
109
+ print_api(message, color='blue', logger=logger)
110
+
111
+ # Set DNS servers
112
+ wmi_helpers.call_method(adapter_config, 'SetDNSServerSearchOrder', dns_servers)