111 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			111 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
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
 | 
						|
{
 | 
						|
    /// <summary>
 | 
						|
    /// RawSocket的ping功能
 | 
						|
    /// </summary>
 | 
						|
    static class RawSocketPing
 | 
						|
    {
 | 
						|
        private static readonly byte[] echoRequestPacket = Convert.FromHexString("0800F6FF0100000000000000");
 | 
						|
        private static readonly byte[] icmpReceiveBuffer = new byte[72];
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// 获取是否支持
 | 
						|
        /// </summary>
 | 
						|
        public static bool IsSupported { get; private set; }
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// RawSocket的ping功能
 | 
						|
        /// </summary>
 | 
						|
        static RawSocketPing()
 | 
						|
        {
 | 
						|
            try
 | 
						|
            {
 | 
						|
                new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp).Dispose();
 | 
						|
                IsSupported = true;
 | 
						|
            }
 | 
						|
            catch (Exception)
 | 
						|
            {
 | 
						|
                IsSupported = false;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// ping目标ip
 | 
						|
        /// </summary>
 | 
						|
        /// <param name="destAddresses"></param>
 | 
						|
        /// <param name="timeWait">等待时间</param>
 | 
						|
        /// <param name="cancellationToken">取消令牌</param>
 | 
						|
        /// <returns>ping通的ip</returns>
 | 
						|
        public static async Task<HashSet<IPAddress>> PingAsync(IEnumerable<IPAddress> 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;
 | 
						|
        }
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// 循环接收任务
 | 
						|
        /// </summary>
 | 
						|
        /// <param name="socket"></param>
 | 
						|
        /// <param name="cancellationToken"></param>
 | 
						|
        /// <returns></returns>
 | 
						|
        private static async Task<HashSet<IPAddress>> ReceiveAsync(Socket socket, CancellationToken cancellationToken)
 | 
						|
        {
 | 
						|
            await Task.Yield();
 | 
						|
 | 
						|
            var hashSet = new HashSet<IPAddress>();
 | 
						|
            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;
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |