Implementing a Distributed Firewall
Модератор: Olej
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Implementing a Distributed Firewall
Собственно, выплыла такая такая работа из предложения (по фриланс занятиям) создать модель 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...
Как? На что?
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 писал(а): В современном 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
Код: Выделить всё
NAME
keynote — a trust-management system library
SYNOPSIS
#include <sys/types.h>
#include <regex.h>
#include <keynote.h>
...
Код: Выделить всё
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
...
Код: Выделить всё
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>
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 писал(а):Собственно, выплыла такая такая работа из предложения (по фриланс занятиям) создать модель Distributed Firewall:
А кому-то, может, окажется, интересным что-то из деталей этого процесса.
Уже на сегодня есть любопытные детали ... хотя меня и трудно чем удивить:
1. Первейшим делом реализаторы вот этого прототипа Implementing a Distributed Firewall называют перехватить системные вызовы accept() & connect(). Они этого не умеют сделать в Linux ... как я их понимаю и потому выбрали OpenBSD (хотя я бы уж выбирал под такую работу NetBSD ... и хотя на год программирования 1999/2000 их прототипа это и в Linux можно было куда проще сделать ... или нет? какая там была версия ядра, 2.4?).
Но ... "мы не ищем лёгких путей"(с).
Поэтому я это стану делать в Linux.
2. В чём идея такого распределённого файервола? И чем он лучше всеми любимого iptables (ipfilter и др. всяких подобных)?
Почему за последние годы довольно много публикаций по теме?
Да потому что:
- Распределённый файервол не должен фильтровать каждый пакет сетевого трафика, пропуская его через себя, и гробя на том производительность процессора. Пока пакеты шли на трафике 10Mbps - это никого не смущало. Когда поток пакетов пощёл на трафике в 1Gbps или несколько - тут вот зачесалось.
- Распределённый файервол должен только разрешить или запретить установление TCP/IP коннекта (accept() & connect()) в начале "3-х уровневого рукопожатия" TCP/IP ... а дальше уже ни4как не вмешиваться в работу IP. Делать это разрешить или запретить он должен на основе какой-то политики.
- Политика распределённого файервола может быть единой (БД) для множества хостов очень большой сети. А отдельные фразы этой большой БД политики могут централизованно рассылаться по хостам этой сети (кому что), и таким образом очень большая сеть может управляться (а не бегать администратору по этой очень большой сети и на каждом хосте править правила iptables).
Идея красивая ... правда, не как замена iptables, а как дополнение к нему.
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: Implementing a Distributed Firewall
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) ... для проверки возможностей и так, чтобы не сильно навредить системе сразу .
Этот тест только "шпионит" за вашим терминалом: всё что выводится на терминал, ещё и пишется параллельно в системный журнал ядра по printk():
P.S. сам printk() работает тоже через системный вызов sys_write - там смешной код чтобы избежать бесконечной рекурсии ... в ядре
В итоге, я вас поздравляю : этот код одинаково хорошо работает как на реальном железе, так и в виртуально машине в VirtualBox.
Меня в этой задаче интересует конкретика - демонстрировать работу в облачной виртуальной машине под управлением Cisco Maestro. Но всему своё время ... и, кроме того, я уже предварительно (по-быстрому, по-верхам) уже проверил в такой облачной виртуальной машине: а). закинуть туда wrog.tgz, б). собрать там модуль ядра (могло не пойти сразу из-за хэдер-файлов ядра), в). выполнить тест ... Первое впечатление такое, что и там этот тест прошёл ОК.
Но хотелось бы это сделать ещё и не только на реальном железе, но и в среде виртуальной машины.
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) ... для проверки возможностей и так, чтобы не сильно навредить системе сразу .
Этот тест только "шпионит" за вашим терминалом: всё что выводится на терминал, ещё и пишется параллельно в системный журнал ядра по 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]
В итоге, я вас поздравляю : этот код одинаково хорошо работает как на реальном железе, так и в виртуально машине в VirtualBox.
Меня в этой задаче интересует конкретика - демонстрировать работу в облачной виртуальной машине под управлением Cisco Maestro. Но всему своё время ... и, кроме того, я уже предварительно (по-быстрому, по-верхам) уже проверил в такой облачной виртуальной машине: а). закинуть туда wrog.tgz, б). собрать там модуль ядра (могло не пойти сразу из-за хэдер-файлов ядра), в). выполнить тест ... Первое впечатление такое, что и там этот тест прошёл ОК.
- Вложения
-
- wrlog.tgz
- (2.68 КБ) 430 скачиваний
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: Implementing a Distributed Firewall
4. Это большое облегчение для разработчиков подобных проектов "вблизи ядра".Olej писал(а):3. Перехват и замена системных вызовов (syscall) Linux - это тема пройденная и известная.
Но хотелось бы это сделать ещё и не только на реальном железе, но и в среде виртуальной машины.
Для этого теперь достаточно простейшей VM такого типа, как я использую - проще не бывает:
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: Implementing a Distributed Firewall
5. Дальше - больше
Разбирательство приводит к тому, что все системные вызовы в Linux сделаны по-людски ... за исключением сетевых системных вызовов, которые сделаны "через жопу" .
Вот здесь об этом я уже писал: куда делись сетевые syscall-ы ?.
Начиная (/usr/include/asm-generic/unistd.h) с системного вызова sys_socket (__NR_socket 198) и заканчивая sys_recvmsg (__NR_recvmsg 212) ... или около того...
Все они мультиплексируются через один системный вызов:
Причём сказано, что а). на некоторых платформах (ia64) сетевые системные вызовы идут нормально, через общую таблицу системных вызовов, но вот на i686/X86_64 присутствует от такое уродство, б). что это сугубо специфика Linux и что такого вызова socketcall() нет в POSIX и ни в одной UNIX-like системе.
Зачем сделано такое уродство - уму непостижимо! (пока?)
Теперь предстоит выяснять:
1. как код вызова call численно соотносится с __NR_* ?
2. как список аргументов разных вызовов единообразно пакуется в args ?
Но мы ведь не ищем лёгких путей?
Результаты конкретных разгребаний именно по этому вопросу, подмены косвенно мультиплексированных системных вызовов accept(2) & connect(2) , я буду складывать ... журналировать в той уже теме куда делись сетевые syscall-ы ?.
Разбирательство приводит к тому, что все системные вызовы в Linux сделаны по-людски ... за исключением сетевых системных вызовов, которые сделаны "через жопу" .
Вот здесь об этом я уже писал: куда делись сетевые syscall-ы ?.
Начиная (/usr/include/asm-generic/unistd.h) с системного вызова sys_socket (__NR_socket 198) и заканчивая sys_recvmsg (__NR_recvmsg 212) ... или около того...
Все они мультиплексируются через один системный вызов:
Код: Выделить всё
int socketcall(int call, unsigned long *args);
Зачем сделано такое уродство - уму непостижимо! (пока?)
Теперь предстоит выяснять:
1. как код вызова call численно соотносится с __NR_* ?
2. как список аргументов разных вызовов единообразно пакуется в args ?
Но мы ведь не ищем лёгких путей?
Результаты конкретных разгребаний именно по этому вопросу, подмены косвенно мультиплексированных системных вызовов accept(2) & connect(2) , я буду складывать ... журналировать в той уже теме куда делись сетевые syscall-ы ?.
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: Implementing a Distributed Firewall
Почему я так часто упоминаю возможность замены системных вызовов на виртуальной машине?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 ]---
Но после такого лёгкого сообщения (обращаем внимание на счётчик ссылок):
Код: Выделить всё
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 часа наблюдать и изучать совершенно неадекватные результаты (и такое было).
В этом случае единственное, что можно делать - перезагрузка! (это при условии, что вы при этом что-то радикально не порушили в ядре, и перезагрузка следующая вообще состоится ... у меня такое было ).
Конечно, на VM это и а). безопаснее и б). быстрее.
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: Implementing a Distributed Firewall
Всё!
Сделано...
Это фактически мини-прототип распределённого файервола, который перехватывает контроль над системными вызовами connect() & accept() Linux, и может запретить как подключения TCP из определённого IP, так и подключения к определённому IP.
Сделано...
Это фактически мини-прототип распределённого файервола, который перехватывает контроль над системными вызовами connect() & accept() Linux, и может запретить как подключения TCP из определённого IP, так и подключения к определённому IP.
- Вложения
-
- fwnet.tar.gz
- (72.39 КБ) 411 скачиваний
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: Implementing a Distributed Firewall
Вот это более законченный вариант всего того, что называлось ранее + ещё кое что.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 КБ) 393 скачивания
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: Implementing a Distributed Firewall
Теперь для памятки себе и для объяснения тем, кто станет делать подобные проекты, скопирую сюда полностью текст репорта, который получил заказчик (правда он получил перевод этого текста на английский ) ... чего не скопировать, если этот текст уже написан .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() в таблице системных вызовов ядра, а при выгрузке восстанавливает старые значения. Этот способ намного более гибкий. Но он очень сложный в реализации.
Мы будем реализовывать динамический способ.
Кто сейчас на конференции
Сейчас этот форум просматривают: нет зарегистрированных пользователей и 2 гостя