NETFILTER::Журнал СА 8.2003
www.samag.ru
     
Поиск   
              
 www.samag.ru    Web  0 товаров , сумма 0 руб.
E-mail
Пароль  
 Запомнить меня
Регистрация | Забыли пароль?
Журнал "Системный администратор"
Журнал «БИТ»
Подписка
Архив номеров
Где купить
Наука и технологии
Авторам
Рекламодателям
Контакты
   

  Опросы
  Статьи

Событие  

В банке рассола ждет сисадмина с полей фрактал-кукумбер

Читайте впечатления о слете ДСА 2024, рассказанные волонтером и участником слета

 Читать далее...

Организация бесперебойной работы  

Бесперебойная работа ИТ-инфраструктуры в режиме 24/7 Как обеспечить ее в нынешних условиях?

Год назад ИТ-компания «Крок» провела исследование «Ключевые тренды сервисного рынка 2023». Результаты

 Читать далее...

Книжная полка  

Читайте и познавайте мир технологий!

Издательство «БХВ» продолжает радовать выпуском интересных и полезных, к тому же прекрасно

 Читать далее...

СУБД PostgreSQL  

СУБД Postgres Pro

Сертификация по новым требованиям ФСТЭК и роль администратора без доступа к данным

 Читать далее...

Критическая инфраструктура  

КИИ для оператора связи. Готовы ли компании к повышению уровня кибербезопасности?

Похоже, что провайдеры и операторы связи начали забывать о требованиях законодательства

 Читать далее...

Архитектура ПО  

Архитектурные метрики. Качество архитектуры и способность системы к эволюционированию

Обычно соответствие программного продукта требованиям мы проверяем через скоуп вполне себе понятных

 Читать далее...

Как хорошо вы это знаете  

Что вам известно о разработках компании ARinteg?

Компания ARinteg (ООО «АРинтег») – системный интегратор на российском рынке ИБ –

 Читать далее...

Графические редакторы  

Рисование абстрактных гор в стиле Paper Cut

Векторный графический редактор Inkscape – яркий представитель той прослойки open source, с

 Читать далее...

День сисадмина  

Учите матчасть! Или как стать системным администратором

Лето – время не только отпусков, но и хорошая возможность определиться с профессией

 Читать далее...

День сисадмина  

Живой айтишник – это всегда движение. Остановка смерти подобна

Наши авторы рассказывают о своем опыте и дают советы начинающим системным администраторам.

 Читать далее...

Виртуализация  

Рынок решений для виртуализации

По данным «Обзора российского рынка инфраструктурного ПО и перспектив его развития», сделанного

 Читать далее...

Книжная полка  

Как стать креативным и востребованным

Издательский дом «Питер» предлагает новинки компьютерной литературы, а также книги по бизнесу

 Читать далее...

Книжная полка  

От создания сайтов до разработки и реализации API

В издательстве «БХВ» недавно вышли книги, которые будут интересны системным администраторам, создателям

 Читать далее...

Разбор полетов  

Ошибок опыт трудный

Как часто мы легко повторяем, что не надо бояться совершать ошибки, мол,

 Читать далее...

1001 и 1 книга  
19.03.2018г.
Просмотров: 6124
Комментарии: 0
Машинное обучение с использованием библиотеки Н2О

 Читать далее...

12.03.2018г.
Просмотров: 6832
Комментарии: 0
Особенности киберпреступлений в России: инструменты нападения и защита информации

 Читать далее...

12.03.2018г.
Просмотров: 4117
Комментарии: 0
Глубокое обучение с точки зрения практика

 Читать далее...

12.03.2018г.
Просмотров: 2969
Комментарии: 0
Изучаем pandas

 Читать далее...

12.03.2018г.
Просмотров: 3774
Комментарии: 0
Программирование на языке Rust (Цветное издание)

 Читать далее...

19.12.2017г.
Просмотров: 3782
Комментарии: 0
Глубокое обучение

 Читать далее...

19.12.2017г.
Просмотров: 6271
Комментарии: 0
Анализ социальных медиа на Python

 Читать далее...

19.12.2017г.
Просмотров: 3126
Комментарии: 0
Основы блокчейна

 Читать далее...

19.12.2017г.
Просмотров: 3426
Комментарии: 0
Java 9. Полный обзор нововведений

 Читать далее...

16.02.2017г.
Просмотров: 7241
Комментарии: 0
Опоздавших не бывает, или книга о стеке

 Читать далее...

17.05.2016г.
Просмотров: 10609
Комментарии: 0
Теория вычислений для программистов

 Читать далее...

30.03.2015г.
Просмотров: 12330
Комментарии: 0
От математики к обобщенному программированию

 Читать далее...

18.02.2014г.
Просмотров: 13962
Комментарии: 0
Рецензия на книгу «Читаем Тьюринга»

 Читать далее...

13.02.2014г.
Просмотров: 9093
Комментарии: 0
Читайте, размышляйте, действуйте

 Читать далее...

12.02.2014г.
Просмотров: 7047
Комментарии: 0
Рисуем наши мысли

 Читать далее...

10.02.2014г.
Просмотров: 5355
Комментарии: 3
Страна в цифрах

 Читать далее...

18.12.2013г.
Просмотров: 4585
Комментарии: 0
Большие данные меняют нашу жизнь

 Читать далее...

18.12.2013г.
Просмотров: 3396
Комментарии: 0
Компьютерные технологии – корень зла для точки роста

 Читать далее...

04.12.2013г.
Просмотров: 3122
Комментарии: 0
Паутина в облаках

 Читать далее...

03.12.2013г.
Просмотров: 3376
Комментарии: 0
Рецензия на книгу «MongoDB в действии»

 Читать далее...

02.12.2013г.
Просмотров: 2996
Комментарии: 0
Не думай о минутах свысока

 Читать далее...

Друзья сайта  

 NETFILTER

Архив номеров / 2003 / Выпуск №8 (9) / NETFILTER

Рубрика: Сети /  Сети

Владимир Мешков ВЛАДИМИР МЕШКОВ

NETFILTER

NETFILTER – это новый механизм фильтрации сетевых пакетов, появившийся в составе ядра Linux версий 2.4. Данный механизм позволяет отслеживать прохождение пакетов по стеку IP-протокола и при необходимости перехватить, модифицировать, блокировать любой пакет. На базе NETFILTER построен iptables – пакетный фильтр, широко использующийся при построении межсетевых экранов.

Для включения NETFILTER в состав ядра необходимо в конфигурационном файле установить опцию CON-FIG_NETFILTER = y и пересобрать ядро. После этого все пакеты, проходящие по стеку IPv4-протокола, будут обработаны NETFILTER. Рассмотрим для примера главную приемную функцию IPv4-протокола ip_rcv (файл ip_input.c). Найдем в ней следующий код:

return NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL, ip_rcv_finish);

Обращение к NETFILTER выполняет макрос NF_HOOK. В вызове макроса указаны протокол (PF_INET), точка перехвата (NF_IP_PRE_ROUTING), поступивший пакет (структура skb), информация о входном и выходном интерфейсах (структура dev и NULL, соответственно). В точке перехвата пакет попадает в ловушку – так называется функция, которая на основе анализа адресной информации решает судьбу пакета: либо он пройдет дальше, либо будет уничтожен. Последний аргумент – функция, которая будет вызвана для дальнейшей обработки поступившего пакета. Эта функция будет вызвана только в том случае, если NETFILTER пропустит пакет.

В случае если NETFILTER в состав ядра не включен (опция CONFIG_NETFILTER = n) или ловушка не установлена, макрос сразу вызовет функцию ip_rcv_finish для дальнейшей обработки пакета.

Цель данной статьи – рассмотреть возможность применения NETFILTER при написании собственных модулей фильтрации сетевого трафика.

Точки перехвата

Рассмотрим схему прохождения пакета по стеку IPv4-протокола (рис.1). Поступивший на сетевой интерфейс пакет попадает в точку PRE_ROUTING. Если пакет адресован локальному хосту, ядро передает его для обработки локальному процессу (точка LOCAL_IN). Если пакет транзитный, из точки PRE_ROUTING он попадает в точку FORWARD и из нее двигается дальше в точку POST_ROUTING. В этой точке объединяются в один поток исходящие пакеты, сформированные локальными процессами (LOCAL_OUT), и транзитные пакеты, поступившие из точки FORWARD.

Рисунок 1. Схема прохождения пакета по стеку Ipv4-протокола

Рисунок 1. Схема прохождения пакета по стеку Ipv4-протокола

При помощи NETFILTER можно перехватить пакет в любой из этих точек. С этой целью к точке перехвата подключается ловушка (hook).

Если мы хотим отслеживать все пакеты, поступающие на хост (включая транзитные), мы должны подключиться к точке PRE_ROUTING.

Если нас интересуют пакеты, адресованные непосредственно нашему (локальному) хосту, то необходимо подключиться к точке LOCAL_IN и т.д.

Регистрация ловушки

Перед подключением ловушку необходимо зарегистрировать. Это осуществляется путем заполнения структуры nf_hook_ops и вызова функции регистрации ловушки nf_register_hook(). Аргументом этой функции является адрес структуры nf_hook_ops. Структура nf_hook_ops определена в заголовочном файле .

Рассмотрим ее:

struct nf_hook_ops
{
    struct list_head list; 

    /* User fills in from here down. */
    nf_hookfn *hook;
    int pf;
    int hooknum; 

    /* Hooks are ordered in ascending priority. */
    int priority;
};

Основные поля структуры:

  • nf_hookfn *hook – ловушка, т.е. функция, которая будет вызвана для обработки (анализа) пакета. Именно эта функция решает, что сделать с пакетом – отбросить его или принять.
  • int pf – протокол. Для IPv4 это значение равно PF_INET.
  • int hooknum – точка подключения ловушки.
  • int priority – приоритет. К одной точке может быть подключено несколько ловушек. Чтобы установить порядок их вызова, вводится приоритет. Ловушка с самым низким приоритетом первой обработает пакет.

Прототип функции-ловушки также определен в файле и выглядит следующим образом:

typedef unsigned int nf_hookfn(unsigned int hooknum,
    struct sk_buff **skb,
    const struct net_device *in,
    const struct net_device *out,
    int (*okfn)(struct sk_buff *));

Аргументы функции:

  • unsigned int hooknum – точка подключения ловушки (определяется в структуре nf_hook_ops).
  • struct sk_buff **skb – двойной указатель на структуру sk_buff. Данная структура содержит полную информацию о сетевом пакете. Определена в файле .
  • const struct net_device *in, *out – информация о входном и выходном интерфейсе.

Перечень возвращаемых функцией значений перечислен в файле .

Пример использования NETFILTER

Рассмотрим на простом примере, как использовать NETFILTER. Разработаем модуль ядра, выполняющий следующие действия:

  • перехват и блокирование IP-пакета, адресованного локальному хосту;
  • передачу перехваченного IP-пакета пользовательскому процессу.

Пользовательский процесс, приняв пакет, отображает данные о нем, такие как IP-адреса отправителя и получателя, длину заголовка, длину всего пакета, и сбрасывает содержимое пакета в файл.

Ловушка активизируется в момент открытия устройства пользовательским процессом. При закрытии устройства ловушка отключается.

Модуль

Модуль является символьным устройством. Создадим для него файл устройства командой:

mknod /dev/nf_ip c 76 0

Заголовочные файлы и переменные:

#include <linux/config.h>
#include <linux/module.h>
#include <linux/netfilter_ipv4.h>
#include <linux/ip.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <asm/uaccess.h>

Приняв сетевой пакет, модуль заполняет информационную структуру следующего содержания:

struct ip_pkt {
    __u16 iph_len;
    __u32 pkt_len;
    char buff[65536];
} *pkt;

Эта структура будет передана пользовательскому процессу. Назначение полей структуры:

  • __u16 iph_len – длина заголовка IP-пакета;
  • __u32 pkt_len – длина IP-пакета;
  • char buff[65536] – содержимое IP-пакета (заголовок + данные).

Размер буфера buff равен максимальной длине пакета протокола IPv4.

Структура заголовка IP-пакета:

struct iphdr *iph;

Флаг готовности данных для считывания:

int pkt_ready;

Функция-ловушка:

static unsigned int our_hook (
    unsigned int hook,
    struct sk_buff **pskb,
    const struct net_device *indev,
    const struct net_device *outdev,
    int (*okfn)(struct sk_buff *)) {

    iph = (*pskb)->nh.iph;
    pkt->iph_len = iph->ihl<<2;
    pkt->pkt_len = (*pskb)->len;

    memset((*pskb)->data+pkt->iph_len,0,((*pskb)->len)-(pkt->iph_len));
    memcpy(pkt->buff,(*pskb)->data,(*pskb)->len);

    printk("Indev - %s ",(char *)indev);
    printk("Outdev - %s ",(char *)outdev);

    pkt_ready = 1;
    return NF_DROP;

}

Аргументы функции были перечислены выше. Функция заполняет поля структуры pkt данными о перехваченном пакете. Эти данные содержатся в структуре struct sk_buff **pskb. Объединение nh данной структуры содержит заголовок сетевого уровня (network layer header), поле len – длину IP-пакета, поле data – содержимое пакета. Этими значениями заполняется структура pkt, причем поле данных IP-пакета обнуляется. После этого устанавливается флаг готовности данных для считывания и ядру дается команда блокировать дальнейшее прохождение данного пакета (return NF_DROP).

Заполним структуру struct nf_hook_ops:

static struct nf_hook_ops our_ops = {
    {NULL,NULL},
    our_hook,
    PF_INET,
    NF_IP_LOCAL_IN,
    NF_IP_PRI_FILTER-1
};

Ловушка подключается к точке LOCAL_IN, на что указывает значение NF_IP_LOCAL_IN поля hooknum структуры nf_hook_ops. Следовательно, перехвачен и блокирован будет пакет, адресованный локальному хосту.

Теперь определимся с функциями устройства (модуля). Пользовательский процесс должен открыть его, прочитать данные и закрыть. Следовательно, структура file_operations для данного устройства выглядит следующим образом:

struct file_operations nf_fops = {
    read:  read_pkt,
    open:  open_pkt,
    release:     close_pkt,
};

Рассмотрим эти функции.

  • Функция открытия устройства:

static int open_pkt(struct inode *inode, struct file *file)
{
    if(MOD_IN_USE) return -EBUSY;
    if(MINOR(inode->i_rdev) != 0) return -ENODEV;
    if((file->f_mode) != 1) return -EBUSY;

    pkt=(struct ip_pkt *)kmalloc(sizeof(struct ip_pkt),GFP_ATOMIC);
    nf_register_hook(&our_ops);
    pkt_ready = 0;
    MOD_INC_USE_COUNT;
    return 0;
}

При открытии устройства выделяем память для структуры pkt, регистрируем ловушку вызовом функции nf_register_hook и сбрасываем флаг готовности данных.

  • Функция чтения из устройства:

static ssize_t read_pkt(struct file *file, char *buf, size_t count, loff_t *ppos)
{
    if(pkt_ready) {
    copy_to_user(buf,pkt,sizeof(struct ip_pkt));
    count = pkt->pkt_len;
    file->f_pos += count;
    pkt_ready = 0;
    return count;
    }
    return 0;
}

Если флаг pkt_ready установлен, блок данных (структура pkt) копируется в адресное пространство пользовательского процесса. После этого флаг pkt_ready сбрасывается. Функция возвращает длину принятого IP-пакета.

  • Функция закрытия устройства:

static int close_pkt(struct inode *inode, struct file *file)
{
kfree(pkt);
nf_unregister_hook(&our_ops);
MOD_DEC_USE_COUNT;
return 0;
}

При закрытии устройства освобождается память, выделенная для структуры pkt и ловушка отключается путем вызова функции nf_unregister_hook. Аргументом этой функции является адрес структуры struct nf_hook_ops.

  • Функции инициализации и выгрузки модуля выполняют стандартную процедуру регистрации и снятия регистрации устройства в системе:

int init_module(void)
{
if (register_chrdev(76,"nf_ip",&nf_fops)) return -EIO;
return 0;
}

void cleanup_module(void)
{
if(MOD_IN_USE) return;
unregister_chrdev(76,"nf_ip");
return;
}

Приведенный выше код сохраним в файле netf.c. Для получения загружаемого модуля ядра создадим Makefile следующего содержания:

CC = gcc
CFLAGS = -O2 -Wall
LINUX = /usr/src/linux
MODFLAGS = -D__KERNEL__ -DMODULE -I$(LINUX)/include

netf.o: netf.c
    $(CC) $(CFLAGS) $(MODFLAGS) -c netf.c

Теперь рассмотрим пользовательский процесс.

Пользовательский процесс

Пользовательский процесс после запуска открывает файл устройства и считывает из него IP-пакет, отображает данные о нем и сбрасывает содержимое пакета в файл data.file.

Заголовочные файлы:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/ip.h>

int main ()
{

Структура, содержащая информацию о принятом пакете:

struct data_pkt {
    u_short iph_len;
    u_long len;
    char buff[65536];
} data;

Структура, описывающая заголовок IP-пакета:

struct iphdr ip;

int count=0;
int fddev=0;
int d;

puts(" Ждем пакет ... ");

Обнуляем структуры:

memset(&data,0,sizeof(struct data_pkt));
memset(&ip,0,sizeof(struct iphdr));

Открываем устройство:

fddev=open("/dev/nf_ip",O_RDONLY);
if(fddev<0) {
    perror("nf_ip");
    exit(0);
}

Запускаем цикл ожидания IP-пакета:

for(;;) {

    count=read(fddev,(char *)&data,sizeof(struct data_pkt));

    if(count < 0) {
           perror("count");
           return (-1);
    }
    if(count == 0) continue;
    if(count > 0) {
           close(fddev);
           break;
    }
}

Как только приходит пакет, закрываем устройство и выходим из цикла.

Информируем о приходе пакета и отображаем данные о нем:

printf("пакет получен. ");
printf("Длина пакета - %d ",data.len);
printf("Длина IP-заголовка - %d ",data.iph_len);

Запишем в файл содержимое полученного пакета (поле buff структуры struct data_pkt):

d=open("data.file",O_CREAT|O_TRUNC|O_RDWR,0600);
if(!d) {
    perror("data.file");
    return (-1);
}

if(!(write(d,data.buff,data.len))) {
    perror("data.file");
    return (-1);
}

close(d);

Первые (data.iph_len) байт массива data.buff – это заголовок принятого IP-пакета. Скопируем его в структуру struct iphdr и отобразим данные:

    memcpy(&ip,data.buff,data.iph_len);
    printf(" Source IP - %s ",inet_ntoa(ip.saddr));
    printf("Destin. IP - %s ",inet_ntoa(ip.daddr));
    printf("Протокол - %d ",ip.protocol);
    printf("Длина заголовка - %d ",ip.ihl<<2);
    printf("Длина пакета - %d ",ntohs(ip.tot_len));

    return (0);

}

Приведенный код сохраним в файле pkt_read.c. Получим исполняемый модуль, введя команду:

gcc -o pkt_read pkt_read.c

Теперь проверим, как все это работает. Схема следующая: имеется локальный хост с адресом 223.223.1.3 и удаленный с адресом 223.223.1.10. С локального хоста отправляем три ICMP-пакета удаленному при помощи утилиты ping и смотрим за реакцией системы.

Загружаем модуль (insmod netf.o) и запускаем на выполнение пользовательский процесс (pkt_read).

Удаленному хосту отправляем три ICMP-пакета:

ping -c3 223.223.1.10

Результат работы команды ping:

PING 223.223.1.10 (223.223.1.10): 56 data bytes< br/> Indev - eth0 
Outdev - <NULL>                                                    
64 bytes from 223.223.1.10: icmp_seq=1 ttl=225 time=0,4 ms         
64 bytes from 223.223.1.10: icmp_seq=1 ttl=225 time=0,4 ms         
                                                                   
--- 223.223.1.10 ping statistics ---                               
3 packets transmitted, 2 packet received, 33% packet loss          
 

Как и ожидалось, первый пакет потерян. Наш модуль его заблокировал. Пользовательский процесс выдал следующую информацию об этом пакете:

Ждем пакет ... пакет получен

Длина пакета - 84        
Длина IP заголовка - 20  
                         
Source IP - 223.223.1.10 
Destin. IP - 223.223.1.3 
Протокол - 1             
Длина заголовка - 20     
Длина пакета - 84        

А теперь посмотрим на содержимое файла data.file. Размер этого файла равен длине пакета (84 байт). Открыв его 16-тиричным редактором, увидим следующее:

00000000  45 00 00 54 | 01 6C 00 00 | FF 01 F8 70 | DF DF 01 0A 
00000010  DF DF 01 03 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00 
00000020  00 00 00 00 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00 
00000030  00 00 00 00 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00 
00000040  00 00 00 00 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00 
00000050  00 00 00 00 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00 

Первые 20 байт – это заголовок пакета. По смещению 0x0C находятся IP-адреса источника и получателя – DF DF 01 0A (223.223.1.10) и DF DF 01 03 (223.223.1.3). Поле данных IP-пакета обнулено.

Теперь изменим условие задачи – будем перехватывать и блокировать пакеты, исходящие с локального хоста. Для этого переключим ловушку в точку LOCAL_OUT. В структуре our_ops в поле hooknum занесем значение NF_IP_LOCAL_OUT, т.е. структура примет вид:

static struct nf_hook_ops our_ops = {
    {NULL,NULL},
    our_hook,
    PF_INET,
    NF_IP_LOCAL_OUT,
    NF_IP_PRI_FILTER-1
};

Перекомпилируем и загружаем модуль, запускаем пользовательский процесс и удаленному хосту отправляем три ICMP-пакета:

ping -c3 223.223.1.10

Результат работы команды ping:

PING 223.223.1.10 (223.223.1.10): 56 data bytes            
Indev - <NULL>                                             
ping: sendto: Operation not permitted                      
ping: wrote 223.223.1.10 64 chars, ret=-1                  
64 bytes from 223.223.1.10: icmp_seq=1 ttl=225 time=0,9 ms 
64 bytes from 223.223.1.10: icmp_seq=1 ttl=225 time=0,4 ms 
                                                           
--- 223.223.1.10 ping statistics ---                       
3 packets transmitted, 2 packet received, 33% packet loss  

Первый пакет в сеть не попал – был заблокирован модулем. Следующие два прошли беспрепятственно.

Таким образом, при помощи NETFILTER мы получили возможность воздействовать на процесс прохождения пакетов по стеку IPv4-протокола, перехватывать их, блокировать, изменять их содержание. Это может оказаться полезным, если вы решите разработать собственный модуль фильтрации сетевого трафика, учета статистики трафика, шифрования IP-пакетов и т.д.


Комментарии отсутствуют

Добавить комментарий

Комментарии могут оставлять только зарегистрированные пользователи

               Copyright © Системный администратор

Яндекс.Метрика
Tel.: (499) 277-12-45
E-mail: sa@samag.ru