Mesh-роутер — это просто
С того момента, когда cjdns добавили в официальный репозиторий OpenWRT, процесс подготовки mesh-роутера стал просто тривиален. Саму установку OpenWRT на роутеры описывать подробно не вижу смысла, т.к. это популярная тема. На многих официально поддерживаемых роутерах задача установки свободной прошивки сводится к простому скачиванию Factory архива и скармливанию его стандартной форме обновления прошивки на заводской системе. Главное, чтобы не было блокировки на установку сторонней прошивки, но и в этом случае, как я полагаю, будет множество обходных путей.
До появления официальной поддержки пакетов cjdns, приходилось возиться немного больше. Можно было собирать пакеты самому или искать собранные кем-то пакеты и устанавливать их. Еще были прошивки от энтузиастов с уже установленным нужных ПО. В любом случае, приходилось повозиться чуть больше, чем сейчас.
Итак, мы имеем роутер на OpenWRT, выполняющий обычные функции домашнего маршрутизатора. Администрировать все это дело будем левой кнопкой мышки в LuCY.
Установка
Как написал выше, OpenWrt Chaos Calmer 15.05 имеет необходимые пакеты в официальном репозитории. Заходим в меню System -> Software. Обновляем список и устанавливаем пакеты luci-app-cjdns и cjdns. Последний является зависимостью первого и должен автоматически установиться.
Mesh режим
После установки, cjdns сразу начнет работать. Т.е. обычная установка проходит в один шаг. Но мы хотим, чтобы роутер не только соединялся с cjdns нодами в нашей локальной сети, но и стал активным участником меш-сети. В меню появляется раздел Services -> cjdns. Во вкладке Overview отображаются все текущие соединения. Если на ваших домашних компьютерах работает cjdns, с большой вероятностью роутер установит с ними соединение в меш-режиме. Нам нужно добавить 802.11s WiFi сеть. Делается это так же просто:
идем в раздел Network -> WiFi,
на нужном физическом интерфейсе нажимаем Add,
по текущей договоренности на форуме cjdroute.net выбираем 11 канал в 2.4 ГГц,
поле Mode будет 802.11s — WiFi mesh,
Network у нее будет отдельный, т.к. нам не нужно, чтобы эти участники попадали во внутреннюю Lan сеть (я создал новый с именем Mesh),
SSID: hyperboria_mesh,
защищать эту сеть не нужно.
В разделе Network -> Interfaces у нас появится новая сеть. Protocol я выбрал unmanaged — нам нет необходимости присваивать участникам обычные IP адреса.
Так же можно добавить простую точку доступа без защиты с именем, например, cjdroute.net, которая подключает устройства к этой сети. Это позволит подключать девайсы, не умеющие в 802.11s, но умеющие в cjdns, к hyperboria.
Теперь идем в Services -> cjdns -> Settings, спускаемся к пункту Ethernet Interfaces и добавляем там нашу новую сеть (если забыли имя, то можно подсмотреть в списке Network -> Interfaces). Beacon Mode я выбрал 2, чтобы он не только ожидал там специальные Ethernet фреймы, с помощью которых будет устанавливать mesh-соединения, но и сам рассылал такие. Так же стоит убедиться, что в домашней локальной сети тоже соединяемся. Если провайдер предоставляет локалку свою, можно попробовать и через WAN интерфейс соединяться с другими клиентами провайдера.
Оверлэйные UDP-соединения (он же UDP транспорт)
Естественно, глупо ожидать, что по всему городу рассыпаны уже эти коробочки, и функционирует полноценная сеть на всю страну. Тем более, что между городами крайне низкая плотность населения. Для дополнительной связи нам нужно будет добавить коннекты через UDP транспорт. Это обычный оверлэйный режим поверх других сетей типа интернета. Примерно так работает TOR. Только в данном случае, соединения будут устанавливаться напрямую без попыток анонимизации и потери скорости.
Стоит так же упомянуть о том, что здесь есть непонятый многими, но очень важный момент — необходимость добавлять такие соединения вручную и устанавливать связь с теми, с кем обменялся ключами и паролями. На первый взгляд, эта процедура идиотская и создает лишние сложности в установке: ведь в оверлэйных сетях типа Tor и I2P этого делать не надо — есть bootstrap ноды, которые передают вам список всех адресов других участников. Однако, это удобство является уязвимостью — в том же Китае к этим нодам подключаются атакующие, получают список всех участников и блокируют соединения с этими адресами и самой нодой. Т.е. удобство добавляет в систему единую точку отказа и ставит под угрозу стабильность работы вообще.
Обменяться ключами и адресами можно на том же форуме cjdroute.net в специальном разделе. Вероятно, позже, ваши друзья и коллеги тоже присоединяться к сети и обменяются с вами нужными данными.
Добавление соединений происходит так же просто в разделе Services -> cjdns -> Peers. Там можно добавить пароли для входящих подключений (помните, что для этого надо роутеру иметь белый IP адрес и открыть UPD порт) и информацию об исходящих подключениях. Каждое новое соединение увеличивает стабильность работы. А благодаря простоте интерфейса, добавлять новые можно будет между делом в течение пары минут.
На этом пункте настройку полноценного mesh-роутера можно считать завершенной. Теперь ваш роутер будет выполнять свои обычные функции домашнего маршрутизатора, но при появлении таких же сознательных соседей, будет создавать с ними новые коннекты, независимые от вашего провайдера.
Бонусный пункт: защищенный выход в интернет
Cjdns — это по сути решение, которое позволяет создавать распределенную виртуальную частную сеть. Благодаря своей распределенной архитектуре эта VPN вырастает в огромную Semi-meh (оверлэйная + меш) сеть и строит новый интернет будущего (Hyperboria).
Если на ваших компьютерах установлен и правильно настроен CJDNS, значит они будет «видеть» друг друга, даже если оба находятся в тысячах километрах друг от друга за провайдерскими NATами. CJDNS предоставляет IPv6, и все поддерживающие его программы будут отлично работать. Этакий хамачи здорового человека. Но кроме собственно доступа в hyperboria и соединения личных устройств в единую сеть хотелось бы в пару кликов сделать защищенный туннель в обычный интернет.
Настройки на сервере, который будет выпускать нас в интернет.
Допустим, у нас есть VPS в какой-нибудь нормальной стране, где интернет не подвергается агрессивным нападкам. Мы настроили на этом VPS такую же CJDNS ноду и хотим иметь возможность выхода через нее в интернет. Для этого в конфиге cjdns нашей VPS нужно добавить входящий туннель в разделе ipTunnel -> allowedConnections. Например:
<
«publicKey»: «kdddddgfgsftrtrtrnrmnmnmgnmdfndmfnmdfnmdnfmdfmdndfdf0.k», // Публичный ключ нашего клиента. Для роутера достаем в настройках Services -> cjdns -> Settings
«ip4Address»: «192.168.45.10», // IP адрес клиента, который будет автоматически присвоен
«ip4Prefix»: 24 // Префикс. Соответствует маске 255.255.255.0
>
В консоли добавляем IPv4-адрес на интерфейс туннеля и разрешаем Forwarding, чтобы выпускать в интернет клиентов.
ip addr add dev tun0 192.168.45.1/24
echo 1 > /proc/sys/net/ipv4/conf/all/forwarding
Добавляем роут и правила для firewall
ip route add dev tun0 192.168.45.0/24
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
iptables -A FORWARD -i eth0 -o tun0 -m state —state RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i eth0 -o tun0 -j ACCEPT
Теперь наш VPS сервер может заменять нам обычные платные VPN сервисы. Кстати, по моим ощущениям, настройка Получается гораздо быстрее и проще чем того же OpenVPN.
Я на этом пункте попался в интересную ловушку. Захотел подключать сразу и роутер, и ноутбук, выдавая им разные IPv4 адреса, но в одной подсети. Как выяснилось, оно для этого не предназначено, первый вписанный клиент нормально роутился, а второй просто получал адрес, но даже не мог пинговать сервер. Если хотите несколько устройств подрубать, то надо делать разные подсети. Это может пригодиться, например, для обеспечения защищенного выхода в интернет поверх не доверенного интернет-соединения.
Настройки на роутере
Тут все просто. Идем в Services -> cjdns -> IP Tunnel и в Outgoing connections добавляем публичный ключ cjdns из конфига нашей VPS ноды. Прописанный IP присваивается автоматически. Маршрутизация клиентов роутера в интернет через этот VPN настраивается добавлением соответствующих правил на фаерволе.
Вы можете прописать адрес нашего сервера 192.168.45.1 в качестве шлюза для всех соединений, а можете просто добавлять статические роуты и перенаправлять запросы только для конкретных сайтов: Network -> Static routes
В данном случае, я сделал защищенные и устойчивые соединения для всех устройств в моей домашней сети на рутрекер и btc-e.com. По какой-то странной причине, мне захотелось сделать подключения к этим сайтам более безопасными.
В этом бонусном пункте есть и обратный вариант: сделать роутер таким сервером. Например вы находись где-то в гостях или пользуетесь общественным WiFi и хотите сделать соединения более безопасными. В той же вкладке настроек роутера добавляем входящие соединения, а на ноутбуке исходящие. Немного другие правила для роутинга — и вот вам более защищенная связь из любого места.
Источник
Создание и настройка Mesh-сети на собственном опыте, а также немного цифр и аналитики
Все началось с того, что на очередном обсуждении дальнейшей судьбы проекта, над которым я тогда работал, кто-то сказал: «А давайте прикрутим меш-сети, ведь это круто, модно и молодёжно!». И именно с этого момента началась моя неравная борьба с меш-сетями, из которой мы с товарищем вышли победителями. Хоть и с небольшой оговоркой.
Итак, что у нас имелось на текущий момент: несколько умных устройств (на базе nrf52840), уже умевших общаться с телефоном по «блютусу», странная среда разработки и я, абсолютно непонимающий, что такое меш-сети. То, как я неделю колдовал с бубном, чтобы arm-овский компилятор съел NRF mesh SDK – это отдельная история. Но после поражения в этой битве и переход на GCC дела пошли быстрее.
Давайте для начала разберемся в том, что такое меш-сеть. Это распределенная сеть, в которой каждый узел может отправлять и принимать сообщения. Узлы, по сути своей, делятся на два типа – проивижионер (создатель сети) и провижиони (рядовой узел сети). В чем их отличие: провижионер – это создатель сети, тот, кто выдает всем адреса, конфигурирует остальные узлы и вообще следит за тем, жива сеть или нет. Если по какой-то причине такой узел выпадает из сети, то сеть не умирает, но пропадает возможность удалять и добавлять узлы. В моем случае — это было равносильно смерти всей сети. Провижиони сам ничего не умеет, он способен только отправлять и принимать сообщения и то, при условии, что провижионер дал ему адрес. Выделяют два отдельных процесса: провижионинг (добавление в сеть и выделение адреса) и конфигурирование, при котором узлу сообщается кому он может слать свои сообщения. Сами сообщения бывают двух видов: юникаст и бродкаст. Каждый узел знает группу, к которой он принадлежит. Адрес этой группы задает проивижионер при конфигурировании. На основе этого адреса он фильтрует входящие сообщения, предназначенные только его группе.
На каждом узле (железке) меш-сети должна находиться модель. Модель – это сущность, которой провижионер присваивает уникальный адрес, и которая может, если она клиент, отправлять запросы, а если сервер – то отвечать на них. Для моей задачи требовалось сделать возможным, чтобы модель могла бы и принимать сообщения, и отправлять их сама. В принципе, никто не запрещает вам на одной железке создать несколько моделей с разными адресами, одна из которых будет отвечать за передачу сообщений, а другая – за прием. Единственное, о чем вам стоит помнить, что конфигурация узла происходит в полуручном режиме. То есть вы не можете написать в коде провижионера: if (state == Configure)
Кстати, я говорил, что на вашем узле может располагаться несколько сущностей, и по умолчанию, у вас уже будет находиться health-client/server, config-client/server. Health-client находится на провижионере и отвечает за опрос health-server на обычных узлах. Этот уровень абстракции позволяет провижионеру контролировать состояние сети, кто жив, а кто мертв. Между девайсами постоянно будут летать сообщения с подобными опросами. Config-client также находится на провижионере, и его задача – просто последовательно выполнить те команды конфигурации, которые вы ему задали изначально. Никакой гибкости здесь не предполагается – что написано один раз, будет выполняться для каждого узла независимо от внешних параметров системы. Аналогично, config-server находится на стандартных узлах, и его цель – отвечать на запросы клиентов.
Итак, когда основные моменты рассмотрены, давайте перейдем к архитектуре. Я в то время находился под сильным впечатлением от прочтения Code Complete, да и уровень сокомандников не позволял написать откровенный говнокод. Тогда я решил акцентировать внимание на подобии архитектуры, а не просто запихнуть весь код в один крутой мега-класс. Ну, или сделал вид.
Вот что из этого получилось:
- У нас есть класс BLEMesh, у которого есть методы Send и Receive, соответственно для приема и отправки сообщений по меш-сети. Также, есть метод SetGroup, с помощью которого можно выставить, к какой группе принадлежит узел. StartProvisioning, как нетрудно догадаться, делает узел провижионером и начинает создавать сеть, последовательно добавляя в нее всех соседей.
- Чтобы не засорять главный интерфейс реализацией, а уж тем более обращениями к SDK, был создан класс BLEMEshImpl. Инстанс этого класса является полем BLEMesh, который, в свою очередь, просто обращается к нему и вызывает соответствующие методы. Здесь реализованы методы по инициализации и запуску всего стека BLE и BLE Mesh, а также регистрируется куча колбеков на разные случаи жизни. Здесь же инициализируется третья сущность – модель.
- Модель в моем случае представляет из себя класс, отвечающий только за передачу и прием данных по меш-сети. При попытке отправить сообщение, модель проверяет, содержится ли в сообщении уникальный адрес или адрес группы и, в зависимости от этого, вызывает разные функции из SDK. Если уникальный адрес не выставлен – сообщение отправляется в группу, то есть всем.
Также, уже изначально была заложена возможность покрытия всего этого шедевра юнит-тестами, а каждый класс был унаследован от интерфейса с приставкой I. Это нужно было сделать, чтобы в последствии безболезненно замокать обращения к Mesh SDK.
В процессе разработки также выяснилось несколько интересных моментов. Класс, который у нас все время занимался записью данных во флэш, перестал работать. Почему? Да потому что BLE Mesh забирал себе все процессорное время, и бедный StorageManager бессильно возвращал коды ошибок. Предложенный же библиотекой MeshStorageManager представлял из себя обычную мапу (словарь) и не мог удовлетворить наших потребностей. Нам нужно было не просто сохранять данные куда-то в память. Нам важно было самим обозначить конкретный адрес. И поэтому, мы не нашли ничего лучше, чем просто отключать BLE Mesh на время записи во флэш.
Следующее, что стало для нас открытием – провижиони не может в ран-тайме становиться профижионером и требует перезагрузки всего узла. Возможно, все-таки существует какой-нибудь способ, но мы его не нашли.
Третий пункт плавно вытекает из нашей задачи: прикрутить BLE Mesh к уже работающему девайсу. А ведь уже был написан код, позволяющий общаться с устройством по блютус с телефона. Как же нам совместить два таких разных SDK? Хорошо, что в комплекте с SDK шел пример их сосуществования, позволивший немного упростить нашу задачу. Почему немного, а потому что она до сих пор не была нами решена. Поколдовав с настройками и приоритетами, мы пришли к следующему. Если устройство когда-то было спэйрино с телефоном, но на телефоне были удалены настройки, то повторный пейринг не проходит. Скорее всего это проблема конкретно нашей реализации, но пока это лечится только отключением пересылки событий SoftDevice в меш стек, как описано здесь. Костыли наше все. Во всех остальных случаях нет никаких проблем с пейрингом устройства и приложения, установлением подключения и работы с Mesh в роли профижионера или профижиони. Может быть в дальнейшем получится исправить эту проблему, и я добавлю заветный UPD.
Ну и настало время аналитики, которую мы делали для себя. Моим коллегой был собран следующий тестовый стенд: четыре узла, один из которых подключен проводом к ПК (через переходник USB-UART). Он будет являться провижионером в нашей сети, а также именно с него будут уходить все запросы в сеть. В том числе у нас есть планшет, с помощью которого мы будем измерять помехи в работе меш-сети, при использовании обычного блютуса. На ПК используется модифицированная программа modpoll, которая реализует тестовые сценарии и выводит в файл результаты измерений. В программе реализовано измерение круговой задержки (RTT) — интервала времени между отправкой запроса и получением ответа. Есть ограничение для круговой задержки — все что больше 1000 мс считается потерей.
Очевидно, что при совместном сосуществовании BLE и Mesh невозможно обойтись без потерь. В наше случае мы рассматривали простейший случай, когда провижионер опрашивает одного провижиони без пересылок. Для оценки выполнялось 100 запросов подряд.
В «case 1» ни одно устройство не подключено к приложению, в «case 2» провижиони подключен к приложению и имеет место некоторый трафик через BLE, а в «case 3» провижионер подключен к приложению. Первый график показывает распределение потерь, второй – распределение круговой задержки. Как мы видим из первого графика — работа провижионера на «два фронта» обходится в дополнительные 5% потерь. В случае с быстродействием получается, что, когда установлено соединение, снижается нагрузка на стек BLE (прекращается сканирование эфира), и обработка событий Mesh происходит быстрее.
Надеюсь, этот короткий обзор Mesh-сетей и анализа их производительности был вам полезен и интересен. Еще увидимся!
Источник