man: netsniff-ng: add section about netlink traffic debugging
[netsniff-ng.git] / staging / mopsrx_arp.c
blob0aac15234fdffc6affe43f425e98c05f1871c7b0
1 /*
2 * Mausezahn - A fast versatile traffic generator
3 * Copyright (C) 2008-2010 Herbert Haas
4 *
5 * This program is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License version 2 as published by the
7 * Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12 * details.
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
19 #include "mz.h"
20 #include "mops.h"
21 #include "cli.h"
23 // Starts an ARP RX thread for *every* device in the device_list.
24 // (Except for the loopback interface)
25 //
26 // RETURN VALUE: 0 upon success,
27 // 1 upon error.
28 //
29 int mops_rx_arp ()
31 int i;
33 for (i=0; i<device_list_entries; i++) {
34 if (mz_strcmp(device_list[i].dev, "lo", 2)==0) continue; // omit loopback!
35 if (pthread_create( &(device_list[i].arprx_thread),
36 NULL,
37 rx_arp,
38 &device_list[i])) { // give thread a pointer to that device_list entry
39 printf("xxxxxxxxxx\n");
40 return 1; // Error creating thread
41 } else {
42 if (verbose) {
43 fprintf(stderr, " Started ARP monitor on device %s.\n",
44 device_list[i].dev);
48 return 0;
52 // Thread function to receive ARP responses for a given device.
53 // Runs forever - until Mausezahn stops (see clean_up())
54 //
55 // Argument: pointer to device_struct!
56 //
57 //
58 //
59 void *rx_arp (void *arg)
61 char errbuf[PCAP_ERRBUF_SIZE];
62 struct pcap *p_arp;
63 struct bpf_program filter;
64 char filter_str[] = "arp"; // We want to analyze both requests and responses!
65 struct device_struct *dev = (struct device_struct*) arg;
67 // FYI, possible filter string is also:
68 // "eth.dst==00:05:4e:51:01:b5 and arp and arp.opcode==2";
70 p_arp = pcap_open_live (dev->dev,
71 100, // max num of bytes to read
72 1, // 1 if promiscuous mode
73 PCAP_READ_TIMEOUT_MSEC, // read timeout 'until error' (-1 = indefinitely)
74 errbuf);
76 if (p_arp == NULL) {
77 fprintf(stderr," rx_arp: [ERROR] %s\n",errbuf);
78 return NULL; // TODO: Should return pointer to error message or something similar
81 dev->p_arp = p_arp; // also assign pointer to a global which is needed for clean_up
83 if ( pcap_compile(p_arp,
84 &filter, // the compiled version of the filter
85 filter_str, // text version of filter
86 0, // 1 = optimize
87 0) // netmask
88 == -1) {
89 fprintf(stderr," rx_arp: [ERROR] Error calling pcap_compile\n");
90 return NULL;
93 if ( pcap_setfilter(p_arp, &filter) == -1) {
94 fprintf(stderr," rx_arp: [ERROR] Error setting pcap filter\n");
95 pcap_perror(p_arp, " rx_arp: ");
96 return NULL;
99 if (pcap_setdirection(p_arp, PCAP_D_IN) == -1) {
100 pcap_perror(p_arp, " rx_arp: ");
101 return NULL;
104 again:
105 pcap_loop (p_arp,
106 1, // number of packets to wait
107 got_arp_packet, // name of callback function
108 (u_char*) dev); // optional additional arguments for callback function
109 goto again;
111 pthread_exit(NULL); // destroy thread
112 return NULL;
116 void got_arp_packet (u_char *args,
117 const struct pcap_pkthdr *header, // statistics about the packet (see 'struct pcap_pkthdr')
118 const u_char *packet) // the bytestring sniffed
120 const struct struct_ethernet *ethernet;
121 const struct struct_arp *arp;
122 int size_ethernet = sizeof(struct struct_ethernet);
123 struct device_struct *dev = (struct device_struct*) args;
125 u_int8_t
126 da[6], // eth da
127 sa[6], // eth sa
128 smac[6], // source hw address
129 sip[4], // source protocol address
130 tmac[6], // target hw address
131 tip[4]; // target protocol address
132 u_int16_t op; // operation
133 u_int32_t sec, nsec;
134 u_int8_t *x;
136 // These are the most important lines here:
137 ethernet = (struct struct_ethernet*)(packet);
138 arp = (struct struct_arp*)(packet+size_ethernet);
139 sec = (u_int32_t) header->ts.tv_sec;
140 nsec = (u_int32_t) ((header->ts.tv_usec) * 1000);
142 op = arp->arp_op; // note that we don't have network byte order anymore!
143 // tmact is:
144 // 100 instead of 00:01 (request)
145 // 200 instead of 00:02 (response)
147 memcpy((void*) da, (void*) ethernet->eth_da, 6);
148 memcpy((void*) sa, (void*) ethernet->eth_sa, 6);
149 memcpy((void*) smac, (void*) arp->arp_smac, 6);
150 memcpy((void*) sip, (void*) arp->arp_sip, 4);
151 memcpy((void*) tmac, (void*) arp->arp_tmac, 6);
152 memcpy((void*) tip, (void*) arp->arp_tip, 4);
154 // Only handle the packet if it is really an ARP response!
155 ////AND if it is not sent by THIS host! (not possible, we only scan inbound!)
156 x = (u_int8_t*) & op;
157 if (*(x+1) == 0x02) {
158 // ARP RESPONSE: Update ARP table
159 arptable_add(dev, sa, da, smac, sip, sec, nsec);
160 } else if (*(x+1) == 0x01) {
161 // ARP REQUEST: Detect poisoning attacks
162 arpwatch(dev, sa, da, smac, sip, tmac, tip, sec, nsec);
168 // ARP binding consists of: sip (IP) - smac (MAC)
170 // User alert, 2 possibilities:
172 // 1. Learned new binding: does smac belong to sip?
174 // 2. Alert: Mismatch of stored versus announced sip-to-smac binding
176 // In both cases user action: [Learn] [Ignore] [Attack] [Amok Attack]
177 // Countermeasures: Mausezahn him!
179 // ALSO correct ARP tables of other hosts, especially on the default gateway
180 // that is, send arp replies with true binding
182 // Finally: Create logging message
188 // Add new entry in device-specific ARP table
189 // but first check if already existing or change.
191 // RETURN VALUE: 0 upon success
192 // 1 upon error
194 int arptable_add(struct device_struct *dev,
195 u_int8_t *sa,
196 u_int8_t *da,
197 u_int8_t *smac,
198 u_int8_t *sip,
199 u_int32_t sec,
200 u_int32_t nsec)
202 struct arp_table_struct *prev=NULL, *cur = dev->arp_table;
203 int i=0, alert=0;
205 // If SA and SMAC are different this might be a MITM !!!
206 if (compare_mac(smac, sa)) alert=1;
208 // Check if IP (sip) is already existing in arp table:
209 while (cur!=NULL) {
210 if (compare_ip(sip, cur->sip)==0) { // IP found!
211 timestamp_hms(cur->when);
212 if (da[0]==0xff) cur->bc_resp++;
213 else cur->uni_resp++;
214 if (compare_mac(smac, cur->smac)==0) {
215 // entry identical !
216 cur->sec=sec;
217 cur->nsec=nsec;
218 return 0;
219 } else {
220 // entry with other MAC address found !
221 if (cur->locked==0) {
222 cur->changed++;
223 memcpy((void*) cur->smac_prev, (void*) cur->smac, 6);
224 memcpy((void*) cur->smac, (void*) smac, 6);
225 cur->sec_prev=cur->sec;
226 cur->nsec_prev=cur->nsec;
227 cur->sec=sec;
228 cur->nsec=nsec;
229 if (alert) cur->flags|=0x02;
231 return 0;
234 prev = cur;
235 cur = cur->next;
236 i++;
239 // If we get here, then there was no entry for that IP yet!
240 // Create new arp_table entry:
241 cur = (struct arp_table_struct *) malloc(sizeof(struct arp_table_struct));
242 if (cur==NULL) return 1;
244 // Append element:
245 if (dev->arp_table==NULL) dev->arp_table = cur;
246 else prev->next = cur;
248 memcpy((void*) cur->sa, (void*) sa, 6);
249 memcpy((void*) cur->smac, (void*) smac, 6);
250 cur->smac_prev[0]=0x00;
251 cur->smac_prev[1]=0x00;
252 cur->smac_prev[2]=0x00;
253 cur->smac_prev[3]=0x00;
254 cur->smac_prev[4]=0x00;
255 cur->smac_prev[5]=0x00;
256 memcpy((void*) cur->sip, (void*) sip, 4);
257 if (da[0]==0xff) {
258 cur->bc_resp=1;
259 cur->uni_resp=0;
260 } else {
261 cur->bc_resp=0;
262 cur->uni_resp=1;
264 cur->changed=1;
265 cur->locked=0;
266 cur->dynamic=1;
267 cur->flags=0;
268 cur->sec=sec;
269 cur->nsec=nsec;
270 cur->sec_prev=0;
271 cur->nsec_prev=0;
272 cur->index=i+1; // I assume users prefer to count from 1.
273 timestamp_hms(cur->when);
274 if (alert) cur->flags|=0x02;
275 cur->next=NULL;
276 return 0;
281 // Validate ARP requests
282 int arpwatch(struct device_struct *dev,
283 u_int8_t *sa,
284 u_int8_t *da,
285 u_int8_t *smac,
286 u_int8_t *sip,
287 u_int8_t *tmac,
288 u_int8_t *tip,
289 u_int32_t sec,
290 u_int32_t nsec)
292 // Unicast requests are considered as anomaly
294 if ((da[0]&0x01)==0) { // broadcast bit NOT set?
295 fprintf(stderr, "NOTE: Non-broadcast ARP request from %02x:%02x:%02x:%02x:%02x:%02x\n",
296 sa[0], sa[1], sa[2], sa[3], sa[4], sa[5]);
299 return 0;