Skip to content

Commit

Permalink
Replaced Windows registry lookup with WMIC process invocation. (#115)
Browse files Browse the repository at this point in the history
  • Loading branch information
Bilge authored Aug 11, 2024
1 parent 758266b commit b7515c1
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 57 deletions.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
},
Expand Down
90 changes: 34 additions & 56 deletions src/WindowsDnsConfigLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,89 +4,67 @@

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(),
) {
}

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);
}
}

0 comments on commit b7515c1

Please sign in to comment.