null

pf: в чужой монастырь со своим уставом

Казалось бы, переход с ipfilter на pf должен вызывать только положительные эмоции. Ведь pf такой хороший, и макросы в нём есть, и группировать адреса/порты/интерфейсы можно, и таблицы есть, и специальное правило antispoof присутствует. Но ведь что-то должно омрачить радость перехода?

Но... Для сначала немного истории. В виду того, что для Solaris 10 выбор бесплатных firewall-ов в общем-то ограничивается великим и ужасным ipfilter, то выбора к чему привыкать не остаётся.  При этом встроенный в Solaris 10 ipfilter протух еще в далёком 2005 году и с тех времён не обновлялся и обладает замечательным набором глюков, типа неработающего block return-rst и периодически теряющихся ответов на ICMP echo request. Но мы ведь не ищем лёгких путей, поэтому встроенный ipfilter подвергаелся pkgrm, на его место ставился скомпилированный руками, исправляя одни глюки и добавляя другие. Как ни странно, но осуществление заката солнца вручную иногда надоедает, поэтому решили попробовать использовать на пограничной системе FreeBSD/sparc64 и, заодно, перейти с ipfilter на pf.

После того, как все конфиги были написаны, а демоны посажены в персональные камеры, всплыл неочевидный глюк. Пользователь, подключившийся по VPN к серверу, в точности с правилами pf имел доступ к серверу по всем адресам интерфейсов оного, а вот попытка обратиться к системам, стоящим во внутренней сети организации, или наоборот заканчивалась получением ICMP Host Unreachable. Смотрим в /etc/pf.conf и видим на эту тему примерно следующее:

pass in on { tun0, bge0 } from 192.168/16 to 192.168/16

Казалось бы по аналогии с правилом ipfilter вида:

pass in on tun0 from 192.168/16 to 192.168/16 keep state

всё должно быть хорошо. При этом стоящее рядом правило:

pass in on bge0 proto tcp from bge0:network to any port 5222

замечательно работает. Более того, все block правила прописаны с модификатором log, а в выводе команды tcpdump -nr /var/log/pflog отсутствуют связанные с проблемой отвергнутые пакеты, что как бы намекает на то, что проблема не в firewall.

Однако интернет по ключевым словам openvpn icmp host unreachable упорно настаивает на том, что надо проверять свои правила firewall. После продолжительных танцев с бубном решаюсь и приведённому правилу дописать еще и симметричное ему pass out. И.. О чудо! Всё заработало.

Оказалось, что привычка к ipfilter сыграла со мной злую шутку. Во-первых, ipfilter требует указания направления пакета in или out. Во-вторых, в ipfilter при наличии keep state для in правил достаточно для того, чтобы пакет смог выйти через какой либо интерфейс, тогда как в pf необходимо разрешение и этого направления. В-третьих, судя по всему, в ipfilter для исходящего пакета сначала обрабатываются правила firewall, а потом уже nat, а для pf - наоборот.

Поэтому соединения на порт 5222 во внешний мир на входе попадали под правило, потом осуществлялась трансляция, а потом они попадали под правило, разрешающее исходящие соединения с адресов сервера. А вот для "внутренних" пакетов никакой трансляции не происходило и ни под какие out правила они не попадали.

Таким образом из правила достаточно было убрать ключевое слово in, и оно должно было звучать так:

pass on { tun0, bge0 } from 192.168/16 to 192.168/16

Правда всё равно не понятно, почему не смотря на стоящее по умолчанию block log all, я получал host unreachable, а не убийство пакета с занесением акта осмотра тела в лог.

Коротко о себе:

Работаю в компании Tune-IT и тьютором кафедры Вычислительной техники в СПбГУИТМО.

Очень люблю команду cat, core solaris и IPv6.