PurpleI2P / i2pd

🛡 I2P: End-to-End encrypted and anonymous Internet
https://i2pd.website
BSD 3-Clause "New" or "Revised" License
3.26k stars 423 forks source link

Поддержка Windows (компилятор vs2013) #5

Closed chertov closed 7 years ago

chertov commented 10 years ago

Собрал исходники с помощью Visual Studio 2013. Вроде бы компилируется, запускается, но есть проблемы. При первом запуске создает два файла router.info и router.keys (в них какая-то каша). Виндовский фаервол спросил разрешить или нет, видимо сервер открыл порт. Пишет такой лог:

netDb doesn't exist
Start listening port 17007
Creating zero hops inbound tunnel...
I2NP msg received len=545, type=23, msgID=0
VariableTunnelBuild
VariableTunnelBuild 1 records
Record 0 is ours
TransitTunnel gateway: 1736841068 created
I2NP msg received len=545, type=23, msgID=555
VariableTunnelBuild
VariableTunnelBuild 1 records
VariableTunnelBuild reply for tunnel 1847386387
TunnelBuildResponse 1 records.
Ret code=0
Inbound tunnel 1847386387 has been created
I2NP msg received len=545, type=23, msgID=1
VariableTunnelBuild
VariableTunnelBuild 1 records
Record 0 is ours
TransitTunnel endp

и падает в void Tunnel::Build (uint32_t replyMsgID, OutboundTunnel * outboundTunnel) в этой точке:

EncryptBuildRequestRecord (*hop->router,
    CreateBuildRequestRecord (hop->router->GetIdentHash (),
...

При последующих запусках не может распарсить router.info и соответственно вылетает.

При компиляции был собран boost 1.55 и crypto++ 5.6.2 и возникли следующие проблемы: 1) Компилятор vs2013 пока не умеет спецификаторы default, но, к счастью, их всего несколько. В коде эти конструкторы не использовались, поэтому большую часть просто закомментил (классы IdentHash и RouterInfo).

2) В винде нету endian.h, использовал такую версию https://gist.github.com/panzi/6856583

3) тип ssize_t отсутствует, не разбирался пока, просто убрал одну s)

4) Отсутствует gmtime_r. Пока оставил так:

#ifdef _WIN32
        gmtime_s(&tm, &t);
#else
        gmtime_r(&t, &tm);
#endif

5) функция sleep в винде начинается с заглавной буквы Sleep

Под линуксом не собирал, думаю стоит поставить линукс и искать 10 отличий) Очень бы хотелось иметь кросплатформенные исходники и собирать проект родным компилятором под виндой.

orignal commented 10 years ago

С падением известная проблема "netDb doesn't exist". Там надо директорию netDb из официального клиента скопировать туда, откуда запускаете. Я это еще не успел починить.

Насчет поддержки Windows мне трудно что либо сказать, посколько я под него никогда в жизни не писал. Насколько я понимаю, вы упретесь там в условные переменные.

ssize_t убирать одну s не следует потому что переменная может принимать отрицательные значения.

endian.h действительно специифична для Линукса, даже для FreeBSD нужно писать #include <sys/endian.h>. Собираюсь сделать заголовчный файл содержаший в себе все платформо-зависимые вещи.

Вообще если есть желание адаптировать проект для Windows, добро пожаловать - всегда буду рад помощи.

orignal commented 10 years ago

Кстати собирать с помощью mingw не пробовали?

chertov commented 10 years ago

Условные переменные это что в < condition_variable >, < condition_variable_any >? vs2013 их вроде бы умеет...

с помощью mingw не собирал (думаю он соберет), но хотелось бы чтобы и студия умела собирать, там вроде бы кроме спецификаторов default ничего такого принципиального не мешает сборке.

Под Windows смогу периодически собирать/проверять... Хотел еще под андройд попробовать собрать в виде библиотеки и запустить, но там, надеюсь, еще проще получится.

Пробовал собрать под linux mint 64, использовал QtCreator в качестве среды, собрал, но бинарник не запускался... там какая-то путаница с бустом и крипт++ версиями библиотек видимо разные под 32 и 64 битные платформы понаставил... Какой средой вы пользуетесь и под каким линуксом собираете?

orignal commented 10 years ago

Вопрос с условными переменными это не вопрос компилятора, а ядра ОС. В виндах насколько я знаю используется функция WaitForSingleObject. По сути своей задача сводится к тому чтобы уложить поток спать до тех пор пока кто то его не разбудит (например пришедшие данные). Возможно что уже тоже реализовано.

Под андроид естественно соберется, только какой в этом смысл пихать C++-ый код в среду, изначально рассчитанную под джаву?

Собираю в gcc как под x86_64, так и под raspberry. Убунту и дебиан.

mikhail4021 commented 10 years ago

chertov, в NetDb.cpp найди строчку:

RouterInfo * r = new RouterInfo (it1->path ().c_str ());

там проблема одна, не знаю как решить. Раз ты сам собирал, то у тебя видимо есть решение.

chertov commented 10 years ago

Да, сделал вот так)

//std::string path_str = it1->path().string();
//RouterInfo * r = new RouterInfo(path_str.data());
RouterInfo * r = new RouterInfo(it1->path().string().data());

orignal, мне кажется ваша реализация будет куда эффективнее реализации на яве мой, далеко не первой свежести, мобильник предпочел бы ее)

orignal commented 10 years ago

Господа, у вас наверное буст более свежий. Они с какого то релиза (50-ого вроде) поменяли filesystem

chertov commented 10 years ago

я собирал последний 1.55... там у них было раньше несколько версий filesystem v2 v3... можно было девфайном выбрать какой использовать

mikhail4021 commented 10 years ago

похоже на то, что свежий. Но это же не значит, что нам нужно ограничиться от 1_46 до 1_50 =) просто придется чуть-чуть подумать

chertov commented 10 years ago

где в проекте vs2013 переменные задать можно? $(BOOST), $(CRYPTOPP) их значения

mikhail4021 commented 10 years ago

ну вообще я сделал по обычной практике. Определяешь переменные среды $(BOOST), $(CRYPTOPP) к соответствующим папочкам, и все работает.

chertov commented 10 years ago

Это прямо в системе? Там есть user-defined macros в них смотрю пусто. Лучше тоже так сделаю... пишу в основном в 2008... там все по-другому)

orignal commented 10 years ago

Но это же не значит, что нам нужно ограничиться от 1_46 до 1_50 У меня была лучшая идея его выкинуть нафик поскольку он там не особо нужен - только по директориям при чтении netDb ходить.

mikhail4021 commented 10 years ago

Это прямо в системе?

да прямо в винде. я обычно "Переменные среды пользователя" определяю, но можно и системные переменные в принципе.

mikhail4021 commented 10 years ago

ssize_t предлагаю заменить на int64_t

orignal commented 10 years ago

Да можно просто на int. Это ж в одном месте где нужно от указателя идти в отрицательном направлении.

mikhail4021 commented 10 years ago

ptrdiff_t там же разность указателей

orignal commented 10 years ago

Кстати по поводу разных бустов. Можно использовать #ifdef BOOST_VERSION > 10500

chertov commented 10 years ago

я бы еще вынес проект vs2013 в отдельную папку, а то она там создает "мусор"... в отдельную папку и .gitignore настроить

orignal commented 10 years ago

Убедительная просьба не тащить буст без особой необходимости, а стараться использовать функции из std. Убрал зависимость от boost::thread

orignal commented 10 years ago

Действительно файлы используемые только для компиляции под windows имеет смысл вынести в отдельную папку, а именно: файлы проекта, I2PEndian.cpp и LittleBigEndian.h

mikhail4021 commented 10 years ago

про I2PEndian.cpp и LittleBigEndian.h не согласен. только неудобства создавать. Остальное скоро вынесу.

2014/1/10 orignal notifications@github.com

Действительно файлы используемые только для компиляции под windows имеет смысл вынести в отдельную папку, а именно: файлы проекта, I2PEndian.cpp и LittleBigEndian.h

Reply to this email directly or view it on GitHubhttps://github.com/orignal/i2pd/issues/5#issuecomment-32023800 .

orignal commented 10 years ago

Я бы лично создал файл platform.h содежащий #include и #include для юниксов и I2PEndian.h и соотвествующий бустовской файл для windows и включал бы его вместо все платформо-зависимых хэдеров.Такой подход позволил бы с одной столроны легко добавлять новые платформы, а с другой стороны платформо-зависимые вещи.

Кстати нужели под windows нет Makefile-ов, т.е. зачем только чтобы скомпилировать нужно запускать IDE и открывать проект? А как тогда билд системы работают?

chertov commented 10 years ago

Из более-менее удобного есть cmake... он сам сделает проект для разных версий IDE на разных платформах, скомпилит тем что найдет, но вообще достаточно часто вижу кросплатформенные либы, которые тащат за собой файл проекта студии в отдельной папке. Для меня это нормально... я привык всегда работать из IDE. И, кстати, проект с cmake сейчас удобно вести в Qt Creator. Компилить он его сможет компилятором от vs2013, либо каким-то другим. Собрать проект студией можно и не открывая ее. Для прогона тестов, например.

mikhail4021 commented 10 years ago

это все здорово, но я, например, за cmake не возьмусь

2014/1/10 chertov notifications@github.com

Из более-менее удобного есть cmake... он сам сделает проект для разных версий IDE на разных платформах, скомпилит тем что найдет, но вообще достаточно часто вижу кросплатформенные либы, которые тащит за собой файл проекта студии в отдельной папке. Для меня это нормально... я привык всегда работать из IDE. И. кстати, проект с cmake сейчас удобно вести в Qt Creator. Компилить он его сможет компилятором от vs2013, либо каким-то другим.

Reply to this email directly or view it on GitHubhttps://github.com/orignal/i2pd/issues/5#issuecomment-32042325 .

orignal commented 10 years ago

Лично мне в этих всех IDE не нравится понятие проекта, в котором смешаны параметры для компиляции или линковки с настройками самой среды. А если завтра надумал использовать другую среду?

mikhail4021 commented 10 years ago

кстати, по поводу надумывания. Может растащить это дело на статическую библиотеку и сам роутер. или не нужно это?

2014/1/10 orignal notifications@github.com

Лично мне в этих всех IDE не нравится понятие проекта, в котором смешаны параметры для компиляции или линковки с настройками самой среды. А если завтра надумал использовать другую среду?

Reply to this email directly or view it on GitHubhttps://github.com/orignal/i2pd/issues/5#issuecomment-32043528 .

orignal commented 10 years ago

Статическую библиотеку чего именно? Вынести создание потоков куда то наружу или что? Сейчас по сути своей роутера как такового еще нет, есть примитивый файл i2p.cpp который в дальнейшем будет запускать демона.

mikhail4021 commented 10 years ago

я сам еще не до конца понял по коду, это может куда-то быть воткнуто еще как клиент? Описания никакого нет, того что сделано.

2014/1/10 orignal notifications@github.com

Статическую библиотеку чего именно? Вынести создание потоков куда то наружу или что? Сейчас по сути своей роутера как такового еще нет, есть примитивый файл i2p.cpp который в дальнейшем будет запускать демона.

Reply to this email directly or view it on GitHubhttps://github.com/orignal/i2pd/issues/5#issuecomment-32046021 .

orignal commented 10 years ago

Клиент на данный момент не планируется, планируется сделать обращение к I2P сайтам внутри класса HTTPServer, работающий по принципу анонимайзера. В дальнейшем возможно доступ через внешние сокеты.

chertov commented 10 years ago

Мне нравится подход как сделали в cjdns. Там создается виртуальная сетевушка и ей присваивается ipv6 адрес, который является публичным ключом. Все что передается этому адресу внутри cjdns шифруется им, расшифровать может только обладатель приватного ключа, который сгенерировал этот ipv6 адрес.

Не знаю можно ли подобный подход применить в i2p... т.е. создать виртуальное сетевое устройство, и однозначно сопоставлять автоматически идентификаторы i2p с ipv6 адресом. Тогда и все что ipv6 поддерживает поддерживалось бы автоматически.

Такой сетевой интерфейс можно вытащить на физический порт роутера и получится физическая сеть работающая исключительно в i2p.

orignal commented 10 years ago

У I2P размер хэша 32-байта, а у ipv6 всего 16. Так что не получится. Вот добавить свой протокол прямо в ядро лиункса это можно, я над этим уже думал. Вообще суть вопроса тут такая. Сейчас есть два файла Streaming и NetDb, фактически являющиеся "точками входа" для всех клиентских задач. Класс Stream это логически аналог сокета, в который можно писать и читать передаваемые данные. Для его создания нужен LeaseSet той стороны, который берется из NetDb: либо он там уже есть либо его следует запросить.

chertov commented 10 years ago

да, в это и уперся) делал демку под виндой, которая поднимала сетевой интерфейс и могла писать/читать из него пакеты. Но чтобы сопоставить однозначно ipv6 с i2p хэшем нужно как-то хитрить... рассматривал некоторое варианты, но если бы размеры адресов совпадали было бы практически идеально) В вики может страничку сделаю со своими идеями. В любом случае если будет удобная либа с "сокетами" i2p, то такую штуку можно реализовать отдельным проектом.

orignal commented 10 years ago

Подскажите как сделать демона под windows, т.е. процесс работающий в фоновом режиме баз всякого интерфейса. Собираюсь наконец сделать приложение демоном, но под windows вряд ли системный вызов fork есть.

mikhail4021 commented 10 years ago

ну вообще это как-то так делается http://code.msdn.microsoft.com/windowsdesktop/CppWindowsService-cacf4948

2014/1/19 orignal notifications@github.com

Подскажите как сделать демона под windows, т.е. процесс работающий в фоновом режиме баз всякого интерфейса. Собираюсь наконец сделать приложение демоном, но под windows вряд ли системный вызов fork есть.

Reply to this email directly or view it on GitHubhttps://github.com/orignal/i2pd/issues/5#issuecomment-32695380 .

orignal commented 10 years ago

А можно как то попроще используя std там или boost? Или может я сделаю для юникса, оставив место под #ifdef WIN32?

mikhail4021 commented 10 years ago

на самом деле это самое простое, что есть. тут винапишные функции уже в класс обернуты проще только просто win32 приложение консольное сделать, но у него будет окно. если будет простой интерфейс типа run()/pause()/stop , то под винду я наверное смогу доделать в #ifdef'е

2014/1/19 orignal notifications@github.com

А можно как то попроще используя std там или boost? Или может я сделаю для юникса, оставив место под #ifdef WIN32?

Reply to this email directly or view it on GitHubhttps://github.com/orignal/i2pd/issues/5#issuecomment-32695532 .

orignal commented 10 years ago

А как официальный клиент выглядит? Как консольное приложение или как сервис?

mikhail4021 commented 10 years ago

точно НЕ как консольное приложение. да и там же под джавамашиной все работает, так что технология другая, и сравнивать не совсем правильно

2014/1/19 orignal notifications@github.com

А как официальный клиент выглядит? Как консольное приложение или как сервис?

Reply to this email directly or view it on GitHubhttps://github.com/orignal/i2pd/issues/5#issuecomment-32699481 .

orignal commented 10 years ago

Кстати вы не пробовали запускать? На данный момент у меня весьма стабильно получает главную страницу Флибусты. Надо:

  1. Скопировать директорию netDb из официального клиента туда откуда запускается.
  2. Доступ извне, потому что будут приходить входящие соединения. Добавить в функцию main первой строчкой i2p::context.OverrideNTCPAddress (<внешний IP>, <порт>); Потом сделаю чтение из конфиг файла.
  3. Смотреть браузером 127.0.0.1:7070. Если все правильно то там достаточно быстро будут появляться новые тоннели.
  4. Как только создадутся несколько входящих и несколько исходящих тоннелей нажать на ссылку Flibusta

Возможно придется сделать несколько попыток потому что скорее всего сначала будет сообщение "LeaseSet not found" но вскоре она его найдет и загрузить страницу.

chertov commented 10 years ago

orignal, уууууу! Поздравляю!!!) Руки чешутся проверить под виндой, но пока не могу, к сожалению...

chertov commented 10 years ago

По-быстрому скомпилил... вываливается в некоторых местах

При первом запуске

// Выдает когда читает что-то из netDb
// Unhandled exception at 0x75D0C41F in i2pd.exe: Microsoft C++ exception:
// CryptoPP::CryptoMaterial::InvalidMaterial at memory location 0x002EEFBC.

// из cryptlib.h
//  //! throws InvalidMaterial if this object fails Validate() test
//  virtual void ThrowIfInvalid(RandomNumberGenerator &rng, unsigned int level) const
//==>   {if (!Validate(rng, level)) throw InvalidMaterial("CryptoMaterial: this object contains invalid values");}

    void RouterInfo::ReadFromBuffer ()
    {
        std::stringstream str (std::string (m_Buffer, m_BufferLen));
        ReadFromStream (str);
        // verify signature
        CryptoPP::DSA::PublicKey pubKey;
        pubKey.Initialize (i2p::crypto::dsap, i2p::crypto::dsaq, i2p::crypto::dsag, CryptoPP::Integer (m_RouterIdentity.signingKey, 128));
        CryptoPP::DSA::Verifier verifier (pubKey);
        int l = m_BufferLen - 40;
 ====>  if (!verifier.VerifyMessage ((uint8_t *)m_Buffer, l, (uint8_t *)m_Buffer + l, 40))
        {   
            LogPrint ("signature verification failed");
        }   
    }   

еще при последующих запусках


// когда читает router.info  в   void RouterInfo::ReadFromFile (const char * filename)
// выкидывает 
/// Run-Time Check Failure #2 - Stack around the variable 'value' was corrupted.
void RouterInfo::ReadFromStream (std::istream& s)
{
...
// тут в конце 
===>  }
mikhail4021 commented 10 years ago

netDb где находится? просто сейчас установил официальный клиент, а там не вижу, и поиск винды не помогает. Может что запустить нужно, чтобы ее сгенерило?

chertov commented 10 years ago

У меня тут "C:\Users\user\AppData\Roaming\I2P\netDb" лежит, отсюда ее кидал в рабочую папку где бинарник сохраняет router.info

mikhail4021 commented 10 years ago

äÏÂÁ×ÉÔØ × ÆÕÎËÃÉÀ main ÐÅÒ×ÏÊ ÓÔÒÏÞËÏÊ i2p::context.

OverrideNTCPAddress (<×ÎÅÛÎÉÊ IP>, <ÐÏÒÔ>);

ÞÔÏ ÅÓÔØ "×ÎÅÛÎÉÊ IP"? ÎÅ ÐÏÎÑÌ × ËÁËÏÍ ËÏÎÔÅËÓÔÅ

2014/1/21 chertov notifications@github.com

õ ÍÅÎÑ ÔÕÔ C:\Users\user\AppData\Roaming\I2P\netDb ÌÅÖÉÔ, ÏÔÓÀÄÁ ÅÅ ËÉÄÁÌ × ÒÁÂÏÞÕÀ ÐÁÐËÕ ÇÄÅ ÂÉÎÁÒÎÉË ÓÏÈÒÁÎÑÅÔ router.info

Reply to this email directly or view it on GitHubhttps://github.com/orignal/i2pd/issues/5#issuecomment-32845696 .

orignal commented 10 years ago

chertov, этот кусок с VerifyMessage можно временно закомментировать без ущерба для функциональности. А вообще неплохо бы узнать чему равно значение переменной m_BufferLen в этот момент, возможно из-за ipv6 они стали слишком длинные и уже не влазят в 2K. mikhail4021, в последнем сообщении вижу только крякозябры

mikhail4021 commented 10 years ago

странно, действительно крякозябры. хотя писал ответом с гуглпочты и там все норм.

Добавить в функцию main первой строчкой i2p::context.OverrideNTCPAddress (<внешний IP>, <порт>);

чей внешний IP, я что-то не понимаю. мой?

orignal commented 10 years ago

Да. Ваш. Я не знаю где у вас он - на вашем компе или где то на маршутизаторе. Если на маршутизаторе то надо пробросить какой нибудь порт к вам, если такой возможности нет то остается только ipv6. Если маршутизатор поддерживает UPnP то будет работать по UDP по протоколу SSU, который я правда еще не сделал

mikhail4021 commented 10 years ago

std::cout << m_BufferLen << "\n"; if (!verifier.VerifyMessage ((uint8_t )m_Buffer, l, (uint8_t )m_Buffer + l, 40)) { LogPrint ("signature verification failed"); }

733 выводит, так что должно влазить

orignal commented 10 years ago

И после этого сразу грохается?