В сети я больше известен как Revertron, давно занимаюсь развитием сети и сообщества Yggdrasil, разработкой клиента Yggdrasil для Android и другими вещами. В последнее время накопилось много разных новостей по этой теме. Но есть опасение, что многие до сих пор не знают что такое Иггдрасиль, поэтому я решил запилить цикл статей, и начать с более общего введения. Но, несмотря на то, что это введение, я постарался сжато, коротенько, расписать важнейшие механизмы сети в этой статье.
Оверлейные сети
В обычном интернете компьютеры и телефоны не общаются с другими напрямую. Трафик идёт через провайдера, потом через магистраль, через некий сервер сервиса, потом через провайдера на другом конце - и на каждом этапе его можно подсмотреть или заблокировать. А если оба устройства находятся за NAT (а сейчас за ним спрятано почти всё), они вообще не могут связаться друг с другом без сервера/посредника.
Оверлейные сети - это сети, построенные поверх обычного интернета. Они заводят своё адресное пространство, свою маршрутизацию и обычно своё шифрование. Снаружи их трафик выглядит как обычные зашифрованные соединения - а внутри живёт отдельная сеть со своими правилами.
Таких сетей много. Tor прогоняет трафик через цепочку узлов, чтобы скрыть, кто с кем общается. I2P - скрытая сеть для анонимных сервисов. CJDNS - зашифрованная IPv6-сеть (кажется, сдохла). А Yggdrasil - пожалуй, самая простая в использовании из подобных сетей.
Что такое Yggdrasil
Yggdrasil - это зашифрованная mesh-сеть, которая работает поверх обычного интернета (или напрямую по локалке). Каждый узел получает IPv6-адрес из диапазона 200::/7, причём адрес не назначается откуда-то сверху - он вычисляется из публичного ключа узла. Это называется криптоадресация: ваш адрес - это, по сути, и есть ваш ключ (скорее наоборот, но я тут упрощаю). Подделать его нельзя - любой может проверить, что владелец адреса действительно владеет соответствующим ключом (опять упрощаю).
Никаких центральных серверов нет. Нет реестров, нет единой точки отказа. Никто не может “выключить” сеть. Узлы сами находят друг друга и сами строят маршруты.
Yggdrasil часто называют наследником CJDNS - обе сети используют криптоадресацию и IPv6. Но Yggdrasil проще в настройке и использует другой подход к маршрутизации (spanning tree вместо DHT).
Из чего состоит сеть
Сеть - это узлы (ноды). Узел - любое устройство, на котором запущен Yggdrasil: компьютер, сервер, телефон, роутер, Raspberry Pi (любой дноплатник). У каждого узла есть пара криптоключей и IPv6-адрес, полученный из них.
Узлы соединяются друг с другом напрямую - это пиринговые связи, в народе скорее линки. Соединение идёт по TCP или TLS через обычный интернет. Не нужно соединяться со всеми подряд - достаточно связи хотя бы с одним узлом, и через него вы получаете доступ ко всей сети.
Из всех связей между узлами автоматически строится spanning tree - остовное дерево, основа маршрутизации (подробнее ниже).
Ещё есть multicast discovery: если несколько устройств с Yggdrasil подключены к одной локальной сети (например, к одному Wi-Fi), они найдут друг друга сами, без настройки.
Как поднять ноду
Тут всё просто:
Установить Yggdrasil. Есть пакеты для Windows, Linux (deb, rpm), macOS, Android.
Сгенерировать конфиг:
yggdrasil -genconf > /etc/yggdrasil.confСоздастся конфиг с новой парой ключей и нормальными настройками по умолчанию.
Добавить пиры. Можно взять парочку публичных пиров с официальной страницы. Достаточно вписать хотя бы один адрес в секцию
Peers:Peers: [ tls://some-public-peer.example.com:port ]Запустить:
yggdrasil -useconffile /etc/yggdrasil.conf
Всё. На устройстве появится сетевой интерфейс с IPv6-адресом 200::/7. Можно пинговать другие узлы, открывать сайты в сети Yggdrasil, запускать свои сервисы. Но, лучше, конечно, запустить yggdrasil потом как сервис.
Шифрование
Весь трафик в Yggdrasil зашифрован end-to-end. Это не настройка, которую нужно включать, так работает сеть. Даже если пакет пролетает через десяток чужих узлов, никто из них не может прочитать содержимое.
Под капотом используется несколько криптографических алгоритмов:
Ed25519 - цифровые подписи. У каждого узла есть пара ключей Ed25519. Открытый ключ - это идентификатор узла, из него выводится IPv6-адрес. Подписями защищены сообщения маршрутизации.
X25519 (Curve25519) - обмен ключами. Когда два узла начинают общаться, они через протокол Диффи-Хеллмана вырабатывают общий секрет. Ключи Ed25519 при этом конвертируются в формат Curve25519.
NaCl box (XSalsa20 + Poly1305) - собственно шифрование. Общий секрет используется для шифрования данных (XSalsa20) с проверкой целостности (Poly1305). Если кто-то изменит хоть один бит - получатель это увидит.
Forward secrecy - сессионные ключи регулярно обновляются (рэтчетинг). Даже если кто-то украдёт текущий ключ, расшифровать прошлый трафик не получится - старые ключи уже удалены.
Между непосредственными соседями соединение может дополнительно идти по TLS - это ещё один слой шифрования, защищающий служебные данные маршрутизации.
Маршрутизация
Это самая интересная часть, она состоит из нескольких частей.
Spanning tree и координаты
Представьте все узлы сети как точки, соединённые линиями. Из этих связей Yggdrasil строит spanning tree - дерево, покрывающее все узлы без циклов.
Корень дерева выбирается автоматически - им становится узел с наибольшим ключом. Про вычисление адреса из ключа можно глянуть в этой статье. Никакого голосования или центрального реестра нет. Каждый узел периодически рассылает соседям подписанное объявление: “я существую, вот мой ключ”. Соседи пересылают его дальше. Так объявления расходятся по сети, и каждый узел со временем узнаёт о существовании корня - просто потому, что его объявление “выигрывает” при сравнении ключей. Если корень уходит из сети, его объявления перестают обновляться, и корнем становится следующий по величине ключа узел.
У каждого узла в дереве есть координаты - последовательность чисел, описывающая путь от корня до этого узла. Каждое число - номер связи, через которую нужно пройти. Проще: у каждого узла его соседи пронумерованы, и координаты - это цепочка таких номеров. Если от корня идём через связь 3, потом 1, потом 5 - координаты будут [3, 1, 5]. Координаты обновляются сами при изменении сети.
Жадная маршрутизация
Когда узел отправляет пакет, он знает координаты получателя. Дальше работает простой принцип: на каждом шаге пакет передаётся тому соседу, который ближе к получателю по координатам.
Аналогия: вы в незнакомом городе, карты нет, но есть компас и вы знаете направление. На каждом перекрёстке выбираете улицу, которая ведёт ближе к цели. Путь не всегда самый короткий, но вы точно дойдёте.
Для spanning tree математически доказано, что такая маршрутизация всегда доставляет пакет. Каждому узлу достаточно знать только своих соседей и их координаты - не нужно хранить карту всей сети.
Оптимизация маршрута
Маршрут через дерево работает, но может вести далеко в обход. Поэтому после первого контакта Yggdrasil ищет прямой путь между узлами.
Когда путь найден, пакеты идут по source route - маршрут записан прямо в заголовке пакета как список номеров связей. Каждый узел по пути просто смотрит следующий номер и пересылает пакет в нужную сторону. Как список поворотов в навигаторе. Такой путь обычно заметно короче маршрута через дерево.
Bloom-фильтры
Остаётся вопрос: мы знаем адрес (то есть ключ) получателя, но как узнать его координаты? Для этого используются bloom-фильтры.
Каждый узел передаёт соседям bloom-фильтр с информацией о том, какие ключи “видны” через него (его собственный и ключи узлов за ним в дереве). Когда нужно отправить пакет незнакомому ключу, узел проверяет фильтры соседей и отправляет в нужном направлении специальный запрос - path lookup. Это не сами данные, а лёгкое сообщение вида “ищу узел с таким-то ключом”. Запрос передаётся по цепочке от узла к узлу (каждый следующий снова проверяет свои bloom-фильтры), пока не дойдёт до адресата. Адресат отвечает уведомлением со своими координатами и обратным маршрутом - после этого отправитель знает, куда слать данные. Bloom-фильтры компактны и быстры, хотя иногда дают ложные срабатывания - но это штатная ситуация, она нормально обрабатывается.
NAT traversal
В обычном интернете устройства за NAT недоступны снаружи - к ним нельзя подключиться, если они сами не начали соединение. Из-за этого мучаются все: VoIP, игры, IoT, торренты, и невозможно делать что-то крутое, с прямой связью.
В Yggdrasil этой проблемы нет, она предоставляет как бы другую среду. У каждого узла глобальный IPv6-адрес, и любой узел может связаться с любым другим - неважно, сколько NAT-ов между ними. Можно запустить сервер на телефоне за тремя NAT-ами, и он будет доступен из любой точки сети.
Что делают в сети Yggdrasil
Сеть экспериментальная, но ей уже лет семь, и ей пользуются:
Хостинг - сайты, файлохранилища, DNS-серверы, доступные по Yggdrasil-адресам.
Игры - мультиплеер напрямую между игроками, без проброса портов (правда только современные, поддерживающие IPv6).
Мессенджеры - P2P-общение без центральных серверов.
Удалённый доступ - подключение к домашним машинам без VPN.
Торренты - есть несколько ретрекеров, но с самим обменом как-то тухло, хотя и возможно.
Плюсы и минусы
Плюсы:
Просто поднять - пять минут и готово.
Сеть сама строит маршруты и подстраивается под изменения.
Всё зашифровано по умолчанию.
Адрес нельзя подделать (криптоадресация).
NAT не проблема.
Работает на Windows, macOS, Linux, Android.
Минусы:
Сеть всё ещё (7 лет как) считается экспериментальной, совместимость между версиями может ломаться.
Дополнительная задержка из-за оверлейной маршрутизации.
Сеть пока небольшая.
Не даёт анонимности - трафик шифруется, но факт общения между узлами не скрывается (это не Tor).
Заключение
Yggdrasil - эксперимент, но рабочий. Он показывает, что можно сделать децентрализованную зашифрованную сеть, которая при этом проста в использовании. Если хотите попробовать - поднять ноду можно за пять минут.
Я думаю написать несколько статей, раскрывающих разные стороны этой сети, если вам это интересно, напишите об этом в комментариях.
