Comments 32
При использовании внешнего сервера – Вы вводите зависимость своей системы как от его работоспособности, так и от формата ответов, который вообще никак не стандартизирован, и который владелец сервера может поменять в любой момент. С теми же последствиями для вашей сети.
Теперь нужен STUN-сервер, к которому Ваша программа будет отправлять запросы. К счастью, такие сервера есть, каждая уважающая себя VOIP-компания держит таковой.
как-то не логично же. от чего ушли — к тому и вернулись…
что зависим от чьих-то серверов. компании обанкротились. сервера перестали существовать и всё — наша система перестала работать
он ведь не статичен…
а то и по первой цитате ж тоже можно актуализировать просто и всё…
1. Усложнение установки. Сейчас в поставке имеется только единственный обязательный элемент — бинарная программа, и конфиг — опционален. А при использовании внешнего списка STUNов — надо ещё в правильное место конфиг копировать, и как-то поддерживать его актуальность. Получается «развесистая» структура.
2. Эксплуатанты программы-кошелька — в основном не-админы, и никто не будет заморачиваться постоянным мониторингом актуальности списка. Работает — и ладно. Поэтому на практике, список будет обновляться вместе с обновлением программы. То есть для пользователей вынесение списка во вне пользы не принесёт.
3. Применённый алгоритм обхода списка требует, чтобы количество элементов списка было простым числом. В случае внешнего списка админ вряд ли будет соблюдать это требование, что приведёт к сильному редуцированию количества возможных путей обхода, что снизит балансировку нагрузки и снизит надёжность подсистемы при выходе из строя части серверов.
Но естественно, в других проектах и условия могут быть другими, и там будут резоны держать список в виде внешнего конфига. Но так как исходный текст программы доступен, авторы другого проекта могут творчески переработать наш код, и сделать список загружаемым.
1. Для чего число серверов должно быть простым?
2. Почему у StunSrv поле char name[30]; а не const char* name;?
2. Ну если нам заранее известны все длины name, мы можем выбрать такую длину, в которую поместятся все имена серверов. В данном случае это 30. Использование char* — это создание указателя на строку, а саму строку держать где-то ещё. Указатель — лишние 8 байт (либо 4 на 32-битовой машине). Средний неиспользуемый хвост строки — меньше. То есть при переходе к архитектуре с указателями, слегка возрастает размер используемой памяти, и без всякой иной пользы для проекта. Соответственно, возникает вопрос уместности такого решения.
А как быть если вам нужно добавить новые N STUN сервера? ждете пока число станет простым?
И как быть с «мертвыми» серверами, их нужно исключать из списка.
p.s.
а вы статический анализ С++ кода не используете?
cppcheck — нашел двойное удаление
github.com/emercoin/emercoin/blob/master/src/wallet.cpp#L496
github.com/emercoin/emercoin/blob/master/src/wallet.cpp#L502
и много других ошибок-предупреждений.
Мы это делаем примерно раз в полгода-год, при выпуске очередной версии программы. На самом деле, поддержка актуальности списка не критична, так как даже если 50% серверов «умрёт», то клиент в среднем после 2х попыток обхода получит искомый IP. Как видите, запас прочности системы колоссальный. В реальности же список актуальных серверов изменяется на ~10% в год, так что беспокоиться просто не о чем.
Ну а чтоб размер списка держать простым — это несложно. Всегда можно его уменьшить до ближайшего простого, выбросив несколько записей.
2. Про двойное удаление.
Этот код мы как есть импортировали из Биткоина. Если посмотрите, там стоит assert(false), который вызывает exception, то есть до второго удаление дело не доходит. Но за помощь в проекте — спасибо.
По крайней мере нет зависимости от протокола, а используемый STUN-сервер можно и поменять без больших проблем. Кроме того, серьезные компании не могут знать, кто сидит за UDP/STUN пакетом, клиент или кто-нибудь ещё, поэтому не могут НЕ отдать ответ, а их стабильность как целого намного выше стабильности одной отдельно взятой компании. Потом вообще будет как с NTP (ИМХО) — появится децентрализованная публичная служба STUN-ответов, независимая от какого-либо бизнеса. Ну или раньше будет полный IPv6.
Почему? Делают, ещё как, та же телефония Cisco всерьез проприетарная, закрытая и всё такое. Просто в случае STUN трафик настолько невелик, что теряется даже в потоке одного SIP-канала, что уж говорить о более толстых вещах, поэтому расходы на него можно "спускать на благотворительность", что-то с этим делать выйдет дороже, чем держать STUN-сервер.
Про недостатки такого подхода как раз и написано в первом абзаце статьи.
В приведённом примере используется единственный внешний WEB-сервер checkip.dyndns.org, с не-стандартизованным ответом. Если хозяевам сервиса вдруг вздумается поменять формат ответа, или просто прекратить его деятельность — все пользователи Mikrotik разом получат массу впечатлений.
/ip cloud set ddns-enabled=yes; :delay 2s;
:global currentIP [/ip cloud get public-address];
:if ( [:typeof $currentIP] != "ip" ) do={
:delay 10s; :set currentIP [/ip cloud get public-address]
}
# /log info message="$currentIP";
Здесь мы может Вам посоветовать взять из нашего проекта Emercoin файл stun.cpp, содержащий законченную подсистему определения внешнего IP через STUN. Благо что проект Open Source, и распространяется под лицензией GPL.
Я ошибаюсь, или подобное действие повлечет за собой необходимость раскрытия кода всего своего приложения? GPL, если мне не изменяет память, весьма своеобразная лицензия…
А Apple и не думает открывать все коды своей MacOS.
HISTORY
The gzip program was originally written by Jean-loup Gailly, licensed under the GNU Public Licence.
Matthew R. Green wrote a simple front end for NetBSD 1.3 distribution media, based on the freely re-distributable redistributable
distributable zlib library. It was enhanced to be mostly feature-compatible with the original GNU gzip
program for NetBSD 2.0.
This implementation of gzip was ported based on the NetBSD gzip, and first appeared in FreeBSD 7.0.
~ uname
Darwin
~ gzip --version
Apple gzip 264.50.1
lorca@defaultvps:$ uname
Linux
lorca@defaultvps:$ gzip --version
gzip 1.6
Copyright (C) 2007, 2010, 2011 Free Software Foundation, Inc.
Copyright (C) 1993 Jean-loup Gailly.
This is free software. You may redistribute copies of it under the terms of
the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.
There is NO WARRANTY, to the extent permitted by law.
Written by Jean-loup Gailly.
Почему надо хардкодить список серверов, если можно скачивать его со своего сервера при каких-то условиях?
Их в мире и так больше 200, зачем ещё один ставить? Не проще воспользоваться готовым?
Кроме того, 200+ независимых серверов — они понадёжнее будут, чем один. Вероятность выхода из строя всех их одновременно пренебрежимо мала.
> Почему надо хардкодить список серверов, если можно скачивать его со своего сервера при каких-то условиях?
И в случае усперной хакерской атаки на наш сервер, или когда к нам придут дяди с паяльником — клиенты скачают незнамо что, и начнут получать такие ответы, которые либо разрушат топологию сети, либо втянут пиринговую сеть под чужой контроль.
На самом деле, у нас сеть — подчёркнуто децентрализована, и создавать в ней зависимость от какого-либо сервера у нас нет желания.
Это конечно не исключает, что в какие-то моменты времени некий сервер случайно наберёт и более 0.5% запросов. Но в среднем этот процент будет сходиться к 0.041.
Ваше утверждение верно только для больших масштабов времени.
Итак, поехали:
Сервер выбирается из списка размером в 241 элемент. Вероятность выбора p=1/241.
Распределение равномерное, и обеспечивается криптографически стойким PRNG из библиотеки OpenSSL. Выбор какого-либо конкретного сервера в акте получения IP описывается процессом Бернулли с биноминальным распределением. Соответственно, среднеквадратичное отклонение от матожидания (среднего) для n экспериментов (актов запроса IP-адреса) есть:
сигма=sqrt(n * p * (1 — p))
Нас интересует такой n, после которого количество попаданий на тот же сервер в силу случайности распределения не превысит указанного мною параметра A=0.5%.
В качестве доверительного интервала примем три сигмы.
Пишем неравенство:
n * p + 3 * sqrt(n * p * (1 — p)) < n * A
Смысл неравенства:
количество заходов на сервер плюс тройная сигма меньше заявленного мною параметра A для того же количества заходов n.
Решаем неравенство относительно n, получаем:
n > p * (1 — p) / ((A — p) / 3)^2
Подставив числа, получаем:
n > 51398
Вот так работает статистика. Если желаете опровергнуть — формулы в студию.
Так как STUN у нас уже работает с 2014го, масштабы давно уже соблюдены, и далее будут соблюдаться ещё больше. И кстати, в новой версии программы будет использован тот список STUN-серверов, который приаттачен к данной статье, а там их поболее будет. И для этого списка n > 23764.
Как узнать свой внешний IP из программы