NAT у FreeBSD за допомогою IPFilter (ipnat)
Зміст
Синдром гамака є одним із ключових моментів деградації сисадміну. Він починається з того, що стабільність та нерухомість стають синонімами. Колись, перш ніж IPFilter включили до складу FreeBSD, єдиним нормальним способом зробити NAT у FreeBSD був natd. Обов'язковою умовою для повноцінної роботи natd є наявність dummynet (4). natd і досі може бути в деяких випадках актуальним. Ми ж розглянемо використання ipnat з IPFilter як засіб для Network Address Translation (NAT).
Цей документ не є покроковим howto для чайників — мається на увазі, що не потрібно пояснювати, що після зміни /etc/syslog.conf йому потрібно надіслати сигнал HUP, а файли, куди він буде писати, створювати потрібно самостійно і як «застосовувати» змінені правила . Якщо Ви вважаєте, що ще не зовсім освоїлися з *nix і з FreeBSD зокрема, то на цю тему можна почитати: ipnat(1), ipnat(5), ipnat(8) ipf(5), ipf(8), ipfstat(8), ipftest(1), ipmon(8)
Тут і далі вважатиметься, що IPFilter має як мінімум версії 3.4.29. Якщо у Вашому випадку це не так — то Ви ще не зовсім вилізли з гамака, хоча вже той факт, що Ви читаєте цей текст, є доказом Вашого бажання.
Підготовка
Отже, розглянемо ситуацію: ми маємо 2 інтерфейси - fxp0 (200.200.200.1), що дивиться у великий і злий інтернет, і dc0 (192.168.0.1), що дивиться у внутрішню мережу.
Завдання: зробити можливість користувачам внутрішньої мережі створювати з'єднання із зовнішніми хостами без використання socks5/http proxy тощо.
У ядрі нам знадобляться всього 2 рядки: options IPFILTER options IPFILTER_LOG
Після цього IPFilter доступний нам у всій своїй красі.
Також в /etc/rc.conf потрібно додати рядок gateway_enable="yes" або /etc/sysctl.conf додати рядок net.inet.ip.forwarding=1.
Простий stateful NAT
Почнемо із простого stateful NAT тобто. IP пакети із зовнішнього інтерфейсу для одержувача у внутрішній мережі транслюватимуться лише в тому випадку, якщо користувач із внутрішньої мережі сам встановив це з'єднання. Всі інші пакети, які прийшли на зовнішній інтерфейс для одержувача у внутрішній мережі, будемо блокувати (див. redirect далі, якщо якісь пакети ззовні потрібно завжди прокидатися всередину).
Для з'єднань, встановлених користувачем, ми будемо створювати запис у state table за допомогою простого правила IPFilter:>pass out quick on fxp0 proto udp from 192.168.1.149 to any keep state (для UDP-з'єднань). Можна замість двох правил зробити одне спільне як TCP, так UDP: pass out quick on fxp0 proto tcp/udp from 192.168.1.149 to any keep state , однак у такому правилі ми не зможемо відстежувати tcp-пакети з прапором SYN за допомогою flags, в результаті чого будь-який пакет із внутрішньої мережі буде створювати запис у state table (якщо її не було), а не ті пакети, які є першими в установці TCP-з'єднання (з прапором SYN). Що зручніше/краще/більше підходить вирішуйте самі.
Слідом за цим правилом ми помістимо правило, що блокує всі пакети для внутрішньої мережі. мережі чи пакети з з'єднань, яких немає у state table
Тепер сама трансляція.Занесемо у файл трансляцій (за замовчуванням це /etc/ipnat.rules) правило: map fxp0 192.168.1.149/32 -> 200.200.200.1/32 portmap tcp/udp 20000:20099
Все, що залишилося - застосувати правила. 😉
Для зручності відстеження роботи NAT можна додати рядок в syslog.conf: local0.* /var/log/ipmon.log і запустити утиліту моніторингу роботи IPFilter - ipmon з ключами -Dvas (стати демоном, показувати більш детальну інформацію, відстежувати всі утрої IPFilter ( NAT, state table і сам IPFilter) і працювати через syslog). Якщо log-файл, що отримується, здається сумбурним - не поспішайте включати log тільки NAT опцією -o N. Правила IPFilter що потрапляють в лог можна туди направляти з іншої facility. Для цього достатньо в кожне правило з прапором log додати facilty: block in log level .block.log. В результаті цього дії в /var/log/ipmon.log потраплятиме інформація про NAT (створені трансляції, закриті трансляції) і state table (створення запису та її видалення), а файл /var/log/ipfilter.block.log пакети , які були заблоковані.
Якщо не бажаєте, щоб у великій кількості правил була вказана facility і правила були коротшими - можна відкинути можливість роботи ipmon через syslog і змусити його писати прямо у файл; наприклад так: ipmon -Dv -o NS /var/log/NAT.log (трансляції та state table протоколуємо у файл /var/log/NAT.log) та ipmon -Dv -o I /var/log/ipfilter.log ( роботу самого фільтра протокольуємо до файлу /var/log/ipfilter.log).
Варто зауважити, що одним правилом можна транслювати кілька хостів. Наприклад замінивши в правилах ipnat та IPFilter 192.168.1.149/32 на 192.168.128/25 ми транслюватимемо пакети хостів звнутрішньої мережі з діапазону від 192.168.1.128 до 192.168.1.254.
Перенаправлення (редирект)
Якщо є необхідність безумовно транслювати якісь пакети, що прийшли ззовні (наприклад, щоб WWW/SMTP сервер із внутрішньої мережі) був доступний зовні – використовується редирект (redirect).
Простий варіант: транслювати пакети від будь-якого хоста.
rdr fxp0 200.200.200.1/32 port 8080 -> 192.168.1.17 port 80 tcp
В даному випадку будь-який пакет, що прийшов на порт 8080 зовнішнього інтерфейсу 200.200.200.1 буде «прокинутий» на 192.168.1.18 порт 80. Природно, що хост 192.168.1.17 краще помістити в таблицю трансляцій як було описано в того, що ініціюватися з'єднання буде зовні - додати правила IPFilter, які дозволяли б їх. У випадку, якщо ipmon протоколює роботу IPFilter, помилку можна буде легко побачити.
Редирект можна робити не всіх пакетів, а вибірково на підставі їх відправника: rdr fxp0 from 212.118.165.100/32 to 200.200.200.1/32 port = 6000 -> 192.168.1.89 port 6000
Цим правилом транслюватимуться пакети, що прийшли на 200.200.200.1 порт 6000лише з хоста 212.118.165.100
Не слід забувати створювати правила IPFilter, що дозволяють проходження таких пакетів. Хоча, якщо ipmon налаштований і запущений, він швидко про це нагадає. 😉
proxy-правило маєобов'язково стояти перед іншими правилами (за винятком redirect).
Безумовна повна трансляція
Контроль над трансляцією
Безумовно безглуздо налаштовувати NAT не дивлячись у протоколи, що генеруються ipmon'ом. Також буде корисним обмежувати здатність встановлювати з'єднання зсередини до привілейованих портів зовнішніх хостів. Все це можнаі потрібно налаштувати за бажанням.
Хорошим помічником може бути старий добрий root-tail (/usr/ports/sysutils/roottail).