1 /*
2     handle ARP
3 
4     Usage #1:
5         At startup, we make a synchronous request for the local router.
6         We'll wait several seconds for a response, but abort the program
7         if we don't receive a response.
8 
9     Usage #2:
10         While running, we'll need to respond to ARPs. That's because we
11         may be bypassing the stack of the local machine with a "spoofed"
12         IP address. Every so often, the local router may drop it's route
13         entry and re-request our address.
14 */
15 #include "rawsock.h"
16 #include "rawsock-adapter.h"
17 #include "stack-src.h"
18 #include "stack-arpv4.h"
19 #include "stack-queue.h"
20 #include "string_s.h"
21 #include "logger.h"
22 #include "pixie-timer.h"
23 #include "proto-preprocess.h"
24 #include "util-checksum.h"
25 
26 #define VERIFY_REMAINING(n) if (offset+(n) > max) return;
27 
28 /**
29  * A structure representing the information parsed from an incoming
30  * ARP packet. Note: unlike normal programming style, this isn't
31  * overlayed on the incoming ARP header, but instead each field
32  * is parsed one-by-one and converted into this internal structure.
33  */
34 struct ARP_IncomingRequest
35 {
36     unsigned is_valid;
37     unsigned opcode;
38     unsigned hardware_type;
39     unsigned protocol_type;
40     unsigned hardware_length;
41     unsigned protocol_length;
42     unsigned ip_src;
43     unsigned ip_dst;
44     const unsigned char *mac_src;
45     const unsigned char *mac_dst;
46 };
47 
48 
49 /****************************************************************************
50  ****************************************************************************/
51 static void
52 proto_arp_parse(struct ARP_IncomingRequest *arp,
53                 const unsigned char px[], unsigned offset, unsigned max)
54 {
55 
56     /*
57      * parse the header
58      */
59     VERIFY_REMAINING(8);
60     arp->is_valid = 0; /* not valid yet */
61 
62     arp->hardware_type = px[offset]<<8 | px[offset+1];
63     arp->protocol_type = px[offset+2]<<8 | px[offset+3];
64     arp->hardware_length = px[offset+4];
65     arp->protocol_length = px[offset+5];
66     arp->opcode = px[offset+6]<<8 | px[offset+7];
67     offset += 8;
68 
69     /* We only support IPv4 and Ethernet addresses */
70     if (arp->protocol_length != 4 && arp->hardware_length != 6)
71         return;
72     if (arp->protocol_type != 0x0800)
73         return;
74     if (arp->hardware_type != 1 && arp->hardware_type != 6)
75         return;
76 
77     /*
78      * parse the addresses
79      */
80     VERIFY_REMAINING(2 * arp->hardware_length + 2 * arp->protocol_length);
81     arp->mac_src = px+offset;
82     offset += arp->hardware_length;
83 
84     arp->ip_src = px[offset+0]<<24 | px[offset+1]<<16 | px[offset+2]<<8 | px[offset+3];
85     offset += arp->protocol_length;
86 
87     arp->mac_dst = px+offset;
88     offset += arp->hardware_length;
89 
90     arp->ip_dst = px[offset+0]<<24 | px[offset+1]<<16 | px[offset+2]<<8 | px[offset+3];
91     //offset += arp->protocol_length;
92 
93     arp->is_valid = 1;
94 }
95 
96 
97 /****************************************************************************
98  * Resolve the IP address into a MAC address. Do this synchronously, meaning,
99  * we'll stop and wait for the response. This is done at program startup,
100  * but not during then normal asynchronous operation during the scan.
101  ****************************************************************************/
102 int
103 stack_arp_resolve(struct Adapter *adapter,
104     ipv4address_t my_ipv4, macaddress_t my_mac_address,
105     ipv4address_t your_ipv4, macaddress_t *your_mac_address)
106 {
107     unsigned char xarp_packet[64];
108     unsigned char *arp_packet = &xarp_packet[0];
109     unsigned i;
110     time_t start;
111     unsigned is_arp_notice_given = 0;
112     struct ARP_IncomingRequest response;
113     int is_delay_reported = 0;
114 
115     /*
116      * [KLUDGE]
117      *  If this is a VPN connection
118      */
119     if (stack_if_datalink(adapter) == 12) {
120         memcpy(your_mac_address->addr, "\0\0\0\0\0\2", 6);
121         return 0; /* success */
122     }
123 
124     memset(&response, 0, sizeof(response));
125 
126     /* zero out bytes in packet to avoid leaking stuff in the padding
127      * (ARP is 42 byte packet, Ethernet is 60 byte minimum) */
128     memset(arp_packet, 0, sizeof(xarp_packet));
129 
130     /*
131      * Create the request packet
132      */
133     memcpy(arp_packet +  0, "\xFF\xFF\xFF\xFF\xFF\xFF", 6);
134     memcpy(arp_packet +  6, my_mac_address.addr, 6);
135 
136     if (adapter->is_vlan) {
137         memcpy(arp_packet + 12, "\x81\x00", 2);
138         arp_packet[14] = (unsigned char)(adapter->vlan_id>>8);
139         arp_packet[15] = (unsigned char)(adapter->vlan_id&0xFF);
140         arp_packet += 4;
141     }
142 
143     memcpy(arp_packet + 12, "\x08\x06", 2);
144 
145 
146     memcpy(arp_packet + 14,
147             "\x00\x01" /* hardware = Ethernet */
148             "\x08\x00" /* protocol = IPv4 */
149             "\x06\x04" /* MAC length = 6, IPv4 length = 4 */
150             "\x00\x01" /* opcode = request */
151             , 8);
152 
153     memcpy(arp_packet + 22, my_mac_address.addr, 6);
154     arp_packet[28] = (unsigned char)(my_ipv4 >> 24);
155     arp_packet[29] = (unsigned char)(my_ipv4 >> 16);
156     arp_packet[30] = (unsigned char)(my_ipv4 >>  8);
157     arp_packet[31] = (unsigned char)(my_ipv4 >>  0);
158 
159     memcpy(arp_packet + 32, "\x00\x00\x00\x00\x00\x00", 6);
160     arp_packet[38] = (unsigned char)(your_ipv4 >> 24);
161     arp_packet[39] = (unsigned char)(your_ipv4 >> 16);
162     arp_packet[40] = (unsigned char)(your_ipv4 >>  8);
163     arp_packet[41] = (unsigned char)(your_ipv4 >>  0);
164 
165 
166     /* Kludge: handle VLNA header if it exists. This is probably
167      * the wrong way to handle this. */
168     if (adapter->is_vlan)
169         arp_packet -= 4;
170 
171     /*
172      * Now loop for a few seconds looking for the response
173      */
174     rawsock_send_packet(adapter, arp_packet, 60, 1);
175     start = time(0);
176     i = 0;
177     for (;;) {
178         unsigned length;
179         unsigned secs;
180         unsigned usecs;
181         const unsigned char *px;
182         int err;
183 
184         if (time(0) != start) {
185             start = time(0);
186             rawsock_send_packet(adapter, arp_packet, 60, 1);
187             if (i++ >= 10)
188                 break; /* timeout */
189 
190             /* It's taking too long, so notify the user */
191             if (!is_delay_reported) {
192                 ipaddress_formatted_t fmt = ipv4address_fmt(your_ipv4);
193                 LOG(0, "[+] resolving router %s with ARP (may take some time)...\n", fmt.string);
194                 is_delay_reported = 1;
195             }
196         }
197 
198         /* If we aren't getting a response back to our ARP, then print a
199          * status message */
200         if (time(0) > start+1 && !is_arp_notice_given) {
201             ipaddress_formatted_t fmt = ipv4address_fmt(your_ipv4);
202             LOG(0, "[+] arping local router %s\n", fmt.string);
203             is_arp_notice_given = 1;
204         }
205 
206         err =  rawsock_recv_packet(
207                     adapter,
208                     &length,
209                     &secs,
210                     &usecs,
211                     &px);
212 
213         if (err != 0)
214             continue;
215 
216         if (adapter->is_vlan && px[17] != 6)
217             continue;
218         if (!adapter->is_vlan && px[13] != 6)
219             continue;
220 
221 
222         /*
223          * Parse the response as an ARP packet
224          */
225         if (adapter->is_vlan)
226             proto_arp_parse(&response, px, 18, length);
227         else
228             proto_arp_parse(&response, px, 14, length);
229 
230         /* Is this an ARP packet? */
231         if (!response.is_valid) {
232             LOG(2, "[-] arp: etype=0x%04x, not ARP\n", px[12]*256 + px[13]);
233             continue;
234         }
235 
236         /* Is this an ARP "reply"? */
237         if (response.opcode != 2) {
238             LOG(2, "[-] arp: opcode=%u, not reply(2)\n", response.opcode);
239             continue;
240         }
241 
242         /* Is this response directed at us? */
243         if (response.ip_dst != my_ipv4) {
244             LOG(2, "[-] arp: dst=%08x, not my ip 0x%08x\n", response.ip_dst, my_ipv4);
245             continue;
246         }
247         if (memcmp(response.mac_dst, my_mac_address.addr, 6) != 0)
248             continue;
249 
250         /* Is this the droid we are looking for? */
251         if (response.ip_src != your_ipv4) {
252             ipaddress_formatted_t fmt1 = ipv4address_fmt(response.ip_src);
253             ipaddress_formatted_t fmt2 = ipv4address_fmt(your_ipv4);
254             LOG(2, "[-] arp: target=%s, not desired %s\n", fmt1.string, fmt2.string);
255             continue;
256         }
257 
258         /*
259          * GOT IT!
260          *  we've got a valid response, so save the results and
261          *  return.
262          */
263         memcpy(your_mac_address->addr, response.mac_src, 6);
264         {
265             ipaddress_formatted_t fmt1 = ipv4address_fmt(response.ip_src);
266             ipaddress_formatted_t fmt2 = macaddress_fmt(*your_mac_address);
267             LOG(1, "[+] arp: %s == %s\n", fmt1.string, fmt2.string);
268         }
269         return 0;
270     }
271 
272     return 1;
273 }
274 
275 
276 
277 
278 /****************************************************************************
279  * Handle an incoming ARP request.
280  ****************************************************************************/
281 int
282 stack_arp_incoming_request( struct stack_t *stack,
283     ipv4address_t my_ip, macaddress_t my_mac,
284     const unsigned char *px, unsigned length)
285 {
286     struct PacketBuffer *response = 0;
287     struct ARP_IncomingRequest request;
288 
289     memset(&request, 0, sizeof(request));
290 
291 
292     /* Get a buffer for sending the response packet. This thread doesn't
293      * send the packet itself. Instead, it formats a packet, then hands
294      * that packet off to a transmit thread for later transmission. */
295     response = stack_get_packetbuffer(stack);
296     if (response == NULL)
297         return -1;
298 
299     /* ARP packets are too short, so increase the packet size to
300      * the Ethernet minimum */
301     response->length = 60;
302 
303     /* Fill the padded area with zeroes to avoid leaking data */
304     memset(response->px, 0, response->length);
305 
306     /*
307      * Parse the response as an ARP packet
308      */
309     proto_arp_parse(&request, px, 14, length);
310 
311     /* Is this an ARP packet? */
312     if (!request.is_valid) {
313         LOG(2, "arp: etype=0x%04x, not ARP\n", px[12]*256 + px[13]);
314         return -1;
315     }
316 
317     /* Is this an ARP "request"? */
318     if (request.opcode != 1) {
319         LOG(2, "arp: opcode=%u, not request(1)\n", request.opcode);
320         return -1;
321     }
322 
323     /* Is this response directed at us? */
324     if (request.ip_dst != my_ip) {
325         LOG(2, "arp: dst=%08x, not my ip 0x%08x\n", request.ip_dst, my_ip);
326         return -1;
327     }
328 
329     /*
330      * Create the response packet
331      */
332     memcpy(response->px +  0, request.mac_src, 6);
333     memcpy(response->px +  6, my_mac.addr, 6);
334     memcpy(response->px + 12, "\x08\x06", 2);
335 
336     memcpy(response->px + 14,
337             "\x00\x01" /* hardware = Ethernet */
338             "\x08\x00" /* protocol = IPv4 */
339             "\x06\x04" /* MAC length = 6, IPv4 length = 4 */
340             "\x00\x02" /* opcode = reply(2) */
341             , 8);
342 
343     memcpy(response->px + 22, my_mac.addr, 6);
344     response->px[28] = (unsigned char)(my_ip >> 24);
345     response->px[29] = (unsigned char)(my_ip >> 16);
346     response->px[30] = (unsigned char)(my_ip >>  8);
347     response->px[31] = (unsigned char)(my_ip >>  0);
348 
349     memcpy(response->px + 32, request.mac_src, 6);
350     response->px[38] = (unsigned char)(request.ip_src >> 24);
351     response->px[39] = (unsigned char)(request.ip_src >> 16);
352     response->px[40] = (unsigned char)(request.ip_src >>  8);
353     response->px[41] = (unsigned char)(request.ip_src >>  0);
354 
355 
356     /*
357      * Now queue the packet up for transmission
358      */
359     stack_transmit_packetbuffer(stack, response);
360 
361     return 0;
362 }
363