基本上,我想写一个内核模块,为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(®); } void cleanup_module(void) { xt_unregister_match(®); }
我成功地加载了模块。 但就好像它不在那里。 我没有得到match
内的日志和check
function,所以桥显然不考虑我的filter。 我究竟做错了什么?
我已经尝试了许多组合,首先加载我的filter,首先设置桥或设置ebtables规则,但没有任何改变。
PS桥本身的作品。 我确定ebtables也是有效的,因为如果我添加一个策略来丢弃包,我不会在最终的计算机上收到它们。 我无法弄清楚的是如何告诉ebtables也考虑我的filter。
要使用内核模块,还需要为用户空间程序编写适当的插件,然后插入调用它的规则。
如果您没有任何选项,请不要在struct xt_match
指定任何.matchsize
参数(等于指定0)。
我得到了这个工作,而不是在最优雅的方式,但无论如何,我写在这里为未来的流浪者:
假设您的过滤器名称是:“any”
您需要在ebtables源外部不可用的头文件。 所以,得到源代码,并进入扩展文件夹。 在Makefile中,将EXT_FUNC
(即要构建的目标)添加到EXT_FUNC
, ebt_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(®); printk("Bridge initializing...done!\n"); return ret; } void cleanup_module(void) { printk("Bridge exiting...\n"); xt_unregister_match(®); printk("Bridge exiting...done!\n"); }
注意:如果在用户空间中使用struct whatever
,则必须在内核空间中使用相同的结构。
注意:与使用ebtables头文件/函数的用户空间插件不同,内核模块使用xtables代替!
编译模块(相当标准),并安装它自动加载。 或者,您可以在删除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
数组中定义的)选项。