В 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-сервер шлет
Нам надо реализовать это в роутере, чтобы мы могли подменять localhost на b32 адрес клиента.
IRC-клиент шлет примерно вот это:
и мы подменяем домен:
Для реализации этой штуки создан дочерний класс I2PTunnelConnectionIRC от I2PTunnelConnection, где основная функция для WebIRC-кода выглядит так:
В качестве IRC-сервера возьмем UnrealIRCd (один из тех, что поддерживают WebIRC протокол), вставляем в конфиг UnrealIRCd строки:
В конфиге тоннеля (tunnels.cfg) указываем логин пароль для WebIRC:
И всё, i2pd будет менять localhost на b32.
walker.i2p — пример такого IRC-сервера.
Для реализации этой штуки нам потребовалось заставить роутер представляться серверу 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-сервера.