Казалось бы, переход с 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, а не убийство пакета с занесением акта осмотра тела в лог.