Вести с полей
Привет всем.
Медленно и печально продираюсь сквозь терни подключения к FB3 минуя fbclient.dll. Добрался до настройки шифрования подключения (op_crypt). Разобравшись что к чему, я даже немного оживился — если делать по уму, то конструкция получается достаточно красивой.
Изначально объект порта отправлял и получал пакеты напрямую через объект сокета. С внедрением шифрования пришлось спрятать сокет за интерфейсом RemoteFB__PortStream:
class RemoteFB__PortStream:public RemoteFB__SmartInterface { public: virtual void Write(size_t cb, const void* pv)=0; virtual void FlushWriteBuf()=0; virtual void Read(size_t cb, void* pv)=0; };//class RemoteFB__PortStream
Для этого интерфейса соорудил класс, который реализует алгоритм шифрования «Arc4» и читает/пишет данные через нижележащий объект с интерфейсом RemoteFB__PortStream:
void RemoteFB__PortStream__Crypt_Arc4::Write(size_t const cb, const void* const pv) { CHECK_READ_PTR(pv,cb); assert(m_spBaseStream); const byte_type* p=reinterpret_cast<const byte_type*>(pv); const byte_type* const e=(p+cb); for(;;) { assert(m_write_buf_beg<=m_write_buf_cur); assert(m_write_buf_cur<=m_write_buf_end); for(;;++p,++m_write_buf_cur) { if(p==e) return; if(m_write_buf_cur==m_write_buf_end) break; (*m_write_buf_cur)=m_Encoder.transform(*p); }//for[ever] assert(m_write_buf_cur==m_write_buf_end); m_spBaseStream->Write(m_write_buf_end-m_write_buf_beg, m_write_buf_beg); //throw m_write_buf_cur=m_write_buf_beg; }//for[ever] }//Write //------------------------------------------------------------------------ void RemoteFB__PortStream__Crypt_Arc4::FlushWriteBuf() { assert(m_write_buf_beg<=m_write_buf_cur); assert(m_write_buf_cur<=m_write_buf_end); assert(m_spBaseStream); //1. сброс буферизированных данных if(m_write_buf_cur!=m_write_buf_beg) { m_spBaseStream->Write(m_write_buf_cur-m_write_buf_beg, m_write_buf_beg); m_write_buf_cur=m_write_buf_beg; }//if assert(m_write_buf_cur==m_write_buf_beg); //2. сброс буфера на нижнем уровне m_spBaseStream->FlushWriteBuf(); //throw }//FlushWriteBuf //------------------------------------------------------------------------ void RemoteFB__PortStream__Crypt_Arc4::Read(size_t const cb, void* const pv) { CHECK_READ_WRITE_PTR(pv,cb); assert(m_spBaseStream); m_spBaseStream->Read(cb,pv); //throw byte_type* p=reinterpret_cast<byte_type*>(pv); const byte_type* const e=(p+cb); for(;p!=e;++p) { (*p)=m_Decoder.transform(*p); }//for p }//Read
Сам процесс «инициализации» шифрования выглядит просто:
1. Отправляем серверу пакет op_crypt с именем типа ключа шифрования (Symmetric) и названием алгоритма (плагина) шифрования (Arc4).
2. Замещаем объект сокета на объект зашифрованного потока:
m_spSocket.swap(spCryptStream);
3. Читаем (зашифрованный!) ответ сервера. Прочитали — все ок (хотя статус вектор, все таки, стоит проверить).
Не смогли прочитать (сервер оборвал подключение) — можно залезть в лог сервера и посмотреть, что он там написал:
HOME3 Wed Aug 17 12:20:11 2016 start_crypt: Client attempted to start wire encryption using unsupported plugin QUQU HOME3 Wed Aug 17 12:34:53 2016 start_crypt: Client attempted to start wire encryption using unsupported plugin QUQU+++
Нормальную нотификацию клиента (вместо обрыва) о проблеме разработчики сервера неасилили. Главное ошибку о некорректном логине/пароле — сервер присылает, а тут тупо закрывает подключение. Жаль.
В тройке еще компрессор к потоку данных прикрутили. По сути, думаю, это то же шифрование. Посмотрим. Потом.