1 /*
2 * Copyright 2007-2010 Boris Kochergin. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 * DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25 #include <string>
26 #include <vector>
27 #include <unordered_map>
28
29 #include <sys/socket.h>
30 #include <sys/time.h>
31
32 #include <arpa/inet.h>
33 #ifdef __FreeBSD__
34 #include <netinet/if_ether.h>
35 #endif
36 #ifdef __linux__
37 #include <netinet/ether.h>
38 #endif
39
40 #include <dnet.h>
41 #include <pcap.h>
42 #include <pthread.h>
43 #include <stdint.h>
44
45 enum ModeType { PASSIVE_MODE, AGGRESSIVE_MODE };
46 enum AttackType { GRATUITOUS_ARP_REQUEST_ATTACK, GRATUITOUS_ARP_REPLY_ATTACK,
47 ARP_REPLY_ATTACK };
48 enum GratuitousARPType { ARP_REQUEST, ARP_REPLY };
49
50 struct Interface {
51 size_t index;
52 pthread_t thread;
53 std::string name;
54 pcap_t *descriptor;
55 std::string replyName;
56 pcap_t *replyDescriptor;
57 ModeType mode;
58 std::unordered_map <uint32_t, std::string> pairs;
59 };
60
61 struct ARPCorrection {
62 Interface *interface;
63 /*
64 * While, from a programming perspective, it might seem more convenient to
65 * use an std::string for "sha", we may be storing a lot of these structures
66 * in memory, so using a character array both lowers our memory requirements
67 * and allows us to actually measure how much memory an instance of this
68 * structure will use.
69 */
70 char sha[6];
71 uint32_t spa;
72 timeval attackTime;
73 };
74
75 /* Returns a pointer to the source address of an Ethernet frame. */
getEthernetSourceAddress(const u_char * packet)76 const char *getEthernetSourceAddress(const u_char *packet) {
77 return (const char*)(packet + ETHER_ADDR_LEN);
78 }
79
80 /* Returns a pointer to the destination address of an Ethernet frame. */
getEthernetDestinationAddress(const u_char * packet)81 const char *getEthernetDestinationAddress(const u_char *packet) {
82 return (const char*)packet;
83 }
84
85 /*
86 * Returns a pointer to the SHA (sender hardware address) field of an ARP
87 * packet.
88 */
getARPSHA(const u_char * packet)89 const u_char *getARPSHA(const u_char *packet) {
90 return packet + 22;
91 }
92
93 /*
94 * Returns a pointer to the SPA (sender protocol address) field of an ARP
95 * packet.
96 */
getARPSPA(const u_char * packet)97 const uint32_t *getARPSPA(const u_char *packet) {
98 return (const uint32_t*)(packet + 28);
99 }
100
101 /*
102 * Returns a pointer to the THA (target hardware address) field of an ARP
103 * packet.
104 */
getARPTHA(const u_char * packet)105 const u_char* getARPTHA(const u_char *packet) {
106 return packet + 32;
107 }
108
109 /*
110 * Returns a pointer to the TPA (target protocol address) field of an ARP
111 * packet.
112 */
getARPTPA(const u_char * packet)113 const uint32_t *getARPTPA(const u_char *packet) {
114 return (const uint32_t*)(packet + 38);
115 }
116
117 /*
118 * Returns the Ethernet address of the "interfaceName" interface upon success,
119 * or "" upon failure.
120 */
getEthernetAddress(const std::string interfaceName)121 std::string getEthernetAddress(const std::string interfaceName) {
122 intf_t *intf;
123 intf_entry interface;
124 intf = intf_open();
125 if (intf == NULL) {
126 return "";
127 }
128 interface.intf_len = sizeof(interface);
129 strncpy(interface.intf_name, interfaceName.c_str(), INTF_NAME_LEN);
130 if (intf_get(intf, &interface) < 0) {
131 return "";
132 }
133 intf_close(intf);
134 return std::string((const char*)interface.intf_link_addr.addr_eth.data,
135 ETHER_ADDR_LEN);
136 }
137
138 /*
139 * Sends a gratuitous ARP packet using "pcapDescriptor", with an Ethernet
140 * source address of "ethernetAddress", an Ethernet destination address of
141 * ff:ff:ff:ff:ff:ff, an ARP sender hardware address of "sha", and an ARP
142 * sender protocol address of "spa". If "type" is REQUEST, the ARP target
143 * hardware address is set to 00:00:00:00:00:00 and an ARP target protocol
144 * address is set to "spa". If "type" is REPLY, the ARP target hardware address
145 * is set to ff:ff:ff:ff:ff:ff and the ARP target protocol address is set to
146 * 0.0.0.0. Returns true upon success or false upon failure, in which case the
147 * pcap_geterr() function may be used to retrieve the error message.
148 */
sendGratuitousARPPacket(pcap_t * pcapDescriptor,const std::string & ethernetAddress,const char * sha,const uint32_t & spa,const GratuitousARPType type)149 bool sendGratuitousARPPacket(pcap_t *pcapDescriptor,
150 const std::string ðernetAddress,
151 const char *sha, const uint32_t &spa,
152 const GratuitousARPType type) {
153 /* Ethernet header. */
154 /* Destination Ethernet address. */
155 std::string packet("\xff\xff\xff\xff\xff\xff");
156 /* Source Ethernet address. */
157 packet.append(ethernetAddress);
158 /* ARP frame type. */
159 packet.append("\x08\x06", 2);
160 /* ARP packet. */
161 /* Hardware type (Ethernet). */
162 packet.append("\x00\x01", 2);
163 /* Protocol type (IP). */
164 packet.append("\x08\x00", 2);
165 /* Hardware size (6). */
166 packet.append("\x06", 1);
167 /* Protocol size (4). */
168 packet.append("\x04", 1);
169 /* Opcode. */
170 switch (type) {
171 /* Request. */
172 case ARP_REQUEST:
173 packet.append("\x00\x01", 2);
174 break;
175 /* Reply. */
176 case ARP_REPLY:
177 packet.append("\x00\x02", 2);
178 break;
179 }
180 /* Sender hardware address. */
181 packet.append(sha, ETHER_ADDR_LEN);
182 /* Sender protocol address. */
183 packet.append((const char*)&spa, 4);
184 switch (type) {
185 case ARP_REQUEST:
186 /* Target hardware address. */
187 packet.append("\x00\x00\x00\x00\x00\x00", ETHER_ADDR_LEN);
188 /* Target protocol address. */
189 packet.append((const char*)&spa, 4);
190 break;
191 case ARP_REPLY:
192 /* Target hardware address. */
193 packet.append("\xff\xff\xff\xff\xff\xff", ETHER_ADDR_LEN);
194 /* Target protocol address. */
195 packet.append("\x00\x00\x00\x00", 4);
196 break;
197 }
198 if (pcap_inject(pcapDescriptor, (const void*)packet.c_str(),
199 packet.length()) == -1) {
200 return false;
201 }
202 return true;
203 }
204