C# 如何通过 .NET 访问 ARP 协议信息?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1148778/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I access ARP-protocol information through .NET?
提问by BerggreenDK
I am trying to figure out what devices are online and offline in our LAN. I've seen many programs doing a kind of graphical network overview, presenting LAN IP and MAC addresses. I would like to know if and how those (ARP?) information can be pulled from C#/.NET ?
我想弄清楚我们局域网中有哪些设备在线和离线。我见过很多程序做一种图形网络概述,显示 LAN IP 和 MAC 地址。我想知道是否以及如何从 C#/.NET 中提取这些(ARP?)信息?
Any sample code snippets/links would be appreciated.
任何示例代码片段/链接将不胜感激。
采纳答案by Rex Logan
If you know which devices are out there you can use the Ping Class. This will allow you to at least fill up the ARP table. You can always execute ARP -a and parse the output if you have to. Here is also a link that shows how to pinvoke to call GetIpNetTable. I have included examples below of Ping Class and how to access the ARP table using the GetIpNetTable.
如果您知道有哪些设备,您可以使用Ping Class。这将允许您至少填写 ARP 表。如果需要,您始终可以执行 ARP -a 并解析输出。这里还有一个链接,显示了如何通过 pinvoke 调用GetIpNetTable。我在下面包含了 Ping 类的示例以及如何使用 GetIpNetTable 访问 ARP 表。
This is an example for the Ping Class
这是 Ping 类的示例
using System;
using System.Net;
using System.Net.NetworkInformation;
using System.Text;
namespace Examples.System.Net.NetworkInformation.PingTest
{
public class PingExample
{
// args[0] can be an IPaddress or host name.
public static void Main (string[] args)
{
Ping pingSender = new Ping ();
PingOptions options = new PingOptions ();
// Use the default Ttl value which is 128,
// but change the fragmentation behavior.
options.DontFragment = true;
// Create a buffer of 32 bytes of data to be transmitted.
string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
byte[] buffer = Encoding.ASCII.GetBytes (data);
int timeout = 120;
PingReply reply = pingSender.Send (args[0], timeout, buffer, options);
if (reply.Status == IPStatus.Success)
{
Console.WriteLine ("Address: {0}", reply.Address.ToString ());
Console.WriteLine ("RoundTrip time: {0}", reply.RoundtripTime);
Console.WriteLine ("Time to live: {0}", reply.Options.Ttl);
Console.WriteLine ("Don't fragment: {0}", reply.Options.DontFragment);
Console.WriteLine ("Buffer size: {0}", reply.Buffer.Length);
}
}
}
}
This is an example of the GetIpNetTable.
这是 GetIpNetTable 的一个示例。
using System;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Net;
namespace GetIpNetTable
{
class Program
{
// The max number of physical addresses.
const int MAXLEN_PHYSADDR = 8;
// Define the MIB_IPNETROW structure.
[StructLayout(LayoutKind.Sequential)]
struct MIB_IPNETROW
{
[MarshalAs(UnmanagedType.U4)]
public int dwIndex;
[MarshalAs(UnmanagedType.U4)]
public int dwPhysAddrLen;
[MarshalAs(UnmanagedType.U1)]
public byte mac0;
[MarshalAs(UnmanagedType.U1)]
public byte mac1;
[MarshalAs(UnmanagedType.U1)]
public byte mac2;
[MarshalAs(UnmanagedType.U1)]
public byte mac3;
[MarshalAs(UnmanagedType.U1)]
public byte mac4;
[MarshalAs(UnmanagedType.U1)]
public byte mac5;
[MarshalAs(UnmanagedType.U1)]
public byte mac6;
[MarshalAs(UnmanagedType.U1)]
public byte mac7;
[MarshalAs(UnmanagedType.U4)]
public int dwAddr;
[MarshalAs(UnmanagedType.U4)]
public int dwType;
}
// Declare the GetIpNetTable function.
[DllImport("IpHlpApi.dll")]
[return: MarshalAs(UnmanagedType.U4)]
static extern int GetIpNetTable(
IntPtr pIpNetTable,
[MarshalAs(UnmanagedType.U4)]
ref int pdwSize,
bool bOrder);
[DllImport("IpHlpApi.dll", SetLastError = true, CharSet = CharSet.Auto)]
internal static extern int FreeMibTable(IntPtr plpNetTable);
// The insufficient buffer error.
const int ERROR_INSUFFICIENT_BUFFER = 122;
static void Main(string[] args)
{
// The number of bytes needed.
int bytesNeeded = 0;
// The result from the API call.
int result = GetIpNetTable(IntPtr.Zero, ref bytesNeeded, false);
// Call the function, expecting an insufficient buffer.
if (result != ERROR_INSUFFICIENT_BUFFER)
{
// Throw an exception.
throw new Win32Exception(result);
}
// Allocate the memory, do it in a try/finally block, to ensure
// that it is released.
IntPtr buffer = IntPtr.Zero;
// Try/finally.
try
{
// Allocate the memory.
buffer = Marshal.AllocCoTaskMem(bytesNeeded);
// Make the call again. If it did not succeed, then
// raise an error.
result = GetIpNetTable(buffer, ref bytesNeeded, false);
// If the result is not 0 (no error), then throw an exception.
if (result != 0)
{
// Throw an exception.
throw new Win32Exception(result);
}
// Now we have the buffer, we have to marshal it. We can read
// the first 4 bytes to get the length of the buffer.
int entries = Marshal.ReadInt32(buffer);
// Increment the memory pointer by the size of the int.
IntPtr currentBuffer = new IntPtr(buffer.ToInt64() +
Marshal.SizeOf(typeof(int)));
// Allocate an array of entries.
MIB_IPNETROW[] table = new MIB_IPNETROW[entries];
// Cycle through the entries.
for (int index = 0; index < entries; index++)
{
// Call PtrToStructure, getting the structure information.
table[index] = (MIB_IPNETROW) Marshal.PtrToStructure(new
IntPtr(currentBuffer.ToInt64() + (index *
Marshal.SizeOf(typeof(MIB_IPNETROW)))), typeof(MIB_IPNETROW));
}
for (int index = 0; index < entries; index++)
{
MIB_IPNETROW row = table[index];
IPAddress ip=new IPAddress(BitConverter.GetBytes(row.dwAddr));
Console.Write("IP:"+ip.ToString()+"\t\tMAC:");
Console.Write( row.mac0.ToString("X2") + '-');
Console.Write( row.mac1.ToString("X2") + '-');
Console.Write( row.mac2.ToString("X2") + '-');
Console.Write( row.mac3.ToString("X2") + '-');
Console.Write( row.mac4.ToString("X2") + '-');
Console.WriteLine( row.mac5.ToString("X2"));
}
}
finally
{
// Release the memory.
FreeMibTable(buffer);
}
}
}
}
回答by jonathanpeppers
Hopefully you are trying to get the MAC Addresses from a IP Addresses and not the other way around.
希望您正在尝试从 IP 地址获取 MAC 地址,而不是相反。
Here is a link of a guy's example:
这是一个人的例子的链接:
I have not tried it, let us know how it works.
我还没有尝试过,让我们知道它是如何工作的。
回答by user8936414
Google search for "fingbox". Seems like you are trying to detect inturders?
谷歌搜索“fingbox”。似乎您正在尝试检测入侵者?
This is an intruder detector device which is totally legal and it good to know who is transporting using your wifi, on what ports. Sometimes it also shows MAC address and can ping. Has heaps of other features.
这是一个完全合法的入侵者探测器设备,很高兴知道谁在使用您的 wifi 进行传输,在哪些端口上。有时它也显示MAC地址并且可以ping通。有很多其他功能。
回答by Ben Adams
In my case, I wanted to see all ARP broadcast traffic on my network to detect devices broadcasting conflicting IP and MAC addresses on my network. I found "arp -a" polling implementations result in stale information, which makes it particularly challenging to detect IP address conflicts. For instance, two devices were responding to ARP requests, but as one response always arrived later, it would conceal the earlier response in the "arp -a" table.
就我而言,我想查看网络上的所有 ARP 广播流量,以检测网络上广播冲突 IP 和 MAC 地址的设备。我发现“arp -a”轮询实现会导致信息陈旧,这使得检测 IP 地址冲突特别具有挑战性。例如,两个设备正在响应 ARP 请求,但由于一个响应总是较晚到达,它会在“arp -a”表中隐藏较早的响应。
I used SharpPcapto create a capture service with a capture filter for ARP traffic. Then I use Packet.Netto parse the ARP packets. Finally, I log and generate alerts about IP and MAC address conflicts as the packets come in.
我使用SharpPcap创建了一个带有 ARP 流量捕获过滤器的捕获服务。然后我使用Packet.Net来解析 ARP 数据包。最后,当数据包进入时,我会记录并生成有关 IP 和 MAC 地址冲突的警报。
回答by Georg Jung
I had a similar problem and wanted to get MAC addresses, given IP addresses for an Asp.Net Core project. I wanted this to work on windows and linux too. As I found no easy to use solution I decided to create a small library called ArpLookupmyself (NuGet).
我有一个类似的问题,想获取 MAC 地址,给定一个 Asp.Net Core 项目的 IP 地址。我希望这也适用于 windows 和 linux。由于我发现没有易于使用的解决方案,因此我决定自己创建一个名为 ArpLookup的小型库(NuGet)。
It is able to assign macs to ips on windows and linux. On windows it uses the IpHlpApi.SendARP
api. On linux it reads the arp table from /proc/net/arp
. If it does not find the ip, it tries pinging it (to froce the OS doing the arp request) and looks in the arp cache again afterwards. This works without taking any dependencies (managed or unmanaged) and without starting processes and parsing their stdout etc..
它能够在 windows 和 linux 上将 macs 分配给 ips。在 Windows 上,它使用IpHlpApi.SendARP
api。在 linux 上,它从/proc/net/arp
. 如果它没有找到 ip,它会尝试 ping 它(以 froce 执行 arp 请求的操作系统),然后再次查看 arp 缓存。这不需要任何依赖(托管或非托管),也不需要启动进程和解析它们的标准输出等。
The windows version is not async, as the underlying API isn't. As the linux version is truly async (async file io for the arp cache + corefx async ping api) I decided to provide an async api anyways and return a finished Task
on windows.
Windows 版本不是异步的,因为底层 API 不是。由于 linux 版本是真正的异步(用于 arp 缓存的异步文件 io + corefx async ping api)我决定无论如何提供一个异步 api 并Task
在 Windows 上返回一个完成的。
It's quite easy to use. A real world usage example is available here.
它很容易使用。此处提供了一个真实世界的使用示例。
This is an excerptof the ARP lookup on windows to map IP -> MAC address:
这是Windows 上用于映射 IP -> MAC 地址的 ARP 查找的摘录:
internal static class ArpLookupService
{
/// <summary>
/// Call ApHlpApi.SendARP to lookup the mac address on windows-based systems.
/// </summary>
/// <exception cref="Win32Exception">If IpHlpApi.SendARP returns non-zero.</exception>
public static PhysicalAddress Lookup(IPAddress ip)
{
if (ip == null)
throw new ArgumentNullException(nameof(ip));
int destIp = BitConverter.ToInt32(ip.GetAddressBytes(), 0);
var addr = new byte[6];
var len = addr.Length;
var res = NativeMethods.SendARP(destIp, 0, addr, ref len);
if (res == 0)
return new PhysicalAddress(addr);
throw new Win32Exception(res);
}
private static class NativeMethods
{
private const string IphlpApi = "iphlpapi.dll";
[DllImport(IphlpApi, ExactSpelling = true)]
[SecurityCritical]
internal static extern int SendARP(int destinationIp, int sourceIp, byte[] macAddress, ref int physicalAddrLength);
}
}
The code achieving the same on Linux can be found here. My above-linked library adds a thin abstraction layer that provides one single cross-platform method to do arp lookups like these.
可以在此处找到在 Linux 上实现相同功能的代码。我上面链接的库添加了一个薄的抽象层,它提供了一个单一的跨平台方法来执行这样的 arp 查找。