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 &ethernetAddress,
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