From f898290fd79e0e64d13ceef56fc5960da879d179 Mon Sep 17 00:00:00 2001 From: netblue30 Date: Sun, 30 Oct 2016 15:54:05 -0400 Subject: major cleanup --- src/fnet/arp.c | 208 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 src/fnet/arp.c (limited to 'src/fnet/arp.c') diff --git a/src/fnet/arp.c b/src/fnet/arp.c new file mode 100644 index 000000000..96684fdf9 --- /dev/null +++ b/src/fnet/arp.c @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2014-2016 Firejail Authors + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "fnet.h" +#include +#include +#include //TCP/IP Protocol Suite for Linux +#include +#include +#include +#include +#include +#include + +typedef struct arp_hdr_t { + uint16_t htype; + uint16_t ptype; + uint8_t hlen; + uint8_t plen; + uint16_t opcode; + uint8_t sender_mac[6]; + uint8_t sender_ip[4]; + uint8_t target_mac[6]; + uint8_t target_ip[4]; +} ArpHdr; + + +// scan interface (--scan option) +void arp_scan(const char *dev, uint32_t ifip, uint32_t ifmask) { + assert(dev); + assert(ifip); + +// printf("Scanning interface %s (%d.%d.%d.%d/%d)\n", +// dev, PRINT_IP(ifip & ifmask), mask2bits(ifmask)); + + if (strlen(dev) > IFNAMSIZ) { + fprintf(stderr, "Error: invalid network device name %s\n", dev); + exit(1); + } + + // find interface mac address + int sock; + if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) + errExit("socket"); + struct ifreq ifr; + memset(&ifr, 0, sizeof (ifr)); + strncpy(ifr.ifr_name, dev, IFNAMSIZ); + if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) + errExit("ioctl"); + close(sock); + uint8_t mac[6]; + memcpy (mac, ifr.ifr_hwaddr.sa_data, 6); + + // open layer2 socket + if ((sock = socket(PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0) + errExit("socket"); + + // try all possible ip addresses in ascending order + uint32_t range = ~ifmask + 1; // the number of potential addresses + // this software is not supported for /31 networks + if (range < 4) { + fprintf(stderr, "Warning: this option is not supported for /31 networks\n"); + close(sock); + return; + } + + uint32_t dest = (ifip & ifmask) + 1; + uint32_t last = dest + range - 1; + uint32_t src = htonl(ifip); + + // wait not more than one second for an answer + int header_printed = 0; + uint32_t last_ip = 0; + struct timeval ts; + ts.tv_sec = 2; // 2 seconds receive timeout + ts.tv_usec = 0; + + while (1) { + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(sock, &rfds); + fd_set wfds; + FD_ZERO(&wfds); + FD_SET(sock, &wfds); + int maxfd = sock; + + uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc + memset(frame, 0, ETH_FRAME_LEN); + + int nready; + if (dest < last) + nready = select(maxfd + 1, &rfds, &wfds, (fd_set *) 0, NULL); + else + nready = select(maxfd + 1, &rfds, (fd_set *) 0, (fd_set *) 0, &ts); + + if (nready < 0) + errExit("select"); + + if (nready == 0) { // timeout + break; + } + + if (FD_ISSET(sock, &wfds) && dest < last) { + // configure layer2 socket address information + struct sockaddr_ll addr; + memset(&addr, 0, sizeof(addr)); + if ((addr.sll_ifindex = if_nametoindex(dev)) == 0) + errExit("if_nametoindex"); + addr.sll_family = AF_PACKET; + memcpy (addr.sll_addr, mac, 6); + addr.sll_halen = htons(6); + + // build the arp packet header + ArpHdr hdr; + memset(&hdr, 0, sizeof(hdr)); + hdr.htype = htons(1); + hdr.ptype = htons(ETH_P_IP); + hdr.hlen = 6; + hdr.plen = 4; + hdr.opcode = htons(1); //ARPOP_REQUEST + memcpy(hdr.sender_mac, mac, 6); + memcpy(hdr.sender_ip, (uint8_t *)&src, 4); + uint32_t dst = htonl(dest); + memcpy(hdr.target_ip, (uint8_t *)&dst, 4); + + // build ethernet frame + uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc + memset(frame, 0, sizeof(frame)); + frame[0] = frame[1] = frame[2] = frame[3] = frame[4] = frame[5] = 0xff; + memcpy(frame + 6, mac, 6); + frame[12] = ETH_P_ARP / 256; + frame[13] = ETH_P_ARP % 256; + memcpy (frame + 14, &hdr, sizeof(hdr)); + + // send packet + int len; + if ((len = sendto (sock, frame, 14 + sizeof(ArpHdr), 0, (struct sockaddr *) &addr, sizeof (addr))) <= 0) + errExit("send"); +//printf("send %d bytes to %d.%d.%d.%d\n", len, PRINT_IP(dest)); + fflush(0); + dest++; + } + + if (FD_ISSET(sock, &rfds)) { + // read the incoming packet + int len = recvfrom(sock, frame, ETH_FRAME_LEN, 0, NULL, NULL); + if (len < 0) { + perror("recvfrom"); + } + + // parse the incoming packet + if ((unsigned int) len < 14 + sizeof(ArpHdr)) + continue; + + // look only at ARP packets + if (frame[12] != (ETH_P_ARP / 256) || frame[13] != (ETH_P_ARP % 256)) + continue; + + ArpHdr hdr; + memcpy(&hdr, frame + 14, sizeof(ArpHdr)); + + if (hdr.opcode == htons(2)) { + // check my mac and my address + if (memcmp(mac, hdr.target_mac, 6) != 0) + continue; + uint32_t ip; + memcpy(&ip, hdr.target_ip, 4); + if (ip != src) + continue; + memcpy(&ip, hdr.sender_ip, 4); + ip = ntohl(ip); + + if (ip == last_ip) // filter duplicates + continue; + last_ip = ip; + + // printing + if (header_printed == 0) { + printf(" Network scan:\n"); + header_printed = 1; + } + printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n", + PRINT_MAC(hdr.sender_mac), PRINT_IP(ip)); + } + } + } + + close(sock); +} + + + -- cgit v1.2.3-54-g00ecf