feat: 简单实现静态arp设置
This commit is contained in:
		
							
								
								
									
										421
									
								
								server/src/ArpClient.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										421
									
								
								server/src/ArpClient.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,421 @@
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
using System.Runtime.InteropServices;
 | 
			
		||||
using System.Text.RegularExpressions;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// ARP 记录管理静态类(跨平台支持)
 | 
			
		||||
/// </summary>
 | 
			
		||||
public static class Arp
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 读取所有 ARP 记录
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <returns>ARP 记录列表</returns>
 | 
			
		||||
    public static async Task<List<ArpEntry>> GetArpTableAsync()
 | 
			
		||||
    {
 | 
			
		||||
        var entries = new List<ArpEntry>();
 | 
			
		||||
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            string command = GetArpListCommand();
 | 
			
		||||
            var result = await ExecuteCommandAsync(command);
 | 
			
		||||
            if (result.IsSuccess)
 | 
			
		||||
            {
 | 
			
		||||
                var lines = result.Output.Split('\n', StringSplitOptions.RemoveEmptyEntries);
 | 
			
		||||
 | 
			
		||||
                foreach (var line in lines)
 | 
			
		||||
                {
 | 
			
		||||
                    var entry = ParseArpEntry(line);
 | 
			
		||||
                    if (entry != null)
 | 
			
		||||
                    {
 | 
			
		||||
                        entries.Add(entry);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        catch (Exception ex)
 | 
			
		||||
        {
 | 
			
		||||
            throw new Exception($"读取 ARP 表失败: {ex.Message}");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return entries;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 添加 ARP 记录
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="ipAddress">IP 地址</param>
 | 
			
		||||
    /// <param name="macAddress">MAC 地址</param>
 | 
			
		||||
    /// <param name="interfaceName">网络接口名称(可选)</param>
 | 
			
		||||
    /// <returns>是否成功</returns>
 | 
			
		||||
    public static async Task<bool> AddArpEntryAsync(string ipAddress, string macAddress, string interfaceName = null)
 | 
			
		||||
    {
 | 
			
		||||
        if (string.IsNullOrWhiteSpace(ipAddress))
 | 
			
		||||
            throw new ArgumentException("IP 地址不能为空", nameof(ipAddress));
 | 
			
		||||
 | 
			
		||||
        if (string.IsNullOrWhiteSpace(macAddress))
 | 
			
		||||
            throw new ArgumentException("MAC 地址不能为空", nameof(macAddress));
 | 
			
		||||
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            string command = GetArpAddCommand(ipAddress, macAddress, interfaceName);
 | 
			
		||||
            var result = await ExecuteCommandAsync(command);
 | 
			
		||||
            return result.IsSuccess;
 | 
			
		||||
        }
 | 
			
		||||
        catch (Exception ex)
 | 
			
		||||
        {
 | 
			
		||||
            throw new Exception($"添加 ARP 记录失败: {ex.Message}");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 删除 ARP 记录
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="ipAddress">要删除的 IP 地址</param>
 | 
			
		||||
    /// <param name="interfaceName">网络接口名称(可选)</param>
 | 
			
		||||
    /// <returns>是否成功</returns>
 | 
			
		||||
    public static async Task<bool> DeleteArpEntryAsync(string ipAddress, string interfaceName = null)
 | 
			
		||||
    {
 | 
			
		||||
        if (string.IsNullOrWhiteSpace(ipAddress))
 | 
			
		||||
            throw new ArgumentException("IP 地址不能为空", nameof(ipAddress));
 | 
			
		||||
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            string command = GetArpDeleteCommand(ipAddress, interfaceName);
 | 
			
		||||
            var result = await ExecuteCommandAsync(command);
 | 
			
		||||
            return result.IsSuccess;
 | 
			
		||||
        }
 | 
			
		||||
        catch (Exception ex)
 | 
			
		||||
        {
 | 
			
		||||
            throw new Exception($"删除 ARP 记录失败: {ex.Message}");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 清空所有 ARP 记录
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <returns>是否成功</returns>
 | 
			
		||||
    public static async Task<bool> ClearArpTableAsync()
 | 
			
		||||
    {
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            string command = GetArpClearCommand();
 | 
			
		||||
            var result = await ExecuteCommandAsync(command);
 | 
			
		||||
            return result.IsSuccess;
 | 
			
		||||
        }
 | 
			
		||||
        catch (Exception ex)
 | 
			
		||||
        {
 | 
			
		||||
            throw new Exception($"清空 ARP 表失败: {ex.Message}");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 查询特定 IP 的 ARP 记录
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="ipAddress">IP 地址</param>
 | 
			
		||||
    /// <returns>ARP 记录,如果不存在则返回 null</returns>
 | 
			
		||||
    public static async Task<ArpEntry?> GetArpEntryAsync(string ipAddress)
 | 
			
		||||
    {
 | 
			
		||||
        if (string.IsNullOrWhiteSpace(ipAddress))
 | 
			
		||||
            throw new ArgumentException("IP 地址不能为空", nameof(ipAddress));
 | 
			
		||||
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            string command = GetArpQueryCommand(ipAddress);
 | 
			
		||||
            var result = await ExecuteCommandAsync(command);
 | 
			
		||||
            if (result.IsSuccess)
 | 
			
		||||
            {
 | 
			
		||||
                var lines = result.Output.Split('\n', StringSplitOptions.RemoveEmptyEntries);
 | 
			
		||||
                foreach (var line in lines)
 | 
			
		||||
                {
 | 
			
		||||
                    var entry = ParseArpEntry(line);
 | 
			
		||||
                    if (entry != null && entry.IpAddress == ipAddress)
 | 
			
		||||
                    {
 | 
			
		||||
                        return entry;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        catch (Exception ex)
 | 
			
		||||
        {
 | 
			
		||||
            throw new Exception($"查询 ARP 记录失败: {ex.Message}");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 获取 ARP 列表命令
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    private static string GetArpListCommand()
 | 
			
		||||
    {
 | 
			
		||||
        return RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
 | 
			
		||||
            ? "arp -a"
 | 
			
		||||
            : "arp -a";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 获取 ARP 添加命令
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    private static string GetArpAddCommand(string ipAddress, string macAddress, string interfaceName)
 | 
			
		||||
    {
 | 
			
		||||
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
 | 
			
		||||
        {
 | 
			
		||||
            return string.IsNullOrWhiteSpace(interfaceName)
 | 
			
		||||
                ? $"arp -s {ipAddress} {macAddress}"
 | 
			
		||||
                : $"arp -s {ipAddress} {macAddress} {interfaceName}";
 | 
			
		||||
        }
 | 
			
		||||
        else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
 | 
			
		||||
        {
 | 
			
		||||
            return string.IsNullOrWhiteSpace(interfaceName)
 | 
			
		||||
                ? $"arp -s {ipAddress} {macAddress}"
 | 
			
		||||
                : $"arp -s {ipAddress} {macAddress} -i {interfaceName}";
 | 
			
		||||
        }
 | 
			
		||||
        else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
 | 
			
		||||
        {
 | 
			
		||||
            return string.IsNullOrWhiteSpace(interfaceName)
 | 
			
		||||
                ? $"arp -s {ipAddress} {macAddress}"
 | 
			
		||||
                : $"arp -s {ipAddress} {macAddress} ifscope {interfaceName}";
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            throw new PlatformNotSupportedException("不支持的操作系统平台");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 获取 ARP 删除命令
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    private static string GetArpDeleteCommand(string ipAddress, string interfaceName)
 | 
			
		||||
    {
 | 
			
		||||
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
 | 
			
		||||
        {
 | 
			
		||||
            return $"arp -d {ipAddress}";
 | 
			
		||||
        }
 | 
			
		||||
        else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
 | 
			
		||||
        {
 | 
			
		||||
            return string.IsNullOrWhiteSpace(interfaceName)
 | 
			
		||||
                ? $"arp -d {ipAddress}"
 | 
			
		||||
                : $"arp -d {ipAddress} -i {interfaceName}";
 | 
			
		||||
        }
 | 
			
		||||
        else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
 | 
			
		||||
        {
 | 
			
		||||
            return string.IsNullOrWhiteSpace(interfaceName)
 | 
			
		||||
                ? $"arp -d {ipAddress}"
 | 
			
		||||
                : $"arp -d {ipAddress} ifscope {interfaceName}";
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            throw new PlatformNotSupportedException("不支持的操作系统平台");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 获取 ARP 清空命令
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    private static string GetArpClearCommand()
 | 
			
		||||
    {
 | 
			
		||||
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
 | 
			
		||||
        {
 | 
			
		||||
            return "arp -d *";
 | 
			
		||||
        }
 | 
			
		||||
        else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
 | 
			
		||||
        {
 | 
			
		||||
            return "ip neigh flush all";
 | 
			
		||||
        }
 | 
			
		||||
        else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
 | 
			
		||||
        {
 | 
			
		||||
            return "arp -d -a";
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            throw new PlatformNotSupportedException("不支持的操作系统平台");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 获取 ARP 查询命令
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    private static string GetArpQueryCommand(string ipAddress)
 | 
			
		||||
    {
 | 
			
		||||
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
 | 
			
		||||
        {
 | 
			
		||||
            return $"arp -a {ipAddress}";
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            return $"arp -n {ipAddress}";
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 执行系统命令
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="command">命令</param>
 | 
			
		||||
    /// <returns>命令执行结果</returns>
 | 
			
		||||
    private static async Task<CommandResult> ExecuteCommandAsync(string command)
 | 
			
		||||
    {
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            ProcessStartInfo processInfo;
 | 
			
		||||
 | 
			
		||||
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
 | 
			
		||||
            {
 | 
			
		||||
                processInfo = new ProcessStartInfo
 | 
			
		||||
                {
 | 
			
		||||
                    FileName = "cmd.exe",
 | 
			
		||||
                    Arguments = $"/c {command}",
 | 
			
		||||
                    RedirectStandardOutput = true,
 | 
			
		||||
                    RedirectStandardError = true,
 | 
			
		||||
                    UseShellExecute = false,
 | 
			
		||||
                    CreateNoWindow = true
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                processInfo = new ProcessStartInfo
 | 
			
		||||
                {
 | 
			
		||||
                    FileName = "/bin/bash",
 | 
			
		||||
                    Arguments = $"-c \"{command}\"",
 | 
			
		||||
                    RedirectStandardOutput = true,
 | 
			
		||||
                    RedirectStandardError = true,
 | 
			
		||||
                    UseShellExecute = false,
 | 
			
		||||
                    CreateNoWindow = true
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            using var process = new Process { StartInfo = processInfo };
 | 
			
		||||
            process.Start();
 | 
			
		||||
 | 
			
		||||
            var output = await process.StandardOutput.ReadToEndAsync();
 | 
			
		||||
            var error = await process.StandardError.ReadToEndAsync();
 | 
			
		||||
 | 
			
		||||
            await process.WaitForExitAsync();
 | 
			
		||||
 | 
			
		||||
            return new CommandResult
 | 
			
		||||
            {
 | 
			
		||||
                IsSuccess = process.ExitCode == 0,
 | 
			
		||||
                Output = output,
 | 
			
		||||
                Error = error,
 | 
			
		||||
                ExitCode = process.ExitCode
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
        catch (Exception ex)
 | 
			
		||||
        {
 | 
			
		||||
            return new CommandResult
 | 
			
		||||
            {
 | 
			
		||||
                IsSuccess = false,
 | 
			
		||||
                Error = ex.Message,
 | 
			
		||||
                ExitCode = -1
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 解析 ARP 记录行
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="line">ARP 记录行</param>
 | 
			
		||||
    /// <returns>解析后的 ARP 记录</returns>
 | 
			
		||||
    private static ArpEntry? ParseArpEntry(string line)
 | 
			
		||||
    {
 | 
			
		||||
        if (string.IsNullOrWhiteSpace(line))
 | 
			
		||||
            return null;
 | 
			
		||||
 | 
			
		||||
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
 | 
			
		||||
        {
 | 
			
		||||
            return ParseWindowsArpEntry(line);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            return ParseUnixArpEntry(line);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 解析 Windows ARP 记录
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    private static ArpEntry? ParseWindowsArpEntry(string line)
 | 
			
		||||
    {
 | 
			
		||||
        // Windows arp -a 输出格式: IP地址 物理地址 类型
 | 
			
		||||
        var pattern = @"(\d+\.\d+\.\d+\.\d+)\s+([a-fA-F0-9-]{17})\s+(\w+)";
 | 
			
		||||
        var match = Regex.Match(line, pattern);
 | 
			
		||||
 | 
			
		||||
        if (match.Success)
 | 
			
		||||
        {
 | 
			
		||||
            return new ArpEntry
 | 
			
		||||
            {
 | 
			
		||||
                IpAddress = match.Groups[1].Value,
 | 
			
		||||
                MacAddress = match.Groups[2].Value.Replace('-', ':'),
 | 
			
		||||
                Type = match.Groups[3].Value
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 解析 Unix/Linux ARP 记录
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    private static ArpEntry? ParseUnixArpEntry(string line)
 | 
			
		||||
    {
 | 
			
		||||
        // Unix/Linux arp -a 输出格式: hostname (ip) at mac [ether] on interface
 | 
			
		||||
        var pattern = @"(\S+)\s+\((\d+\.\d+\.\d+\.\d+)\)\s+at\s+([a-fA-F0-9:]{17})\s+\[(\w+)\]\s+on\s+(\S+)";
 | 
			
		||||
        var match = Regex.Match(line, pattern);
 | 
			
		||||
 | 
			
		||||
        if (match.Success)
 | 
			
		||||
        {
 | 
			
		||||
            return new ArpEntry
 | 
			
		||||
            {
 | 
			
		||||
                Hostname = match.Groups[1].Value,
 | 
			
		||||
                IpAddress = match.Groups[2].Value,
 | 
			
		||||
                MacAddress = match.Groups[3].Value,
 | 
			
		||||
                Type = match.Groups[4].Value,
 | 
			
		||||
                Interface = match.Groups[5].Value
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 匹配简单格式: ip mac interface
 | 
			
		||||
        var simplePattern = @"(\d+\.\d+\.\d+\.\d+)\s+([a-fA-F0-9:]{17})\s+(\S+)";
 | 
			
		||||
        var simpleMatch = Regex.Match(line, simplePattern);
 | 
			
		||||
 | 
			
		||||
        if (simpleMatch.Success)
 | 
			
		||||
        {
 | 
			
		||||
            return new ArpEntry
 | 
			
		||||
            {
 | 
			
		||||
                IpAddress = simpleMatch.Groups[1].Value,
 | 
			
		||||
                MacAddress = simpleMatch.Groups[2].Value,
 | 
			
		||||
                Interface = simpleMatch.Groups[3].Value
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// ARP 记录条目
 | 
			
		||||
/// </summary>
 | 
			
		||||
public class ArpEntry
 | 
			
		||||
{
 | 
			
		||||
    public string Hostname { get; set; } = string.Empty;
 | 
			
		||||
    public string IpAddress { get; set; } = string.Empty;
 | 
			
		||||
    public string MacAddress { get; set; } = string.Empty;
 | 
			
		||||
    public string Type { get; set; } = string.Empty;
 | 
			
		||||
    public string Interface { get; set; } = string.Empty;
 | 
			
		||||
 | 
			
		||||
    public override string ToString()
 | 
			
		||||
    {
 | 
			
		||||
        return $"{IpAddress} -> {MacAddress} ({Interface})";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// 命令执行结果
 | 
			
		||||
/// </summary>
 | 
			
		||||
public class CommandResult
 | 
			
		||||
{
 | 
			
		||||
    public bool IsSuccess { get; set; }
 | 
			
		||||
    public string Output { get; set; } = string.Empty;
 | 
			
		||||
    public string Error { get; set; } = string.Empty;
 | 
			
		||||
    public int ExitCode { get; set; }
 | 
			
		||||
}
 | 
			
		||||
@@ -585,242 +585,6 @@ public class UDPServer
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 强制进行ARP刷新,防止后续传输时造成影响
 | 
			
		||||
        // FlushArpEntry(ipAddr);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 跨平台ARP缓存刷新
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="ipAddr">目标IP地址</param>
 | 
			
		||||
    private void FlushArpEntry(string ipAddr)
 | 
			
		||||
    {
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            // 验证IP地址格式
 | 
			
		||||
            if (!IPAddress.TryParse(ipAddr, out var _))
 | 
			
		||||
            {
 | 
			
		||||
                logger.Warn($"Invalid IP address format: {ipAddr}");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            ExecuteArpFlush(ipAddr);
 | 
			
		||||
        }
 | 
			
		||||
        catch (Exception ex)
 | 
			
		||||
        {
 | 
			
		||||
            logger.Error($"Error during ARP cache flush for {ipAddr}: {ex.Message}");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 使用Ping类重新刷新ARP缓存
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="ipAddr">目标IP地址</param>
 | 
			
		||||
    private async void RefreshArpWithPing(string ipAddr)
 | 
			
		||||
    {
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            using var ping = new Ping();
 | 
			
		||||
            var options = new PingOptions
 | 
			
		||||
            {
 | 
			
		||||
                DontFragment = true,
 | 
			
		||||
                Ttl = 32,
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            // 创建32字节的数据包
 | 
			
		||||
            byte[] buffer = new byte[32];
 | 
			
		||||
            for (int i = 0; i < buffer.Length; i++)
 | 
			
		||||
            {
 | 
			
		||||
                buffer[i] = (byte)(i % 256);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // 异步发送ping,100ms超时
 | 
			
		||||
            var reply = await ping.SendPingAsync(ipAddr, 100, buffer, options);
 | 
			
		||||
 | 
			
		||||
            if (reply.Status == IPStatus.Success)
 | 
			
		||||
            {
 | 
			
		||||
                logger.Debug($"ARP cache refreshed successfully for {ipAddr} (RTT: {reply.RoundtripTime}ms)");
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                logger.Warn($"Ping to {ipAddr} failed with status: {reply.Status}, but ARP entry should still be updated");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        catch (Exception ex)
 | 
			
		||||
        {
 | 
			
		||||
            logger.Error($"Error refreshing ARP with ping for {ipAddr}: {ex.Message}");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 执行ARP刷新流程:先删除ARP条目,再用ping重新刷新
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="ipAddr">目标IP地址</param>
 | 
			
		||||
    private void ExecuteArpFlush(string ipAddr)
 | 
			
		||||
    {
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            // 第一步:删除ARP条目
 | 
			
		||||
            bool deleteSuccess = DeleteArpEntry(ipAddr);
 | 
			
		||||
 | 
			
		||||
            if (deleteSuccess)
 | 
			
		||||
            {
 | 
			
		||||
                logger.Debug($"ARP entry deleted successfully for {ipAddr}");
 | 
			
		||||
 | 
			
		||||
                // 第二步:使用Ping类重新刷新ARP缓存
 | 
			
		||||
                RefreshArpWithPing(ipAddr);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                logger.Warn($"Failed to delete ARP entry for {ipAddr}, but continuing with ping refresh");
 | 
			
		||||
                // 即使删除失败,也尝试ping刷新
 | 
			
		||||
                RefreshArpWithPing(ipAddr);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        catch (Exception ex)
 | 
			
		||||
        {
 | 
			
		||||
            logger.Error($"Failed to execute ARP flush for {ipAddr}: {ex.Message}");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 删除ARP条目
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="ipAddr">目标IP地址</param>
 | 
			
		||||
    /// <returns>是否成功删除</returns>
 | 
			
		||||
    private bool DeleteArpEntry(string ipAddr)
 | 
			
		||||
    {
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            string command;
 | 
			
		||||
            string arguments;
 | 
			
		||||
 | 
			
		||||
            if (OperatingSystem.IsWindows())
 | 
			
		||||
            {
 | 
			
		||||
                // Windows: arp -d <ip>
 | 
			
		||||
                command = "arp";
 | 
			
		||||
                arguments = $"-d {ipAddr}";
 | 
			
		||||
            }
 | 
			
		||||
            else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
 | 
			
		||||
            {
 | 
			
		||||
                // Linux/macOS: 优先使用 ip 命令删除
 | 
			
		||||
                if (IsCommandAvailable("ip"))
 | 
			
		||||
                {
 | 
			
		||||
                    command = "ip";
 | 
			
		||||
                    arguments = $"neigh del {ipAddr}";
 | 
			
		||||
                }
 | 
			
		||||
                else if (IsCommandAvailable("arp"))
 | 
			
		||||
                {
 | 
			
		||||
                    command = "arp";
 | 
			
		||||
                    arguments = $"-d {ipAddr}";
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    logger.Warn("Neither 'ip' nor 'arp' command is available for ARP entry deletion");
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                logger.Warn($"Unsupported operating system for ARP entry deletion");
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return ExecuteCommand(command, arguments, $"delete ARP entry for {ipAddr}");
 | 
			
		||||
        }
 | 
			
		||||
        catch (Exception ex)
 | 
			
		||||
        {
 | 
			
		||||
            logger.Error($"Error deleting ARP entry for {ipAddr}: {ex.Message}");
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 检查系统命令是否可用
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="command">命令名称</param>
 | 
			
		||||
    /// <returns>命令是否可用</returns>
 | 
			
		||||
    private bool IsCommandAvailable(string command)
 | 
			
		||||
    {
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            var process = new System.Diagnostics.Process
 | 
			
		||||
            {
 | 
			
		||||
                StartInfo = new System.Diagnostics.ProcessStartInfo
 | 
			
		||||
                {
 | 
			
		||||
                    FileName = OperatingSystem.IsWindows() ? "where" : "which",
 | 
			
		||||
                    Arguments = command,
 | 
			
		||||
                    UseShellExecute = false,
 | 
			
		||||
                    RedirectStandardOutput = true,
 | 
			
		||||
                    CreateNoWindow = true
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            process.Start();
 | 
			
		||||
            process.WaitForExit(1000); // 1秒超时
 | 
			
		||||
            return process.ExitCode == 0;
 | 
			
		||||
        }
 | 
			
		||||
        catch
 | 
			
		||||
        {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 执行系统命令
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="command">命令</param>
 | 
			
		||||
    /// <param name="arguments">参数</param>
 | 
			
		||||
    /// <param name="operation">操作描述</param>
 | 
			
		||||
    /// <returns>是否成功执行</returns>
 | 
			
		||||
    private bool ExecuteCommand(string command, string arguments, string operation)
 | 
			
		||||
    {
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            var process = new System.Diagnostics.Process
 | 
			
		||||
            {
 | 
			
		||||
                StartInfo = new System.Diagnostics.ProcessStartInfo
 | 
			
		||||
                {
 | 
			
		||||
                    FileName = command,
 | 
			
		||||
                    Arguments = arguments,
 | 
			
		||||
                    UseShellExecute = false,
 | 
			
		||||
                    RedirectStandardOutput = true,
 | 
			
		||||
                    RedirectStandardError = true,
 | 
			
		||||
                    CreateNoWindow = true
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            process.Start();
 | 
			
		||||
 | 
			
		||||
            // 设置超时时间,避免进程挂起
 | 
			
		||||
            if (process.WaitForExit(5000)) // 5秒超时
 | 
			
		||||
            {
 | 
			
		||||
                var output = process.StandardOutput.ReadToEnd();
 | 
			
		||||
                var error = process.StandardError.ReadToEnd();
 | 
			
		||||
 | 
			
		||||
                if (process.ExitCode == 0)
 | 
			
		||||
                {
 | 
			
		||||
                    logger.Debug($"Command executed successfully: {operation}");
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    logger.Warn($"Command failed: {operation}. Exit code: {process.ExitCode}, Error: {error}");
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                process.Kill();
 | 
			
		||||
                logger.Warn($"Command timed out: {operation}");
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        catch (Exception ex)
 | 
			
		||||
        {
 | 
			
		||||
            logger.Error($"Failed to execute command for {operation}: {ex.Message}");
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user