using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
namespace FastGithub.Scanner
{
///
/// RawSocket的ping功能
///
static class RawSocketPing
{
private static readonly byte[] echoRequestPacket = Convert.FromHexString("0800F6FF0100000000000000");
private static readonly byte[] icmpReceiveBuffer = new byte[72];
///
/// 获取是否支持
///
public static bool IsSupported { get; private set; }
///
/// RawSocket的ping功能
///
static RawSocketPing()
{
try
{
new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp).Dispose();
IsSupported = true;
}
catch (Exception)
{
IsSupported = false;
}
}
///
/// ping目标ip
///
///
/// 等待时间
/// 取消令牌
/// ping通的ip
public static async Task> PingAsync(IEnumerable destAddresses, TimeSpan timeWait, CancellationToken cancellationToken = default)
{
using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp)
{
Ttl = 128,
DontFragment = false
};
socket.Bind(new IPEndPoint(IPAddress.Any, 0));
using var cancellationTokenSource = new CancellationTokenSource();
using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, cancellationTokenSource.Token);
var receiveTask = ReceiveAsync(socket, linkedTokenSource.Token);
var distinctDestAddresses = destAddresses.Distinct();
foreach (var address in distinctDestAddresses)
{
var remoteEndPoint = new IPEndPoint(address, 0);
await socket.SendToAsync(echoRequestPacket, SocketFlags.None, remoteEndPoint);
}
await Task.Delay(timeWait, cancellationToken);
cancellationTokenSource.Cancel();
socket.Close();
var hashSet = await receiveTask;
hashSet.IntersectWith(distinctDestAddresses);
return hashSet;
}
///
/// 循环接收任务
///
///
///
///
private static async Task> ReceiveAsync(Socket socket, CancellationToken cancellationToken)
{
await Task.Yield();
var hashSet = new HashSet();
var remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
while (cancellationToken.IsCancellationRequested == false)
{
try
{
var result = await socket.ReceiveFromAsync(icmpReceiveBuffer, SocketFlags.None, remoteEndPoint);
if (result.RemoteEndPoint is IPEndPoint ipEndPoint)
{
hashSet.Add(ipEndPoint.Address);
}
}
catch (SocketException ex) when (ex.SocketErrorCode == SocketError.OperationAborted)
{
break;
}
catch (Exception)
{
}
}
return hashSet;
}
}
}