using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
namespace Rainbow.Services;
/// <summary>Windows 路由管ç†å™¨ã€‚通过 route.exe 实现 INetworkRouteManager</summary>
public class WindowsRouteManager : INetworkRouteManager
{
/// <summary>èŽ·å–æ‰€æœ‰è·¯ç”±æ¡ç›®ã€‚è§£æž route print 输出</summary>
public async Task<List<RouteInfo>> GetRoutesAsync()
{
var result = new List<RouteInfo>();
try
{
var psi = new ProcessStartInfo("route", "print")
{
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true,
};
using var proc = Process.Start(psi);
if (proc == null) return result;
var output = await proc.StandardOutput.ReadToEndAsync();
await proc.WaitForExitAsync().WaitAsync(TimeSpan.FromSeconds(10));
// route print è¾“å‡ºæ ¼å¼ï¼ˆIPv4 部分):
// 0.0.0.0 0.0.0.0 192.168.1.1 192.168.1.100 25
// 10.0.0.0 255.0.0.0 10.0.0.1 10.0.0.100 1
var parsing = false;
foreach (var line in output.Split('\n'))
{
var trimmed = line.Trim();
// IPv4 è·¯ç”±è¡¨å¼€å§‹æ ‡è®°
if (trimmed.Contains("IPv4") || trimmed.Contains("======="))
{
parsing = true;
continue;
}
if (!parsing) continue;
if (String.IsNullOrEmpty(trimmed)) continue;
if (trimmed.StartsWith("=")) continue;
if (trimmed.Contains("接å£åˆ—表") || trimmed.Contains("Interface List")) continue;
var parts = trimmed.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length < 4) continue;
// è§£æž IP 和掩ç
var network = parts[0];
var netmask = parts[1];
var gateway = parts[2];
var interfaceName = parts.Length > 3 ? parts[3] : "";
var metric = parts.Length > 4 ? parts[4] : "0";
// 组装 CIDR
if (network == "0.0.0.0" && netmask == "0.0.0.0")
{
network = "0.0.0.0/0";
}
else if (!String.IsNullOrEmpty(netmask))
{
var cidr = NetmaskToCidr(netmask);
if (cidr > 0)
network = $"{network}/{cidr}";
}
result.Add(new RouteInfo
{
Network = network,
Gateway = gateway,
InterfaceName = interfaceName,
Metric = Int32.TryParse(metric, out var m) ? m : 0,
IsDefault = network == "0.0.0.0/0" || network == "::/0",
Source = "kernel",
});
}
}
catch
{
// 异常时返回空列表
}
return result;
}
/// <summary>获å–默认路由</summary>
public async Task<RouteInfo?> GetDefaultRouteAsync()
{
var routes = await GetRoutesAsync();
return routes.FirstOrDefault(r => r.IsDefault);
}
/// <summary>æ·»åŠ è·¯ç”±</summary>
public async Task<Boolean> AddRouteAsync(String network, String gateway, String? interfaceName = null, Int32 metric = 0)
{
try
{
var metricArg = metric > 0 ? $" metric {metric}" : "";
var ifArg = !String.IsNullOrEmpty(interfaceName) ? $" if {interfaceName}" : "";
var cmd = $"add {network} {gateway}{ifArg}{metricArg}";
return await RunRouteAsync(cmd);
}
catch
{
return false;
}
}
/// <summary>åˆ é™¤è·¯ç”±</summary>
public async Task<Boolean> DeleteRouteAsync(String network, String? gateway = null)
{
try
{
var gwArg = !String.IsNullOrEmpty(gateway) ? $" {gateway}" : "";
var cmd = $"delete {network}{gwArg}";
return await RunRouteAsync(cmd);
}
catch
{
return false;
}
}
/// <summary>修改默认路由</summary>
public async Task<Boolean> SetDefaultRouteAsync(String gateway, Int32 metric = 0)
{
try
{
var metricArg = metric > 0 ? $" metric {metric}" : "";
var cmd = $"change 0.0.0.0 mask 0.0.0.0 {gateway}{metricArg}";
return await RunRouteAsync(cmd);
}
catch
{
return false;
}
}
private static async Task<Boolean> RunRouteAsync(String arguments)
{
var psi = new ProcessStartInfo("route", arguments)
{
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true,
};
using var proc = Process.Start(psi);
if (proc == null) return false;
await proc.WaitForExitAsync().WaitAsync(TimeSpan.FromSeconds(10));
return proc.ExitCode == 0;
}
/// <summary>å网掩ç 转 CIDR å‰ç¼€é•¿åº¦</summary>
private static Int32 NetmaskToCidr(String netmask)
{
try
{
var parts = netmask.Split('.');
if (parts.Length != 4) return 0;
var cidr = 0;
foreach (var part in parts)
{
if (Byte.TryParse(part, out var b))
{
for (var i = 7; i >= 0; i--)
{
if ((b & (1 << i)) != 0) cidr++;
}
}
}
return cidr;
}
catch
{
return 0;
}
}
}
|