feat: 简单实现静态arp设置
This commit is contained in:
parent
80b6dfb38d
commit
69c7cbf4d8
|
@ -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>
|
/// <summary>
|
||||||
|
|
Loading…
Reference in New Issue