Сети для самых маленьких. Часть 20: VPN и прокси
В девятнадцатой части мы разобрали IPsec и IKEv2 как протоколы: пакеты, обмены, ключи. Сегодня — что из них получается на машине пользователя, когда он нажимает «Подключиться», и чем это отличается от другого способа пустить трафик через чужой сервер — прокси. Слово «VPN» затёрто до неузнаваемости: им называют и туннель между офисами, и кнопку в браузере, и это разные вещи с разной механикой. Серия построена на уровнях, и именно уровни дают точный ответ: VPN работает на сетевом уровне, прокси — на транспортном или прикладном. Всё остальное из этого следует.
Что такое VPN
VPN, Virtual Private Network — виртуальная сеть поверх другой сети. В терминах серии: туннель, то есть протокол внутри протокола, как PPPoE внутри Ethernet в четвёртой части или кадр внутри UDP в VXLAN, обычно с шифрованием. Туннель бывает L2 (внутри едут кадры, как в VXLAN) и L3 (внутри едут IP-пакеты, как в IPsec); для удалённого доступа почти всегда L3.
Главное практическое свойство: с точки зрения операционной системы VPN — это сетевой интерфейс и маршруты. После подключения в системе появляется интерфейс tun0, ipsec0, wg0 или ppp0 с адресом из «той» сети, а в таблицу маршрутов ложатся префиксы, которые надо отправлять в него. Приложения пишут в сокеты как обычно; стек по таблице маршрутов решает, что пакет пойдёт в tun0; VPN-клиент берёт его оттуда, шифрует и отправляет по настоящему интерфейсу на сервер; сервер расшифровывает и отправляет дальше, как роутер. Ни одна программа на машине не знает, что что-то изменилось, и это работает для любого протокола — TCP, UDP, ICMP, чего угодно поверх IP.
Два вида:
- site-to-site — туннель между двумя шлюзами; хосты за ними вообще не участвуют, для них «та» сеть — просто ещё один маршрут через свой роутер. Так соединяют офисы.
- remote access — клиент на ноутбуке или телефоне, подключающийся к шлюзу. О нём дальше.
IKEv2 remote access: по шагам
Сотрудник в кафе подключается к корпоративной сети. Ноутбук получил от кафе адрес 192.168.1.10, шлюз VPN — vpn.example.com, корпоративная сеть — 10.0.0.0/8.
1. Рукопожатие. Клиент резолвит vpn.example.com в 203.0.113.5 и проводит IKE_SA_INIT и IKE_AUTH из прошлой части: сервер предъявляет сертификат с именем vpn.example.com, клиент — логин и пароль через EAP-MSCHAPv2. В IKE_AUTH клиент просит конфигурацию (CP): «дай адрес, DNS», и предлагает селекторы трафика 0.0.0.0/0 с обеих сторон — «хочу защищать всё».
2. Сервер отвечает. CP: внутренний адрес 10.0.5.17, DNS 10.0.0.53, домен example.com. Селекторы: либо оставляет 0.0.0.0/0 (полный туннель), либо сужает до 10.0.0.0/8 (раздельный). Создаётся пара Child SA.
3. Клиент настраивает систему. Вот что меняется в ip addr и ip route:
$ ip addr show ipsec0 # или адрес на том же eth0 в policy-based реализациях
inet 10.0.5.17/32 scope global ipsec0
$ ip route
default via 192.168.1.1 dev wlan0 metric 600 # осталось
203.0.113.5 via 192.168.1.1 dev wlan0 # (а) хост-маршрут до VPN-сервера
10.0.0.0/8 dev ipsec0 # (б) корпоративная сеть — в туннель
Для полного туннеля вместо (б) появится 0.0.0.0/0 dev ipsec0 с лучшей метрикой, чем у кафе, или два маршрута 0.0.0.0/1 и 128.0.0.0/1: они длиннее, чем /0, и по правилу самого длинного префикса побеждают старый default, не удаляя его. Маршрут (а) обязателен: пакеты к самому VPN-серверу должны идти мимо туннеля, иначе зашифрованный пакет попадёт в туннель, будет зашифрован ещё раз, и так до бесконечности.
DNS: в resolv.conf или systemd-resolved первым становится 10.0.0.53, домен поиска example.com.
4. Пакет к корпоративному серверу. Приложение подключается к 10.0.0.42:443:
приложение sendto(10.0.0.42:443)
│
стек: ip route get 10.0.0.42 → dev ipsec0, src 10.0.5.17
│
┌────┴──────────────────────────────────────┐
│ IP 10.0.5.17 → 10.0.0.42 │ TCP 443 │ TLS │ ← то, что видит приложение
└────┬──────────────────────────────────────┘
│ xfrm: политика «10.0.0.0/8 → защищать», SA найдена
┌────┴────────────────────────────────────────────────────────────────────────────┐
│ IP 192.168.1.10 → 203.0.113.5 │ UDP 4500 │ ESP spi, seq │ ░░ весь пакет выше ░░ │ ← то, что видит кафе
└────┬────────────────────────────────────────────────────────────────────────────┘
│ dev wlan0 → шлюз кафе → NAT кафе → интернет → 203.0.113.5
▼
сервер: расшифровать, проверить селекторы, маршрутизировать 10.0.5.17 → 10.0.0.42 в корпоративную сеть
Кафе и провайдер видят один UDP-поток на 4500 порт: ни адреса 10.0.0.42, ни порта 443, ни содержимого. Сервер 10.0.0.42 видит соединение от 10.0.5.17 — адреса из своей сети — и отвечает ему; ответ по маршрутам корпоративной сети приходит на VPN-шлюз, тот заворачивает его в ESP к 192.168.1.10 (точнее, к внешнему адресу NAT кафе, с которого пришёл клиент), и стек ноутбука, расшифровав, отдаёт приложению.
5. Пакет в интернет зависит от режима.
Полный и раздельный туннель
Split tunneling — в туннель только корпоративные префиксы, остальное напрямую через кафе. Быстрее, не грузит корпоративный канал видео с YouTube, и сервер сам задаёт список через селекторы или CP-атрибут INTERNAL_IP4_SUBNET. Цена — два пути наружу одновременно, и отсюда утечки:
- DNS. Запрос
intranet.example.comможет уйти не в10.0.0.53, а в DNS кафе, если клиент не сумел настроить «этот домен — через этот сервер», а остальное — как было. Кафе узнаёт, какие внутренние имена вы ищете, а имя не резолвится. Windows с несколькими интерфейсами и DNS-серверами на каждом здесь особенно изобретательна. - IPv6. Туннель настроен только на IPv4, а у кафе есть IPv6 (тринадцатая часть). Всё, что резолвится в AAAA, уходит мимо туннеля, в открытую. Клиент должен либо провести IPv6 тоже, либо заблокировать его на время подключения.
- Приложения, знающие свои адреса. WebRTC в браузере (механизм звонков из девятой части) честно перечисляет все локальные адреса машины, включая адрес кафе, тому, с кем соединяется.
Полный туннель — всё в VPN. Кафе видит один шифрованный поток и ничего больше; сайты видят адрес VPN-шлюза. Но весь интернет-трафик идёт через корпоративный канал, и, если VPN-шлюз далеко, с соответствующей задержкой. И даже здесь есть момент до подключения и после обрыва, когда трафик идёт открыто. Для этого придуман kill switch: правило файрвола «ничего, кроме пакетов к VPN-серверу, через wlan0 не выпускать», которое остаётся, пока VPN не отключат явно.
Коммерческие «VPN-сервисы» — это remote access с полным туннелем, где «корпоративная сеть» — интернет за сервером провайдера услуги. Механика та же; меняется только, кто видит ваш трафик расшифрованным: не кафе, а оператор сервиса.
Другие протоколы VPN
IKEv2/IPsec — то, что встроено в Windows, macOS, iOS и Android без клиентов. Остальные, чтобы было понятно, что написано в настройках:
- WireGuard — туннель поверх UDP с фиксированной криптографией (Curve25519, ChaCha20-Poly1305): у каждого пира открытый ключ, у соединения — список разрешённых префиксов на пира (которые заодно и маршруты), никакого рукопожатия с выбором алгоритмов. Интерфейс
wg0в ядре Linux, несколько тысяч строк кода против сотен тысяч у IPsec, переезд клиента между адресами сам собой. Из-за простоты сейчас самый быстрый и всё чаще предпочитаемый. - OpenVPN — туннель внутри TLS-сессии по UDP или TCP, пользовательский процесс и интерфейс
tun. Старше, медленнее, но проходит там, где UDP 500/4500 закрыт, потому что умеет TCP 443 и выглядит как HTTPS. - L2TP/IPsec — две вещи сразу: L2TP, туннель для кадров PPP поверх UDP 1701, защищённый IPsec в транспортном режиме. Внутри — тот же PPP из четвёртой части с аутентификацией и IPCP. Встроен в старые Windows, живёт по инерции.
- SSTP — PPP внутри TLS на порту 443, вариант Microsoft для обхода файрволов.
- PPTP — PPP внутри GRE с шифрованием MPPE, взломан окончательно, не использовать.
Все они одинаковы в главном: интерфейс плюс маршруты, трафик всех приложений.
Прокси
Прокси — посредник на транспортном или прикладном уровне. Приложение не отправляет пакет получателю; оно устанавливает соединение с прокси и просит его соединиться с получателем, а дальше прокси перекладывает байты между двумя соединениями. Операционная система, таблица маршрутов и интерфейсы не меняются. Прокси использует только то приложение, которому его прописали.
HTTP-прокси и CONNECT
Браузер с настроенным прокси proxy.example.com:3128 для открытого HTTP (протокол запросов страниц, запрос — текстовая строка «метод, адрес, версия») шлёт прокси запрос с полным URL:
GET http://www.example.com/page HTTP/1.1
Host: www.example.com
Прокси сам идёт на www.example.com, получает ответ и отдаёт браузеру, по дороге кешируя, фильтруя и записывая всё, что захочет: он читает содержимое.
Для HTTPS читать нечего, и для него есть метод CONNECT:
CONNECT www.example.com:443 HTTP/1.1
Host: www.example.com:443
Proxy-Authorization: Basic dXNlcjpwYXNz
HTTP/1.1 200 Connection established
<дальше в этом же TCP-соединении — сырые байты TLS между браузером и сайтом>
Прокси открывает TCP к www.example.com:443, отвечает 200 и с этого момента просто пересылает байты в обе стороны. TLS устанавливается сквозь него, между браузером и сайтом; прокси видит только имя и порт из CONNECT. Так работает большинство корпоративных прокси, так браузер ходит через них на HTTPS, и так же через CONNECT можно пропустить что угодно поверх TCP, например SSH.
В curl -v -x http://proxy.example.com:3128 https://www.example.com первые строки — ровно этот CONNECT и 200.
Прозрачный прокси — тот же HTTP-прокси, но приложение о нём не знает: роутер перенаправляет весь трафик на порт 80 в прокси, и тот разбирает запросы по заголовку Host. С HTTPS прозрачно уже не выходит: без подмены сертификатов прокси видит только имя сервера в начале TLS.
Обратный прокси — та же программа с другой стороны: стоит перед серверами, принимает запросы от всех клиентов и раздаёт их по бэкендам. Это nginx или Traefik перед сайтом, и к теме «пустить мой трафик через посредника» он отношения не имеет; упомянут, чтобы слово не путало.
SOCKS5
SOCKS, RFC 1928, — прокси уровнем ниже HTTP: он не понимает, что внутри, и просто соединяет. Обмен:
клиент → прокси: 05 02 00 02 версия 5, умею два способа аутентификации: нет и логин/пароль
прокси → клиент: 05 00 выбираю «без аутентификации»
клиент → прокси: 05 01 00 03 0f www.example.com 01 bb
│ │ │ └ адрес: тип 3 — доменное имя длиной 15, порт 443
│ │ └── резерв
│ └── команда 1 — CONNECT
└── версия
прокси → клиент: 05 00 00 01 <адрес, с которого прокси подключился> <порт>
└ статус 0 — успех
дальше — сырые байты в обе стороны
Два свойства, которых нет у HTTP CONNECT. Во-первых, SOCKS5 принимает адрес как имя, и тогда резолвит его прокси, а не клиент: имя не уходит в локальный DNS, и это закрывает ту самую утечку DNS; в curl это --socks5-hostname, в браузерах — «proxy DNS when using SOCKS». Во-вторых, есть команда UDP ASSOCIATE, через которую можно проксировать и UDP; реализаций немного, но они есть.
Самый доступный SOCKS-прокси — ssh -D 1080 user@server: SSH, протокол удалённого терминала с шифрованием, открывает на локальной машине порт 1080, и всё, что приложение отправит в него по SOCKS, уезжает внутри SSH-сессии и выходит в интернет с сервера. Между клиентом и сервером — шифрованный SSH, дальше — обычный трафик от имени сервера.
Чем VPN отличается от прокси
| VPN | Прокси | |
|---|---|---|
| Уровень | L3: интерфейс и маршруты | L4 (SOCKS) или L7 (HTTP): соединение к посреднику |
| Кто им пользуется | всё, что есть на машине, не зная об этом | только приложения, где прокси настроен |
| Протоколы внутри | любые поверх IP: TCP, UDP, ICMP | TCP; UDP — только SOCKS5 и редко |
| Шифрование | часть протокола (IPsec, WireGuard, TLS у OpenVPN) | нет по умолчанию: HTTP-прокси и SOCKS открыты, если не завернуть их в TLS или SSH |
| Что видит посредник | все пакеты расшифрованными: адреса, порты, содержимое, если его не защищает TLS | адреса назначения; содержимое открытого HTTP; у HTTPS — только имя и порт |
| Что видит локальная сеть (кафе) | один шифрованный поток к VPN-серверу | соединения к прокси; содержимое, если прокси не по TLS; DNS-запросы, если резолвит клиент |
| Что видит сайт | адрес VPN-сервера | адрес прокси |
| DNS | через туннель (при полном) или по правилам (при раздельном) | клиентский, кроме SOCKS5 с именами |
| Настройка | клиент с правами на интерфейсы и маршруты | строка в настройках приложения или переменная https_proxy |
| Где работает | в ядре или с его участием | в пространстве пользователя |
| Что ломает | MTU меньше на 50–80 байт; раздельный туннель — утечки | приложения без поддержки прокси; UDP |
Два практических вывода.
«VPN» в расширении браузера — это прокси. Расширение не может создать интерфейс и менять маршруты; оно настраивает в браузере HTTPS- или SOCKS-прокси. Через него идёт только трафик этого браузера, остальные программы и другие браузеры — мимо. Для сайта в этом браузере разницы нет, для картины «всё моё устройство за VPN» — есть.
Ни то, ни другое не анонимность. VPN-сервер и прокси видят, куда вы ходите, и могут это записывать. Они переносят доверие от локальной сети и провайдера к оператору сервера. Если задача — чтобы никто не связал запрос с вами, нужны цепочки посредников, как в Tor, где каждый узел знает только соседей, и это отдельная история.
Когда что: доступ ко всей удалённой сети всеми программами — VPN; одна программа через другой выход — прокси; обойти файрвол, пропускающий только HTTPS, — прокси по TLS на 443 или VPN, умеющий притворяться HTTPS (OpenVPN на TCP 443, SSTP); между офисами — site-to-site VPN, и никаких прокси.
Смотрим руками
До и после подключения VPN — что изменилось в системе:
$ ip addr | grep -A2 'tun\|wg\|ipsec'
$ ip route
$ ip route get 10.0.0.42 # куда уйдёт пакет в корпоративную сеть
$ ip route get 203.0.113.5 # а к самому VPN-серверу — должен уйти мимо туннеля
$ resolvectl status # какие DNS и для каких доменов
WireGuard и некоторые клиенты используют policy routing: маршруты лежат в отдельной таблице, а правило ip rule отправляет туда всё, кроме пакетов самого туннеля (помеченных fwmark). Тогда ip route покажет старую картину, а ip rule и ip route show table all — настоящую.
Утечки: dig intranet.example.com и смотреть в tcpdump, на какой сервер ушёл запрос и по какому интерфейсу; curl -6 https://example.com — уходит ли IPv6 мимо туннеля; ip route get 2001:db8::1.
Прокси вживую:
$ curl -v -x http://proxy.example.com:3128 https://www.example.com # увидите CONNECT и 200
$ ssh -D 1080 -N user@server.example.com & # SOCKS на 1080
$ curl --socks5-hostname 127.0.0.1:1080 https://www.example.com # имя резолвит сервер
и tcpdump на локальном интерфейсе покажет разницу: в случае VPN — только ESP или UDP к одному адресу; в случае прокси — TCP-соединение к прокси с CONNECT в открытом виде (если прокси без TLS) или SSH-сессию.
Что запомнить
- VPN — туннель на сетевом уровне: интерфейс и маршруты, все приложения, любые протоколы поверх IP, шифрование встроено. Remote access на IKEv2: адрес и DNS через CP, префиксы через селекторы, хост-маршрут до сервера мимо туннеля.
- Полный туннель прячет всё от локальной сети; раздельный быстрее, но течёт через DNS, IPv6 и WebRTC. Kill switch закрывает окна до и после.
- WireGuard, OpenVPN, L2TP/IPsec, SSTP — те же интерфейс и маршруты с другой упаковкой; PPTP — нет.
- Прокси — посредник для соединений: HTTP с полным URL или CONNECT для TLS, SOCKS5 с резолвом имён на стороне прокси и UDP; работает только для настроенных приложений, шифрование — отдельно.
- «VPN» в браузере — прокси для одного браузера. Ни VPN, ни прокси не анонимность: они меняют, кто видит ваш трафик.
Дальше — Часть 21: OSPF: как роутеры внутри одной сети сами узнают друг о друге и обо всех подсетях, строят общую карту и считают по ней кратчайшие пути. Hello и соседство, LSA и база состояний линков, алгоритм Дейкстры, стоимость линков, области и что происходит при обрыве кабеля.
Серия «Сети для самых маленьких»
- Модели OSI и TCP/IP — зачем сетевой стек разбит на уровни и как данные обрастают заголовками по пути пакета.
- Ethernet — кадр по байтам, MAC-адреса и как коммутатор решает, в какой порт отправить кадр.
- Wi-Fi — чем радио отличается от кабеля, как клиент подключается к точке доступа и как защищается эфир.
- PPPoE — как провайдер заворачивает сессию абонента в Ethernet и откуда берётся MTU 1492.
- IPv4: адреса, маски и подсети — как читать адрес и маску, делить сеть на подсети и решать, нужен ли шлюз.
- IPv4: заголовок, маршрутизация и NAT — как роутер выбирает маршрут для пакета и как вся квартира выходит в интернет с одного адреса.
- ARP — как по IP-адресу соседа узнать его MAC-адрес и почему соседа так легко подменить.
- ICMP — служебные сообщения IP, как на самом деле работают ping и traceroute и что ломается, когда их режут.
- UDP — восемь байт заголовка, порты и почему отправка без соединения иногда лучше.
- TCP — как из ненадёжного IP получается надёжный поток байтов и почему потеря пакета режет скорость.
- DHCPv4 — как машина без адреса получает адрес, маску, шлюз и DNS четырьмя сообщениями.
- DNS — как имя превращается в адрес: дерево зон, рекурсивные серверы, записи и кеширование.
- IPv6: адреса и заголовок — как записываются 128-битные адреса, какие они бывают и чем заголовок IPv6 отличается от IPv4.
- ICMPv6 и Neighbor Discovery — как в IPv6 без ARP и широковещания находят соседей и роутер.
- SLAAC — как хост собирает себе адрес IPv6 из объявления роутера без всякого сервера.
- DHCPv6 — зачем DHCP, если есть SLAAC, и как провайдер выдаёт домашнему роутеру целый блок сетей.
- VLAN — как один коммутатор и один кабель несут несколько независимых сетей.
- VXLAN — как растянуть сеть Ethernet через роутеры, завернув кадры в UDP.
- IPsec и IKEv2 — как шифруют пакеты на сетевом уровне и договариваются о ключах.
- VPN и прокси (эта статья) — куда уходит каждый пакет при включённом VPN и чем прокси отличается от VPN.
- OSPF — как роутеры одной сети сами строят общую карту и считают по ней кратчайшие пути.
- BGP — как десятки тысяч независимых сетей интернета договариваются о маршрутах.
- TLS и сертификаты — как защищают одно TCP-соединение и откуда браузер знает, что сервер настоящий.
Оставить комментарий могут только зарегистрированные пользователи.
Войдите на сайт или зарегистрируйтесь, чтобы оставить комментарий.