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,181 +1,350 @@
1
- import sys
2
1
  import ssl
2
+ from dataclasses import dataclass
3
+ from typing import Callable, Any
3
4
 
4
- from . import certificator, creator
5
+ from ..loggingw import loggingw
5
6
  from ...domains import get_domain_without_first_subdomain_if_no_subdomain_return_as_is
6
7
  from ...print_api import print_api
7
8
 
9
+ from . import certificator, creator
10
+
11
+
12
+ @dataclass
13
+ class SNIReceivedParameters:
14
+ ssl_socket: ssl.SSLSocket
15
+ destination_name: str
16
+ ssl_context: ssl.SSLContext
17
+
8
18
 
9
- def add_sni_callback_function_reference_to_ssl_context(
10
- ssl_context, config: dict, dns_domain: str = None,
11
- sni_function_name=None, use_default_sni_function: bool = False, use_sni_extended: bool = False,
12
- print_kwargs: dict = None):
19
+ class SNIDefaultCertificateCreationError(Exception):
20
+ pass
21
+
22
+
23
+ class SNISetup:
13
24
  """
14
- Add SNI callback function reference to SSLContext object. Inplace.
15
-
16
- :param ssl_context:
17
- :param config:
18
- :param dns_domain: domain that was received from DNS Server that will be used if no SNI was passed.
19
- :param sni_function_name: Reference to the function that will be called when SNI is present in the request.
20
- :param use_default_sni_function: If True, will use default SNI function.
21
- :param use_sni_extended: If True, will use extended SNI function.
22
- :param print_kwargs: dict, that contains all the arguments for 'print_api' function.
23
- :return:
25
+ Class to handle setting up SNI related features in socket and context.
24
26
  """
27
+ def __init__(
28
+ self,
29
+ ca_certificate_name: str,
30
+ ca_certificate_filepath: str,
31
+ default_server_certificate_usage: bool,
32
+ default_server_certificate_name: str,
33
+ default_server_certificate_directory: str,
34
+ default_certificate_domain_list: list,
35
+ sni_custom_callback_function: Callable[..., Any],
36
+ sni_use_default_callback_function: bool,
37
+ sni_use_default_callback_function_extended: bool,
38
+ sni_add_new_domains_to_default_server_certificate: bool,
39
+ sni_create_server_certificate_for_each_domain: bool,
40
+ sni_server_certificates_cache_directory: str,
41
+ sni_get_server_certificate_from_server_socket: bool,
42
+ sni_server_certificate_from_server_socket_download_directory: str,
43
+ custom_server_certificate_usage: bool,
44
+ custom_server_certificate_path: str,
45
+ custom_private_key_path: str,
46
+ forwarding_dns_service_ipv4_list___only_for_localhost: list,
47
+ tls: bool,
48
+ domain_from_dns_server: str = None,
49
+ skip_extension_id_list: list = None,
50
+ exceptions_logger: loggingw.ExceptionCsvLogger = None,
51
+ enable_sslkeylogfile_env_to_client_ssl_context: bool = False,
52
+ sslkeylog_file_path: str = None
53
+ ):
54
+ self.ca_certificate_name = ca_certificate_name
55
+ self.ca_certificate_filepath = ca_certificate_filepath
56
+ self.default_server_certificate_usage = default_server_certificate_usage
57
+ self.default_server_certificate_name = default_server_certificate_name
58
+ self.default_server_certificate_directory = default_server_certificate_directory
59
+ self.default_certificate_domain_list = default_certificate_domain_list
60
+ self.sni_custom_callback_function: Callable[..., Any] = sni_custom_callback_function
61
+ self.sni_use_default_callback_function: bool = sni_use_default_callback_function
62
+ self.sni_use_default_callback_function_extended: bool = sni_use_default_callback_function_extended
63
+ self.sni_add_new_domains_to_default_server_certificate = sni_add_new_domains_to_default_server_certificate
64
+ self.sni_create_server_certificate_for_each_domain = sni_create_server_certificate_for_each_domain
65
+ self.sni_server_certificates_cache_directory = sni_server_certificates_cache_directory
66
+ self.sni_get_server_certificate_from_server_socket = sni_get_server_certificate_from_server_socket
67
+ self.sni_server_certificate_from_server_socket_download_directory = (
68
+ sni_server_certificate_from_server_socket_download_directory)
69
+ self.custom_server_certificate_usage = custom_server_certificate_usage
70
+ self.custom_server_certificate_path = custom_server_certificate_path
71
+ self.custom_private_key_path = custom_private_key_path
72
+ self.forwarding_dns_service_ipv4_list___only_for_localhost = (
73
+ forwarding_dns_service_ipv4_list___only_for_localhost)
74
+ self.domain_from_dns_server: str = domain_from_dns_server
75
+ self.skip_extension_id_list = skip_extension_id_list
76
+ self.tls = tls
77
+ self.exceptions_logger = exceptions_logger
78
+ self.certificator_instance = None
79
+ self.enable_sslkeylogfile_env_to_client_ssl_context: bool = enable_sslkeylogfile_env_to_client_ssl_context
80
+ self.sslkeylog_file_path: str = sslkeylog_file_path
81
+
82
+ def wrap_socket_with_ssl_context_server_sni_extended(
83
+ self,
84
+ socket_object,
85
+ print_kwargs: dict = None
86
+ ):
25
87
 
26
- if sni_function_name and (use_default_sni_function or use_sni_extended):
27
- raise ValueError("You can't use both custom and default SNI function at the same time.")
28
-
29
- if use_sni_extended and not use_default_sni_function:
30
- raise ValueError("You can't use extended SNI function without default SNI function.")
31
-
32
- # SNI - Server Name Indication: https://en.wikipedia.org/wiki/Server_Name_Indication
33
- # SNI is extension to TLS protocol to tell the Server what is destination domain that the client is trying to
34
- # connect. The server knowing the destination domain then can present to the client the appropriate certificate.
35
- # "sni_callback" method: https://docs.python.org/3/library/ssl.html#ssl.SSLContext.sni_callback
36
- # The method calls your custom function. If there is SNI present in the TLS request from the client, then the
37
- # function will be called. Automatically providing 3 parameters from the system: ssl.SSLSocket, The destination
38
- # server name, current ssl.SSLContext object.
39
- # If you check the custom function it has all these variables mandatory, since this is what system provides and
40
- # handled by the system, if SNI is existent.
41
- # The function is actually called at "accept()" method of the "ssl.SSLSocket"
42
- # This needs to be set only once on the listening socket
43
- if sni_function_name:
44
- ssl_context.sni_callback = sni_function_name
45
-
46
- if use_default_sni_function:
47
- ssl_context.set_servername_callback(
48
- setup_sni_callback(
49
- use_sni_extended=use_sni_extended, config=config, dns_domain=dns_domain, print_kwargs=print_kwargs)
88
+ # Create SSL Socket to wrap the raw socket with.
89
+ ssl_context: ssl.SSLContext = creator.create_ssl_context_for_server(
90
+ allow_legacy=True, enable_sslkeylogfile_env_to_client_ssl_context=self.enable_sslkeylogfile_env_to_client_ssl_context,
91
+ sslkeylog_file_path=self.sslkeylog_file_path)
92
+
93
+ self.certificator_instance = certificator.Certificator(
94
+ ca_certificate_name=self.ca_certificate_name,
95
+ ca_certificate_filepath=self.ca_certificate_filepath,
96
+ default_server_certificate_usage=self.default_server_certificate_usage,
97
+ default_server_certificate_name=self.default_server_certificate_name,
98
+ default_server_certificate_directory=self.default_server_certificate_directory,
99
+ default_certificate_domain_list=self.default_certificate_domain_list,
100
+ sni_server_certificates_cache_directory=self.sni_server_certificates_cache_directory,
101
+ sni_get_server_certificate_from_server_socket=self.sni_get_server_certificate_from_server_socket,
102
+ sni_server_certificate_from_server_socket_download_directory=(
103
+ self.sni_server_certificate_from_server_socket_download_directory),
104
+ custom_server_certificate_usage=self.custom_server_certificate_usage,
105
+ custom_server_certificate_path=self.custom_server_certificate_path,
106
+ custom_private_key_path=self.custom_private_key_path,
107
+ forwarding_dns_service_ipv4_list___only_for_localhost=(
108
+ self.forwarding_dns_service_ipv4_list___only_for_localhost),
109
+ skip_extension_id_list=self.skip_extension_id_list,
110
+ tls=self.tls,
111
+ enable_sslkeylogfile_env_to_client_ssl_context=self.enable_sslkeylogfile_env_to_client_ssl_context,
112
+ sslkeylog_file_path=self.sslkeylog_file_path
50
113
  )
51
114
 
115
+ # Add SNI callback function to the SSL context.
116
+ self.add_sni_callback_function_to_ssl_context(ssl_context=ssl_context, print_kwargs=print_kwargs)
117
+
118
+ server_certificate_file_path, server_private_key_file_path = \
119
+ self.certificator_instance.select_server_ssl_context_certificate(print_kwargs=print_kwargs)
52
120
 
53
- # Server Name Indication (SNI) is an extension to the Transport Layer Security (TLS) computer networking protocol.
54
- # Function to handle server's SSLContext's SNI callback function.
55
- # This is actually called first during "accept()" method of the "ssl.SSLSocket" then comes accept itself.
56
- # This happens in 'ssl.py' module in 'self._sslobj.do_handshake()' function.
57
- def setup_sni_callback(
58
- use_sni_extended: bool = False, config: dict = None, dns_domain: str = None, print_kwargs: dict = None):
121
+ # If the user chose 'sni_create_server_certificate_for_each_domain = 1' in the configuration file,
122
+ # it means that 'self.server_certificate_file_path' will be empty, which is OK, since we'll inject
123
+ # dynamically created certificate from certs folder through SNI.
124
+ if server_certificate_file_path:
125
+ creator.load_certificate_and_key_into_server_ssl_context(
126
+ ssl_context, server_certificate_file_path, server_private_key_file_path,
127
+ print_kwargs=print_kwargs)
128
+
129
+ ssl_socket, error_message = creator.wrap_socket_with_ssl_context_server_with_error_message(
130
+ socket_object=socket_object, ssl_context=ssl_context, domain_from_dns_server=self.domain_from_dns_server,
131
+ print_kwargs=print_kwargs)
132
+
133
+ return ssl_socket, error_message
134
+
135
+ def add_sni_callback_function_to_ssl_context(
136
+ self,
137
+ ssl_context,
138
+ print_kwargs: dict = None
139
+ ):
140
+ """
141
+ Add SNI callback function reference to SSLContext object. Inplace.
142
+
143
+ :param ssl_context: SSLContext object.
144
+ :param print_kwargs: dict, that contains all the arguments for 'print_api' function.
145
+ :return:
146
+ """
147
+
148
+ # SNI - Server Name Indication: https://en.wikipedia.org/wiki/Server_Name_Indication
149
+ # SNI is extension to TLS protocol to tell the Server what is destination domain that the client is trying to
150
+ # connect. The server knowing the destination domain then can present to the client the appropriate certificate.
151
+ # "sni_callback" method: https://docs.python.org/3/library/ssl.html#ssl.SSLContext.sni_callback
152
+ # The method calls your custom function. If there is SNI present in the TLS request from the client, then the
153
+ # function will be called. Automatically providing 3 parameters from the system: ssl.SSLSocket, The destination
154
+ # server name, current ssl.SSLContext object.
155
+ # If you check the custom function it has all these variables mandatory, since this is what system provides and
156
+ # handled by the system, if SNI is existent.
157
+ # The function is actually called at "accept()" method of the "ssl.SSLSocket"
158
+ # This needs to be set only once on the listening socket
159
+ if self.sni_custom_callback_function:
160
+ # ssl_context.sni_callback = self.sni_custom_callback_function
161
+ ssl_context.set_servername_callback(self.sni_custom_callback_function)
162
+
163
+ if self.sni_use_default_callback_function:
164
+ sni_handler_instance = SNIHandler(
165
+ sni_use_default_callback_function_extended=self.sni_use_default_callback_function_extended,
166
+ sni_add_new_domains_to_default_server_certificate=self.sni_add_new_domains_to_default_server_certificate,
167
+ sni_create_server_certificate_for_each_domain=self.sni_create_server_certificate_for_each_domain,
168
+ certificator_instance=self.certificator_instance,
169
+ domain_from_dns_server=self.domain_from_dns_server,
170
+ default_certificate_domain_list=self.default_certificate_domain_list,
171
+ exceptions_logger=self.exceptions_logger,
172
+ enable_sslkeylogfile_env_to_client_ssl_context=(
173
+ self.certificator_instance.enable_sslkeylogfile_env_to_client_ssl_context),
174
+ sslkeylog_file_path=self.certificator_instance.sslkeylog_file_path)
175
+ ssl_context.set_servername_callback(
176
+ sni_handler_instance.setup_sni_callback(print_kwargs=print_kwargs))
177
+
178
+
179
+ class SNIHandler:
59
180
  """
60
- Setup SNI callback function.
61
- :param use_sni_extended: Use extended SNI function, besides the default one.
62
- :param config:
63
- :param dns_domain: domain that was received from DNS Server that will be used if no SNI was passed.
64
- :param print_kwargs: dict, that contains all the arguments for 'print_api' function.
65
- :return:
181
+ THe class is responsible for handling SNI callback execution.
66
182
  """
67
183
 
68
- def sni_handle(
69
- sni_ssl_socket: ssl.SSLSocket,
70
- sni_destination_name: str,
71
- sni_ssl_context: ssl.SSLContext):
72
-
73
- if use_sni_extended and not config:
74
- raise ValueError("You can't use extended SNI function without config.")
75
-
76
- sni_received_dict = {
77
- 'ssl_socket': sni_ssl_socket,
78
- 'destination_name': sni_destination_name,
79
- 'ssl_context': sni_ssl_context
80
- }
81
-
82
- # If 'sni_execute_extended' was set to True.
83
- if use_sni_extended:
84
- sni_handle_extended(sni_received_dict, config=config, dns_domain=dns_domain, print_kwargs=print_kwargs)
85
- # Just set the server_hostname in current socket.
86
- else:
87
- sni_received_dict['ssl_socket'].server_hostname = sni_destination_name
88
- return sni_handle
89
-
90
-
91
- def sni_handle_extended(sni_received_dict: dict, config: dict, dns_domain: str = None, print_kwargs: dict = None):
92
- # Set 'server_hostname' for the socket.
93
- set_socket_server_hostname(sni_received_dict=sni_received_dict, dns_domain=dns_domain, print_kwargs=print_kwargs)
94
-
95
- # If 'sni_default_server_certificates_addons' was set to 'True' in the 'config.ini'.
96
- # This section will add all the new domains that hit the server to default certificate SAN with wildcard.
97
- if config['certificates']['sni_default_server_certificate_addons']:
98
- sni_add_domain_to_default_server_certificate(sni_received_dict=sni_received_dict, config=config,
99
- print_kwargs=print_kwargs)
100
-
101
- # If SNI server certificate creation was set to 'True', we'll create certificate for each incoming domain if
102
- # non-existent in certificates cache folder.
103
- if config['certificates']['sni_create_server_certificate_for_each_domain']:
104
- certificator.create_use_sni_server_certificate_ca_signed(
105
- sni_received_dict=sni_received_dict, config=config, print_kwargs=print_kwargs)
106
-
107
-
108
- def set_socket_server_hostname(sni_received_dict: dict, dns_domain: str = None, print_kwargs: dict = None):
109
- service_name_from_sni = None
110
-
111
- # Try on general settings in the SNI function.
112
- try:
113
- # Check if SNI was passed.
114
- if sni_received_dict['destination_name']:
115
- service_name_from_sni = sni_received_dict['destination_name']
116
- # If no SNI was passed.
117
- else:
118
- # If DNS server is enabled we'll get the domain from dns server.
119
- if dns_domain:
120
- service_name_from_sni = dns_domain
121
- message = f"SNI Handler: No SNI was passed, using domain from DNS Server: {service_name_from_sni}"
122
- print_api(message, **print_kwargs)
123
- # If DNS server is disabled, the domain from dns server will be empty.
184
+ def __init__(
185
+ self,
186
+ sni_use_default_callback_function_extended: bool,
187
+ sni_add_new_domains_to_default_server_certificate: bool,
188
+ sni_create_server_certificate_for_each_domain: bool,
189
+ certificator_instance: certificator.Certificator,
190
+ domain_from_dns_server: str,
191
+ default_certificate_domain_list: list,
192
+ exceptions_logger: loggingw.ExceptionCsvLogger,
193
+ enable_sslkeylogfile_env_to_client_ssl_context: bool,
194
+ sslkeylog_file_path: str
195
+ ):
196
+ self.sni_use_default_callback_function_extended = sni_use_default_callback_function_extended
197
+ self.sni_add_new_domains_to_default_server_certificate = sni_add_new_domains_to_default_server_certificate
198
+ self.sni_create_server_certificate_for_each_domain = sni_create_server_certificate_for_each_domain
199
+ self.certificator_instance = certificator_instance
200
+ self.domain_from_dns_server: str = domain_from_dns_server
201
+ self.default_certificate_domain_list = default_certificate_domain_list
202
+ self.exceptions_logger = exceptions_logger
203
+ self.enable_sslkeylogfile_env_to_client_ssl_context: bool = enable_sslkeylogfile_env_to_client_ssl_context
204
+ self.sslkeylog_file_path: str = sslkeylog_file_path
205
+
206
+ # noinspection PyTypeChecker
207
+ self.sni_received_parameters: SNIReceivedParameters = None
208
+
209
+ # Server Name Indication (SNI) is an extension to the Transport Layer Security (TLS) computer networking protocol.
210
+ # Function to handle server's SSLContext's SNI callback function.
211
+ # This is actually called first during "accept()" method of the "ssl.SSLSocket" then comes accept itself.
212
+ # This happens in 'ssl.py' module in 'self._sslobj.do_handshake()' function.
213
+ def setup_sni_callback(
214
+ self,
215
+ print_kwargs: dict = None
216
+ ):
217
+ """
218
+ Setup SNI callback function.
219
+ :param print_kwargs: dict, that contains all the arguments for 'print_api' function.
220
+ :return:
221
+ """
222
+
223
+ def sni_handle(
224
+ sni_ssl_socket: ssl.SSLSocket,
225
+ sni_destination_name: str,
226
+ sni_ssl_context: ssl.SSLContext):
227
+
228
+ try:
229
+ # Set 'server_hostname' for the socket.
230
+ sni_ssl_socket.server_hostname = sni_destination_name
231
+
232
+ # If 'sni_execute_extended' was set to True.
233
+ if self.sni_use_default_callback_function_extended:
234
+ self.sni_received_parameters = SNIReceivedParameters(
235
+ ssl_socket=sni_ssl_socket,
236
+ destination_name=sni_destination_name,
237
+ ssl_context=sni_ssl_context
238
+ )
239
+
240
+ self.sni_handle_extended(print_kwargs=print_kwargs)
241
+ except Exception as e:
242
+ self.exceptions_logger.write(e)
243
+
244
+ return sni_handle
245
+
246
+ def sni_handle_extended(
247
+ self,
248
+ print_kwargs: dict = None
249
+ ):
250
+ # Set 'server_hostname' for the socket.
251
+ self.set_socket_server_hostname(print_kwargs=print_kwargs)
252
+
253
+ # If 'sni_default_server_certificates_addons' was set to 'True' in the 'config.ini'.
254
+ # This section will add all the new domains that hit the server to default certificate SAN with wildcard.
255
+ if self.sni_add_new_domains_to_default_server_certificate:
256
+ self.sni_add_domain_to_default_server_certificate(print_kwargs=print_kwargs)
257
+
258
+ # If SNI server certificate creation was set to 'True', we'll create certificate for each incoming domain if
259
+ # non-existent in certificates cache folder.
260
+ if self.sni_create_server_certificate_for_each_domain:
261
+ self.certificator_instance.create_use_sni_server_certificate_ca_signed(
262
+ sni_received_parameters=self.sni_received_parameters, print_kwargs=print_kwargs)
263
+
264
+ def set_socket_server_hostname(
265
+ self,
266
+ print_kwargs: dict = None
267
+ ):
268
+ service_name_from_sni = None
269
+
270
+ # Try on general settings in the SNI function.
271
+ try:
272
+ # Check if SNI was passed. If no SNI was passed.
273
+ if not self.sni_received_parameters.destination_name:
274
+ # If DNS server is enabled we'll get the domain from dns server.
275
+ if self.domain_from_dns_server:
276
+ self.sni_received_parameters.destination_name = self.domain_from_dns_server
277
+ print_api("SNI Passed: False", color="yellow", **(print_kwargs or {}))
278
+
279
+ message = f"SNI Handler: No SNI was passed, using domain from DNS Server: {self.domain_from_dns_server}"
280
+ print_api(message, color="yellow", **(print_kwargs or {}))
281
+ # If DNS server is disabled, the domain from dns server will be empty.
282
+ else:
283
+ print_api("SNI Passed: False", color="yellow", **(print_kwargs or {}))
284
+
285
+ message = (
286
+ f"SNI Handler: No SNI was passed, No domain passed from DNS Server. Service name will be 'None'.")
287
+ print_api(message, color="yellow", **(print_kwargs or {}))
288
+
289
+ # Setting "server_hostname" as a domain.
290
+ self.sni_received_parameters.ssl_socket.server_hostname = self.sni_received_parameters.destination_name
291
+ print_api("SNI Passed: True", **(print_kwargs or {}))
292
+ message = (
293
+ f"SNI Handler: port {self.sni_received_parameters.ssl_socket.getsockname()[1]}: "
294
+ f"Incoming connection for [{self.sni_received_parameters.ssl_socket.server_hostname}]")
295
+ print_api(message, **(print_kwargs or {}))
296
+ except Exception as exception_object:
297
+ message = f"SNI Handler: Undocumented exception general settings section: {exception_object}"
298
+ print_api(message, error_type=True, logger_method="error", traceback_string=True,
299
+ **(print_kwargs or {}))
300
+ pass
301
+
302
+ def sni_add_domain_to_default_server_certificate(
303
+ self,
304
+ print_kwargs: dict = None
305
+ ):
306
+ # Check if incoming domain is already in the parent domains of 'domains_all_times' list.
307
+ if not any(x in self.sni_received_parameters.ssl_socket.server_hostname for x in
308
+ self.default_certificate_domain_list):
309
+ message = f"SNI Handler: Current domain is not in known domains list. Adding."
310
+ print_api(message, **(print_kwargs or {}))
311
+ # In the past was using 'certauth' to extract tlds, but it works only in online mode, so rewrote
312
+ # the function to disable online fetching of TLD snapshot.
313
+ # Initialize 'certauth' object.
314
+ # certificate_object = CertificateAuthority(certificate_ca_name, certificate_ca_filepath)
315
+ # Extract parent domain from the current SNI domain.
316
+ # parent_domain = certificate_object.get_wildcard_domain(service_name_from_sni)
317
+
318
+ # Extract parent domain from the current SNI domain.
319
+ parent_domain = get_domain_without_first_subdomain_if_no_subdomain_return_as_is(
320
+ self.sni_received_parameters.ssl_socket.server_hostname)
321
+ # Add the parent domain to the known domains list.
322
+ self.default_certificate_domain_list.append(parent_domain)
323
+
324
+ default_server_certificate_path, subject_alternate_names = \
325
+ self.certificator_instance.create_overwrite_default_server_certificate_ca_signed()
326
+
327
+ if default_server_certificate_path:
328
+ message = f"SNI Handler: Default Server Certificate was created / overwritten: " \
329
+ f"{default_server_certificate_path}"
330
+ print_api(message, **(print_kwargs or {}))
331
+
332
+ message = f"SNI Handler: Server Certificate current 'Subject Alternative Names': " \
333
+ f"{subject_alternate_names}"
334
+ print_api(message, **(print_kwargs or {}))
335
+
336
+ # Since new default certificate was created we need to create new SSLContext and add the certificate.
337
+ # You need to build new context and exchange the context that being inherited from the main socket,
338
+ # or else the context will receive previous certificate each time.
339
+ self.sni_received_parameters.ssl_socket.context = (
340
+ creator.create_server_ssl_context___load_certificate_and_key(
341
+ default_server_certificate_path,
342
+ None,
343
+ inherit_from=self.sni_received_parameters.ssl_socket.context,
344
+ enable_sslkeylogfile_env_to_client_ssl_context=self.enable_sslkeylogfile_env_to_client_ssl_context,
345
+ sslkeylog_file_path=self.sslkeylog_file_path
346
+ )
347
+ )
124
348
  else:
125
- message = f"SNI Handler: No SNI was passed, No domain passed from DNS Server. " \
126
- f"Service name will be 'None'."
127
- print_api(message, **print_kwargs)
128
-
129
- # Setting "server_hostname" as a domain.
130
- sni_received_dict['ssl_socket'].server_hostname = service_name_from_sni
131
- message = \
132
- f"SNI Handler: port {sni_received_dict['ssl_socket'].getsockname()[1]}: " \
133
- f"Incoming connection for [{sni_received_dict['ssl_socket'].server_hostname}]"
134
- print_api(message, **print_kwargs)
135
- except Exception as exception_object:
136
- message = f"SNI Handler: Undocumented exception general settings section: {exception_object}"
137
- print_api(message, error_type=True, logger_method="error", traceback_string=True, oneline=True,
138
- **print_kwargs)
139
- pass
140
-
141
-
142
- def sni_add_domain_to_default_server_certificate(sni_received_dict: dict, config: dict, print_kwargs: dict = None):
143
- # Check if incoming domain is already in the parent domains of 'domains_all_times' list.
144
- if not any(x in sni_received_dict['ssl_socket'].server_hostname for x in
145
- config['certificates']['domains_all_times']):
146
- message = f"SNI Handler: Current domain is not in known domains list. Adding."
147
- print_api(message, **print_kwargs)
148
- # In the past was using 'certauth' to extract tlds, but it works only in online mode, so rewrote
149
- # the function to disable online fetching of TLD snapshot.
150
- # Initialize 'certauth' object.
151
- # certificate_object = CertificateAuthority(certificate_ca_name, certificate_ca_filepath)
152
- # Extract parent domain from the current SNI domain.
153
- # parent_domain = certificate_object.get_wildcard_domain(service_name_from_sni)
154
-
155
- # Extract parent domain from the current SNI domain.
156
- parent_domain = get_domain_without_first_subdomain_if_no_subdomain_return_as_is(
157
- sni_received_dict['ssl_socket'].server_hostname)
158
- # Add the parent domain to the known domains list.
159
- config['certificates']['domains_all_times'].append(parent_domain)
160
-
161
- default_server_certificate_path, subject_alternate_names = \
162
- certificator.create_overwrite_default_server_certificate_ca_signed(config=config)
163
-
164
- if default_server_certificate_path:
165
- message = f"SNI Handler: Default Server Certificate was created / overwritten: " \
166
- f"{default_server_certificate_path}"
167
- print_api(message, **print_kwargs)
168
-
169
- message = f"SNI Handler: Server Certificate current 'Subject Alternative Names': " \
170
- f"{subject_alternate_names}"
171
- print_api(message, **print_kwargs)
172
-
173
- # Since new default certificate was created we need to create new SSLContext and add the certificate.
174
- # You need to build new context and exchange the context that being inherited from the main socket,
175
- # or else the context will receive previous certificate each time.
176
- sni_received_dict['ssl_socket'].context = \
177
- creator.create_server_ssl_context___load_certificate_and_key(default_server_certificate_path, None)
178
- else:
179
- message = f"Couldn't create / overwrite Default Server Certificate: {default_server_certificate_path}"
180
- print_api(message, error_type=True, logger_method="critical", **print_kwargs)
181
- sys.exit()
349
+ message = f"Couldn't create / overwrite Default Server Certificate: {default_server_certificate_path}"
350
+ raise SNIDefaultCertificateCreationError(message)
@@ -0,0 +1,134 @@
1
+ import socket
2
+ import time
3
+
4
+
5
+ LOCALHOST_IPV4: str = '127.0.0.1'
6
+ DEFAULT_IPV4: str = socket.gethostbyname(socket.gethostname())
7
+ THIS_DEVICE_IP_LIST: list = [LOCALHOST_IPV4, DEFAULT_IPV4]
8
+
9
+
10
+ def get_local_network_interfaces_ip_address(family_type: str = None, ip_only: bool = False) -> list:
11
+ """
12
+ Return list of IP addresses of local network interfaces.
13
+
14
+ :param family_type: string, available options:
15
+ None: default, returns both ipv4 and ipv6 addresses.
16
+ "ipv4": returns only ipv4 addresses.
17
+ "ipv6": returns only ipv6 addresses.
18
+ :param ip_only: bool, if True, returns only IP addresses, if False, returns tuples with all objects.
19
+ :return: list.
20
+ """
21
+ family: int = 0
22
+ if not family_type:
23
+ family = 0
24
+ elif family_type == "ipv4":
25
+ family = socket.AF_INET
26
+ elif family_type == "ipv6":
27
+ family = socket.AF_INET6
28
+
29
+ network_interfaces_tuples = list(socket.getaddrinfo(socket.gethostname(), None, family=family))
30
+
31
+ if not ip_only:
32
+ return network_interfaces_tuples
33
+ else:
34
+ return [i[4][0] for i in network_interfaces_tuples]
35
+
36
+
37
+ def get_destination_address_from_socket(socket_object):
38
+ """
39
+ Return destination IP and port.
40
+
41
+ :param socket_object:
42
+ :return:
43
+ """
44
+ # return ip_address, port
45
+ return socket_object.getsockname()[0], socket_object.getsockname()[1]
46
+
47
+
48
+ def get_source_address_from_socket(socket_object):
49
+ """
50
+ Return source IP and port.
51
+
52
+ :param socket_object:
53
+ :return:
54
+ """
55
+ # return ip_address, port
56
+ return socket_object.getpeername()[0], socket_object.getpeername()[1]
57
+
58
+
59
+ def get_source_destination(socket_object):
60
+ return get_source_address_from_socket(socket_object), get_destination_address_from_socket(socket_object)
61
+
62
+
63
+ def set_socket_timeout(socket_object, seconds: int = 1):
64
+ # Setting timeout on the socket before "accept()" drastically slows down connections.
65
+ socket_object.settimeout(seconds)
66
+
67
+
68
+ def get_default_ip_address() -> str:
69
+ """
70
+ Get the default IP address of the system (in other words the interface IPv4 that is used for internet connection).
71
+ :return: string.
72
+ """
73
+ return socket.gethostbyname(socket.gethostname())
74
+
75
+
76
+ def is_socket_closed(socket_object) -> bool:
77
+ """
78
+ Check if the socket is closed.
79
+ :param socket_object: socket object or ssl socket object.
80
+ :return: bool.
81
+ """
82
+ try:
83
+ # If the socket is closed, the fileno() method will raise an exception or return -1.
84
+
85
+ if socket_object.fileno() == -1:
86
+ return True
87
+ else:
88
+ return False
89
+ except socket.error:
90
+ return False
91
+
92
+
93
+ def get_host_name_from_ip_address(ip_address: str) -> str:
94
+ """
95
+ Get the host name from the IP address.
96
+ :param ip_address: string, IP address.
97
+ :return: string, host name.
98
+ """
99
+
100
+ host_name, alias_list, ipaddr_list = socket.gethostbyaddr(ip_address)
101
+ _ = alias_list, ipaddr_list
102
+
103
+ return host_name
104
+
105
+
106
+ def wait_for_ip_bindable(
107
+ ip: str,
108
+ port: int = 0,
109
+ timeout: float = 15.0,
110
+ interval: float = 0.5,
111
+ ) -> None:
112
+ """
113
+ Wait until a single IP is bindable (or timeout).
114
+
115
+ Raises TimeoutError if the IP cannot be bound within 'timeout' seconds.
116
+ """
117
+ deadline = time.time() + timeout
118
+ last_err: OSError | None = None
119
+
120
+ while time.time() < deadline:
121
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
122
+ try:
123
+ s.bind((ip, port))
124
+ s.close()
125
+ return # success
126
+ except OSError as e:
127
+ last_err = e
128
+ s.close()
129
+ time.sleep(interval)
130
+
131
+ raise TimeoutError(
132
+ f"IP {ip} not bindable within {timeout} seconds; "
133
+ f"last error: {last_err}"
134
+ )