Add Windows desktop version
This commit is contained in:
169
windows/StreamPlayer.Desktop/Services/WindowsDnsService.cs
Normal file
169
windows/StreamPlayer.Desktop/Services/WindowsDnsService.cs
Normal file
@@ -0,0 +1,169 @@
|
||||
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<DnsSetupResult> 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<string> 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<bool> 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);
|
||||
}
|
||||
Reference in New Issue
Block a user