Данная статья основывается на материале "Разработка 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_H
enum {
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. Если кого интересует данная тема, то я доделаю статью и допишу модуль,
просто пока всё работает и так не хочется ничего переделывать, но если нужно сделаю.
|