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