Permalink
Browse files

Merge pull request #7 from wertarbyte/filters

use multiple filters with a single ettercap instance
  • Loading branch information...
drizzt committed Oct 3, 2011
2 parents 8dc8039 + 7b9adb9 commit 28d05b5886465ddf36b3dfce6324e55c44a473d9
Showing with 153 additions and 27 deletions.
  1. +14 −3 include/ec_filter.h
  2. +2 −2 include/ec_globals.h
  3. +2 −0 man/ettercap.8.in
  4. +1 −2 src/ec_decode.c
  5. +70 −19 src/ec_filter.c
  6. +5 −1 src/ec_globals.c
  7. +3 −0 src/ec_main.c
  8. +56 −0 src/interfaces/text/ec_text.c
View
@@ -112,6 +112,14 @@ struct filter_env {
size_t len;
};
+/* filter list entry */
+struct filter_list {
+ uint8_t enabled;
+ char *name;
+ struct filter_env env;
+ struct filter_list *next;
+};
+
/* uset to compile the regex while loading the file */
struct regex_opt {
regex_t *regex;
@@ -123,11 +131,14 @@ struct regex_opt {
#define PCRE_OVEC_SIZE 100
+void filter_init_mutex(void);
+
/* exported functions */
-EC_API_EXTERN int filter_engine(struct filter_op *fop, struct packet_object *po);
-EC_API_EXTERN int filter_load_file(char *filename, struct filter_env *fenv);
-EC_API_EXTERN void filter_unload(struct filter_env *fenv);
+EC_API_EXTERN void filter_packet(struct packet_object *po);
+EC_API_EXTERN int filter_load_file(char *filename, struct filter_list **list);
+EC_API_EXTERN void filter_unload(struct filter_list **list);
+EC_API_EXTERN void filter_clear(void);
#endif
View
@@ -162,7 +162,7 @@ struct globals {
struct target_env *t2;
LIST_HEAD(, hosts_list) hosts_list_head;
TAILQ_HEAD(gbl_ptail, host_profile) profiles_list_head;
- struct filter_env *filters;
+ struct filter_list *filters;
};
EC_API_EXTERN struct globals *gbls;
@@ -183,7 +183,7 @@ EC_API_EXTERN struct globals *gbls;
#define GBL_TARGET2 (GBLS->t2)
#define GBL_HOSTLIST (GBLS->hosts_list_head)
#define GBL_PROFILES (GBLS->profiles_list_head)
-#define GBL_FILTERS (GBLS->filters)
+#define GBL_FILTERS &(GBLS->filters)
#define GBL_FORMAT (GBL_OPTIONS->format)
View
@@ -622,6 +622,8 @@ Load the filter from the file <FILE>. The filter must be compiled with
etterfilter(8). The utility will compile the filter script and produce an
ettercap-compliant binary filter file. Read the etterfilter(8) man page for the
list of functions you can use inside a filter script.
+Any number of filters can be loaded by specifying the option multiple times;
+packets are passed through each filter in the order specified on the command line.
.br
NOTE: these filters are different from those set with \-\-pcapfilter. An ettercap
filter is a content filter and can modify the payload of a packet before
View
@@ -297,8 +297,7 @@ FUNC_DECODER(decode_data)
* here we can filter the content of the packet.
* the injection is done elsewhere.
*/
- if (GBL_FILTERS->chain)
- filter_engine(GBL_FILTERS->chain, po);
+ filter_packet(po);
/* If the modified packet exceeds the MTU split it into inject buffer */
inject_split_data(po);
View
@@ -36,18 +36,19 @@
#define JIT_FAULT(x, ...) do { USER_MSG("JIT FILTER FAULT: " x "\n", ## __VA_ARGS__); return -EFATAL; } while(0)
-static pthread_mutex_t filters_mutex = PTHREAD_MUTEX_INITIALIZER;
+/* since we need a recursive mutex, we cannot initialize it here statically */
+static pthread_mutex_t filters_mutex;
#define FILTERS_LOCK do{ pthread_mutex_lock(&filters_mutex); }while(0)
#define FILTERS_UNLOCK do{ pthread_mutex_unlock(&filters_mutex); }while(0)
/* protos */
-int filter_load_file(char *filename, struct filter_env *fenv);
-void filter_unload(struct filter_env *fenv);
+int filter_load_file(char *filename, struct filter_list **list);
+void filter_unload(struct filter_list **list);
static void reconstruct_strings(struct filter_env *fenv, struct filter_header *fh);
static int compile_regex(struct filter_env *fenv, struct filter_header *fh);
-int filter_engine(struct filter_op *fop, struct packet_object *po);
+static int filter_engine(struct filter_op *fop, struct packet_object *po);
static int execute_test(struct filter_op *fop, struct packet_object *po);
static int execute_assign(struct filter_op *fop, struct packet_object *po);
static int execute_incdec(struct filter_op *fop, struct packet_object *po);
@@ -71,12 +72,21 @@ static int cmp_leq(u_int32 a, u_int32 b);
static int cmp_geq(u_int32 a, u_int32 b);
/*******************************************/
+/* initialize the filter mutex */
+void filter_init_mutex(void) {
+ pthread_mutexattr_t at;
+ pthread_mutexattr_init(&at);
+ /* we want an recursive mutex, so we can re-aquire it in the same thread */
+ pthread_mutexattr_settype(&at, PTHREAD_MUTEX_RECURSIVE_NP);
+ pthread_mutex_init(&filters_mutex, &at);
+}
+
/*
* JIT interpreter for binary filters.
* it process the filter_ops and apply the instructions
* on the given packet object
*/
-int filter_engine(struct filter_op *fop, struct packet_object *po)
+static int filter_engine(struct filter_op *fop, struct packet_object *po)
{
u_int32 eip = 0;
u_int32 flags = 0;
@@ -161,6 +171,20 @@ int filter_engine(struct filter_op *fop, struct packet_object *po)
return 0;
}
+/*
+ * pass a packet through every (enabled) filter loaded
+ */
+void filter_packet(struct packet_object *po) {
+ struct filter_list **l;
+ for (l = GBL_FILTERS; *l != NULL; l = &(*l)->next) {
+ /* if a script drops the packet, do not present it to following scripts */
+ if ( po->flags & PO_DROPPED )
+ break;
+ /* check whether the filter script is enabled */
+ if ((*l)->enabled)
+ filter_engine((*l)->env.chain, po);
+ }
+}
/*
* execute a function.
@@ -922,16 +946,17 @@ static int cmp_geq(u_int32 a, u_int32 b)
/*
* load the filter from a file
*/
-int filter_load_file(char *filename, struct filter_env *fenv)
+int filter_load_file(char *filename, struct filter_list **list)
{
int fd;
void *file;
size_t size, ret;
+ struct filter_env *fenv;
struct filter_header fh;
DEBUG_MSG("filter_load_file (%s)", filename);
-
- /* open the file */
+
+ /* open the file */
if ((fd = open(filename, O_RDONLY | O_BINARY)) == -1)
FATAL_MSG("File not found or permission denied");
@@ -963,10 +988,14 @@ int filter_load_file(char *filename, struct filter_env *fenv)
if (ret != size)
FATAL_MSG("Cannot read the file into memory");
- /* make sure we don't override a previous filter */
- filter_unload(fenv);
-
FILTERS_LOCK;
+
+ /* advance to the end of the filter list */
+ while (*list) list = &(*list)->next;
+
+ /* allocate memory for the list entry */
+ SAFE_CALLOC(*list, 1, sizeof(struct filter_list));
+ fenv = &(*list)->env;
/* set the global variables */
fenv->map = file;
@@ -979,6 +1008,12 @@ int filter_load_file(char *filename, struct filter_env *fenv)
*/
reconstruct_strings(fenv, &fh);
+ /* save the name of the loaded filter */
+ (*list)->name = strdup(filename);
+
+ /* enable the filter */
+ (*list)->enabled = 1;
+
FILTERS_UNLOCK;
/* compile the regex to speed up the matching */
@@ -991,21 +1026,20 @@ int filter_load_file(char *filename, struct filter_env *fenv)
}
/*
- * unload a filter chain.
+ * unload a filter list entry
*/
-void filter_unload(struct filter_env *fenv)
+void filter_unload(struct filter_list **list)
{
+ if (*list == NULL) return;
+
+ FILTERS_LOCK;
+
+ struct filter_env *fenv= &(*list)->env;
size_t i = 0;
struct filter_op *fop = fenv->chain;
DEBUG_MSG("filter_unload");
- /* if not loaded, return */
- if (fenv->map == NULL || fenv->chain == NULL)
- return;
-
- FILTERS_LOCK;
-
/* free the memory alloc'd for regex */
while (fop != NULL && i < (fenv->len / sizeof(struct filter_op)) ) {
/* search for func regex and pcre */
@@ -1036,6 +1070,23 @@ void filter_unload(struct filter_env *fenv)
fenv->chain = NULL;
fenv->len = 0;
+ SAFE_FREE((*list)->name);
+
+ /* reclose the filter list */
+ struct filter_list **ptr = list;
+ struct filter_list *succ = (*list)->next;
+ *ptr = succ;
+ SAFE_FREE(*list);
+
+ FILTERS_UNLOCK;
+}
+
+void filter_clear(void) {
+ FILTERS_LOCK;
+ struct filter_list **l = GBL_FILTERS;
+ while (*l) {
+ filter_unload(l);
+ }
FILTERS_UNLOCK;
}
View
@@ -20,6 +20,7 @@
#include <ec.h>
#include <ec_sniff.h>
+#include <ec_filter.h>
#define GBL_FREE(x) do{ if (x != NULL) { free(x); x = NULL; } }while(0)
@@ -51,7 +52,8 @@ void globals_alloc(void)
SAFE_CALLOC(gbls->sm, 1, sizeof(struct sniffing_method));
SAFE_CALLOC(gbls->t1, 1, sizeof(struct target_env));
SAFE_CALLOC(gbls->t2, 1, sizeof(struct target_env));
- SAFE_CALLOC(gbls->filters, 1, sizeof(struct filter_env));
+ /* filter list entries are allocated as needed */
+ gbls->filters = NULL;
/* init the struct */
TAILQ_INIT(&GBL_PROFILES);
@@ -91,6 +93,8 @@ void globals_free(void)
GBL_FREE(gbls->stats);
GBL_FREE(gbls->options);
GBL_FREE(gbls->conf);
+ /* destroy the list structure */
+ filter_clear();
GBL_FREE(gbls);
View
@@ -66,6 +66,9 @@ int main(int argc, char *argv[])
DEBUG_INIT();
DEBUG_MSG("main -- here we go !!");
+
+ /* initialize the filter mutex */
+ filter_init_mutex();
/* register the main thread as "init" */
ec_thread_register(EC_PTHREAD_SELF, "init", "initialization phase");
@@ -56,6 +56,7 @@ static void text_input(const char *title, char *input, size_t n, void (*callback
static void text_help(void);
static int text_progress(char *title, int value, int max);
static void text_run_plugin(void);
+static void text_run_filter(void);
static void text_stats(void);
static void text_stop_cont(void);
static void text_hosts_list(void);
@@ -324,6 +325,10 @@ void text_interface(void)
case 'p':
text_run_plugin();
break;
+ case 'F':
+ case 'f':
+ text_run_filter();
+ break;
case 'S':
case 's':
text_stats();
@@ -372,6 +377,7 @@ static void text_help(void)
fprintf(stderr, "\nInline help:\n\n");
fprintf(stderr, " [vV] - change the visualization mode\n");
fprintf(stderr, " [pP] - activate a plugin\n");
+ fprintf(stderr, " [fF] - (de)activate a filter\n");
fprintf(stderr, " [lL] - print the hosts list\n");
fprintf(stderr, " [oO] - print the profiles list\n");
fprintf(stderr, " [cC] - print the connections list\n");
@@ -459,6 +465,56 @@ static void text_run_plugin(void)
}
+/*
+ * display the list of loaded filters and
+ * allow the user to enable or disable them
+ */
+static void text_run_filter(void) {
+ int restore = 0;
+ /* stop the visualization while the plugin interface is running */
+ if (!GBL_OPTIONS->quiet) {
+ text_stop_cont();
+ restore = 1;
+ }
+ ui_msg_flush(MSG_ALL);
+
+ fprintf(stderr, "\nLoaded etterfilter scripts:\n\n");
+ while(1) {
+ struct filter_list **l;
+ char input[20];
+ int i = 1;
+ int number = -1;
+
+ /* repristinate the buffer input */
+ tcsetattr(0, TCSANOW, &old_tc);
+
+ for (l = GBL_FILTERS; *l; l = &(*l)->next) {
+ fprintf(stdout, "[%d (%d)]: %s\n", i++, (*l)->enabled, (*l)->name);
+ }
+
+ fprintf(stdout, "\nEnter number to enable/disable filter (0 to quit): ");
+ /* get the user input */
+ fgets(input, 19, stdin);
+ number = -1;
+ sscanf(input, "%d", &number);
+ if (number == 0) {
+ break;
+ } else if (number > 0) {
+ for (l = GBL_FILTERS; *l; l = &(*l)->next) {
+ if (!--number) {
+ /* we reached the item */
+ (*l)->enabled = ! (*l)->enabled;
+ break;
+ }
+ }
+ }
+ };
+
+ /* continue the visualization */
+ if (restore)
+ text_stop_cont();
+}
+
/*
* print the interface statistics
*/

0 comments on commit 28d05b5

Please sign in to comment.