С годами мы обрастаем компьютерами и девайсами, которые ещё иногда называют хостами. Например, один виртуальный хост висит в стране чистого интернета, есть хосты на работе, дома, на даче, и т. д. Хотелось бы иметь средство для управления всеми ими, чтобы можно было из любого места зайти в любое другое, в режиме командной строки, разумеется. Например, с дачи нам хотелось бы зайти на рабочий компьютер, а с работы — на хост чистого интернета и т. д. Но на нашем пути встают препятствия: хосты находятся за NATом, на работе нет прав администратора, а в чистый интернет нас и подавно не хотят пускать.
Решение
Я одно время пробовал решать эту проблему методом множественных ssh соединений с проброской портов туда и обратно, но эта схема оказалась ненадёжной. Сессии имеют свойство рваться, не спасает даже autossh: сессия какое-то время после обрыва висит и не даёт запуститься следующей сессии. В общем, в ответственные моменты связь пропадала. Тогда я написал программу dnet, которая объединяет все мои хосты в единую сеть и позволяет с любого хоста управлять любым другим. Может быть, кому-то ещё она пригодится, или же, возможно, читатели выскажут какие-либо пожелания по её дальнейшей разработке.
Структура сети
Программа строит защищённые TCP-соединения между хостами и таким образом возникает сеть. В простейшем случае те хосты, которые находятся за NATом, подключаются к хосту в стране чистого интернета и образуется звездообразная структура, но структура сети может быть и более сложной. Для защиты соединений используется собственный алгоритм потокового шифрования, а его сеансовый ключ шифруется собственной реализацией метода RSA. На стороне каждого хоста при первом запуске программы генерируются необходимые ключи (1024-4096 бит). Далее хосты самостоятельно строят защищенное соединение между собой, вручную переносить ключи между хостами нет необходимости. Хосты периодически обмениваются сообщениями и определяют маршруты друг к другу внутри сети. При обрыве какого-либо соединения оно сразу же начинает строиться заново. Таким образом, длительных сбоев в сети не возникает.
Возможности программы
При старте программы мы попадаем в режим интерактивного ввода команды и можно управлять сетью. Есть определённый набор команд, причём действует правило: любую команду можно выполнить как будто мы её вводим на другом хосте. Для этого нужно перед командой написать имя хоста. Например, можно выполнить команду shell на другом хосте, введя имя этого хоста и далее команду.
Если ввести только имя хоста, то мы попадаем в оболочку shell на нём, причём авторизовываться там не надо — используются привилегии, данные программе dnet. На удалённом хосте можно запустить любое консольное приложение — например, mc или htop. Кроме того, можно скопировать файл или каталог с одного хоста на другой. Также можно перенаправить tcp или udp порты на другой хост. Наконец, если у нас есть tap интерфейсы на двух хостах, то между ними можно организовать туннель, т. е. передачу ethernet пакетов.
Где взять
Исходные тексты есть на гитхабе: https://github.com/dcherukhin/dnet. Бинарную программу для Linux (она же работает в Windows 10 с установленным пакетом bash) можно скачать по этой ссылке: https://dcherukhin.info/dnet. Есть версия на Qt под Android, с почти идентичной функциональностью. В частности, с Android-устройства можно давать команды, которые будут выполняться на любом хосте сети, а с компьютера можно зайти в shell на Android, причём права рута на андроиде не нужны. Я зарегистрировался на google play и разместил приложение там, но пока у них что-то синхронизируется. Если оно успешно досинхронизируется, то найти приложение можно будет под именем info.dcherukhin.dnet.
Пример использования
В простейшем случае запустить программу можно без параметров. Она подумает примерно секунд 5 и выдаст подсказку.
$ ./dnet
Generating keys... OK # генерируюстя ключи RSA 2048 бит
dnet>
По умолчанию программа включает ваш хост в единую сеть, а именно, подключается к моему серверу в стране чистого интернета. Далее можно узнать временное имя вашего хоста и поменять его на постоянное, которое стоит выбирать глобально-уникальным.
dnet> host
AB12CD34 ... # это временное имя
dnet> rename AB12CD34 MyHost666 # меняем на постоянное
dnet> host # проверяем
MyHost666 ...
Здесь стоит обратить внимание на безопасность, иначе каждый сможет выполнить что-нибудь на вашей машине. Есть такое понятие, как доверенные хосты. Если ни один не указан в качестве доверенного, то по умолчанию доверенными считаются все. Если же указать хотя бы один доверенный хост, то доверенными становятся только явно указанные. Все пакеты, приходящие внутри сети с недоверенных хостов, отбрасываются.
Допустим, наряду с упомянутым хостом у нас есть ещё один, Kitty777, и мы хотим сделать его доверенным. Тогда набираем (аналогичное надо сделать и на том хосте):
dnet> trust Kitty777
dnet> host Kitty777 # проверяем
Kitty777 ... trust ...
Теперь у нас есть две машины и между ними можно копировать файлы/каталоги, перенаправлять порты, делать туннели между tap интерфейсами. Примеры команд ниже:
dnet> copy file Kitty777:file
dnet> copy Kitty777:catalog catalog
dnet> tcp 2222 Kitty777 22
dnet> udp 7777 Kitty777 192.168.1.2:7
dnet> tunnel 1 Kitty777 2 # туннель между tap1 у нас и tap2 на Kitty777
Разумеется, подключаться к моему серверу не обязательно, можно организовать сеть исключительно из своих машин. Для этого при запуске каждого экземпляра программы dnet ей надо указать, на каких портах слушать и куда подключаться, например:
$ ./dnet -s 0.0.0.0:12345 192.168.1.5:12345 50.5.15.35:2222
Generating keys... OK # в этом случае генерируются ключи 4096 бит, ждать надо порядка минуты
dnet>
Что дальше
В первую очередь хотелось бы, чтобы всё описанное выше заработало с учётом масштабирования. Далее в планах есть end-to-end шифрование, т. е. если вы соединяете свои хосты через чужой сервер, то данные проходят через него зашифрованными. И, конечно, на случай нажатия красной кнопки хотелось бы написать TCP-соединения между хостами «на котиках». Таких, как на картинке в самом верху. До скорого.)
Автор: dcherukhin