Implementing a Distributed Firewall

Вопросы программного кода и архитектуры Linux

Модератор: Olej

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Implementing a Distributed Firewall

Непрочитанное сообщение Olej » 19 июн 2015, 15:50

Собственно, выплыла такая такая работа из предложения (по фриланс занятиям) создать модель Distributed Firewall:
Distributed Firewalls
Implementing a Distributed Firewall
1-й документ описывает общую идею, а 2-й даёт даже наброски реализации ... в OpenBSD по состоянию на 1999г.

Занятие это само по себе интересное... :!:
В прототипе OpenBSD всё достаточно понятно, применительно к Linux:
- перехватить системные вызовы connect() и accept() и вставить перед стандартной обработкой проверку допустимости правилам файервола...
- для взаимодействия с демоном политики реализовать модуль ядра (драйвер псевдоустройства) /dev/policy...
- демоном политики - процесс юзерспейс - читает-пишет /dev/policy для проверки политики доступа.

Всё относительно понято и реализуемо (но непросто).
Кроме того, что в оригинальном прототипе для проверки соответствия политике используется библиотека KeyNote - RFC2704.
В современном Debian пакета-библиотеки с таким именем нет.
Такая библиотека и утилиты были в Ubuntu, периода версий 8.04-11.04.

Этот проект, KeyNote, судя по всему, был или переименован, или заменен на аналогичный более позднего RFC...
Как? На что?

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Implementing a Distributed Firewall

Непрочитанное сообщение Olej » 19 июн 2015, 21:31

Olej писал(а): В современном Debian пакета-библиотеки с таким именем нет.
Такая библиотека и утилиты были в Ubuntu, периода версий 8.04-11.04.

Этот проект, KeyNote, судя по всему, был или переименован, или заменен на аналогичный более позднего RFC...
Как? На что?
Нашёлся ;-)
The KeyNote Trust-Management System

Только странно, что всё связанно раскидано по самым разным URL:

Index of /misc - здесь можно скачать ... но и то, не последнюю версию, а предпоследнюю:

Код: Выделить всё

Parent Directory        01-Feb-2009 14:00      -  
keynote-2.2-1.i386.rpm  13-Dec-2001 13:11   111k  
keynote-2.2-1.src.rpm   13-Dec-2001 13:11   139k  
netflow-collector.py    27-Aug-2003 15:45     3k  
keynote(3)

Код: Выделить всё

NAME
keynote — a trust-management system library
SYNOPSIS
#include <sys/types.h>
#include <regex.h>
#include <keynote.h>
...
keynote(4)

Код: Выделить всё

NAME
keynote — a trust-management system
SYNOPSIS
#include <sys/types.h>
#include <regex.h>
#include <keynote.h>
Link options: -lkeynote -lm -lcrypto
...
FILES
keynote.h
libkeynote.a
EXAMPLES
...
keynote(5)

Код: Выделить всё

NAME
keynote — assertion format
SYNOPSIS
KeyNote-Version: 2
Local-Constants: <assignments>
Authorizer: <public key or tag>
Licensees: <public key or tag expression>
Comment: <comment text>
Conditions: <logic predicates>
Signature: <public key signature>
И оттуда же - Python интерфейс:
pykeynote - скачивание ...
pykeynote - страница проекта на Google:
pykeynote is a Python extension module for KeyNote. It provides a high-level object-oriented interface to the KeyNote trust management API. From the KeyNote web page:
Trust management is a unified approach to specifying and interpreting security policies, credentials, and relationships; it allows direct authorization of security-critical actions. KeyNote credentials describe a specific delegation of trust and subsume the role of public key certificates; unlike traditional certificates, which bind keys to names, credentials can bind keys directly to the authorization to perform specific tasks.

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Implementing a Distributed Firewall

Непрочитанное сообщение Olej » 25 июн 2015, 09:11

Olej писал(а):Собственно, выплыла такая такая работа из предложения (по фриланс занятиям) создать модель Distributed Firewall:
И здесь я буду оставлять для себя памятки, комментировать ход развития ... проекта. ;-)
А кому-то, может, окажется, интересным что-то из деталей этого процесса.

Уже на сегодня есть любопытные детали ... хотя меня и трудно чем удивить:

1. Первейшим делом реализаторы вот этого прототипа Implementing a Distributed Firewall называют перехватить системные вызовы accept() & connect(). Они этого не умеют сделать в Linux ... как я их понимаю ;-) и потому выбрали OpenBSD (хотя я бы уж выбирал под такую работу NetBSD ... и хотя на год программирования 1999/2000 их прототипа это и в Linux можно было куда проще сделать ... или нет? какая там была версия ядра, 2.4?).

Но ... "мы не ищем лёгких путей"(с).
Поэтому я это стану делать в Linux.

2. В чём идея такого распределённого файервола? И чем он лучше всеми любимого ;-) iptables (ipfilter и др. всяких подобных)?
Почему за последние годы довольно много публикаций по теме?
Да потому что:
- Распределённый файервол не должен фильтровать каждый пакет сетевого трафика, пропуская его через себя, и гробя на том производительность процессора. Пока пакеты шли на трафике 10Mbps - это никого не смущало. Когда поток пакетов пощёл на трафике в 1Gbps или несколько - тут вот зачесалось. :lol:
- Распределённый файервол должен только разрешить или запретить установление TCP/IP коннекта (accept() & connect()) в начале "3-х уровневого рукопожатия" TCP/IP ... а дальше уже ни4как не вмешиваться в работу IP. Делать это разрешить или запретить он должен на основе какой-то политики.
- Политика распределённого файервола может быть единой (БД) для множества хостов очень большой сети. А отдельные фразы этой большой БД политики могут централизованно рассылаться по хостам этой сети (кому что), и таким образом очень большая сеть может управляться (а не бегать администратору по этой очень большой сети и на каждом хосте править правила iptables).

Идея красивая ... правда, не как замена iptables, а как дополнение к нему.

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Implementing a Distributed Firewall

Непрочитанное сообщение Olej » 25 июн 2015, 09:35

3. Перехват и замена системных вызовов (syscall) Linux - это тема пройденная и известная.
Но хотелось бы это сделать ещё и не только на реальном железе, но и в среде виртуальной машины.

P.S. В чём здесь сложность и фишка?
В том, что сначала умельцы Линуса Торвальдса унесли адрес таблицы системных вызовов sys_call_table из числа экспортруемых символов ядра.
И решили что тем они сделали Linux сильно защищённым ;-)
Но этого показалось мало, и позже они для страницы RAM размещения sys_call_table средствами диспетчера MMU установили правило доступа read-only. И если захочется модифицировать sys_call_table, то нужно сначала убрать флаг read-only, а потом вернуть его в зад. ;-) А для этого нужно писать в скрытые системные аппаратные регистры процессора x86 (на некоторых других платформах они пишут, что не применяется защита read-only).

Вот это нужно проверять.
Делаем тест, который подменяет системный вызов sys_write (вывод на tty, printf(), __NR_write = 4) ... для проверки возможностей и так, чтобы не сильно навредить системе сразу :lol: .

Этот тест только "шпионит" за вашим терминалом: всё что выводится на терминал, ещё и пишется параллельно в системный журнал ядра по printk():

Код: Выделить всё

olej@nvidia ~/2015_WORK/in.WORK/FWall/drivers/wrlog $ sudo insmod wrlog.ko

olej@nvidia ~/2015_WORK/in.WORK/FWall/drivers/wrlog $ sudo rmmod wrlog

olej@nvidia ~/2015_WORK/in.WORK/FWall/drivers/wrlog $ dmesg | tail -n25
[ 1220.476585] device eth0 entered promiscuous mode
[ 7850.815396] ! set new sys_write syscall [f8bff000]
[ 7850.815399] ! CR0 = 8005003b
[ 7850.815401] ! CR0 = 8004003b
[ 7850.815402] ! CR0 = 8005003b
[ 7850.817121] ! {0049} /home/olej/2015_WORK/in.WORK/FWall/drivers/wrlog
[ 7850.817483] ! {0075} \x1b[01;32molej@nvidia\x1b[01;34m ~/2015_WORK/in.WORK/FWall/drivers/wrlog $\x1b[00m
[ 7853.997031] ! {0001} s
[ 7854.301131] ! {0001} u
[ 7854.541040] ! {0001} d
[ 7854.901050] ! {0001} o
[ 7857.934642] ! {0001}
[ 7858.317047] ! {0001} r
[ 7859.061051] ! {0001} m
[ 7859.284676] ! {0001} m
[ 7860.268919] ! {0001} o
[ 7860.884974] ! {0001} d
[ 7862.149085] ! {0001}
[ 7863.748656] ! {0001} w
[ 7864.005039] ! {0001} r
[ 7865.141581] ! {0001} l
[ 7865.453121] ! {0001} o
[ 7865.925047] ! {0001} g
[ 7866.910978] ! {0002}
[ 7866.917365] ! restore old sys_write syscall [c1179f70]
P.S. сам printk() работает тоже через системный вызов sys_write - там смешной код чтобы избежать бесконечной рекурсии ... в ядре :lol:

В итоге, я вас поздравляю ;-) : этот код одинаково хорошо работает как на реальном железе, так и в виртуально машине в VirtualBox.
Меня в этой задаче интересует конкретика - демонстрировать работу в облачной виртуальной машине под управлением Cisco Maestro. Но всему своё время ... и, кроме того, я уже предварительно (по-быстрому, по-верхам) уже проверил в такой облачной виртуальной машине: а). закинуть туда wrog.tgz, б). собрать там модуль ядра (могло не пойти сразу из-за хэдер-файлов ядра), в). выполнить тест ... Первое впечатление такое, что и там этот тест прошёл ОК.
Вложения
wrlog.tgz
(2.68 КБ) 423 скачивания

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Implementing a Distributed Firewall

Непрочитанное сообщение Olej » 25 июн 2015, 09:55

Olej писал(а):3. Перехват и замена системных вызовов (syscall) Linux - это тема пройденная и известная.
Но хотелось бы это сделать ещё и не только на реальном железе, но и в среде виртуальной машины.
4. Это большое облегчение для разработчиков подобных проектов "вблизи ядра".
Для этого теперь достаточно простейшей VM такого типа, как я использую - проще не бывает:
xu.png

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Implementing a Distributed Firewall

Непрочитанное сообщение Olej » 25 июн 2015, 10:21

5. Дальше - больше :lol:
Разбирательство приводит к тому, что все системные вызовы в Linux сделаны по-людски ... за исключением сетевых системных вызовов, которые сделаны "через жопу" :-o .
Вот здесь об этом я уже писал: куда делись сетевые syscall-ы ?.

Начиная (/usr/include/asm-generic/unistd.h) с системного вызова sys_socket (__NR_socket 198) и заканчивая sys_recvmsg (__NR_recvmsg 212) ... или около того...
Все они мультиплексируются через один системный вызов:

Код: Выделить всё

int socketcall(int call, unsigned long *args);
Причём сказано, что а). на некоторых платформах (ia64) сетевые системные вызовы идут нормально, через общую таблицу системных вызовов, но вот на i686/X86_64 присутствует от такое уродство, б). что это сугубо специфика Linux и что такого вызова socketcall() нет в POSIX и ни в одной UNIX-like системе.

Зачем сделано такое уродство - уму непостижимо! (пока?)

Теперь предстоит выяснять:
1. как код вызова call численно соотносится с __NR_* ?
2. как список аргументов разных вызовов единообразно пакуется в args ?

Но мы ведь не ищем лёгких путей? :lol:

Результаты конкретных разгребаний именно по этому вопросу, подмены косвенно мультиплексированных системных вызовов accept(2) & connect(2) , я буду складывать ... журналировать ;-) в той уже теме куда делись сетевые syscall-ы ?.

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Implementing a Distributed Firewall

Непрочитанное сообщение Olej » 26 июн 2015, 10:52

Olej писал(а): Но хотелось бы это сделать ещё и не только на реальном железе, но и в среде виртуальной машины.
Почему я так часто упоминаю возможность замены системных вызовов на виртуальной машине?
Не только потому, что об этом просит заказчик, точнее куратор ;-) , этого проекта ... есть куда важнее обстоятельство (обратите на него внимание те, кто думает иметь дело с подобными техниками).
Дело в том, что подмена системных вызовов - техника рисковая, здесь малейшая недодуманность в коде приводит к ошибкам ядра.
Вот как это примерно происходит:

Код: Выделить всё

olej@ubuntu:~/WORK_2015/FWall/drivers/fwnet$ sudo insmod fwnet.ko deny=192.168.1.100 debug=1
olej@ubuntu:~/WORK_2015/FWall/drivers/fwnet$ dmesg | tail -n15
[ 3781.016788]  000040f7 00200246 00000000 c196bf43 0000000f 00000000 00000029 dc51def2
[ 3781.016797] Call Trace:
[ 3781.016806]  [<c1096b5c>] ? kallsyms_on_each_symbol+0x6c/0xa0
[ 3781.016813]  [<c1003233>] ? devt_from_partuuid+0xc3/0x180
[ 3781.016821]  [<e1a180e0>] find_sym+0x40/0x56 [fwnet]
[ 3781.016828]  [<e1a1d04b>] init+0x4b/0x1000 [fwnet]
[ 3781.016834]  [<c1003035>] do_one_initcall+0x35/0x170
[ 3781.016841]  [<e1a1d000>] ? 0xe1a1cfff
[ 3781.016847]  [<c1095f9d>] sys_init_module+0xad/0x210
[ 3781.016854]  [<c1142bb3>] ? sys_close+0x73/0xc0
[ 3781.016862]  [<c15afedf>] sysenter_do_call+0x12/0x28
[ 3781.016866] Code: 00 00 00 00 00 00 00 00 00 00 80 70 df 51 dc 6d 65 02 05 c0 a8 01 64 02 16 00 00 e4 03 6e b7 44 df 51 dc e0 80 a1 e1 00 00 00 00 <68> 30 df 51 dc e9 c3 a0 4f 05 a1 e1 6d 65 02 05 58 df 51 dc 4b 
[ 3781.016908] EIP: [<dc51df34>] 0xdc51df34 SS:ESP 0068:dc51de8c
[ 3781.016915] CR2: 00000000dc51df34
[ 3781.016921] ---[ end trace f7e1d0b531d88a11 ]---
Это ещё лёгкое недомогание ;-) , может быть Ooops сообщение kernel или вообще kernel panic ...
Но после такого лёгкого сообщения (обращаем внимание на счётчик ссылок):

Код: Выделить всё

olej@ubuntu:~/WORK_2015/FWall/drivers/fwnet$ lsmod | head -n4
Module                  Size  Used by
fwnet                  18508  1 
vboxvideo              12511  1 
drm                   197692  2 vboxvideo
И естественно:

Код: Выделить всё

olej@ubuntu:~/WORK_2015/FWall/drivers/fwnet$ sudo rmmod fwnet.ko
ERROR: Module fwnet is in use
Модуль (ломанный) теперь удалён быть не может ... систему он поломал, а удалиться не может.
Продолжать отладку дальше невозможно - система не позволит загрузить 2 дубликата одного модуля.
Вообще работать нельзя - ядро в неустойчивом, непредсказуемом состоянии ... вы можете 3 часа наблюдать и изучать совершенно неадекватные результаты :shock: (и такое было).
В этом случае единственное, что можно делать - перезагрузка! (это при условии, что вы при этом что-то радикально не порушили в ядре, и перезагрузка следующая вообще состоится ... у меня такое было :-o ).
Конечно, на VM это и а). безопаснее и б). быстрее.

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Implementing a Distributed Firewall

Непрочитанное сообщение Olej » 26 июн 2015, 23:36

Всё!
Сделано...
Это фактически мини-прототип распределённого файервола, который перехватывает контроль над системными вызовами connect() & accept() Linux, и может запретить как подключения TCP из определённого IP, так и подключения к определённому IP.
Вложения
fwnet.tar.gz
(72.39 КБ) 404 скачивания

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Implementing a Distributed Firewall

Непрочитанное сообщение Olej » 08 июл 2015, 21:24

Olej писал(а):Это фактически мини-прототип распределённого файервола, который перехватывает контроль над системными вызовами connect() & accept() Linux, и может запретить как подключения TCP из определённого IP, так и подключения к определённому IP.
Вот это более законченный вариант всего того, что называлось ранее + ещё кое что.

На этом работа (незавершённая) над этим проектом заканчивается, заказчик полностью удовлетворён тем, что уже получил, и даже оплатил более-менее сделанное.

Код: Выделить всё

olej@nvidia ~/2015_WORK/in.WORK/FWall/disfw $ ls -l
итого 116
-rw-rw-r-- 1 olej olej  6568 июля   5 15:52 all.hist
drwxrwxr-x 2 olej olej  4096 июля   5 16:56 cliserv
-rw-rw-r-- 1 olej olej  1134 июля   5 15:38 common.h
-rw-r--r-- 1 olej olej  1346 июля   5 11:24 CR0.c
-rw-r--r-- 1 olej olej   554 июля   5 11:24 find.c
drwxrwxr-x 2 olej olej  4096 июля   5 15:47 fwnet.ver1
drwxrwxr-x 2 olej olej  4096 июля   5 16:56 fwnet.ver2
drwxrwxr-x 2 olej olej  4096 июля   5 15:47 fwtest
-rw-r--r-- 1 olej olej   334 июля   5 15:50 Makefile
-rw-rw-r-- 1 olej olej 68122 июля   5 11:24 socketcall1.pdf
-rw-rw-r-- 1 olej olej   690 июля   5 11:24 URL.txt
drwxrwxr-x 2 olej olej  4096 июля   5 15:47 wrlog
Вложения
disfw.tgz
(102.31 КБ) 386 скачиваний

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: Implementing a Distributed Firewall

Непрочитанное сообщение Olej » 08 июл 2015, 21:51

Olej писал(а):На этом работа (незавершённая) над этим проектом заканчивается, заказчик полностью удовлетворён тем, что уже получил,
Теперь для памятки себе и для объяснения тем, кто станет делать подобные проекты, скопирую сюда полностью текст репорта, который получил заказчик (правда он получил перевод этого текста на английский ;-) ) ... чего не скопировать, если этот текст уже написан ;-).
(и это необходимое и достаточное объяснение к архиву, прилепленному выше)

Для создания распределенного фаервола нужно взять под свое управление системные вызовы accept() и connect(). Как только локальная программа попытается выполнить connect(), или от удаленной программы поступит запрос на соединение в accept() - управление должно передаться фаерволу, который по параметрам вызова должен определить разрешить или отвергнуть (возвратить код ошибки) этот системный вызов.

Как видно из самого определения, такая модель распределённого фаервола годится только для протокола TCP/IP. Она не работает для других протоколов семейства IP: UDP, SCTP etc. В отличие от традиционных фаерволов (iptables, ipfilter etc.), эта технология не контролирует динамически каждый пакет IP при его поступлении в процессе сеанса связи. Контроль производится только в начальный момент соединения. Это позволяет на порядки уменьшить загрузку процессора на эти цели. Это очень важно для больших и сверхбольших сегментов сети.

Для решения этой задачи нужно заменить на свои в таблице системных вызовов (sys_call_table) в ядре функции обрабатывающие accept() и connect(). Собственные функции обработки должны проанализировать параметры вызова и в зависимости от них или возвратить код ошибки (отвергнуть), или вызвать оригинальную (старую) функцию обработки (принять).

Это можно сделать двумя способами:

1. Статический способ: внести собственный патч в исходный код ядра Linux, перекомпилировать ядро, и загружать это ядро с измененной обработкой accept() и connect(). Этот способ крайне трудоемкий в отладке. Кроме того, такой способ при тиражировании проекта потребует модификации ядра на всех компьютерах.

2. Динамический способ: создать модуль ядра (драйвер Linux) который при загрузке заменяет адреса функций обработки accept() и connect() в таблице системных вызовов ядра, а при выгрузке восстанавливает старые значения. Этот способ намного более гибкий. Но он очень сложный в реализации.

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

Ответить

Вернуться в «Linux изнутри»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 9 гостей