1 /* $Id$ */
2 /*
3 ** Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
4 ** Copyright (C) 2004-2013 Sourcefire, Inc.
5 ** Copyright (C) 2001-2004 Jeff Nathan <jeff@snort.org>
6 **
7 ** This program is free software; you can redistribute it and/or modify
8 ** it under the terms of the GNU General Public License Version 2 as
9 ** published by the Free Software Foundation.  You may not use, modify or
10 ** distribute this program under any other version of the GNU General
11 ** Public License.
12 **
13 ** This program is distributed in the hope that it will be useful,
14 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 ** GNU General Public License for more details.
17 **
18 ** You should have received a copy of the GNU General Public License
19 ** along with this program; if not, write to the Free Software
20 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 */
22 
23 /* Snort ARPspoof Preprocessor Plugin
24  *   by Jeff Nathan <jeff@snort.org>
25  *   Version 0.1.4
26  *
27  * Purpose:
28  *
29  * This preprocessor looks for anomalies in ARP traffic and attempts to
30  * maliciously overwrite  ARP cache information on hosts.
31  *
32  * Arguments:
33  *
34  * To check for unicast ARP requests use:
35  * arpspoof: -unicast
36  *
37  * WARNING: this can generate false positives as Linux systems send unicast
38  * ARP requests repetatively for entries in their cache.
39  *
40  * This plugin also takes a list of IP addresses and MAC address in the form:
41  * arpspoof_detect_host: 10.10.10.10 29:a2:9a:29:a2:9a
42  * arpspoof_detect_host: 192.168.40.1 f0:0f:00:f0:0f:00
43  * and so forth...
44  *
45  * Effect:
46  * By comparing information in the Ethernet header to the ARP frame, obvious
47  * anomalies are detected.  Also, utilizing a user supplied list of IP
48  * addresses and MAC addresses, ARP traffic appearing to have originated from
49  * any IP in that list is carefully examined by comparing the source hardware
50  * address to the user supplied hardware address.  If there is a mismatch, an
51  * alert is generated as either an ARP request or REPLY can be used to
52  * overwrite cache information on a remote host.  This should only be used for
53  * hosts/devices on the **same layer 2 segment** !!
54  *
55  * Bugs:
56  * This is a proof of concept ONLY.  It is clearly not complete.  Also, the
57  * lookup function LookupIPMacEntryByIP is in need of optimization.  The
58  * arpspoof_detect_host functionality may false alarm in redundant environments. * Also, see the comment above pertaining to Linux systems.
59  *
60  * Thanks:
61  *
62  * First and foremost Patrick Mullen who sat beside me and helped every step of
63  * the way.  Andrew Baker for graciously supplying the tougher parts of this
64  * code.  W. Richard Stevens for readable documentation and finally
65  * Marty for being a badass.  All your packets are belong to Marty.
66  *
67  */
68 
69 /*  I N C L U D E S  ************************************************/
70 #include <assert.h>
71 #include <sys/types.h>
72 #include <stdlib.h>
73 #include <string.h>
74 #include <stdio.h>
75 
76 #ifndef WIN32
77 # include <sys/time.h>
78 # include <sys/socket.h>
79 # include <netinet/in.h>
80 # include <arpa/inet.h>
81 #else
82 # include <time.h>
83 #endif
84 
85 #ifdef HAVE_CONFIG_H
86 #include "config.h"
87 #endif
88 
89 #include "generators.h"
90 #include "log.h"
91 #include "detect.h"
92 #include "decode.h"
93 #include "event.h"
94 #include "plugbase.h"
95 #include "parser.h"
96 #include "mstring.h"
97 #include "snort_debug.h"
98 #include "util.h"
99 #include "event_queue.h"
100 
101 #include "snort.h"
102 #include "profiler.h"
103 #include "sfPolicy.h"
104 #include "session_api.h"
105 
106 /*  D E F I N E S  **************************************************/
107 #define MODNAME "spp_arpspoof"
108 #define WITHUNICAST "-unicast"
109 
110 
111 /*  D A T A   S T R U C T U R E S  **********************************/
112 typedef struct _IPMacEntry
113 {
114     uint32_t ipv4_addr;
115     uint8_t  mac_addr[6];
116     uint8_t  pad[2];
117 } IPMacEntry;
118 
119 typedef struct _IPMacEntryListNode
120 {
121     IPMacEntry *ip_mac_entry;
122     struct _IPMacEntryListNode *next;
123 } IPMacEntryListNode;
124 
125 typedef struct _IPMacEntryList
126 {
127     int size;
128     IPMacEntryListNode *head;
129     IPMacEntryListNode *tail;
130 } IPMacEntryList;
131 
132 typedef struct _ArpSpoofConfig
133 {
134     int check_unicast_arp;
135     int check_overwrite;
136     IPMacEntryList *ipmel;
137 
138 } ArpSpoofConfig;
139 
140 
141 /*  G L O B A L S  **************************************************/
142 static tSfPolicyUserContextId arp_spoof_config = NULL;
143 
144 static const uint8_t bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
145 
146 #ifdef PERF_PROFILING
147 PreprocStats arpPerfStats;
148 #endif
149 
150 
151 /*  P R O T O T Y P E S  ********************************************/
152 static void ARPspoofInit(struct _SnortConfig *, char *args);
153 static void ARPspoofHostInit(struct _SnortConfig *, char *args);
154 static void ParseARPspoofArgs(ArpSpoofConfig *, char *);
155 static void ParseARPspoofHostArgs(IPMacEntryList *, char *);
156 static void DetectARPattacks(Packet *p, void *context);
157 static void ARPspoofCleanExit(int signal, void *unused);
158 static void FreeIPMacEntryList(IPMacEntryList *ip_mac_entry_list);
159 static int AddIPMacEntryToList(IPMacEntryList *ip_mac_entry_list,
160                                IPMacEntry *ip_mac_entry);
161 static IPMacEntry *LookupIPMacEntryByIP(IPMacEntryList *ip_mac_entry_list,
162                                         uint32_t ipv4_addr);
163 static void ArpSpoofFreeConfig(tSfPolicyUserContextId config);
164 
165 #ifdef DEBUG
166 static void PrintIPMacEntryList(IPMacEntryList *ip_mac_entry_list);
167 #endif
168 
169 #ifdef SNORT_RELOAD
170 static void ARPspoofReload(struct _SnortConfig *, char *, void **);
171 static void ARPspoofReloadHost(struct _SnortConfig *, char *, void **);
172 static void * ARPspoofReloadSwap(struct _SnortConfig *, void *);
173 static void ARPspoofReloadSwapFree(void *);
174 #endif
175 
176 
SetupARPspoof(void)177 void SetupARPspoof(void)
178 {
179 #ifndef SNORT_RELOAD
180     RegisterPreprocessor("arpspoof", ARPspoofInit);
181     RegisterPreprocessor("arpspoof_detect_host", ARPspoofHostInit);
182 #else
183     RegisterPreprocessor("arpspoof", ARPspoofInit, ARPspoofReload, NULL,
184                          ARPspoofReloadSwap, ARPspoofReloadSwapFree);
185     RegisterPreprocessor("arpspoof_detect_host", ARPspoofHostInit,
186                          ARPspoofReloadHost, NULL, NULL, NULL);
187 #endif
188 
189     DEBUG_WRAP(DebugMessage(DEBUG_INIT,
190             "Preprocessor: ARPspoof is setup...\n"););
191 }
192 
193 
ARPspoofInit(struct _SnortConfig * sc,char * args)194 static void ARPspoofInit(struct _SnortConfig *sc, char *args)
195 {
196     int policy_id = (int)getParserPolicy(sc);
197     ArpSpoofConfig *pDefaultPolicyConfig = NULL;
198     ArpSpoofConfig *pCurrentPolicyConfig = NULL;
199 
200     DEBUG_WRAP(DebugMessage(DEBUG_INIT,
201             "Preprocessor: ARPspoof Initialized\n"););
202 
203     if (arp_spoof_config == NULL)
204     {
205        arp_spoof_config = sfPolicyConfigCreate();
206 
207 #ifdef PERF_PROFILING
208         RegisterPreprocessorProfile("arpspoof", &arpPerfStats, 0, &totalPerfStats, NULL);
209 #endif
210 
211         AddFuncToPreprocCleanExitList(ARPspoofCleanExit, NULL, PRIORITY_LAST, PP_ARPSPOOF);
212     }
213 
214     sfPolicyUserPolicySet (arp_spoof_config, policy_id);
215     pDefaultPolicyConfig = (ArpSpoofConfig *)sfPolicyUserDataGetDefault(arp_spoof_config);
216     pCurrentPolicyConfig = (ArpSpoofConfig *)sfPolicyUserDataGetCurrent(arp_spoof_config);
217 
218     if ((policy_id != 0) && (pDefaultPolicyConfig == NULL))
219     {
220         ParseError("Arpspoof configuration: Must configure default policy "
221                    "if other policies are to be configured.");
222     }
223 
224     if (pCurrentPolicyConfig)
225     {
226         ParseError("Arpspoof can only be configured once.\n");
227     }
228 
229     pCurrentPolicyConfig = (ArpSpoofConfig *)SnortAlloc(sizeof(ArpSpoofConfig));
230     if (!pCurrentPolicyConfig)
231     {
232         ParseError("Arpspoof preprocessor: memory allocate failed.\n");
233     }
234 
235     sfPolicyUserDataSetCurrent(arp_spoof_config, pCurrentPolicyConfig);
236     /* Add arpspoof to the preprocessor function list */
237     AddFuncToPreprocList(sc, DetectARPattacks, PRIORITY_NETWORK, PP_ARPSPOOF, PROTO_BIT__ARP);
238     session_api->enable_preproc_all_ports( sc, PP_ARPSPOOF, PROTO_BIT__ARP );
239 
240     //policy independent configuration. First policy defines actual values.
241     if (policy_id != 0)
242     {
243        pCurrentPolicyConfig->check_unicast_arp =
244            ((ArpSpoofConfig *)sfPolicyUserDataGetDefault(arp_spoof_config))->check_unicast_arp;
245         return;
246     }
247 
248     /* Parse the arpspoof arguments from snort.conf */
249     ParseARPspoofArgs(pCurrentPolicyConfig, args);
250 }
251 
252 
253 /**
254  * Parse arguments passed to the arpspoof keyword.
255  *
256  * @param args preprocessor argument string
257  *
258  * @return void function
259  */
ParseARPspoofArgs(ArpSpoofConfig * config,char * args)260 static void ParseARPspoofArgs(ArpSpoofConfig *config, char *args)
261 {
262     if ((config == NULL) || (args == NULL))
263         return;
264 
265     if (strcasecmp(WITHUNICAST, args) == 0)
266         config->check_unicast_arp = 1;
267     else
268         ParseError("Invalid option to arpspoof configuration");
269 }
270 
271 
ARPspoofHostInit(struct _SnortConfig * sc,char * args)272 static void ARPspoofHostInit(struct _SnortConfig *sc, char *args)
273 {
274     tSfPolicyId policy_id = getParserPolicy(sc);
275     ArpSpoofConfig *pPolicyConfig = NULL;
276 
277     if (arp_spoof_config == NULL)
278     {
279         ParseError("Please activate arpspoof before trying to "
280                    "use arpspoof_detect_host.");
281     }
282 
283     sfPolicyUserPolicySet(arp_spoof_config, policy_id);
284     pPolicyConfig = (ArpSpoofConfig *)sfPolicyUserDataGetCurrent(arp_spoof_config);
285 
286     if (pPolicyConfig == NULL)
287     {
288         ParseError("Please activate arpspoof before trying to "
289                    "use arpspoof_detect_host.");
290     }
291 
292     DEBUG_WRAP(DebugMessage(DEBUG_INIT,
293             "Preprocessor: ARPspoof (overwrite list) Initialized\n"););
294 
295     if (pPolicyConfig->ipmel == NULL)
296     {
297         pPolicyConfig->ipmel = (IPMacEntryList *)SnortAlloc(sizeof(IPMacEntryList));
298     }
299 
300     /* Add MAC/IP pairs to ipmel */
301     ParseARPspoofHostArgs(pPolicyConfig->ipmel, args);
302 
303     if (pPolicyConfig->check_overwrite == 0)
304         pPolicyConfig->check_overwrite = 1;
305 }
306 
307 
308 /**
309  * Parse arguments passed to the arpspoof_detect_host keyword.
310  *
311  * @param args preprocessor argument string
312  *
313  * @return void function
314  */
ParseARPspoofHostArgs(IPMacEntryList * ipmel,char * args)315 static void ParseARPspoofHostArgs(IPMacEntryList *ipmel, char *args)
316 {
317     char **toks;
318     char **macbytes;
319     int num_toks, num_macbytes;
320     int i;
321     struct in_addr IP_struct;
322     IPMacEntry *ipme = NULL;
323 
324     if (ipmel == NULL)
325         return;
326 
327     toks = mSplit(args, " ", 0, &num_toks, '\\');
328 
329     if (num_toks != 2)
330         ParseError("Invalid arguments to arpspoof_detect_host.");
331 
332     /* Add entries */
333     ipme = (IPMacEntry *)SnortAlloc(sizeof(IPMacEntry));
334 
335     if ((IP_struct.s_addr = inet_addr(toks[0])) == INADDR_NONE)
336     {
337         ParseError("Invalid IP address as first argument of "
338                    "IP/MAC pair to arpspoof_detect_host.");
339     }
340 
341     ipme->ipv4_addr = (uint32_t)IP_struct.s_addr;
342 
343     macbytes = mSplit(toks[1], ":", 6, &num_macbytes, '\\');
344 
345     if (num_macbytes < 6)
346     {
347         ParseError("Invalid MAC address as second argument of IP/MAC "
348                    "pair to arpspoof_detect_host.");
349     }
350     else
351     {
352         for (i = 0; i < 6; i++)
353             ipme->mac_addr[i] = (uint8_t) strtoul(macbytes[i], NULL, 16);
354     }
355 
356     AddIPMacEntryToList(ipmel, ipme);
357 
358     mSplitFree(&toks, num_toks);
359     mSplitFree(&macbytes, num_macbytes);
360 
361 #if defined(DEBUG)
362     PrintIPMacEntryList(ipmel);
363 #endif
364 }
365 
366 
367 /**
368  * Detect ARP anomalies and overwrite attacks.
369  *
370  * @param p packet to detect anomalies and overwrite attacks on
371  * @param context unused
372  *
373  * @return void function
374  */
DetectARPattacks(Packet * p,void * context)375 static void DetectARPattacks(Packet *p, void *context)
376 {
377     IPMacEntry *ipme;
378     ArpSpoofConfig *aconfig = NULL;
379     const uint8_t *dst_mac_addr = NULL, *src_mac_addr = NULL;
380     PROFILE_VARS;
381     sfPolicyUserPolicySet (arp_spoof_config, getNapRuntimePolicy());
382     aconfig = (ArpSpoofConfig *)sfPolicyUserDataGetCurrent(arp_spoof_config);
383     uint32_t *arp_spa;
384 
385     /* is the packet valid? */
386     if ( aconfig == NULL || p->ah == NULL)
387         return;
388 
389     // preconditions - what we registered for
390     if( p->eh != NULL)
391     {
392         src_mac_addr = p->eh->ether_src;
393         dst_mac_addr = p->eh->ether_dst;
394     }
395 #ifndef NO_NON_ETHER_DECODER
396     else if( p->wifih != NULL )
397     {
398          if ((p->wifih->frame_control & WLAN_FLAG_TODS) &&
399              (p->wifih->frame_control & WLAN_FLAG_FROMDS))
400          {
401              dst_mac_addr = p->wifih->addr3;
402              src_mac_addr = p->wifih->addr4;
403          }
404          else if (p->wifih->frame_control & WLAN_FLAG_TODS)
405          {
406              src_mac_addr = p->wifih->addr2;
407              dst_mac_addr = p->wifih->addr3;
408          }
409          else if (p->wifih->frame_control & WLAN_FLAG_FROMDS)
410          {
411              dst_mac_addr = p->wifih->addr1;
412              src_mac_addr = p->wifih->addr3;
413          }
414          else
415          {
416              dst_mac_addr = p->wifih->addr1;
417              src_mac_addr = p->wifih->addr2;
418          }
419     }
420 #endif
421     else
422     {
423          return;
424     }
425 
426     /* is the ARP protocol type IP and the ARP hardware type Ethernet? */
427     if ((ntohs(p->ah->ea_hdr.ar_hrd) != 0x0001) ||
428             (ntohs(p->ah->ea_hdr.ar_pro) != ETHERNET_TYPE_IP))
429         return;
430 
431     PREPROC_PROFILE_START(arpPerfStats);
432 
433     switch(ntohs(p->ah->ea_hdr.ar_op))
434     {
435         case ARPOP_REQUEST:
436             if (aconfig->check_unicast_arp)
437             {
438                 if (memcmp((u_char *)dst_mac_addr, (u_char *)bcast, 6) != 0)
439                 {
440                     SnortEventqAdd(GENERATOR_SPP_ARPSPOOF,
441                             ARPSPOOF_UNICAST_ARP_REQUEST, 1, 0, 3,
442                             ARPSPOOF_UNICAST_ARP_REQUEST_STR, 0);
443 
444                     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,
445                             "MODNAME: Unicast request\n"););
446                 }
447             }
448             else if (memcmp((u_char *)src_mac_addr,
449                     (u_char *)p->ah->arp_sha, 6) != 0)
450             {
451                 SnortEventqAdd(GENERATOR_SPP_ARPSPOOF,
452                         ARPSPOOF_ETHERFRAME_ARP_MISMATCH_SRC, 1, 0, 3,
453                         ARPSPOOF_ETHERFRAME_ARP_MISMATCH_SRC_STR, 0);
454 
455                 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,
456                             "MODNAME: Ethernet/ARP mismatch request\n"););
457             }
458             break;
459         case ARPOP_REPLY:
460             if (memcmp((u_char *)src_mac_addr,
461                     (u_char *)p->ah->arp_sha, 6) != 0)
462             {
463                 SnortEventqAdd(GENERATOR_SPP_ARPSPOOF,
464                         ARPSPOOF_ETHERFRAME_ARP_MISMATCH_SRC, 1, 0, 3,
465                         ARPSPOOF_ETHERFRAME_ARP_MISMATCH_SRC_STR, 0);
466 
467                 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,
468                         "MODNAME: Ethernet/ARP mismatch reply src\n"););
469             }
470             else if (memcmp((u_char *)dst_mac_addr,
471                     (u_char *)p->ah->arp_tha, 6) != 0)
472             {
473                 SnortEventqAdd(GENERATOR_SPP_ARPSPOOF,
474                         ARPSPOOF_ETHERFRAME_ARP_MISMATCH_DST, 1, 0, 3,
475                         ARPSPOOF_ETHERFRAME_ARP_MISMATCH_DST_STR, 0);
476 
477                 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,
478                         "MODNAME: Ethernet/ARP mismatch reply dst\n"););
479             }
480             break;
481     }
482     PREPROC_PROFILE_END(arpPerfStats);
483 
484     /* return if the overwrite list hasn't been initialized */
485     if (!aconfig->check_overwrite)
486         return;
487 
488     /* LookupIPMacEntryByIP() is too slow, will be fixed later */
489     arp_spa = (uint32_t *)&p->ah->arp_spa[0];
490     if ((ipme = LookupIPMacEntryByIP(aconfig->ipmel,
491                                      *arp_spa)) == NULL)
492     {
493         DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,
494                 "MODNAME: LookupIPMacEntryByIp returned NULL\n"););
495         return;
496     }
497     else
498     {
499         DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,
500                 "MODNAME: LookupIPMacEntryByIP returned %p\n", ipme););
501 
502         /* If the Ethernet source address or the ARP source hardware address
503          * in p doesn't match the MAC address in ipme, then generate an alert
504          */
505         if ((memcmp((uint8_t *)src_mac_addr,
506                 (uint8_t *)ipme->mac_addr, 6)) ||
507                 (memcmp((uint8_t *)p->ah->arp_sha,
508                 (uint8_t *)ipme->mac_addr, 6)))
509         {
510             SnortEventqAdd(GENERATOR_SPP_ARPSPOOF,
511                     ARPSPOOF_ARP_CACHE_OVERWRITE_ATTACK, 1, 0, 3,
512                     ARPSPOOF_ARP_CACHE_OVERWRITE_ATTACK_STR, 0);
513 
514             DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,
515                     "MODNAME: Attempted ARP cache overwrite attack\n"););
516 
517             return;
518         }
519     }
520 }
521 
522 
523 /**
524  * Add IP/MAC pair to a linked list.
525  *
526  * @param ip_mac_entry_list pointer to the list structure
527  * @param ip_mac_entry linked list structure node
528  *
529  * @return 0 if the node is added successfully, 1 otherwise
530  */
AddIPMacEntryToList(IPMacEntryList * ip_mac_entry_list,IPMacEntry * ip_mac_entry)531 static int AddIPMacEntryToList(IPMacEntryList *ip_mac_entry_list,
532                                IPMacEntry *ip_mac_entry)
533 {
534     IPMacEntryListNode *newNode;
535 
536     if (ip_mac_entry == NULL || ip_mac_entry_list == NULL)
537         return 1;
538 
539     newNode = (IPMacEntryListNode *)SnortAlloc(sizeof(IPMacEntryListNode));
540     newNode->ip_mac_entry = ip_mac_entry;
541     newNode->next = NULL;
542 
543     if (ip_mac_entry_list->head == NULL)
544     {
545         ip_mac_entry_list->head = newNode;
546         ip_mac_entry_list->size = 1;
547     }
548     else
549     {
550         ip_mac_entry_list->tail->next = newNode;
551         ip_mac_entry_list->size += 1;
552     }
553     ip_mac_entry_list->tail = newNode;
554     return 0;
555 }
556 
557 
558 /**
559  * Locate a linked list structure node by an IP address.
560  *
561  * @param ip_mac_entry_list pointer to the list structure
562  * @param ipv4_addr IPv4 address as an unsigned 32-bit integer
563  *
564  * @return pointer to a structure node if a match is found, NULL otherwise
565  */
LookupIPMacEntryByIP(IPMacEntryList * ip_mac_entry_list,uint32_t ipv4_addr)566 static IPMacEntry *LookupIPMacEntryByIP(IPMacEntryList *ip_mac_entry_list,
567                                         uint32_t ipv4_addr)
568 {
569     IPMacEntryListNode *current;
570 #if defined(DEBUG)
571     char *cha, *chb;
572     sfaddr_t ina, inb;
573 #endif
574 
575     if (ip_mac_entry_list == NULL)
576         return NULL;
577 
578     for (current = ip_mac_entry_list->head; current != NULL;
579             current = current->next)
580     {
581 #if defined(DEBUG)
582         sfip_set_raw(&ina, &ipv4_addr, AF_INET);
583         sfip_set_raw(&inb, &current->ip_mac_entry->ipv4_addr, AF_INET);
584         cha = strdup(inet_ntoa(IP_ARG(ina)));
585         chb = strdup(inet_ntoa(IP_ARG(inb)));
586 
587         DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,
588             "MODNAME: LookupIPMacEntryByIP() comparing %s to %s\n", cha, chb););
589         free(cha);
590         free(chb);
591 #endif
592         if (current->ip_mac_entry->ipv4_addr == ipv4_addr)
593         {
594             DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,
595                     "MODNAME: LookupIPMecEntryByIP() match!"););
596 
597             return current->ip_mac_entry;
598         }
599     }
600     return NULL;
601 }
602 
603 
604 /**
605  * Free the linked list of IP/MAC address pairs
606  *
607  * @param ip_mac_entry_list pointer to the list structure
608  *
609  * @return void function
610  */
FreeIPMacEntryList(IPMacEntryList * ip_mac_entry_list)611 static void FreeIPMacEntryList(IPMacEntryList *ip_mac_entry_list)
612 {
613     IPMacEntryListNode *prev;
614     IPMacEntryListNode *current;
615 
616     if (ip_mac_entry_list == NULL)
617         return;
618 
619     current = ip_mac_entry_list->head;
620     while (current != NULL)
621     {
622         if (current->ip_mac_entry != NULL)
623             free(current->ip_mac_entry);
624 
625         prev = current;
626         current = current->next;
627         free(prev);
628     }
629     ip_mac_entry_list->head = NULL;
630     ip_mac_entry_list->size = 0;
631 
632     return;
633 }
634 
635 
ARPspoofCleanExit(int signal,void * unused)636 static void ARPspoofCleanExit(int signal, void *unused)
637 {
638     ArpSpoofFreeConfig(arp_spoof_config);
639     arp_spoof_config = NULL;
640 }
641 
ArpSpoofFreeConfigPolicy(tSfPolicyUserContextId config,tSfPolicyId policyId,void * pData)642 static int ArpSpoofFreeConfigPolicy(tSfPolicyUserContextId config,tSfPolicyId policyId, void* pData )
643 {
644     ArpSpoofConfig *pPolicyConfig = (ArpSpoofConfig *)pData;
645     if(pPolicyConfig->ipmel != NULL)
646     {
647          FreeIPMacEntryList(pPolicyConfig->ipmel);
648          free(pPolicyConfig->ipmel);
649     }
650     sfPolicyUserDataClear (config, policyId);
651     free(pPolicyConfig);
652     return 0;
653 }
654 
ArpSpoofFreeConfig(tSfPolicyUserContextId config)655 static void ArpSpoofFreeConfig(tSfPolicyUserContextId config)
656 {
657 
658     if (config == NULL)
659         return;
660 
661     sfPolicyUserDataFreeIterate (config, ArpSpoofFreeConfigPolicy);
662     sfPolicyConfigDelete(config);
663 
664 }
665 
666 
667 #ifdef DEBUG
668 /**
669  * Print the overwrite list for debugging purposes
670  *
671  * @param ip_mac_entry_list pointer to the list structure
672  *
673  * @return void function
674  */
PrintIPMacEntryList(IPMacEntryList * ip_mac_entry_list)675 static void PrintIPMacEntryList(IPMacEntryList *ip_mac_entry_list)
676 {
677     IPMacEntryListNode *current;
678     int i;
679     sfaddr_t in;
680 
681     if (ip_mac_entry_list == NULL)
682         return;
683 
684     current = ip_mac_entry_list->head;
685     printf("Arpspoof IPMacEntry List");
686     printf("  Size: %i\n", ip_mac_entry_list->size);
687     while (current != NULL)
688     {
689         sfip_set_raw(&in, &current->ip_mac_entry->ipv4_addr, AF_INET);
690         printf("%s -> ", inet_ntoa(IP_ARG(in)));
691         for (i = 0; i < 6; i++)
692         {
693             printf("%02x", current->ip_mac_entry->mac_addr[i]);
694             if (i != 5)
695                 printf(":");
696         }
697         printf("\n");
698         current = current->next;
699     }
700     return;
701 }
702 #endif
703 
704 #ifdef SNORT_RELOAD
ARPspoofReload(struct _SnortConfig * sc,char * args,void ** new_config)705 static void ARPspoofReload(struct _SnortConfig *sc, char *args, void **new_config)
706 {
707     tSfPolicyUserContextId arp_spoof_swap_config = (tSfPolicyUserContextId)*new_config;
708     int policy_id = (int)getParserPolicy(sc);
709     ArpSpoofConfig *pPolicyConfig;
710 
711     if (!arp_spoof_swap_config)
712     {
713         arp_spoof_swap_config = sfPolicyConfigCreate();
714         *new_config = (void *)arp_spoof_swap_config;
715     }
716 
717     sfPolicyUserPolicySet (arp_spoof_swap_config, policy_id);
718 
719     pPolicyConfig = (ArpSpoofConfig *)sfPolicyUserDataGetCurrent(arp_spoof_swap_config);
720     if (pPolicyConfig)
721     {
722         FatalError("Arpspoof can only be configured once.\n");
723     }
724 
725     pPolicyConfig = (ArpSpoofConfig *)SnortAlloc(sizeof(ArpSpoofConfig));
726     if (!pPolicyConfig)
727     {
728         ParseError("ARPSPOOF preprocessor: memory allocate failed.\n");
729     }
730      sfPolicyUserDataSetCurrent(arp_spoof_swap_config, pPolicyConfig);
731 
732 
733     /* Add arpspoof to the preprocessor function list */
734     AddFuncToPreprocList(sc, DetectARPattacks, PRIORITY_NETWORK, PP_ARPSPOOF, PROTO_BIT__ARP);
735 
736     //policy independent configuration. First policy defines actual values.
737     if (policy_id != 0)
738     {
739        pPolicyConfig->check_unicast_arp = ((ArpSpoofConfig *)sfPolicyUserDataGetDefault(arp_spoof_swap_config))->check_unicast_arp;
740         return;
741     }
742 
743     /* Parse the arpspoof arguments from snort.conf */
744     ParseARPspoofArgs(pPolicyConfig, args);
745 
746 }
747 
ARPspoofReloadHost(struct _SnortConfig * sc,char * args,void ** new_config)748 static void ARPspoofReloadHost(struct _SnortConfig *sc, char *args, void **new_config)
749 {
750     int policy_id = (int)getParserPolicy(sc);
751     ArpSpoofConfig *pPolicyConfig = NULL;
752     tSfPolicyUserContextId arp_spoof_swap_config;
753 
754     arp_spoof_swap_config = (tSfPolicyUserContextId)GetRelatedReloadData(sc, "arpspoof");
755 
756     if ((arp_spoof_swap_config == NULL) ||
757         (pPolicyConfig == NULL))
758     {
759         ParseError("Please activate arpspoof before trying to "
760                    "use arpspoof_detect_host.");
761     }
762 
763     sfPolicyUserPolicySet(arp_spoof_swap_config, policy_id);
764     pPolicyConfig = (ArpSpoofConfig *)sfPolicyUserDataGetCurrent(arp_spoof_swap_config);
765 
766     DEBUG_WRAP(DebugMessage(DEBUG_INIT,
767             "Preprocessor: ARPspoof (overwrite list) Initialized\n"););
768 
769     if (pPolicyConfig->ipmel == NULL)
770     {
771         pPolicyConfig->ipmel =
772             (IPMacEntryList *)SnortAlloc(sizeof(IPMacEntryList));
773     }
774 
775     /* Add MAC/IP pairs to ipmel */
776     ParseARPspoofHostArgs(pPolicyConfig->ipmel, args);
777 
778     if (pPolicyConfig->check_overwrite == 0)
779         pPolicyConfig->check_overwrite = 1;
780 }
781 
ARPspoofReloadSwap(struct _SnortConfig * sc,void * swap_config)782 static void * ARPspoofReloadSwap(struct _SnortConfig *sc, void *swap_config)
783 {
784     tSfPolicyUserContextId arp_spoof_swap_config = (tSfPolicyUserContextId)swap_config;
785     tSfPolicyUserContextId old_config = arp_spoof_config;
786 
787     if (arp_spoof_swap_config == NULL)
788         return NULL;
789 
790     arp_spoof_config = arp_spoof_swap_config;
791     arp_spoof_swap_config = NULL;
792 
793     return (void *)old_config;
794 }
795 
ARPspoofReloadSwapFree(void * data)796 static void ARPspoofReloadSwapFree(void *data)
797 {
798     if (data == NULL)
799         return;
800 
801     ArpSpoofFreeConfig((tSfPolicyUserContextId)data);
802 }
803 #endif
804