diff options
author | netblue30 <netblue30@yahoo.com> | 2016-10-30 15:54:05 -0400 |
---|---|---|
committer | netblue30 <netblue30@yahoo.com> | 2016-10-30 15:54:05 -0400 |
commit | f898290fd79e0e64d13ceef56fc5960da879d179 (patch) | |
tree | 7112345d8121d1d61f90995e09754bbfbfbf467f /src/fnet/arp.c | |
parent | Merge pull request #878 from msva/patch-1 (diff) | |
download | firejail-f898290fd79e0e64d13ceef56fc5960da879d179.tar.gz firejail-f898290fd79e0e64d13ceef56fc5960da879d179.tar.zst firejail-f898290fd79e0e64d13ceef56fc5960da879d179.zip |
major cleanup
Diffstat (limited to 'src/fnet/arp.c')
-rw-r--r-- | src/fnet/arp.c | 208 |
1 files changed, 208 insertions, 0 deletions
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 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2016 Firejail Authors | ||
3 | * | ||
4 | * This file is part of firejail project | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | #include "fnet.h" | ||
21 | #include <sys/socket.h> | ||
22 | #include <sys/ioctl.h> | ||
23 | #include <linux/if_ether.h> //TCP/IP Protocol Suite for Linux | ||
24 | #include <net/if.h> | ||
25 | #include <netinet/in.h> | ||
26 | #include <linux/ip.h> | ||
27 | #include <linux/udp.h> | ||
28 | #include <linux/tcp.h> | ||
29 | #include <linux/if_packet.h> | ||
30 | |||
31 | typedef struct arp_hdr_t { | ||
32 | uint16_t htype; | ||
33 | uint16_t ptype; | ||
34 | uint8_t hlen; | ||
35 | uint8_t plen; | ||
36 | uint16_t opcode; | ||
37 | uint8_t sender_mac[6]; | ||
38 | uint8_t sender_ip[4]; | ||
39 | uint8_t target_mac[6]; | ||
40 | uint8_t target_ip[4]; | ||
41 | } ArpHdr; | ||
42 | |||
43 | |||
44 | // scan interface (--scan option) | ||
45 | void arp_scan(const char *dev, uint32_t ifip, uint32_t ifmask) { | ||
46 | assert(dev); | ||
47 | assert(ifip); | ||
48 | |||
49 | // printf("Scanning interface %s (%d.%d.%d.%d/%d)\n", | ||
50 | // dev, PRINT_IP(ifip & ifmask), mask2bits(ifmask)); | ||
51 | |||
52 | if (strlen(dev) > IFNAMSIZ) { | ||
53 | fprintf(stderr, "Error: invalid network device name %s\n", dev); | ||
54 | exit(1); | ||
55 | } | ||
56 | |||
57 | // find interface mac address | ||
58 | int sock; | ||
59 | if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) | ||
60 | errExit("socket"); | ||
61 | struct ifreq ifr; | ||
62 | memset(&ifr, 0, sizeof (ifr)); | ||
63 | strncpy(ifr.ifr_name, dev, IFNAMSIZ); | ||
64 | if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) | ||
65 | errExit("ioctl"); | ||
66 | close(sock); | ||
67 | uint8_t mac[6]; | ||
68 | memcpy (mac, ifr.ifr_hwaddr.sa_data, 6); | ||
69 | |||
70 | // open layer2 socket | ||
71 | if ((sock = socket(PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0) | ||
72 | errExit("socket"); | ||
73 | |||
74 | // try all possible ip addresses in ascending order | ||
75 | uint32_t range = ~ifmask + 1; // the number of potential addresses | ||
76 | // this software is not supported for /31 networks | ||
77 | if (range < 4) { | ||
78 | fprintf(stderr, "Warning: this option is not supported for /31 networks\n"); | ||
79 | close(sock); | ||
80 | return; | ||
81 | } | ||
82 | |||
83 | uint32_t dest = (ifip & ifmask) + 1; | ||
84 | uint32_t last = dest + range - 1; | ||
85 | uint32_t src = htonl(ifip); | ||
86 | |||
87 | // wait not more than one second for an answer | ||
88 | int header_printed = 0; | ||
89 | uint32_t last_ip = 0; | ||
90 | struct timeval ts; | ||
91 | ts.tv_sec = 2; // 2 seconds receive timeout | ||
92 | ts.tv_usec = 0; | ||
93 | |||
94 | while (1) { | ||
95 | fd_set rfds; | ||
96 | FD_ZERO(&rfds); | ||
97 | FD_SET(sock, &rfds); | ||
98 | fd_set wfds; | ||
99 | FD_ZERO(&wfds); | ||
100 | FD_SET(sock, &wfds); | ||
101 | int maxfd = sock; | ||
102 | |||
103 | uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc | ||
104 | memset(frame, 0, ETH_FRAME_LEN); | ||
105 | |||
106 | int nready; | ||
107 | if (dest < last) | ||
108 | nready = select(maxfd + 1, &rfds, &wfds, (fd_set *) 0, NULL); | ||
109 | else | ||
110 | nready = select(maxfd + 1, &rfds, (fd_set *) 0, (fd_set *) 0, &ts); | ||
111 | |||
112 | if (nready < 0) | ||
113 | errExit("select"); | ||
114 | |||
115 | if (nready == 0) { // timeout | ||
116 | break; | ||
117 | } | ||
118 | |||
119 | if (FD_ISSET(sock, &wfds) && dest < last) { | ||
120 | // configure layer2 socket address information | ||
121 | struct sockaddr_ll addr; | ||
122 | memset(&addr, 0, sizeof(addr)); | ||
123 | if ((addr.sll_ifindex = if_nametoindex(dev)) == 0) | ||
124 | errExit("if_nametoindex"); | ||
125 | addr.sll_family = AF_PACKET; | ||
126 | memcpy (addr.sll_addr, mac, 6); | ||
127 | addr.sll_halen = htons(6); | ||
128 | |||
129 | // build the arp packet header | ||
130 | ArpHdr hdr; | ||
131 | memset(&hdr, 0, sizeof(hdr)); | ||
132 | hdr.htype = htons(1); | ||
133 | hdr.ptype = htons(ETH_P_IP); | ||
134 | hdr.hlen = 6; | ||
135 | hdr.plen = 4; | ||
136 | hdr.opcode = htons(1); //ARPOP_REQUEST | ||
137 | memcpy(hdr.sender_mac, mac, 6); | ||
138 | memcpy(hdr.sender_ip, (uint8_t *)&src, 4); | ||
139 | uint32_t dst = htonl(dest); | ||
140 | memcpy(hdr.target_ip, (uint8_t *)&dst, 4); | ||
141 | |||
142 | // build ethernet frame | ||
143 | uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc | ||
144 | memset(frame, 0, sizeof(frame)); | ||
145 | frame[0] = frame[1] = frame[2] = frame[3] = frame[4] = frame[5] = 0xff; | ||
146 | memcpy(frame + 6, mac, 6); | ||
147 | frame[12] = ETH_P_ARP / 256; | ||
148 | frame[13] = ETH_P_ARP % 256; | ||
149 | memcpy (frame + 14, &hdr, sizeof(hdr)); | ||
150 | |||
151 | // send packet | ||
152 | int len; | ||
153 | if ((len = sendto (sock, frame, 14 + sizeof(ArpHdr), 0, (struct sockaddr *) &addr, sizeof (addr))) <= 0) | ||
154 | errExit("send"); | ||
155 | //printf("send %d bytes to %d.%d.%d.%d\n", len, PRINT_IP(dest)); | ||
156 | fflush(0); | ||
157 | dest++; | ||
158 | } | ||
159 | |||
160 | if (FD_ISSET(sock, &rfds)) { | ||
161 | // read the incoming packet | ||
162 | int len = recvfrom(sock, frame, ETH_FRAME_LEN, 0, NULL, NULL); | ||
163 | if (len < 0) { | ||
164 | perror("recvfrom"); | ||
165 | } | ||
166 | |||
167 | // parse the incoming packet | ||
168 | if ((unsigned int) len < 14 + sizeof(ArpHdr)) | ||
169 | continue; | ||
170 | |||
171 | // look only at ARP packets | ||
172 | if (frame[12] != (ETH_P_ARP / 256) || frame[13] != (ETH_P_ARP % 256)) | ||
173 | continue; | ||
174 | |||
175 | ArpHdr hdr; | ||
176 | memcpy(&hdr, frame + 14, sizeof(ArpHdr)); | ||
177 | |||
178 | if (hdr.opcode == htons(2)) { | ||
179 | // check my mac and my address | ||
180 | if (memcmp(mac, hdr.target_mac, 6) != 0) | ||
181 | continue; | ||
182 | uint32_t ip; | ||
183 | memcpy(&ip, hdr.target_ip, 4); | ||
184 | if (ip != src) | ||
185 | continue; | ||
186 | memcpy(&ip, hdr.sender_ip, 4); | ||
187 | ip = ntohl(ip); | ||
188 | |||
189 | if (ip == last_ip) // filter duplicates | ||
190 | continue; | ||
191 | last_ip = ip; | ||
192 | |||
193 | // printing | ||
194 | if (header_printed == 0) { | ||
195 | printf(" Network scan:\n"); | ||
196 | header_printed = 1; | ||
197 | } | ||
198 | printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n", | ||
199 | PRINT_MAC(hdr.sender_mac), PRINT_IP(ip)); | ||
200 | } | ||
201 | } | ||
202 | } | ||
203 | |||
204 | close(sock); | ||
205 | } | ||
206 | |||
207 | |||
208 | |||