From b7515c1c41e12cbd09b1ab76872bf0b04e949142 Mon Sep 17 00:00:00 2001 From: Bilge Date: Sun, 11 Aug 2024 16:10:35 +0100 Subject: [PATCH] Replaced Windows registry lookup with WMIC process invocation. (#115) --- composer.json | 3 +- src/WindowsDnsConfigLoader.php | 90 +++++++++++++--------------------- 2 files changed, 36 insertions(+), 57 deletions(-) diff --git a/composer.json b/composer.json index 9838f5c..cc4c653 100644 --- a/composer.json +++ b/composer.json @@ -36,11 +36,12 @@ "require": { "php": ">=8.1", "ext-filter": "*", + "ext-json": "*", "amphp/amp": "^3", "amphp/byte-stream": "^2", "amphp/cache": "^2", "amphp/parser": "^1", - "amphp/windows-registry": "^1.0.1", + "amphp/process": "^2", "daverandom/libdns": "^2.0.2", "revolt/event-loop": "^1 || ^0.2" }, diff --git a/src/WindowsDnsConfigLoader.php b/src/WindowsDnsConfigLoader.php index efa3326..cc7060e 100644 --- a/src/WindowsDnsConfigLoader.php +++ b/src/WindowsDnsConfigLoader.php @@ -4,19 +4,14 @@ use Amp\ForbidCloning; use Amp\ForbidSerialization; -use Amp\WindowsRegistry\KeyNotFoundException; -use Amp\WindowsRegistry\WindowsRegistry; +use Amp\Process\Process; +use function Amp\ByteStream\buffer; final class WindowsDnsConfigLoader implements DnsConfigLoader { use ForbidCloning; use ForbidSerialization; - private const NETWORK_CARDS_KEY = - 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards'; - private const TCPIP_PARAMETERS_KEY = - 'HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces'; - public function __construct( private readonly HostLoader $hostLoader = new HostLoader(), ) { @@ -24,69 +19,52 @@ public function __construct( public function loadConfig(): DnsConfig { - $keys = [ - "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\NameServer", - "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\DhcpNameServer", - ]; - - $nameserver = ""; - - while ($nameserver === "" && ($key = \array_shift($keys))) { - try { - $nameserver = WindowsRegistry::read($key); - } catch (KeyNotFoundException) { - // retry other possible locations - } - } - - if ($nameserver === "") { - foreach (self::findNetworkCardGuids() as $guid) { - foreach (["NameServer", "DhcpNameServer"] as $property) { - try { - $nameserver = WindowsRegistry::read(self::TCPIP_PARAMETERS_KEY . "\\$guid\\$property"); - - if ($nameserver !== "") { - break 2; - } - } catch (KeyNotFoundException) { - // retry other possible locations - } - } - } - } + $wmic = Process::start(['wmic', 'NICCONFIG', 'GET', 'DNSServerSearchOrder']); - if ($nameserver === "") { - throw new DnsConfigException("Could not find a nameserver in the Windows Registry"); + if ($wmic->join() !== 0) { + throw new DnsConfigException("Could not fetch DNS servers from WMI: " . buffer($wmic->getStderr())); } - $nameservers = []; + $ips = self::parseWmicOutput(buffer($wmic->getStdout())); - // Comma is the delimiter for the NameServer key, but space is used for the DhcpNameServer key. - foreach (\explode(" ", \strtr($nameserver, ",", " ")) as $nameserver) { - $nameserver = \trim($nameserver); - $ip = \inet_pton($nameserver); - - if ($ip === false) { - continue; - } + $nameservers = \array_reduce($ips, static function (array $nameservers, string $address): array { + $ip = \inet_pton($address); if (isset($ip[15])) { // IPv6 - $nameservers[] = "[" . $nameserver . "]:53"; - } else { // IPv4 - $nameservers[] = $nameserver . ":53"; + $nameservers[] = "[$address]:53"; + } elseif (isset($ip[3])) { // IPv4 + $nameservers[] = "$address:53"; } - } + + return $nameservers; + }, []); $hosts = $this->hostLoader->loadHosts(); return new DnsConfig($nameservers, $hosts); } - private static function findNetworkCardGuids(): array + private static function parseWmicOutput(string $output): array { - return \array_map( - static fn (string $key): string => WindowsRegistry::read("$key\\ServiceName"), - WindowsRegistry::listKeys(self::NETWORK_CARDS_KEY), + // Massage WMIC output into JSON format. + $json = \preg_replace( + [ + // Convert header line into opening bracket. + '[^\V*\v+]', + // Convert closing braces into commas. + '[}]', + // Remove final comma. + '[,(?=[^,]*+$)]', + // Removing opening braces. + '[{]', + ], + [ + '[', + ',', + ], + $output, ); + + return \json_decode("$json]", true, flags: \JSON_THROW_ON_ERROR); } }