forked from dotpcap/sharppcap
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathARP.cs
223 lines (191 loc) · 8.21 KB
/
ARP.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
/*
This file is part of SharpPcap.
SharpPcap is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
SharpPcap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with SharpPcap. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Copyright 2005 Tamir Gal <[email protected]>
* Copyright 2008-2009 Chris Morgan <[email protected]>
*/
using System;
using System.Net.NetworkInformation;
namespace SharpPcap
{
/// <summary>
/// Resolves MAC addresses from IP addresses using the Address Resolution Protocol (ARP)
/// </summary>
public class ARP
{
private LibPcap.LibPcapLiveDevice _device;
/// <summary>
/// Constructs a new ARP Resolver
/// </summary>
/// <param name="device">The network device on which this resolver sends its ARP packets</param>
public ARP(LibPcap.LibPcapLiveDevice device)
{
_device = device;
}
private TimeSpan timeout = new TimeSpan(0, 0, 1);
/// <summary>
/// Timeout for a given call to Resolve()
/// </summary>
public TimeSpan Timeout
{
get
{
return timeout;
}
set
{
timeout = value;
}
}
/// <summary>
/// Resolves the MAC address of the specified IP address. The 'DeviceName' propery must be set
/// prior to using this method.
/// </summary>
/// <param name="destIP">The IP address to resolve</param>
/// <returns>The MAC address that matches to the given IP address</returns>
public PhysicalAddress Resolve(System.Net.IPAddress destIP)
{
return Resolve(destIP, null, null);
}
/// <summary>
/// Resolves the MAC address of the specified IP address
/// </summary>
/// <param name="destIP">The IP address to resolve</param>
/// <param name="localIP">The local IP address from which to send the ARP request, if null the local address will be discovered</param>
/// <param name="localMAC">The localMAC address to use, if null the local mac will be discovered</param>
/// <returns>The MAC address that matches to the given IP address or
/// null if there was a timeout</returns>
public PhysicalAddress Resolve(System.Net.IPAddress destIP,
System.Net.IPAddress localIP,
PhysicalAddress localMAC)
{
// if no local ip address is specified attempt to find one from the adapter
if (localIP == null)
{
if (_device.Addresses.Count > 0)
{
// attempt to find an ipv4 address.
// ARP is ipv4, NDP is used for ipv6
foreach(var address in _device.Addresses)
{
if(address.Addr.type == LibPcap.Sockaddr.AddressTypes.AF_INET_AF_INET6)
{
// make sure the address is ipv4
if (address.Addr.ipAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
{
localIP = address.Addr.ipAddress;
break; // break out of the foreach
}
}
}
// if we can't find either an ipv6 or an ipv4 address use the localhost address
if(localIP == null)
{
localIP = System.Net.IPAddress.Parse("127.0.0.1");
}
}
}
// if no local mac address is specified attempt to find one from the device
if(localMAC == null)
{
foreach(var address in _device.Addresses)
{
if(address.Addr.type == LibPcap.Sockaddr.AddressTypes.HARDWARE)
{
localMAC = address.Addr.hardwareAddress;
}
}
}
if(localIP == null)
{
throw new System.InvalidOperationException("Unable to find local ip address");
}
if(localMAC == null)
{
throw new System.InvalidOperationException("Unable to find local mac address");
}
//Build a new ARP request packet
var request = BuildRequest(destIP, localMAC, localIP);
//create a "tcpdump" filter for allowing only arp replies to be read
String arpFilter = "arp and ether dst " + localMAC.ToString();
//open the device with 20ms timeout
_device.Open(DeviceMode.Promiscuous, 20);
//set the filter
_device.Filter = arpFilter;
// set a last request time that will trigger sending the
// arp request immediately
var lastRequestTime = DateTime.FromBinary(0);
var requestInterval = new TimeSpan(0, 0, 1);
PacketDotNet.ArpPacket arpPacket = null;
// attempt to resolve the address with the current timeout
var timeoutDateTime = DateTime.Now + Timeout;
while(DateTime.Now < timeoutDateTime)
{
if(requestInterval < (DateTime.Now - lastRequestTime))
{
// inject the packet to the wire
_device.SendPacket(request);
lastRequestTime = DateTime.Now;
}
//read the next packet from the network
var reply = _device.GetNextPacket();
if(reply == null)
{
continue;
}
// parse the packet
var packet = PacketDotNet.Packet.ParsePacket(reply.LinkLayerType, reply.Data);
// is this an arp packet?
arpPacket = packet.Extract<PacketDotNet.ArpPacket>();
if(arpPacket == null)
{
continue;
}
//if this is the reply we're looking for, stop
if(arpPacket.SenderProtocolAddress.Equals(destIP))
{
break;
}
}
// free the device
_device.Close();
// the timeout happened
if(DateTime.Now >= timeoutDateTime)
{
return null;
} else
{
//return the resolved MAC address
return arpPacket.SenderHardwareAddress;
}
}
private PacketDotNet.Packet BuildRequest(System.Net.IPAddress destinationIP,
PhysicalAddress localMac,
System.Net.IPAddress localIP)
{
// an arp packet is inside of an ethernet packet
var ethernetPacket = new PacketDotNet.EthernetPacket(localMac,
PhysicalAddress.Parse("FF-FF-FF-FF-FF-FF"),
PacketDotNet.EthernetType.Arp);
var arpPacket = new PacketDotNet.ArpPacket(PacketDotNet.ArpOperation.Request,
PhysicalAddress.Parse("00-00-00-00-00-00"),
destinationIP,
localMac,
localIP);
// the arp packet is the payload of the ethernet packet
ethernetPacket.PayloadPacket = arpPacket;
return ethernetPacket;
}
}
}