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).

Date: 2014-12-13 11:54 (UTC)
From: [identity profile] dadv.livejournal.com
Не интересовался, скажем так.

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