NAT для LAN через tun0 на шлюзі OpenBSD VPN
Виберіть між NAT джерела та зворотним маршрутом для LAN-трафіку, що залишає вихід tun0 OpenBSD, а потім розмістіть правило nat-to там, де pf ще пропустить його.
Двоє інженерів з одним і тим самим шлюзом OpenBSD часто дадуть вам два різні набори правил для доступу до віддаленої мережі, і обидва можна захистити. Вибір між трансляцією джерела та зворотним маршрутом зовсім не питання синтаксису. Усе зводиться до того, що віддалена сторона вже знає про 192.168.88.0/24, і що вам потрібно зберегти в журналах. Помилитеся тут, і рядок nat-to виглядатиме цілком правильно, поки відповіді зникають у віддаленому шлюзі за замовчуванням.
Маршрутизація та перезапис відповідають на різні питання
Таблиця маршрутизації вирішує, що 172.20.0.0/16 доступний через tun0, і це рішення ухвалюється до того, як буде запитано будь-яку трансляцію pf. Далі трансляція джерела змінює заголовок пакета, щоб віддалена сторона бачила адресу тунелю шлюзу, а не хост LAN. Жоден механізм не замінює інший: правило nat не може створити маршрут, а маршрут не може переконати віддалений маршрутизатор, який ніколи не чув про вашу приватну підмережу. Коли у віддаленої сторони немає зворотного шляху, відповіді відкидаються або пересилаються на її шлюз за замовчуванням, і жодне налаштування правил це не виправить.
Простіше кажучи, пересилання відповідає на питання, куди йде трафік, а трансляція — звідки він виглядає таким, що приходить. Тримайте їх в окремих уявних коробках, поки проєктуєте набір правил.
Три умови, які все вирішують
Поставте три питання по черзі, і проєкт зазвичай вибирається сам. Чи має віддалена мережа статичний маршрут на адресу тунелю для 192.168.88.0/24, чи її адміністратор керує маршрутизаторами на цьому шляху? Якщо так, пропустіть LAN-адреси без змін і повністю відмовтеся від трансляції. Чи потрібна вам видимість за кожним клієнтом на віддаленій стороні — для політики доступу чи для журналу аудиту? Якщо так, збереження джерела варте праці з маршрутизації. Чи достатньо стабільна адреса тунелю, щоб прописати її у віддалений маршрут, чи вона змінюється між перепідключеннями?
Якщо будь-яка відповідь «ні» або невідома, nat-to — прагматичний варіант, і він же зворотний. Правило трансляції прибирається одним рядком, щойно віддалена сторона додасть нормальний маршрут. Зворотний маршрут, який так і не було встановлено, коштує вам однієї гілки підтримки щоразу, коли хтось запитує, чому тунель працює лише в один бік.
Розмістіть фрагмент так, щоб pf справді його оцінював
Наведений нижче фрагмент припускає, що LAN — це 192.168.88.0/24, віддалена мережа — 172.20.0.0/16, а інтерфейс тунелю — tun0. Ніщо в ньому не вибирає наступний хоп. Він лише перезаписує джерело в пакетах, які вже виходять через тунель.
match out on tun0 inet from 192.168.88.0/24 to 172.20.0.0/16 nat-to (tun0)
pass in on em0 inet from 192.168.88.0/24 to any keep state
Дві деталі в цьому першому рядку несуть основне навантаження. Дужки навколо tun0 кажуть pf читати адресу інтерфейсу щоразу, коли він будує запис стану, що важливо, коли після перепідключення тунелю призначають новий номер. Слово match означає, що правило перезаписує і потім провалюється далі, тому окремому pass-правилу все одно треба пропустити потік. Інтерфейс, названий у рядку match, також має бути тим, який вибирає таблиця маршрутизації, інакше pf оцінить правило на іншому вихідному шляху, ніж той, яким пакет реально йде.
Не забудьте про бік ядра. Пересилання IPv4 має бути ввімкнене, а stateful pass-правила для тунелю та LAN мають існувати до того, як усе це набуде сенсу. Розділ PF NAT у FAQ OpenBSD — правильне посилання на порядок ключових слів.
Перевірте набір правил, перш ніж довіряти трафіку
Спочатку перевірте синтаксис командою pfctl -nf /etc/pf.conf, яка розбирає файл, не завантажуючи його. Потім завантажте політику і перечитайте, що ядро справді тримає, бо чисто розібране правило все одно може бути затінене або прив'язане до неправильного інтерфейсу. pfctl -sn друкує правила трансляції в завантаженому вигляді, а pfctl -sr друкує правила фільтрації в порядку обчислення.
Далі спостерігайте за проводом. На шлюзі tcpdump -ni tun0 'host 172.20.0.10' показує, чи є адреса джерела, що виходить із тунелю, адресою тунелю чи хостом LAN. Швидкий netstat -rn -f inet підтверджує, на який інтерфейс розв'язується призначення. Щойно трафік пішов, pfctl -ss перелічує записи стану; якщо потік не створив стану, пакет жодного разу не збігся з правилом, яке його створює.
Якщо бік тунелю виглядає правильно, а відповіді все не приходять, припиніть редагувати pf. Залишкова несправність на віддаленому маршрутизаторі, де відповідь надсилається на приватну адресу, недосяжну з того боку.
Коли трансляція коштує дорожче, ніж економить
Трансляція приховує клієнтів, і іноді це якраз невдалий обмін. Перекривні підмережі — один випадок: якщо віддалена сторона теж використовує 192.168.88.0/24 усередині, подання LAN-хостів як шлюзу робить колізію гіршою, а не кращою. Політики IPsec, які вибирають трафік за парою адрес, — інший випадок, бо база політик безпеки зіставляється до трансляції і ніколи не бачить перезаписаний пакет. Будь-яке розгортання, яке тарифікує, обмежує або аудитує за користувачем, також втрачає ідентичність, потрібну йому в момент, коли джерело стискається до однієї адреси.
Портативні похідні pf — окрема пастка. Продукти, що генерують власні файли правил, очікують, що NAT налаштовуватиметься через їхній інтерфейс, а відредаговані вручну фрагменти перезаписуються під час наступного перезавантаження правил. Набори правил, скопійовані з посібників, написаних до появи ключового слова match, не завантажаться на поточному ядрі, тому перенесіть синтаксис і прочитайте помилку замість того, щоб вгадувати.
Правило ухвалення рішень, яке виживає в контакті з реальними мережами, коротке: встановіть зворотний маршрут, коли можете, транслюйте, коли не можете, і запишіть, яка з трьох умов змусила вас обрати саме це. Ця нотатка економить наступній людині півдня.