refactor: 枚举移入Models目录,命名空间更新为Rainbow.Entity.Models
大石头 authored at 2026-07-02 12:54:58
5.83 KiB
RainbowBridge
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;
        }
    }
}