如何编写自定义模块的ebtables?

基本上,我想写一个内核模块,为ebtables添加一个可能的filter。 然后我需要告诉ebtables在我设置的桥上使用我的filter。

我需要编写自己的模块的原因是我想在连续的包之间引入延迟(出于某种testing原因)。 为了演示,我的networking原来有这样的stream量:

+++-----------------+++-----------------+++-----------------+++----------------- 

其中+显示一个包的stream量,并且-表示没有包裹在线上。 我想在两者之间架起一座桥梁,这样数据包的模式就会变成这样:

 +----+----+---------+----+----+---------+----+----+---------+----+----+--------- 

这意味着我将确保每个数据包到达之间会有一定的延迟。

现在我已经写了下面这个简单的代码,我基本上从linux-source / net / bridge / netfilter / ebt_ip.c:

 static bool match(const struct sk_buff *skb, const struct xt_match_param *par) { printk(KERN_INFO"match called\n"); return true; // match everything! } static bool check(const struct xt_mtchk_param *par) { printk(KERN_INFO"check called\n"); return true; // pass everything! } static struct xt_match reg __read_mostly = { .name = "any", // I made this up, but I tried also putting ip for example which didn't change anything. .revision = 0, .family = NFPROTO_BRIDGE, .match = match, .checkentry = check, .matchsize = XT_ALIGN(4), // don't know what this is, so I just gave it an `int` .me = THIS_MODULE }; int init_module(void) { return xt_register_match(&reg); } void cleanup_module(void) { xt_unregister_match(&reg); } 

我成功地加载了模块。 但就好像它不在那里。 我没有得到match内的日志和checkfunction,所以桥显然不考虑我的filter。 我究竟做错了什么?

我已经尝试了许多组合,首先加载我的filter,首先设置桥或设置ebtables规则,但没有任何改变。

PS桥本身的作品。 我确定ebtables也是有效的,因为如果我添加一个策略来丢弃包,我不会在最终的计算机上收到它们。 我无法弄清楚的是如何告诉ebtables也考虑我的filter。

要使用内核模块,还需要为用户空间程序编写适当的插件,然后插入调用它的规则。

如果您没有任何选项,请不要在struct xt_match指定任何.matchsize参数(等于指定0)。

我得到了这个工作,而不是在最优雅的方式,但无论如何,我写在这里为未来的流浪者:

假设您的过滤器名称是:“any”

用户空间插件

您需要在ebtables源外部不可用的头文件。 所以,得到源代码,并进入扩展文件夹。 在Makefile中,将EXT_FUNC (即要构建的目标)添加到EXT_FUNCebt_any.c像下面这样写入源文件ebt_any.c

 #include <stdio.h> #include <getopt.h> #include "../include/ebtables_u.h" /*struct whatever { int a; };*/ static struct option _any_opts[] = { {"use-any", required_argument, 0, 0}, {'\0'} }; static void _any_help(void) { printf("any match options: nothing!\n"); } static void _any_init(struct ebt_entry_match *match) { printf("any_init\n"); } static void _any_check(const struct ebt_u_entry *entry, const struct ebt_entry_match *match, const char *name, unsigned int hookmask, unsigned int time) { printf("any_check\n"); } static int _any_parse(int c, char **argv, int argc, const struct ebt_u_entry *entry, unsigned int *flags, struct ebt_entry_match **match) { printf("any_parse: %d\n", c); if (c == 0) return 1; return 0; // return true for anything } static int _any_compare(const struct ebt_entry_match *m1, const struct ebt_entry_match *m2) { /* struct whatever *w1 = (struct whatever *)m1->data; struct whatever *w2 = (struct whatever *)m2->data; if (w1->a != w2->a) return 0;*/ return 1; } static void _any_print(const struct ebt_u_entry *entry, const struct ebt_entry_match *match) { printf("any_print"); } static struct ebt_u_match _reg = { .name = "any", // .size = sizeof(struct whatever), .help = _any_help, .init = _any_init, .parse = _any_parse, .final_check = _any_check, .print = _any_print, .compare = _any_compare, .extra_ops = _any_opts, }; void _init(void) { ebt_register_match(&_reg); } 

注意:如果你有从用户空间到内核空间的数据,写一些东西而不是struct whatever 。 我已经评论了,因为我没有使用任何东西。

注意:即使你的程序不需要一个选项(比如我应该匹配所有的选项),你仍然需要提供一个选项,因为这是ebtables知道如何使用你的过滤器。

注意:其中一些功能看起来没有必要,但是如果不写这些功能,则会出现“BUG:错误合并”错误。

内核空间模块

内核空间模块更简单:

 #include <linux/netfilter/x_tables.h> #include <linux/module.h> #include <linux/kernel.h> MODULE_LICENSE("GPL"); MODULE_AUTHOR("Shahbaz Youssefi"); MODULE_ALIAS("ebt_any"); /*struct whatever { int a; };*/ static bool match(const struct sk_buff *skb, const struct xt_match_param *par) { printk(KERN_INFO"Matching\n"); return true; } static bool check(const struct xt_mtchk_param *par) { printk(KERN_INFO"Checking\n"); return true; } static struct xt_match reg __read_mostly = { .name = "any", .match = match, // .matchsize = sizeof(struct whatever), .checkentry = check, .me = THIS_MODULE }; int init_module(void) { int ret = 0; printk("Bridge initializing...\n"); ret = xt_register_match(&reg); printk("Bridge initializing...done!\n"); return ret; } void cleanup_module(void) { printk("Bridge exiting...\n"); xt_unregister_match(&reg); printk("Bridge exiting...done!\n"); } 

注意:如果在用户空间中使用struct whatever ,则必须在内核空间中使用相同的结构。

注意:与使用ebtables头文件/函数的用户空间插件不同,内核模块使用xtables代替!

编译模块(相当标准),并安装它自动加载。 或者,您可以在删除ebtables规则之前添加/删除模块。

如何让ebtables使用你的过滤器

只需添加一个包含--use-any some_value的规则--use-any some_value 。 例如:

 ebtables -A FORWARD --use-any 1 -j ACCEPT 

注意:这个--use-any是用户空间插件中的ebt_u_match reg.extra_ops (在ebt_u_match reg.extra_ops数组中定义的)选项。