mirror of
https://github.com/vvzvlad/trickster-vpn.git
synced 2024-12-25 18:31:00 +03:00
update article
This commit is contained in:
parent
40c4d0f33e
commit
509bcba1f8
Before Width: | Height: | Size: 863 KiB After Width: | Height: | Size: 863 KiB |
BIN
article/2.jpg
Normal file
BIN
article/2.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 218 KiB |
Binary file not shown.
Before Width: | Height: | Size: 95 KiB |
@ -17,30 +17,28 @@ https://tunsafe.com/user-guide/linux
|
||||
---------
|
||||
|
||||
# Разбираемся с WireGuard и делаем свой умный VPN
|
||||
IMG_1589.PNG
|
||||
![](1.png)
|
||||
|
||||
Сейчас в РФ сложилась забавная ситуация: с одной стороны, РКН блокирует довольно много сайтов, к которым иногда нужен доступ, а с другой стороны, из-за DDOS-атак, многие крупные компании ограничили доступность своих сайтов из-за границы: например, pochta.ru, leroymerlin.ru, rt.ru, avito.ru, не открываются через VPN.
|
||||
Получается ситуация из мема:
|
||||
— Нужен твиттер!
|
||||
— Включить VPN!
|
||||
— А теперь заказать еду!
|
||||
— Выключить VPN!
|
||||
— А теперь выложить еду в инстаграм!
|
||||
— Включить VPN!
|
||||
|
||||
Каждый с этим борется как может. Например, на iphone [родными средствами](https://superg.ru/kak-nastroit-avtomaticheskoe-vklyuchenie-vpn-na-iphone/) можно настроить автоматизацию, которая будет запускать VPN при открытии определенных приложений (например, твиттера), а при выходе из них — выключать обратно.
|
||||
Сейчас в РФ сложилась забавная ситуация: с одной стороны, РКН блокирует довольно много сайтов, к которым иногда нужен доступ, а с другой стороны, из-за DDOS-атак, многие крупные компании ограничили доступность своих сайтов из-за границы: например, pochta.ru, leroymerlin.ru, rt.ru, avito.ru, не открываются через VPN.
|
||||
Получается мем:
|
||||
![](2.jpg)
|
||||
|
||||
Каждый с этим борется как может. Например, на устройствах Apple [родными средствами](https://superg.ru/kak-nastroit-avtomaticheskoe-vklyuchenie-vpn-na-iphone/) можно настроить автоматизацию, которая будет запускать VPN при открытии определенных приложений (например, твиттера), а при выходе из них — выключать обратно. Но это костыль, а хочется все сделать красиво, да еще и поднять рабочие навыки.
|
||||
|
||||
Поэтому мы сейчас займемся тем, что будем "включать чуть-чуть VPN".
|
||||
|
||||
Но на одной из картинок я видел, что последнюю реплику заменяют на "Включить VPN, но чуть-чуть!". Вот тем, что сейчас будем "включать чуть-чуть VPN" мы и займемся.
|
||||
Примечание душнилы: я прекрасно понимаю, что при таком использовании это скорее прокси, а не VPN, но с языком ничего не поделать — если все называют программы для обхода блокировок VPN, то лучшее, что можно тут сделать — постараться привыкнуть и получать удовольствие.
|
||||
Заодно чуть улучшим качество связи с локальными ресурсами: необходимость таскать трафик сначала до VPN вне страны, а потом обратно до сервера внутри ее драматично сказывается если не на скорости, то на задержке точно: даже на проводном интернете пинг в 4мс до яндекса легко превращается в 190мс, а на мобильном интернете — из 80мс в 240. Дополнительный хоп чуть ухудшит ситуацию, но далеко не так драматично.
|
||||
|
||||
Делать мы это будем на основе WireGuard — это относительно новая (разрабатыавется с 2016 года в отличии от OpenVPN (2002) и IPsec (где-то в том же районе)) технология VPN, которая была создана, по сути, одним человеком — zx2c4, которого в миру зовут Джейсоном Доненфельдом. Плюсы WG — скорость (особенно для Linux, где он может работать как модуль ядра начиная с 5.6 и Windows, где модуль для ядра выпустили порядка недели назад), низкие задержки, современная криптография, и простое использование конечным юзером.
|
||||
Ах да, еще UDP. UDP для туннелей это хорошо, потому что у TCP уже есть механизмы, которые позволяют ему работать на неидеальных соединениях, а UDP представляет из себя именно такое соединение. А когда вы засовываете TCP в TCP, то отказываетесь от большей части этих механизмов (инкапсулированный TCP-пакет будет гарантированно доставлен другой стороне, хотя протокол допускает недоставку), но все еще несете весь оверхед вида "хендшейк соединения для отправки хендшейка".
|
||||
Делать мы это будем на основе WireGuard — это относительно новая (разрабатыавется с 2016 года в отличии от OpenVPN и IPsec — первый это двухтысячные, а второй еще раньше) технология VPN, которая была создана, по сути, одним человеком — zx2c4, которого в миру зовут Джейсоном Доненфельдом. Плюсы WG — скорость (особенно для Linux, где он может работать как модуль ядра начиная с Kernel 5.6 и Windows, где модуль для ядра выпустили порядка недели назад), низкие задержки, современная криптография, и простое использование конечным юзером.
|
||||
Ах да, еще UDP. UDP для туннелей это хорошо, потому что у TCP уже есть механизмы, которые позволяют ему работать на неидеальных соединениях, а UDP представляет из себя именно такое соединение. А когда вы засовываете TCP в TCP, то отказываетесь от большей части этих механизмов (инкапсулированный TCP-пакет будет гарантированно доставлен другой стороне, хотя протокол допускает недоставку), но все еще несете весь оверхед вида "хендшейк соединения для отправки хендшейка".
|
||||
Не говоря уж о том, что инкапсулировать UDP в TCP — ничуть не лучшая идея, потому что сразу рушит все предположеия всяких скайпов о том, что лучше пропустить пару пакетов, чем уменьшить задержку: каждый UDP пакет в этом случае будет обязательно доставлен и доставлен корретно, не считаясь с тем, сколько это займет времени.
|
||||
|
||||
Особенно для одинокого пользователя-хакера приятна работа с шифрованием: нет ни необходимости в сертификатах и удостоверяющих центрах, ни в логинах-паролях, все, что нужно — это с тем пиром, с которым хотите установить соедиение, передать друг другу публичные ключи вашего интерфейса WG. Для больших компаний, это, конечно, будет скорее минусом, как и то, что WG — это только базовая часть полноценной большой инфраструктуры VPN.
|
||||
Но, например, именно WireGuard использовали в Cloudflare для своего WARP (https://blog.cloudflare.com/announcing-warp-plus/, https://blog.cloudflare.com/warp-technical-challenges/), правда, написав его собственную реализацию — boringtun.
|
||||
|
||||
Еще одним минусом WG является то, что трафик не обфусцирован — DPI может обнаружить трафик WireGuard, так что его можно довольно легко заблокировать (не говоря уж о блокировке UDP совсем, что почти не мешает вебу, но гарантированно ломает работу WireGuard). Для скрытия трафика рекомендуется использовать специализированное ПО — Cloak, Obfsproxy, Shadowsocks, Stunnel, SoftEther, SSTP, в конце-концов, SSH.
|
||||
Еще одним минусом WG является то, что трафик не обфусцирован — DPI может обнаружить трафик WireGuard, так что его можно довольно легко заблокировать (не говоря уж о блокировке UDP совсем, что почти не мешает вебу, но гарантированно ломает работу WireGuard). Для скрытия трафика рекомендуется использовать специализированное ПО — Cloak, Obfsproxy, Shadowsocks, Stunnel, SoftEther, SSTP, или, в конце-концов, простой SSH.
|
||||
|
||||
|
||||
Если очень упрощать, ключи работают следующим образом: у нас есть закрытый (приватный) ключ, из которого можно сгенерировать открытый, или публичный. Наоборот — нельзя, из открытого ключа мы получить закрытый никак не можем. После чего, мы можем зашифровать с помощью закрытого ключая какую-то строку, а при помощи открытого — расшифровать ее и тем самым убедиться, что у собеседника точно есть закрытый ключ, а значит, он тот, за кого себя выдает. Таким образом, мы можем без проблем публиковать открытый ключ — он всего лишь позволяет проверить подлинность автора, но не притвориться им. Это как в SSH — публичный ключ лежит на сервере, где его потеря небольшая беда: все что сможет сделать с ним злоумышленник это положить его на свой сервер, чтобы вы к нему могли подключиться с помощью закрытого ключа.
|
||||
@ -66,10 +64,12 @@ sysctl -p /etc/sysctl.conf
|
||||
Опционально (но очень удобно) сразу поменять hostname обоих серверов, чтобы не запутаться, где какая консоль:
|
||||
```bash
|
||||
hostnamectl set-hostname trickster-internal
|
||||
```
|
||||
```bash
|
||||
hostnamectl set-hostname trickster-external
|
||||
```
|
||||
|
||||
### Шаг второй: настраиваем WireGuard для связи двух серверов:
|
||||
## Шаг второй: настраиваем WireGuard для связи двух серверов:
|
||||
Для начала генерируем ключи. Запускаем два раза **wg genkey** и получаем два приватных ключа:
|
||||
```bash
|
||||
root@trikster-internal:~# wg genkey
|
||||
@ -81,19 +81,21 @@ root@trikster-internal:~# wg genkey
|
||||
Утилита wg genkey не делает никакой магии, это просто аналог чего-то типа "```echo $RANDOM | md5sum | head -c 32 | base64```", только наверняка более криптостойкое: мы просто генерируем 32 байта случайных значений и представляем их в виде base64.
|
||||
|
||||
Создаем два конфига:
|
||||
На **internal**: ```/etc/wireguard/wg-internal.conf```
|
||||
На **internal**:
|
||||
```/etc/wireguard/wg-internal.conf```
|
||||
```ini
|
||||
[Interface]
|
||||
Address = 10.20.30.1/32
|
||||
ListenPort = 17968
|
||||
PrivateKey = kOd3FVBggwpjD3AlZKXUxNTzJT0+f3MJdUdR8n6ZBn8=
|
||||
PostUp = iptables -t nat -A POSTROUTING -o `ip route | awk '/default/ {print $5; exit}'` -j MASQUERADE
|
||||
PostUp = ip rule add from `ip route | awk '/default/ {print $3; exit}'` table main
|
||||
PostUp = ip rule add from `ip addr show $(ip route | awk '/default/ { print $5 }') | grep "inet" | grep -v "inet6" | head -n 1 | awk '/inet/ {print $2}' | awk -F/ '{print $1}'` table main
|
||||
PostDown = iptables -t nat -D POSTROUTING -o `ip route | awk '/default/ {print $5; exit}'` -j MASQUERADE
|
||||
PostDown = ip rule del from `ip route | awk '/default/ {print $3; exit}'` table main
|
||||
PostDown = ip rule del from `ip addr show $(ip route | awk '/default/ { print $5 }') | grep "inet" | grep -v "inet6" | head -n 1 | awk '/inet/ {print $2}' | awk -F/ '{print $1}'` table main
|
||||
```
|
||||
|
||||
На **external**: ```/etc/wireguard/wg-external.conf```
|
||||
На **external**:
|
||||
```/etc/wireguard/wg-external.conf```
|
||||
```ini
|
||||
[Interface]
|
||||
Address=10.20.30.2/32
|
||||
@ -120,8 +122,25 @@ PostDown = iptables -t nat -D POSTROUTING -o `ip route | awk '/default/ {print $
|
||||
Кроме публичных и приватных ключей есть еще опция **PresharedKey**, которая обеспечивает дополнительное шифрование симметричным шифром. Ключ генерируется командой ```wg genpsk``` и кладется в **PresharedKey** в секциях **Peer** на обоих пирах. Неиспользование этой опции не снижает нагрузку по шифровке-расшифровке: если ключ не указан, используется нулевое значение ключа. Для действительного обеспечения пост-квантовой безопасности (невозможности расшифровки данных квантовыми компьютерами) разработчики рекомендуют дополнительный внешний квантово-устойчивый механизм хендшека (например, Microsoft SIDH, который они пиарят именно в таком контексте), чей найденный общий ключ можно использовать в качестве **PresharedKey**.
|
||||
|
||||
Заклинания в PostUp достаточно просты. ````ip route | awk '/default/ {print $5; exit}'```` — это команда для подстановки имени сетевого интерфейса, куда по-умолчанию выполняется маршрутизация: как правило, это тот интерфейс, в который воткнут провайдер или роутер.
|
||||
````ip route | awk '/default/ {print $3; exit}'```` — тоже самое, но подставляет IP-адрес дефолтного маршрута. Таким образом, первая страшная команда упрощается и превращается в ```iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE```, которая представляет собой включение NAT в режиме маскарада: сервер будет отправлять пришедшие ему пакеты пакеты во внешнюю сеть, подменяя в них адрес отправителя на свой, чтобы ответы на эти пакеты тоже приходили ему, а не исходному отправителю.
|
||||
Вторая страшная команда превращается в ```ip rule add from 95.93.219.123 table main``` — это необходимо для сервера **internal**, потому что иначе при активации маршрута 0.0.0.0/0 он начинает пересылать ответы на пакеты, приходящие ему на внешние адреса через туннель WG. Сервер на том конце, конечно, пересылает их по назначению, но тут уже не готов отправитель пакета: он присылает что-то на внешний адрес сервера **internal**, а ответ ему приходит с **external**. Естественно, при включенном rp_filter пакет отбрасывается. В этом случае сервер перестает быть доступен, например, по SSH снаружи, к нему надо коннектиться только по внутреннему IP wireguard-а. Отключать rp_filter у сервера это из пушки по воробьям, а вот дополнительное правило исправляет ситуацию.
|
||||
Таким образом страшная команда превращается просто в ```iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE```, которая представляет собой включение NAT в режиме маскарада: сервер будет отправлять пришедшие ему пакеты пакеты во внешнюю сеть, подменяя в них адрес отправителя на свой, чтобы ответы на эти пакеты тоже приходили ему, а не исходному отправителю.
|
||||
|
||||
Вторая команда уже немного сложнее, но она подставляет IP-адрес дефолтного маршрута.
|
||||
```bash
|
||||
`ip addr show $(ip route | awk '/default/ { print $5 }') | grep "inet" | grep -v "inet6" | head -n 1 | awk '/inet/ {print $2}' | awk -F/ '{print $1}'`
|
||||
```
|
||||
Сначала мы получаем, как и выше, сетевой интерфейс маршрута по-умолчанию:
|
||||
```bash
|
||||
root@:~# ip route | awk '/default/ { print $5 }'
|
||||
enp1s0
|
||||
```
|
||||
|
||||
Потом данные о состоянии этого интерфейса
|
||||
```bash
|
||||
root@:~# ip route | awk '/default/ { print $5 }'
|
||||
inet 192.168.88.70/24 brd 192.168.88.255 scope global dynamic enp1s0
|
||||
```
|
||||
И дальше вытаскиваем оттуда адрес, в данном случае 192.168.88.70.
|
||||
И команда превращается в ```ip rule add from 95.93.219.123 table main``` — это необходимо для сервера **internal**, потому что иначе при активации маршрута 0.0.0.0/0 он начинает пересылать ответы на пакеты, приходящие ему на внешние адреса через туннель WG. Сервер на том конце, конечно, пересылает их по назначению, но тут уже не готов отправитель пакета: он присылает что-то на внешний адрес сервера **internal**, а ответ ему приходит с **external**. Естественно, при включенном rp_filter пакет отбрасывается. В этом случае сервер перестает быть доступен, например, по SSH снаружи, к нему надо коннектиться только по внутреннему IP wireguard-а. Отключать rp_filter у сервера это из пушки по воробьям, а вот дополнительное правило исправляет ситуацию.
|
||||
|
||||
Продолжим писать конфиг: в него надо добавить секцию **Peer**, чтобы связать их с друг-другом.
|
||||
Я намеренно не привожу сразу готовые конфиги, потому что хочу показать механизм создания конфигов в ручном режиме — в свое время у меня были проблемы с тем, что я генерировал конфиги утилитами типа ```easy-wg-quick```, которые спрашивают тебя о названии клиента и красиво показывают QR-код прям в консоли, но отнюдь не способствуют пониманию того, как работает WG на самом деле.
|
||||
@ -145,17 +164,17 @@ PersistentKeepalive=25
|
||||
Там же, в **Endpoint** указываем адрес сервера **internal** и порт, который мы задали в **ListenPort**.
|
||||
С **AllowedIPs** при использовании ```wg-quick``` возникает небольшая путаница: это изначально именно, то как оно называется — список разрешенных IP-адресов к приему из туннеля: если что-то прилетает с другим src, оно будет отброшено. Но при использовании ```wg-quick``` она разумно считает, что если там есть какие-то устройства, которые могут послать пакет, то значит пакеты к этим устройствам надо маршрутизировать туда же, и создает маршруты на эти адреса, указывающие на туннель пира. В данных примерах **AllowedIPs** можно читать как "адреса, трафик на которые будут маршрутизироваться в туннель этого пира и с которых пир сможет отправить что-то в туннель".
|
||||
|
||||
Т.е. пункт "```AllowedIPs = 10.20.30.3/32```" означает, буквально, "только запросы на 10.20.30.3 (адрес пира WG) отправлять в туннель", т.е. дать доступ только до машины этого клиента.
|
||||
Пункт "```AllowedIPs = 192.168.88.0/24```" означает, что при запросе адреса из этой подсети, этот запрос уйдет в туннель клиента, и если у него включен форвардинг и ему доступна эта подсеть, то к ней можно будет получить доступ.
|
||||
А "```AllowedIPs = 0.0.0.0/0```" означает, что в туннель надо маршрутизировать весь трафик вообще. Правда, это не относится к трафику, например, локальной сети: приоритет у маршрута, который создастся из маски подсети и адреса шлюза, выше чем у 0.0.0.0/0. Также, маршрут 0.0.0.0/0 перебьют маршруты других пиров, если они будут в конфиге.
|
||||
В данном случае "```AllowedIPs=10.20.30.0/24```" — означает что трафик с **external** в подсеть 10.20.30.0-10.20.30.255 будет уходить в туннель к **internal**. В принципе, нужды в этом особо нет, **external** у нас исключительно выходная нода. Но вдруг мы как-нибудь захотим зайти оттуда по ssh на какую-нибудь другую машину.
|
||||
Т.е. пункт ```AllowedIPs = 10.20.30.3/32``` означает, буквально, "только запросы на 10.20.30.3 (адрес пира WG) отправлять в туннель", т.е. дать доступ только до машины этого клиента.
|
||||
Пункт ```AllowedIPs = 192.168.88.0/24``` означает, что при запросе адреса из этой подсети, этот запрос уйдет в туннель клиента, и если у него включен форвардинг и ему доступна эта подсеть, то к ней можно будет получить доступ.
|
||||
А ```AllowedIPs = 0.0.0.0/0``` означает, что в туннель надо маршрутизировать весь трафик вообще. Правда, это не относится к трафику, например, локальной сети: приоритет у маршрута, который создастся из маски подсети и адреса шлюза, выше чем у 0.0.0.0/0. Также, маршрут 0.0.0.0/0 перебьют маршруты других пиров, если они будут в конфиге.
|
||||
В данном случае ```AllowedIPs=10.20.30.0/24``` — означает что трафик с **external** в подсеть 10.20.30.0-10.20.30.255 будет уходить в туннель к **internal**. В принципе, нужды в этом особо нет, **external** у нас исключительно выходная нода. Но вдруг мы как-нибудь захотим зайти оттуда по ssh на какую-нибудь другую машину.
|
||||
|
||||
Повторяем генерацию публичного ключа с **external**:
|
||||
```bash
|
||||
echo "6CCRP42JiTObyf64Vo0BcqsX6vptsqOU+MKUslUun28=" | wg pubkey
|
||||
root@:~# echo "6CCRP42JiTObyf64Vo0BcqsX6vptsqOU+MKUslUun28=" | wg pubkey
|
||||
FulnUTovyyfgn5kmgPkcj2OjKRFGeLkaTsHtAOy6HW8=
|
||||
```
|
||||
Мы получаем публичный ключ сервера **external** и помещаем его в секцию peer сервера internal:
|
||||
Мы получаем публичный ключ сервера **external** и помещаем его в секцию peer сервера **internal**:
|
||||
```/etc/wireguard/wg-internal.conf```
|
||||
```ini
|
||||
[Peer] #external node
|
||||
@ -163,8 +182,7 @@ PublicKey = FulnUTovyyfgn5kmgPkcj2OjKRFGeLkaTsHtAOy6HW8=
|
||||
AllowedIPs = 10.20.30.2/32, 0.0.0.0/0
|
||||
```
|
||||
|
||||
|
||||
AllowedIPs тут ```10.20.30.2/32, 0.0.0.0/0``` — указываем, что за туннелем находится конкретный IP 10.20.30.2 и помимо этого, пробрасываем весь трафик, не связанный другими маршрутами, в этот туннель: **external** у нас это основная выходная нода нашего VPN, так что по умолчанию весь трафик будет направляться через нее, т.к. зарубежных маршрутов больше, чем российских, и логичнее фильтровать именно российские, а зарубежный трафик пустить по умолчанию через ноду в другой стране.
|
||||
**AllowedIPs** тут ```10.20.30.2/32, 0.0.0.0/0``` — указываем, что за туннелем находится конкретный IP 10.20.30.2 и помимо этого, пробрасываем весь трафик, не связанный другими маршрутами, в этот туннель: **external** у нас это основная выходная нода нашего VPN, так что по умолчанию весь трафик будет направляться через нее, т.к. зарубежных маршрутов больше, чем российских, и логичнее фильтровать именно российские, а зарубежный трафик пустить по умолчанию через ноду в другой стране.
|
||||
|
||||
Итак, два конфига:
|
||||
`/etc/wireguard/wg-internal.conf`
|
||||
@ -174,9 +192,9 @@ Address = 10.20.30.1/32
|
||||
ListenPort = 17968
|
||||
PrivateKey = kOd3FVBggwpjD3AlZKXUxNTzJT0+f3MJdUdR8n6ZBn8=
|
||||
PostUp = iptables -t nat -A POSTROUTING -o `ip route | awk '/default/ {print $5; exit}'` -j MASQUERADE
|
||||
PostUp = ip rule add from `ip route | awk '/default/ {print $3; exit}'` table main
|
||||
PostUp = ip rule add from `ip addr show $(ip route | awk '/default/ { print $5 }') | grep "inet" | grep -v "inet6" | head -n 1 | awk '/inet/ {print $2}' | awk -F/ '{print $1}'` table main
|
||||
PostDown = iptables -t nat -D POSTROUTING -o `ip route | awk '/default/ {print $5; exit}'` -j MASQUERADE
|
||||
PostDown = ip rule del from `ip route | awk '/default/ {print $3; exit}'` table main
|
||||
PostDown = ip rule del from `ip addr show $(ip route | awk '/default/ { print $5 }') | grep "inet" | grep -v "inet6" | head -n 1 | awk '/inet/ {print $2}' | awk -F/ '{print $1}'` table main
|
||||
|
||||
#external node
|
||||
[Peer]
|
||||
@ -193,24 +211,26 @@ AllowedIPs = 10.20.30.3/32
|
||||
```/etc/wireguard/wg-external.conf```
|
||||
```ini
|
||||
[Interface]
|
||||
Address=10.20.30.2/32
|
||||
PrivateKey=6CCRP42JiTObyf64Vo0BcqsX6vptsqOU+MKUslUun28=
|
||||
Address = 10.20.30.2/32
|
||||
PrivateKey = 6CCRP42JiTObyf64Vo0BcqsX6vptsqOU+MKUslUun28=
|
||||
PostUp = iptables -t nat -A POSTROUTING -o `ip route | awk '/default/ {print $5; exit}'` -j MASQUERADE
|
||||
PostDown = iptables -t nat -D POSTROUTING -o `ip route | awk '/default/ {print $5; exit}'` -j MASQUERADE
|
||||
|
||||
#internal node
|
||||
[Peer]
|
||||
PublicKey=MxnOnIlKfSyZyRutnYyoWHb3Izjalgf1t8F1oPJiyyw=
|
||||
AllowedIPs=10.20.30.0/24
|
||||
Endpoint=195.2.79.13:17968
|
||||
PersistentKeepalive=25
|
||||
PublicKey = MxnOnIlKfSyZyRutnYyoWHb3Izjalgf1t8F1oPJiyyw=
|
||||
AllowedIPs = 10.20.30.0/24
|
||||
Endpoint = 195.2.79.13:17968
|
||||
PersistentKeepalive = 25
|
||||
```
|
||||
|
||||
|
||||
Теперь можно поднять туннели на обоих серверах:
|
||||
```bash
|
||||
wg-quick down wg-external ; wg-quick up wg-external
|
||||
wg-quick down wg-internal ; wg-quick up wg-internal
|
||||
root@trikster-external:~# wg-quick down wg-external ; wg-quick up wg-external
|
||||
```
|
||||
```bash
|
||||
root@trikster-internal:~# wg-quick down wg-internal ; wg-quick up wg-internal
|
||||
```
|
||||
|
||||
|
||||
@ -224,6 +244,8 @@ peer: FulnUTovyyfgn5kmgPkcj2OjKRFGeLkaTsHtAOy6HW8=
|
||||
latest handshake: 13 seconds ago
|
||||
transfer: 180 B received, 92 B sent
|
||||
|
||||
```
|
||||
```bash
|
||||
root@trikster-external:~# wg
|
||||
...
|
||||
peer: MxnOnIlKfSyZyRutnYyoWHb3Izjalgf1t8F1oPJiyyw=
|
||||
@ -235,14 +257,16 @@ peer: MxnOnIlKfSyZyRutnYyoWHb3Izjalgf1t8F1oPJiyyw=
|
||||
```
|
||||
|
||||
|
||||
Если видим "latest handshake" и байты и в received и в sent, значит, все ок. Если ,байты только в send, без хендшейка и полученных данных, где-то в ошибка в конфиге или сервера недоступны друг для друга.
|
||||
Если видим "latest handshake: ... seconds ago" и байты и в **received** и в **sent**, значит, все ок. Если, байты только в **send**, без хендшейка и полученных данных, где-то в ошибка в конфиге или сервера недоступны друг для друга.
|
||||
|
||||
Если что-то пошло не так, и отвалился ssh, то достаточно перезагрузить сервер. Если все хорошо, и доступ к серверам сохранился, ставим туннели в автозапуск:
|
||||
Если что-то пошло не так, и отвалился ssh, то достаточно перезагрузить сервер — активные туннели сбросятся.
|
||||
Если все хорошо, и доступ к серверам сохранился, ставим туннели в автозапуск:
|
||||
```bash
|
||||
systemctl enable wg-quick@wg-external.service
|
||||
systemctl enable wg-quick@wg-internal.service
|
||||
root@trikster-internal:~# systemctl enable wg-quick@wg-internal.service
|
||||
```
|
||||
```bash
|
||||
root@trikster-external:~# systemctl enable wg-quick@wg-external.service
|
||||
```
|
||||
|
||||
|
||||
Попробуем посмотреть маршрут (рекомендую замечательную утилиту ```mytraceroute```, ```mtr```) без туннеля:
|
||||
```bash
|
||||
@ -269,18 +293,18 @@ HOST: trikster-internal.local Loss% Snt Last Avg Best Wrst StDev
|
||||
Все хорошо, трафик идет через внешний сервер — сначала на 10.20.30.2, который у нас выходная нода, а потом через его маршрутизаторы.
|
||||
|
||||
|
||||
### Шаг третий: добавляем конфиг клиента
|
||||
Создаем конфиг клиента, конечного устройства-пользователя VPN. За основу берем ```wg-external.conf```, потому что он такой же точно клиент, который подключается к internal, разница только в том, что **external** получает пакеты, а наш клиент будет отправлять.
|
||||
## Шаг третий: добавляем конфиг клиента
|
||||
Создаем конфиг клиента, конечного устройства-пользователя VPN. За основу берем ```wg-external.conf```, потому что он такой же точно клиент, который подключается к **internal**, разница только в том, что **external** получает пакеты, а наш клиент будет отправлять.
|
||||
|
||||
Генерируем ему сразу пару публичный-приватный ключ:
|
||||
```bash
|
||||
prk=`wg genkey` && pbk=`echo $prk | wg pubkey` && printf "Private: $prk\nPublic: $pbk\n"
|
||||
root@trikster-internal:~# prk=`wg genkey` && pbk=`echo $prk | wg pubkey` && printf "Private: $prk\nPublic: $pbk\n"
|
||||
Private: iPK7hYSU8TLVRD+w13nd3aGSYNLfnTx6zwdRzKcGb1o=
|
||||
Public: 26Vhud00ag/bdB9molvSxfBzZTlzdO+aZgrX3ZDncSg=
|
||||
```
|
||||
|
||||
|
||||
Конфиг почти такой же:
|
||||
Конфиг почти такой же (файл уже на вашем устройстве, не на сервере):
|
||||
```/etc/wireguard/wg-notebook-client.conf```
|
||||
```ini
|
||||
[Interface]
|
||||
@ -300,7 +324,7 @@ PersistentKeepalive = 25
|
||||
А в отличии от TCP в UDP нет никаких договоренностей о поддержании сессии, т.к. нет и самого понятия сессии. WG же построен таким образом, что при отсуствии трафика, попадающего в туннель, не будет и трафика между пирами, только хедшейки раз в две минуты. Опция **PersistentKeepalive** заставлет его посылать пустые пакеты каждые 25 секунд, предовращая потерю маршрута на промежуточных роутерах, потому что иначе возможна ситуация, когда мы будем раз за разом отправить пакеты, а до второго пира они доходить не будут, а он об этом и не будет знать.
|
||||
|
||||
|
||||
Дальше мы для нашего клиента добавляем еще одну секцию peer в конфиг на internal:
|
||||
Дальше мы для нашего клиента добавляем еще одну секцию peer в конфиг на **internal**:
|
||||
```ini
|
||||
#notebook-client node
|
||||
[Peer]
|
||||
@ -308,8 +332,8 @@ PublicKey = 26Vhud00ag/bdB9molvSxfBzZTlzdO+aZgrX3ZDncSg=
|
||||
AllowedIPs = 10.20.30.3/32
|
||||
```
|
||||
|
||||
Перезапускаем туннель на internal (```wg-quick down/up```), подключаемся.. Оп, хендшейк есть, данные пошли.
|
||||
Открываем какой-нибудь https://www.reg.ru/web-tools/myip, видим IP external ноды, и другую страну.
|
||||
Перезапускаем туннель на **internal** (```wg-quick down/up```), подключаемся.. Оп, хендшейк есть, данные пошли.
|
||||
Открываем какой-нибудь https://www.reg.ru/web-tools/myip, видим IP **external** ноды, и другую страну.
|
||||
|
||||
Таким же образом создаем конфиги для других клиентов. Если это мобильные устройства, то удобнее показать им QR. Он делается следующим образом: создаем в текущей папке конфиг как обычно, конечно, с новыми ключами и другим IP, какой-нибудь ```wg-moblie-client.conf``` и дальше командой ```qrencode -t ansiutf8 < wg-moblie-client.conf``` показываем прям в консоли QR, который сканируем с телефона.
|
||||
Это удобнее копирования файлов, но вам так же никто не мешает скинуть ```wg-moblie-client.conf``` на телефон или вообще ввести значения 7 полей вручную.
|
||||
@ -319,7 +343,7 @@ AllowedIPs = 10.20.30.3/32
|
||||
Давайте доделаем.
|
||||
|
||||
## Шаг четвертый: добавляем регион-зависимую маршрутизацию.
|
||||
Как мы помним, мы отправляем все данные с клиента на **internal**, а тот все данные отправляет на external, а тот уже своему провайдеру. Так же, мы помним, что у нас на **internal** "слабый" маршрут 0.0.0.0/0, который перебивается любыми другими маршрутами, а сам **internal** находится в российском сегменте. Значит, все, что нам надо — это как-то перехватить запросы на российские IP на уровне **internal** и перенаправить их не в туннель WG до **external**, а напрямую в сетевой порт самого сервера, в тот, через который он получает доступ в православный, российский интернет со скрепами и девицами в кокошниках.
|
||||
Как мы помним, мы отправляем все данные с клиента на **internal**, а тот все данные отправляет на **external**, а тот уже своему провайдеру. Так же, мы помним, что у нас на **internal** "слабый" маршрут 0.0.0.0/0, который перебивается любыми другими маршрутами, а сам **internal** находится в российском сегменте. Значит, все, что нам надо — это как-то перехватить запросы на российские IP на уровне **internal** и перенаправить их не в туннель WG до **external**, а напрямую в сетевой порт самого сервера, в тот, через который он получает доступ в православный, российский интернет со скрепами и девицами в кокошниках.
|
||||
|
||||
Давайте проверим предположение. На клиенте получим IP того же сбермаркета (```nslookup sbermarket.ru```), и посмотрим, как туда идет трафик (```traceroute 212.193.158.175```):
|
||||
```bash
|
||||
@ -340,7 +364,7 @@ default via 195.2.79.1 dev ens3 onlink
|
||||
...
|
||||
```
|
||||
|
||||
Вот 195.2.79.1 и ens3 и есть нужные нам данные. Используем уже знакомые нам подстановочные команды и создадим новый маршрут такой командой:
|
||||
Вот 195.2.79.1 и ens3 и есть нужные нам данные. Используем уже знакомые нам подстановочные команды и создадим новый маршрут:
|
||||
```bash
|
||||
target_ip="212.193.158.175/32"
|
||||
gateway=`ip route | awk '/default/ {print $3; exit}'`
|
||||
@ -370,7 +394,8 @@ HOST: vvzvladMBP14.local Loss% Snt Last Avg Best Wrst StDev
|
||||
5.|-- cdn.ngenix.net 0.0% 10 3.8 5.0 3.8 8.4 1.3
|
||||
```
|
||||
|
||||
Сбермаркет, правда, все еще не открываемся: видимо, проверяет на наличие VPN какой-то другой сервер, а не тот, в адрес которого ресолвится имя домена. Можно сходить на https://asnlookup.com/, вбить туда адрес, и получить принадлежность адреса к AS и заодно список подсетей этой AS (AS34879, OOO Sovremennye setevye tekhnologii). С большой вероятностью для более-менее крупных компаний это и будет их сетевая инфраструктура (ну или по крайней мере, инфраструктура, относящаяся к конкретному сайту), прописав для которой маршруты, вы обеспечите доступ на нужный вам сайт/сервис. Для мелких сайтов вы скорее всего получите AS хостера или дата-центра, но, во-первых, это тоже сработает, а во-вторых, мелкие сайты обычно и не закрывают иностранные диапазоны, потому что не испытывают проблем с DDOSом из-за границы.
|
||||
Сбермаркет, правда, все еще не открываемся: видимо, проверяет на наличие VPN какой-то другой сервер, а не тот, в адрес которого ресолвится имя домена.
|
||||
Можно сходить на https://asnlookup.com/, вбить туда адрес, и получить принадлежность адреса к AS и заодно список подсетей этой autonomous system (AS34879, OOO Sovremennye setevye tekhnologii). С большой вероятностью для более-менее крупных компаний это и будет их сетевая инфраструктура (ну или по крайней мере, инфраструктура, относящаяся к конкретному сайту), прописав для которой маршруты, вы обеспечите доступ на нужный вам сайт/сервис. Для мелких сайтов вы скорее всего получите AS хостера или дата-центра, но, во-первых, это тоже сработает, а во-вторых, мелкие сайты обычно и не закрывают иностранные диапазоны, потому что не испытывают проблем с DDOSом из-за границы.
|
||||
|
||||
Но можно сделать проще: засунуть в маршруты все адреса российского сегмента (спасибо [статье](https://habr.com/en/post/659655/) на хабре) и не париться о ручном добавлении.
|
||||
RIPE отдает их все в виде JSON вот по этому адресу: https://stat.ripe.net/data/country-resource-list/data.json?resource=ru
|
||||
@ -564,4 +589,4 @@ P.S. особые параноики могут запустить cloudflared
|
||||
|
||||
Пары ключей в статье — действующие, так что вы можете, ничего не исправляя в конфигах (только IP и имена адаптеров), залить их на два своих сервера и клиент и поиграться. Но для боевого применения ключи надо перегенерить, конечно.
|
||||
|
||||
Если кто-то захочет это все красиво обернуть в два докера и прикрутить к этому веб-интерфейс (потому что конфиги клиентов все же удобнее создавать в нем) — добро пожаловать в issues на гитхабе.
|
||||
Если кто-то захочет это все красиво обернуть в два докера и прикрутить к этому веб-интерфейс (потому что конфиги клиентов все же удобнее создавать в нем) — добро пожаловать в issues на гитхабе: [Trickster VPN](https://github.com/vvzvlad/trickster-vpn).
|
||||
|
BIN
article/comics_orig.psd
Normal file
BIN
article/comics_orig.psd
Normal file
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 379 KiB |
Loading…
Reference in New Issue
Block a user