From 9a4dd79638987e65143a2b75ac1639070bb02eba Mon Sep 17 00:00:00 2001 From: Bilge Date: Wed, 31 Jan 2024 12:32:36 +0000 Subject: [PATCH 1/2] Replaced Windows registry lookup with WMIC process invocation. --- 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); } } From e5c64200a864db31eec1390bf450ffb3c4a802f1 Mon Sep 17 00:00:00 2001 From: Bilge Date: Wed, 31 Jan 2024 18:27:19 +0000 Subject: [PATCH 2/2] Replaced WMIC nameserver lookup with PowerShell equivalent. --- src/WindowsDnsConfigLoader.php | 42 ++++++++++------------------------ 1 file changed, 12 insertions(+), 30 deletions(-) diff --git a/src/WindowsDnsConfigLoader.php b/src/WindowsDnsConfigLoader.php index cc7060e..2302e38 100644 --- a/src/WindowsDnsConfigLoader.php +++ b/src/WindowsDnsConfigLoader.php @@ -6,6 +6,7 @@ use Amp\ForbidSerialization; use Amp\Process\Process; use function Amp\ByteStream\buffer; +use function Amp\ByteStream\splitLines; final class WindowsDnsConfigLoader implements DnsConfigLoader { @@ -19,15 +20,20 @@ public function __construct( public function loadConfig(): DnsConfig { - $wmic = Process::start(['wmic', 'NICCONFIG', 'GET', 'DNSServerSearchOrder']); - - if ($wmic->join() !== 0) { - throw new DnsConfigException("Could not fetch DNS servers from WMI: " . buffer($wmic->getStderr())); + $powershell = Process::start([ + 'powershell', + '-Command', + 'Get-WmiObject -Class Win32_NetworkAdapterConfiguration | + Select-Object -ExpandProperty DNSServerSearchOrder', + ]); + + if ($powershell->join() !== 0) { + throw new DnsConfigException("Could not fetch DNS servers from WMI: " . buffer($powershell->getStderr())); } - $ips = self::parseWmicOutput(buffer($wmic->getStdout())); + $output = \iterator_to_array(splitLines($powershell->getStdout())); - $nameservers = \array_reduce($ips, static function (array $nameservers, string $address): array { + $nameservers = \array_reduce($output, static function (array $nameservers, string $address): array { $ip = \inet_pton($address); if (isset($ip[15])) { // IPv6 @@ -43,28 +49,4 @@ public function loadConfig(): DnsConfig return new DnsConfig($nameservers, $hosts); } - - private static function parseWmicOutput(string $output): array - { - // 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); - } }