Данная статья основывается на материале "Разработка 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. Если кого интересует данная тема, то я доделаю статью и допишу модуль, просто пока всё работает и так не хочется ничего переделывать, но если нужно сделаю.
URL: http://www.linuxjournal.com/article/7184
Обсуждается: http://www.opennet.dev/tips/info/2570.shtml