[Snort-devel] arpspoof preprocessor, the patch

Sergey Lyubka devnull at ...2232...
Thu Dec 4 08:11:14 EST 2003


Here's the patch for arpspoof preprocessor.
The ARP entry expiration is solved.

the patch is included, the source can be found as well at 
http://oasis.uptsoft.com/~devnull/spp_arpspoof.c


-- 
Sergey Lyubka, Network Security Consultant
NetFort ISS Ltd, Galway, Ireland
-------------- next part --------------
--- src/preprocessors/spp_arpspoof.c.orig	Fri Jul 25 16:17:28 2003
+++ src/preprocessors/spp_arpspoof.c	Thu Dec  4 13:50:59 2003
@@ -1,80 +1,24 @@
-/* $Id: spp_arpspoof.c,v 1.20 2003/07/25 15:17:28 chrisgreen Exp $ */
 /*
-** Copyright (C) 2001-2003 Jeff Nathan <jeff at ...835...>
-**
-** This program is free software; you can redistribute it and/or modify
-** it under the terms of the GNU General Public License as published by
-** the Free Software Foundation; either version 2 of the License, or
-** (at your option) any later version.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-** GNU General Public License for more details.
-**                
-** You should have received a copy of the GNU General Public License
-** along with this program; if not, write to the Free Software
-** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-*/
-
-/* Snort ARPspoof Preprocessor Plugin
- *   by Jeff Nathan <jeff at ...835...>
- *   Version 0.1.3
+ * Copyright (C) 2001-2003 Jeff Nathan <jeff at ...835...>
+ * Copyright (c) 2003 Sergey Lyubka <devnull at ...2232...>
  *
- * Purpose:
- *
- * This preprocessor looks for anomalies in ARP traffic and attempts to 
- * maliciously overwrite  ARP cache information on hosts.
- *
- * Arguments:
- *
- * To check for unicast ARP requests use:
- * arpspoof: -unicast
- *
- * WARNING: this can generate false positives as Linux systems send unicast 
- * ARP requests repetatively for entries in their cache.
- *
- * This plugin also takes a list of IP addresses and MAC address in the form:
- * arpspoof_detect_host: 10.10.10.10 29:a2:9a:29:a2:9a
- * arpspoof_detect_host: 192.168.40.1 f0:0f:00:f0:0f:00
- * and so forth...
- *
- * Effect:
- * By comparing information in the Ethernet header to the ARP frame, obvious
- * anomalies are detected.  Also, utilizing a user supplied list of IP 
- * addresses and MAC addresses, ARP traffic appearing to have originated from 
- * any IP in that list is carefully examined by comparing the source hardware 
- * address to the user supplied hardware address.  If there is a mismatch, an 
- * alert is generated as either an ARP request or REPLY can be used to 
- * overwrite cache information on a remote host.  This should only be used for 
- * hosts/devices on the **same layer 2 segment** !!
- *
- * Bugs:
- * This is a proof of concept ONLY.  It is clearly not complete.  Also, the 
- * lookup function LookupIPMacEntryByIP is in need of optimization.  The
- * arpspoof_detect_host functionality may false alarm in redundant environments. * Also, see the comment above pertaining to Linux systems.
- *
- * Thanks:
- *
- * First and foremost Patrick Mullen who sat beside me and helped every step of
- * the way.  Andrew Baker for graciously supplying the tougher parts of this 
- * code.  W. Richard Stevens for readable documentation and finally 
- * Marty for being a badass.  All your packets are belong to Marty.
+ * The ARP spoof preprocessor for Snort IDS
  *
+ * $Id$
  */
 
-/*  I N C L U D E S  ************************************************/
+#ifndef WIN32
 #include <sys/types.h>
-#include <stdlib.h>
-#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif /* !WIN32 */
+
+#include <assert.h>
 #include <stdio.h>
-#if !defined(WIN32)
-    #include <sys/time.h>
-    #include <sys/socket.h>
-    #include <netinet/in.h>
-    #include <arpa/inet.h>
-#elif defined(WIN32)
-    #include <time.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
 #endif
 
 #include "generators.h"
@@ -87,498 +31,277 @@
 #include "mstring.h"
 #include "debug.h"
 #include "util.h"
+#include "sfxhash.h"
 
+/*
+ * ARP table entry
+ */
+struct arpentry {
+	uint32_t ip;			/* IP address of the host */
+	uint8_t ether[6];		/* MAC address */
+	time_t stamp;			/* Last seen time stamp */
+};
 
-/*  D E F I N E S  **************************************************/
-#define MODNAME "spp_arpspoof"
-#define WITHUNICAST "-unicast"
-
-
-/*  D A T A   S T R U C T U R E S  **********************************/
-typedef struct _IPMacEntry
-{
-    u_int32_t ipv4_addr;
-    u_int8_t  mac_addr[6];
-    u_int8_t  pad[2];
-} IPMacEntry;
-
-typedef struct _IPMacEntryListNode
-{
-    IPMacEntry *ip_mac_entry;
-    struct _IPMacEntryListNode *next;
-} IPMacEntryListNode;
+/*
+ * Local functions
+ */
+static void as_init(unsigned char *args);
+static void as_fini(int signal, void *arg);
+static void as_detect(Packet *);
+static unsigned as_haship(SFHASHFCN *p, unsigned char *data, int datalen);
+static int as_cmpip(const void *arg1, const void *arg2, size_t len);
+static void as_checkpoison(Packet *p, void *ip, const uint8_t *ether);
+static void as_checkequal(Packet *, const void *, const void *, int, char *);
+static void as_checkunicast(Packet *p);
+static void as_expire(time_t now);
 
-typedef struct _IPMacEntryList
-{
-    int size;
-    IPMacEntryListNode *head;
-    IPMacEntryListNode *tail;
-} IPMacEntryList;
-
-
-/*  G L O B A L S  **************************************************/
-int check_unicast_arp, check_overwrite;
-u_int8_t bcast[6];  /* generic buffer to store Ethernet broadcast address */
-static IPMacEntryList *ipmel;
-
-
-/*  P R O T O T Y P E S  ********************************************/
-void ARPspoofInit(u_char *);
-void ARPspoofHostInit(u_char *);
-void ParseARPspoofArgs(char *);
-void ParseARPspoofHostArgs(char *);
-void DetectARPattacks(Packet *);
-void ARPspoofCleanExitFunction(int, void *);
-void FreeIPMacEntryList(IPMacEntryList *);
-int AddIPMacEntryToList(IPMacEntryList *, IPMacEntry *);
-IPMacEntry *LookupIPMacEntryByIP(IPMacEntryList *, u_int32_t);
-#if defined(DEBUG)
-    void PrintIPMacEntryList(IPMacEntryList *);
-#endif
+/*
+ * Local variables
+ */
+static SFXHASH *_arptbl;		/* The ARP table */
+static int _unicast;			/* Check unicast ARP */
+static uint8_t _zeromac[6];		/* Zero-filled MAC address */
+static uint8_t _bcstmac[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+#define	NARPENTRIES	500		/* Average number of ARP entries */
+#define	MINTIME		2		/* Time threshold, seconds */
+#define	ARPENTRYTTL	60 * 60 * 24	/* Time-to-live for the entry */
+#define MODNAME "(spp_arpspoof)"	/* Module name */
+#define WITHUNICAST 	"-unicast"	/* Configuration parameter */
 
 
 void SetupARPspoof(void)
 {
-    RegisterPreprocessor("arpspoof", ARPspoofInit);
-    RegisterPreprocessor("arpspoof_detect_host", ARPspoofHostInit);
-
-    DEBUG_WRAP(DebugMessage(DEBUG_INIT, 
-            "Preprocessor: Arpspoof is setup...\n"););
-
-    return;
-}
-
-
-void ARPspoofInit(u_char *args)
-{
-    DEBUG_WRAP(DebugMessage(DEBUG_INIT, 
-            "Preprocessor: Arpspoof Initialized\n"););
-
-    /* parse the argument list from the rules file */
-    ParseARPspoofArgs(args);
-
-    /* Set the preprocessor function into the function list */
-    AddFuncToPreprocList(DetectARPattacks);
-    AddFuncToCleanExitList(ARPspoofCleanExitFunction, NULL);
-    /* the code for Restart is identical to CleanExit.  This is intentional */
-    AddFuncToRestartList(ARPspoofCleanExitFunction, NULL);
-
-    return;
+	RegisterPreprocessor("arpspoof", as_init);
+	DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,  "Preprocessor: arpspoof\n"););
 }
 
-
-/**
- * Parse arguments passed to the arpspoof keyword.
- *
- * @param args preprocessor argument string
- * 
- * @return void function
- */
-void ParseARPspoofArgs(char *args)
+int
+as_cmpip(const void *arg1, const void *arg2, size_t len)
 {
-    char **toks;
-    int num_toks;
-    int num;
-
-    if (!args)
-        return;
-
-    toks = mSplit(args, " ", 2, &num_toks, '\\');
-
-    if (num_toks > 1)
-    {      
-        FatalError(MODNAME ": ERROR: %s (%d) => ARPspoof configuration "
-                "format: -unicast\n", file_name, file_line);
-    } 
-
-    for (num = 0; num < num_toks; num++)
-    {
-        if (!strncasecmp(WITHUNICAST, toks[num], sizeof WITHUNICAST))
-            check_unicast_arp = 1;
-    }
+	return (memcmp(arg1, arg2, sizeof(uint32_t)));
 }
 
-
-void ARPspoofHostInit(u_char *args)
+unsigned
+as_haship(SFHASHFCN *p, unsigned char *key, int keylen)
 {
-    DEBUG_WRAP(DebugMessage(DEBUG_INIT, 
-            "Preprocessor: Arpspoof (overwrite list) Initialized\n"););
-
-    ipmel = (IPMacEntryList *)SnortAlloc(sizeof(IPMacEntryList));
+	uint32_t hash = 0;
 
-    /* parse the argument list from the rules file */
-    ParseARPspoofHostArgs(args);
+	keylen = MIN(keylen, sizeof(uint32_t));
 
-    check_overwrite = 1;
-    return;
+	(void) memcpy(&hash, key, keylen);
+		
+	return (hash);
 }
 
-
-/**
- * Parse arguments passed to the arpspoof_detect_host keyword.
- *
- * @param args preprocessor argument string
- * 
- * @return void function
- */
-void ParseARPspoofHostArgs(char *args)
+void
+as_init(unsigned char *args)
 {
-    char **toks;
-    char **macbytes; 
-    int num_toks, num_macbytes;
-    int i;
-    struct in_addr IP_struct;
-    IPMacEntry *ipme = NULL;
-
-    if (ipmel == NULL)
-    {
-        FatalError("%s(%d) => Please activate arpspoof before trying to "
-                "use arpspoof_detect_host\n", file_name, file_line);
-    }
-
-    toks = mSplit(args, " ", 2, &num_toks, '\\');
-
-    if (num_toks != 2)
-    {
-        FatalError("Arpspoof %s(%d) => Invalid arguments to "
-                   "arpspoof_detect_host\n", file_name, file_line);
-    }
-
-    /* Add entries */
-    ipme = (IPMacEntry *)SnortAlloc(sizeof(IPMacEntry));
-
-    if ((IP_struct.s_addr = inet_addr(toks[0])) == -1)
-    {
-        FatalError("Arpspoof %s(%d) => Invalid IP address as first argument of "
-                "IP/MAC pair to arpspoof_detect_host\n", file_name, file_line);
-    }
-
-    ipme->ipv4_addr = (u_int32_t)IP_struct.s_addr;
-
-    macbytes = mSplit(toks[1], ":", 6, &num_macbytes, '\\');
-
-    if (num_macbytes < 6)
-    {
-        FatalError("Arpspoof %s(%d) => Invalid MAC address as second "
-                   "argument of IP/MAC pair to arpspoof_detect_host\n", 
-                   file_name, file_line);
-    }
-    else
-    {
-        for (i = 0; i < 6; i++)
-            ipme->mac_addr[i] = (u_int8_t) strtoul(macbytes[i], NULL, 16);
-    }
+	char **toks;
+	int num_toks, num;
+	
+	/* Set the preprocessor function into the function list */
+	AddFuncToPreprocList(&as_detect);
+	AddFuncToCleanExitList(&as_fini, NULL);
+	AddFuncToRestartList(&as_fini, NULL);
 
-    AddIPMacEntryToList(ipmel, ipme);
+	/* Create ARP table, which is a hash table */
+	/* XXX Snort's hash table interface sucks. Take a look at glib! */
+	_arptbl = sfxhash_new(NARPENTRIES, sizeof(uint32_t),
+	    sizeof(struct arpentry), 0, 0, NULL, NULL, 0);
+	assert(_arptbl != NULL);
 
-    FreeToks(toks, num_toks);
-    FreeToks(macbytes, num_macbytes);
+	(void) sfxhash_set_keyops(_arptbl, &as_haship, &as_cmpip);
 
-#if defined(DEBUG)
-    PrintIPMacEntryList(ipmel);
-#endif
+	/*
+	 * Parse for -unicast option.
+	 * XXX Ugly! Should it be some good interface for
+	 * fetching the options for plugins etc ?
+	 */
+	if (args) {
+		toks = mSplit(args, " ", 2, &num_toks, '\\');
 
-    return;
-}
+		if (num_toks > 1) {
+			FatalError("%s: ERROR: %s (%d) => ARPspoof"
+			    " configuration format: -unicast\n",
+			    MODNAME, file_name, file_line);
+		} 
 
+		for (num = 0; num < num_toks; num++) {
+			if (!strncasecmp(WITHUNICAST, toks[num],
+			    sizeof WITHUNICAST))
+				_unicast = 1;
+		}
+	}
 
-/**
- * Detect ARP anomalies and overwrite attacks.
- *
- * @param p packet to detect anomalies and overwrite attacks on
- *
- * @return void function
- */
-void DetectARPattacks(Packet *p)
-{
-    Event event;
-    IPMacEntry *ipme;
-    u_int32_t addr;
-
-    /* is the packet valid? */
-    if (p == NULL)
-        return;
-
-    /* is Arpspoof supposed to operate on this packet? */
-    if(!(p->preprocessors & PP_ARPSPOOF))
-        return;
-
-    /* are the Ethernet and ARP headers present? */
-    if (p->eh == NULL || p->ah == NULL)
-        return;
-
-    /* is the ARP protocol type IP and the ARP hardware type Ethernet? */
-    if ((ntohs(p->ah->ea_hdr.ar_hrd) != 0x0001) || 
-            (ntohs(p->ah->ea_hdr.ar_pro) != ETHERNET_TYPE_IP))
-        return;
-
-    addr = 0;
-    memset(bcast, 0xff, 6);
-
-    switch(ntohs(p->ah->ea_hdr.ar_op))
-    {
-        case ARPOP_REQUEST:
-            if (check_unicast_arp) 
-            {
-                if (memcmp((u_char *)p->eh->ether_dst, (u_char *)bcast, 6) != 0)
-                {
-                    SetEvent(&event, GENERATOR_SPP_ARPSPOOF, 
-                                ARPSPOOF_UNICAST_ARP_REQUEST, 1, 0, 0, 0);
-
-                    CallAlertFuncs(p, ARPSPOOF_UNICAST_ARP_REQUEST_STR, NULL, 
-                            &event);
-
-                    CallLogFuncs(p, ARPSPOOF_UNICAST_ARP_REQUEST_STR, NULL, 
-                            &event);
-
-                    DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, 
-                            "MODNAME: unicast ARP request\n"););
-                }
-            }
-            else if (memcmp((u_char *)p->eh->ether_src, 
-                    (u_char *)p->ah->arp_sha, 6) != 0) 
-            {
-                SetEvent(&event, GENERATOR_SPP_ARPSPOOF, 
-                        ARPSPOOF_ETHERFRAME_ARP_MISMATCH_SRC, 1, 0, 0, 0);
-
-                CallAlertFuncs(p, ARPSPOOF_ETHERFRAME_ARP_MISMATCH_SRC_STR, 
-                        NULL, &event);
-
-                CallLogFuncs(p, ARPSPOOF_ETHERFRAME_ARP_MISMATCH_SRC_STR, 
-                        NULL, &event);
-
-                DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, 
-                            "MODNAME: Ethernet/ARP mismatch request\n"););
-            }
-            break;
-        case ARPOP_REPLY:
-            if (memcmp((u_char *)p->eh->ether_src, 
-                    (u_char *)p->ah->arp_sha, 6) != 0)
-            {
-                SetEvent(&event, GENERATOR_SPP_ARPSPOOF, 
-                        ARPSPOOF_ETHERFRAME_ARP_MISMATCH_SRC, 1, 0, 0, 0);
-
-                CallAlertFuncs(p, ARPSPOOF_ETHERFRAME_ARP_MISMATCH_SRC_STR, 
-                        NULL, &event);
-
-                CallLogFuncs(p, ARPSPOOF_ETHERFRAME_ARP_MISMATCH_SRC_STR, 
-                        NULL, &event);
-
-                DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, 
-                        "MODNAME: Ethernet/ARP mismatch reply src\n"););
-            }
-            else if (memcmp((u_char *)p->eh->ether_dst, 
-                    (u_char *)p->ah->arp_tha, 6) != 0)
-            {
-                SetEvent(&event, GENERATOR_SPP_ARPSPOOF, 
-                        ARPSPOOF_ETHERFRAME_ARP_MISMATCH_DST, 1, 0, 0, 0);
-
-                CallAlertFuncs(p, ARPSPOOF_ETHERFRAME_ARP_MISMATCH_DST_STR,
-                        NULL, &event);
-
-                CallLogFuncs(p, ARPSPOOF_ETHERFRAME_ARP_MISMATCH_DST_STR,
-                        NULL, &event);
-
-                DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,
-                        "MODNAME: Ethernet/ARP mismatch reply dst\n"););
-            }
-            break;
-    }
-
-    /* bail if the overwrite list hasn't been initialized */
-    if (!check_overwrite)
-        return;
-
-    /* LookupIPMacEntryByIP() is too slow, will be fixed later */
-    memcpy(&addr, p->ah->arp_spa, 4);
-
-    if ((ipme = LookupIPMacEntryByIP(ipmel, addr)) == NULL)
-    {
-        DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, 
-                "MODNAME: LookupIPMacEntryByIp returned NULL\n"););
-        return;
-    }
-    else
-    {
-        DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, 
-                "MODNAME: LookupIPMacEntryByIP returned %p\n", ipme););
-
-        if ((!memcmp((u_int8_t *)p->eh->ether_src, 
-                (u_int8_t *)ipme->mac_addr, 6)) || 
-                (!memcmp((u_int8_t *)p->ah->arp_sha, 
-                (u_int8_t *)ipme->mac_addr, 6)))
-        {
-            SetEvent(&event, GENERATOR_SPP_ARPSPOOF, 
-                    ARPSPOOF_ARP_CACHE_OVERWRITE_ATTACK, 1, 0, 0, 0);
-
-            CallAlertFuncs(p, ARPSPOOF_ARP_CACHE_OVERWRITE_ATTACK_STR,
-                    NULL, &event);
-
-            CallLogFuncs(p, ARPSPOOF_ARP_CACHE_OVERWRITE_ATTACK_STR,
-                    NULL, &event);
-
-            DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, 
-                    "MODNAME: Attempted ARP cache overwrite attack\n"););
-
-            return;
-        }
-    } 
+	DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, 
+	    "Preprocessor: Arpspoof Initialized\n"););
 }
 
-
-/**
- * Add IP/MAC pair to a linked list.
- *
- * @param ip_mac_entry_list pointer to the list structure
- * @param ip_mac_entry linked list structure node
- *
- * @return 0 if the node is added successfully, 1 otherwise
- */
-int AddIPMacEntryToList(IPMacEntryList *ip_mac_entry_list, 
-        IPMacEntry *ip_mac_entry)
+void
+as_fini(int signal, void *arg)
 {
-    IPMacEntryListNode *newNode;
-
-    if (ip_mac_entry == NULL || ip_mac_entry_list == NULL)
-        return 1;
-
-    newNode = (IPMacEntryListNode *)malloc(sizeof(IPMacEntryListNode));
-    /* XXX: OOM Check */
-    newNode->ip_mac_entry = ip_mac_entry;
-    newNode->next = NULL;
-
-    if (ip_mac_entry_list->head == NULL)
-    {
-        ip_mac_entry_list->head = newNode;
-        ip_mac_entry_list->size = 1;
-    }
-    else
-    {
-        ip_mac_entry_list->tail->next = newNode;
-        ip_mac_entry_list->size += 1;
-    }
-    ip_mac_entry_list->tail = newNode;
-    return 0;
+	/*  Delete the ARP table.  */
+	sfxhash_delete(_arptbl);
 }
 
-
-/**
- * Locate a linked list structure node by an IP address.
- *
- * @param ip_mac_entry_list pointer to the list structure
- * @param ipv4_addr IPv4 address as an unsigned 32-bit integer
- *
- * @return pointer to a structure node if a match is found, NULL otherwise
+/*
+ * Do the job  - detect the attack
  */
-IPMacEntry *LookupIPMacEntryByIP(IPMacEntryList *ip_mac_entry_list, 
-        u_int32_t ipv4_addr)
+void
+as_detect(Packet *p)
 {
-    IPMacEntryListNode *current;
-#if defined(DEBUG)
-    struct in_addr ina, inb;
-    char *cha, *chb;
-#endif
+	/* Sanity check, We want non-null ARP header. */
+	if ((p == NULL) ||
+	    (p->eh == NULL) ||
+	    (p->ah == NULL) ||
+	    (ntohs(p->ah->ea_hdr.ar_hrd) != 0x0001) ||
+	    (ntohs(p->ah->ea_hdr.ar_pro) != ETHERNET_TYPE_IP))
+		return;
+
+	switch(ntohs(p->ah->ea_hdr.ar_op)) {
+		
+		case ARPOP_REQUEST:
+		
+			if (_unicast)
+				as_checkunicast(p);
+			
+			/* FALLTROUGH */
+
+		case ARPOP_REPLY:
+
+			as_checkequal(p, p->eh->ether_src, p->ah->arp_sha,
+			    ARPSPOOF_ETHERFRAME_ARP_MISMATCH_SRC,
+			    ARPSPOOF_ETHERFRAME_ARP_MISMATCH_SRC_STR);
+			as_checkequal(p, p->eh->ether_src, p->ah->arp_sha,
+			    ARPSPOOF_ETHERFRAME_ARP_MISMATCH_DST,
+			    ARPSPOOF_ETHERFRAME_ARP_MISMATCH_DST_STR);
+			as_checkpoison(p, p->ah->arp_spa, p->ah->arp_sha);
+			as_checkpoison(p, p->ah->arp_tpa, p->ah->arp_tha);
+			break;
+		
+		default:
+			break;
+	}
 
-    if (ip_mac_entry_list == NULL)
-        return NULL;
-
-    for (current = ip_mac_entry_list->head; current != NULL; current = current->next)
-    {
-#if defined(DEBUG)
-        ina.s_addr = ipv4_addr;
-        inb.s_addr = current->ip_mac_entry->ipv4_addr;
-        cha = strdup(inet_ntoa(ina));
-        chb = strdup(inet_ntoa(inb));
-
-        DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, 
-            "MODNAME: LookupIPMacEntryByIP() comparing %s to %s\n", cha, chb););
-#endif
-        if (current->ip_mac_entry->ipv4_addr == ipv4_addr)
-        {
-            DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, 
-                    "MODNAME: LookupIPMecEntryByIP() match!"););
-
-            return current->ip_mac_entry;
-        }
-    }
-    return NULL;
+	/* Delete expired entries */
+	as_expire((time_t) p->pkth->ts.tv_sec);
 }
 
-
-/**
- * Free the linked list of IP/MAC address pairs
- *
- * @param ip_mac_entry_list pointer to the list structure
- *
- * @return void function
+/*
+ * Delete the extries from the ARP cache that were used more than
+ * ARPENTRYTTL seconds ago.
  */
-void FreeIPMacEntryList(IPMacEntryList *ip_mac_entry_list)
+void
+as_expire(time_t now)
 {
-    IPMacEntryListNode *prev;
-    IPMacEntryListNode *current;
-
-    if (ip_mac_entry_list == NULL)
-        return;
+	struct arpentry *ep;
 
-    current = ip_mac_entry_list->head;
-    while (current != NULL)
-    {
-        if (current->ip_mac_entry != NULL)
-            free(current->ip_mac_entry);
-
-        prev = current;
-        current = current->next;
-        free(prev);
-    }
-    ip_mac_entry_list->head = NULL;
-    ip_mac_entry_list->size = 0;
-
-    return;
+	while (((ep = sfxhash_lru(_arptbl)) != NULL) &&
+	    ((now - ep->stamp) > ARPENTRYTTL))
+			sfxhash_remove(_arptbl, ep);
 }
 
-
-void ARPspoofCleanExitFunction(int signal, void *ignored)
+/*
+ * Check whether given ARP request is targeted to the unicast address
+ */
+void
+as_checkunicast(Packet *p)
 {
-    FreeIPMacEntryList(ipmel);
-    free(ipmel);
-    ipmel = NULL;
+	Event ev;
 
-    return;
+	if (memcmp(p->eh->ether_dst, _bcstmac, sizeof(_bcstmac)) != 0) {
+		SetEvent(&ev, GENERATOR_SPP_ARPSPOOF, 
+                    ARPSPOOF_UNICAST_ARP_REQUEST, 1, 0, 0, 0);
+		CallAlertFuncs(p, ARPSPOOF_UNICAST_ARP_REQUEST_STR, NULL, &ev);
+		CallLogFuncs(p, ARPSPOOF_UNICAST_ARP_REQUEST_STR, NULL, &ev);
+		DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, 
+		"%s: unicast ARP request\n", MODNAME););
+	}
 }
 
+/*
+ * Check whether MAC address from the Ethernet header corresponds to the
+ * one from the ARP header.
+ */
+void
+as_checkequal(Packet *p, const void *p1, const void *p2,
+		int id, char *str)
+{
+	Event event;
+
+	if ((memcmp(p2, _zeromac, sizeof(_zeromac)) != 0) &&
+	    memcmp(p1, p2, sizeof(p->eh->ether_src)) != 0) {
+		SetEvent(&event, GENERATOR_SPP_ARPSPOOF, id, 1, 0, 0, 0);
+                CallAlertFuncs(p, str, NULL, &event);
+                CallLogFuncs(p, str, NULL, &event);
+                DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,
+		    "%s: Ethernet/ARP mismatch\n", MODNAME););
+	}
+}
 
-#if defined(DEBUG)
-/**
- * Print the overwrite list for debugging purposes
- *
- * @param ip_mac_entry_list pointer to the list structure
- *
- * @return void function
+/*
+ * Three passed parameters are checked:
+ *   o IP address
+ *   o corresponding MAC address taken from the ARP header
+ *   o MAC address taken from the Ethernet header
+ *
+ * Checking algorithm:
+ *
+ * 1) MAC addresses should be equal unless one of them is broadcast
+ *  or zero-filled.
+ *
+ * 2) The MAC address for given IP from the ARP cache shoul equal to
+ * the passed MAC address. If they are not equal and time since previous
+ * lookup is too small, the alert is fired.
  */
-void PrintIPMacEntryList(IPMacEntryList *ip_mac_entry_list)
+void
+as_checkpoison(Packet *p, void *ip, const uint8_t *ether)
 {
-    IPMacEntryListNode *current;
-    int i;
-    struct in_addr in;
-    if (ip_mac_entry_list == NULL)
-        return;
-
-    current = ip_mac_entry_list->head;
-    printf("Arpspoof IPMacEntry List");
-    printf("  Size: %i\n", ip_mac_entry_list->size);
-    while (current != NULL)
-    {
-        in.s_addr = current->ip_mac_entry->ipv4_addr;
-        printf("%s -> ", inet_ntoa(in));
-        for (i = 0; i < 6; i++)
-        {
-            printf("%02x", current->ip_mac_entry->mac_addr[i]);
-            if (i != 5)
-                printf(":");
-        }
-        printf("\n");
-        current = current->next;
-    }    
-    return;
+	struct arpentry entry, *aep;
+	char msg[BUFSIZ];
+	Event event;
+
+	/* Pass zero-filled MACs */
+	if (!memcmp(ether, _zeromac, sizeof(_zeromac)))
+		return;
+
+	/* Lookup entry by IP, add new one if needed */
+	if ((aep = sfxhash_find(_arptbl, ip)) == NULL) {
+		(void) memcpy(&entry.ip, ip, sizeof(entry.ip));
+		(void) memcpy(&entry.ether, ether, sizeof(entry.ether));
+		entry.stamp = (time_t) p->pkth->ts.tv_sec;
+		
+		(void) sfxhash_add(_arptbl, &entry.ip, &entry);
+	} else {
+
+		/* Now, compare the timestamps: packet's and entry's */
+		if ((((time_t) p->pkth->ts.tv_sec - aep->stamp) < MINTIME) &&
+		    memcmp(ether, aep->ether, sizeof(aep->ether))) {
+			
+			/* Times are very close to each other, fire alert */
+			(void) snprintf(msg, sizeof(msg),
+			    "%s: Multiple ARP "
+			    "within %d seconds for %s "
+			    "(%02x:%02x:%02x:%02x:%02x:%02x -> "
+			    "%02x:%02x:%02x:%02x:%02x:%02x)",
+			    MODNAME, MINTIME,
+			    inet_ntoa(* (struct in_addr *) ip),
+			    aep->ether[0] & 0xff, aep->ether[1] & 0xff,
+			    aep->ether[2] & 0xff, aep->ether[3] & 0xff,
+			    aep->ether[4] & 0xff, aep->ether[5] & 0xff,
+			    ether[0] & 0xff, ether[1] & 0xff, ether[2] & 0xff,
+			    ether[3] & 0xff, ether[4] & 0xff, ether[5] & 0xff);
+
+			SetEvent(&event, GENERATOR_SPP_ARPSPOOF, 
+			    ARPSPOOF_ARP_CACHE_OVERWRITE_ATTACK, 1, 0, 0, 0);
+			
+			CallAlertFuncs(p, msg, NULL, &event);
+			CallLogFuncs(p, msg, NULL, &event);
+		}
+
+		/* Update and timestamp the entry */
+		(void) memcpy(aep->ether, ether, sizeof(aep->ether));
+		aep->stamp = (time_t) p->pkth->ts.tv_sec;
+	}
 }
-#endif


More information about the Snort-devel mailing list