FreeBSD Kernel NAT

Купил я себе новый 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

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

options         IPFIREWALL
options         IPFIREWALL_FORWARD
options         IPFIREWALL_VERBOSE
options         IPFIREWALL_VERBOSE_LIMIT=1000
options         IPFIREWALL_NAT
options         LIBALIAS
options         IPDIVERT
options         DUMMYNET

Далее:

# cd /usr/src
# make buildkernel KERNCONF=NEW_MY_CONF
....
# make installkernel KERNCONF=NEW_MY_CONF

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

#       ${fwcmd} add divert natd all from any to any via ${inet_if}
#       ${fwcmd} add divert natd all from any to any via lo0

         ${fwcmd} nat 1 config ip ${inet_ip} log same_ports unreg_only
         ${fwcmd} add nat 1 all from ${lan_net} to any
         ${fwcmd} add nat 1 all from any to ${inet_ip}

, где ${inet_if} — интерфейс смотрящий «наружу», ${lan_net} — внутренняя сеть (192.168.0.1/24), ${inet_ip} — внешняя пиха.
unreg_only говорит ipfw натить только частные сети
same_ports пытается оставлять те же номера портов
Дальше нам нужно остановить нат:

# /etc/rc.d/natd stop

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

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

        ${fwcmd} nat 1 config ip ${inet_ip} unreg_only same_ports log redirect_port tcp 192.168.0.17:80 80
        ${fwcmd} add nat 1 all from ${lan_net} to any
        ${fwcmd} add nat 1 all from any to ${inet_ip}

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

Опубликовано 09.11.2009 в 22:02 · Автор Berezhinskiy · Ссылка
Рубрики: FreeBSD, Security · Теги: , , , , ,

3 комментария

Подписаться на комментарии по RSS

  1. Написал(-а) Satarum
    9 февраля 2010 в 0:45
    Ответить · Ссылка

    В правиле проброски портов заместо ${fwcmd} nat 1 config if ${inet_ip} надо ставить не адрес а интерфейс, раз уж такое дело… Поправьте если не прав.
    Возник вопрос. Не подскажете, почему правила при проброске портов вписаные в стартап скрипт ipfw при старте не работают, однако, при введении непосредственно команды, например
    ipfw nat 123 config if rl0 log same_ports unreg_only redirect_port tcp 192.168.0.2:17084 17084
    правио моментально вступает в силу? Синтаксис проверял, все вроде абсолютно верно, все остальные правила срабатывают, однако проброска нет (

  2. Написал(-а) Berezhinskiy
    9 февраля 2010 в 12:43
    Ответить · Ссылка

    @ Satarum:
    1) Спасибо за указание на очепятку. На самом деле строка конфига должна выглядеть так:
    ${fwcmd} nat 1 config ip ${inet_ip}
    Сейчас же исправлю :)
    2) По поводу страртового скрипта ipfw:
    Путь к твоему скрипту должен быть статически прописан в rc.conf. У меня это выглядит так:
    # cat /etc/rc.conf | grep firewall
    firewall_enable=»YES»
    firewall_script=»/usr/local/etc/firewall/rc.firewall»
    С правилами при старте нет никаких проблемм. Также не забудь вписать в начало своего скрипта строку с указанием ipfw сбросить все правила:
    ipfw -f flush

  3. Написал(-а) kvirtu
    10 ноября 2010 в 22:52
    Ответить · Ссылка

    в rc.conf добавить вместо старых значений
    firewall_nat_enable=»YES»
    firewall_nat_interface=»rl0″

Подписаться на комментарии по RSS

Написать комментарий