NAT вирішує, яку адресу джерела ваш VPN-сервер насправді бачить
Адреса вашого ноутбука ніколи не доходить до VPN-сервера. NAT переписує її на останньому стрибку, а IP-адреса тунелю призначається пізніше. Як порівняти обидва кінці.
Ви уявляєте, що VPN-сервер читає адресу вашого ноутбука з пакета і записує її до журналу. Насправді він читає те, що останній стрибок NAT помістив у зовнішній заголовок, а на телефоні, який використовується як точка доступу, це часто адреса, спільна з сотнями інших абонентів. Власна адреса вашої машини 192.168.x.x ніколи не перетинає інтернет у цьому заголовку, а адресу тунелю сервер видає вже після встановлення з'єднання. Тому, коли журнал сервера і ip addr на ноутбуці розходяться, жоден із них не помиляється; вони описують різні рівні однієї сесії.
Три адреси, і лише одна з них у журналі
Плутанина виникає через зведення трьох адрес до однієї. Кожна має іншого власника, живе в іншому заголовку і доходить до сервера іншим шляхом.
| Address | Who assigns it | Where it sits | Visible to the VPN server |
|---|---|---|---|
Device address, e.g. 192.168.1.24 | Your router via DHCP | Outer header, before translation | No, rewritten in place |
| Translated address and port | Router, ISP CGNAT, or both | Outer header, after translation | Yes, this is the tuple it logs |
Tunnel address, e.g. 10.8.0.6 | The VPN server itself | Inner header, after decapsulation | Yes, but it chose it |
Лише середній рядок невідомий у момент підключення. Сервер записує його до таблиці партнерів, файлу стану або журналу потоків залежно від демона: WireGuard називає його кінцевою точкою, файл стану OpenVPN позначає його як Real Address, а strongSwan повідомляє його як віддалений хост IKE_SA. Це значення оновлюється щоразу, коли надходить пакет з іншого джерела, тому змінюється без чийогось перезапуску.
Нижній рядок — це те, що люди помилково читають як твердження про ідентичність. Він позначає місце в конфігурації сервера, а не людину, бо сервер вибрав його зі свого пулу. Двоє користувачів можуть отримати одну й ту саму адресу тунелю в різні дні, а один може мати дві з двох пристроїв.
Чому записаний кортеж змінюється, поки тунель залишається піднятим
Трансляція адрес — це таблиця з таймером, а не постійна прив'язка. Домашній маршрутизатор тримає своє UDP-зіставлення ще деякий час після останнього пакета, шлюз оператора переробляє порти за власним розкладом, а телефон, що переходить з Wi-Fi на LTE, повертається зовсім з іншим джерелом. Значення conntrack за замовчуванням у Linux — корисний орієнтир: nf_conntrack_udp_timeout становить 30 секунд, а потоковий варіант 120, тож тихий тунель може втратити зіставлення задовго до того, як користувач це помітить.
Тунель виживає тому, що протокол автентифікує партнера, а не адресу. WireGuard після рукостискання не має стану, тому будь-який автентифікований пакет оновлює збережену кінцеву точку, і переприв'язка виправляється на наступному пакеті; саме для цього існує persistent-keepalive = 25 — щоб зіставлення залишалося теплим під час простою. --float в OpenVPN робить те саме і дозволяє автентифікованому клієнту продовжити з нової адреси й порту. У збірках 2.4 і 2.5, де float вимкнено за замовчуванням, переприв'язка скидає сесію, і клієнт підключається заново.
IPsec досягає цього з більшою кількістю рухомих частин. IKEv2 помічає трансляцію, порівнюючи хеші джерела й призначення в корисному навантаженні виявлення NAT, переходить на інкапсуляцію UDP 4500 і стежить за keepalive до нового кортежу. Коли keepalive заблоковані, SA залишається піднятим лише на папері, а трафік в одному напрямку тихо зупиняється.
Що сервер може приписати, а що ні
Міф, який варто вбити, полягає в тому, що трансляція ховає вас від оператора. Вона змінює мітку, а не спостереження. Шлюз за NAT оператора бачить простір 100.64.0.0/10 або одну публічну адресу, спільну для багатьох абонентів, і все ж може пов'язати потік із суб'єктом сертифіката, відкритим ключем WireGuard, виданою адресою тунелю, лічильниками байтів і часовим вікном. Нічому з цього не потрібна ваша адреса LAN.
Обмеження працюють і в зворотному напрямку. Спільна адреса в журналі вказує на шлюз, а не на домогосподарство; дві сесії з однієї трансльованої адреси на різних портах — це різні пристрої; та сама адреса в два різні дні може належати двом не пов'язаним абонентам, якщо порт було перероблено. Сервер, що записує лише ключі партнерів, не може зіставити їх із клієнтом без бази даних облікових записів, а сервер, що записує лише адреси, не відрізнить ноутбук від телефона за одним маршрутизатором.
Порівняйте обидва кінці замість здогадок
Щоб з'ясувати, що сталося, захопіть те саме з'єднання на обох кінцях в один момент і порівняйте кортеж, а не адресу. На клієнті, до будь-якої трансляції:
ss -uapn 'dport = :51820'
ip -4 route get 203.0.113.10
wg show wg0 endpoints
Потім прочитайте запис трансляції на маршрутизаторі або шлюзі CGNAT і те, що зрештою надходить на сервер:
conntrack -L -p udp --dport 51820
tcpdump -ni eth0 udp port 51820
Три схеми пояснюють більшість розбіжностей. Порт джерела на сервері відрізняється від локального порту, а призначення збігається: звичайна трансляція портів. Адреса джерела на сервері належить блоку ISP, який не ваш: принаймні один додатковий рівень NAT. Пакети зупиняються після періоду простою і відновлюються з новим портом: зіставлення минуло, а не збій маршрутизації. Якщо мітки часу розходяться більш ніж на секунду-дві, ви порівнюєте дві різні спроби.
Де різниця ламає все
Збої, схожі на відмови сервера, зазвичай починаються тут. Правило доступу, прив'язане до вашої домашньої адреси, перестає працювати після зміни оренди в ISP. Правило fail2ban, що збігається з трансльованою адресою, блокує всіх абонентів за цим шлюзом одразу. Партнер «сайт-сайт» із фіксованою віддаленою адресою перестає оновлювати ключі після зміни мобільного каналу. Протокол тунелю був гаразд; припущення про зовнішній кортеж — ні.
Та сама плутанина видна і на боці сервера. Якщо сам VPN-бокс стоїть за NAT, потрібні проброс порту й робочий шлях пересилання; посібник strongSwan з пересилання охоплює цей випадок для IPsec. Сервер, доступний лише за приватною адресою, ніколи не бачить трансльований кортеж, який подають його клієнти, і це інша проблема, ніж трансляція клієнтів.
Пройдіть ці чотири перевірки по порядку і зупиніться на першій невдалій:
- Захопіть на обох кінцях одночасно; підтвердьте, що порт джерела, порт призначення й мітки часу збігаються.
- Прочитайте в списку партнерів сервера адресу, яку він зараз тримає, а не ту, яку ви очікували.
- Перевірте таблицю conntrack або NAT на запис і його залишковий термін життя.
- Підтвердьте, що адреса інтерфейсу тунелю на клієнті збігається з виданою сервером, а не з адресою LAN.
Якщо обидва захоплення збігаються щодо кортежу, а тунель усе одно не працює, трансляція — не ваша проблема; переходьте до рукостискання й до таблиці маршрутизації всередині тунелю.