📄 sp_respond2.c
字号:
/* $Id$ *//*** Copyright (C) 2002-2004 Jeff Nathan <jeff@snort.org>** Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>** Copyright (C) 1999,2000,2001 Christian Lademann <cal@zls.de>**** This program is free software; you can redistribute it and/or modify** it under the terms of the GNU General Public License Version 2 as** published by the Free Software Foundation. You may not use, modify or** distribute this program under any other version of the GNU General** Public License.**** 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 sp_respond2 Detection Plugin * by Jeff Nathan <jeff@snort.org> * Version 1.0.2 * * Purpose: * * Perform active response on packets matching conditions specified * in Snort rules. * * * Arguments: * * To enable link-layer response, specify the following in snort.conf * config flexresp2_interface: <interface> * * To configure the number of TCP response attempts, specify the following in * snort.conf (the maximum is 20) * config flexresp2_attempts: <attempts> * * To configure the response cache memcap, specify the following in snort.conf * config flexresp2_memcap: <memcap> * * To configure the number of rows in the response cache , specify the * following in snort.conf * config flexresp2_rows: <rows> * * Effect: * * Shutdown hostile network connections by falsifying TCP resets or ICMP * unreachable packets * * * Acknowledgements: * * Improvements inspired by Dug Song's tcpkill. Thanks Dug. * * * Comments: * * sp_respond2 uses libdnet rather than libnet and supports link-layer * injection so you can specify the network interface responses will be sent * from (and bypass the kernel routing table). This allows multi-homed * systems to use Snort's flexible response system (sp_respond was broken in * this regard). * * Resetting TCP connections with a passive NIDS is depends on speed, * and prediction. sp_respond2 attempts to brute force active response by * trying to predict changes in the sequence number and ack number of * an active connection while trying to shut it down. * * Finally, * sp_respond2 does NOT utilize TCP flags to determine whether or not * a packet should be considered valid. This is primarily due to * inconsistencies in establishing TCP connections. Reference: * http://www.securityfocus.com/archive/1/296122/2002-10-19/2002-10-25/2 * * * Bugs: * * All software has bugs. When you find a bug read the BUGS document * in the doc directory of the Snort source distribution for instructions * on submitting a bug report. * * Enjoy, * * -Jeff */#ifdef HAVE_CONFIG_H#include "config.h"#endif#if defined(ENABLE_RESPONSE2) && !defined(ENABLE_RESPONSE)#include <dnet.h>#include "decode.h"#include "rules.h"#include "plugbase.h"#include "parser.h"#include "debug.h"#include "util.h"#include "log.h"#include "mstring.h"#include "plugin_enum.h"#include "snort.h"#include "checksum.h"#include "bounds.h"#include "sfxhash.h"#define IPIDCOUNT 8192 /* number of randomly generated IP IDs */#define CACHETIME 2 /* dampening interval */ #define MODNAME "sp_respond2" /* plugin name */#define DEFAULT_ROWS 1024#define DEFAULT_MEMCAP (1024 * 1024)typedef struct _RespondData{ u_int response_flag;} RespondData;/* response cache data structure */typedef struct _RESPKEY{ u_int32_t sip; /* source IP */ u_int32_t dip; /* dest IP */ u_int16_t sport; /* source port/ICMP type */ u_int16_t dport; /* dest port/ICMP code */ u_int8_t proto; /* IP protocol */ u_int8_t _pad[3]; /* empty bits for word alignment */} RESPKEY;typedef struct _RESPOND2_CONFIG{ int rows; /* response cache size (in rows) */ int memcap; /* response cache memcap */ u_int8_t respond_attempts; /* respond attempts per trigger */ ip_t *rawdev; /* dnet(3) raw IP handle */ eth_t *ethdev; /* dnet(3) ethernet device handle */ rand_t *randh; /* dnet(3) rand handle */} RESPOND2_CONFIG;extern PV pv;static void *ip_id_pool = NULL; /* random IP ID buffer */static u_int32_t ip_id_iterator; /* consumed IP IDs */static void *tcp_pkt = NULL; /* TCP packet memory placeholder */static void *icmp_pkt = NULL; /* ICMP packet memory placeholder */static u_int8_t link_offset; /* offset from L2 to L3 header */static u_int8_t alignment; /* force alignment ?? */SFXHASH *respcache = NULL; /* cache responses to prevent loops */static RESPKEY response;static RESPOND2_CONFIG config;/* API functions */static void Respond2Init(char *data, OptTreeNode *otn, int protocol);static void Respond2Restart(int signal, void *data);static int ParseResponse2(char *type);/* CORE respond2 functions */static int Respond2(Packet *p, RspFpList *fp_list);static INLINE void SendReset(const int mode, Packet *p, RESPOND2_CONFIG *conf);static INLINE void SendUnreach(const int code, Packet *p, RESPOND2_CONFIG *conf);static INLINE int IsRSTCandidate(Packet *p);static INLINE int IsUNRCandidate(Packet *p);static INLINE int IsLinkCandidate(Packet *p);static INLINE u_int16_t RandID(RESPOND2_CONFIG *conf);static INLINE u_int8_t CalcOriginalTTL(Packet *p);/* UTILITY functions */static void PrecacheTCP(void);static void PrecacheICMP(void);static void GenRandIPID(RESPOND2_CONFIG *conf);static void SetLinkInfo(void);static void SetRespAttempts(RESPOND2_CONFIG *conf);static void SetRespCacheRows(RESPOND2_CONFIG *conf);static void SetRespCacheMemcap(RESPOND2_CONFIG *conf);/* HASH functions */static int respcache_init(SFXHASH **cache, RESPOND2_CONFIG *conf);static INLINE int dampen_response(Packet *p);static INLINE int respkey_make(RESPKEY *hashkey, Packet *p);/* ######## API section ######## *//** * Initialize respond2 plugin * * @return void function */void SetupRespond2(void){ RegisterPlugin("resp", Respond2Init, OPT_TYPE_ACTION); GenRandIPID(&config); /* generate random IP ID cache */ return;}/** * Respond2 initialization function * * @param data argument passed to the resp keyword * @param otn pointer to an OptTreeNode structure * @param protocol Snort rule protocol (IP/TCP/UDP) * * @return void function */static void Respond2Init(char *data, OptTreeNode *otn, int protocol) { static int setup = 0; RespondData *rd = NULL; if (!(protocol & (IPPROTO_ICMP | IPPROTO_TCP | IPPROTO_UDP))) FatalError("%s: %s(%d): Can't respond to IP protocol rules.\n", MODNAME, file_name, file_line); rd = (RespondData *)SnortAlloc(sizeof(RespondData)); if (!setup) { SetLinkInfo(); /* setup link-layer pointer arithmetic info */ SetRespAttempts(&config); /* configure # of TCP attempts */ SetRespCacheRows(&config); /* configure # of rows in cache */ SetRespCacheMemcap(&config); /* configure response cache memcap */ if ((respcache_init(&respcache, &config)) != 0) FatalError("%s: Unable to allocate hash table memory.\n", MODNAME); /* Open raw socket or network device before Snort drops privileges */ if (link_offset) { if (config.ethdev == NULL) /* open link-layer device */ { if ((config.ethdev = eth_open(pv.respond2_ethdev)) == NULL) FatalError("%s: Unable to open link-layer device: %s.\n", MODNAME, pv.respond2_ethdev); } DEBUG_WRAP( DebugMessage(DEBUG_PLUGIN, "%s: using link-layer " "injection on interface %s\n", MODNAME, pv.respond2_ethdev); DebugMessage(DEBUG_PLUGIN, "%s: link_offset = %d\n", MODNAME, link_offset); ); } else { if (config.rawdev == NULL) /* open raw device if necessary */ { if ((config.rawdev = ip_open()) == NULL) FatalError("%s: Unable to open raw socket.\n", MODNAME); } } setup = 1; DEBUG_WRAP( DebugMessage(DEBUG_PLUGIN, "%s: respond_attempts = %d\n", MODNAME, config.respond_attempts); DebugMessage(DEBUG_PLUGIN, "Plugin: Respond2 is setup\n"); ); } rd->response_flag = ParseResponse2(data); AddRspFuncToList(Respond2, otn, (void *)rd); /* Restart and CleanExit function are identical */ AddFuncToCleanExitList(Respond2Restart, &config); AddFuncToRestartList(Respond2Restart, &config); return;}/** * respond2 signal handler * re-initializes packet memory and close device handles * * @param data pointer to a RESPOND2_CONFIG data structure * * @return void function */static void Respond2Restart(int signal, void *data){ RESPOND2_CONFIG *conf = (RESPOND2_CONFIG *)data; /* device and raw IP handles */ if (conf->rawdev != NULL) conf->rawdev = ip_close(conf->rawdev); if (conf->ethdev != NULL) conf->ethdev = eth_close(conf->ethdev); /* free packet memory */ if (tcp_pkt != NULL) { tcp_pkt -= alignment; free(tcp_pkt); tcp_pkt = NULL; } if (icmp_pkt != NULL) { icmp_pkt -= alignment; free(icmp_pkt); icmp_pkt = NULL; } /* free IP ID pool and close random handle */ if (ip_id_pool != NULL) { free(ip_id_pool); ip_id_pool = NULL; /* reset iterator */ ip_id_iterator = 0; } if (conf->randh != NULL) conf->randh = rand_close(conf->randh); /* destroy the response dampening hash table */ if (respcache != NULL) { sfxhash_delete(respcache); respcache = NULL; } return;}/** * Determine how to handle hostile connection attempts * * @param type string of comma-separated response modifiers * * @return integer describing the type of response action on a matching packet */static int ParseResponse2(char *type){ char **toks; int response_flag = 0; int num_toks; static int make_tcp = 0; static int make_icmp = 0; int i; while (isspace((int) *type)) type++; if (!type || !(*type)) return 0; toks = mSplit(type, ",", 6, &num_toks, 0); if (num_toks < 1) FatalError("ERROR %s (%d): Bad arguments to respond2: %s.\n", file_name, file_line, type); i = 0; while (i < num_toks) { if (!strcasecmp(toks[i], "reset_source")) { response_flag |= RESP_RST_SND; if (!make_tcp) make_tcp = 1; i++; } else if (!strcasecmp(toks[i], "reset_dest")) { response_flag |= RESP_RST_RCV; if (!make_tcp) make_tcp = 1; i++; } else if (!strcasecmp(toks[i], "reset_both")) { response_flag |= (RESP_RST_RCV | RESP_RST_SND); if (!make_tcp) make_tcp = 1; i++; } else if (!strcasecmp(toks[i], "icmp_net")) { response_flag |= RESP_BAD_NET; if (!make_icmp) make_icmp = 1; i++; } else if (!strcasecmp(toks[i], "icmp_host")) { response_flag |= RESP_BAD_HOST; if (!make_icmp) make_icmp = 1; i++; } else if (!strcasecmp(toks[i], "icmp_port")) { response_flag |= RESP_BAD_PORT; if (!make_icmp) make_icmp = 1; i++; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -