Kernel NAT во FreeBSD

Купил я себе новый HDD: WD GreenPower, емкостью 1 TB. Цель покупки — файло/медиапомойка. Организация любой помойки, при условии анлимного канала и аккаунта на torrents.ru — дело пустяковое. Через некоторое время активного использования торента (больше 20 раздач со скоростью > 1 Mb) начал замечать такую картину:
# top | grep natd
42549 root 1 45 0 9408K 2856K select 0:01 7.78% natd

# uname -a

FreeBSD fire.data.local 8.2-RELEASE-p4 FreeBSD 8.2-RELEASE-p4 #0: Mon Dec 26 13:04:26 NOVT 2011 ark@fire.data.local:/usr/obj/usr/src/sys/mykernel i386


Мало того, что natd светит адреса внутренних хостов, так он еще нехило потребляет системные ресурсы. Решено было переходить на «ядерный» нат. Добавляем в конфиг ядра опции для поддержки ipfw и ipfw nat:


options IPFIREWALL #
Обязателен
options IPFIREWALL_FORWARD
options IPFIREWALL_VERBOSE
options IPFIREWALL_VERBOSE_LIMIT=100
options IPFIREWALL_NAT
# Обязателен
options LIBALIAS
# Обязателен
options IPDIVERT
options DUMMYNET



Далее:


# cd /usr/src
# make kernel KERNKONF=mykernel


Пока пересобирается и устанавливается новое ядро можно сходить покурить или посидеть отдохнуть попить чай с жасмином


Ребутимся и редактируем скрипт ipfw. Коментим те строки, где были правила divert и заменяем на правила ipfw nat:

ipfw.conf
nat 1 config ip 95.150.164.212 log same_ports unreg_only
add nat 1 all from 192.168.100.13 to any # DRO
add nat 1 all from 192.168.100.24 to any # ARK
add nat 1 all from 192.168.100.38 to any # PAN
add nat 1 all from 192.168.100.59 to any # ALEX
add nat 1 all from 192.168.100.208 to any # SQUID
add nat 1 all from 192.168.100.
0/24 to any # Это правило для тех случаев если надо выпустить в инет сразу всю сеть
add nat 1 all from any to 95.150.164.212


где 95.150.164.212 — интерфейс смотрящий «наружу»,

${lan_net} — внутренняя сеть (192.168.100.0/24)

${inet_ip} — внешняя пиха. unreg_only говорит ipfw натить только частные сети same_ports пытается оставлять те же номера портов


rc.conf

gateway_enable="YES"
firewall_enable="YES"
firewall_nat_enable="YES"
firewall_type="/etc/se/ipfw.conf"
firewall_logging="YES"
firewall_nat_interface="fxp0"
# Внешний сетевой интерфейс
dummynet_enable="YES"


Дальше комментируем все строки связанные с natd в /etc/rc.conf и перегружаем правила ipfw. Проверяем работу kernel nat и наслаждаемся всеми его преимуществами.

P.S. Для того, чтобы пробросить порт внутрь локальной сети, конфигурация ipfw nat должна выглядеть так:


nat 1 config ip 95.150.164.212 unreg_only same_ports log redirect_port tcp 192.168.
100.17:80 80
add nat 1 all from 192.168.
100.17 to any
add nat 1 all from any to 95.150.164.212



Это будет означать что мы прокидываем все входящие tcp пакеты адресованные 80 порту на внешнем IP на 80 порт машины с адресом 192.168.
100.17

P.S

Можно конечно поиграться еще с опциями в /etc/sysctl.conf

#net.inet.ip.fw.one_pass=0
net.inet.ip.fw.one_pass=1
net.inet.ip.fastforwarding=1
net.inet.tcp.maxtcptw=40960
kern.ipc.somaxconn=4096
kern.ipc.nmbclusters=65536
net.inet.tcp.nolocaltimewait=1
net.inet.ip.portrange.randomized=0

Да кстати на просторах инета валяются мануалы где рекомендуют при сборке ядра использовать пареметр в make.conf

CFLAGS+= -DIPFIREWALL_NAT

на кой это надо так и остается загадкой

На основе http://yaroslav.berezhinskiy.name/2009/11/freebsd-kernel-nat/

Обновлено: 12.03.2015