diff --git a/server/.idea/encodings.xml b/server/.idea/encodings.xml index aae22e9..5ff5c23 100644 --- a/server/.idea/encodings.xml +++ b/server/.idea/encodings.xml @@ -8,8 +8,11 @@ + + + @@ -19,6 +22,8 @@ + + diff --git a/server/tp_core/common/base_record.cpp b/server/tp_core/common/base_record.cpp index 3a617fc..beb26b8 100644 --- a/server/tp_core/common/base_record.cpp +++ b/server/tp_core/common/base_record.cpp @@ -1,7 +1,7 @@ #include -#include -#include +//#include +//#include #include "base_record.h" @@ -10,13 +10,15 @@ TppRecBase::TppRecBase() m_cache.reserve(MAX_SIZE_PER_FILE); m_start_time = 0; m_last_time = 0; + //m_protocol = } TppRecBase::~TppRecBase() { + end(); } -void TppRecBase::begin(const wchar_t* base_path, const wchar_t* base_fname, int record_id, const TPP_CONNECT_INFO* info) +bool TppRecBase::begin(const wchar_t* base_path, const wchar_t* base_fname, int record_id, const TPP_CONNECT_INFO* info) { m_start_time = ex_get_tick_count(); @@ -24,21 +26,22 @@ void TppRecBase::begin(const wchar_t* base_path, const wchar_t* base_fname, int m_base_path = base_path; wchar_t _str_rec_id[24] = { 0 }; - ex_wcsformat(_str_rec_id, 24, L"%06d", record_id); + ex_wcsformat(_str_rec_id, 24, L"%09d", record_id); ex_path_join(m_base_path, false, _str_rec_id, NULL); ex_mkdirs(m_base_path); - _on_begin(info); + return _on_begin(info); } -void TppRecBase::end() +bool TppRecBase::end() { _on_end(); -#ifdef EX_DEBUG if (m_cache.size() > 0) { EXLOGE("not all record data saved.\n"); + return false; } -#endif + + return true; } diff --git a/server/tp_core/common/base_record.h b/server/tp_core/common/base_record.h index b7c60bd..7e6993a 100644 --- a/server/tp_core/common/base_record.h +++ b/server/tp_core/common/base_record.h @@ -11,22 +11,31 @@ #pragma pack(push,1) +/* + * 录像 + * + * 一个录像分为两个文件,一个信息文件,一个数据文件。 + * 服务内部缓存最大4M,或者5秒,就将数据写入数据文件中,并同时更新信息文件。 + * + */ + + // 录像文件头(随着录像数据写入,会改变的部分) typedef struct TS_RECORD_HEADER_INFO { + ex_u32 magic; // "TPPR" 标志 TelePort Protocol Record + ex_u16 ver; // 录像文件版本,目前为3 ex_u32 packages; // 总包数 ex_u32 time_ms; // 总耗时(毫秒) - ex_u32 file_size; // 数据总大小(不包括文件头) + ex_u32 file_size; // 数据文件大小 }TS_RECORD_HEADER_INFO; +#define ts_record_header_info_size sizeof(TS_RECORD_HEADER_INFO) // 录像文件头(固定不变部分) typedef struct TS_RECORD_HEADER_BASIC { - ex_u32 magic; // "TPPR" 标志 TelePort Protocol Record - ex_u16 ver; // 录像文件版本,目前为3 - ex_u16 protocol_type; // 协议:1=RDP, 2=SSH, 3=Telnet - ex_u16 protocol_sub_type; // 子协议:100=RDP, 200=SSH, 201=SFTP, 300=Telnet + ex_u16 protocol_sub_type; // 子协议:100=RDP-DESKTOP, 200=SSH-SHELL, 201=SSH-SFTP, 300=Telnet ex_u64 timestamp; // 本次录像的起始时间(UTC时间戳) ex_u16 width; // 初始屏幕尺寸:宽 ex_u16 height; // 初始屏幕尺寸:高 @@ -42,7 +51,7 @@ typedef struct TS_RECORD_HEADER_BASIC // RDP专有 ex_u8 rdp_security; // 0 = RDP, 1 = TLS - ex_u8 reserve[512 - 4 - 2 - 2 - 2 - 8 - 2 - 2 - 64 - 64 - 40 - 2 - 40 - 40 - 1 - 12]; // 保留,其中,12B是为header-info留出的空间 + ex_u8 _reserve[512 - 4 - 2 - 2 - 2 - 8 - 2 - 2 - 64 - 64 - 40 - 2 - 40 - 40 - 1 - ts_record_header_info_size]; }TS_RECORD_HEADER_BASIC; #define ts_record_header_basic_size sizeof(TS_RECORD_HEADER_BASIC) @@ -62,7 +71,7 @@ typedef struct TS_RECORD_PKG ex_u8 type; // 包的数据类型 ex_u32 size; // 这个包的总大小(不含包头) ex_u32 time_ms; // 这个包距起始时间的时间差(毫秒,意味着一个连接不能持续超过49天) - ex_u8 reserve[3]; // 保留 + ex_u8 _reserve[3]; // 保留 }TS_RECORD_PKG; #pragma pack(pop) @@ -73,17 +82,17 @@ public: TppRecBase(); virtual ~TppRecBase(); - void begin(const wchar_t* base_path, const wchar_t* base_fname, int record_id, const TPP_CONNECT_INFO* info); - void end(void); + bool begin(const wchar_t* base_path, const wchar_t* base_fname, int record_id, const TPP_CONNECT_INFO* info); + bool end(); - virtual void record(ex_u8 type, const ex_u8* data, size_t size) = 0; + //virtual void record(ex_u8 type, const ex_u8* data, size_t size) = 0; protected: - virtual void _on_begin(const TPP_CONNECT_INFO* info) = 0; - virtual void _on_end(void) = 0; + virtual bool _on_begin(const TPP_CONNECT_INFO* info) = 0; + virtual bool _on_end() = 0; protected: - int m_protocol; + //int m_protocol; ex_wstr m_base_path; // 录像文件基础路径,例如 /usr/local/eom/teleport/data/replay/ssh/123,数字编号是内部附加的,作为本次会话录像文件的目录名称 ex_wstr m_base_fname; // 录像文件的文件名,不含扩展名部分,内部会以此为基础合成文件全名,并将录像文件存放在 m_base_path 指向的目录中 diff --git a/server/tp_core/protocol/ssh/ssh_proxy.cpp b/server/tp_core/protocol/ssh/ssh_proxy.cpp index 4158243..40db541 100644 --- a/server/tp_core/protocol/ssh/ssh_proxy.cpp +++ b/server/tp_core/protocol/ssh/ssh_proxy.cpp @@ -7,6 +7,7 @@ SshProxy::SshProxy() : ExThreadBase("ssh-proxy-thread"), m_bind(NULL) { + m_timer_counter = 0; } SshProxy::~SshProxy() @@ -16,8 +17,8 @@ SshProxy::~SshProxy() ssh_finalize(); - ts_sftp_sessions::iterator it = m_sftp_sessions.begin(); - for (; it != m_sftp_sessions.end(); ++it) + ts_sftp_sessions::iterator it; + for (it = m_sftp_sessions.begin(); it != m_sftp_sessions.end(); ++it) { delete it->second; } @@ -69,7 +70,20 @@ bool SshProxy::init(void) } void SshProxy::timer(void) { + // be called per one second. // EXLOGV("[ssh] on-timer.\n"); + m_timer_counter++; + if(m_timer_counter < 5) + return; + + m_timer_counter = 0; + + ExThreadSmartLock locker(m_lock); + + ts_ssh_sessions::iterator it; + for(it = m_sessions.begin(); it != m_sessions.end(); ++it) { + it->first->flush_record(); + } } void SshProxy::_thread_loop(void) diff --git a/server/tp_core/protocol/ssh/ssh_proxy.h b/server/tp_core/protocol/ssh/ssh_proxy.h index 331aa95..3452bb7 100644 --- a/server/tp_core/protocol/ssh/ssh_proxy.h +++ b/server/tp_core/protocol/ssh/ssh_proxy.h @@ -52,7 +52,8 @@ private: private: ssh_bind m_bind; - bool m_stop_flag; + //bool m_stop_flag; + int m_timer_counter; ExThreadLock m_lock; diff --git a/server/tp_core/protocol/ssh/ssh_recorder.cpp b/server/tp_core/protocol/ssh/ssh_recorder.cpp index d05586a..05b8d39 100644 --- a/server/tp_core/protocol/ssh/ssh_recorder.cpp +++ b/server/tp_core/protocol/ssh/ssh_recorder.cpp @@ -1,5 +1,5 @@ #include "ssh_recorder.h" -#include +//#include static ex_u8 TPP_RECORD_MAGIC[4] = { 'T', 'P', 'P', 'R' }; @@ -8,23 +8,26 @@ TppSshRec::TppSshRec() m_cmd_cache.reserve(MAX_SIZE_PER_FILE); memset(&m_head, 0, sizeof(TS_RECORD_HEADER)); - memcpy((ex_u8*)(&m_head.basic.magic), TPP_RECORD_MAGIC, sizeof(ex_u32)); - m_head.basic.ver = 0x02; + memcpy((ex_u8*)(&m_head.info.magic), TPP_RECORD_MAGIC, sizeof(ex_u32)); + m_head.info.ver = 0x03; + + m_file_info = NULL; + m_file_data = NULL; + m_file_cmd = NULL; } TppSshRec::~TppSshRec() { - end(); } -void TppSshRec::_on_begin(const TPP_CONNECT_INFO* info) +bool TppSshRec::_on_begin(const TPP_CONNECT_INFO* info) { if (NULL == info) - return; - m_head.basic.timestamp = time(NULL); - m_head.basic.protocol_type = info->protocol_type; - m_head.basic.protocol_sub_type = info->protocol_sub_type; - m_head.basic.conn_port = info->conn_port; + return false; + m_head.basic.timestamp = (ex_u64)time(NULL); + m_head.basic.protocol_type = (ex_u16)info->protocol_type; + m_head.basic.protocol_sub_type = (ex_u16)info->protocol_sub_type; + m_head.basic.conn_port = (ex_u16)info->conn_port; // memcpy(m_head.account, info.acc_username.c_str(), info.acc_username.length() > 15 ? 15 : info.acc_username.length()); // memcpy(m_head.username, info.user_username.c_str(), info.user_username.length() > 15 ? 15 : info.user_username.length()); // memcpy(m_head.ip, info.host_ip.c_str(), info.host_ip.length() > 17 ? 17 : info.host_ip.length()); @@ -33,9 +36,42 @@ void TppSshRec::_on_begin(const TPP_CONNECT_INFO* info) memcpy(m_head.basic.user_username, info->user_username, strlen(info->user_username) >= 63 ? 63 : strlen(info->user_username)); memcpy(m_head.basic.host_ip, info->host_ip, strlen(info->host_ip) >= 39 ? 39 : strlen(info->host_ip)); memcpy(m_head.basic.conn_ip, info->conn_ip, strlen(info->conn_ip) >= 39 ? 39 : strlen(info->conn_ip)); + + + + ex_wstr fname_info = m_base_path; + ex_path_join(fname_info, false, m_base_fname.c_str(), NULL); + fname_info += L".tpr"; + ex_wstr fname_data = m_base_path; + ex_path_join(fname_data, false, m_base_fname.c_str(), NULL); + fname_data += L".dat"; + ex_wstr fname_cmd = m_base_path; + ex_path_join(fname_cmd, false, m_base_fname.c_str(), NULL); + fname_cmd += L"-cmd.txt"; + + m_file_info = ex_fopen(fname_info, L"wb"); + if (NULL == m_file_info) + { + EXLOGE("[ssh] can not open record info-file for write.\n"); + return false; + } + m_file_data = ex_fopen(fname_data, L"wb"); + if (NULL == m_file_data) + { + EXLOGE("[ssh] can not open record data-file for write.\n"); + return false; + } + m_file_cmd = ex_fopen(fname_cmd, L"wb"); + if (NULL == m_file_cmd) + { + EXLOGE("[ssh] can not open record cmd-file for write.\n"); + return false; + } + + return true; } -void TppSshRec::_on_end(void) +bool TppSshRec::_on_end() { // 如果还有剩下未写入的数据,写入文件中。 if (m_cache.size() > 0) @@ -43,24 +79,37 @@ void TppSshRec::_on_end(void) if (m_cmd_cache.size() > 0) _save_to_cmd_file(); - // 更新头信息 - //m_head.timestamp = m_start_time; - m_head.info.time_ms = (ex_u32)(m_last_time - m_start_time); +// // 更新头信息 +// //m_head.timestamp = m_start_time; +// m_head.info.time_ms = (ex_u32)(m_last_time - m_start_time); +// +// ex_wstr fname = m_base_path; +// ex_path_join(fname, false, m_base_fname.c_str(), NULL); +// fname += L".tpr"; +// +// FILE* f = ex_fopen(fname, L"wb"); +// if (NULL == f) +// { +// EXLOGE("[ssh] can not open record file for write.\n"); +// return false; +// } +// +// fwrite(&m_head, sizeof(TS_RECORD_HEADER), 1, f); +// fflush(f); +// fclose(f); - ex_wstr fname = m_base_path; - ex_path_join(fname, false, m_base_fname.c_str(), NULL); - fname += L".tpr"; + fclose(m_file_info); + fclose(m_file_data); + fclose(m_file_cmd); - FILE* f = ex_fopen(fname, L"wb"); - if (NULL == f) - { - EXLOGE("[ssh] can not open record file for write.\n"); - return; - } + return true; +} - fwrite(&m_head, sizeof(TS_RECORD_HEADER), 1, f); - fflush(f); - fclose(f); +void TppSshRec::flush_record() { + if (m_cache.size() > 0) + _save_to_data_file(); + if (m_cmd_cache.size() > 0) + _save_to_cmd_file(); } void TppSshRec::record(ex_u8 type, const ex_u8* data, size_t size) @@ -68,14 +117,15 @@ void TppSshRec::record(ex_u8 type, const ex_u8* data, size_t size) if (data == NULL || 0 == size) return; m_head.info.packages++; + m_head.info.time_ms = (ex_u32)(m_last_time - m_start_time); if (sizeof(TS_RECORD_PKG) + size + m_cache.size() > m_cache.buffer_size()) _save_to_data_file(); - TS_RECORD_PKG pkg; - memset(&pkg, 0, sizeof(TS_RECORD_PKG)); + TS_RECORD_PKG pkg = {0}; + //memset(&pkg, 0, sizeof(TS_RECORD_PKG)); pkg.type = type; - pkg.size = size; + pkg.size = (ex_u32)size; if (m_start_time > 0) { @@ -89,19 +139,19 @@ void TppSshRec::record(ex_u8 type, const ex_u8* data, size_t size) void TppSshRec::record_win_size_startup(int width, int height) { - m_head.basic.width = width; - m_head.basic.height = height; + m_head.basic.width = (ex_u16)width; + m_head.basic.height = (ex_u16)height; } void TppSshRec::record_win_size_change(int width, int height) { - TS_RECORD_WIN_SIZE pkg; + TS_RECORD_WIN_SIZE pkg = {0}; pkg.width = (ex_u16)width; pkg.height = (ex_u16)height; record(TS_RECORD_TYPE_SSH_TERM_SIZE, (ex_u8*)&pkg, sizeof(TS_RECORD_WIN_SIZE)); } -void TppSshRec::record_command(const ex_astr cmd) +void TppSshRec::record_command(const ex_astr& cmd) { char szTime[100] = { 0 }; #ifdef EX_OS_WIN32 @@ -117,7 +167,7 @@ void TppSshRec::record_command(const ex_astr cmd) return; sprintf(szTime, "[%04d-%02d-%02d %02d:%02d:%02d] ", p->tm_year + 1900, p->tm_mon + 1, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec); #endif - int lenTime = strlen(szTime); + size_t lenTime = strlen(szTime); if (m_cmd_cache.size() + cmd.length() + lenTime > m_cache.buffer_size()) @@ -127,29 +177,29 @@ void TppSshRec::record_command(const ex_astr cmd) m_cmd_cache.append((ex_u8*)cmd.c_str(), cmd.length()); } -bool TppSshRec::_save_to_data_file(void) +bool TppSshRec::_save_to_data_file() { - wchar_t _str_file_id[24] = { 0 }; - ex_wcsformat(_str_file_id, 24, L".%03d", 0);// m_head.file_count); - - ex_wstr fname = m_base_path; - ex_path_join(fname, false, m_base_fname.c_str(), NULL); - fname += _str_file_id; - - FILE* f = ex_fopen(fname, L"wb"); - - if (NULL == f) - { - EXLOGE("[ssh] can not open record data-file for write.\n"); - m_cache.empty(); - return false; - } +// wchar_t _str_file_id[24] = { 0 }; +// ex_wcsformat(_str_file_id, 24, L".%03d", 0);// m_head.file_count); +// +// ex_wstr fname = m_base_path; +// ex_path_join(fname, false, m_base_fname.c_str(), NULL); +// fname += _str_file_id; +// +// FILE* f = ex_fopen(fname, L"wb"); +// +// if (NULL == f) +// { +// EXLOGE("[ssh] can not open record data-file for write.\n"); +// m_cache.empty(); +// return false; +// } ex_u32 size = m_cache.size(); - fwrite(&size, sizeof(ex_u32), 1, f); - fwrite(m_cache.data(), m_cache.size(), 1, f); - fflush(f); - fclose(f); + fwrite(&size, sizeof(ex_u32), 1, m_file_data); + fwrite(m_cache.data(), m_cache.size(), 1, m_file_data); +// fflush(f); +// fclose(f); //m_head.file_count++; //m_head.file_size += m_cache.size(); @@ -158,7 +208,7 @@ bool TppSshRec::_save_to_data_file(void) return true; } -bool TppSshRec::_save_to_cmd_file(void) +bool TppSshRec::_save_to_cmd_file() { ex_wstr fname = m_base_path; ex_path_join(fname, false, m_base_fname.c_str(), NULL); diff --git a/server/tp_core/protocol/ssh/ssh_recorder.h b/server/tp_core/protocol/ssh/ssh_recorder.h index f6c6d8a..c5644e6 100644 --- a/server/tp_core/protocol/ssh/ssh_recorder.h +++ b/server/tp_core/protocol/ssh/ssh_recorder.h @@ -54,19 +54,25 @@ public: void record(ex_u8 type, const ex_u8* data, size_t size); void record_win_size_startup(int width, int height); void record_win_size_change(int width, int height); - void record_command(const ex_astr cmd); + void record_command(const ex_astr& cmd); + + void flush_record(); protected: - void _on_begin(const TPP_CONNECT_INFO* info); - void _on_end(void); + bool _on_begin(const TPP_CONNECT_INFO* info); + bool _on_end(); - bool _save_to_data_file(void); - bool _save_to_cmd_file(void); + bool _save_to_data_file(); + bool _save_to_cmd_file(); protected: TS_RECORD_HEADER m_head; MemBuffer m_cmd_cache; + + FILE* m_file_info; + FILE* m_file_data; + FILE* m_file_cmd; }; #endif // __TPP_SSH_RECORDER_H__ diff --git a/server/tp_core/protocol/ssh/ssh_session.cpp b/server/tp_core/protocol/ssh/ssh_session.cpp index 7931a42..76d0713 100644 --- a/server/tp_core/protocol/ssh/ssh_session.cpp +++ b/server/tp_core/protocol/ssh/ssh_session.cpp @@ -220,6 +220,10 @@ void SshSession::_run(void) { ssh_event_free(event_loop); } +void SshSession::flush_record() { + m_rec.flush_record(); +} + int SshSession::_on_auth_password_request(ssh_session session, const char *user, const char *password, void *userdata) { // 这里拿到的user就是我们要的session-id,password可以用ticket来填充,作为额外判断用户是否被允许访问的依据。 diff --git a/server/tp_core/protocol/ssh/ssh_session.h b/server/tp_core/protocol/ssh/ssh_session.h index 51cd9d5..01f416d 100644 --- a/server/tp_core/protocol/ssh/ssh_session.h +++ b/server/tp_core/protocol/ssh/ssh_session.h @@ -53,6 +53,8 @@ public: void client_port(ex_u16 port) { m_client_port = port; } ex_u16 client_port(void) const { return m_client_port; } + void flush_record(); + protected: // 继承自 TppSessionBase bool _on_session_begin(const TPP_CONNECT_INFO* info); diff --git a/server/tp_core/protocol/ssh/tpssh.cpp b/server/tp_core/protocol/ssh/tpssh.cpp index 5923a8f..2df77ab 100644 --- a/server/tp_core/protocol/ssh/tpssh.cpp +++ b/server/tp_core/protocol/ssh/tpssh.cpp @@ -35,5 +35,6 @@ TPP_API ex_rv tpp_stop(void) } TPP_API void tpp_timer(void) { + // be called per one second. g_ssh_proxy.timer(); }