On 09.12.2014 15:39, Anton Sayetsky wrote:
> 8 декабря 2014 г., 18:43 пользователь Eugene Grosbein
> <eu...@grosbein.net> написал:
>> On Mon, Dec 08, 2014 at 06:03:36PM +0200, Anton Sayetsky wrote:
>>> Вообще задача следующая:
>>> Есть сервак, на внешнем интерфейсе которого поднят IPSec (cryptomap
>>> 172.31.249.0/24=>192.168.137.0/24).
>>> Есть несколько tun/tap, с которых приходят различные сети.
>>> (192.168.90.0/24, 172.17.5.0/24 и т.п.)
>>> Вот и нужно из всех tun/tap отнатить в 172.31.249.0/24, чтобы дальше
>>> трафик ушёл на 192.168.137.0/24
>>> ipfw nat не работает, трафик натится правильно, но не заходит в SPD IPSec.
>>>
>>> Правила вида:
>>> ipfw nat 1 config ip 172.31.249.1
>>> ipfw add nat 1 ip from any to any via tun1
>>> Дают мне траф вида 172.31.249.1=>192.168.137.2 на re0, а должно
>>> паковаться в ESP.
>>
>> Неплохо бы о применении IPSEC в схеме упоминать в первом письме,
>> а не к концу обсуждения. Потому как пакет на выходе из роутера
>> сначала поступает на обработку в IPSEC, а только потом идёт
>> через пакетные фильтры (ipfw) и выйдя из NAT, уже в IPSEC
>> не направляется. И неважно, ipfw nat это, natd или pf.
> Т.е. ipfw nat работать не будет принципиально? ipsec.filtertunnel может 
> помочь?

filtertunnel может помочь в трансляции входящих пакетов, но его недостаточно
для трансляции исходящих.

Сделал патч на ядерную часть 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.

Трансляция для пакетов, не имеющих таких тегов, выполняется как на непатченной
системе. Для пакетов, имеющих теги, эти теги при трансляции снимаются.

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

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

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

Не забываем, что при sysctl net.inet.ip.fw.one_pass=1 оттранслированные
на входе пакеты не идут дальше по правилам ipfw.

Прикладывать патч:

cd /usr/src && patch < /path/to/patch

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

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

Ответить