С годами мы обрастаем компьютерами и девайсами, которые ещё иногда называют хостами. Например, один виртуальный хост висит в стране чистого интернета, есть хосты на работе, дома, на даче, и т. д. Хотелось бы иметь средство для управления всеми ими, чтобы можно было из любого места зайти в любое другое, в режиме командной строки, разумеется. Например, с дачи нам хотелось бы зайти на рабочий компьютер, а с работы — на хост чистого интернета и т. д. Но на нашем пути встают препятствия: хосты находятся за 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-соединения между хостами «на котиках». Таких, как на картинке в самом верху. До скорого )
Комментарии (60)
Temmokan
07.04.2017 08:09+2Не проще использовать tinc в качестве простого способа создать «приватную сеть»?
Написание собственных решений — занятие полезное для тренировки навыков программирования, с этим не спорю.dcherukhin
07.04.2017 16:47Да, посмотрел, есть такой tinc. Правда, не разбирался, в точности ли он один в один. А как насчёт импортозамещения?)
Temmokan
07.04.2017 17:38+1Если найдёте платную версию — без сомнений замещайте. Больше года использую tinc в ситуации, описанной в статье — всем устраивает.
Erelecano
07.04.2017 21:10+1Вы не с того начали замещать. Тогда уж начните с того, что разработайте собственные берестяные компьютеры на триединой логике, в которой у вас каждый бит является всем тритом сразу, но при этом сам по себе(а еще в нем третий бит исходит от двух других, но при этом существует сам по себе), придумайте свои протоколы передачи данных стуком по березе и так далее. А если используете «вражеские» компьютеры и «вражеские» ОС, то не изобретайте велосипедов с треугольными колесами, а просто воспользуйтесь надежными решениями от людей у которых есть знания и мозги.
dcherukhin
07.04.2017 22:25У меня есть мозги.)
Erelecano
07.04.2017 22:26+1Были бы мозги, использовали бы tinc или peervpn, а не писали чушь про «импортозамещение».
dcherukhin
07.04.2017 22:50Чтобы использовать уже известное мозги как раз не особо нужны.
Erelecano
07.04.2017 23:27+1Что бы понять, что ты со своими низкими знаниями напишешь заведомо хуже, чем люди, которые этим занимаются давно и чей код отсматривают другие специалисты нужны мозги. А что бы писать про «импортозамещение» нужно их отсутствие.
dcherukhin
08.04.2017 10:02-3Я не хуже) Я специалист по дискретной математике и у меня результаты мирового уровня. Так что насчёт алгоритмов можно не сомневаться. А что касается маркетинга — тут, увы, есть над чем задуматься.)
ValdikSS
07.04.2017 09:56+2Занятно.
Если хотите избавиться от центрального сервера, можно генерировать идентификатор сети, который нужно ввести на всех компьютерах, которые хотят подключиться к этой сети. Для обнаружения хостов тогда можно будет использовать Bittorrent DHT (или даже публичные торрент-анонсеры), а идентификатор будет являться infohash раздачи. Порты для хостов за NAT можно пробрасывать привычными способами: STUN/TURN/ICE с серверами Google и Mozilla.
Еще можно написать userspace-реализацию протокола Teredo, которая не будет требовать root-прав, и использовать публичные серверы, тогда вообще заморачиваться с NAT не придется.ValdikSS
07.04.2017 10:06Если код писать не хочется, или для вас это не так просто, то можно воспользоваться клиентом сети I2P i2pd от orignal. I2P позволяет устанавливать прямые туннели, без дополнительных хопов, а также работать за NAT. Также можно воспользоваться и Tor, в последних версиях можно создавать неанонимные Hidden Service.
dcherukhin
07.04.2017 16:57Я немного не понял. Есть два хоста. Оба за NATом. Как нам передать данные с одного на другой. Много данных.
Кстати, Tor использую в качестве основного браузера, но в соцсети так ходить неудобно, да и Tor Bundle в последнее время стал падать. Так что в качестве альтернативы хожу по туннелю через вот эту программу dnet в другую страну. И i2p кстати у меня запущен, но опять же, чтобы не смущать своего провайдера i2p соединениями, они заходят ко мне по этому же туннелю.ValdikSS
07.04.2017 17:16+1Есть два хоста. Оба за NATом. Как нам передать данные с одного на другой.
Мы отсылаем UDP-пакеты с обеих сторон и с заданными портами отправления и назначения. Данные начинают передаваться.
Tor, I2P и Teredo установят вам соединение даже в том случае, если оба хоста за NAT.
orignal
07.04.2017 19:13Нужен третий, который пошлет второму сообщение, что первый хочет соединиться. Тогда второй попытается отправить пустое сообщение первому, в результате чего на NAT возникнет Hole Punch и первый сможет отправить UDP пакет второму. Аналогично Hole Punch возникнет у первого и они смогут обмениться пакетами.
Третий участник называется introducer-ом. Те, кто сидят за NAT должны при публикации указывать адреса introducer-ов вместо своих.dcherukhin
07.04.2017 22:56Тут надо очень хорошо представлять, как устроен NAT у конкретного провайдера. Возможны ситуации, когда тому, кто за натом, вообще ничего нельзя послать первым. Бывают ещё двойные наты, например, интернет через wifi от смартфона, который подключён к мобильному оператору.
orignal
07.04.2017 23:41Не получится соединиться с одним, получится с другим. Тоннель можно строить как угодно.
I2P адреса то через тоннели работают.
Lelik13a
07.04.2017 10:20+2А чем OpenVPN не угодил?
PaulZi
07.04.2017 10:44+1И правда? Поднять OpenVPN на 443 порту и никаких проблем)
dcherukhin
07.04.2017 16:45-1Tor, i2p, vpn — всё это известно и неинтересно.) А именно, включено в DPIные базы данных и при необходимости банится.
orignal
07.04.2017 21:00+1Хотелось бы узнать, каким образом DPI определяет I2P, кроме как сбором списка IP адресов всех узлов сети.
dcherukhin
07.04.2017 22:44Вот тут пишут о неком методе «connection probe».
orignal
07.04.2017 23:42Известная тема. Решается введением подписью адреса. Уже над этим работаем
dcherukhin
08.04.2017 09:58Вы из команды i2p/i2pd?
orignal
08.04.2017 15:12Я и есть главный разработчик i2pd.
dcherukhin
08.04.2017 17:02О-о! Кстати, dcherukhin.i2p/dnet ) Интересно, а протокол i2p где-нибудь формализован, чтобы можно было к вам подключиться? Когда-то смотрел код ip2d на предмет того, чтобы встроить его в свою систему. На тот момент мне не понравился C++, хотя сейчас это не проблема. И ещё, может ошибаюсь, но там есть какие-то тяжёлые зависимости вроде boost.
Shaltay
07.04.2017 11:46+4На что люди только не идут, чтобы ipv6 не внедрять…
dcherukhin
07.04.2017 16:44Поддерживаю. В связи с тем, что на ipv4 хостится много всего непотребного, предлагаю его полностью запретить с 1 января 2018 г. Думаю, профильный комитет одобрит.)
С другой стороны, даже при ip6v всё равно будет NAT на стороне провайдера, я так понял со слов представителя провайдера.ValdikSS
07.04.2017 17:18Для IPv6 NAT не нужен для повседневной жизни, и уж точно его не будет на стороне провайдера.
dcherukhin
07.04.2017 22:46Провайдеру виднее, что ему нужно для повседневной жизни.) А нужно ему снять денег за белые адреса.
Shaltay
10.04.2017 14:26С другой стороны, даже при ip6v всё равно будет NAT на стороне провайдера
А зачем?dcherukhin
10.04.2017 17:01Зачем-то им это надо. Например, мой провайдер, пока я ему не заплатил 130 руб за белый адрес, менял адреса каждый 5 минут, хотя это совсем не нужно. Но белый адрес в его понимании — это всего лишь постоянный адрес. А такого, чтобы были открыты порты снаружи у них в принципе не предусмотрено. Иметь какие-то службы дома — это уже экстремизм.)
Shaltay
10.04.2017 17:04+1А такого, чтобы были открыты порты снаружи у них в принципе не предусмотрено.
Это плохой, негодный провайдер.
koldyr
07.04.2017 13:53+2За усердие и находчивость безусловный плюс, но «Вы опасно некомпетентны в криптографии.»
dcherukhin
07.04.2017 16:37Знаю, что в программе есть дыры, буду их исправлять по мере необходимости.
Tomatos
08.04.2017 09:12А что считается необходимостью? Вы не подумайте, что я осуждаю — мне нравится ваш подход.
dcherukhin
08.04.2017 09:56Пока в сеть заходил только я, не было потребности даже вводить доверенные хосты, т. е. теоретически любой, подключившийся к сети, мог выполнить команду на моём компьютере, но о ней никто не знал. Когда я решил использовать сеть для обучения студентов, то всё же ввёл доверенные хосты. Вряд ли студенты будут специально что-то делать на моих машинах, но могут это сделать случайно. Сейчас другие люди сеть используют периодически, на пробу. Постоянных пользователей, кроме меня, нет. Когда они появятся, будет необходимость заняться исправлением более тонких уязвимостей, до которых можно дойти, хорошо проработав код.
manchelsi
07.04.2017 16:48+1бегло просмотрев исходный код, наблюдаем, что жестко прописан ip адрес
https://github.com/dcherukhin/dnet/blob/master/dnet/dnet_main.c#L111
Мы тут действительно говорим о «приватной» сети?dcherukhin
07.04.2017 16:52-1Да, есть такое. Это адрес моего центрального сервера. Эта константа работает только в режиме запуска без параметров, о чём была речь в тексте. В произвольном случае можно к нему не подключаться, а коннектиться между своими хостами. Вообще было бы здорово, чтобы сеть была децентрализованной, т. е. было много таких серверов, это придало бы ей больше приватности. Тогда можно было бы подумать о протоколе обмена такими адресами.
immaculate
07.04.2017 19:33Есть серьезные альтернативы:
https://www.zerotier.com/
http://meshbird.com/
Правда ни одной из них пока не пользовался, так как не было необходимости.
dcherukhin
07.04.2017 22:48Они уж больно серьёзные. У нас простое решение: загрузил бинарник, в котором лично я уверен, никакой установки и настройки, никаких прав root, запустил и заработало. Очень мне помогает на занятиях со студентами, когда мы проходим тему клиент-сервер. Одмины позаботились о том, чтобы компьютеры в классе были изолированы друг от друга, но оставили всё же выход в интернет.
Tomatos
08.04.2017 09:14в котором лично я уверен
Вы же понимаете, что это аргумент только для вас? :)dcherukhin
08.04.2017 09:57Да, но исходный код открыт. Если соберётся достаточное число пользователей (не буду говорить о вероятности этого события), то можно будет организовать сбор денег на независимую проверку.
sotnikdv
08.04.2017 16:54> Для защиты соединений используется собственный алгоритм потокового шифрования, а его сеансовый ключ шифруется собственной реализацией метода RSA.
Amateurs Produce Amateur Cryptography © Bruce Schneier
Нет, вы конечно молодец, но пускать такое решение в массы рисково ИМХОdcherukhin
08.04.2017 16:58Насчёт своего собственного алгоритма — тут я частично согласен, над его взломом никто особо не думал. А RSA — это наше всё, там основная сложность приходится на умножение длинных чисел, а это почти тема моей научной работы.
ls1
dcherukhin
Обычный ssh могут запросто блокировать по номеру порта или протоколу, то же и с vpn, а до моего им дела пока нет.) А вот и не стрёмно. Пример: вот прямо сейчас сижу в компьютерном классе в одном вузе, тут у меня нет прав администратора, но я вставил флешку с ключом одного хоста и приконнектился. Палится только ключ одного хоста. Если этот хост войдёт в сеть без моего участия, это будет заметно, там логируется время захода.
pansa
Ничто не мешает поднять ssh на нестандартном порту — 443, например.
А блокировать ssh «по протоколу» — это вот вы о чем сейчас?
dcherukhin
ssh уж наверняка есть в базе данных quosmos (это такой DPI). Даже и я видел, как в самом начале сессии он посылает какую-то фразу вроде своей версии. Если по телнету подключиться к 22-му порту, то в начале приходит такое: SSH-2.0-OpenSSH 7.2
Envek
openconnect (который реализация Cisco AnyConnect) вообще по HTTPS работает (фиг отличишь), так что если веб разрешён, то и openconnect разрешён.
Erelecano
sslh на 443 порту.
И там будет отвечать и https, и ssh, и openvpn
Что ваш DPI там найдет?
dcherukhin
Спросите у товарища майора.) Я (больше) не занимаюсь DPI. Думаю, что каждую сессию будут анализировать отдельно, и те протоколы, которые не запрещены, пропустят.
Envek
HTTPS без устроения «человека посередине» после установления соединения не поанализируешь: всё, что увидишь — белый шум.
dcherukhin
Над человеком посередине уже работают, сам видел.
orignal
Времена и длины пакетов можно мерять и делать выводы о характере трафика.
OmManiPadmeHum
еще как вариант SoftEther VPN использовать
dcherukhin
Спасибо. Чем больше разных протоколов, тем больше можно спутать карты ловцам человеков.