using System.Net; using System.Text; using System.Xml.Linq; namespace AmtScanner.Api.Services; public interface IAmtNetworkService { Task GetNetworkConfigAsync(string ip, string username, string password); Task SetStaticIpAsync(string ip, string username, string password, string newIp, string subnetMask, string? gateway, string? primaryDns, string? secondaryDns); Task SetDhcpModeAsync(string ip, string username, string password); } public class AmtNetworkConfig { public bool DhcpEnabled { get; set; } public string? IpAddress { get; set; } public string? SubnetMask { get; set; } public string? Gateway { get; set; } public string? PrimaryDns { get; set; } public string? SecondaryDns { get; set; } public string? MacAddress { get; set; } public bool LinkIsUp { get; set; } public bool SharedMac { get; set; } public bool IpSyncEnabled { get; set; } } public class AmtNetworkService : IAmtNetworkService { private readonly ILogger _logger; private const int AMT_PORT = 16992; // AMT_EthernetPortSettings 的 InstanceID private const string WIRED_INSTANCE_ID = "Intel(r) AMT Ethernet Port Settings 0"; public AmtNetworkService(ILogger logger) { _logger = logger; } public async Task GetNetworkConfigAsync(string ip, string username, string password) { try { // 使用 GET 请求配合 SelectorSet 获取 AMT_EthernetPortSettings var soapEnvelope = BuildGetEthernetPortSettingsRequest(ip, AMT_PORT); var response = await SendWsmanRequestAsync(ip, AMT_PORT, username, password, soapEnvelope); if (response == null) { _logger.LogWarning("无法获取 AMT_EthernetPortSettings"); return null; } _logger.LogDebug("获取到网络配置响应: {Response}", response.Length > 500 ? response[..500] + "..." : response); return ParseNetworkConfig(response); } catch (Exception ex) { _logger.LogError(ex, "获取网络配置失败: {Ip}", ip); return null; } } public async Task SetStaticIpAsync(string ip, string username, string password, string newIp, string subnetMask, string? gateway, string? primaryDns, string? secondaryDns) { try { // 首先获取当前配置 var currentConfig = await GetNetworkConfigAsync(ip, username, password); if (currentConfig == null) { _logger.LogWarning("无法获取当前配置,尝试直接设置静态IP"); } // 构建 PUT 请求设置静态 IP var soapEnvelope = BuildSetStaticIpRequest(ip, AMT_PORT, newIp, subnetMask, gateway, primaryDns, secondaryDns); var response = await SendWsmanRequestAsync(ip, AMT_PORT, username, password, soapEnvelope); if (response == null) { _logger.LogWarning("设置静态IP请求无响应"); return false; } if (response.Contains("Fault")) { _logger.LogWarning("设置静态IP返回错误: {Response}", response); return false; } return true; } catch (Exception ex) { _logger.LogError(ex, "设置静态 IP 失败: {Ip}", ip); return false; } } public async Task SetDhcpModeAsync(string ip, string username, string password) { try { var soapEnvelope = BuildSetDhcpRequest(ip, AMT_PORT); var response = await SendWsmanRequestAsync(ip, AMT_PORT, username, password, soapEnvelope); if (response == null) { _logger.LogWarning("设置DHCP请求无响应"); return false; } if (response.Contains("Fault")) { _logger.LogWarning("设置DHCP返回错误: {Response}", response); return false; } return true; } catch (Exception ex) { _logger.LogError(ex, "设置 DHCP 模式失败: {Ip}", ip); return false; } } private async Task SendWsmanRequestAsync(string ip, int port, string username, string password, string soapEnvelope) { var url = $"http://{ip}:{port}/wsman"; _logger.LogDebug("发送 WS-Man 请求到: {Url}", url); _logger.LogDebug("请求内容: {Envelope}", soapEnvelope.Length > 1000 ? soapEnvelope[..1000] + "..." : soapEnvelope); var handler = new HttpClientHandler { Credentials = new CredentialCache { { new Uri($"http://{ip}:{port}"), "Digest", new NetworkCredential(username, password) } }, PreAuthenticate = false }; using var client = new HttpClient(handler) { Timeout = TimeSpan.FromSeconds(15) }; var content = new StringContent(soapEnvelope, Encoding.UTF8, "application/soap+xml"); try { var response = await client.PostAsync(url, content); var responseContent = await response.Content.ReadAsStringAsync(); _logger.LogDebug("响应状态码: {StatusCode}", response.StatusCode); _logger.LogDebug("响应内容: {Content}", responseContent.Length > 1000 ? responseContent[..1000] + "..." : responseContent); if (response.IsSuccessStatusCode) { return responseContent; } _logger.LogWarning("WS-Management 请求失败: {StatusCode}, 响应: {Response}", response.StatusCode, responseContent); return null; } catch (Exception ex) { _logger.LogWarning("HTTP 请求异常: {Message}", ex.Message); return null; } } private static string BuildGetEthernetPortSettingsRequest(string ip, int port) { var toAddress = $"http://{ip}:{port}/wsman"; var messageId = $"uuid:{Guid.NewGuid()}"; // 使用 GET 请求配合 SelectorSet,这是 SDK 推荐的方式 return $@" {toAddress} http://intel.com/wbem/wscim/1/amt-schema/1/AMT_EthernetPortSettings http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous http://schemas.xmlsoap.org/ws/2004/09/transfer/Get 153600 {messageId} PT60.000S {WIRED_INSTANCE_ID} "; } private static string BuildSetStaticIpRequest(string ip, int port, string ipAddress, string subnetMask, string? gateway, string? primaryDns, string? secondaryDns) { var toAddress = $"http://{ip}:{port}/wsman"; var messageId = $"uuid:{Guid.NewGuid()}"; // 构建可选字段 var gatewayXml = string.IsNullOrEmpty(gateway) ? "" : $"{gateway}"; var primaryDnsXml = string.IsNullOrEmpty(primaryDns) ? "" : $"{primaryDns}"; var secondaryDnsXml = string.IsNullOrEmpty(secondaryDns) ? "" : $"{secondaryDns}"; return $@" {toAddress} http://intel.com/wbem/wscim/1/amt-schema/1/AMT_EthernetPortSettings http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous http://schemas.xmlsoap.org/ws/2004/09/transfer/Put 153600 {messageId} PT60.000S {WIRED_INSTANCE_ID} {WIRED_INSTANCE_ID} Intel(r) AMT Ethernet Port Settings false {ipAddress} {subnetMask} {gatewayXml} {primaryDnsXml} {secondaryDnsXml} "; } private static string BuildSetDhcpRequest(string ip, int port) { var toAddress = $"http://{ip}:{port}/wsman"; var messageId = $"uuid:{Guid.NewGuid()}"; return $@" {toAddress} http://intel.com/wbem/wscim/1/amt-schema/1/AMT_EthernetPortSettings http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous http://schemas.xmlsoap.org/ws/2004/09/transfer/Put 153600 {messageId} PT60.000S {WIRED_INSTANCE_ID} {WIRED_INSTANCE_ID} Intel(r) AMT Ethernet Port Settings true "; } private AmtNetworkConfig? ParseNetworkConfig(string xmlResponse) { try { var doc = XDocument.Parse(xmlResponse); // 检查是否有错误 var fault = doc.Descendants().FirstOrDefault(e => e.Name.LocalName == "Fault"); if (fault != null) { _logger.LogWarning("WS-Man 响应包含错误: {Fault}", fault.ToString()); return null; } var config = new AmtNetworkConfig { DhcpEnabled = GetBoolValue(doc, "DHCPEnabled"), IpAddress = GetStringValue(doc, "IPAddress"), SubnetMask = GetStringValue(doc, "SubnetMask"), Gateway = GetStringValue(doc, "DefaultGateway"), PrimaryDns = GetStringValue(doc, "PrimaryDNS"), SecondaryDns = GetStringValue(doc, "SecondaryDNS"), MacAddress = GetStringValue(doc, "MACAddress"), LinkIsUp = GetBoolValue(doc, "LinkIsUp"), SharedMac = GetBoolValue(doc, "SharedMAC"), IpSyncEnabled = GetBoolValue(doc, "IpSyncEnabled") }; _logger.LogDebug("解析网络配置: DHCP={Dhcp}, IP={Ip}, MAC={Mac}", config.DhcpEnabled, config.IpAddress, config.MacAddress); return config; } catch (Exception ex) { _logger.LogError(ex, "解析网络配置失败"); return null; } } private static string? GetStringValue(XDocument doc, string localName) { var element = doc.Descendants() .FirstOrDefault(e => e.Name.LocalName.Equals(localName, StringComparison.OrdinalIgnoreCase)); return element?.Value; } private static bool GetBoolValue(XDocument doc, string localName) { var value = GetStringValue(doc, localName); return string.Equals(value, "true", StringComparison.OrdinalIgnoreCase); } }