dadv: (chuck)
[personal profile] dadv


При совмещении на одном маршрутизаторе функций NAT и IPSEC gateway администратор FreeBSD сталкивается с проблемой: для транзитного трафика на выходе из маршрутизатора сначала выполняется IPSEC-обработка и только потом пропуск трафика через пакетные фильтры. Поэтому невозможно сначала выполнить трансляцию (NAT), а затем зашифровать результат - после NAT трафик в IPSEC уже не направляется, и неважно, чем именно делается NAT: ipfw nat, pf, natd.

Решением для ipfw divert/natd является перенос трансляции трафика, идущего изнутри наружу, с традиционного второго прохода по списку правил ipfw, выполняемого после routing lookup, на первый проход. При этом в конфигурации natd вместо имени внешнего интерфейса нужно задавать непосредственно внешний alias_address и вместо единого divert socket для входящего/исходящего трафика использовать два отдельных сокета, указывая их ключами -in_port и -out_port. Входящий трафик из мира в локальную сеть, как и прежде, направляется в natd на входе через внешний интерфейс в in_port, а вот исходящий нужно направлять в out_port на входе в маршрутизатор через локальный интерфейс, а не на выходе через внешний.

Этим достигается требуемый результат: исходящий трафик из локальной сети транслируется на первом проходе по списку правил ipfw до routing lookup, а шифрование оттранслированных пакетов средствами IPSEC выполняется позже, после routing lookup.

К сожалению, реализовать то же самое средствами ipfw nat невозможно, так как аналога in_port/out_port у него нет ни в одной версии FreeBSD, включая 10.1 и текущую 11-CURRENT.

Сделал патч на ядерную часть ipfw nat для поддержки этой функциональности, что была в natd: патч позволяет явно задавать направление трансляции пакетов (in->out или out->in). Сейчас ipfw nat определяет это направление только автоматически: если пакет проходит по списку правил ipfw первый раз, на входе в маршрутизатор, он считается входящим и транслируется только как out->in. Если пакет проходит по правилам ipfw повторно и после выполнения routing lookup (на выходе и уже имеет атрибут xmit interface), то он транслируется только как in->out.

Патч http://www.grosbein.net/freebsd/patches/ip_fw_nat.c.diff не меняет это поведение по умолчанию: патченная система работает так же. Однако, патч вводит два новых sysctl с дефолтными нулевыми значениям:

net.inet.ip.fw.nat_tag_in
net.inet.ip.fw.nat_tag_out

Если пакет, попавший в правило ipfw nat, имеет прикрепленный тег с номером, равным ненулевому значению sysctl net.inet.ip.fw.nat_tag_out, он безусловно транслируется по схеме in->out, даже если обрабатывается на входе в маршрутизатор.

Аналогично, если пакет имеет тег, равный ненулевому net.inet.ip.fw.nat_tag_in, он транслируется как входящий снаружи по схеме out->in. Трансляция для пакетов, не имеющих таких тегов, выполняется как на непатченной системе. Для пакетов, имеющих теги, эти теги при трансляции снимаются (снимаются не все теги, а только равные nat_tag_in/nat_tag_out).

Теперь для решения исходной задачи можно задать sysctl net.inet.ip.fw.nat_tag_out=10 и заменить одно правило вида ipfw add nat 123 ip from any to any via $ext_if на три:

tag_out=$(sysctl -n net.inet.ip.fw.nat_tag_out)
# Трансляция трафика из мира в локалку
ipfw add 1000 nat 123 ip from any to any in recv $ext_if
# Тегирование пакетов для трансляции из локалки в мир
ipfw add 1010 count tag $tag_out ip from $LAN to not $LAN in recv $int_if
# Трансляция тегированных пакетов на ВХОДЕ в маршрутизатор
ipfw add 1020 nat 123 ip from any to any tagged $tag_out in

Таким образом, добиваемся необходимого эффекта: сначала трансляция исходящего
трафика, затем обработка IPSEC на выходе (между ними routing lookup).

Прикладывать патч: cd /usr/src && patch < /path/to/patch

Затем пересобрать ядро либо только модуль ipfw_nat.ko (модуль ipfw.ko не требуется пересобирать), если используется модуль, а не кастомное ядро с FIREWALL_NAT:

cd /usr/src/sys/modules/ipfw_nat && make obj depend && make all install

Модуль можно затем выгрузить/загрузить на лету, только после этого обязательно сделать service ipfw start, иначе трансляция не заработает.

Патч сделан и проверен на 9.3 (вариант для 8.4: http://www.grosbein.net/freebsd/patches/ip_fw_nat.c.8.diff ). Для других версий, возможно, потребуется незначительная правка.

Update 07.09.2016: обновление патча для 11.0 (для 10.x работает первоначальный вариант от 9.3).

This account has disabled anonymous posting.
(will be screened if not validated)
If you don't have an account you can create one now.
HTML doesn't work in the subject.
More info about formatting

If you are unable to use this captcha for any reason, please contact us by email at support@dreamwidth.org

Profile

dadv: (Default)
Choose your future

July 2024

M T W T F S S
12 34567
891011121314
15161718192021
22232425262728
293031    

Tags

Style Credit

Powered by Dreamwidth Studios