[Ebtables-devel] New match extension, similar to iptables --packet
Brought to you by:
bdschuym
From: Daniele G. <dan...@gm...> - 2006-10-16 17:03:19
|
I have developed a new match extension which matches every 'n'th frame. This may be useful for research purposes or for load balancing (e.g. we are using it to scatter frames to several IDS sensors using DNAT in a round-robin fashion). $ diff -r ebtables-v2.0.8-rc2 ebtables-v2.0.8-rc2_DanieleGozzi Only in ebtables-v2.0.8-rc2_DanieleGozzi/extensions: ebt_nth.c diff -r ebtables-v2.0.8-rc2/extensions/Makefile ebtables-v2.0.8-rc2_DanieleGozzi/extensions/Makefile 4c4 < pkttype stp among limit ulog --- > pkttype stp among limit ulog nth Only in ebtables-v2.0.8-rc2_DanieleGozzi/include/linux/netfilter_bridge:ebt_nth.h The code of the two new files (following) should compile without warning against ebtables v2.0.8-rc2 (I'm using gcc v4.0.3). ---***--- ebt_nth.h ---***--- #ifndef __LINUX_BRIDGE_EBT_NTH_H #define __LINUX_BRIDGE_EBT_NTH_H #define EBT_NTH_MATCH "nth" struct ebt_nth_info { unsigned long int every; // match every /every/ frames. unsigned long int frame; // match phase shift. match on /frame-th/ frame every /every/ frames. /* Used internally by the kernel module*/ unsigned long int counter; }; #endif ---***---***---***--- ---***--- ebt_nth.c ---***--- /* Shared library add-on to ebtables to add "nth" match support. * Daniele Gozzi <dan...@gm...> * based on: * Shared library add-on to ebtables to add limit support. (part of ebtables package) * (Swipted from iptables' limit match.) */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <getopt.h> #include <netinet/ether.h> #include "../include/ebtables_u.h" #include <linux/netfilter_bridge/ebt_nth.h> /* from iptables.c */ #include <errno.h> int string_to_number_lu(const char *s, unsigned long int min, unsigned long int max, unsigned long int *ret) { unsigned long int number; char *end; /* Handle hex, octal, etc. */ errno = 0; number = strtoul(s, &end, 0); if (*end == '\0' && end != s) { /* we parsed a number, let's see if we want this */ if (errno != ERANGE && min <= number && number <= max) { *ret = number; return 0; } } return -1; } #define FLAG_EVERY 0x01 #define FLAG_FRAME 0x02 #define ARG_EVERY '1' #define ARG_FRAME '2' static struct option opts[] = { { "every", required_argument, 0, ARG_EVERY }, { "frame", required_argument, 0, ARG_FRAME }, { 0 } }; static void print_help(void) { printf( "limit options:\n" "--every number match rate\n" "--frame number frame number to match, 0 <= number < every_number" " (default = 0)\n" "\n"); } /* Initialize the match. */ static void init(struct ebt_entry_match *m) { struct ebt_nth_info *r = (struct ebt_nth_info *)m->data; r->counter = 0; r->frame = 0; // default r->every = 0; // default } static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry, unsigned int *flags, struct ebt_entry_match **match) { struct ebt_nth_info *r = (struct ebt_nth_info *)(*match)->data; switch(c) { case ARG_EVERY: ebt_check_option2(flags, FLAG_EVERY); if (ebt_check_inverse2(optarg)) ebt_print_error2("Unexpected `!' after --every"); if (string_to_number_lu(optarg, 1, ULONG_MAX,&r->every) == -1) ebt_print_error2("bad --every `%s' (must be between 1 and %u)", optarg, ULONG_MAX); break; case ARG_FRAME: ebt_check_option2(flags, FLAG_FRAME); if (ebt_check_inverse2(optarg)) ebt_print_error2("Unexpected `!' after --frame"); if (string_to_number_lu(optarg, 0, ULONG_MAX-1, &r->frame) == -1) ebt_print_error2("bad --frame `%s' (must be between 1 and %u)", optarg, ULONG_MAX-1); break; default: return 0; } return 1; } static void final_check(const struct ebt_u_entry *entry, const struct ebt_entry_match *match, const char *name, unsigned int hookmask, unsigned int time) { struct ebt_nth_info *r = (struct ebt_nth_info *)match->data; if (r->every==0 || r->frame >= r->every) ebt_print_error("--frame argument must be lower than --every"); } /* Prints out the matchinfo. */ static void print(const struct ebt_u_entry *entry, const struct ebt_entry_match *match) { struct ebt_nth_info *r = (struct ebt_nth_info *)match->data; printf("--every %lu ",r->every); printf("--frame %lu ",r->frame); } static int compare(const struct ebt_entry_match* m1, const struct ebt_entry_match *m2) { struct ebt_nth_info* li1 = (struct ebt_nth_info*)m1->data; struct ebt_nth_info* li2 = (struct ebt_nth_info*)m2->data; if (li1->every != li2->every) return 0; if (li1->frame != li2->frame) return 0; return 1; } static struct ebt_u_match nth_match = { .name = EBT_NTH_MATCH, .size = sizeof(struct ebt_nth_info), .help = print_help, .init = init, .parse = parse, .final_check = final_check, .print = print, .compare = compare, .extra_ops = opts, }; //static _init(void) __attribute((constructor)); void _init(void) { ebt_register_match(&nth_match); } ---***---***---***--- Of course a matching kernel module is needed. Module code follows (it uses the same ebt_nth.h header file as the previous ebtables code): ---***--- ebt_nth.c ---***--- /* * ebt_nth * * Authors: * Daniele Gozzi <dan...@gm...> * * Nth frame match module for ebtables / linux netfilter-bridge * Based on ebt_limit.c by Tom Marshall and bt_802_3.c by Chris Vitale */ #include <linux/module.h> /* Needed by all modules */ #include <linux/kernel.h> /* Needed for KERN_INFO */ #include <linux/init.h> /* Needed for the macros */ #include <linux/netfilter_bridge/ebtables.h> #include "ebt_nth.h" MODULE_AUTHOR("Daniele Gozzi"); static int ebt_nth_match(const struct sk_buff *skb, const struct net_device *in, const struct net_device *out, const void *data, unsigned int datalen) { struct ebt_nth_info *info = (struct ebt_nth_info *) data; /* update counter value (modulo /every/) */ info->counter = (info->counter + 1) % info->every; /* is this frame supposed to match? */ if (info->counter == info->frame) return EBT_MATCH; return EBT_NOMATCH; } static int ebt_nth_check(const char *tablename, unsigned int hookmask, const struct ebt_entry *e, void *data, unsigned int datalen) { struct ebt_nth_info *info = (struct ebt_nth_info *) data; if (datalen < sizeof(struct ebt_nth_info)) return -EINVAL; if (info->every == 0 || info->frame >= info->every) return -EINVAL; return 0; } static struct ebt_match ebt_nth_reg = { .name = EBT_NTH_MATCH, .match = ebt_nth_match, .check = ebt_nth_check, .me = THIS_MODULE, }; static int __init nth_match_init(void) { printk(KERN_INFO "Initializing nth match for ebtables\n"); return ebt_register_match(&ebt_nth_reg); } static void __exit nth_match_exit(void) { printk(KERN_INFO "Unloading nth match for ebtables\n"); ebt_unregister_match(&ebt_nth_reg); } module_init(nth_match_init); module_exit(nth_match_exit); ---***---***---***--- ---***--- Makefile ---***--- obj-m += ebt_nth.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean ---***---***---***--- Thank you for your consideration. Daniele Gozzi |