47
Вадим Гончаров Томский политехнический университет Реорганизация IPFW и NETGRAPH: новый подход к контролю сетевого стека

Nuclight Ipfw Rootconf2009

Embed Size (px)

Citation preview

Page 1: Nuclight Ipfw Rootconf2009

Вадим ГончаровТомский политехнический университет

Реорганизация IPFW и NETGRAPH: новый подход к контролю сетевого стека

Page 2: Nuclight Ipfw Rootconf2009

Человеко-машинные системы• ПроцедурныеНабор функций (процедур)

внутри прикладной области, описываемых в терминах прикладной области. Набор решений ограничен.

• ПроективныеНа языке инструментальной

области составляется проект, описывающий ее предполагаемое поведение, затем машина его выполняет.

Page 3: Nuclight Ipfw Rootconf2009

Процедурные системы• Набор слабосвязанных предписаний• Ограниченная осведомленность• Гарантированные (простые) навыки• Быстрота решения предусмотренной ситуации

Примеры:– Пульт управления телевизором– Мастер настройки Internet в Windows

Page 4: Nuclight Ipfw Rootconf2009

Проективные системы• Сложность решения задачи• Информационная открытость: документация• Ответственность

» Unix way:ls -dt1 `grep -il отчет *` | head -1

Page 5: Nuclight Ipfw Rootconf2009

История файрволов• Сначала требовалась лишь статическая фильтрация• Затем потребовалась динамика: отслеживание

соединений и поддержка NAT• Затем потребовалась возможность легкого

расширения функционала• Наконец, теперь требуется управляемость всем

этим разросшимся хозяйством

Page 6: Nuclight Ipfw Rootconf2009

Статическая фильтрацияОснова любого нынешнего файрвола. Наиболее популярный

подход:• набор правил (ruleset)• каждое правило — отдельная логическая единица,

состоящая из одного или нескольких условий и одного (или нескольких вспомогательных) действий, выполняемых при совпадении (match) условий

• правила имеют разный приоритет

Page 7: Nuclight Ipfw Rootconf2009

Статические правила: реализацияКлассический подход (ipfilter, ipfw1, pf) — фиксированная

структура, описывающая все возможные варианты проверок, поле флагов описывает, какие именно проверки применены в данном конкретном правиле.

Недостатки:• сложность расширения• большой размер одного правила в байтах в ядре: у pf это

более 600 байт (см. pfrulepl в vmstat -z), тогда как типичный размер cache-line процессора — 64 байта.

Page 8: Nuclight Ipfw Rootconf2009

А в это время...80-е — Berkley Packet Filter (BPF), виртуальная машина в ядре ОС# tcpdump -d -s 123 src host 1.2.3.4(000) ldh [12](001) jeq #0x800 jt 2 jf 4(002) ld [26](003) jeq #0x1020304 jt 8 jf 9(004) jeq #0x806 jt 6 jf 5(005) jeq #0x8035 jt 6 jf 9(006) ld [28](007) jeq #0x1020304 jt 8 jf 9(008) ret #123(009) ret #0

Page 9: Nuclight Ipfw Rootconf2009

Ассемблер BPF• Аккумулятор A• Индексный регистр X• 16 слов памяти M[]• Опкоды (opcode, код операции, т. е. инструкция)

одинаковой длины (8 байт)• DLT: Data Link Type

– #define DLT_EN10MB 1 /* Ethernet 10Mb */– #define DLT_RAW 12 /* raw IP */

Page 10: Nuclight Ipfw Rootconf2009

BSD/OS ipfw, 90-еБазируется на расширенном BPF, в который

компилируется из своего языка:implicit permit;output interface(pif0) {srcaddr(212.22.64.128/26) { established { permit; } switch ipprotocol { case tcp: switch dstport { case pop3/tcp: permit;

Page 11: Nuclight Ipfw Rootconf2009

Точки входа в сетевом стекеBSD/OS ipfw FreeBSD ipfw/pfil Linux iptables

pre-input PFIL_IN PREROUTING

input INPUT

forward FORWARD

pre-output* OUTPUT

output* PFIL_OUT POSTROUTING

Page 12: Nuclight Ipfw Rootconf2009

output иpre-output в

BSD/OS ipfw:• Всё наоборот с

локальными пакетами

• В других системах forward → output

Page 13: Nuclight Ipfw Rootconf2009

Linux iptables (netfilter, 2001)• struct ipt_* (entry, match, ip, target, …)• Переменная длина структур, в постоянных полях

ссылки на функции конкретного модуля• Введены средства облегчения управляемости

(цепочки) и отслеживания соединений (conntrack) как неотъемлемая часть самого файрвола

Page 14: Nuclight Ipfw Rootconf2009

FreeBSD/NetBSD: pfil(9)

ether_outputether_output()()

ip_input()ip_input() ip_output()ip_output()

К локальным сокетам этой машиныК локальным сокетам этой машины

Драйвера сетевых интерфейсовДрайвера сетевых интерфейсов

ether_demuxether_demux()()

Page 15: Nuclight Ipfw Rootconf2009

FreeBSD: pfil(9)• ipfw:

pfil_add_hook(ipfw_check_in, NULL, PFIL_IN, pfh_inet);pfil_add_hook(ipfw_check_out, NULL, PFIL_OUT, pfh_inet);

• pf:pfil_add_hook(pf_check_in, NULL, PFIL_IN, pfh_inet);pfil_add_hook(pf_check_out, NULL, PFIL_OUT, pfh_inet);

• ip_input():pfil_run_hooks(&inet_pfil_hook, &m, m->m_pkthdr.rcvif,

PFIL_IN, NULL);• pfil_list_add():

if (flags & PFIL_IN) TAILQ_INSERT_HEAD(list, pfh1, pfil_link);else TAILQ_INSERT_TAIL(list, pfh1, pfil_link);

Page 16: Nuclight Ipfw Rootconf2009

NetGraph• Коммуникационный объектно—ориентированный

фреймворк внутри ядра• Граф в математике: узлы (nodes) и рёбра (edges)• Граф в ядре: каждый узел имеет крючки (hooks),

соединение хуков двух узлов образует ребро, вдоль которого передаются пакеты

• ОО-стиль: узлы управляются сообщениями (msg)

Page 17: Nuclight Ipfw Rootconf2009

ngctl9010ngctl9010[ng_socket][ng_socket] [ng_echo][ng_echo]

Команды в ngctl+ mkpeer echo localhook hook1+ name .:localhook myecho

localhook hook1myecho

+ show myecho: Name: myecho Type: echo ID: 00001645 Num hooks: 1 Local hook Peer name Peer type Peer ID Peer hook ---------- --------- --------- ------- --------- hook1 ngctl9010 socket 00001644 localhook

Page 18: Nuclight Ipfw Rootconf2009

Типы узлов• Граничные (edge nodes) — взаимодействие с

остальной частью ядра– ng_ether, ng_socket, ng_ipfw, ng_iface, ...

• Внутренние — взаимодействие только с соседними узлами– ng_echo, ng_tee, ng_bpf, ng_tag, ng_pppoe, ...

Page 19: Nuclight Ipfw Rootconf2009

ng_ether(4)

Драйвер интерфейсаДрайвер интерфейса

ether_demuxether_demux()()

upper

lower

В норме хуки ноды как бызамкнуты между собой

Page 20: Nuclight Ipfw Rootconf2009

Обычный сокетint fd = socket(AF_INET);int fd = socket(AF_INET);

Машинерия Машинерия TCP/IPTCP/IP

Generic socket Generic socket layerlayer

Ядро

Userland

Page 21: Nuclight Ipfw Rootconf2009

int fd = socket(AF_NETGRAPH);int fd = socket(AF_NETGRAPH);

Generic socket Generic socket layerlayer

Узел типа Узел типа ng_socketng_socket

Ядро

Userland

ng_socket

Page 22: Nuclight Ipfw Rootconf2009

Машинерия Машинерия TCP/IPTCP/IP

Generic socket Generic socket layerlayer Узел типа ng_ksocketУзел типа ng_ksocket

Ядро

Userland ng_ksocket

Page 23: Nuclight Ipfw Rootconf2009

Пример графаГраф из ядра легко

можно визуализировать в пакете graphviz, скормив ему текстовый вывод команды ngctl dot

Page 24: Nuclight Ipfw Rootconf2009

А вот такое автоматически создает mpd

(фрагмент для одного интерфейса ng3 в соединенном состоянии)

Page 25: Nuclight Ipfw Rootconf2009

Правила ipfw2• Расширяемость была достигнута введением

опкодов, смоделированных наподобие BPF.• FreeBSD следует POLA (принцип наименьшего

удивления пользователя), поэтому интерфейс, основанный на правилах, требовалось сохранить

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

Page 26: Nuclight Ipfw Rootconf2009

Опкоды• Опкод начинается с номера, длины в 4-байтных словах

(возможные аргументы) и флагов• На каждое элементарное действие: O_IP_SRC,

O_IP_SRC_MASK, O_IP_SRC_ME, O_IP_DSTPORT, O_RECV, O_VERREVPATH, O_LOG, O_ACCEPT, O_DIVERT и др.

• Парсер располагает сначала опкоды проверки условий, затем в конце — опкоды действия (action) правила; каждый опкод выставляет match в 0 или 1, при 0 исполнение естественным образом прекращается, не доходя до действия

Page 27: Nuclight Ipfw Rootconf2009

Конъюнктивная нормальная форма (КНФ)• Каждый опкод имеет флаги F_OR и F_OR• По умолчанию правило исполняется как

конъюнкция (AND) опкодов — первый же false прекращает работу данного правила

• В случае выставленного F_OR действует OR-блок — false переходит к следующему опкоду, true же пропускает опкоды до конца OR-блока (оптимизация выполнения)

Page 28: Nuclight Ipfw Rootconf2009

Пример правила в КНФipfw add deny { src-ip 1.2.3.4 or src-ip 1.2.3.5 or dst-ip 5.6.7.8} { not dst-port 80 or not dst-port 443 }

• O_IP_SRC, F_OR, 1.2.3.4• O_IP_SRC, F_OR, 1.2.3.5• O_IP_DST, 5.6.7.8• O_IP_DSTPORT, F_OR|F_NOT, 80• O_IP_DSTPORT, F_NOT, 443• O_DENY

Page 29: Nuclight Ipfw Rootconf2009

Динамические правила• Коммутативная относительно

источника/назначения хэш-функция• O_PROBE_STATE, O_CHECK_STATE, O_LIMIT,

O_KEEP_STATE• Указатель на родительское правило: исполнение

начинается с action offset и продолжается дальше как и в статическом варианте

Page 30: Nuclight Ipfw Rootconf2009

Трюки делать можно, но...• pf: одно правило с кейвордом reply-to• ipfw:

add 100 skipto 300 tag 1 in recv $ext_if1 keep-stateadd 200 skipto 300 tag 2 in recv $ext_if2 keep-stateadd 300 allow { recv $ext_if1 or recv $ext_if2 }add 400 allow in recv $int_ifadd 500 fwd $gw1 tagged 1add 600 fwd $gw2 tagged 2

Page 31: Nuclight Ipfw Rootconf2009

Но лучше, чем когда нельзяЗадача: отфильтровать внутри транзитного PPTP

GRE src-адреса нашей клиентской подсети• pf: невозможно в принципе• ipfw + netgraph позволяют это сделать, хотя и

дорогой ценой — сложные скрипты и выражения для tcpdump

Page 32: Nuclight Ipfw Rootconf2009

Выкурим кучу мануалов и начнем...#define GRESTART IPHDRLEN(0)/* Check that is GREv1 with seq num and proto set per RFC 2637 */#define VALID_PPTP_GRE ((ip[GRESTART:4] & 0xff7fffff) = 0x3001880b)/* ACK is optional 4 bytes to previous 12 */#define GRE_DATA_START (GRESTART + ((ip[GRESTART+1] & 0x80) >> 5) + 12)/* Actual IP subnet/Mask to find in the src IP of inner IP datagram */#define SUBNET 0x52754000 /* 82.117.64.0 */#define MASK 0xffffff00 /* 255.255.255.0 */#define INNER_SRC_EQ_SUBNET(ppp_hdr_len) (ip[(GRE_DATA_START+ppp_hdr_len+12):4] & MASK =

SUBNET)/* Finally, expression: sort by most frequent pattern first */proto gre and VALID_PPTP_GRE and ( ( (ip[GRE_DATA_START]=0x21) and INNER_SRC_EQ_SUBNET(1) ) or ( (ip[GRE_DATA_START:2]=0xff03) and (ip[GRE_DATA_START+2]=0x21) and

INNER_SRC_EQ_SUBNET(3) ) or ( (ip[GRE_DATA_START:4]=0xff030021) and INNER_SRC_EQ_SUBNET(4) ) or ( (ip[GRE_DATA_START:2]=0x0021) and INNER_SRC_EQ_SUBNET(2) ))

Page 33: Nuclight Ipfw Rootconf2009

Совершенно нечитаемо, правда?$ cpp -P tcpdump-gre-addr-cppproto gre and ((ip[((ip[0]&0xf)<<2):4] & 0xff7fffff) = 0x3001880b) and ( ( (ip[(((ip[0]&0xf)<<2) + ((ip[((ip[0]&0xf)<<2)+1] & 0x80) >> 5) + 12)]=0x21) and

(ip[((((ip[0]&0xf)<<2) + ((ip[((ip[0]&0xf)<<2)+1] & 0x80) >> 5) + 12)+1 +12):4] & 0xffffff00 = 0x52754000)

) or ( (ip[(((ip[0]&0xf)<<2) + ((ip[((ip[0]&0xf)<<2)+1] & 0x80) >> 5) + 12):2]=0xff03) and

(ip[(((ip[0]&0xf)<<2) + ((ip[((ip[0]&0xf)<<2)+1] & 0x80) >> 5) + 12)+2]=0x21) and (ip[((((ip[0]&0xf)<<2) + ((ip[((ip[0]&0xf)<<2)+1] & 0x80) >> 5) + 12)+3 +12):4] & 0xffffff00 = 0x52754000)

) or ( (ip[(((ip[0]&0xf)<<2) + ((ip[((ip[0]&0xf)<<2)+1] & 0x80) >> 5) + 12):4]=0xff030021) and

(ip[((((ip[0]&0xf)<<2) + ((ip[((ip[0]&0xf)<<2)+1] & 0x80) >> 5) + 12)+4 +12):4] & 0xffffff00 = 0x52754000)

) or ( (ip[(((ip[0]&0xf)<<2) + ((ip[((ip[0]&0xf)<<2)+1] & 0x80) >> 5) + 12):2]=0x0021) and

(ip[((((ip[0]&0xf)<<2) + ((ip[((ip[0]&0xf)<<2)+1] & 0x80) >> 5) + 12)+2 +12):4] & 0xffffff00 = 0x52754000)

))

Page 34: Nuclight Ipfw Rootconf2009

А теперь — в netgraph!#!/bin/shPATTERN=`cpp -P tcpdump-gre-addr-cpp`BPFPROG=`tcpdump -s 8192 -r dltraw.pcap -ddd

$PATTERN | awk -f /tmp/bpf.awk`...ngctl mkpeer ipfw: bpf 190 $INHOOKngctl name ipfw:190 $NODENAMEngctl msg $NODEPATH setprogram

{ thisHook=\"$INHOOK\" ifMatch=\"$MATCHHOOK\" ifNotMatch=\"$NOTMATCHHOOK\" $BPFPROG }

ipfw add 4492 netgraph 190 gre from 82.117.64.0/24 to any iplen 60-1500

Page 35: Nuclight Ipfw Rootconf2009

Что будем улучшать?• Единый набор правил для всего — неудобен при большом

количестве правил (хотя можно сгенерировать правила машиной)

• Надо сохранить управляемость машиной, привычный интерфейс (кто хочет учить netgraph?) и возможность знающему сотворить что-то, не укладывающееся в шаблоны

Делаем несколько наборов правил, каждый — как узел netgraph, и человеческий интерфейс (кто хочет — прицепит узлы нестандартным образом сам)

Page 36: Nuclight Ipfw Rootconf2009

Интерфейс?ipfw chain mychain create [default-policy {allow | deny}]

ipfw chain mychain add 200 ...ipfw chain mychain delete 300ipfw chain mychain destroyipfw bind mychain to interface em0 direction out

ipfw pfil-order move ipfilter last

Page 37: Nuclight Ipfw Rootconf2009

Влечет за собой другие изменения• Меняем API/ABI — setsockopt() требует правки других

файлов ядра при значительных изменениях типа таблиц; сообщения netgraph же легко расширяемы и естественным образом адресуются конкретному набору правил (узлу)

• Переведем на это же dummynet и введем в юзерлэнде модульную структуру парсера

• Динамические правила: серьезная переработка (единственный номер родительского правила недостаточен), нет интерфейса управлением соединением

Page 38: Nuclight Ipfw Rootconf2009

Пока мы здесь, надо это перетрясти хорошенько и в других местах

Модули: более удобный к ним и netgraph интерфейс, кейворды ngcall/ngmatch, вызов наборов правил из других наборов правил

• ipfw ng_bpf mygreaddr create• ipfw ng_bpf mygreaddr config `cpp -P tcpdump-gre-addr-cpp`

• ipfw add deny ngmatch mygreaddr

Page 39: Nuclight Ipfw Rootconf2009

Похоже на BPF?Возьмем еще больше от BPF!• Введем регистры как аналог M[]: хранение

информации о пакете, о динамическом соединении, tablearg будет аналогом аккумулятора A

• Вычисления над регистрами и данными пакета

Page 40: Nuclight Ipfw Rootconf2009

И пристыкуем• Динамические правила — собственный небольшой

массив опкодов, использование регистров, вычислений– Хотите каждые 10 секунд медленно уменьшать

пакетам соединения TTL, а потом обратно? Без проблем!

• Дополнительные обработчики соединений• Операции над таблицами

Page 41: Nuclight Ipfw Rootconf2009

Что еще?• Наборы портов: add deny src-ip table(1) src-

port portset(1) dst-port portset(tablearg) …• API/ABI для изменения состояния

динамических правил из netgraph и не только– отслеживание соединений– возможность failover в carp(4)

Page 42: Nuclight Ipfw Rootconf2009

Более мелкие изменения• Расширим tablearg до uint64_t, таблицы для хранения

MAC-адресов, Ipv6• Действия call/return внутри одного набора правил• Операции над счетчиками и их проверка• Быстрое сохранение/загрузка правил в бинарном виде• Разворачивание и сворачивание типичных конструкций

алиасами в парсере (reply-to?)• Ваши предложения? :-)

Page 43: Nuclight Ipfw Rootconf2009

Планы на будущее• Можно уйти от ориентации на правила и

сделать плоскую структуру опкодов, с оптимизатором в парсере– Позволит сделать описание конфигов на другом

языке, по типу BSD/OS или Juniper– Проблемы со счетчиками, логами– Позволит сделать компиляцию в машинный код

аналогично BPF JIT в 7.x

Page 44: Nuclight Ipfw Rootconf2009

Если пофантазировать...• Сделать ipfw узлом netgraph когда-то было

фантастической идеей, из перечня его авторов• Можно пойти дальше, перевести на netgraph и

другие части сетевого стека, создать расширяемый визуальный конфигуратор сетевой системы в едином стиле

Page 45: Nuclight Ipfw Rootconf2009

Идеи носятся в воздухеСовсем недавно команда разработчиков Netfilter обнародовала

сообщение о выпуске первой альфы нового файрвола для Linux, грядущего на замену iptables.

include "ipv4-filter"chain filter output { ct state established,related accept tcp dport 22 accept counter drop}

Page 46: Nuclight Ipfw Rootconf2009

Чем оно отличается?• Таблицы реализованы как хэши и RB-деревья прямо

в наборе правил– нет возможности адресовать таблицу как

отдельную сущность• Требование декомпиляции ограничивает

возможности по оптимизации• Отсутствие обратной совместимости• Фиксированные точки входа — не netgraph

Page 47: Nuclight Ipfw Rootconf2009

Спасибо за внимание!