diff options
Diffstat (limited to 'src/firejail/arp.c')
-rw-r--r-- | src/firejail/arp.c | 186 |
1 files changed, 1 insertions, 185 deletions
diff --git a/src/firejail/arp.c b/src/firejail/arp.c index fb5e426b0..ddb75905f 100644 --- a/src/firejail/arp.c +++ b/src/firejail/arp.c | |||
@@ -40,6 +40,7 @@ typedef struct arp_hdr_t { | |||
40 | uint8_t target_ip[4]; | 40 | uint8_t target_ip[4]; |
41 | } ArpHdr; | 41 | } ArpHdr; |
42 | 42 | ||
43 | |||
43 | // returns 0 if the address is not in use, -1 otherwise | 44 | // returns 0 if the address is not in use, -1 otherwise |
44 | int arp_check(const char *dev, uint32_t destaddr, uint32_t srcaddr) { | 45 | int arp_check(const char *dev, uint32_t destaddr, uint32_t srcaddr) { |
45 | if (strlen(dev) > IFNAMSIZ) { | 46 | if (strlen(dev) > IFNAMSIZ) { |
@@ -286,189 +287,4 @@ uint32_t arp_assign(const char *dev, Bridge *br) { | |||
286 | return ip; | 287 | return ip; |
287 | } | 288 | } |
288 | 289 | ||
289 | // scan interface (--scan option) | ||
290 | void arp_scan(const char *dev, uint32_t ifip, uint32_t ifmask) { | ||
291 | assert(dev); | ||
292 | assert(ifip); | ||
293 | |||
294 | // printf("Scanning interface %s (%d.%d.%d.%d/%d)\n", | ||
295 | // dev, PRINT_IP(ifip & ifmask), mask2bits(ifmask)); | ||
296 | |||
297 | if (strlen(dev) > IFNAMSIZ) { | ||
298 | fprintf(stderr, "Error: invalid network device name %s\n", dev); | ||
299 | exit(1); | ||
300 | } | ||
301 | |||
302 | // find interface mac address | ||
303 | int sock; | ||
304 | if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) | ||
305 | errExit("socket"); | ||
306 | struct ifreq ifr; | ||
307 | memset(&ifr, 0, sizeof (ifr)); | ||
308 | strncpy(ifr.ifr_name, dev, IFNAMSIZ); | ||
309 | if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) | ||
310 | errExit("ioctl"); | ||
311 | close(sock); | ||
312 | uint8_t mac[6]; | ||
313 | memcpy (mac, ifr.ifr_hwaddr.sa_data, 6); | ||
314 | |||
315 | // open layer2 socket | ||
316 | if ((sock = socket(PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0) | ||
317 | errExit("socket"); | ||
318 | |||
319 | // try all possible ip addresses in ascending order | ||
320 | uint32_t range = ~ifmask + 1; // the number of potential addresses | ||
321 | // this software is not supported for /31 networks | ||
322 | if (range < 4) { | ||
323 | fprintf(stderr, "Warning: this option is not supported for /31 networks\n"); | ||
324 | close(sock); | ||
325 | return; | ||
326 | } | ||
327 | |||
328 | uint32_t dest = (ifip & ifmask) + 1; | ||
329 | uint32_t last = dest + range - 1; | ||
330 | uint32_t src = htonl(ifip); | ||
331 | |||
332 | // wait not more than one second for an answer | ||
333 | int header_printed = 0; | ||
334 | uint32_t last_ip = 0; | ||
335 | struct timeval ts; | ||
336 | ts.tv_sec = 2; // 2 seconds receive timeout | ||
337 | ts.tv_usec = 0; | ||
338 | |||
339 | while (1) { | ||
340 | fd_set rfds; | ||
341 | FD_ZERO(&rfds); | ||
342 | FD_SET(sock, &rfds); | ||
343 | fd_set wfds; | ||
344 | FD_ZERO(&wfds); | ||
345 | FD_SET(sock, &wfds); | ||
346 | int maxfd = sock; | ||
347 | |||
348 | uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc | ||
349 | memset(frame, 0, ETH_FRAME_LEN); | ||
350 | |||
351 | int nready; | ||
352 | if (dest < last) | ||
353 | nready = select(maxfd + 1, &rfds, &wfds, (fd_set *) 0, NULL); | ||
354 | else | ||
355 | nready = select(maxfd + 1, &rfds, (fd_set *) 0, (fd_set *) 0, &ts); | ||
356 | |||
357 | if (nready < 0) | ||
358 | errExit("select"); | ||
359 | |||
360 | if (nready == 0) { // timeout | ||
361 | break; | ||
362 | } | ||
363 | |||
364 | if (FD_ISSET(sock, &wfds) && dest < last) { | ||
365 | // configure layer2 socket address information | ||
366 | struct sockaddr_ll addr; | ||
367 | memset(&addr, 0, sizeof(addr)); | ||
368 | if ((addr.sll_ifindex = if_nametoindex(dev)) == 0) | ||
369 | errExit("if_nametoindex"); | ||
370 | addr.sll_family = AF_PACKET; | ||
371 | memcpy (addr.sll_addr, mac, 6); | ||
372 | addr.sll_halen = htons(6); | ||
373 | |||
374 | // build the arp packet header | ||
375 | ArpHdr hdr; | ||
376 | memset(&hdr, 0, sizeof(hdr)); | ||
377 | hdr.htype = htons(1); | ||
378 | hdr.ptype = htons(ETH_P_IP); | ||
379 | hdr.hlen = 6; | ||
380 | hdr.plen = 4; | ||
381 | hdr.opcode = htons(1); //ARPOP_REQUEST | ||
382 | memcpy(hdr.sender_mac, mac, 6); | ||
383 | memcpy(hdr.sender_ip, (uint8_t *)&src, 4); | ||
384 | uint32_t dst = htonl(dest); | ||
385 | memcpy(hdr.target_ip, (uint8_t *)&dst, 4); | ||
386 | |||
387 | // build ethernet frame | ||
388 | uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc | ||
389 | memset(frame, 0, sizeof(frame)); | ||
390 | frame[0] = frame[1] = frame[2] = frame[3] = frame[4] = frame[5] = 0xff; | ||
391 | memcpy(frame + 6, mac, 6); | ||
392 | frame[12] = ETH_P_ARP / 256; | ||
393 | frame[13] = ETH_P_ARP % 256; | ||
394 | memcpy (frame + 14, &hdr, sizeof(hdr)); | ||
395 | |||
396 | // send packet | ||
397 | int len; | ||
398 | if ((len = sendto (sock, frame, 14 + sizeof(ArpHdr), 0, (struct sockaddr *) &addr, sizeof (addr))) <= 0) | ||
399 | errExit("send"); | ||
400 | //printf("send %d bytes to %d.%d.%d.%d\n", len, PRINT_IP(dest)); | ||
401 | fflush(0); | ||
402 | dest++; | ||
403 | } | ||
404 | |||
405 | if (FD_ISSET(sock, &rfds)) { | ||
406 | // read the incoming packet | ||
407 | int len = recvfrom(sock, frame, ETH_FRAME_LEN, 0, NULL, NULL); | ||
408 | if (len < 0) { | ||
409 | perror("recvfrom"); | ||
410 | } | ||
411 | |||
412 | // parse the incoming packet | ||
413 | if ((unsigned int) len < 14 + sizeof(ArpHdr)) | ||
414 | continue; | ||
415 | |||
416 | // look only at ARP packets | ||
417 | if (frame[12] != (ETH_P_ARP / 256) || frame[13] != (ETH_P_ARP % 256)) | ||
418 | continue; | ||
419 | |||
420 | ArpHdr hdr; | ||
421 | memcpy(&hdr, frame + 14, sizeof(ArpHdr)); | ||
422 | |||
423 | if (hdr.opcode == htons(2)) { | ||
424 | // check my mac and my address | ||
425 | if (memcmp(mac, hdr.target_mac, 6) != 0) | ||
426 | continue; | ||
427 | uint32_t ip; | ||
428 | memcpy(&ip, hdr.target_ip, 4); | ||
429 | if (ip != src) | ||
430 | continue; | ||
431 | memcpy(&ip, hdr.sender_ip, 4); | ||
432 | ip = ntohl(ip); | ||
433 | |||
434 | if (ip == last_ip) // filter duplicates | ||
435 | continue; | ||
436 | last_ip = ip; | ||
437 | |||
438 | // printing | ||
439 | if (header_printed == 0) { | ||
440 | printf(" Network scan:\n"); | ||
441 | |||
442 | // print parent interface | ||
443 | if (cfg.bridge0.configured && cfg.bridge0.ip && cfg.bridge0.macvlan && | ||
444 | (cfg.bridge0.ip & cfg.bridge0.mask) == (ifip & cfg.bridge0.mask)) | ||
445 | printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n", | ||
446 | PRINT_MAC(cfg.bridge0.mac), PRINT_IP(cfg.bridge0.ip)); | ||
447 | |||
448 | if (cfg.bridge1.configured && cfg.bridge1.ip && cfg.bridge1.macvlan && | ||
449 | (cfg.bridge1.ip & cfg.bridge1.mask) == (ifip & cfg.bridge1.mask)) | ||
450 | printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n", | ||
451 | PRINT_MAC(cfg.bridge1.mac), PRINT_IP(cfg.bridge1.ip)); | ||
452 | |||
453 | if (cfg.bridge2.configured && cfg.bridge2.ip && cfg.bridge2.macvlan && | ||
454 | (cfg.bridge2.ip & cfg.bridge2.mask) == (ifip & cfg.bridge2.mask)) | ||
455 | printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n", | ||
456 | PRINT_MAC(cfg.bridge2.mac), PRINT_IP(cfg.bridge2.ip)); | ||
457 | |||
458 | if (cfg.bridge3.configured && cfg.bridge3.ip && cfg.bridge3.macvlan && | ||
459 | (cfg.bridge3.ip & cfg.bridge3.mask) == (ifip & cfg.bridge3.mask)) | ||
460 | printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n", | ||
461 | PRINT_MAC(cfg.bridge3.mac), PRINT_IP(cfg.bridge3.ip)); | ||
462 | |||
463 | header_printed = 1; | ||
464 | } | ||
465 | printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n", | ||
466 | PRINT_MAC(hdr.sender_mac), PRINT_IP(ip)); | ||
467 | } | ||
468 | } | ||
469 | } | ||
470 | |||
471 | close(sock); | ||
472 | } | ||
473 | |||
474 | 290 | ||