Данная статья основывается на материале "Разработка Match-модуля для iptables своими руками" (http://www.linuxjournal.com/article/7184), но код работает на ядрах 2.6.20+.Мне потребовалось изменить ID IP пакетов, в интернете подходящей инструкции как это сделать на ядре 2.6.24 я не нашел, из-за этого решил написать, как удалось решить задачу.
Для реализации задуманного нам понадобится написать модуль ядра, который будет выполнять проверку и модуль расширения для iptables, который будет работать с модулем ядра - создавать новые цепочки,
использующие наш модуль, выводить информацию о критерии при выводе списка правил на экран, а также проверять корректность передаваемых модулю параметров.Сначала создадим общий заголовочный файл ipt_ID.h:
#ifndef _IPT_ID_H
#define _IPT_ID_Henum {
IPT_ID_RAND = 0,
IPT_ID_INC
};#define IPT_ID_MAXMODE IPT_ID_INC
struct ipt_ID_info {
u_int8_t mode;
u_int16_t id;
};#endif
Теперь скопируем его в исходники netfilter в директорию
linux/netfilter_ipv4/Далее рассмотрим модуль ядра ipt_ID.с.
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <net/checksum.h>
#include <linux/random.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv4/ipt_ID.h>MODULE_AUTHOR("Xlise <demonxlise@gmail.com>");
MODULE_DESCRIPTION("Xtables: IPv4 ID field modification target");
MODULE_LICENSE("GPL");
static int count=0;
static struct iphdr l_iph[5];
static unsigned int
id_tg(struct sk_buff *skb, const struct net_device *in,
const struct net_device *out, unsigned int hooknum,
const struct xt_target *target, const void *targinfo)
{
struct iphdr *iph;
const struct ipt_ID_info *info = targinfo;
u_int16_t new_id;
int i=0;
if (!skb_make_writable(skb, skb->len))
return NF_DROP;iph = ip_hdr(skb);
switch (info->mode) {
case IPT_ID_RAND:
get_random_bytes(&info->id, sizeof(info->id));
new_id = info->id;
break;
case IPT_ID_INC:
while (i<5)
{
if (l_iph[i].daddr == iph->daddr)
{
new_id = l_iph[i].id + htons(1);
l_iph[i].id = new_id;
}else
{new_id = iph->id;
l_iph[count] = *iph;
count++;
if (count > 4)
count = 0;
}
i++;
}
default:
new_id = iph->id;
break;
}if (new_id != iph->id) {
csum_replace2(&iph->check, iph->id,
new_id);
iph->id = new_id;
}return XT_CONTINUE;
}static bool
id_tg_check(const char *tablename, const void *e,
const struct xt_target *target, void *targinfo,
unsigned int hook_mask)
{
const struct ipt_ID_info *info = targinfo;if (info->mode > IPT_ID_MAXMODE) {
printk(KERN_WARNING "ipt_ID: invalid or unknown Mode %u\n",
info->mode);
return false;
}
if (info->mode != IPT_ID_SET && info->id == 0)
return false;
return true;
}static struct xt_target id_tg_reg __read_mostly = {
.name = "ID",
.family = AF_INET,
.target = id_tg,
.targetsize = sizeof(struct ipt_ID_info),
.table = "mangle",
.checkentry = id_tg_check,
.me = THIS_MODULE,
};static int __init id_tg_init(void)
{
return xt_register_target(&id_tg_reg);
}static void __exit id_tg_exit(void)
{
xt_unregister_target(&id_tg_reg);
}module_init(id_tg_init);
module_exit(id_tg_exit);Напишем Makefile для нашего модуля:
obj-m := ipt_ID.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
$(MAKE) -C $(KDIR) M=$(PWD) modulesдобавим модуль в ядро
insmod ipt_ID.ko
Для создания модуля для iptables нам потребуются исходники для iptables-1.4.4
Создадим файл libipt_ID.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <xtables.h>
#include <linux/netfilter_ipv4/ipt_ID.h>#define IPT_ID_USED 1
static void ID_help(void)
{
printf(
"ID target options\n"
" --id-rand value Set ID to \n"
" --id-inc value Increment ID by \n");
}static int ID_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_target **target)
{
struct ipt_ID_info *info = (struct ipt_ID_info *) (*target)->data;
u_int16_t value;if (*flags & IPT_ID_USED) {
xtables_error(PARAMETER_PROBLEM,
"Can't specify ID option twice");
}if (!optarg)
xtables_error(PARAMETER_PROBLEM,
"ID: You must specify a value");if (xtables_check_inverse(optarg, &invert, NULL, 0))
xtables_error(PARAMETER_PROBLEM,
"ID: unexpected `!'");if (!xtables_strtoui(optarg, NULL, &value, 0, UINT16_MAX))
xtables_error(PARAMETER_PROBLEM,
"ID: Expected value between 0 and 255");switch (c) {
case '1':
info->mode = IPT_ID_RAND;
break;case '2':
if (value == 0) {
xtables_error(PARAMETER_PROBLEM,
"ID: increasing by 0?");
}info->mode = IPT_ID_INC;
break;default:
return 0;}
info->id = value;
*flags |= IPT_ID_USED;return 1;
}static void ID_check(unsigned int flags)
{
if (!(flags & IPT_ID_USED))
xtables_error(PARAMETER_PROBLEM,
"TTL: You must specify an action");
}static void ID_save(const void *ip, const struct xt_entry_target *target)
{
const struct ipt_ID_info *info =
(struct ipt_ID_info *) target->data;switch (info->mode) {
case IPT_ID_SET:
printf("--id-set ");
break;
case IPT_ID_DEC:
printf("--id-dec ");
break;case IPT_ID_INC:
printf("--id-inc ");
break;
}
printf("%u ", info->id);
}static void ID_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct ipt_ID_info *info =
(struct ipt_ID_info *) target->data;printf("ID ");
switch (info->mode) {
case IPT_ID_SET:
printf("set to ");
break;
case IPT_ID_DEC:
printf("decrement by ");
break;
case IPT_ID_INC:
printf("increment by ");
break;
}
printf("%u ", info->id);
}static const struct option ID_opts[] = {
{ "id-set", 1, NULL, '1' },
{ "id-inc", 1, NULL, '2' },
{ .name = NULL }
};static struct xtables_target id_tg_reg = {
.name = "ID",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV4,
.size = XT_ALIGN(sizeof(struct ipt_ID_info)),
.userspacesize = XT_ALIGN(sizeof(struct ipt_ID_info)),
.help = ID_help,
.parse = ID_parse,
.final_check = ID_check,
.print = ID_print,
.save = ID_save,
.extra_opts = ID_opts,
};void _init(void)
{
xtables_register_target(&id_tg_reg);
}Далее скопируем файл ipt_ID.h в iptables-1.4.4/include/linux/netfilter_ipv4/ и файл libipt_ID.c в iptables-1.4.4/extensions/
теперь скомпилируем iptables и скопируем файл iptables-1.4.4/extensions/libipt_ID.so в /lib/xtables/Теперь можно создавать цепочки в iptables
пример:
iptables -t mangle -A POSTROUTING -j ID --id-rand 1
Будет выдавть всем пакетам случайные ID (единица в конце ничего не обозначает просто я не доделал модуль)
iptables -t mangle -A POSTROUTING -j ID --id-inc 1
Будет пакетам направленным на один IP присваивать ID постоянно увеличивая на единицу, может хранить в памяти пять таких цепочек (количество цепочек можно увеличить)
P.S. Если кого интересует данная тема, то я доделаю статью и допишу модуль, просто пока всё работает и так не хочется ничего переделывать, но если нужно сделаю.
URL: http://www.linuxjournal.com/article/7184
Обсуждается: http://www.opennet.me/tips/info/2570.shtml
А для чего это вообще нужно? Ну в смысле менять ID пакета?
Гораздо полезнее было бы сделать U32 target для изменения произвольного поля пакета, а --id описать как синоним опр. смещения.
а зачем это?
могу подкинуть идею полезного и вроде как реально нужного патча / модуля:Итак, ситуация - вебсервер, (д)дос.
Прилетает запрос к веб-серверу. Хотим делать фильтрацию iptables-ом по содержимому запроса. Чтобы получить запрос, соединение должно быть установлено.
В тот момент, когда срабатывает правило-A INPUT -p tcp --dport 80 -m string -string .... -j REJECT --reject-with tcp-reset
tcp-reset отправляется только в сторону, откуда пришел запрос, в итоге имеем подвешенное соединение с нашей стороны.
Ну вот соответственно требуется модификация имеющегося или новый модуль :-)
> Итак, ситуация - вебсервер, (д)дос.
> Прилетает запрос к веб-серверу. Хотим делать фильтрацию iptables-ом по содержимому запроса.
> Чтобы получить запрос, соединение должно быть установлено.
> В тот момент, когда срабатывает правило
> -A INPUT -p tcp --dport 80 -m string -string .... -j REJECT
> --reject-with tcp-resetНу и будет там запрос "GET / HTTP/1.1" и чё дальше?
Как это спасёт от DoS/DDoS ?> tcp-reset отправляется только в сторону, откуда пришел запрос, в итоге имеем
> подвешенное соединение с нашей стороны.-j REJECT --reject-with tcp-reset сбрасывает соединение, а не вешает.
>> Итак, ситуация - вебсервер, (д)дос.
>> Прилетает запрос к веб-серверу. Хотим делать фильтрацию iptables-ом по содержимому запроса.
>> Чтобы получить запрос, соединение должно быть установлено.
>> В тот момент, когда срабатывает правило
>> -A INPUT -p tcp --dport 80 -m string -string .... -j REJECT
>> --reject-with tcp-reset
> Ну и будет там запрос "GET / HTTP/1.1" и чё дальше?
> Как это спасёт от DoS/DDoS ?Допустим что там будет нечто специфичное и мы сможем выделить "нужные" :-)
>> tcp-reset отправляется только в сторону, откуда пришел запрос, в итоге имеем
>> подвешенное соединение с нашей стороны.
> -j REJECT --reject-with tcp-reset сбрасывает соединение, а не вешает.:-) Ты уже посмотрел в код? Типовой use-case это посылка сброса на еще не установленном соединении (флаг определяет что полетит _не_ icmp пакет).
В рассматриваемом случае использование несколько иное - соединение будет уже установлено. И далее:
>> tcp-reset отправляется только в сторону, откуда пришел запрос, в итоге имеем
>> подвешенное соединение с нашей стороны.так что соединение с нашей стороны "будет не проинформировано" и будет тихо мирно ждать таймаута.
см ipt_REJECT.c / send_reset()
>> Ну и будет там запрос "GET / HTTP/1.1" и чё дальше?
>> Как это спасёт от DoS/DDoS ?
> Допустим что там будет нечто специфичное и мы сможем выделить "нужные" :-)На месте DDoSеров я бы не повторялся,
"GET /1 HTTP/1.1"
"GET /11 HTTP/1.1"
"GET /111 HTTP/1.1"
"GET /1111 HTTP/1.1"
...
"GET /FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF HTTP/1.1":)
---
Можно с другой стороны конечно...Через парсер от апача создавать проверку на запрос к реальным ресурсам
-m string ! -string "GET / HTTP/1.1" -j REJECT --reject-with tcp-reset
-m string ! -string "GET /index.html HTTP/1.1" -j REJECT --reject-with tcp-reset
-m string ! -string "GET /index.php HTTP/1.1" -j REJECT --reject-with tcp-reset
-m string ! -string "GET /main.php HTTP/1.1" -j REJECT --reject-with tcp-reset
-m string ! -string "GET /about.php HTTP/1.1" -j REJECT --reject-with tcp-reset
...
...
...
-m string ! -string "GET http://www.opennet.me/cgi-bin/openforum/vsluhboard.cgi?quote... HTTP/1.1" -j REJECT --reject-with tcp-reset
ну так как-бы согласен с тем, что соединение подвиснет ?
> ну так как-бы согласен с тем, что соединение подвиснет ?Если честно, лень смотреть, пущай будет сбрасываться :)