using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net.NetworkInformation; using System.Runtime.InteropServices; using System.Security.Principal; using System.Threading; using System.Threading.Tasks; namespace StreamPlayer.Desktop.Services; public sealed class WindowsDnsService { private static readonly string[] PreferredDns = { "8.8.8.8", "8.8.4.4" }; private bool _attempted; public async Task EnsureGoogleDnsAsync(CancellationToken cancellationToken) { if (!OperatingSystem.IsWindows()) { return DnsSetupResult.CreateSuccess(); } if (_attempted) { return DnsSetupResult.CreateSuccess(); } _attempted = true; bool needsElevation = !IsRunningAsAdministrator(); if (needsElevation) { var consent = PromptForElevation(); if (!consent) { return DnsSetupResult.CreateFailure("Se canceló la solicitud de permisos. Ejecuta la app como administrador o configura los DNS manualmente (8.8.8.8 y 8.8.4.4)."); } } var interfaces = GetEligibleInterfaces().ToList(); if (interfaces.Count == 0) { return DnsSetupResult.CreateSuccess("No se detectaron adaptadores de red activos para forzar DNS."); } foreach (var adapter in interfaces) { bool primary = await RunNetshAsync( $"interface ipv4 set dns name=\"{adapter}\" static {PreferredDns[0]} primary", cancellationToken, needsElevation); bool secondary = await RunNetshAsync( $"interface ipv4 add dns name=\"{adapter}\" {PreferredDns[1]} index=2", cancellationToken, needsElevation); if (!primary || !secondary) { return DnsSetupResult.CreateFailure($"No se pudo configurar DNS para el adaptador \"{adapter}\". Verifica permisos de administrador o configura manualmente los DNS de Google."); } } return DnsSetupResult.CreateSuccess("DNS de Google aplicados correctamente a los adaptadores de red activos."); } private static bool IsRunningAsAdministrator() { if (!OperatingSystem.IsWindows()) { return false; } try { using var identity = WindowsIdentity.GetCurrent(); var principal = new WindowsPrincipal(identity); return principal.IsInRole(WindowsBuiltInRole.Administrator); } catch { return false; } } private static IEnumerable GetEligibleInterfaces() { return NetworkInterface.GetAllNetworkInterfaces() .Where(ni => ni.OperationalStatus == OperationalStatus.Up && ni.NetworkInterfaceType != NetworkInterfaceType.Loopback && ni.NetworkInterfaceType != NetworkInterfaceType.Tunnel && ni.Supports(NetworkInterfaceComponent.IPv4)) .Select(ni => ni.Name); } private static bool PromptForElevation() { try { var psi = new ProcessStartInfo { FileName = "netsh", Arguments = "advfirewall show currentprofile", UseShellExecute = true, Verb = "runas", CreateNoWindow = true }; using var process = Process.Start(psi); if (process == null) { return false; } process.WaitForExit(); return process.ExitCode == 0; } catch (System.ComponentModel.Win32Exception ex) when (ex.NativeErrorCode == 1223) { // User cancelled UAC prompt. return false; } catch { return false; } } private static async Task RunNetshAsync(string arguments, CancellationToken cancellationToken, bool elevate) { try { var psi = new ProcessStartInfo { FileName = "netsh", Arguments = arguments, UseShellExecute = elevate, RedirectStandardOutput = !elevate, RedirectStandardError = !elevate, CreateNoWindow = true }; if (elevate) { psi.Verb = "runas"; } using var process = Process.Start(psi); if (process == null) { return false; } await process.WaitForExitAsync(cancellationToken); return process.ExitCode == 0; } catch (System.ComponentModel.Win32Exception ex) when (ex.NativeErrorCode == 1223) { return false; } catch { return false; } } } public sealed record DnsSetupResult(bool Success, string Message) { public static DnsSetupResult CreateSuccess(string message = "") => new(true, message); public static DnsSetupResult CreateFailure(string message) => new(false, message); }