Програмування в Linux: Netfilter Kernel Programming (исходники), Різне, Програмування, статті

У цій статті я постараюся дати початкові відомості про netfilter “e і про те, як запобігти Land-подібну атаку за допомогою написання модуля для ядра.
І так, netfilter – це підсистема фільтрації пакетів в ядрах гілки 2.4/6.x, він же – перший вбудований в ядро ​​контекстний брендмауер (Stateful Firewall). Контекстний брендмауер відрізняється від звичайного тим, що він може визначати, чи є справжній пакет частиною будь-якого з’єднання. Зокрема, в TCP протокол вбудована система трьохетапного квінтірованія. Для цього клієнт шле серверу запит на з’єднання, вказавши в хедері прапор syn, на що сервак відповідає йому таким же пакетом, але плюс до syn прапора він ще додає прапор ack, вказуючи тим самим, що він хоче з ним встановити з’єднання, після згоди на це клієнта. Ну, так от, звичайний брендмауер не здатний відрізнити пакет, який буде йти в цій сесії з’єднання або ж це будь-якої інший пакет, власник якого вже секунд 20 тому встановив з’єднання. Зате контекстний брендмауер визначає, чи належить цей пакет до нашого з ним з’єднанню або ж до іншого, подивившись для цього таблицю коннектів. Приблизно таким же чином він обробляє і інші протоколи: UDP, ICMP, etc (дивися / etc / protocols). Зокрема, такий тип брендмауеров використовується в Cisco. Ну да ладно, багато цікавого про архітектуру та особливості netfilter “a ви можете дізнатися, поботав доки з www.netfilter.org.


А тепер поговоримо про те, як же нам запрогать netfilter. Він здатний перехоплювати пакети наступних мережевих стеків: IPv4, IPv6, DECnet. Ми розглянемо тільки IPv4. Для даного стека в хереде / usr/include/linux/netfilter_ipv4.h визначені наступні можливі значення захоплення IP-пакетів (так звані хуки):


. NF_IP_PRE_ROUTING: вирішуємо, що робити з пакетом на вході.
1.NF_IP_LOCAL_IN: вхідний, для нашого компа.
2.NF_IP_FORWARD: якщо пакет призначений для іншого інтерфейсу.
3.NF_IP_LOCAL_OUT: якщо цей пакет створений локально.
4.NF_IP_POST_ROUTING: вирішуємо що робити з пакетом на виході.
Перед тим, як до нас прилетить пакет, викликається NF_IP_PRE_ROUTING хук. Далі викликається функція, яка і вирішить, що ми зробимо з пакетом. Ці функції визначені в / usr / include / linux / netfilter.h:


0.NF_DROP: відкинути пакет.
1.NF_ACCEPT: пропустити на подальшу обробку.
2.NF_STOLEN: запам’ятати цей пакет в понятті котекстного брандмауер.
3.NF_QUEUE: поставити пакет в чергу.
4.NF_REPEAT: викликати цю функцію повторно.
Структура оголошення хуков визначена в / usr / include / linux / netfilter.h:


struct nf_hook_ops
{
/ * Член списку цієї структури використовується для підтримки списку хуков
netfilter “a і він не несе ніякого смислового навантаження на реєстрацію хука * /
 struct list_head list;
/ * Укаказатель на хук-функию, див.вище * /
 nf_hookfn *hook;
/ * Яке сімейство протоколів будемо використовувати. Так як ми визначилися
працювати зі стеком IPv4, то подивившись хедер / usr / include / linux / socket.h,
дізнаємося що це PF_INET * /
 int pf;
/ * Який з хуков ми будемо використовувати, див.вище * /
 int hooknum;
/ * Кожному хуку можна призначити свій пріоритет, для нашого стека см. файл
/usr/include/linux/netfilter_ipv4.h */
 int priority;
};
Тепер же, щоб зареєструвати хук, нам знадобитися функція nf_register_hook, прототип якої визначений у файлі / usr / include / linux / netfilter.h.


int nf_register_hook(struct nf_hook_ops *reg);
Як аргумент ця функція приймає вище позначену структуру. Для визначення даних, які передаються в хук-функцію, використовується прототип nf_hookfn, що визначений у тому ж хедері:


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 *));
Тут перший аргумент – це номер хука, а другий – покажчик на покажчик на sk_buff структуру, яка визначена в / usr / include / linux / skbuff.h хедері. Це потрібно для того, щоб ядро ​​знало, з якими пакетами ми працюємо. Наступні два аргументи – це покажчики на net_device структуру, визначену в / usr / include / linux / netdevice.h. Вони використовуються для того, щоб ядро ​​знало, що за інтерфейс ми використовуємо (Eth0, tap0, lo, etc). In і Out, відповідно, вхідний та вихідний інтерфейси. Зокрема, in буде здійснено для NF_IP_PRE_ROUTING і NF_IP_LOCAL_IN, а out – для NF_IP_POST_ROUTING і NF_IP_LOCAL_OUT хуков. Останній аргумент – функція, яка в якості аргументу знову ж приймає структуру sk_buff. Ця функція потрібна, щоб дарма не витрачати процесор очікуванням пакету, який поставлений в чергу за допомогою функції NF_QUEUE.


Так як всі основні визначення я вже дав, залишається зашарили в ядерному написанні модулів. Для цієї мети поботайте статейки dev0id “a про” Linux Kernel Modules “. Все, тепер я надам ісходник нашого фільтру пакетів, який виявлятиме пакети, які шлються при Land-атаці, тобто де порт і IP атакується сервера співпадають з портом і IP цього ж сервера (тобто source = destination ip / port).


/ * Хедери * /
#define __KERNEL__
#define MODULE
#include
#include
#include
#include
#include
/ * Структура, яку ми будемо використовувати для реєстрації нашої функції * /
static struct nf_hook_ops nfho;


/ * Інтерфейс, який ми використовуємо * /
static char *drop_if = “eth0”;
/ * Тут вказуємо наш ip-адреса, в даному випадку 192.168.168.1 * /
static unsigned char *drop_ip = “xc0xa8xa8x01”;
/ * Порт. Укзиваем поки що один відкритий 80-й порт, але реально дописати програму,
яка буде відслідковувати всі відкриті TCP / UDP-порти * /
unsigned char *deny_port = “x00x50”;


/ * Це наша хук-функція * /
unsigned int hook_func(unsigned int hooknum,
    struct sk_buff **skb,
    const struct net_device *in,
    const struct net_device *out,
    int (*okfn)(struct sk_buff *))
{
 struct sk_buff *sb = *skb;
 struct tcphdr *port;
 port = (struct tcphdr *)(skb->data + (skb->nh.iph->ihl * 4));
 if ((strcmp(in->name, drop_if) == 0) &&
  (sb->nh.iph->saddr == drop_ip) &&
  ((skb->nh.iph->protocol != IPPROTO_TCP) //
   (skb->nh.iph->protocol != IPPROTO_UDP)) &&
  ((port->dest) == *(unsigned short *)deny_port))
 {
  printk(“Packet dropped…”);
  return NF_DROP;
 }else{
  return NF_ACCEPT;
 }
}


/ * Стандартна функція ініціалізації * /
int init_module()
{
    nfho.hook     = hook_func;
    nfho.hooknum  = NF_IP_PRE_ROUTING;
    nfho.pf       = PF_INET;
    nfho.priority = NF_IP_PRI_FIRST;
 
    nf_register_hook(&nfho);
   
    return 0;
}
 
/ * Стандартна функція видалення модуля * /
void cleanup_module()
{
    nf_unregister_hook(&nfho);
}
Ну ось власне і все, що я хотів розповісти в цій вступній статті. Ботай фізику і, фізтех – рулез!


Основні джерела:
[0] netfilter.org
[1] lists.netfilter.org/pipermail/netfilter-devel/
[2] www.geocities.com/victorhugo83/
[3] www.linuxsecurity.com/feature_stories/kernel-netfilter.html


Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*