From fbbb708bfd0062942835cb526e3dedb00cc6a80d Mon Sep 17 00:00:00 2001 From: mikisoq Date: Wed, 29 Jul 2026 01:59:02 -0100 Subject: [PATCH] Make auto-discovery cross-platform (Windows + Linux) --- Services/DomainDiscovery.cs | 179 ++++++++++++++++++++++++++++++------ 1 file changed, 150 insertions(+), 29 deletions(-) diff --git a/Services/DomainDiscovery.cs b/Services/DomainDiscovery.cs index 16f611d..f5cd761 100644 --- a/Services/DomainDiscovery.cs +++ b/Services/DomainDiscovery.cs @@ -1,4 +1,6 @@ using System.Net; +using System.Net.NetworkInformation; +using System.Runtime.InteropServices; using ADBulkTool.Models; using DnsClient; @@ -16,7 +18,7 @@ public static class DomainDiscovery if (string.IsNullOrWhiteSpace(domain)) { return new DiscoveryResult(null, null, null, null, null, - "Could not detect a DNS domain from this machine. Check that you are on a domain-joined network and that /etc/resolv.conf has a search or domain entry."); + "Could not detect a DNS domain. Ensure the machine is on a domain network with a proper DNS configuration."); } steps.Add($"Detected domain: {domain}"); @@ -27,8 +29,8 @@ public static class DomainDiscovery var dnsServers = GetDnsServers(); var dnsServer = dnsServers.FirstOrDefault(); steps.Add(dnsServer is not null - ? $"DNS server from /etc/resolv.conf: {dnsServer}" - : "No DNS server found in /etc/resolv.conf, using system default."); + ? $"DNS server found: {dnsServer}" + : "No DNS server found, using system default resolver."); var ldapHost = await FindDomainControllerViaSrvAsync(domain, dnsServer, timeout); @@ -62,29 +64,12 @@ public static class DomainDiscovery public static List GetDnsServers() { - var servers = new List(); - - try - { - var lines = File.ReadAllLines("/etc/resolv.conf"); - foreach (var line in lines) - { - var trimmed = line.Trim(); - if (trimmed.StartsWith("nameserver ", StringComparison.OrdinalIgnoreCase)) - { - var parts = trimmed.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); - if (parts.Length >= 2 && IPAddress.TryParse(parts[1], out _)) - { - servers.Add(parts[1]); - } - } - } - } - catch + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { + return GetDnsServersWindows(); } - return servers; + return GetDnsServersLinux(); } public static string? DomainToSearchBase(string? domain) @@ -109,10 +94,22 @@ public static class DomainDiscovery { using var cts = new CancellationTokenSource(timeout); - var resolvDomain = await Task.Run(() => GetDomainFromResolvConf(), cts.Token); - if (!string.IsNullOrWhiteSpace(resolvDomain)) + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { - return resolvDomain; + var resolvDomain = await Task.Run(() => GetDomainFromResolvConf(), cts.Token); + if (!string.IsNullOrWhiteSpace(resolvDomain)) + { + return resolvDomain; + } + } + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + var winDomain = await Task.Run(() => GetDomainFromWindows(), cts.Token); + if (!string.IsNullOrWhiteSpace(winDomain)) + { + return winDomain; + } } var hostDomain = await Task.Run(() => GetDomainFromHostname(), cts.Token); @@ -123,8 +120,14 @@ public static class DomainDiscovery var ipDomain = await Task.Run(() => { - try { return System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().DomainName; } - catch { return string.Empty; } + try + { + return IPGlobalProperties.GetIPGlobalProperties().DomainName; + } + catch + { + return string.Empty; + } }, cts.Token); if (!string.IsNullOrWhiteSpace(ipDomain) && !string.Equals(ipDomain, "localdomain", StringComparison.OrdinalIgnoreCase)) { @@ -139,6 +142,68 @@ public static class DomainDiscovery } } + private static List GetDnsServersWindows() + { + var servers = new List(); + + try + { + foreach (var ni in NetworkInterface.GetAllNetworkInterfaces()) + { + if (ni.OperationalStatus != OperationalStatus.Up) + { + continue; + } + + var props = ni.GetIPProperties(); + if (props is null) + { + continue; + } + + foreach (var dns in props.DnsAddresses) + { + if (dns.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork && !servers.Contains(dns.ToString())) + { + servers.Add(dns.ToString()); + } + } + } + } + catch + { + } + + return servers; + } + + private static List GetDnsServersLinux() + { + var servers = new List(); + + try + { + var lines = File.ReadAllLines("/etc/resolv.conf"); + foreach (var line in lines) + { + var trimmed = line.Trim(); + if (trimmed.StartsWith("nameserver ", StringComparison.OrdinalIgnoreCase)) + { + var parts = trimmed.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); + if (parts.Length >= 2 && IPAddress.TryParse(parts[1], out _)) + { + servers.Add(parts[1]); + } + } + } + } + catch + { + } + + return servers; + } + private static string? GetDomainFromResolvConf() { try @@ -174,6 +239,62 @@ public static class DomainDiscovery return null; } + private static string? GetDomainFromWindows() + { + try + { + foreach (var ni in NetworkInterface.GetAllNetworkInterfaces()) + { + if (ni.OperationalStatus != OperationalStatus.Up) + { + continue; + } + + var props = ni.GetIPProperties(); + if (props is null) + { + continue; + } + + var suffix = props.DnsSuffix; + if (!string.IsNullOrWhiteSpace(suffix)) + { + return suffix.TrimEnd('.'); + } + } + } + catch + { + } + +#pragma warning disable CA1416 // Registry access is guarded by platform check + try + { + using var key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey( + @"SYSTEM\CurrentControlSet\Services\Tcpip\Parameters"); + if (key is not null) + { + var domain = key.GetValue("Domain") as string; + if (!string.IsNullOrWhiteSpace(domain)) + { + return domain.TrimEnd('.'); + } + + var dhcpDomain = key.GetValue("DhcpDomain") as string; + if (!string.IsNullOrWhiteSpace(dhcpDomain)) + { + return dhcpDomain.TrimEnd('.'); + } + } + } + catch + { + } +#pragma warning restore CA1416 + + return null; + } + private static string? GetDomainFromHostname() { try @@ -192,7 +313,7 @@ public static class DomainDiscovery try { - var fullHostname = System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().HostName; + var fullHostname = IPGlobalProperties.GetIPGlobalProperties().HostName; var dotIndex = fullHostname.IndexOf('.'); if (dotIndex > 0 && dotIndex < fullHostname.Length - 1) {