You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
450 lines
15 KiB
450 lines
15 KiB
using Apewer.Internals.Interop;
|
|
using Apewer.Network;
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Net;
|
|
using System.Net.NetworkInformation;
|
|
using System.Net.Sockets;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
|
|
namespace Apewer
|
|
{
|
|
|
|
/// <summary></summary>
|
|
public class NetworkUtility
|
|
{
|
|
|
|
#region UDP
|
|
|
|
/// <summary>唤醒局域网中拥有指定 MAC 地址的设备。</summary>
|
|
/// <param name="mac">被唤醒设备的 MAC 地址,必须是长度为 6 的字节数组。</param>
|
|
public static void WakeOnLan(byte[] mac)
|
|
{
|
|
if (mac.Length != 6) return;
|
|
|
|
var uc = new System.Net.Sockets.UdpClient();
|
|
uc.Connect(IPAddress.Broadcast, 65535);
|
|
|
|
var pack = new List<byte>();
|
|
|
|
// 前 6 字节为 0xFF。
|
|
for (int i = 0; i < 6; i++) pack.Add(255);
|
|
|
|
// 目标 MAC 地址重复 16 次。
|
|
for (int i = 0; i < 16; i++)
|
|
{
|
|
for (int j = 0; j < 6; j++) pack.Add(mac[j]);
|
|
}
|
|
|
|
// 发送 102 字节数据。
|
|
uc.Send(pack.ToArray(), pack.Count);
|
|
|
|
uc.Close();
|
|
}
|
|
|
|
/// <summary>从 NTP 服务器获取 UTC 时间。</summary>
|
|
/// <remarks>
|
|
/// Worldwide: pool.ntp.org<br/>
|
|
/// Asia: asia.pool.ntp.org<br/>
|
|
/// Europe: europe.pool.ntp.org<br/>
|
|
/// North: America north-america.pool.ntp.org<br/>
|
|
/// Oceania: oceania.pool.ntp.org<br/>
|
|
/// South America: south-america.pool.ntp.org<br/>
|
|
/// Windows: time.windows.com<br/>
|
|
/// Windows: time.nist.gov<br/>
|
|
/// China: us.ntp.org.cn<br/>
|
|
/// China: edu.ntp.org.cn<br/>
|
|
/// </remarks>
|
|
public static DateTime GetUtcFromNtp(string server = "pool.ntp.org", int port = 123, int timeout = 1000)
|
|
{
|
|
try
|
|
{
|
|
var addresses = Dns.GetHostEntry(server).AddressList;
|
|
if (addresses.Length > 0)
|
|
{
|
|
var endpoint = new IPEndPoint(addresses[0], port);
|
|
return GetUtcFromNtp(endpoint, timeout);
|
|
}
|
|
}
|
|
catch { }
|
|
return ClockUtility.Zero;
|
|
}
|
|
|
|
/// <summary>从 NTP 服务器获取 UTC 时间。</summary>
|
|
public static DateTime GetUtcFromNtp(IPEndPoint endpoint, int timeout = 1000)
|
|
{
|
|
try
|
|
{
|
|
var request = new byte[48];
|
|
request[0] = 0x1B;
|
|
|
|
var response = new byte[48];
|
|
response[0] = 0x1B;
|
|
|
|
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
|
socket.Connect(endpoint);
|
|
socket.ReceiveTimeout = timeout;
|
|
socket.Send(request);
|
|
socket.Receive(response);
|
|
socket.Close();
|
|
|
|
const byte replytime = 40;
|
|
ulong secondspart = BitConverter.ToUInt32(response, replytime);
|
|
ulong secondsfraction = BitConverter.ToUInt32(response, replytime + 4);
|
|
secondspart = SwapEndian(secondspart);
|
|
secondsfraction = SwapEndian(secondsfraction);
|
|
ulong milliseconds = (secondspart * 1000) + ((secondsfraction * 1000) / 0x100000000UL);
|
|
|
|
var utc = (new DateTime(1900, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).AddMilliseconds(milliseconds);
|
|
return utc;
|
|
}
|
|
catch { }
|
|
return ClockUtility.Zero;
|
|
}
|
|
|
|
private static uint SwapEndian(ulong x)
|
|
{
|
|
var a = ((x & 0x000000ff) << 24);
|
|
var b = ((x & 0x0000ff00) << 8);
|
|
var c = ((x & 0x00ff0000) >> 8);
|
|
var d = ((x & 0xff000000) >> 24);
|
|
return (uint)(a + b + c + d);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ARP
|
|
|
|
/// <summary>发送 ARP 请求,获取目标 IP 地址对应设备的 MAC 地址,MAC 格式为 01-23-45-67-89-AB。</summary>
|
|
/// <param name="ip">目标 IP 地址。</param>
|
|
/// <remarks>注:<br />仅 Windows 可用。</remarks>
|
|
/// <returns>MAC 地址。</returns>
|
|
public static string SendARP(string ip)
|
|
{
|
|
if (!string.IsNullOrEmpty(ip))
|
|
{
|
|
try
|
|
{
|
|
var ipa = IPAddress.Parse(ip);
|
|
uint dip = BitConverter.ToUInt32(ipa.GetAddressBytes(), 0);
|
|
ulong mac = 0;
|
|
uint len = 6;
|
|
uint err = IpHlpApi.SendARP(dip, 0, ref mac, ref len);
|
|
byte[] bytes = BitConverter.GetBytes(mac);
|
|
return BitConverter.ToString(bytes, 0, 6);
|
|
}
|
|
catch { }
|
|
}
|
|
return "";
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Puny Code
|
|
|
|
/// <summary></summary>
|
|
public static string ToPunyCode(string chinese)
|
|
{
|
|
if (string.IsNullOrEmpty(chinese)) return "";
|
|
try { return new IdnMapping().GetAscii(chinese); }
|
|
catch { return chinese; }
|
|
}
|
|
|
|
/// <summary></summary>
|
|
public static string FromPunyCode(string punycode)
|
|
{
|
|
if (string.IsNullOrEmpty(punycode)) return "";
|
|
try { return new IdnMapping().GetUnicode(punycode); }
|
|
catch { return punycode; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IP
|
|
|
|
/// <summary>获取本地计算机的计算机名。</summary>
|
|
public static string LocalHost
|
|
{
|
|
get
|
|
{
|
|
var hn = Dns.GetHostName();
|
|
return string.IsNullOrEmpty(hn) ? "" : hn;
|
|
}
|
|
}
|
|
|
|
/// <summary>本地计算机的 IP 地址。</summary>
|
|
public static List<string> LocalIP
|
|
{
|
|
get
|
|
{
|
|
var list = new List<string>();
|
|
var he = Dns.GetHostEntry(Dns.GetHostName());
|
|
foreach (var ip in he.AddressList)
|
|
{
|
|
list.Add(ip.ToString());
|
|
}
|
|
return list;
|
|
}
|
|
}
|
|
|
|
/// <summary>判断 IPv4 地址格式是否正确。</summary>
|
|
public static bool IsIP(string ipv4)
|
|
{
|
|
try
|
|
{
|
|
if (string.IsNullOrEmpty(ipv4)) return false;
|
|
|
|
var split = ipv4.Split('.');
|
|
if (split.Length != 4) return false;
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
var n = Convert.ToInt32(split[i]);
|
|
if (n < 0 || n > 255) return false;
|
|
if (n.ToString() != split[i]) return false;
|
|
}
|
|
return true;
|
|
}
|
|
catch { }
|
|
return false;
|
|
}
|
|
|
|
/// <summary>对目标地址进行解析。</summary>
|
|
public static string Resolve(string host)
|
|
{
|
|
try
|
|
{
|
|
if (IsIP(host))
|
|
{
|
|
var ip = IPAddress.Parse(host);
|
|
var he = Dns.GetHostEntry(ip);
|
|
return he.HostName;
|
|
}
|
|
else
|
|
{
|
|
var ip = "";
|
|
var dn = host.ToLower();
|
|
var he = Dns.GetHostEntry(dn);
|
|
var ts = "";
|
|
var on = he.Aliases;
|
|
he = Dns.GetHostEntry(dn);
|
|
for (int i = 0; i < on.Length; i++) ts = ts + on[i].ToString() + ",";
|
|
ts = "";
|
|
var al = he.AddressList;
|
|
for (int i = 0; i < al.Length; i++) ts = ts + al[i].ToString() + ",";
|
|
ip = ts;
|
|
if (ip.Length > 0)
|
|
{
|
|
if (ip.Substring(ip.Length - 1, 1) == ",") ip = ip.Substring(0, ip.Length - 1);
|
|
}
|
|
return ip;
|
|
}
|
|
}
|
|
catch { }
|
|
return "";
|
|
}
|
|
|
|
/// <summary>对目标地址进行解析。</summary>
|
|
private static IPHostEntry InternalResolve(string hostName)
|
|
{
|
|
if (hostName.Length <= 255 && (hostName.Length != 255 || hostName[254] == '.'))
|
|
{
|
|
var intPtr = WS2_32.gethostbyname(hostName);
|
|
if (intPtr != IntPtr.Zero) return NativeToHostEntry(intPtr);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private static IntPtr IntPtrAdd(IntPtr a, int b)
|
|
{
|
|
return (IntPtr)((long)a + b);
|
|
}
|
|
|
|
private static IPHostEntry NativeToHostEntry(IntPtr nativePointer)
|
|
{
|
|
hostent hostent = (hostent)Marshal.PtrToStructure(nativePointer, typeof(hostent));
|
|
IPHostEntry iPHostEntry = new IPHostEntry();
|
|
if (hostent.h_name != IntPtr.Zero)
|
|
{
|
|
iPHostEntry.HostName = Marshal.PtrToStringAnsi(hostent.h_name);
|
|
}
|
|
ArrayList arrayList = new ArrayList();
|
|
IntPtr intPtr = hostent.h_addr_list;
|
|
nativePointer = Marshal.ReadIntPtr(intPtr);
|
|
while (nativePointer != IntPtr.Zero)
|
|
{
|
|
int newAddress = Marshal.ReadInt32(nativePointer);
|
|
arrayList.Add(new IPAddress(newAddress));
|
|
intPtr = IntPtrAdd(intPtr, IntPtr.Size);
|
|
nativePointer = Marshal.ReadIntPtr(intPtr);
|
|
}
|
|
iPHostEntry.AddressList = new IPAddress[arrayList.Count];
|
|
arrayList.CopyTo(iPHostEntry.AddressList, 0);
|
|
arrayList.Clear();
|
|
intPtr = hostent.h_aliases;
|
|
nativePointer = Marshal.ReadIntPtr(intPtr);
|
|
while (nativePointer != IntPtr.Zero)
|
|
{
|
|
string value = Marshal.PtrToStringAnsi(nativePointer);
|
|
arrayList.Add(value);
|
|
intPtr = IntPtrAdd(intPtr, IntPtr.Size);
|
|
nativePointer = Marshal.ReadIntPtr(intPtr);
|
|
}
|
|
iPHostEntry.Aliases = new string[arrayList.Count];
|
|
arrayList.CopyTo(iPHostEntry.Aliases, 0);
|
|
return iPHostEntry;
|
|
}
|
|
|
|
/// <summary>将由字符串表示的 IPv4 地址转换为 32 位整数。</summary>
|
|
public static int GetNumber(IPAddress ipv4)
|
|
{
|
|
try
|
|
{
|
|
var ba = ipv4.GetAddressBytes();
|
|
return BitConverter.ToInt32(ba, 0);
|
|
}
|
|
catch { return 0; }
|
|
}
|
|
|
|
/// <summary>转换 IP 地址格式。</summary>
|
|
public static string GetPlainAddress(IPAddress address)
|
|
{
|
|
try { return address.ToString(); }
|
|
catch { return ""; }
|
|
}
|
|
|
|
/// <summary>转换 IP 地址格式。</summary>
|
|
public static string GetPlainAddress(IPEndPoint endpoint)
|
|
{
|
|
try { return GetPlainAddress(endpoint.Address); }
|
|
catch { return ""; }
|
|
}
|
|
|
|
/// <summary>转换 IP 地址格式。</summary>
|
|
public static IPAddress GetIPAddress(string address)
|
|
{
|
|
try { return IPAddress.Parse(address); }
|
|
catch { return new IPAddress(0); }
|
|
}
|
|
|
|
/// <summary>转换 IP 地址格式。</summary>
|
|
public static IPEndPoint GetIPEndPoint(string address, int port)
|
|
{
|
|
try { return new IPEndPoint(IPAddress.Parse(address), NumberUtility.RestrictValue(port, 0, ushort.MaxValue)); }
|
|
catch { return new IPEndPoint(0, 0); }
|
|
}
|
|
|
|
/// <summary>转换 IP 地址格式。</summary>
|
|
public static IPEndPoint GetIPEndPoint(IPAddress address, int port)
|
|
{
|
|
try { return new IPEndPoint(address, NumberUtility.RestrictValue(port, 0, ushort.MaxValue)); }
|
|
catch { return new IPEndPoint(0, 0); }
|
|
}
|
|
|
|
/// <summary>转换 IP 地址格式。</summary>
|
|
public static IPEndPoint GetIPEndPoint(EndPoint endpoint)
|
|
{
|
|
try { return (IPEndPoint)endpoint; }
|
|
catch { return new IPEndPoint(0, 0); }
|
|
}
|
|
|
|
/// <summary>判断私有 IP 地址。</summary>
|
|
public static bool FromLAN(string ipv4)
|
|
{
|
|
if (ipv4.IsEmpty()) return false;
|
|
|
|
// localhost
|
|
if (ipv4 == "::1") return true;
|
|
if (ipv4 == "127.0.0.1") return true;
|
|
|
|
// IPv4
|
|
var a = ipv4.Split('.');
|
|
if (a.Length != 4) return false;
|
|
switch (a[0])
|
|
{
|
|
case "10":
|
|
return true;
|
|
case "172":
|
|
var a1 = TextUtility.GetInt32(a[1]);
|
|
if (a1 >= 16 && a1 <= 31) return true;
|
|
break;
|
|
case "192":
|
|
if (a[1] == "168") return true;
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region HTTP
|
|
|
|
/// <summary>GET</summary>
|
|
public static HttpClient HttpGet(string url, int timeout = 30000)
|
|
{
|
|
return HttpClient.SimpleGet(url, timeout);
|
|
}
|
|
|
|
/// <summary>POST</summary>
|
|
public static HttpClient HttpPost(string url, byte[] data, int timeout = 30000, string type = "application/octet-stream")
|
|
{
|
|
return HttpClient.SimplePost(url, data, timeout, type);
|
|
}
|
|
|
|
/// <summary>POST text/plain</summary>
|
|
public static HttpClient HttpPost(string url, string text, int timeout = 30000, string type = "text/plain")
|
|
{
|
|
return HttpClient.SimpleText(url, text, timeout, type);
|
|
}
|
|
|
|
/// <summary>POST application/x-www-form-urlencoded</summary>
|
|
public static HttpClient HttpPost(string url, IDictionary<string, string> form, int timeout = 30000)
|
|
{
|
|
return HttpClient.SimpleForm(url, form, timeout);
|
|
}
|
|
|
|
/// <summary>POST application/x-www-form-urlencoded</summary>
|
|
public static HttpClient HttpPost(string url, TextSet form, int timeout = 30000)
|
|
{
|
|
return HttpClient.SimpleForm(url, form, timeout);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Port
|
|
|
|
private static List<int> ListActivePort(IPEndPoint[] endpoints)
|
|
{
|
|
var list = new List<int>(endpoints.Length);
|
|
foreach (var endpoint in endpoints)
|
|
{
|
|
var port = endpoint.Port;
|
|
if (list.Contains(port)) continue;
|
|
list.Add(port);
|
|
}
|
|
list.Sort();
|
|
list.Capacity = list.Count;
|
|
return list;
|
|
}
|
|
|
|
/// <summary>列出活动的 TCP 端口。</summary>
|
|
public static List<int> ListActiveTcpPort()
|
|
{
|
|
return ListActivePort(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners());
|
|
}
|
|
|
|
/// <summary>列出活动的 UDP 端口。</summary>
|
|
public static List<int> ListActiveUdpPort()
|
|
{
|
|
return ListActivePort(IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners());
|
|
}
|
|
|
|
#endregion
|
|
|
|
}
|
|
|
|
}
|
|
|