UNИX, весна 2009, 03 лекция (от 11 марта)
Материал из eSyr's wiki.
- Диктофонная запись: http://esyr.org/lections/audio/uneex_2009_summer/uneex_09_03_11.ogg
Лектор в этот раз не будет рассказывать про iptables. Лектор расскажет про ipfw. По причине того, что очень многие понятия, присущие фаерволлу вообще, гораздо проще рассматривать на примере линейных структур, а не на примере древовидных структур типа iptables. К тому же, некоторая специфика реализации, присущая фаерволлам, что можно сделать на самом деле не всё, зашита достаточно глубоко, в отличие от iptables, где на это натыкаешься сразу.
Чтобы было понятно, о чём идёт речь. Само название довольно старое, так как функция, ip firewall, была реализована ещё в FreeBSD 2.2 или около того, что касается реализации, во FreeBSD она является самой старой. Правда, он обладал недостатками, и в какой-то момент во FreeBSD из, кажется, OpenBSD пришел другой вариант, под названием ipf. Потом в 2002 году появилось сразу два новшества, а именно:
- ipfw был дополнен большим количеством функций и стал называться ipfw2
- был спортирован из openbsd pf.
Так что линейчатых фаерволлов только три штуки. Самый крутой это pf, но ipfw2 тоже достаточно крутой.
Лектор немного будет подглядывать в бумажку.
ipfw имеет строго линейатую структуру. Это список правил, которые применяются к пакету, проходящему через TCP/IP стек, причём сразу в нескольких местах. В мане по ipfw эта картинка есть в ascii-art. Есть как минимум два случая, когда нужно обрабатывать пакеты: входящие и исходящие. В первом случае — непосредственно когда вошёл в интерфейс, во втором — перед выходом из него. Картинка примерно следующая:
К ipfw приходит пакет, возможно из верхних уровней, например, из tcp, но его это не касается. Это не значит, что с tcp ipfw не работает, эта информация всё равно есть внутри пакета. Ещё есть уровень eth. Можно включить у себя в фаероволле опцию bridge, и тогда появится пятое действие, собственно bridge. Вот на всех этих 5 участках ipfw работает. Чаще всего используется ip уровень, интерфейсный уровень обычно используется bridge.
В чём при этом хитрость линейного фарволла: все эти пакеты ставятся на все очереди правил, в не зависимости от того, какие это пакеты. С точки зрения польз. выглядит, что он проходит по всем областям. Если нельзя выковырять информацию (например, на ip-уровне нельзя получить инф. о mac), то правило не сработает, но если включили уровень соотв., то сработает.
Правила линейны, но чем-то похожи на программу на бейские, поскольку у правила есть свой номер, от 1 до 65535, и принято при ручном задании делать шаг 100. Одно из правил всегда пробито, это 65535, в зависимости от того, с какими параметрами собрано ядро (всё убивать или всё принимать), то и правило будет всё пропускать или убивать. Почему так: поскольку в ipfw действует правило 1st wins, и если ни одно из правил не смогло примениться, то применяется последнее.
Примерный упрощённый вид правил:
[номер] [действие] [тело]
Тело — обычная фильтрация, но это не всегда так. Например, пометка пакетов, проверка на присутствие в таблицах и так далее, так что нельзя с точностью определить, что делается в последней части. Если в случае iptables это цепочка-условие-действие, то ipfw это штука монолитная. Что мы можен делать с пакетами, проходящими через ipfw:
- allow
- drop
- reject
- fwd
Эти правила приводят к тому, что пакет так или иначе куда-то там девается. Либо он проходит, либо не проходит, либо перенаправляется на другой адрес.
Что касается allow, то всё очевидно. Тело будет условием на пакет, и означает следующие: если данное правило — первое, где условие совпадает со свойствами пакета, если его к тому моменту модифицировали, то значит так.
Про условие поговорим чуть позже, а пока посмотрим на два других правила, drop и reject:
Что касается drop, то пакет просто исчезает, вот пришёл он и исчез. Чем это плохо: если мы честные люди, то если мы не хотим, чтобы он был доставлен, то надо отвечать по icmp какое-то умное слово, например, host unreachable. И если пользователь будет ломиться к нам, особенно по udp, где нета обратной связи, то он даже не узнает, дошли пакеты или не дошли.
В случае reject будет сгенерирован icmp-пакет host unreachable. ( Внимание, reject (Deprecated). Synonym for unreach host, поэтому лучше не использовать reject, а использовать unreach host). Чем то правило плохо: если вы защищаетесь от flood-атак, то ответов флудеру слать не надо.
Относительно fwd: fwd <куда>. При этом пакет не меняется, и действует на выходе, указывая в сопроводительной информации, куда должен быть отправлен пакет. Если машина не настроена на получение пакетов для чужих ip, то она его просто выбросит. Зачем это нужно: например, на той машине висит демон, который все пакеты принимает и журнализирует.
Пример:
65535 deny ip form any to any # ip form any to any — тело
Достаточно понятный формат, не изучая досколнально все правила, можно понять, что выбрю все пакеты. Можно добавить правила:
100 allow ip from any to any via lo0
lo0, если кто не знает, интерфейс loopback в bsd. В bsd интерфейсы называются не eth, а по имени драйвера, такое legacy. Если учесть, что там одним из первых появилось переименование интерфейсом, ноо не мешает.
Что означает это правило: ктобы что бы не собирался послать что через lo, пусть шлёт. Но у лектора есть пример, когда человек режет пакеты на 127.0.0.0/8:
200 deny all from any to 127.0.0.0/8
То есть, всё остальное надо убить.
Пример с fwd лектор приводить не будет, это довольно редкая штука, но она полезна, с той разницей, что та машина, куда fwd, не должна из пугаться.
В принципе, слово ip лишь синоним для all. Можно писать ip6 или ip4, но на уровне ipfw предп., что мы оперирруем пакетами именно такого сорта.
Разумеется, вместо any можно написать любой адрес или сеть, а также me. Довольно удобно, когда интерфейсов много и разных.
В случае, когда мы оперируем пакетами подобным родом, выбор у нас довольно небольшой, указать тип пакета, откуда и куда.
Помимо тех действий, которые лектор рассказал, может быть что ещё.
Про NAT. В ipfw2 появилась встроенная поддержка nat, но лектор никогда ею не пользовался. Лектор лучше расскажет, как был устроен nat изначально. Как лектор говорил на предыдущей лекции, nat делался в юзерспейсе. ( Многие до сих пор думают, что все работает через natd и реализуют nat с помощью pf. Однако в 2005 году на google summer of code для ipfw была написана реализация nat на уровне ядра, как написать правила можно посмотреть в мане ) В bsd есть такие divert sockets, которые позволяют иметь сокет из ядра в юзерспейс. Как это реализуется:
{divert tee } <port>
То есть, мы пренаправляем пакет в указанный divert-сокет. При этом в userspace должна быть запущена некая программа, которая слушает его, и оттуда стандартными командами (recvfrom) будет читать. Она эти пакеты обрабатывает, и потом стандартными командами (sendto). Что она с ними делает - это её личная проблема. В результате пакет попадает сразу за правилом и обр. дальше.
В отличие от бейсика, можно иметь несколько правил за одним номером, чтобы можно было удалять блоками. Идея в чём: если таких правил много, то они, даже те, которые идут под одним и тем же номером, и пакет будет обр. след. правилом в таблице.
Зачем нужен divert сокет? Чтобы делать с пакетами что угодно, не занимаясь написанием ядерного модуля. Кстати сказать, если на сокете никто не сидит, то пакет просто пропадает. Кроме того, эта команда асинхронная: фаерволл работает дальше, в это время юзерспейс-программа прочухается, что-то запишет обратно и тогда дальше обр. этот пакет.
Чем отл. divert от tee: divert просто перенаправляет, а tee его раздваивает.
В станд. поставке лектор обнаружил ровно один демон, natd, и догадайтесь что он делает. natd - это просто юзерспейс-программа, у него в районе 2 десятков ключей, делает всё, что полагается нату, может натить на входе, на выходе.
По всей видимости, это направление развилось бы и дальше, поск. если мы хотим произвольным обр. пакеты, ... например, присобачить netgraph, даже action есть:
netgraph <надпись>
Исп. divert и netgrapha отл. тем, что netgraph работает очень быстро.
Помимо netgraph есть ещё ngtee.
Правило типа count это понятно что. Довольно забавно: у каждого такого правила есть счётчик, сколько оно применялось, это особенно полезно, чтобы посмотреть, применялось оно или нет. И count ничего не делает, только считает.
Очень важная вещь, это правило checkstate...
Очень страшная вещь: правило skipto <номер>. Это goto, как в настоящем бейсике. Поск. табличка линейчатая, то нужно делать переходы, можно, например, делать переходы назад, тогда он не вылезет из kernelspace и зависнет к чертям. Но без этой штуки обойтись нельзя, поск. пакеты, прох. через эти 5 точек, обр. ровно этим списком. Есть флаги, которые позв. фильтровать, и иногда удобно проверить флаги и сделать skipto.
Чего лектор не сказал: как работать с stateful firewall. Очень часто, особенно из сообр. быстродействия полезно делать вот что: мы наш пакет прогнали по всему своду правил, и в какой-то момент приняли решение, что этот пакет и все подобного класса надо пропускать, например, если уст. tcp-соединение, то надо все его пакеты пропускать. Как это делается: есть правило checkstate, у которого нет параметров. Правило типа check-state приводит к тому, что все пакеты, дошедшие досюда, проверяются частью фаерволла, хранящей состояние.
500 check-state
почему это делается не сразу: поскольку проверка сост. это довольно тяжёлая процедура, и если можно отфильтровать пакет без неё, то лучше это сделать.
правило checkstate делает ещё одну вещь: ещё при этом проверяются пресловутые состояния, то есть,. если у вас пакет принадл. потоку данных, у которого сохр. состояние, то это правило будет ему применено. Как правило, это allow.
510 deny all from any to any astablished 520 allow tcp from any to any ...
Stateful firewall устроен след. образом: есть флаг keep state, который запоминает состояние, что такой уже пропускали. Это сост. проверяется checkstate, и если среди этих сост. есть такое правило, то оно применяется, в противном случае он проваливается дальше.
stateful firewall это способ его убыстрить сильно, одной командой проверить, не имеет ли данный пакет отношения к таким, которые мы уже проверяли.
Общая идея состоит в том, что мы допускаем пакеты типа setup, то есть начала tcp-сессий, после чего говорим сохр. сост., после чего говорим, что бы такие пакеты проходили.
Что касается огр. трафика: есть каманда pipe, queue. Чтобы оно работало, нужно, чтобы в ядро был вкопилирован модуль ..., это такой эмулятор сети. Идея том, чтобы прежде, чем пакет отсылать, оно сначала засовывается в трубу с соотв. номером, труба с точки зрения польз. предст. собой некий конвейер, у которого опр. пропуск. способность, кроме того, у него есть другие параметры: опр. процент потери пакетов, длина очереди и так далее. У queue такого нет, зато есть разные политики.
Трубы, например, используются для борьбы с любителями осла, как только такой человек находится (по количеству одновр. соед. на извращ. порт), то он добавл. в блок адресов, которые пользуются одной довольно жёсткой трубой.
Можно делать дерево труб и так далее. Там есть ещё qos.
Относительно флагов. Мы помним из прошлого раза, что основной способ работы фаерволла состоит в том, что при прохождении через стек пакеты снабжаются разнообр. инф., и фаерволл на основании её решает, что с ним делать. Можно перед действием вставить tag #, это аналог -j MARK iptables, тегов может быть не более 65534 (0 и 1 заняты), и если у пакета есть тег, то можно с ним сделать что-то. теги не отклеиваются, когда он отправляется в divert socket, то теги с него снимаются, поск. это искл. kernel-space штука, а пока он ходит по ядру, они на нём висят.
Вкусности: можно указать вероятность применения правила.
Вопрос: откуда берётся энтропия?
Ответ: вероятно, исп. не /dev/urandom, а что-то более простое.
Ещё у каждого фаерволла можно указать set #, и можно выключать и включать правила блоками. После его упр. ими по крону, эмулируя два режима, например, дневной и ночной.
Какие флаги: помимо типа, откуда и куда, может быть большой список разных флагов — дополн. св-в пакета:
- Если это исх. пакет, то можно затребовать uid, pid, gid и прочая (только в ipfw2)
- Если пакет ходил через divert, ходил через bridge, получил таг, то можно всё это проверить (diverted и так далее)
- Фрагментированые пакеты
- Есть in и out
- Во freebsd есть простая вирт. под названием jail, чтобы запустить процесс в изолированном файл. пространстве и ipc. Если пакет пришёл из jail, то можно узнать из какого. Ближайший аналог в линукс — vserver(?)
В общем, тут чёрте сколько флагов, можно указывать виды icmp-трафик.
Могут быть счётчики, напр. правило применяется не более чем столько-то раз, это актуально для stateful firewall-ов.
В ipfw2 есть также встроенный nat.
Чтобы закончить эту лекцию, что есть для поддержки со стороны юзерспейса: есть утилита ipfw, которая позв. делать всё, о чём говорили, из ком. строки. В rc-скриптах есть скрипты по запуску фаерволла, там указ. типа фаерволла, который пропис. правила по умолчанию и куда можно указ. путь к скрипту.
ipfw нужен не только для настр. правил, но и для настр. пайпов, очередей. В ipfw2 можно настр. таблицы адресов. Можно отдельно задать таблицу ip-адресов и исп. её в кач. адреса. Этим занимается ipfw table.
Чтобы закончить, лектор скажет так: ещё один способ. исп. set-ов след: заводите два сета, текущее и новое. Текущая табл. включена, новая выключена. Но когда работает ipfw, то он обр. все правила. В таком случае можно проверить неск. раз правила, как минимум на синтаксис, и только после этого сказать ipfw set swap.
В след раз про check-state, nat и очереди.
Конспект Kda
Рассказа про iptables не будет. Рассказ будет про ipfw. Даже не одна лекция, а несколько. Очень многие понятия, присущие фарйволу вообще, проще рассматривать не на примере древовидных структур вроде iptables. Некоторая специфика реализации внутри ipfw зашита глубоко, и очень долго кажется, что сделать можно все. В случае iptables это не так.
Чтобы было понятно, о чем идет речь. Само название довольно старое, в том смысле, что функциональность была реализована еще во второй версии freebsd. Он обладал некоторыми недостатками по сравнению с толстыми файрволами. Был портирован другой вариант файрвола ipf. В 2002 появились сразу два новых. ipfw стал ipfw2. Пакет ipfilter. Если не считать других вещей вроде нетграфа, файрволов 3 штуки. Каждый предполагал покрывать функциональность предыдущих. Но ipfw2 тоже весьма развесистая штука.
Файрвол имеет строгий список правил, которые применяются к пакету, проходящему через tcp/ip стек, причем сразу в нескольких местах. Давайте нарисуем картинку. В мане по ipfw эта картинка есть в аски-арте. Есть два случая, когда нужно отрабатывать пакеты, исходящие и входящие. Одни обрабатываются, когда пакет вошел, другие — перед выходом из интерфейса. Приняли все решения относительно судьбы пакета.
Есть входящий и исходящий поток — ip_in, ip_out. Вполне возможно, что пакет пройдет на более высокий уровень (транспортный, прикладной). С более высокими уровнями тоже возможно работать. Существует еще ethernet уровень. На вход eth_demix, на выход eth_outp. Можно включить в ядре опцию bridge, тогда появится еще пятый элемент — собственно bridge. Интерфейсный уровень работает обычно с bridge.
В чем хитрость линейного файрвола? На каждом этапе ставится обработка по всей очереди правил, которые сформулированы на этот счет. Пакет проходит область и прощелкивается в соответствии с правилами файрвола.
Общий формат правил достаточно сложный. Правила линейчатые и программа немного похожа на программу на бейсике — есть номера строк. Есть правило делать шаг 100 — в бейсике шаг 10, а в ipfw шаг 100. При этом одно из правил всегда пробито — 65535, в зависимости от параметров компиляции файрвола. Частая практика — перекомпиляция ядра с разными ключами. Либо всех выпустить, либо всех впустить. Список правил организован по принципу first wins. Если правил нет, или ни одно не сработало, применяется общее правило — всех убить или всех пропустить.
Примерный вид правила. Номер, действие, тело. Правило может выполнять различные действия. Помимо фильтрации могут быть другие действия — например, пометка пакета. Проверка внутренних таблиц. С момента выполнения действия пакеты проверяются на таблицы. Нельзя определить точно, что есть последняя часть. Цепочка — действие и условие (ранее рассмотрено). Тело нельзя называть условием, там много разного.
Самое популярное действие — allow, drop, reject, fwd. Что касается allow — тело будет условием. Если при прохождении правил это было первое совпавшее, то пакет просто пропускается. Если он модифицирован или что-то произошло, значит да. Давайте посмотрим на drop и reject. Что касается правила drop, то пакет, попавший под него, просто исчезает. Чем это плохо? Это плохо тем, что если мы честные люди, то пакет, который мы не хотим, чтобы он был доставлен, нужно ответить по ICMP хотя бы unreachable. Если пользователь запустил программу, ломящуюся по UDP, то если написано drop, то он не будет знать, что они не дошли и завалит пакетами.
Если же reject, то будет сгенерировано unreachable. ICMP пакет будет отправлен отправителю. Если мы защищаемся от атак, то ответов слать не нужно, потому что он плевать хотел на них, а кроме того, они будут загружать нашу сеть.
fwd. На выходные пакеты. Относительно них принято решение о маршрутизации. fwd это решение меняет. Оно меняет и пробивает next hop на тот, который мы напишем. Если машина не настроена на прием пакетов с чужими ip, то она выбросит пакет. Не обязательно пользоваться для этого более глубинными инструментами. Пакет не модифицируется. Это бывает нужно: висит демон, который все пакеты принимает и журнализирует.
65535 deny ip from any to any
Все, что после deny — тело. Это правило выбрасывает все отовсюду.
100 allow ip from any to any via lo0
lo0 — loopback
Если будем интересоваться, то в freebsd называются интерфейсы по драйверам, а не eth*. Потом появилось переименование интерфейсов.
Что делает правило? Кто бы что не пытался пропустить через loopback, пускай шлет. Есть пример, когда пришедшие пакеты на 127.0.0.1 человек режет. Если пакет через loopback изнутри, нормально, а вот если снаружи (с нашим маком, но с таким ip — глупая хакерская атака).
200 deny all from any to 127.0.0.0/8
Это будет работать, потому что в нормальном режиме до 200 анализатор не дойдет. Редирект ip нужно сделать так, чтобы принимающая машина нормально приняла пакет с чужим ip. В принципе слово ip — синоним для all. Можно написать ip4. На уровне ipfw мы манипулируем такими пакетами. Можно написать me — любой их моих адресов, loopback, адреса сетевых карт. Если речь идет о манипуляции пакетами, то выбор не очень большой. Пишем тип, откуда, куда, опционально флаги.
NAT — в ipfw не было. Как изначально был сделан NAT в FreeBSD. NAT делался в userspace. Divert socket. К нему можно забиндиться, но если указать адрес, он проигнорируется. {divert tee} <ropt> Перенаправляем в сокет пришедший пакет. IP-адрес в таком сокете игнорируется. В userspace запущена программа, которая биндится к сокету, слушает его. Читает командой receive. Делает все, что хочет с полученными пакетами, как-то их обрабатывает. С помощью стандартных команд пишет обратно.
Возможно несколько правил с одним номером для атомарности — удаление всех правил с одним номером. Правила под одним номером идут в нужном порядке в таблице. Можно делать что угодно с пакетами, не заморачиваясь написанием ядерного модуля. Ядерный модуль писать сложнее userspace программы. Если не забинден сокет, пакет исчезает, ничего плохого не происходит. Мы записали в сокет, файрволинг идет своим чередом. Программа прочухивается, пишет обратно. Пакет возникает. divert — пакет уйдет и удалится, а если tee — пойдет в обе стороны. Может быть журнализатор на стороне сокета, а пакет будет обрабатываться дальше. natd — догадайтесь, что он делает. Слушает сокеты, вынимает пакеты, умеет все, что должен делать nat. Он разбирается, в какую сторону натить. Может быть запущен в режиме входного и выходного ната.
Если мы хотим произвольным образом обрабатывать пакеты, мы можем написать референс, а потом для ускорения сделать netgraph. Можно написать что-нибудь на пакете для сведения нетграфа. netgraph <Надпись> Нетграф работает очень быстро. Передача через divert работает достаточно долго. Понадобился нормальный kernelspace NAT. Пока интерфейсы были 10 мегабит, проблем не было. Довольно забавно — у каждого правила есть счетчик, сколько раз оно применялось. Можно ничего не делать, только считать. Помимо netgraph есть еще ngtee (то же самое, только шлет дальше).
skipto <номер> Нужно обеспечить возможность применять куски правил в зависимости от условий. Можно уйти назад, даже завесить намертво (не выйдет из kernelspace никогда). Тем не менее, без этой штуки обойтись нельзя. Все пакеты, проходящие через эти пять точек обрабатываются списком правил. Есть флаги, которые позволяют определять фильтр. Здоровенный свод правил, удобно использовать флаги и применять нужные куски правил. Но это сильно усложняет линейную структуру.
Очень часто из соображений быстродействия полезно делать следующее. Прогнали пакет по своду правил и решили допускать его и все его класса. Установление соединения tcp прошло и дальше пускаем все его пакеты. Во-первых, есть правило checkstate. У него нет параметров. Это правило приводит к тому, что все пакеты обрабатываются куском анализа состояний. Почему правило есть? Прогонка по всем состояниям — относительно тяжеловесная процедура, и если возможно принять решение до проверки состояний, лучше это сделать. Включаем это правило. Если пакет принадлежит потоку данных с запомненным состоянием, то запомненное правило будет применено. Рассказ будет продолжен в следующий раз. Есть набор правил и флаг keep-state. Если среди списка состояний есть такое, про которое было применено данное правило, оно будет использовано. Не в таблице дело, а в том, что проверить, что такие пакеты уже пропускались. Это способ убыстрить файрвол, проверив, не относится ли данный пакет к типу уже проверенных. Общая идея в том, что мы допускаем пакеты setup в начале сессии и говорим сохранить состояние.
Ограничение трафика. pipe, queue. Что делают эти команды? Подробнее в следующий раз. Для того, чтобы команда работала, должен быть модуль в ядре. Вместо отсылки пакетов они засовываются в трубу с соответствующим номером. Труба — некий конвейер. У него определенная пропускная способность и другие свойства — процент потери пакетов, длина очереди и пр. Очередь — другой механизм, нет процента потери пакетов, но есть политики обработки очереди. У нас на факультете трубы используются для любителей запускать осла на бесконечно большой скорости и с неограниченным количеством пользователей. У такого пользователя несколько сотен соединений с большим трафиком на специальный ослиный порт. Трафик такого пользователя ограничивается специальным каналом для всех таких людей. Используется труба. Когда количество мест в очереди заканчивается, то пакеты, которым не хватило места, выбрасываются. Передергивается tcp. Очередь — более хитрая.
Основной способ работы файрвола — при прохождении пакеты снабжаются метаинформацией. В частности, при каждом таком пакете можно сделать ipfw на предмет что с ним делать. tag # Приклеить бумажку очередного цвета. Номера от одного до 65534. Мы можем навесить метку и потом указать флаг tagging #, то есть если есть бумажка, сделать что-то. Когда пакет уезжает в divert socket, бумажки снимаются. А так будет таскать на себе.
Мы можем указать вероятность применения правила. Правило будет срабатывать не всегда. Вряд ли оно будет ждать, пока накопится энтропия из /dev/random. Скорее всего, механизм более простой.
Возможность включать и выключать правила целыми блоками. Днем политика одна, а ночью совершенно другая, потому что охранники качают специфические фильмы. Какие интересные флаги есть? Помимо типа откуда и куда, можно, например, затребовать userid. Ограничиваем именно конкретного пользователя. Если с пакетом что-то было — ходил через divert, bridge или еще что-то. Проверяем, что было с пакетом. Флаг in, out. В freebsd есть виртуализация (простая) — jail. Запуск процесса в ограниченном пространстве, файловом и ограниченном ipc. Таблица процессов одна, но они изолированы в jail'ах. Можно проверить, из какого jail пришел пакет. Флагов очень много. Можем указать протокол. Вид ICMP. Правильная настройка файрвола заключается в затыкании ICMP и разрешении большого числа типов ICMP. Ограничение количества применений правила к пакетам. В ipfw2 есть встроенный nat. Про NAT разговор в следующий раз.
Есть ipfw — замечательная утилита. Позволяет делать все это из командной строки. Есть скрипт старта файрвола. Файрвол открытый всем. Разрешить все всем и запретить все всем. Клиентская машина с открытым пингом. Сервер с открытыми 80 портом или другими. ipfw предназначена не только для добавления-удаления правил, но и для настройки пайпов, очередей, таблиц. Таблицы адресов. В ipfw2 таблица адресов. Просмотр по таблице имеет логарфмическую сложность.
Чтобы закончить: еще один способ использования сеток. Два множества правил — текущее и новое. Текущее — действующее. Новая выключена. Когда заводим файрвол, обрабатываются и те правила, и другие. Модифицируем файрвол, новые таблицы и проверяем новые таблицы. Мы ничего не меняем, и ситуация пропадания доступа по ssh в свежеисправленном в файрволе почти исключается. Строим новую таблицу, смотрим, свапаем таблицы.