atomicshop 2.11.47__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.
- atomicshop/__init__.py +1 -1
- atomicshop/{addons/mains → a_mains}/FACT/update_extract.py +3 -2
- atomicshop/a_mains/addons/process_list/compile.cmd +7 -0
- atomicshop/a_mains/addons/process_list/compiled/Win10x64/process_list.dll +0 -0
- atomicshop/a_mains/addons/process_list/compiled/Win10x64/process_list.exp +0 -0
- atomicshop/a_mains/addons/process_list/compiled/Win10x64/process_list.lib +0 -0
- atomicshop/{addons → a_mains/addons}/process_list/process_list.cpp +8 -1
- atomicshop/a_mains/dns_gateway_setting.py +11 -0
- atomicshop/a_mains/get_local_tcp_ports.py +85 -0
- atomicshop/a_mains/github_wrapper.py +11 -0
- atomicshop/a_mains/install_ca_certificate.py +172 -0
- atomicshop/{addons/mains → a_mains}/msi_unpacker.py +3 -1
- atomicshop/a_mains/process_from_port.py +119 -0
- atomicshop/a_mains/set_default_dns_gateway.py +90 -0
- atomicshop/a_mains/update_config_toml.py +38 -0
- atomicshop/appointment_management.py +5 -3
- atomicshop/basics/ansi_escape_codes.py +3 -1
- atomicshop/basics/argparse_template.py +2 -0
- atomicshop/basics/booleans.py +27 -30
- atomicshop/basics/bytes_arrays.py +43 -0
- atomicshop/basics/classes.py +149 -1
- atomicshop/basics/dicts.py +12 -0
- atomicshop/basics/enums.py +2 -2
- atomicshop/basics/exceptions.py +5 -1
- atomicshop/basics/list_of_classes.py +29 -0
- atomicshop/basics/list_of_dicts.py +69 -5
- atomicshop/basics/lists.py +14 -0
- atomicshop/basics/multiprocesses.py +374 -50
- atomicshop/basics/package_module.py +10 -0
- atomicshop/basics/strings.py +160 -7
- atomicshop/basics/threads.py +14 -0
- atomicshop/basics/tracebacks.py +13 -4
- atomicshop/certificates.py +153 -52
- atomicshop/config_init.py +12 -7
- atomicshop/console_user_response.py +7 -14
- atomicshop/consoles.py +9 -0
- atomicshop/datetimes.py +98 -0
- atomicshop/diff_check.py +340 -40
- atomicshop/dns.py +128 -12
- atomicshop/etws/_pywintrace_fix.py +17 -0
- atomicshop/etws/const.py +38 -0
- atomicshop/etws/providers.py +21 -0
- atomicshop/etws/sessions.py +43 -0
- atomicshop/etws/trace.py +168 -0
- atomicshop/etws/traces/trace_dns.py +162 -0
- atomicshop/etws/traces/trace_sysmon_process_creation.py +126 -0
- atomicshop/etws/traces/trace_tcp.py +130 -0
- atomicshop/file_io/csvs.py +222 -24
- atomicshop/file_io/docxs.py +35 -18
- atomicshop/file_io/file_io.py +35 -19
- atomicshop/file_io/jsons.py +49 -0
- atomicshop/file_io/tomls.py +139 -0
- atomicshop/filesystem.py +864 -293
- atomicshop/get_process_list.py +133 -0
- atomicshop/{process_name_cmd.py → get_process_name_cmd_dll.py} +52 -19
- atomicshop/http_parse.py +149 -93
- atomicshop/ip_addresses.py +6 -1
- atomicshop/mitm/centered_settings.py +132 -0
- atomicshop/mitm/config_static.py +207 -0
- atomicshop/mitm/config_toml_editor.py +55 -0
- atomicshop/mitm/connection_thread_worker.py +875 -357
- atomicshop/mitm/engines/__parent/parser___parent.py +4 -17
- atomicshop/mitm/engines/__parent/recorder___parent.py +108 -51
- atomicshop/mitm/engines/__parent/requester___parent.py +116 -0
- atomicshop/mitm/engines/__parent/responder___parent.py +75 -114
- atomicshop/mitm/engines/__reference_general/parser___reference_general.py +10 -7
- atomicshop/mitm/engines/__reference_general/recorder___reference_general.py +5 -5
- atomicshop/mitm/engines/__reference_general/requester___reference_general.py +47 -0
- atomicshop/mitm/engines/__reference_general/responder___reference_general.py +95 -13
- atomicshop/mitm/engines/create_module_template.py +58 -14
- atomicshop/mitm/import_config.py +359 -139
- atomicshop/mitm/initialize_engines.py +160 -74
- atomicshop/mitm/message.py +64 -23
- atomicshop/mitm/mitm_main.py +892 -0
- atomicshop/mitm/recs_files.py +183 -0
- atomicshop/mitm/shared_functions.py +4 -10
- atomicshop/mitm/ssh_tester.py +82 -0
- atomicshop/mitm/statistic_analyzer.py +257 -166
- atomicshop/mitm/statistic_analyzer_helper/analyzer_helper.py +136 -0
- atomicshop/mitm/statistic_analyzer_helper/moving_average_helper.py +525 -0
- atomicshop/monitor/change_monitor.py +96 -120
- atomicshop/monitor/checks/dns.py +139 -70
- atomicshop/monitor/checks/file.py +77 -0
- atomicshop/monitor/checks/network.py +81 -77
- atomicshop/monitor/checks/process_running.py +33 -34
- atomicshop/monitor/checks/url.py +94 -0
- atomicshop/networks.py +671 -0
- atomicshop/on_exit.py +205 -0
- atomicshop/package_mains_processor.py +84 -0
- atomicshop/permissions/permissions.py +22 -0
- atomicshop/permissions/ubuntu_permissions.py +239 -0
- atomicshop/permissions/win_permissions.py +33 -0
- atomicshop/print_api.py +24 -41
- atomicshop/process.py +63 -17
- atomicshop/process_poller/__init__.py +0 -0
- atomicshop/process_poller/pollers/__init__.py +0 -0
- atomicshop/process_poller/pollers/psutil_pywin32wmi_dll.py +95 -0
- atomicshop/process_poller/process_pool.py +207 -0
- atomicshop/process_poller/simple_process_pool.py +311 -0
- atomicshop/process_poller/tracer_base.py +45 -0
- atomicshop/process_poller/tracers/__init__.py +0 -0
- atomicshop/process_poller/tracers/event_log.py +46 -0
- atomicshop/process_poller/tracers/sysmon_etw.py +68 -0
- atomicshop/python_file_patcher.py +1 -1
- atomicshop/python_functions.py +27 -75
- atomicshop/question_answer_engine.py +2 -2
- atomicshop/scheduling.py +24 -5
- atomicshop/sound.py +4 -2
- atomicshop/speech_recognize.py +8 -0
- atomicshop/ssh_remote.py +158 -172
- atomicshop/startup/__init__.py +0 -0
- atomicshop/startup/win/__init__.py +0 -0
- atomicshop/startup/win/startup_folder.py +53 -0
- atomicshop/startup/win/task_scheduler.py +119 -0
- atomicshop/system_resource_monitor.py +61 -46
- atomicshop/system_resources.py +8 -8
- atomicshop/tempfiles.py +1 -2
- atomicshop/timer.py +30 -11
- atomicshop/urls.py +41 -0
- atomicshop/venvs.py +28 -0
- atomicshop/versioning.py +27 -0
- atomicshop/web.py +110 -25
- atomicshop/web_apis/__init__.py +0 -0
- atomicshop/web_apis/google_custom_search.py +44 -0
- atomicshop/web_apis/google_llm.py +188 -0
- atomicshop/websocket_parse.py +450 -0
- atomicshop/wrappers/certauthw/certauth.py +1 -0
- atomicshop/wrappers/cryptographyw.py +29 -8
- atomicshop/wrappers/ctyping/etw_winapi/__init__.py +0 -0
- atomicshop/wrappers/ctyping/etw_winapi/const.py +335 -0
- atomicshop/wrappers/ctyping/etw_winapi/etw_functions.py +393 -0
- atomicshop/wrappers/ctyping/file_details_winapi.py +67 -0
- atomicshop/wrappers/ctyping/msi_windows_installer/cabs.py +2 -1
- atomicshop/wrappers/ctyping/msi_windows_installer/extract_msi_main.py +13 -9
- atomicshop/wrappers/ctyping/msi_windows_installer/tables.py +35 -0
- atomicshop/wrappers/ctyping/setup_device.py +466 -0
- atomicshop/wrappers/ctyping/win_console.py +39 -0
- atomicshop/wrappers/dockerw/dockerw.py +113 -2
- atomicshop/wrappers/elasticsearchw/config_basic.py +0 -12
- atomicshop/wrappers/elasticsearchw/elastic_infra.py +75 -0
- atomicshop/wrappers/elasticsearchw/elasticsearchw.py +2 -20
- atomicshop/wrappers/factw/get_file_data.py +12 -5
- atomicshop/wrappers/factw/install/install_after_restart.py +89 -5
- atomicshop/wrappers/factw/install/pre_install_and_install_before_restart.py +20 -14
- atomicshop/wrappers/factw/postgresql/firmware.py +4 -6
- atomicshop/wrappers/githubw.py +583 -51
- atomicshop/wrappers/loggingw/consts.py +49 -0
- atomicshop/wrappers/loggingw/filters.py +102 -0
- atomicshop/wrappers/loggingw/formatters.py +58 -71
- atomicshop/wrappers/loggingw/handlers.py +459 -40
- atomicshop/wrappers/loggingw/loggers.py +19 -0
- atomicshop/wrappers/loggingw/loggingw.py +1010 -178
- atomicshop/wrappers/loggingw/reading.py +344 -19
- atomicshop/wrappers/mongodbw/__init__.py +0 -0
- atomicshop/wrappers/mongodbw/mongo_infra.py +31 -0
- atomicshop/wrappers/mongodbw/mongodbw.py +1432 -0
- atomicshop/wrappers/netshw.py +271 -0
- atomicshop/wrappers/playwrightw/engine.py +34 -19
- atomicshop/wrappers/playwrightw/infra.py +5 -0
- atomicshop/wrappers/playwrightw/javascript.py +7 -3
- atomicshop/wrappers/playwrightw/keyboard.py +14 -0
- atomicshop/wrappers/playwrightw/scenarios.py +172 -5
- atomicshop/wrappers/playwrightw/waits.py +9 -7
- atomicshop/wrappers/powershell_networking.py +80 -0
- atomicshop/wrappers/psutilw/processes.py +81 -0
- atomicshop/wrappers/psutilw/psutil_networks.py +85 -0
- atomicshop/wrappers/psutilw/psutilw.py +9 -0
- atomicshop/wrappers/pyopensslw.py +9 -2
- atomicshop/wrappers/pywin32w/__init__.py +0 -0
- atomicshop/wrappers/pywin32w/cert_store.py +116 -0
- atomicshop/wrappers/pywin32w/console.py +34 -0
- atomicshop/wrappers/pywin32w/win_event_log/__init__.py +0 -0
- atomicshop/wrappers/pywin32w/win_event_log/fetch.py +174 -0
- atomicshop/wrappers/pywin32w/win_event_log/subscribe.py +212 -0
- atomicshop/wrappers/pywin32w/win_event_log/subscribes/__init__.py +0 -0
- atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_create.py +57 -0
- atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_terminate.py +49 -0
- atomicshop/wrappers/pywin32w/win_event_log/subscribes/schannel_logging.py +97 -0
- atomicshop/wrappers/pywin32w/winshell.py +19 -0
- atomicshop/wrappers/pywin32w/wmis/__init__.py +0 -0
- atomicshop/wrappers/pywin32w/wmis/msft_netipaddress.py +113 -0
- atomicshop/wrappers/pywin32w/wmis/win32_networkadapterconfiguration.py +259 -0
- atomicshop/wrappers/pywin32w/wmis/win32networkadapter.py +112 -0
- atomicshop/wrappers/pywin32w/wmis/wmi_helpers.py +236 -0
- atomicshop/wrappers/socketw/accepter.py +21 -7
- atomicshop/wrappers/socketw/certificator.py +216 -150
- atomicshop/wrappers/socketw/creator.py +190 -50
- atomicshop/wrappers/socketw/dns_server.py +500 -173
- atomicshop/wrappers/socketw/exception_wrapper.py +45 -52
- atomicshop/wrappers/socketw/process_getter.py +86 -0
- atomicshop/wrappers/socketw/receiver.py +144 -102
- atomicshop/wrappers/socketw/sender.py +65 -35
- atomicshop/wrappers/socketw/sni.py +334 -165
- atomicshop/wrappers/socketw/socket_base.py +134 -0
- atomicshop/wrappers/socketw/socket_client.py +137 -95
- atomicshop/wrappers/socketw/socket_server_tester.py +14 -9
- atomicshop/wrappers/socketw/socket_wrapper.py +717 -116
- atomicshop/wrappers/socketw/ssl_base.py +15 -14
- atomicshop/wrappers/socketw/statistics_csv.py +148 -17
- atomicshop/wrappers/sysmonw.py +157 -0
- atomicshop/wrappers/ubuntu_terminal.py +65 -26
- atomicshop/wrappers/win_auditw.py +189 -0
- atomicshop/wrappers/winregw/__init__.py +0 -0
- atomicshop/wrappers/winregw/winreg_installed_software.py +58 -0
- atomicshop/wrappers/winregw/winreg_network.py +232 -0
- {atomicshop-2.11.47.dist-info → atomicshop-3.10.5.dist-info}/METADATA +31 -49
- atomicshop-3.10.5.dist-info/RECORD +306 -0
- {atomicshop-2.11.47.dist-info → atomicshop-3.10.5.dist-info}/WHEEL +1 -1
- atomicshop/_basics_temp.py +0 -101
- atomicshop/addons/a_setup_scripts/install_psycopg2_ubuntu.sh +0 -3
- atomicshop/addons/a_setup_scripts/install_pywintrace_0.3.cmd +0 -2
- atomicshop/addons/mains/install_docker_rootless_ubuntu.py +0 -11
- atomicshop/addons/mains/install_docker_ubuntu_main_sudo.py +0 -11
- atomicshop/addons/mains/install_elastic_search_and_kibana_ubuntu.py +0 -10
- atomicshop/addons/mains/install_wsl_ubuntu_lts_admin.py +0 -9
- atomicshop/addons/package_setup/CreateWheel.cmd +0 -7
- atomicshop/addons/package_setup/Setup in Edit mode.cmd +0 -6
- atomicshop/addons/package_setup/Setup.cmd +0 -7
- atomicshop/addons/process_list/compile.cmd +0 -2
- atomicshop/addons/process_list/compiled/Win10x64/process_list.dll +0 -0
- atomicshop/addons/process_list/compiled/Win10x64/process_list.exp +0 -0
- atomicshop/addons/process_list/compiled/Win10x64/process_list.lib +0 -0
- atomicshop/archiver/_search_in_zip.py +0 -189
- atomicshop/archiver/archiver.py +0 -34
- atomicshop/archiver/search_in_archive.py +0 -250
- atomicshop/archiver/sevenz_app_w.py +0 -86
- atomicshop/archiver/sevenzs.py +0 -44
- atomicshop/archiver/zips.py +0 -293
- atomicshop/etw/dns_trace.py +0 -118
- atomicshop/etw/etw.py +0 -61
- atomicshop/file_types.py +0 -24
- atomicshop/mitm/engines/create_module_template_example.py +0 -13
- atomicshop/mitm/initialize_mitm_server.py +0 -240
- atomicshop/monitor/checks/hash.py +0 -44
- atomicshop/monitor/checks/hash_checks/file.py +0 -55
- atomicshop/monitor/checks/hash_checks/url.py +0 -62
- atomicshop/pbtkmultifile_argparse.py +0 -88
- atomicshop/permissions.py +0 -110
- atomicshop/process_poller.py +0 -237
- atomicshop/script_as_string_processor.py +0 -38
- atomicshop/ssh_scripts/process_from_ipv4.py +0 -37
- atomicshop/ssh_scripts/process_from_port.py +0 -27
- atomicshop/wrappers/_process_wrapper_curl.py +0 -27
- atomicshop/wrappers/_process_wrapper_tar.py +0 -21
- atomicshop/wrappers/dockerw/install_docker.py +0 -209
- atomicshop/wrappers/elasticsearchw/infrastructure.py +0 -265
- atomicshop/wrappers/elasticsearchw/install_elastic.py +0 -232
- atomicshop/wrappers/ffmpegw.py +0 -125
- atomicshop/wrappers/loggingw/checks.py +0 -20
- atomicshop/wrappers/nodejsw/install_nodejs.py +0 -139
- atomicshop/wrappers/process_wrapper_pbtk.py +0 -16
- atomicshop/wrappers/socketw/base.py +0 -59
- atomicshop/wrappers/socketw/get_process.py +0 -107
- atomicshop/wrappers/wslw.py +0 -191
- atomicshop-2.11.47.dist-info/RECORD +0 -251
- /atomicshop/{addons/mains → a_mains}/FACT/factw_fact_extractor_docker_image_main_sudo.py +0 -0
- /atomicshop/{addons → a_mains/addons}/PlayWrightCodegen.cmd +0 -0
- /atomicshop/{addons → a_mains/addons}/ScriptExecution.cmd +0 -0
- /atomicshop/{addons/mains → a_mains/addons}/inits/init_to_import_all_modules.py +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/ReadMe.txt +0 -0
- /atomicshop/{addons/mains → a_mains}/search_for_hyperlinks_in_docx.py +0 -0
- /atomicshop/{archiver → etws}/__init__.py +0 -0
- /atomicshop/{etw → etws/traces}/__init__.py +0 -0
- /atomicshop/{monitor/checks/hash_checks → mitm/statistic_analyzer_helper}/__init__.py +0 -0
- /atomicshop/{wrappers/nodejsw → permissions}/__init__.py +0 -0
- /atomicshop/wrappers/pywin32w/{wmi_win32process.py → wmis/win32process.py} +0 -0
- {atomicshop-2.11.47.dist-info → atomicshop-3.10.5.dist-info/licenses}/LICENSE.txt +0 -0
- {atomicshop-2.11.47.dist-info → atomicshop-3.10.5.dist-info}/top_level.txt +0 -0
|
@@ -3,47 +3,251 @@ import datetime
|
|
|
3
3
|
import time
|
|
4
4
|
import threading
|
|
5
5
|
import socket
|
|
6
|
+
import logging
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Literal, Optional
|
|
9
|
+
import multiprocessing
|
|
6
10
|
|
|
7
11
|
from ...print_api import print_api
|
|
8
12
|
from ..loggingw import loggingw
|
|
13
|
+
from ..psutilw import psutil_networks
|
|
14
|
+
from ...basics import booleans, tracebacks
|
|
15
|
+
from ...file_io import csvs
|
|
16
|
+
from ... import networks
|
|
9
17
|
|
|
18
|
+
# noinspection PyPackageRequirements
|
|
10
19
|
import dnslib
|
|
20
|
+
# noinspection PyPackageRequirements
|
|
11
21
|
from dnslib import DNSRecord, DNSHeader, RR, A
|
|
12
22
|
|
|
13
23
|
|
|
24
|
+
class DnsPortInUseError(Exception):
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class DnsConfigurationValuesError(Exception):
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
LOGGER_NAME: str = 'dns_traffic'
|
|
33
|
+
DNS_STATISTICS_HEADER: str = (
|
|
34
|
+
'timestamp,dns_type,client_ipv4,client_port,qname,qtype,qclass,header,error')
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class DnsStatisticsCSVWriter:
|
|
38
|
+
"""
|
|
39
|
+
Class to write statistics to CSV file.
|
|
40
|
+
This can be initiated at the main, and then passed to the thread worker function.
|
|
41
|
+
"""
|
|
42
|
+
def __init__(
|
|
43
|
+
self,
|
|
44
|
+
statistics_directory_path: str
|
|
45
|
+
):
|
|
46
|
+
self.csv_logger = loggingw.create_logger(
|
|
47
|
+
logger_name=LOGGER_NAME,
|
|
48
|
+
directory_path=statistics_directory_path,
|
|
49
|
+
add_timedfile_with_internal_queue=True,
|
|
50
|
+
formatter_filehandler='MESSAGE',
|
|
51
|
+
file_type='csv',
|
|
52
|
+
header=DNS_STATISTICS_HEADER
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
def write_row(
|
|
56
|
+
self,
|
|
57
|
+
client_address: tuple,
|
|
58
|
+
timestamp=None,
|
|
59
|
+
dns_type: Literal['request', 'response'] = None,
|
|
60
|
+
dns_request = None,
|
|
61
|
+
dns_response = None,
|
|
62
|
+
error: str = None,
|
|
63
|
+
):
|
|
64
|
+
if not timestamp:
|
|
65
|
+
timestamp = datetime.datetime.now()
|
|
66
|
+
|
|
67
|
+
if not dns_type:
|
|
68
|
+
if not dns_request and not dns_response:
|
|
69
|
+
raise ValueError("Either DNS Request or DNS Response must be provided.")
|
|
70
|
+
elif dns_request and dns_response:
|
|
71
|
+
raise ValueError("Either DNS Request or DNS Response must be provided. Not both.")
|
|
72
|
+
|
|
73
|
+
if dns_request:
|
|
74
|
+
dns_type = 'request'
|
|
75
|
+
elif dns_response:
|
|
76
|
+
dns_type = 'response'
|
|
77
|
+
|
|
78
|
+
if dns_type not in ['request', 'response']:
|
|
79
|
+
raise ValueError(f"DNS Type can be only 'request' or 'response'. Provided: {dns_type}")
|
|
80
|
+
|
|
81
|
+
client_ipv4, client_port = client_address
|
|
82
|
+
client_ipv4: str
|
|
83
|
+
client_port: str = str(client_port)
|
|
84
|
+
|
|
85
|
+
qname: str = str()
|
|
86
|
+
qtype: str = str()
|
|
87
|
+
qclass: str = str()
|
|
88
|
+
rr: str = str()
|
|
89
|
+
header: str = str()
|
|
90
|
+
|
|
91
|
+
if dns_request:
|
|
92
|
+
qname = str(dns_request.q.qname)[:-1]
|
|
93
|
+
qtype = dnslib.QTYPE[dns_request.q.qtype]
|
|
94
|
+
qclass = dnslib.CLASS[dns_request.q.qclass]
|
|
95
|
+
|
|
96
|
+
if dns_response:
|
|
97
|
+
qname = str(dns_response.q.qname)[:-1]
|
|
98
|
+
qtype = dnslib.QTYPE[dns_response.q.qtype]
|
|
99
|
+
qclass = dnslib.CLASS[dns_response.q.qclass]
|
|
100
|
+
rr: str = str(dns_response.rr)
|
|
101
|
+
header = str(dns_response.header)
|
|
102
|
+
|
|
103
|
+
escaped_line_string: str = csvs.escape_csv_line_to_string([
|
|
104
|
+
timestamp,
|
|
105
|
+
dns_type,
|
|
106
|
+
client_ipv4,
|
|
107
|
+
client_port,
|
|
108
|
+
qname,
|
|
109
|
+
qtype,
|
|
110
|
+
qclass,
|
|
111
|
+
rr,
|
|
112
|
+
header,
|
|
113
|
+
error
|
|
114
|
+
])
|
|
115
|
+
|
|
116
|
+
self.csv_logger.info(escaped_line_string)
|
|
117
|
+
|
|
118
|
+
def write_error(
|
|
119
|
+
self,
|
|
120
|
+
dns_type: Literal['request', 'response'],
|
|
121
|
+
error_message: str,
|
|
122
|
+
client_address: tuple
|
|
123
|
+
):
|
|
124
|
+
"""
|
|
125
|
+
Write the error message to the statistics CSV file.
|
|
126
|
+
This is used for easier execution, since most of the parameters will be empty on accept.
|
|
127
|
+
|
|
128
|
+
:param dns_type: Literal['request', 'response'], DNS request or response.
|
|
129
|
+
:param error_message: string, error message.
|
|
130
|
+
:param client_address: tuple, client address (IPv4, Port).
|
|
131
|
+
:return:
|
|
132
|
+
"""
|
|
133
|
+
|
|
134
|
+
self.write_row(
|
|
135
|
+
dns_type=dns_type,
|
|
136
|
+
client_address=client_address,
|
|
137
|
+
error=error_message
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
|
|
14
141
|
class DnsServer:
|
|
15
142
|
"""
|
|
16
143
|
DnsServer class is responsible to handle DNS Requests on port 53 based on configuration and send DNS Response back.
|
|
17
144
|
"""
|
|
18
|
-
|
|
145
|
+
# noinspection PyPep8Naming
|
|
146
|
+
def __init__(
|
|
147
|
+
self,
|
|
148
|
+
listening_address: str,
|
|
149
|
+
log_directory_path: str,
|
|
150
|
+
backupCount_log_files_x_days: int = 0,
|
|
151
|
+
forwarding_dns_service_ipv4: str = '8.8.8.8',
|
|
152
|
+
forwarding_dns_service_port: int = 53,
|
|
153
|
+
resolve_by_engine: tuple[bool, list] = (False, None),
|
|
154
|
+
resolve_regular_pass_thru: bool = False,
|
|
155
|
+
resolve_all_domains_to_ipv4: tuple[bool, str] = (False, '127.0.0.1'),
|
|
156
|
+
offline_mode: bool = False,
|
|
157
|
+
buffer_size_receive: int = 8192,
|
|
158
|
+
response_ttl: int = 60,
|
|
159
|
+
dns_service_retries: int = 5,
|
|
160
|
+
cache_timeout_minutes: int = 60,
|
|
161
|
+
logger: logging.Logger = None,
|
|
162
|
+
logging_queue: multiprocessing.Queue = None,
|
|
163
|
+
logger_name: str = None
|
|
164
|
+
):
|
|
165
|
+
"""
|
|
166
|
+
Initialize the DNS Server object with all the necessary settings.
|
|
167
|
+
|
|
168
|
+
:param listening_address: str: Interface and a port that the DNS Server will listen on.
|
|
169
|
+
Example: '0.0.0.0:53'. For all interfaces on port 53.
|
|
170
|
+
:param log_directory_path: str: Path to the directory where the logs will be saved.
|
|
171
|
+
:param backupCount_log_files_x_days: int: How many days the log files will be kept.
|
|
172
|
+
Default is 0, which means that the log files will be kept indefinitely.
|
|
173
|
+
More than 0 means that the log files will be deleted after the specified days.
|
|
174
|
+
:param forwarding_dns_service_ipv4: str: IPv4 address of the DNS Service that will be used for resolving.
|
|
175
|
+
Example: '8.8.8.8'. For Google DNS Service.
|
|
176
|
+
:param forwarding_dns_service_port: int: Port number of the DNS Service that will be used for resolving.
|
|
177
|
+
Default is 53.
|
|
178
|
+
:param resolve_by_engine: tuple(boolean to enable the feature, list of engines).
|
|
179
|
+
True, The list of predefined engines will be used to resolve the domains.
|
|
180
|
+
Each list has a list of specific domains that will be routed to specified destination IPv4 address.
|
|
181
|
+
:param resolve_all_domains_to_ipv4: bool: If the DNS Server should resolve all the domains
|
|
182
|
+
to the provided origin DNS Service without altering the DNS request/response.
|
|
183
|
+
:param resolve_all_domains_to_ipv4: tuple(boolean to enable the feature, string IPv4 of the target).
|
|
184
|
+
True, the DNS Server will route all domains to the specified IPv4.
|
|
185
|
+
:param offline_mode: bool: If the DNS Server should work in offline mode.
|
|
186
|
+
:param buffer_size_receive: int: Buffer size of the connection while receiving messages.
|
|
187
|
+
:param response_ttl: int, Time to live of the DNS Response that will be returned. Default is 60 seconds.
|
|
188
|
+
:param dns_service_retries: int, How many times the request will be sent to forwarded DNS Service on errors:
|
|
189
|
+
(socket connect / request send / response receive).
|
|
190
|
+
:param cache_timeout_minutes: int: Timeout in minutes to clear the DNS Cache.
|
|
191
|
+
server. Each domain will be pass in the queue as a string.
|
|
192
|
+
|
|
193
|
+
:param logger: logging.Logger: Logger object to use for logging. If not provided, a new logger will be created.
|
|
194
|
+
:param logging_queue: multiprocessing.Queue: Queue to pass the logs to the QueueListener.
|
|
195
|
+
You will use this in case you run the DNS Server in a separate process.
|
|
196
|
+
Of course, you need to have a QueueListener to listen to this queue.
|
|
197
|
+
|
|
198
|
+
You can pass only one of the following: 'logger', 'logging_queue'.
|
|
199
|
+
"""
|
|
200
|
+
|
|
201
|
+
self.listening_address: str = listening_address
|
|
202
|
+
self.log_directory_path: str = log_directory_path
|
|
203
|
+
self.backupCount_log_files_x_days: int = backupCount_log_files_x_days
|
|
204
|
+
self.forwarding_dns_service_ipv4: str = forwarding_dns_service_ipv4
|
|
205
|
+
self.forwarding_dns_service_port: int = forwarding_dns_service_port
|
|
206
|
+
self.resolve_by_engine: tuple[bool, list] = resolve_by_engine
|
|
207
|
+
self.resolve_regular_pass_thru: bool = resolve_regular_pass_thru
|
|
208
|
+
self.resolve_all_domains_to_ipv4: tuple[bool, str] = resolve_all_domains_to_ipv4
|
|
209
|
+
self.offline_mode: bool = offline_mode
|
|
210
|
+
self.buffer_size_receive: int = buffer_size_receive
|
|
211
|
+
self.response_ttl: int = response_ttl
|
|
212
|
+
self.dns_service_retries: int = dns_service_retries
|
|
213
|
+
self.cache_timeout_minutes: int = cache_timeout_minutes
|
|
214
|
+
self.logging_queue: multiprocessing.Queue = logging_queue
|
|
215
|
+
self.logging_name: str = logger_name
|
|
216
|
+
|
|
217
|
+
if logger and logging_queue:
|
|
218
|
+
raise ValueError("You can pass only one of the following: 'logger', 'logging_queue'.")
|
|
219
|
+
|
|
220
|
+
self.listening_interface, listening_port = self.listening_address.split(':')
|
|
221
|
+
self.listening_interface: str
|
|
222
|
+
self.listening_port: int = int(listening_port)
|
|
223
|
+
self.resolve_by_engine_enable, self.engine_list = self.resolve_by_engine
|
|
224
|
+
self.resolve_by_engine_enable: bool
|
|
225
|
+
self.engine_list: list
|
|
226
|
+
self.resolve_all_domains_to_ipv4_enable, self.resolve_all_domains_target = self.resolve_all_domains_to_ipv4
|
|
227
|
+
self.resolve_all_domains_to_ipv4_enable: bool
|
|
228
|
+
self.resolve_all_domains_target: str
|
|
229
|
+
|
|
230
|
+
self.intercept_domain_dict: dict = dict()
|
|
231
|
+
for engine in self.engine_list:
|
|
232
|
+
# If the engine is not a reference engine.
|
|
233
|
+
if engine.engine_name != '__reference_general':
|
|
234
|
+
# Get the domains from the engine.
|
|
235
|
+
|
|
236
|
+
self.intercept_domain_dict.update(engine.domain_target_dict)
|
|
19
237
|
|
|
20
|
-
def __init__(self, config):
|
|
21
238
|
# Settings for static DNS Responses in offline mode.
|
|
22
|
-
self.offline_route_ipv4 = '10.10.10.10'
|
|
23
|
-
self.offline_route_ipv6 = 'fe80::3c09:df29:d52b:af39'
|
|
24
|
-
self.offline_route_domain = 'domain.com'
|
|
25
|
-
self.offline_srv_answer = \
|
|
239
|
+
self.offline_route_ipv4: str = '10.10.10.10'
|
|
240
|
+
self.offline_route_ipv6: str = 'fe80::3c09:df29:d52b:af39'
|
|
241
|
+
self.offline_route_domain: str = 'domain.com'
|
|
242
|
+
self.offline_srv_answer: str = \
|
|
26
243
|
'. 86391 IN SOA domain.com. domain.com. 2022012500 1800 900 604800 86400'
|
|
244
|
+
# self.offline_https_answer: str = str()
|
|
27
245
|
|
|
28
|
-
# Other settings.
|
|
29
|
-
# Full domain list to pass to TCP Server module.
|
|
30
|
-
self.domain_list: list = list()
|
|
31
|
-
|
|
32
|
-
# Set Buffer size of the connection while receiving messages. The function uses this variable right away.
|
|
33
|
-
self.buffer_size_receive: int = 8192
|
|
34
|
-
# TTL variable that is going to be returned in DNS response.
|
|
35
|
-
self.response_ttl: int = 60
|
|
36
|
-
# How many times the DNS Service will retry on errors (socket connect / request send / response receive)
|
|
37
|
-
self.dns_service_retries: int = 5
|
|
38
246
|
# If forwarding to Live DNS Service fails. Currently, we didn't send anything, so it's 'False'.
|
|
39
247
|
self.retried: bool = False
|
|
40
248
|
# Defining cache dictionary for assigning DNS Questions to DNS Answers
|
|
41
249
|
self.dns_questions_to_answers_cache: dict = dict()
|
|
42
250
|
|
|
43
|
-
# Queue for all the requested domains that hit the dns server.
|
|
44
|
-
# self.request_domain_queue: queue.Queue = queue.Queue()
|
|
45
|
-
self.request_domain_queue = None
|
|
46
|
-
|
|
47
251
|
# Filename to save all the known domains and their relative IPv4 addresses.
|
|
48
252
|
self.known_domains_filename: str = 'dns_known_domains.txt'
|
|
49
253
|
# Filename to save all the known IPv4 addresses and their relative domains.
|
|
@@ -51,13 +255,77 @@ class DnsServer:
|
|
|
51
255
|
# Filename to save domains and their IPv4 addresses by time they hit the DNS server.
|
|
52
256
|
self.known_dns_ipv4_by_time_filename: str = 'dns_ipv4_by_time.txt'
|
|
53
257
|
|
|
54
|
-
# Configuration object with all the settings.
|
|
55
|
-
self.config = config
|
|
56
|
-
|
|
57
258
|
# Logger that logs all the DNS Requests and responses in DNS format. These entries will not present in
|
|
58
259
|
# network log of TCP Server module.
|
|
59
|
-
self.
|
|
60
|
-
|
|
260
|
+
self.dns_statistics_csv_writer = DnsStatisticsCSVWriter(statistics_directory_path=log_directory_path)
|
|
261
|
+
|
|
262
|
+
if not logger_name and not logger and not logging_queue:
|
|
263
|
+
self.logger_name = Path(__file__).stem
|
|
264
|
+
elif logger_name and (logger or logging_queue):
|
|
265
|
+
self.logger_name = f'{logger_name}.{Path(__file__).stem}'
|
|
266
|
+
|
|
267
|
+
# Check if the logger was provided, if not, create a new logger.
|
|
268
|
+
if not logger and not logging_queue:
|
|
269
|
+
self.logger: logging.Logger = loggingw.create_logger(
|
|
270
|
+
logger_name=Path(__file__).stem,
|
|
271
|
+
directory_path=self.log_directory_path,
|
|
272
|
+
add_stream=True,
|
|
273
|
+
add_timedfile_with_internal_queue=True,
|
|
274
|
+
formatter_streamhandler='DEFAULT',
|
|
275
|
+
formatter_filehandler='DEFAULT',
|
|
276
|
+
backupCount=self.backupCount_log_files_x_days
|
|
277
|
+
)
|
|
278
|
+
elif logger:
|
|
279
|
+
# Create child logger for the provided logger with the module's name.
|
|
280
|
+
self.logger: logging.Logger = loggingw.get_logger_with_level(self.logger_name)
|
|
281
|
+
elif logging_queue:
|
|
282
|
+
self.logger: logging.Logger = loggingw.create_logger(
|
|
283
|
+
logger_name=self.logger_name,
|
|
284
|
+
add_queue_handler=True,
|
|
285
|
+
log_queue=self.logging_queue
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
self.test_config()
|
|
289
|
+
|
|
290
|
+
def test_config(self):
|
|
291
|
+
try:
|
|
292
|
+
booleans.is_only_1_true_in_list(
|
|
293
|
+
booleans_list_of_tuples=[
|
|
294
|
+
(self.resolve_by_engine_enable, 'resolve_by_engine_enable'),
|
|
295
|
+
(self.resolve_regular_pass_thru, 'resolve_regular_pass_thru'),
|
|
296
|
+
(self.resolve_all_domains_to_ipv4_enable, 'resolve_all_domains_to_ipv4_enable')
|
|
297
|
+
],
|
|
298
|
+
raise_if_all_false=True
|
|
299
|
+
)
|
|
300
|
+
except ValueError as e:
|
|
301
|
+
print_api(f'DnsConfigurationValuesError: {str(e)}', error_type=True, color="red", logger=self.logger)
|
|
302
|
+
# Wait for the message to be printed and saved to file.
|
|
303
|
+
time.sleep(1)
|
|
304
|
+
raise DnsConfigurationValuesError(e)
|
|
305
|
+
|
|
306
|
+
# If the listening interface is not localhost, check if the interface can be bound to.
|
|
307
|
+
if not self.listening_interface.startswith('127.'):
|
|
308
|
+
host_ips: list[str] = networks.get_host_ips_psutil(ipv6=False)
|
|
309
|
+
if self.listening_interface not in host_ips:
|
|
310
|
+
message = (f"Listening interface [{self.listening_interface}] is not assigned to any of the host "
|
|
311
|
+
f"network interfaces. Current host IPv4 addresses: {host_ips}")
|
|
312
|
+
print_api(f'DnsConfigurationValuesError: {str(message)}', error_type=True, color="red", logger=self.logger)
|
|
313
|
+
# Wait for the message to be printed and saved to file.
|
|
314
|
+
time.sleep(1)
|
|
315
|
+
raise DnsConfigurationValuesError(message)
|
|
316
|
+
|
|
317
|
+
ips_ports: list[str] = [f'{self.listening_interface}:{self.listening_port}']
|
|
318
|
+
port_in_use = psutil_networks.get_processes_using_port_list(ips_ports)
|
|
319
|
+
if port_in_use:
|
|
320
|
+
error_messages: list = list()
|
|
321
|
+
for port, process_info in port_in_use.items():
|
|
322
|
+
error_messages.append(f"Port [{port}] is already in use by process: {process_info}")
|
|
323
|
+
|
|
324
|
+
message = "\n".join(error_messages)
|
|
325
|
+
print_api(f'DnsPortInUseError: {str(message)}', error_type=True, color="red", logger=self.logger)
|
|
326
|
+
# Wait for the message to be printed and saved to file.
|
|
327
|
+
time.sleep(1)
|
|
328
|
+
raise DnsPortInUseError(message)
|
|
61
329
|
|
|
62
330
|
def thread_worker_empty_dns_cache(self, function_sleep_time: int):
|
|
63
331
|
"""
|
|
@@ -71,10 +339,15 @@ class DnsServer:
|
|
|
71
339
|
self.dns_questions_to_answers_cache = dict()
|
|
72
340
|
self.logger.info("*** DNS cache cleared")
|
|
73
341
|
|
|
74
|
-
def start(
|
|
342
|
+
def start(
|
|
343
|
+
self,
|
|
344
|
+
is_ready_multiprocessing: multiprocessing.Event = None
|
|
345
|
+
):
|
|
75
346
|
"""
|
|
76
347
|
Main DNS Server function to start it.
|
|
77
348
|
|
|
349
|
+
:param is_ready_multiprocessing: multiprocessing.Event: Event to signal that the DNS Server is ready.
|
|
350
|
+
|
|
78
351
|
:return: None.
|
|
79
352
|
"""
|
|
80
353
|
|
|
@@ -90,31 +363,32 @@ class DnsServer:
|
|
|
90
363
|
known_a_records_ipv4_dict: dict = dict()
|
|
91
364
|
|
|
92
365
|
# Check if 'route_to_tcp_server_only_engine_domains' was set to 'True' and output message accordingly.
|
|
93
|
-
if self.
|
|
94
|
-
message = "Routing
|
|
366
|
+
if self.resolve_by_engine_enable:
|
|
367
|
+
message = "Routing engine domains to the specified IPv4 targets."
|
|
95
368
|
print_api(message, logger=self.logger)
|
|
96
369
|
|
|
97
|
-
message = f"Current
|
|
98
|
-
print_api(message, logger=self.logger, color='
|
|
370
|
+
message = f"Current all engines domains: {list(self.intercept_domain_dict.keys())}"
|
|
371
|
+
print_api(message, logger=self.logger, color='blue')
|
|
99
372
|
|
|
100
|
-
if self.
|
|
101
|
-
message = "Routing all domains to
|
|
102
|
-
print_api(message, logger=self.logger, color='
|
|
373
|
+
if self.resolve_all_domains_to_ipv4_enable:
|
|
374
|
+
message = f"Routing all domains to the specified target: [{self.resolve_all_domains_target}]"
|
|
375
|
+
print_api(message, logger=self.logger, color='blue')
|
|
103
376
|
|
|
104
|
-
if self.
|
|
105
|
-
message = f"Routing all domains to
|
|
106
|
-
print_api(message, logger=self.logger, color='
|
|
377
|
+
if self.resolve_regular_pass_thru:
|
|
378
|
+
message = f"Routing all domains to the specified Origin DNS Service: {self.forwarding_dns_service_ipv4}:{self.forwarding_dns_service_port}"
|
|
379
|
+
print_api(message, logger=self.logger, color='blue')
|
|
107
380
|
|
|
108
381
|
# The list that will hold all the threads that can be joined later
|
|
109
382
|
threads_list: list = list()
|
|
110
383
|
|
|
111
384
|
# Starting a thread that will empty the DNS Cache lists
|
|
112
385
|
thread_current = threading.Thread(target=self.thread_worker_empty_dns_cache,
|
|
113
|
-
args=(self.
|
|
114
|
-
|
|
115
|
-
threads_list.append(thread_current)
|
|
386
|
+
args=(self.cache_timeout_minutes,))
|
|
387
|
+
thread_current.daemon = True
|
|
116
388
|
# Start the thread
|
|
117
389
|
thread_current.start()
|
|
390
|
+
# Append to list of threads, so they can be "joined" later
|
|
391
|
+
threads_list.append(thread_current)
|
|
118
392
|
|
|
119
393
|
# To handle DNS requests UDP socket is needed.
|
|
120
394
|
# AF_INET - Socket family of IPv4
|
|
@@ -124,9 +398,15 @@ class DnsServer:
|
|
|
124
398
|
|
|
125
399
|
# Binding / assigning the port to the server / this script, that is going to be used for
|
|
126
400
|
# receiving connections.
|
|
127
|
-
main_socket_object.bind((self.
|
|
401
|
+
main_socket_object.bind((self.listening_interface, self.listening_port))
|
|
402
|
+
|
|
403
|
+
if is_ready_multiprocessing:
|
|
404
|
+
# If the DNS Server is running in a separate process, signal that the DNS Server is ready.
|
|
405
|
+
is_ready_multiprocessing.set()
|
|
128
406
|
|
|
129
407
|
while True:
|
|
408
|
+
forward_to_tcp_server = False # reset every request
|
|
409
|
+
|
|
130
410
|
# Needed this logging line when DNS was separate process.
|
|
131
411
|
# self.logger.info("Waiting to receive new requests...")
|
|
132
412
|
|
|
@@ -135,24 +415,30 @@ class DnsServer:
|
|
|
135
415
|
client_data: bytes
|
|
136
416
|
client_address: tuple
|
|
137
417
|
except ConnectionResetError:
|
|
418
|
+
client_address = (str(), int())
|
|
419
|
+
traceback_string = tracebacks.get_as_string(one_line=True)
|
|
138
420
|
# This error happens when the client closes the connection before the server.
|
|
139
421
|
# This is not an error for a DNS Server, but we'll log it anyway only with the full DNS logger.
|
|
140
|
-
message = "Error: to receive DNS request, An existing connection was forcibly closed"
|
|
141
|
-
|
|
142
|
-
print_api(
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
self.dns_full_logger.info("==========")
|
|
146
|
-
pass
|
|
422
|
+
message = (f"Error: to receive DNS request, An existing connection was forcibly closed | "
|
|
423
|
+
f"{traceback_string}")
|
|
424
|
+
# print_api(message, logger=self.logger, logger_method='critical', traceback_string=True)
|
|
425
|
+
self.dns_statistics_csv_writer.write_error(
|
|
426
|
+
dns_type='request', client_address=client_address, error_message=message)
|
|
147
427
|
continue
|
|
148
|
-
except
|
|
149
|
-
message = "
|
|
150
|
-
print_api(
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
428
|
+
except KeyboardInterrupt:
|
|
429
|
+
# message = "KeyboardInterrupt: Stopping DNS Server..."
|
|
430
|
+
# print_api(message, logger=self.logger, logger_method='info')
|
|
431
|
+
# self.logger.info(message)
|
|
432
|
+
# Stop the server
|
|
433
|
+
break
|
|
434
|
+
except Exception as e:
|
|
435
|
+
message = f"Unknown Exception to receive DNS request: {str(e)}"
|
|
436
|
+
print_api(message, logger=self.logger, logger_method='critical', traceback_string=True)
|
|
437
|
+
self.dns_statistics_csv_writer.write_error(
|
|
438
|
+
dns_type='request', client_address=client_address, error_message=message)
|
|
154
439
|
continue
|
|
155
440
|
|
|
441
|
+
# noinspection PyBroadException
|
|
156
442
|
try:
|
|
157
443
|
# This is the real point when the request received was logged, but since it takes too much place
|
|
158
444
|
# on the screen, moved it to full request logging position.
|
|
@@ -162,11 +448,11 @@ class DnsServer:
|
|
|
162
448
|
|
|
163
449
|
# Received DNS request that needs to be parsed to readable format
|
|
164
450
|
dns_object: dnslib.dns.DNSRecord = DNSRecord.parse(client_data)
|
|
165
|
-
# "qtype" returns as numeric identification, we need to convert it to
|
|
166
|
-
# provided by the dnslib
|
|
451
|
+
# "qtype" returns as numeric identification, we need to convert it to
|
|
452
|
+
# Readable QType (DNS Record Type) provided by the dnslib
|
|
167
453
|
# "dns_object.q" is the Question from the client that holds all the DNS question data,
|
|
168
|
-
# like which domain was
|
|
169
|
-
#
|
|
454
|
+
# like which domain was questioned for resolving,
|
|
455
|
+
# the class (example: IN), DNS Record Type that was questioned and a header.
|
|
170
456
|
# "dns_object.q.qtype" returns only QType of the Question
|
|
171
457
|
qtype_string: str = dnslib.QTYPE[dns_object.q.qtype]
|
|
172
458
|
# "qclass" returns as numeric identification, we need to convert it
|
|
@@ -182,25 +468,18 @@ class DnsServer:
|
|
|
182
468
|
# "dns_object.q.qname" returns only the questioned domain with "." (dot) in the end,
|
|
183
469
|
# which needs to be removed.
|
|
184
470
|
question_domain: str = str(dns_object.q.qname)[:-1]
|
|
185
|
-
self.
|
|
186
|
-
self.dns_full_logger.info(f"QTYPE: {qtype_string}")
|
|
187
|
-
self.dns_full_logger.info(f"Question Domain: {question_domain}")
|
|
471
|
+
self.dns_statistics_csv_writer.write_row(client_address=client_address, dns_request=dns_object)
|
|
188
472
|
|
|
189
|
-
message = f"Received request
|
|
473
|
+
message = (f"Received DNS request: {question_domain} | {qclass_string} | {qtype_string} | "
|
|
474
|
+
f"From: {client_address}.")
|
|
190
475
|
self.logger.info(message)
|
|
191
|
-
self.dns_full_logger.info(message)
|
|
192
|
-
|
|
193
|
-
self.dns_full_logger.info("--")
|
|
194
476
|
|
|
195
477
|
# Nullifying the DNS cache for current request before check.
|
|
196
478
|
dns_cached_request = False
|
|
197
479
|
# Check if the received data request from client is already in the cache
|
|
198
480
|
if client_data in self.dns_questions_to_answers_cache:
|
|
199
|
-
message = "!!!
|
|
481
|
+
# message = "!!! Request / Response is already in the dictionary..."
|
|
200
482
|
# self.logger.info(message)
|
|
201
|
-
self.dns_full_logger.info(message)
|
|
202
|
-
|
|
203
|
-
self.dns_full_logger.info("--")
|
|
204
483
|
|
|
205
484
|
# Get the response from the cached answers list
|
|
206
485
|
dns_response = self.dns_questions_to_answers_cache[client_data]
|
|
@@ -211,12 +490,12 @@ class DnsServer:
|
|
|
211
490
|
else:
|
|
212
491
|
# Check if the incoming Record is "A" record.
|
|
213
492
|
if qtype_string == "A":
|
|
214
|
-
# Check if '
|
|
215
|
-
# If so, we need to check if the incoming domain contain any of the
|
|
216
|
-
if self.
|
|
493
|
+
# Check if 'resolve_to_tcp_server_only_tcp_resolve_domains' is set to 'True'.
|
|
494
|
+
# If so, we need to check if the incoming domain contain any of the domains in the list.
|
|
495
|
+
if self.resolve_by_engine_enable:
|
|
217
496
|
# If current query domain (+ subdomains) CONTAIN any of the domains from modules config
|
|
218
497
|
# files and current request contains "A" (IPv4) record.
|
|
219
|
-
if any(x in question_domain for x in self.
|
|
498
|
+
if any(x in question_domain for x in self.intercept_domain_dict.keys()):
|
|
220
499
|
# If incoming domain contains any of the 'engine_domains' then domain will
|
|
221
500
|
# be forwarded to our TCP Server.
|
|
222
501
|
forward_to_tcp_server = True
|
|
@@ -225,12 +504,12 @@ class DnsServer:
|
|
|
225
504
|
|
|
226
505
|
# If 'route_to_tcp_server_all_domains' was set to 'False' in 'config.ini' file then
|
|
227
506
|
# we'll forward all 'A' records domains to the Built-in TCP Server.
|
|
228
|
-
if self.
|
|
507
|
+
if self.resolve_all_domains_to_ipv4_enable:
|
|
229
508
|
forward_to_tcp_server = True
|
|
230
509
|
|
|
231
510
|
# If 'regular_resolving' was set to 'True' in 'config.ini' file then
|
|
232
511
|
# we'll forward all 'A' records domains to the Live DNS Service.
|
|
233
|
-
if self.
|
|
512
|
+
if self.resolve_regular_pass_thru:
|
|
234
513
|
forward_to_tcp_server = False
|
|
235
514
|
|
|
236
515
|
# If incoming record is not an "A" record, then it will not be forwarded to our TCP Server.
|
|
@@ -239,9 +518,15 @@ class DnsServer:
|
|
|
239
518
|
|
|
240
519
|
# If 'forward_to_tcp_server' is 'True' we'll resolve the record with our TCP Server IP address.
|
|
241
520
|
if forward_to_tcp_server:
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
521
|
+
if self.resolve_by_engine_enable:
|
|
522
|
+
for engine in self.engine_list:
|
|
523
|
+
resolved_target_ipv4 = get_target_ip_from_engine(question_domain, engine.domain_target_dict)
|
|
524
|
+
# If the domain was found in the current engine's domain list, we can stop the loop.
|
|
525
|
+
if resolved_target_ipv4:
|
|
526
|
+
break
|
|
527
|
+
elif self.resolve_all_domains_to_ipv4_enable:
|
|
528
|
+
# Assign the target IPv4 address to the resolved target IPv4 variable.
|
|
529
|
+
resolved_target_ipv4 = self.resolve_all_domains_target
|
|
245
530
|
|
|
246
531
|
# Make DNS response that will refer TCP traffic to our server
|
|
247
532
|
dns_built_response = DNSRecord(
|
|
@@ -250,7 +535,7 @@ class DnsServer:
|
|
|
250
535
|
# q=DNSQuestion(question_domain),
|
|
251
536
|
q=dns_object.q,
|
|
252
537
|
a=RR(question_domain,
|
|
253
|
-
rdata=A(
|
|
538
|
+
rdata=A(resolved_target_ipv4),
|
|
254
539
|
ttl=self.response_ttl)
|
|
255
540
|
)
|
|
256
541
|
# Encode the response that was built above to legit DNS Response
|
|
@@ -261,7 +546,7 @@ class DnsServer:
|
|
|
261
546
|
# any of the domains from modules config files
|
|
262
547
|
else:
|
|
263
548
|
# If we're in offline mode
|
|
264
|
-
if self.
|
|
549
|
+
if self.offline_mode:
|
|
265
550
|
# Make DNS response that will refer TCP traffic to our server
|
|
266
551
|
# dns_question = DNSRecord.question(question_domain)
|
|
267
552
|
dns_built_response = dns_object.reply()
|
|
@@ -272,14 +557,13 @@ class DnsServer:
|
|
|
272
557
|
if qtype_string == "AAAA":
|
|
273
558
|
dns_built_response.add_answer(
|
|
274
559
|
*RR.fromZone(
|
|
275
|
-
question_domain
|
|
276
|
-
self.offline_route_ipv6)
|
|
560
|
+
f'{question_domain} {str(self.response_ttl)} {qtype_string} '
|
|
561
|
+
f'{self.offline_route_ipv6}')
|
|
277
562
|
)
|
|
278
563
|
|
|
279
|
-
message = f"!!!
|
|
564
|
+
message = f"!!! Request / Response is in offline mode returning " \
|
|
280
565
|
f"{self.offline_route_ipv6}."
|
|
281
566
|
self.logger.info(message)
|
|
282
|
-
self.dns_full_logger.info(message)
|
|
283
567
|
|
|
284
568
|
# SRV Record type explanation:
|
|
285
569
|
# https://www.cloudflare.com/learning/dns/dns-records/dns-srv-record/
|
|
@@ -290,44 +574,39 @@ class DnsServer:
|
|
|
290
574
|
# com. domain.com. 2022012500 1800 900 604800 86400
|
|
291
575
|
# Basically SOA is the same, but can be with additional fields.
|
|
292
576
|
# Since, it's offline and not online - we don't really care.
|
|
293
|
-
elif qtype_string == "SRV" or qtype_string == "SOA":
|
|
577
|
+
elif qtype_string == "SRV" or qtype_string == "SOA" or qtype_string == "HTTPS":
|
|
294
578
|
dns_built_response.add_answer(*RR.fromZone(self.offline_srv_answer))
|
|
295
579
|
|
|
296
|
-
message = f"!!!
|
|
580
|
+
message = f"!!! Request / Response is in offline mode returning: " \
|
|
297
581
|
f"{self.offline_srv_answer}."
|
|
298
582
|
self.logger.info(message)
|
|
299
|
-
self.dns_full_logger.info(message)
|
|
300
583
|
elif qtype_string == "ANY":
|
|
301
584
|
dns_built_response.add_answer(
|
|
302
|
-
# *RR.fromZone(question_domain + " " + str(response_ttl) + " " + qclass_string +
|
|
303
|
-
# " CNAME " + dns_server_offline_route_domain)
|
|
304
585
|
*RR.fromZone(question_domain + " " + str(self.response_ttl) + " CNAME " +
|
|
305
586
|
self.offline_route_domain)
|
|
306
587
|
)
|
|
307
588
|
|
|
308
|
-
message = f"!!!
|
|
589
|
+
message = f"!!! Request / Response is in offline mode returning " \
|
|
309
590
|
f"{self.offline_route_domain}."
|
|
310
591
|
self.logger.info(message)
|
|
311
|
-
self.dns_full_logger.info(message)
|
|
312
592
|
else:
|
|
313
593
|
dns_built_response.add_answer(
|
|
314
594
|
*RR.fromZone(
|
|
315
|
-
question_domain + " " + str(self.response_ttl) + " " + qtype_string +
|
|
316
|
-
self.offline_route_ipv4)
|
|
595
|
+
question_domain + " " + str(self.response_ttl) + " " + qtype_string +
|
|
596
|
+
" " + self.offline_route_ipv4)
|
|
317
597
|
)
|
|
318
598
|
|
|
319
|
-
message = f"!!!
|
|
599
|
+
message = f"!!! Request / Response is in offline mode returning " \
|
|
320
600
|
f"{self.offline_route_ipv4}."
|
|
321
601
|
self.logger.info(message)
|
|
322
|
-
self.dns_full_logger.info(message)
|
|
323
602
|
# Values error means in most cases that you create wrong response
|
|
324
603
|
# for specific type of request.
|
|
325
604
|
except ValueError:
|
|
326
605
|
message = f"Looks like wrong type of response for QTYPE: {qtype_string}. Response: "
|
|
327
606
|
print_api(message, logger=self.logger, logger_method='critical',
|
|
328
|
-
traceback_string=True
|
|
607
|
+
traceback_string=True)
|
|
329
608
|
print_api(f"{dns_built_response}", logger=self.logger, logger_method='critical',
|
|
330
|
-
traceback_string=True
|
|
609
|
+
traceback_string=True)
|
|
331
610
|
# Pass the exception.
|
|
332
611
|
pass
|
|
333
612
|
# Continue to the next DNS request, since there's nothing to do here right now.
|
|
@@ -335,18 +614,15 @@ class DnsServer:
|
|
|
335
614
|
# General exception in response creation.
|
|
336
615
|
except Exception:
|
|
337
616
|
message = \
|
|
338
|
-
f"Unknown exception while creating response for QTYPE: {qtype_string}.
|
|
617
|
+
(f"Unknown exception while creating response for QTYPE: {qtype_string}. "
|
|
618
|
+
f"Response: \n{dns_built_response}")
|
|
339
619
|
print_api(message, logger=self.logger, logger_method='critical',
|
|
340
|
-
traceback_string=True
|
|
341
|
-
print_api(f"{dns_built_response}", logger=self.logger, logger_method='critical',
|
|
342
|
-
traceback_string=True, oneline=True)
|
|
620
|
+
traceback_string=True)
|
|
343
621
|
# Pass the exception.
|
|
344
622
|
pass
|
|
345
623
|
# Continue to the next DNS request, since there's nothing to do here right now.
|
|
346
624
|
continue
|
|
347
625
|
|
|
348
|
-
self.dns_full_logger.info("--")
|
|
349
|
-
|
|
350
626
|
# Encode the response that was built above to legit DNS Response
|
|
351
627
|
dns_response = dns_built_response.pack()
|
|
352
628
|
# If we're in online mode
|
|
@@ -361,26 +637,26 @@ class DnsServer:
|
|
|
361
637
|
# Since, it's probably going to succeed.
|
|
362
638
|
if counter > 0:
|
|
363
639
|
self.logger.info(f"Retry #: {counter}/{self.dns_service_retries}")
|
|
364
|
-
self.
|
|
640
|
+
self.logger.info(
|
|
365
641
|
f"Forwarding request. Creating UDP socket to: "
|
|
366
|
-
f"{self.
|
|
367
|
-
f"{self.
|
|
642
|
+
f"{self.forwarding_dns_service_ipv4}:"
|
|
643
|
+
f"{self.forwarding_dns_service_port}")
|
|
368
644
|
try:
|
|
369
645
|
google_dns_ipv4_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
370
646
|
google_dns_ipv4_socket.settimeout(5)
|
|
371
647
|
|
|
372
648
|
message = "Socket created, Forwarding..."
|
|
373
649
|
# self.logger.info(message)
|
|
374
|
-
self.
|
|
650
|
+
self.logger.info(message)
|
|
375
651
|
|
|
376
652
|
google_dns_ipv4_socket.sendto(client_data, (
|
|
377
|
-
self.
|
|
378
|
-
self.
|
|
653
|
+
self.forwarding_dns_service_ipv4,
|
|
654
|
+
self.forwarding_dns_service_port
|
|
379
655
|
))
|
|
380
656
|
# The script needs to wait a second or receive can hang
|
|
381
657
|
message = "Request sent to the forwarding DNS, Receiving the answer..."
|
|
382
658
|
# self.logger.info(message)
|
|
383
|
-
self.
|
|
659
|
+
self.logger.info(message)
|
|
384
660
|
|
|
385
661
|
dns_response, google_address = \
|
|
386
662
|
google_dns_ipv4_socket.recvfrom(self.buffer_size_receive)
|
|
@@ -399,9 +675,8 @@ class DnsServer:
|
|
|
399
675
|
self.logger.info(
|
|
400
676
|
f"Retried {self.dns_service_retries} times. "
|
|
401
677
|
f"Couldn't forward DNS request to: "
|
|
402
|
-
f"[{self.
|
|
678
|
+
f"[{self.forwarding_dns_service_ipv4}]. "
|
|
403
679
|
f"Continuing to next request.")
|
|
404
|
-
self.dns_full_logger.info("==========")
|
|
405
680
|
|
|
406
681
|
# From here continue to the next iteration of While loop.
|
|
407
682
|
continue
|
|
@@ -414,36 +689,28 @@ class DnsServer:
|
|
|
414
689
|
if retried:
|
|
415
690
|
continue
|
|
416
691
|
|
|
417
|
-
self.
|
|
418
|
-
f"Answer received from: {self.
|
|
692
|
+
self.logger.info(
|
|
693
|
+
f"Answer received from: {self.forwarding_dns_service_ipv4}")
|
|
419
694
|
|
|
420
695
|
# Closing the socket to forwarding service
|
|
421
696
|
google_dns_ipv4_socket.close()
|
|
422
|
-
self.
|
|
697
|
+
self.logger.info("Closed socket to forwarding service")
|
|
423
698
|
|
|
424
699
|
# Appending current DNS Request and DNS Answer to the Cache
|
|
425
700
|
self.dns_questions_to_answers_cache.update({client_data: dns_response})
|
|
426
701
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
# dns_response = dns_object.reply()
|
|
430
|
-
# dns_response.add_answer(*RR.fromZone(f"{question_domain} 60 {qtype_object} 8.8.8.8"))
|
|
431
|
-
|
|
432
|
-
# dns_built_response = \
|
|
433
|
-
# DNSRecord(
|
|
434
|
-
# DNSHeader(id=dns_object.header.id, qr=1, aa=1, ra=1), q=DNSQuestion(question_domain),
|
|
435
|
-
# a=RR.fromZone(question_domain + " 60 " + qtype_object + " " + dns_server_offline_ipv4))
|
|
436
|
-
|
|
437
|
-
# If 'forward_to_tcp_server' it means that we built the response, and we don't need to reparse it, since
|
|
438
|
-
# we already have all the data.
|
|
702
|
+
# If 'forward_to_tcp_server' it means that we built the response, and we don't need to reparse it,
|
|
703
|
+
# since we already have all the data.
|
|
439
704
|
if forward_to_tcp_server:
|
|
440
|
-
self.
|
|
705
|
+
# self.logger.info(f"Response {dns_built_response.short()}")
|
|
706
|
+
self.dns_statistics_csv_writer.write_row(
|
|
707
|
+
client_address=client_address, dns_response=dns_built_response)
|
|
441
708
|
|
|
442
709
|
message = f"Response Details: {dns_built_response.rr}"
|
|
443
|
-
print_api(message, logger=self.
|
|
710
|
+
print_api(message, logger=self.logger, logger_method='info', oneline=True)
|
|
444
711
|
|
|
445
|
-
message = f"Response Full Details: {dns_built_response.format(prefix='', sort=True)}"
|
|
446
|
-
print_api(message, logger=self.
|
|
712
|
+
# message = f"Response Full Details: {dns_built_response.format(prefix='', sort=True)}"
|
|
713
|
+
# print_api(message, logger=self.logger, logger_method='info', oneline=True)
|
|
447
714
|
|
|
448
715
|
# Now we can turn it to false, so it won't trigger this
|
|
449
716
|
# condition next time if the response was not built
|
|
@@ -459,30 +726,34 @@ class DnsServer:
|
|
|
459
726
|
# Reinitializing the ipv4 addresses list.
|
|
460
727
|
ipv4_addresses = list()
|
|
461
728
|
|
|
462
|
-
|
|
729
|
+
# If the DNS answer section isn't empty, and log the returned IPv4 addresses.
|
|
730
|
+
if dns_response_parsed.rr:
|
|
463
731
|
for rr in dns_response_parsed.rr:
|
|
464
732
|
if isinstance(rr.rdata, A):
|
|
465
|
-
self.
|
|
733
|
+
self.dns_statistics_csv_writer.write_row(
|
|
734
|
+
client_address=client_address, dns_response=dns_response_parsed)
|
|
735
|
+
|
|
736
|
+
self.logger.info(f"Response IP: {rr.rdata}")
|
|
466
737
|
|
|
467
738
|
# Adding the address to the list as 'str' object and not 'dnslib.dns.A'.
|
|
468
739
|
ipv4_addresses.append(str(rr.rdata))
|
|
469
740
|
|
|
470
|
-
message = f"Response Details: {dns_response_parsed.rr}"
|
|
471
|
-
print_api(message, logger=self.
|
|
472
|
-
|
|
473
|
-
message = f"Response Full Details: {dns_response_parsed}"
|
|
474
|
-
print_api(message, logger=self.
|
|
741
|
+
# message = f"Response Details: {dns_response_parsed.rr}"
|
|
742
|
+
# print_api(message, logger=self.dns_statistics_csv_writer, logger_method='info', oneline=True)
|
|
743
|
+
#
|
|
744
|
+
# message = f"Response Full Details: {dns_response_parsed}"
|
|
745
|
+
# print_api(message, logger=self.dns_statistics_csv_writer, logger_method='info', oneline=True)
|
|
475
746
|
|
|
476
|
-
self.
|
|
747
|
+
self.logger.info("Sending DNS response back to client...")
|
|
477
748
|
main_socket_object.sendto(dns_response, client_address)
|
|
478
|
-
self.
|
|
749
|
+
self.logger.info("DNS Response sent...")
|
|
479
750
|
|
|
480
751
|
# 'ipv4_addresses' list contains entries of type 'dnslib.dns.A' and not string.
|
|
481
752
|
# We'll convert each entry to string, so strings can be searched in this list.
|
|
482
753
|
# for index, ip_address in enumerate(ipv4_addresses):
|
|
483
754
|
# ipv4_addresses[index] = str(ip_address)
|
|
484
755
|
|
|
485
|
-
#
|
|
756
|
+
# ==================================================================================================
|
|
486
757
|
# # Known domain dictionary of last 2 A records' management.
|
|
487
758
|
#
|
|
488
759
|
# # Sorting the addresses, so it will be easier to compare dictionaries in the list.
|
|
@@ -504,7 +775,7 @@ class DnsServer:
|
|
|
504
775
|
#
|
|
505
776
|
# dns.logger.info(f"Latest known list: {known_a_records_domains_list_last_entries}")
|
|
506
777
|
|
|
507
|
-
#
|
|
778
|
+
# ==================================================================================================
|
|
508
779
|
# Known domain list management (A Records only)
|
|
509
780
|
|
|
510
781
|
# If current request is in the cache,
|
|
@@ -550,20 +821,20 @@ class DnsServer:
|
|
|
550
821
|
|
|
551
822
|
# Save this string object as log file.
|
|
552
823
|
with open(
|
|
553
|
-
self.
|
|
824
|
+
self.log_directory_path + os.sep + self.known_domains_filename, 'w'
|
|
554
825
|
) as output_file:
|
|
555
826
|
output_file.write(record_string_line)
|
|
556
827
|
|
|
557
|
-
self.
|
|
558
|
-
|
|
559
|
-
|
|
828
|
+
# self.logger.info(
|
|
829
|
+
# f"Saved new known domains file: "
|
|
830
|
+
# f"{self.log_directory_path}{os.sep}{self.known_domains_filename}")
|
|
560
831
|
|
|
561
832
|
# Known domain list managements EOF
|
|
562
|
-
#
|
|
833
|
+
# ==================================================================================================
|
|
563
834
|
# Known IPv4 address to domains list management (A Records only)
|
|
564
835
|
|
|
565
836
|
# If DNS Server 'offline_mode' was set to 'False'.
|
|
566
|
-
if not self.
|
|
837
|
+
if not self.offline_mode:
|
|
567
838
|
dump_ipv4_dictionary_to_file = False
|
|
568
839
|
# If IPv4 address list is not empty, meaning this DNS request was A type.
|
|
569
840
|
if ipv4_addresses:
|
|
@@ -576,9 +847,9 @@ class DnsServer:
|
|
|
576
847
|
# If so, get the list of current domains for current ipv4 address.
|
|
577
848
|
current_domains_list = known_a_records_ipv4_dict[current_ip_address]
|
|
578
849
|
|
|
579
|
-
# If current question domain is not in the known domains that we had from
|
|
580
|
-
# requests for the same IPv4 address, then we'll add this domain
|
|
581
|
-
# list for this IPv4.
|
|
850
|
+
# If current question domain is not in the known domains that we had from
|
|
851
|
+
# previous DNS requests for the same IPv4 address, then we'll add this domain
|
|
852
|
+
# to the known domains list for this IPv4.
|
|
582
853
|
# And update the dictionary of known IPv4 addresses and their domains.
|
|
583
854
|
if question_domain not in current_domains_list:
|
|
584
855
|
current_domains_list.append(question_domain)
|
|
@@ -609,16 +880,16 @@ class DnsServer:
|
|
|
609
880
|
|
|
610
881
|
# Save this string object as log file.
|
|
611
882
|
with open(
|
|
612
|
-
self.
|
|
883
|
+
self.log_directory_path + os.sep + self.known_ipv4_filename, 'w'
|
|
613
884
|
) as output_file:
|
|
614
885
|
output_file.write(record_string_line)
|
|
615
886
|
|
|
616
|
-
self.
|
|
617
|
-
|
|
618
|
-
|
|
887
|
+
# self.logger.info(
|
|
888
|
+
# f"Saved new known IPv4 addresses file: "
|
|
889
|
+
# f"{self.log_directory_path}{os.sep}{self.known_ipv4_filename}")
|
|
619
890
|
|
|
620
891
|
# Known IPv4 address to domains list management EOF
|
|
621
|
-
#
|
|
892
|
+
# ==================================================================================================
|
|
622
893
|
# Writing IPs by time.
|
|
623
894
|
|
|
624
895
|
# If IPv4 address list is not empty, meaning this DNS request was A type.
|
|
@@ -629,31 +900,87 @@ class DnsServer:
|
|
|
629
900
|
|
|
630
901
|
# Save this string object as log file.
|
|
631
902
|
with open(
|
|
632
|
-
self.
|
|
903
|
+
self.log_directory_path + os.sep + self.known_dns_ipv4_by_time_filename, 'a'
|
|
633
904
|
) as output_file:
|
|
634
905
|
output_file.write(record_string_line + '\n')
|
|
635
906
|
|
|
636
907
|
# EOF Writing IPs by time.
|
|
637
|
-
#
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
# Starting a thread that will query IPs of the last DNS request.
|
|
641
|
-
# thread_current = \
|
|
642
|
-
# threading.Thread(
|
|
643
|
-
# target=thread_worker_check_process_by_ip, args=(ipv4_addresses, client_address[0],))
|
|
644
|
-
# # Append to list of threads, so they can be "joined" later
|
|
645
|
-
# threads_list.append(thread_current)
|
|
646
|
-
# # Start the thread
|
|
647
|
-
# thread_current.start()
|
|
648
|
-
|
|
649
|
-
# EOF SSH / LOCALHOST executing process command line harvesting.
|
|
650
|
-
# ==================================================================================================================
|
|
651
|
-
|
|
652
|
-
self.dns_full_logger.info("==========")
|
|
908
|
+
# ==================================================================================================
|
|
909
|
+
|
|
910
|
+
# self.logger.info("==========")
|
|
653
911
|
except Exception:
|
|
654
912
|
message = "Unknown Exception: to parse DNS request"
|
|
655
913
|
print_api(
|
|
656
|
-
message, logger=self.logger, logger_method='critical', traceback_string=True
|
|
914
|
+
message, logger=self.logger, logger_method='critical', traceback_string=True)
|
|
657
915
|
self.logger.info("==========")
|
|
658
916
|
pass
|
|
659
917
|
continue
|
|
918
|
+
|
|
919
|
+
|
|
920
|
+
def get_target_ip_from_engine(
|
|
921
|
+
target_domain: str,
|
|
922
|
+
engine_domain_target_dict: dict
|
|
923
|
+
) -> Optional[str]:
|
|
924
|
+
"""
|
|
925
|
+
Get the target IP address from the engine.
|
|
926
|
+
|
|
927
|
+
:param target_domain: str: The domain to return the target IP address for.
|
|
928
|
+
:param engine_domain_target_dict: dict: The dictionary of domains and their target IPs.
|
|
929
|
+
|
|
930
|
+
:return: str: The target IP address.
|
|
931
|
+
"""
|
|
932
|
+
# Iterate through the list of engines.
|
|
933
|
+
for domain, target_ip_port in engine_domain_target_dict.items():
|
|
934
|
+
# If the domain is exactly the same as the target domain,
|
|
935
|
+
if domain == target_domain:
|
|
936
|
+
# Get the target IP address from the engine.
|
|
937
|
+
return target_ip_port['ip']
|
|
938
|
+
elif domain in target_domain:
|
|
939
|
+
# Get the target IP address from the engine.
|
|
940
|
+
return target_ip_port['ip']
|
|
941
|
+
|
|
942
|
+
return None
|
|
943
|
+
|
|
944
|
+
|
|
945
|
+
# noinspection PyPep8Naming
|
|
946
|
+
def start_dns_server_multiprocessing_worker(
|
|
947
|
+
listening_address: str,
|
|
948
|
+
log_directory_path: str,
|
|
949
|
+
backupCount_log_files_x_days: int,
|
|
950
|
+
forwarding_dns_service_ipv4: str,
|
|
951
|
+
forwarding_dns_service_port: int,
|
|
952
|
+
resolve_by_engine: tuple[bool, list],
|
|
953
|
+
resolve_regular_pass_thru: bool,
|
|
954
|
+
resolve_all_domains_to_ipv4: tuple[bool, str],
|
|
955
|
+
offline_mode: bool,
|
|
956
|
+
cache_timeout_minutes: int,
|
|
957
|
+
logging_queue: multiprocessing.Queue,
|
|
958
|
+
logger_name: str,
|
|
959
|
+
is_ready_multiprocessing: multiprocessing.Event=None
|
|
960
|
+
):
|
|
961
|
+
# Setting the current thread name to the current process name.
|
|
962
|
+
current_process_name = multiprocessing.current_process().name
|
|
963
|
+
threading.current_thread().name = current_process_name
|
|
964
|
+
|
|
965
|
+
try:
|
|
966
|
+
dns_server_instance = DnsServer(
|
|
967
|
+
listening_address=listening_address,
|
|
968
|
+
log_directory_path=log_directory_path,
|
|
969
|
+
backupCount_log_files_x_days=backupCount_log_files_x_days,
|
|
970
|
+
forwarding_dns_service_ipv4=forwarding_dns_service_ipv4,
|
|
971
|
+
forwarding_dns_service_port=forwarding_dns_service_port,
|
|
972
|
+
resolve_by_engine=resolve_by_engine,
|
|
973
|
+
resolve_regular_pass_thru=resolve_regular_pass_thru,
|
|
974
|
+
resolve_all_domains_to_ipv4=resolve_all_domains_to_ipv4,
|
|
975
|
+
offline_mode=offline_mode,
|
|
976
|
+
cache_timeout_minutes=cache_timeout_minutes,
|
|
977
|
+
logging_queue=logging_queue,
|
|
978
|
+
logger_name=logger_name
|
|
979
|
+
)
|
|
980
|
+
except (DnsPortInUseError, DnsConfigurationValuesError) as e:
|
|
981
|
+
_ = e
|
|
982
|
+
# Wait for the message to be printed and saved to file.
|
|
983
|
+
time.sleep(1)
|
|
984
|
+
return 1
|
|
985
|
+
|
|
986
|
+
dns_server_instance.start(is_ready_multiprocessing=is_ready_multiprocessing)
|