forked from robertdavidgraham/masscan
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstack-arpv4.c
executable file
·362 lines (299 loc) · 11.2 KB
/
stack-arpv4.c
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
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
/*
handle ARP
Usage #1:
At startup, we make a synchronous request for the local router.
We'll wait several seconds for a response, but abort the program
if we don't receive a response.
Usage #2:
While running, we'll need to respond to ARPs. That's because we
may be bypassing the stack of the local machine with a "spoofed"
IP address. Every so often, the local router may drop it's route
entry and re-request our address.
*/
#include "rawsock.h"
#include "rawsock-adapter.h"
#include "stack-src.h"
#include "stack-arpv4.h"
#include "stack-queue.h"
#include "string_s.h"
#include "logger.h"
#include "pixie-timer.h"
#include "proto-preprocess.h"
#include "util-checksum.h"
#define VERIFY_REMAINING(n) if (offset+(n) > max) return;
/**
* A structure representing the information parsed from an incoming
* ARP packet. Note: unlike normal programming style, this isn't
* overlayed on the incoming ARP header, but instead each field
* is parsed one-by-one and converted into this internal structure.
*/
struct ARP_IncomingRequest
{
unsigned is_valid;
unsigned opcode;
unsigned hardware_type;
unsigned protocol_type;
unsigned hardware_length;
unsigned protocol_length;
unsigned ip_src;
unsigned ip_dst;
const unsigned char *mac_src;
const unsigned char *mac_dst;
};
/****************************************************************************
****************************************************************************/
static void
proto_arp_parse(struct ARP_IncomingRequest *arp,
const unsigned char px[], unsigned offset, unsigned max)
{
/*
* parse the header
*/
VERIFY_REMAINING(8);
arp->is_valid = 0; /* not valid yet */
arp->hardware_type = px[offset]<<8 | px[offset+1];
arp->protocol_type = px[offset+2]<<8 | px[offset+3];
arp->hardware_length = px[offset+4];
arp->protocol_length = px[offset+5];
arp->opcode = px[offset+6]<<8 | px[offset+7];
offset += 8;
/* We only support IPv4 and Ethernet addresses */
if (arp->protocol_length != 4 && arp->hardware_length != 6)
return;
if (arp->protocol_type != 0x0800)
return;
if (arp->hardware_type != 1 && arp->hardware_type != 6)
return;
/*
* parse the addresses
*/
VERIFY_REMAINING(2 * arp->hardware_length + 2 * arp->protocol_length);
arp->mac_src = px+offset;
offset += arp->hardware_length;
arp->ip_src = px[offset+0]<<24 | px[offset+1]<<16 | px[offset+2]<<8 | px[offset+3];
offset += arp->protocol_length;
arp->mac_dst = px+offset;
offset += arp->hardware_length;
arp->ip_dst = px[offset+0]<<24 | px[offset+1]<<16 | px[offset+2]<<8 | px[offset+3];
//offset += arp->protocol_length;
arp->is_valid = 1;
}
/****************************************************************************
* Resolve the IP address into a MAC address. Do this synchronously, meaning,
* we'll stop and wait for the response. This is done at program startup,
* but not during then normal asynchronous operation during the scan.
****************************************************************************/
int
stack_arp_resolve(struct Adapter *adapter,
ipv4address_t my_ipv4, macaddress_t my_mac_address,
ipv4address_t your_ipv4, macaddress_t *your_mac_address)
{
unsigned char xarp_packet[64];
unsigned char *arp_packet = &xarp_packet[0];
unsigned i;
time_t start;
unsigned is_arp_notice_given = 0;
struct ARP_IncomingRequest response;
int is_delay_reported = 0;
/*
* [KLUDGE]
* If this is a VPN connection
*/
if (stack_if_datalink(adapter) == 12) {
memcpy(your_mac_address->addr, "\0\0\0\0\0\2", 6);
return 0; /* success */
}
memset(&response, 0, sizeof(response));
/* zero out bytes in packet to avoid leaking stuff in the padding
* (ARP is 42 byte packet, Ethernet is 60 byte minimum) */
memset(arp_packet, 0, sizeof(xarp_packet));
/*
* Create the request packet
*/
memcpy(arp_packet + 0, "\xFF\xFF\xFF\xFF\xFF\xFF", 6);
memcpy(arp_packet + 6, my_mac_address.addr, 6);
if (adapter->is_vlan) {
memcpy(arp_packet + 12, "\x81\x00", 2);
arp_packet[14] = (unsigned char)(adapter->vlan_id>>8);
arp_packet[15] = (unsigned char)(adapter->vlan_id&0xFF);
arp_packet += 4;
}
memcpy(arp_packet + 12, "\x08\x06", 2);
memcpy(arp_packet + 14,
"\x00\x01" /* hardware = Ethernet */
"\x08\x00" /* protocol = IPv4 */
"\x06\x04" /* MAC length = 6, IPv4 length = 4 */
"\x00\x01" /* opcode = request */
, 8);
memcpy(arp_packet + 22, my_mac_address.addr, 6);
arp_packet[28] = (unsigned char)(my_ipv4 >> 24);
arp_packet[29] = (unsigned char)(my_ipv4 >> 16);
arp_packet[30] = (unsigned char)(my_ipv4 >> 8);
arp_packet[31] = (unsigned char)(my_ipv4 >> 0);
memcpy(arp_packet + 32, "\x00\x00\x00\x00\x00\x00", 6);
arp_packet[38] = (unsigned char)(your_ipv4 >> 24);
arp_packet[39] = (unsigned char)(your_ipv4 >> 16);
arp_packet[40] = (unsigned char)(your_ipv4 >> 8);
arp_packet[41] = (unsigned char)(your_ipv4 >> 0);
/* Kludge: handle VLNA header if it exists. This is probably
* the wrong way to handle this. */
if (adapter->is_vlan)
arp_packet -= 4;
/*
* Now loop for a few seconds looking for the response
*/
rawsock_send_packet(adapter, arp_packet, 60, 1);
start = time(0);
i = 0;
for (;;) {
unsigned length;
unsigned secs;
unsigned usecs;
const unsigned char *px;
int err;
if (time(0) != start) {
start = time(0);
rawsock_send_packet(adapter, arp_packet, 60, 1);
if (i++ >= 10)
break; /* timeout */
/* It's taking too long, so notify the user */
if (!is_delay_reported) {
ipaddress_formatted_t fmt = ipv4address_fmt(your_ipv4);
LOG(0, "[+] resolving router %s with ARP (may take some time)...\n", fmt.string);
is_delay_reported = 1;
}
}
/* If we aren't getting a response back to our ARP, then print a
* status message */
if (time(0) > start+1 && !is_arp_notice_given) {
ipaddress_formatted_t fmt = ipv4address_fmt(your_ipv4);
LOG(0, "[+] arping local router %s\n", fmt.string);
is_arp_notice_given = 1;
}
err = rawsock_recv_packet(
adapter,
&length,
&secs,
&usecs,
&px);
if (err != 0)
continue;
if (adapter->is_vlan && px[17] != 6)
continue;
if (!adapter->is_vlan && px[13] != 6)
continue;
/*
* Parse the response as an ARP packet
*/
if (adapter->is_vlan)
proto_arp_parse(&response, px, 18, length);
else
proto_arp_parse(&response, px, 14, length);
/* Is this an ARP packet? */
if (!response.is_valid) {
LOG(2, "[-] arp: etype=0x%04x, not ARP\n", px[12]*256 + px[13]);
continue;
}
/* Is this an ARP "reply"? */
if (response.opcode != 2) {
LOG(2, "[-] arp: opcode=%u, not reply(2)\n", response.opcode);
continue;
}
/* Is this response directed at us? */
if (response.ip_dst != my_ipv4) {
LOG(2, "[-] arp: dst=%08x, not my ip 0x%08x\n", response.ip_dst, my_ipv4);
continue;
}
if (memcmp(response.mac_dst, my_mac_address.addr, 6) != 0)
continue;
/* Is this the droid we are looking for? */
if (response.ip_src != your_ipv4) {
ipaddress_formatted_t fmt1 = ipv4address_fmt(response.ip_src);
ipaddress_formatted_t fmt2 = ipv4address_fmt(your_ipv4);
LOG(2, "[-] arp: target=%s, not desired %s\n", fmt1.string, fmt2.string);
continue;
}
/*
* GOT IT!
* we've got a valid response, so save the results and
* return.
*/
memcpy(your_mac_address->addr, response.mac_src, 6);
{
ipaddress_formatted_t fmt1 = ipv4address_fmt(response.ip_src);
ipaddress_formatted_t fmt2 = macaddress_fmt(*your_mac_address);
LOG(1, "[+] arp: %s == %s\n", fmt1.string, fmt2.string);
}
return 0;
}
return 1;
}
/****************************************************************************
* Handle an incoming ARP request.
****************************************************************************/
int
stack_arp_incoming_request( struct stack_t *stack,
ipv4address_t my_ip, macaddress_t my_mac,
const unsigned char *px, unsigned length)
{
struct PacketBuffer *response = 0;
struct ARP_IncomingRequest request;
memset(&request, 0, sizeof(request));
/* Get a buffer for sending the response packet. This thread doesn't
* send the packet itself. Instead, it formats a packet, then hands
* that packet off to a transmit thread for later transmission. */
response = stack_get_packetbuffer(stack);
if (response == NULL)
return -1;
/* ARP packets are too short, so increase the packet size to
* the Ethernet minimum */
response->length = 60;
/* Fill the padded area with zeroes to avoid leaking data */
memset(response->px, 0, response->length);
/*
* Parse the response as an ARP packet
*/
proto_arp_parse(&request, px, 14, length);
/* Is this an ARP packet? */
if (!request.is_valid) {
LOG(2, "arp: etype=0x%04x, not ARP\n", px[12]*256 + px[13]);
return -1;
}
/* Is this an ARP "request"? */
if (request.opcode != 1) {
LOG(2, "arp: opcode=%u, not request(1)\n", request.opcode);
return -1;
}
/* Is this response directed at us? */
if (request.ip_dst != my_ip) {
LOG(2, "arp: dst=%08x, not my ip 0x%08x\n", request.ip_dst, my_ip);
return -1;
}
/*
* Create the response packet
*/
memcpy(response->px + 0, request.mac_src, 6);
memcpy(response->px + 6, my_mac.addr, 6);
memcpy(response->px + 12, "\x08\x06", 2);
memcpy(response->px + 14,
"\x00\x01" /* hardware = Ethernet */
"\x08\x00" /* protocol = IPv4 */
"\x06\x04" /* MAC length = 6, IPv4 length = 4 */
"\x00\x02" /* opcode = reply(2) */
, 8);
memcpy(response->px + 22, my_mac.addr, 6);
response->px[28] = (unsigned char)(my_ip >> 24);
response->px[29] = (unsigned char)(my_ip >> 16);
response->px[30] = (unsigned char)(my_ip >> 8);
response->px[31] = (unsigned char)(my_ip >> 0);
memcpy(response->px + 32, request.mac_src, 6);
response->px[38] = (unsigned char)(request.ip_src >> 24);
response->px[39] = (unsigned char)(request.ip_src >> 16);
response->px[40] = (unsigned char)(request.ip_src >> 8);
response->px[41] = (unsigned char)(request.ip_src >> 0);
/*
* Now queue the packet up for transmission
*/
stack_transmit_packetbuffer(stack, response);
return 0;
}