The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]

форумы  помощь  поиск  регистрация  майллист  вход/выход  слежка  RSS
"Раздел полезных советов: Создание модуля для iptables, измен..."
Вариант для распечатки  
Пред. тема | След. тема 
Форум Разговоры, обсуждение новостей
Изначальное сообщение [ Отслеживать ]

"Раздел полезных советов: Создание модуля для iptables, измен..."  +/
Сообщение от auto_tips (ok) on 02-Май-11, 13:24 
Данная статья основывается на материале "Разработка 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
Обсуждается: https://www.opennet.ru/tips/info/2570.shtml

Ответить | Правка | Cообщить модератору

Оглавление

Сообщения по теме [Сортировка по времени | RSS]


1. "Создание модуля для iptables, изменяющего ID пакета"  +/
Сообщение от Hubbitus email(ok) on 02-Май-11, 13:24 
А для чего это вообще нужно? Ну в смысле менять ID пакета?
Ответить | Правка | ^ к родителю #0 | Наверх | Cообщить модератору

2. "Создание модуля для iptables, изменяющего ID пакета"  +/
Сообщение от segoon email(ok) on 02-Май-11, 15:15 
Гораздо полезнее было бы сделать U32 target для изменения произвольного поля пакета, а --id описать как синоним опр. смещения.
Ответить | Правка | ^ к родителю #0 | Наверх | Cообщить модератору

3. "Создание модуля для iptables, изменяющего ID пакета"  +/
Сообщение от Новичок email(??) on 03-Май-11, 00:34 
а зачем это?
Ответить | Правка | ^ к родителю #0 | Наверх | Cообщить модератору

4. "Создание модуля для iptables, изменяющего ID пакета"  +/
Сообщение от PavelR (??) on 03-Май-11, 06:50 
могу подкинуть идею полезного и вроде как реально нужного патча / модуля:

Итак, ситуация - вебсервер, (д)дос.
Прилетает запрос к веб-серверу. Хотим делать фильтрацию iptables-ом по содержимому запроса. Чтобы получить запрос, соединение должно быть установлено.
В тот момент, когда срабатывает правило

-A INPUT -p tcp --dport 80 -m string -string .... -j REJECT --reject-with tcp-reset

tcp-reset отправляется только в сторону, откуда пришел запрос, в итоге имеем подвешенное соединение с нашей стороны.

Ну вот соответственно требуется модификация имеющегося или новый модуль :-)

Ответить | Правка | ^ к родителю #0 | Наверх | Cообщить модератору

5. "Создание модуля для iptables, изменяющего ID пакета"  +/
Сообщение от pavlinux (ok) on 03-Май-11, 22:47 
> Итак, ситуация - вебсервер, (д)дос.
> Прилетает запрос к веб-серверу. Хотим делать фильтрацию 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  сбрасывает соединение, а не вешает.

Ответить | Правка | ^ к родителю #4 | Наверх | Cообщить модератору

6. "Создание модуля для iptables, изменяющего ID пакета"  +/
Сообщение от PavelR (??) on 04-Май-11, 10:19 
>> Итак, ситуация - вебсервер, (д)дос.
>> Прилетает запрос к веб-серверу. Хотим делать фильтрацию 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()

Ответить | Правка | ^ к родителю #5 | Наверх | Cообщить модератору

7. "Создание модуля для iptables, изменяющего ID пакета"  +/
Сообщение от pavlinux (ok) on 04-Май-11, 14:07 
>> Ну и будет там запрос  "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 https://www.opennet.ru/cgi-bin/openforum/vsluhboard.cgi?quote... HTTP/1.1" -j REJECT --reject-with tcp-reset

Ответить | Правка | ^ к родителю #6 | Наверх | Cообщить модератору

8. "Создание модуля для iptables, изменяющего ID пакета"  +/
Сообщение от PavelR (??) on 05-Май-11, 19:10 
ну так как-бы согласен с тем, что соединение подвиснет ?
Ответить | Правка | ^ к родителю #7 | Наверх | Cообщить модератору

9. "Создание модуля для iptables, изменяющего ID пакета"  +/
Сообщение от pavlinux (ok) on 05-Май-11, 23:17 
> ну так как-бы согласен с тем, что соединение подвиснет ?

Если честно, лень смотреть, пущай будет сбрасываться :)

Ответить | Правка | ^ к родителю #8 | Наверх | Cообщить модератору

Архив | Удалить

Рекомендовать для помещения в FAQ | Индекс форумов | Темы | Пред. тема | След. тема




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру