根据此链接:using System.Net.NetworkInformation, is there a way to bind a ping to a specific interface? ICMP无法绑定到网络接口(与基于套接字的东西不同):
ICMP不是基于套接字的。 ping将根据路由表发送到适当的端口。https://stackoverflow.com/editing-help
但我看不出任何正确的方法来获取有关“pinger”的信息。至少,在shell命令中,我可以指定源IP地址,但不能在我使用Ping类时。
我尝试以编程方式执行一些traceroutes以获取Ping路由中涉及的IP地址,但我没有得到网络接口的IP地址(我猜它来自我无法将TTL设置为0的事实)。
有关如何确定哪个网络接口用于某个ping的任何想法? (或指定用于ping的网络接口的方法)。
答案 0 :(得分:3)
i know this is a old question but i found a solution and want to share it.
我在CodeProject上发布了这里是链接: http://www.codeproject.com/Questions/828234/Ping-over-specific-Interface-with-IcmpSendEchoEx?loginkey=false
编辑:
因此解决方案是在Iphlpapi.dll中使用IcmpSendEcho2Ex函数。
此函数使用接口ipaddress来确定应该在哪个接口上发送ping。
链接包括p调用和包装函数输出的回复类。
codeproject中的代码:
public static PingReply Send(IPAddress srcAddress, IPAddress destAddress, int timeout = 5000, byte[] buffer = null, PingOptions po = null)
{
if (destAddress == null || destAddress.AddressFamily != AddressFamily.InterNetwork || destAddress.Equals(IPAddress.Any))
throw new ArgumentException();
//Defining pinvoke args
var source = srcAddress == null ? 0 : BitConverter.ToUInt32(srcAddress.GetAddressBytes(), 0);
var destination = BitConverter.ToUInt32(destAddress.GetAddressBytes(), 0);
var sendbuffer = buffer ?? new byte[] {};
var options = new Interop.Option
{
Ttl = (po == null ? (byte) 255 : (byte) po.Ttl),
Flags = (po == null ? (byte) 0 : po.DontFragment ? (byte) 0x02 : (byte) 0) //0x02
};
var fullReplyBufferSize = Interop.ReplyMarshalLength + sendbuffer.Length; //Size of Reply struct and the transmitted buffer length.
var allocSpace = Marshal.AllocHGlobal(fullReplyBufferSize); // unmanaged allocation of reply size. TODO Maybe should be allocated on stack
try
{
DateTime start = DateTime.Now;
var nativeCode = Interop.IcmpSendEcho2Ex(
Interop.IcmpHandle, //_In_ HANDLE IcmpHandle,
default(IntPtr), //_In_opt_ HANDLE Event,
default(IntPtr), //_In_opt_ PIO_APC_ROUTINE ApcRoutine,
default(IntPtr), //_In_opt_ PVOID ApcContext
source, //_In_ IPAddr SourceAddress,
destination, //_In_ IPAddr DestinationAddress,
sendbuffer, //_In_ LPVOID RequestData,
(short) sendbuffer.Length, //_In_ WORD RequestSize,
ref options, //_In_opt_ PIP_OPTION_INFORMATION RequestOptions,
allocSpace, //_Out_ LPVOID ReplyBuffer,
fullReplyBufferSize, //_In_ DWORD ReplySize,
timeout //_In_ DWORD Timeout
);
TimeSpan duration = DateTime.Now - start;
var reply = (Interop.Reply) Marshal.PtrToStructure(allocSpace, typeof (Interop.Reply)); // Parse the beginning of reply memory to reply struct
byte[] replyBuffer = null;
if (sendbuffer.Length != 0)
{
replyBuffer = new byte[sendbuffer.Length];
Marshal.Copy(allocSpace + Interop.ReplyMarshalLength, replyBuffer, 0, sendbuffer.Length); //copy the rest of the reply memory to managed byte[]
}
if (nativeCode == 0) //Means that native method is faulted.
return new PingReply(nativeCode, reply.Status, new IPAddress(reply.Address), duration);
else
return new PingReply(nativeCode, reply.Status, new IPAddress(reply.Address), reply.RoundTripTime, replyBuffer);
}
finally
{
Marshal.FreeHGlobal(allocSpace); //free allocated space
}
}
/// <summary>Interoperability Helper
/// <see cref="http://msdn.microsoft.com/en-us/library/windows/desktop/bb309069(v=vs.85).aspx" />
/// </summary>
private static class Interop
{
private static IntPtr? icmpHandle;
private static int? _replyStructLength;
/// <summary>Returns the application legal icmp handle. Should be close by IcmpCloseHandle
/// <see cref="http://msdn.microsoft.com/en-us/library/windows/desktop/aa366045(v=vs.85).aspx" />
/// </summary>
public static IntPtr IcmpHandle
{
get
{
if (icmpHandle == null)
{
icmpHandle = IcmpCreateFile();
//TODO Close Icmp Handle appropiate
}
return icmpHandle.GetValueOrDefault();
}
}
/// <summary>Returns the the marshaled size of the reply struct.</summary>
public static int ReplyMarshalLength
{
get
{
if (_replyStructLength == null)
{
_replyStructLength = Marshal.SizeOf(typeof (Reply));
}
return _replyStructLength.GetValueOrDefault();
}
}
[DllImport("Iphlpapi.dll", SetLastError = true)]
private static extern IntPtr IcmpCreateFile();
[DllImport("Iphlpapi.dll", SetLastError = true)]
private static extern bool IcmpCloseHandle(IntPtr handle);
[DllImport("Iphlpapi.dll", SetLastError = true)]
public static extern uint IcmpSendEcho2Ex(IntPtr icmpHandle, IntPtr Event, IntPtr apcroutine, IntPtr apccontext, UInt32 sourceAddress, UInt32 destinationAddress, byte[] requestData, short requestSize, ref Option requestOptions, IntPtr replyBuffer, int replySize, int timeout);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct Option
{
public byte Ttl;
public readonly byte Tos;
public byte Flags;
public readonly byte OptionsSize;
public readonly IntPtr OptionsData;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct Reply
{
public readonly UInt32 Address;
public readonly int Status;
public readonly int RoundTripTime;
public readonly short DataSize;
public readonly short Reserved;
public readonly IntPtr DataPtr;
public readonly Option Options;
}
}
[Serializable]
public class PingReply
{
private readonly byte[] _buffer = null;
private readonly IPAddress _ipAddress = null;
private readonly uint _nativeCode = 0;
private readonly TimeSpan _roundTripTime = TimeSpan.Zero;
private readonly IPStatus _status = IPStatus.Unknown;
private Win32Exception _exception;
internal PingReply(uint nativeCode, int replystatus, IPAddress ipAddress, TimeSpan duration)
{
_nativeCode = nativeCode;
_ipAddress = ipAddress;
if (Enum.IsDefined(typeof (IPStatus), replystatus))
_status = (IPStatus) replystatus;
}
internal PingReply(uint nativeCode, int replystatus, IPAddress ipAddress, int roundTripTime, byte[] buffer)
{
_nativeCode = nativeCode;
_ipAddress = ipAddress;
_roundTripTime = TimeSpan.FromMilliseconds(roundTripTime);
_buffer = buffer;
if (Enum.IsDefined(typeof (IPStatus), replystatus))
_status = (IPStatus) replystatus;
}
/// <summary>Native result from <code>IcmpSendEcho2Ex</code>.</summary>
public uint NativeCode
{
get { return _nativeCode; }
}
public IPStatus Status
{
get { return _status; }
}
/// <summary>The source address of the reply.</summary>
public IPAddress IpAddress
{
get { return _ipAddress; }
}
public byte[] Buffer
{
get { return _buffer; }
}
public TimeSpan RoundTripTime
{
get { return _roundTripTime; }
}
/// <summary>Resolves the <code>Win32Exception</code> from native code</summary>
public Win32Exception Exception
{
get
{
if (Status != IPStatus.Success)
return _exception ?? (_exception = new Win32Exception((int) NativeCode, Status.ToString()));
else
return null;
}
}
public override string ToString()
{
if (Status == IPStatus.Success)
return Status + " from " + IpAddress + " in " + RoundTripTime + " ms with " + Buffer.Length + " bytes";
else if (Status != IPStatus.Unknown)
return Status + " from " + IpAddress;
else
return Exception.Message + " from " + IpAddress;
}
}
答案 1 :(得分:0)
Christian Sack 提供的解决方案正是我所需要的。下面是我如何使用 Christian 提供的代码来允许使用 NIC 卡的名称从给定的源 IP ping 目标 IP。
<块引用>我创建了一个名为 IpSupport 的新静态类,并向其中添加了以下两个辅助方法。然后我从他的帖子中添加了 Christian 的所有代码。完整的类稍后显示。
public static bool PingIpFromNic(string ipToPing, string nicName)
{
var sourceIpStr = GetIpOfNicFromName(nicName);
if (sourceIpStr == "")
{
MessageBox.Show($"Unable to find an ip for the nic name of {nicName}");
return false;
}
var p = Send(
srcAddress: IPAddress.Parse(sourceIpStr),
destAddress: IPAddress.Parse(ipToPing));
return p.Status == IPStatus.Success;
}
public static string GetIpOfNicFromName(string nicName)
{
string ip = "";
var adapters = NetworkInterface.GetAllNetworkInterfaces();
foreach (var adapter in adapters)
{
if (!string.Equals(adapter.Name, nicName, StringComparison.CurrentCultureIgnoreCase)) continue;
foreach (var uni in adapter.GetIPProperties().UnicastAddresses)
{
// Return the first one found
return uni.Address.ToString();
}
}
return ip;
}
<块引用>
这是完整的课程。
namespace Helpers.ChristianSack
{
public static class IpSupport
{
/// <summary>
/// Pass in the IP you want to ping as a string along with the name of the NIC on your machine that
/// you want to send the ping from.
/// </summary>
/// <param name="ipToPing">The destination IP as a string ex. '10.10.10.1'</param>
/// <param name="nicName">The name of the NIC ex. 'LECO Hardware'. Non-case sensitive.</param>
/// <returns></returns>
public static bool PingIpFromNic(string ipToPing, string nicName)
{
var sourceIpStr = GetIpOfNicFromName(nicName);
if (sourceIpStr == "")
{
MessageBox.Show($"Unable to find an ip for the nic name of {nicName}");
return false;
}
var p = Send(
srcAddress: IPAddress.Parse(sourceIpStr),
destAddress: IPAddress.Parse(ipToPing));
return p.Status == IPStatus.Success;
}
/// <summary>
/// Pass in the name of a NIC on your machine and this method will return the IPV4 address of it.
/// </summary>
/// <param name="nicName">The name of the NIC you want the IP of ex. 'TE Hardware'</param>
/// <returns></returns>
public static string GetIpOfNicFromName(string nicName)
{
var adapters = NetworkInterface.GetAllNetworkInterfaces();
foreach (var adapter in adapters)
{
// Ignoring case in NIC name
if (!string.Equals(adapter.Name, nicName, StringComparison.CurrentCultureIgnoreCase)) continue;
foreach (var uni in adapter.GetIPProperties().UnicastAddresses)
{
// Return the first one found
return uni.Address.ToString();
}
}
return "";
}
public static PingReply Send(IPAddress srcAddress, IPAddress destAddress,
int timeout = 5000,
byte[] buffer = null, PingOptions po = null)
{
if (destAddress == null || destAddress.AddressFamily != AddressFamily.InterNetwork ||
destAddress.Equals(IPAddress.Any))
throw new ArgumentException();
//Defining pinvoke args
var source = srcAddress == null ? 0 : BitConverter.ToUInt32(srcAddress.GetAddressBytes(), 0);
var destination = BitConverter.ToUInt32(destAddress.GetAddressBytes(), 0);
var sendBuffer = buffer ?? new byte[] { };
var options = new Interop.Option
{
Ttl = (po == null ? (byte)255 : (byte)po.Ttl),
Flags = (po == null ? (byte)0 : po.DontFragment ? (byte)0x02 : (byte)0) //0x02
};
var fullReplyBufferSize =
Interop.ReplyMarshalLength +
sendBuffer.Length; //Size of Reply struct and the transmitted buffer length.
var allocSpace =
Marshal.AllocHGlobal(
fullReplyBufferSize); // unmanaged allocation of reply size. TODO Maybe should be allocated on stack
try
{
var start = DateTime.Now;
var nativeCode = Interop.IcmpSendEcho2Ex(
Interop.IcmpHandle, //_In_ HANDLE IcmpHandle,
Event: default(IntPtr), //_In_opt_ HANDLE Event,
apcRoutine: default(IntPtr), //_In_opt_ PIO_APC_ROUTINE ApcRoutine,
apcContext: default(IntPtr), //_In_opt_ PVOID ApcContext
source, //_In_ IPAddr SourceAddress,
destination, //_In_ IPAddr DestinationAddress,
sendBuffer, //_In_ LPVOID RequestData,
(short)sendBuffer.Length, //_In_ WORD RequestSize,
ref options, //_In_opt_ PIP_OPTION_INFORMATION RequestOptions,
replyBuffer: allocSpace, //_Out_ LPVOID ReplyBuffer,
fullReplyBufferSize, //_In_ DWORD ReplySize,
timeout //_In_ DWORD Timeout
);
var duration = DateTime.Now - start;
var reply = (Interop.Reply)Marshal.PtrToStructure(allocSpace,
typeof(Interop.Reply)); // Parse the beginning of reply memory to reply struct
byte[] replyBuffer = null;
if (sendBuffer.Length != 0)
{
replyBuffer = new byte[sendBuffer.Length];
Marshal.Copy(allocSpace + Interop.ReplyMarshalLength, replyBuffer, 0,
sendBuffer.Length); //copy the rest of the reply memory to managed byte[]
}
if (nativeCode == 0) //Means that native method is faulted.
return new PingReply(nativeCode, reply.Status,
new IPAddress(reply.Address), duration);
else
return new PingReply(nativeCode, reply.Status,
new IPAddress(reply.Address), reply.RoundTripTime,
replyBuffer);
}
finally
{
Marshal.FreeHGlobal(allocSpace); //free allocated space
}
}
/// <summary>Interoperability Helper
/// <see cref="http://msdn.microsoft.com/en-us/library/windows/desktop/bb309069(v=vs.85).aspx" />
/// </summary>
public static class Interop
{
private static IntPtr? _icmpHandle;
private static int? _replyStructLength;
/// <summary>Returns the application legal icmp handle. Should be close by IcmpCloseHandle
/// <see cref="http://msdn.microsoft.com/en-us/library/windows/desktop/aa366045(v=vs.85).aspx" />
/// </summary>
public static IntPtr IcmpHandle
{
get
{
if (_icmpHandle == null)
{
_icmpHandle = IcmpCreateFile();
//TODO Close Icmp Handle appropriate
}
return _icmpHandle.GetValueOrDefault();
}
}
/// <summary>Returns the the marshaled size of the reply struct.</summary>
public static int ReplyMarshalLength
{
get
{
if (_replyStructLength == null)
{
_replyStructLength = Marshal.SizeOf(typeof(Reply));
}
return _replyStructLength.GetValueOrDefault();
}
}
[DllImport("Iphlpapi.dll", SetLastError = true)]
private static extern IntPtr IcmpCreateFile();
[DllImport("Iphlpapi.dll", SetLastError = true)]
private static extern bool IcmpCloseHandle(IntPtr handle);
[DllImport("Iphlpapi.dll", SetLastError = true)]
public static extern uint IcmpSendEcho2Ex(IntPtr icmpHandle, IntPtr Event, IntPtr apcRoutine, IntPtr apcContext, uint sourceAddress, UInt32 destinationAddress, byte[] requestData, short requestSize, ref Option requestOptions, IntPtr replyBuffer, int replySize, int timeout);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct Option
{
public byte Ttl;
public readonly byte Tos;
public byte Flags;
public readonly byte OptionsSize;
public readonly IntPtr OptionsData;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct Reply
{
public readonly UInt32 Address;
public readonly int Status;
public readonly int RoundTripTime;
public readonly short DataSize;
public readonly short Reserved;
public readonly IntPtr DataPtr;
public readonly Option Options;
}
}
[Serializable]
public class PingReply
{
private Win32Exception _exception;
internal PingReply(uint nativeCode, int replyStatus, IPAddress ipAddress, TimeSpan duration)
{
NativeCode = nativeCode;
IpAddress = ipAddress;
if (Enum.IsDefined(typeof(IPStatus), replyStatus))
Status = (IPStatus)replyStatus;
}
internal PingReply(uint nativeCode, int replyStatus, IPAddress ipAddress, int roundTripTime, byte[] buffer)
{
NativeCode = nativeCode;
IpAddress = ipAddress;
RoundTripTime = TimeSpan.FromMilliseconds(roundTripTime);
Buffer = buffer;
if (Enum.IsDefined(typeof(IPStatus), replyStatus))
Status = (IPStatus)replyStatus;
}
/// <summary>Native result from <code>IcmpSendEcho2Ex</code>.</summary>
public uint NativeCode { get; }
public IPStatus Status { get; } = IPStatus.Unknown;
/// <summary>The source address of the reply.</summary>
public IPAddress IpAddress { get; }
public byte[] Buffer { get; }
public TimeSpan RoundTripTime { get; } = TimeSpan.Zero;
public Win32Exception Exception
{
get
{
if (Status != IPStatus.Success)
return _exception ?? (_exception = new Win32Exception((int)NativeCode, Status.ToString()));
else
return null;
}
}
public override string ToString()
{
if (Status == IPStatus.Success)
return Status + " from " + IpAddress + " in " + RoundTripTime + " ms with " + Buffer.Length + " bytes";
else if (Status != IPStatus.Unknown)
return Status + " from " + IpAddress;
else
return Exception.Message + " from " + IpAddress;
}
}
}
}
<块引用>
这是一种获取机器上所有 NIC 卡名称及其 IP 地址的方法
var adapters = NetworkInterface.GetAllNetworkInterfaces();
foreach(var adapter in adapters)
{
cmbNicNames.Items.Add(adapter.Name);
foreach (var uni in adapter.GetIPProperties().UnicastAddresses)
{
Debug.WriteLine($" IPv4 : {uni.Address}");
cmbSourceIP.Items.Add(uni.Address);
}
}
<块引用>
这是对 Christian 代码的调用。
var bSuccess = Helpers.ChristianSack.IpSupport.PingIpFromNic("10.10.10.1", "TE Hardware");