Как написать собственный модуль для ebtables?
По сути, я хочу написать модуль ядра, который добавляет возможный фильтр в ebtables. Затем я должен указать ebtables использовать мой фильтр на мосту, который я настроил.
Причина, по которой мне нужно написать свой собственный модуль, заключается в том, что я хочу ввести задержку между последовательными пакетами (по некоторым причинам тестирования). Чтобы продемонстрировать, у моей сети первоначально есть трафик как это:
+++-----------------+++-----------------+++-----------------+++-----------------
где +
показывает трафик пакета и -
означает, что нет пакета на линии. Я хочу поставить мост между ними, чтобы шаблон пакетов изменился на это:
+----+----+---------+----+----+---------+----+----+---------+----+----+---------
Это означает, что я должен быть уверен, что между прибытием каждого пакета будет определенная задержка.
Теперь я написал следующий простой код, который я в основном взял из 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
функции, поэтому мост явно не рассматривает мой фильтр. Что я делаю неправильно?
Я пробовал много комбинаций: сначала загрузить фильтр, сначала настроить мост, либо сначала установить правила ebtables, но ни одно из них ничего не изменило.
PS Сам мост работает. Я уверен, что ebtables также действует, потому что, если я добавлю политику для удаления пакетов, я не получу их на конечном компьютере. Чего я не могу понять, так это как ebtables учесть мой фильтр.
2 ответа
Чтобы использовать модуль ядра, вам также нужно написать соответствующий плагин для программы пользовательского пространства, а затем вставить правило, вызывающее его.
Если у вас нет вариантов, не указывайте .matchsize
параметр в struct xt_match
(равно указанию 0).
Я понял, что это работает не самым элегантным образом, но в любом случае, я пишу это здесь для будущего странника:
Допустим, ваш фильтр называется: "любой"
Плагин пользовательского пространства
Вам нужны заголовки, которые не доступны за пределами источника ebtables. Итак, получите исходный код и перейдите в папку расширений. В Makefile добавьте any
в EXT_FUNC
(то есть цели, которые будут построены) и напишите исходный файл 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: bad merge".
Ядро-космический модуль
Модуль пространства ядра проще:
#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!!
Скомпилируйте модуль (достаточно стандартный) и установите его для автоматической загрузки. Кроме того, вы можете insmod
а также rmmod
модуль самостоятельно до добавления / после удаления правил ebtables.
Как заставить ebtables использовать ваш фильтр
Просто добавьте правило, которое содержит --use-any some_value
и ты в порядке. Например:
ebtables -A FORWARD --use-any 1 -j ACCEPT
Примечание: это --use-any
это option
это было дано в ebt_u_match reg.extra_ops
(который был определен в массиве _any_opts
) в плагине пространства пользователя.