Ну вот, на смену старому natd приходит новый kernel NAT, который как заявляют разработчики шустрее, меньше нагружает сервер, имеет больше возможностей, да и много ещё чего. Ниже будет рассказано, как настроить быстро и просто шлюз.
Эта статья больше походит на обновление статьи про natd, так что в ней присутствуют только новшества. Остальное можно почерпнуть из статьи про natd.
Внимание!
1) Перед установкой следует позаботиться о достаточном количестве файловых дескрипторов для пользователя, от которого работает squid, при включённом кешировании.
2) В src/UPDATING (RELENG-9) появилась запись, информирующая об удалении опции IPFIREWALL_FORWARD. Теперь этот функционал работает “из коробки”, достаточно просто загрузить модуль ядра ipfw.ko. В stable/9 это изменение уже тоже есть, но в релиз оно не попадёт. И так, начиная с 9.1 уже не нужно будет пересобирать ядро для ipfw fwd. Более того, при пересборке с этой опцией make будет ругаться на то, что не знает такой опции. Так что, если у вас пошла ругань – просто исключите эту опцию
3) В 9.2-Stable обнаружен баг: любое создание интерфейса вырубало форвардинг, устанавливало параметр net.inet.ip.forwarding в 0. Что бы этого не было, нужно устанавливать gateway_enable=”YES” в rc.conf
1) Включение IPFW+kernel NAT
Пересобираем ядро с такими опциями
options IPFIREWALL
options IPFIREWALL_NAT
options IPFIREWALL_FORWARD
options IPFIREWALL_DEFAULT_TO_ACCEPT
options IPFIREWALL_VERBOSE
options LIBALIAS
options DUMMYNET
2) Устанавливаем squid
Обновляем порты и ставим “кальмара”. Рекомендую ставить версию 3.0, так как она наиболее описана в инете и проблемы решаемы.
Конфиг можно взять с версии 2.6, правда кое-какие опции изменились, будьте внимательны.
3) Настройка файервола и NAT’a
Для нормальной работы достаточно таких переменных (остальные уже вкомпиллены в ядро) в /etc/rc.conf:
gateway_enable="YES"
firewall_script=/etc/fire.wall
Теперь создадим свой набор правил (файл /etc/fire.wall)
#!/bin/sh
FwCMD="/sbin/ipfw "
ExtIF="le1"
ExtIP="1.1.1.1"
LocalNet="10.10.10.0/24"
${FwCMD} -f flush
# deny flood traffic
${FwCMD} add 101 allow all from any to any via lo0
${FwCMD} add 102 deny all from any to 127.0.0.0/8
${FwCMD} add 103 deny all from 127.0.0.0/8 to any
${FwCMD} add 110 deny icmp from any to any frag
# squid
${FwCMD} add 301 allow all from ${LocalNet} to me 3128
${FwCMD} add 302 fwd 127.0.0.1,3128 tcp from ${LocalNet} to any dst-port 80
# NAT
${FwCMD} nat 1 config if ${ExtIF} log \
redirect_port tcp 10.10.10.55:22 4444 \
redirect_port tcp 10.10.10.66:80 6666
${FwCMD} add 501 nat 1 ip from ${LocalNet} to any via ${ExtIF}
${FwCMD} add 502 nat 1 ip from any to ${ExtIP} via ${ExtIF}
#${FwCMD} add 500 nat 1 ip from any to any via ${ExtIF}
В этом конфиге мы дополнительно пробросили 2 порта на внутренние машины, демонстрируя тем самым возможность и сиснтаксис проброса порта.
Примечание.
Правила NAT’a желательно располагать как можно выше, то есть выше правил для фильтрации трафика наружу. Вот выдержка из lissyara.su:
Относительно DIVERT в MAN-е по IPFW присутствует присутствует некая двусмысленность, согласно MAN-у для пакета попавшего под правило с DIVERT дальнейший поиск прекращается, а что происходит с самим пакетом – неясно.
Экпериментально установлено, что в случае трансляции адресов, пакет прошедший через DIVERT-сокет, продолжает путь по правилам IPFW сразу после правила с DIVERT, имея переписаный (транслированный) IP в заголовке.
Примечание2.
Во избежании проблем с kernel nat рекомендуется выключать TSO на всех интерфейсах. Вот, что говориться в man’e
$man ipfw | tail | head -4
Due to the architecture of libalias(3), ipfw nat is not compatible with the TCP segmentation offloading (TSO). Thus, to reliably nat your network traffic, please disable TSO on your NICs using ifconfig(8).
4) Рекомендации.
Для нормальной работы ipfw+kernel nat со строками включающими более двадцати rediretc’ов, необходимо выполнить следующее (для 9.0 и выше это уже не надо делать, там эти ограничения сняты):
– открываем /usr/src/sys/netinet/ip_fw.h
– ищем строку
#define NAT_BUF_LEN 1024
– меняем значение с 1024 на 11264
После этого пересобираем ipfw:
#cd /usr/src/sbin/ipfw && make && make install && make clean
5) Просмотр таблицы NAT’a
Наконец-то появилась возможность смотреть таблицу НАТа и в kernel nat (только это статистика, а не сама таблица). Делается это следующим образом:
#ipfw nat show
nat 1: icmp=106, udp=34388, tcp=115736, pptp=0, proto=0, frag_id=14 frag_ptr=0 / tot=150244
6) Послесловие.
kernel nat появился впервые в версии 7.0, до этого приходилось пользоваться natd. Но после 7-ки, natd не исчез, поэтому кому нравиться последний, может продолжать его использовать (но я бы не советовал 🙂 ). По сути kernel nat – это второе поколение natd, поэтому можно смело использовать синтаксис от natd. А если всё-таки сомневаетесь, то лучше загляните в man.
Очень хорошо про NAT и 2-х провайдеров описано здесь http://birdofluck.livejournal.com/8778.html
Опубликовано с разрешения журнала root.ua
13 коментарів “ipfw, kernel nat, squid”
имхо!!!
лучше PF в этом плане пока ничего нет
Доводилось ли автору настраивать ipfw kernel nat + фильтрацию из локальной сети в мир + фильтрацию из мира на внешний ip ?
Доводилось. А в чём собственно сложность?
em1 – в локалку, em0 – в инет. Цель – разрешить из локальной сети только пинг в интернет, и разрешить из интернета пинг интерфейса em0. Внешний IP (на em1) – 10.0.0.1. Проблема в том, что когда пингую из инета внешний IP, трафик заварачивается в нат, хотя стоит опция deny_in. Пробовал менять правила фильтрации и правила ната местами, результата нет.
ipfw -q -f flush
ipfw add allow icmp from 192.168.10.0/24 to any via em1
ipfw nat 1 config if em0 deny_in
ipfw add nat 1 ip from 192.168.10.0/24 to any via em0
ipfw add nat 1 ip from any to 10.0.0.1 in via em0
ipfw add allow icmp from any to 10.0.0.1 keep-state # Почему правило заваричается в НАТ ?
опечатался – на 10.0.0.1 это на em0
А что это за правило NAT’a?
ipfw nat 1 config if em0 deny_in
откуда вы его взяли?
И ещё, если вы используете keep-state то в самом начале должно быть ещё правило проверки состояний, то есть правило
ipfw add check-state.
В противном случае keep-state не сработает.
Это правило НАТ брал из мана
ipfw nat 123 config ip 192.168.0.123 log deny_in reset same_ports
Таки да. Но в остальном у вас всё равно ошибки.
Подскажите в чем именно
1) Прочитайте мой ответ выше про keep-state
2) Вот как должны выглядеть правила:
FwCMD=”/sbin/ipfw ”
ExtIF=”em0″
IntIF=”em1″
ExtIP=”1.1.1.1″
LocalNet=”192.168.10.0/24″
${FwCMD} -f flush
${FwCMD} add check state
${FwCMD} nat 1 config if ${ExtIF} deny_in
${FwCMD} add nat 1 ip from ${LocalNet} to any via ${ExtIF}
${FwCMD} add nat 1 ip from any to ${ExtIP} via ${ExtIF}
${FwCMD} add allow icmp from ${LocalNet} to any keep-state
${FwCMD} add allow icmp from any to ${ExtIP} keep-state
${FwCMD} nat 1 config if ${ExtIF} log \
redirect_port tcp 10.10.10.55:22 4444 \
redirect_port tcp 10.10.10.66:80 6666
Здесь вы привели пример проброса портов, причем как я понял все должно быть записано в одну строчку. Мне надо пробросить около 10-ти портов в локалку, есть ли более удобный синтаксис? Или вынести все это в отдельный файл?
Можно и в одну строчку, но вы можете натолкнуться на ограничение в количество символов в строке. Более удобного способа добавления пока нету. Если хотите выносить в отдельный файл – можно и так. Я разбивал на строки для удобства восприятия. И ещё – если у вас порядка 10-ти редиректов, лучше сразу увеличить размер стека (почитайте пункт 4.)
Хочу добавить по поводу четвертого пункта. Изменение только файла /usr/src/sys/netinet/ip_fw.h желаемого результата не дало. У моем случае помогло редактирование /usr/include/netinet/ip_fw.h (установил такое-же значение NAT_BUF_LEN как и в /usr/src/sys/netinet/ip_fw.h (8192) ) плюс пересобрал ipfw (cd /usr/src/sbin/ipfw && make && make install && make clean)