diff --git a/article/IMG_1589.PNG b/article/1.png similarity index 100% rename from article/IMG_1589.PNG rename to article/1.png diff --git a/article/2.jpg b/article/2.jpg new file mode 100644 index 0000000..bed5c7a Binary files /dev/null and b/article/2.jpg differ diff --git a/article/369d462c6c7e1cd24831dce12b5b21c7.jpeg b/article/369d462c6c7e1cd24831dce12b5b21c7.jpeg deleted file mode 100644 index 4816602..0000000 Binary files a/article/369d462c6c7e1cd24831dce12b5b21c7.jpeg and /dev/null differ diff --git a/article/article_draft.md b/article/article_draft.md index cc73886..f397237 100644 --- a/article/article_draft.md +++ b/article/article_draft.md @@ -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). diff --git a/article/comics_orig.psd b/article/comics_orig.psd new file mode 100644 index 0000000..3036704 Binary files /dev/null and b/article/comics_orig.psd differ diff --git a/article/Комиксы-приколы-для-даунов-инстаграм-юмор-7273847.jpeg b/article/Комиксы-приколы-для-даунов-инстаграм-юмор-7273847.jpeg deleted file mode 100644 index 1b5cb03..0000000 Binary files a/article/Комиксы-приколы-для-даунов-инстаграм-юмор-7273847.jpeg and /dev/null differ