Как стать автором
Обновить

Серверные IRC-тоннели в i2pd

В i2pd реализованы серверные тоннели, и их без проблем можно использовать для IRC-сервиса. Одна особенность — у всех пользователей в инфо стоит домен «localhost». На официальном же IRC-сервере в I2P (irc.postman.i2p, irc.dg.i2p, irc.echelon.i2p) у пользователей в инфо в поле домена стоит адрес клиента b32. Мы решили реализовать эту фичу в i2pd.

Для реализации этой штуки нам потребовалось заставить роутер представляться серверу IRC сервером WebIRC. WebIRC был создан для того, чтобы позволить пользователям подключаться не через IRC клиент, а, например, через браузер и, в то же время, показывать реальный IP пользователя. То есть, IRC-сервер не ругается на замену «localhost» на «b32» только если роутер представится WebIRC сервером, передав пароль.

Технически авторизация выглядит следующим образом.
Самой первой строкой при коннекте клиента, WebIRC-сервер шлет

WEBIRC your_password cgiirc clientB32address.b32.i2p 127.0.0.1

Нам надо реализовать это в роутере, чтобы мы могли подменять localhost на b32 адрес клиента.
IRC-клиент шлет примерно вот это:

USER username localhost localhost username

и мы подменяем домен:

USER username localhost jq6al5ajtwsngjgtxkiq764dm4psvu4tfwftkolurxw4xii2pz2a.b32.i2p username

Для реализации этой штуки создан дочерний класс I2PTunnelConnectionIRC от I2PTunnelConnection, где основная функция для WebIRC-кода выглядит так:

    void I2PTunnelConnectionIRC::Write (const uint8_t * buf, size_t len)
    {
    	if (m_NeedsWebIrc) {                // флаг, который ставится когда в конфиге тоннеля есть webircpassword
        	m_NeedsWebIrc = false;   // пуляем первым делом строчку WebIRC-авторизации
        	m_OutPacket.str ("");
                m_OutPacket << "WEBIRC " << this->m_WebircPass << " cgiirc " << context.GetAddressBook ().ToAddress (m_From->GetIdentHash ()) << " 127.0.0.1\n";
                I2PTunnelConnection::Write ((uint8_t *)m_OutPacket.str ().c_str (), m_OutPacket.str ().length ());
        }

    	std::string line;
        m_OutPacket.str ("");
        m_InPacket.clear ();
        m_InPacket.write ((const char *)buf, len);
        
        while (!m_InPacket.eof () && !m_InPacket.fail ())
        {
            std::getline (m_InPacket, line);
            if (line.length () == 0 && m_InPacket.eof ()) {
            	m_InPacket.str ("");
            }
            auto pos = line.find ("USER");                     // если находим, что клиент 
            if (pos != std::string::npos && pos == 0)           // шлет строчку USER blah blah
            {                                    // подменяем localhost на b32 адрес
                pos = line.find (" ");
                pos++;
                pos = line.find (" ", pos);
                pos++;
                auto nextpos = line.find (" ", pos);
                m_OutPacket << line.substr (0, pos);
                m_OutPacket << context.GetAddressBook ().ToAddress (m_From->GetIdentHash ());
                m_OutPacket << line.substr (nextpos) << '\n';
            } else {
                m_OutPacket << line << '\n';
            }
        }
        I2PTunnelConnection::Write ((uint8_t *)m_OutPacket.str ().c_str (), m_OutPacket.str ().length ());
    }

Настройка

В качестве IRC-сервера возьмем UnrealIRCd (один из тех, что поддерживают WebIRC протокол), вставляем в конфиг UnrealIRCd строки:

webirc {
       mask 127.0.0.1;
       password <your_password>; // no <> brackets around password!
};

В конфиге тоннеля (tunnels.cfg) указываем логин пароль для WebIRC:

[walker]
type = irc
host = 127.0.0.1
port = 5555          <--- UnrealIRCd listen port
crypto.tagsToSend = 20
keys = walker-key.dat
webircpassword = your_password     <---- это включает WebIRC

И всё, i2pd будет менять localhost на b32.
walker.i2p — пример такого IRC-сервера.
Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.