diff --git a/common/teleport/teleport_const.h b/common/teleport/teleport_const.h index 3223186..0fc01a9 100644 --- a/common/teleport/teleport_const.h +++ b/common/teleport/teleport_const.h @@ -40,7 +40,7 @@ //======================================================= // 远程连接会话状态 //======================================================= -#define TP_SESS_STAT_RUNNING 0 // 会话开始了,尚未结束 +#define TP_SESS_STAT_RUNNING 0 // 会话开始了,正在连接 #define TP_SESS_STAT_END 9999 // 会话成功结束 #define TP_SESS_STAT_ERR_AUTH_DENIED 1 // 会话结束,因为认证失败 #define TP_SESS_STAT_ERR_CONNECT 2 // 会话结束,因为无法连接到远程主机 diff --git a/server/tp_core/common/base_record.cpp b/server/tp_core/common/base_record.cpp index 07d38a0..663d5a1 100644 --- a/server/tp_core/common/base_record.cpp +++ b/server/tp_core/common/base_record.cpp @@ -1,8 +1,5 @@ #include -//#include -//#include - #include "base_record.h" TppRecBase::TppRecBase() diff --git a/server/tp_core/common/base_record.h b/server/tp_core/common/base_record.h index 7d576cf..9adb99f 100644 --- a/server/tp_core/common/base_record.h +++ b/server/tp_core/common/base_record.h @@ -85,8 +85,6 @@ public: 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; - protected: virtual bool _on_begin(const TPP_CONNECT_INFO* info) = 0; virtual bool _on_end() = 0; diff --git a/server/tp_core/common/protocol_interface.h b/server/tp_core/common/protocol_interface.h index 7db1008..60fa17c 100644 --- a/server/tp_core/common/protocol_interface.h +++ b/server/tp_core/common/protocol_interface.h @@ -44,7 +44,7 @@ typedef struct TPP_CONNECT_INFO typedef TPP_CONNECT_INFO* (*TPP_GET_CONNNECT_INFO_FUNC)(const char* sid); typedef void(*TPP_FREE_CONNECT_INFO_FUNC)(TPP_CONNECT_INFO* info); typedef bool(*TPP_SESSION_BEGIN_FUNC)(const TPP_CONNECT_INFO* info, int* db_id); -typedef bool(*TPP_SESSION_UPDATE_FUNC)(int db_id, int state); +typedef bool(*TPP_SESSION_UPDATE_FUNC)(int db_id, int protocol_sub_type, int state); typedef bool(*TPP_SESSION_END_FUNC)(const char* sid, int db_id, int ret); diff --git a/server/tp_core/core/ts_http_rpc.cpp b/server/tp_core/core/ts_http_rpc.cpp index 3167d14..199539a 100644 --- a/server/tp_core/core/ts_http_rpc.cpp +++ b/server/tp_core/core/ts_http_rpc.cpp @@ -359,9 +359,9 @@ void TsHttpRpc::_rpc_func_request_session(const Json::Value& json_param, ex_astr return; } - info->ref_count = 0; - info->ticket_start = ex_get_tick_count(); - +// info->ref_count = 0; +// info->ticket_start = ex_get_tick_count(); +// // 生成一个session-id(内部会避免重复) ex_astr sid; if (!g_session_mgr.request_session(sid, info)) { diff --git a/server/tp_core/core/ts_main.cpp b/server/tp_core/core/ts_main.cpp index 15af5d2..6dd355c 100644 --- a/server/tp_core/core/ts_main.cpp +++ b/server/tp_core/core/ts_main.cpp @@ -54,6 +54,8 @@ void tpp_free_connect_info(TPP_CONNECT_INFO* info) if (NULL == info) return; + g_session_mgr.free_connect_info(info->sid); + free(info->sid); free(info->user_username); free(info->host_ip); @@ -90,8 +92,8 @@ bool tpp_session_begin(const TPP_CONNECT_INFO* info, int* db_id) return ts_web_rpc_session_begin(sinfo, *db_id); } -bool tpp_session_update(int db_id, int state) { - return ts_web_rpc_session_update(db_id, state); +bool tpp_session_update(int db_id, int protocol_sub_type, int state) { + return ts_web_rpc_session_update(db_id, protocol_sub_type, state); } bool tpp_session_end(const char* sid, int db_id, int ret) diff --git a/server/tp_core/core/ts_session.cpp b/server/tp_core/core/ts_session.cpp index 30bc324..f9d2ed8 100644 --- a/server/tp_core/core/ts_session.cpp +++ b/server/tp_core/core/ts_session.cpp @@ -40,7 +40,7 @@ void TsSessionManager::_set_stop_flag(void) void TsSessionManager::_remove_expired_connect_info(void) { - // 超过30秒未进行连接的connect-info会被移除 + // 超过15秒未进行连接的connect-info会被移除 ExThreadSmartLock locker(m_lock); @@ -48,15 +48,13 @@ void TsSessionManager::_remove_expired_connect_info(void) ts_connections::iterator it = m_connections.begin(); for (; it != m_connections.end(); ) { -#ifdef EX_DEBUG - if (it->second->ref_count == 0 && _now - it->second->ticket_start >= 60*1000*60) -#else - if (it->second->ref_count == 0 && _now - it->second->ticket_start >= 30000) -#endif + //EXLOGD("[core] check expired connect info: [%s] %d, %d %d %d\n", it->first.c_str(), it->second->ref_count, int(_now), int(it->second->ticket_start), int(_now - it->second->ticket_start)); + if (it->second->ref_count == 0 && _now - it->second->ticket_start > 15000) { - EXLOGV("[core] remove connection info: %s\n", it->first.c_str()); + EXLOGD("[core] remove connection info, because timeout: %s\n", it->first.c_str()); delete it->second; m_connections.erase(it++); + EXLOGD("[core] there are %d connection info exists.\n", m_connections.size()); } else { @@ -96,6 +94,24 @@ bool TsSessionManager::get_connect_info(const ex_astr& sid, TS_CONNECT_INFO& inf return true; } +bool TsSessionManager::free_connect_info(const ex_astr& sid) { + ExThreadSmartLock locker(m_lock); + + ts_connections::iterator it = m_connections.find(sid); + if (it == m_connections.end()) + return false; + + it->second->ref_count--; + if (it->second->ref_count <= 0) { + EXLOGD("[core] remove connection info, because all connections closed: %s\n", it->first.c_str()); + delete it->second; + m_connections.erase(it); + EXLOGD("[core] there are %d connection info exists.\n", m_connections.size()); + } + + return true; +} + bool TsSessionManager::request_session(ex_astr& sid, TS_CONNECT_INFO* info) { ExThreadSmartLock locker(m_lock); @@ -118,6 +134,8 @@ bool TsSessionManager::request_session(ex_astr& sid, TS_CONNECT_INFO* info) } info->sid = _sid; + info->ref_count = 0; + info->ticket_start = ex_get_tick_count(); m_connections.insert(std::make_pair(_sid, info)); sid = _sid; diff --git a/server/tp_core/core/ts_session.h b/server/tp_core/core/ts_session.h index 6b7354c..7227810 100644 --- a/server/tp_core/core/ts_session.h +++ b/server/tp_core/core/ts_session.h @@ -50,20 +50,10 @@ public: // generate a sid for connection info. bool request_session(ex_astr& sid, TS_CONNECT_INFO* info); - // +ref for connection-info. - bool session_connect(const ex_astr& sid, TPP_CONNECT_INFO** info); - - // free connection-info created by session_connect(). - bool free_connect_info(TPP_CONNECT_INFO* info); - - // -ref for connecton-info, and release it when ref is 0. - bool session_end(const ex_astr& sid); - - // TODO: - void timer(); - - // 根据sid得到session信息 + // 根据sid得到连接信息(并增加引用计数) bool get_connect_info(const ex_astr& sid, TS_CONNECT_INFO& info); + // 减少引用计数,当引用计数为0时,删除之 + bool free_connect_info(const ex_astr& sid); protected: // 线程循环 diff --git a/server/tp_core/core/ts_web_rpc.cpp b/server/tp_core/core/ts_web_rpc.cpp index 0efb8b0..d12dcae 100644 --- a/server/tp_core/core/ts_web_rpc.cpp +++ b/server/tp_core/core/ts_web_rpc.cpp @@ -263,11 +263,12 @@ bool ts_web_rpc_session_begin(TS_CONNECT_INFO& info, int& record_id) return true; } -bool ts_web_rpc_session_update(int record_id, int state) { +bool ts_web_rpc_session_update(int record_id, int protocol_sub_type, int state) { Json::FastWriter json_writer; Json::Value jreq; jreq["method"] = "session_update"; jreq["param"]["rid"] = record_id; + jreq["param"]["protocol_sub_type"] = protocol_sub_type; jreq["param"]["code"] = state; ex_astr json_param; diff --git a/server/tp_core/core/ts_web_rpc.h b/server/tp_core/core/ts_web_rpc.h index e451431..5d42acf 100644 --- a/server/tp_core/core/ts_web_rpc.h +++ b/server/tp_core/core/ts_web_rpc.h @@ -14,7 +14,7 @@ int ts_web_rpc_get_conn_info(int conn_id, TS_CONNECT_INFO& info); // 记录会话的开始 bool ts_web_rpc_session_begin(TS_CONNECT_INFO& info, int& record_id); // update session state -bool ts_web_rpc_session_update(int id, int state); +bool ts_web_rpc_session_update(int id, int protocol_sub_type, int state); //session 结束 bool ts_web_rpc_session_end(const char* sid, int id, int ret_code); diff --git a/server/tp_core/protocol/ssh/ssh_proxy.cpp b/server/tp_core/protocol/ssh/ssh_proxy.cpp index 9bb35f4..8dbbbb5 100644 --- a/server/tp_core/protocol/ssh/ssh_proxy.cpp +++ b/server/tp_core/protocol/ssh/ssh_proxy.cpp @@ -16,13 +16,6 @@ SshProxy::~SshProxy() ssh_bind_free(m_bind); ssh_finalize(); - - ts_sftp_sessions::iterator it; - for (it = m_sftp_sessions.begin(); it != m_sftp_sessions.end(); ++it) - { - delete it->second; - } - m_sftp_sessions.clear(); } bool SshProxy::init() @@ -70,7 +63,7 @@ bool SshProxy::init() } void SshProxy::timer() { - // be called per one second. + // timer() will be called per one second, and I will do my job per 5 seconds. m_timer_counter++; if(m_timer_counter < 5) return; @@ -88,36 +81,7 @@ void SshProxy::timer() { void SshProxy::_thread_loop() { EXLOGV("[ssh] TeleportServer-SSH ready on %s:%d\n", m_host_ip.c_str(), m_host_port); - _run(); - EXLOGV("[ssh] main-loop end.\n"); -} -void SshProxy::_set_stop_flag() -{ - m_stop_flag = true; - - if (m_is_running) - { - // 用一个变通的方式来结束阻塞中的监听,就是连接一下它。 - ex_astr host_ip = m_host_ip; - if (host_ip == "0.0.0.0") - host_ip = "127.0.0.1"; - - ssh_session _session = ssh_new(); - ssh_options_set(_session, SSH_OPTIONS_HOST, host_ip.c_str()); - ssh_options_set(_session, SSH_OPTIONS_PORT, &m_host_port); - - int _timeout_us = 10; - ssh_options_set(_session, SSH_OPTIONS_TIMEOUT, &_timeout_us); - ssh_connect(_session); - ssh_free(_session); - } - - m_thread_mgr.stop_all(); -} - -void SshProxy::_run() -{ for (;;) { // 注意,ssh_new()出来的指针,如果遇到停止标志,本函数内部就释放了,否则这个指针交给了SshSession类实例管理,其析构时会释放。 @@ -169,92 +133,38 @@ void SshProxy::_run() // 等待所有工作线程退出 m_thread_mgr.stop_all(); + + EXLOGV("[ssh] main-loop end.\n"); } -void SshProxy::_dump_sftp_sessions() +void SshProxy::_set_stop_flag() { - ts_sftp_sessions::iterator it = m_sftp_sessions.begin(); - for (; it != m_sftp_sessions.end(); ++it) - { - EXLOGD("[ssh] ssh-proxy session: sid: %s\n", it->first.c_str()); - } -} + m_stop_flag = true; -void SshProxy::add_sftp_session_info(const ex_astr& sid, const ex_astr& host_ip, int host_port, const ex_astr& user_name, const ex_astr& user_auth, int auth_mode) -{ - ExThreadSmartLock locker(m_lock); - EXLOGD("[ssh] add sftp session-id: %s\n", sid.c_str()); - ts_sftp_sessions::iterator it = m_sftp_sessions.find(sid); - if (it != m_sftp_sessions.end()) + if (m_is_running) { - EXLOGD("[ssh] sftp-session-id '%s' already exists.\n", sid.c_str()); - it->second->ref_count++; - return; + // 用一个变通的方式来结束阻塞中的监听,就是连接一下它。 + ex_astr host_ip = m_host_ip; + if (host_ip == "0.0.0.0") + host_ip = "127.0.0.1"; + + ssh_session _session = ssh_new(); + ssh_options_set(_session, SSH_OPTIONS_HOST, host_ip.c_str()); + ssh_options_set(_session, SSH_OPTIONS_PORT, &m_host_port); + + int _timeout_us = 10; + ssh_options_set(_session, SSH_OPTIONS_TIMEOUT, &_timeout_us); + ssh_connect(_session); + ssh_free(_session); } - TS_SFTP_SESSION_INFO* info = new TS_SFTP_SESSION_INFO; - info->host_ip = host_ip; - info->host_port = host_port; - info->user_name = user_name; - info->user_auth = user_auth; - info->auth_mode = auth_mode; - info->ref_count = 1; - - if (!m_sftp_sessions.insert(std::make_pair(sid, info)).second) - { - EXLOGE("[ssh] ssh-proxy can not insert a sftp-session-id.\n"); - } - - _dump_sftp_sessions(); -} - -bool SshProxy::get_sftp_session_info(const ex_astr& sid, TS_SFTP_SESSION_INFO& info) -{ - ExThreadSmartLock locker(m_lock); - EXLOGD("[ssh] try to get info by sftp session-id: %s\n", sid.c_str()); - - _dump_sftp_sessions(); - - ts_sftp_sessions::iterator it = m_sftp_sessions.find(sid); - if (it == m_sftp_sessions.end()) - { - EXLOGD("[ssh] sftp-session '%s' not exists.\n", sid.c_str()); - return false; - } - - info.host_ip = it->second->host_ip; - info.host_port = it->second->host_port; - info.user_name = it->second->user_name; - info.user_auth = it->second->user_auth; - info.auth_mode = it->second->auth_mode; - info.ref_count = it->second->ref_count; - - return true; -} - -void SshProxy::remove_sftp_sid(const ex_astr& sid) -{ - EXLOGD("[ssh] try to remove sftp session-id: %s\n", sid.c_str()); - - ExThreadSmartLock locker(m_lock); - ts_sftp_sessions::iterator it = m_sftp_sessions.find(sid); - if (it == m_sftp_sessions.end()) - { - EXLOGE("[ssh] ssh-proxy when remove sftp sid, it not in charge.\n"); - return; - } - - it->second->ref_count--; - if (it->second->ref_count <= 0) - { - delete it->second; - m_sftp_sessions.erase(it); - EXLOGD("[ssh] sftp session-id '%s' removed.\n", sid.c_str()); - } + m_thread_mgr.stop_all(); } void SshProxy::session_finished(SshSession* sess) { + // TODO: 向核心模块汇报此会话终止,以减少对应连接信息的引用计数 + ExThreadSmartLock locker(m_lock); ts_ssh_sessions::iterator it = m_sessions.find(sess); if (it != m_sessions.end()) diff --git a/server/tp_core/protocol/ssh/ssh_proxy.h b/server/tp_core/protocol/ssh/ssh_proxy.h index 5d0cff0..187293b 100644 --- a/server/tp_core/protocol/ssh/ssh_proxy.h +++ b/server/tp_core/protocol/ssh/ssh_proxy.h @@ -7,18 +7,6 @@ typedef std::map ts_ssh_sessions; -typedef struct TS_SFTP_SESSION_INFO -{ - ex_astr host_ip; - int host_port; - ex_astr user_name; - ex_astr user_auth; - int auth_mode; - int ref_count; // 引用计数器,但所有引用本登录信息的ssh-sftp通道关闭,就销毁之 -}TS_SFTP_SESSION_INFO; - -typedef std::map ts_sftp_sessions; - class SshProxy : public ExThreadBase { public: @@ -28,31 +16,14 @@ public: bool init(); void timer(); - void add_sftp_session_info( - const ex_astr& sid, - const ex_astr& host_ip, - int host_port, - const ex_astr& user_name, - const ex_astr& user_auth, - int auth_mode - ); - bool get_sftp_session_info(const ex_astr& sid, TS_SFTP_SESSION_INFO& info); - void remove_sftp_sid(const ex_astr& sid); - void session_finished(SshSession* sess); protected: void _thread_loop(); void _set_stop_flag(); - void _run(); - -private: - void _dump_sftp_sessions(); - private: ssh_bind m_bind; - //bool m_stop_flag; int m_timer_counter; ExThreadLock m_lock; @@ -61,7 +32,6 @@ private: int m_host_port; ts_ssh_sessions m_sessions; - ts_sftp_sessions m_sftp_sessions; ExThreadManager m_thread_mgr; }; diff --git a/server/tp_core/protocol/ssh/ssh_session.cpp b/server/tp_core/protocol/ssh/ssh_session.cpp index bdcf7d9..2510826 100644 --- a/server/tp_core/protocol/ssh/ssh_session.cpp +++ b/server/tp_core/protocol/ssh/ssh_session.cpp @@ -5,19 +5,27 @@ #include #include +TP_SSH_CHANNEL_PAIR::TP_SSH_CHANNEL_PAIR() { + type = TS_SSH_CHANNEL_TYPE_UNKNOWN; + + cli_channel = NULL; + srv_channel = NULL; + + retcode = TP_SESS_STAT_RUNNING; + db_id = 0; +} + + SshSession::SshSession(SshProxy *proxy, ssh_session sess_client) : ExThreadBase("ssh-session-thread"), m_proxy(proxy), m_cli_session(sess_client), - m_srv_session(NULL) + m_srv_session(NULL), + m_conn_info(NULL) { - m_retcode = TP_SESS_STAT_RUNNING; - m_db_id = 0; - m_auth_type = TP_AUTH_TYPE_PASSWORD; m_is_first_server_data = true; - m_is_sftp = false; m_is_logon = false; m_have_error = false; @@ -44,8 +52,8 @@ SshSession::~SshSession() { _set_stop_flag(); - if (m_is_sftp) { - m_proxy->remove_sftp_sid(m_sid); + if (NULL != m_conn_info) { + g_ssh_env.free_connect_info(m_conn_info); } EXLOGD("[ssh] session destroy.\n"); @@ -53,7 +61,6 @@ SshSession::~SshSession() { void SshSession::_thread_loop(void) { _run(); - _on_session_end(); m_proxy->session_finished(this); } @@ -72,71 +79,85 @@ void SshSession::_set_stop_flag(void) { } } -bool SshSession::_on_session_begin(const TPP_CONNECT_INFO* info) -{ - if (!g_ssh_env.session_begin(info, &m_db_id)) +void SshSession::_session_error(int err_code) { + int db_id = 0; + if (!g_ssh_env.session_begin(m_conn_info, &db_id)) { - EXLOGD("[ssh] session_begin error. %d\n", m_db_id); + EXLOGE("[ssh] can not write session error to database.\n"); + return; + } + + g_ssh_env.session_end(m_sid.c_str(), db_id, err_code); +} + + +bool SshSession::_on_session_begin(TP_SSH_CHANNEL_PAIR* cp) +{ + if (!g_ssh_env.session_begin(m_conn_info, &(cp->db_id))) + { + EXLOGD("[ssh] session_begin error. %d\n", cp->db_id); return false; } - m_rec.begin(g_ssh_env.replay_path.c_str(), L"tp-ssh", m_db_id, info); + if (!g_ssh_env.session_update(cp->db_id, m_conn_info->protocol_sub_type, TP_SESS_STAT_STARTED)) + { + EXLOGD("[ssh] session_update error. %d\n", cp->db_id); + return false; + } + + + cp->rec.begin(g_ssh_env.replay_path.c_str(), L"tp-ssh", cp->db_id, m_conn_info); return true; } -bool SshSession::_on_session_end(void) +void SshSession::_on_session_end(TP_SSH_CHANNEL_PAIR* cp) { - if (m_db_id > 0) + if (cp->db_id > 0) { - EXLOGD("[ssh] session ret-code: %d\n", m_retcode); + EXLOGD("[ssh] session ret-code: %d\n", cp->retcode); // 如果会话过程中没有发生错误,则将其状态改为结束,否则记录下错误值 - if (m_retcode == TP_SESS_STAT_RUNNING) - m_retcode = TP_SESS_STAT_END; + if (cp->retcode == TP_SESS_STAT_RUNNING || cp->retcode == TP_SESS_STAT_STARTED) + cp->retcode = TP_SESS_STAT_END; - g_ssh_env.session_end(m_sid.c_str(), m_db_id, m_retcode); + g_ssh_env.session_end(m_sid.c_str(), cp->db_id, cp->retcode); + + cp->db_id = 0; } - - return true; } void SshSession::_close_channels(void) { ExThreadSmartLock locker(m_lock); - if (m_channel_cli_srv.size() > 0) - EXLOGW("[ssh] when close all channels, %d client channel need close.\n", m_channel_cli_srv.size()); - if (m_channel_srv_cli.size() > 0) - EXLOGW("[ssh] when close all channels, %d server channel need close.\n", m_channel_srv_cli.size()); - - ts_ssh_channel_map::iterator it = m_channel_cli_srv.begin(); - for (; it != m_channel_cli_srv.end(); ++it) { - if (!ssh_channel_is_eof(it->first)) - ssh_channel_send_eof(it->first); - if (!ssh_channel_is_closed(it->first)) - ssh_channel_close(it->first); - ssh_channel_free(it->first); - - if (NULL != it->second) { - if (!ssh_channel_is_eof(it->second->channel)) - ssh_channel_send_eof(it->second->channel); - if (!ssh_channel_is_closed(it->second->channel)) - ssh_channel_close(it->second->channel); - ssh_channel_free(it->second->channel); - - delete it->second; + tp_channels::iterator it = m_channels.begin(); + for (; it != m_channels.end(); ++it) { + ssh_channel ch = (*it)->srv_channel; + if (ch != NULL) { + if (!ssh_channel_is_closed(ch)) { + if (!ssh_channel_is_eof(ch)) + ssh_channel_send_eof(ch); + ssh_channel_close(ch); + } + ssh_channel_free(ch); } + + ch = (*it)->cli_channel; + if (ch != NULL) { + if (!ssh_channel_is_closed(ch)) { + if (!ssh_channel_is_eof(ch)) + ssh_channel_send_eof(ch); + ssh_channel_close(ch); + } + ssh_channel_free(ch); + } + + _on_session_end(*it); + + delete (*it); } - it = m_channel_srv_cli.begin(); - for (; it != m_channel_srv_cli.end(); ++it) { - if (NULL != it->second) { - delete it->second; - } - } - - m_channel_cli_srv.clear(); - m_channel_srv_cli.clear(); + m_channels.clear(); } void SshSession::_run(void) { @@ -175,7 +196,7 @@ void SshSession::_run(void) { // 认证,并打开一个通道 int r = 0; - while (!(m_is_logon && m_channel_cli_srv.size() > 0)) { + while (!(m_is_logon && m_channels.size() > 0)) { if (m_have_error) break; r = ssh_event_dopoll(event_loop, -1); @@ -211,7 +232,7 @@ void SshSession::_run(void) { _close_channels(); } - } while (m_channel_cli_srv.size() > 0); + } while (m_channels.size() > 0); EXLOGV("[ssh] [%s:%d] all channel in this session are closed.\n", m_client_ip.c_str(), m_client_port); @@ -221,7 +242,12 @@ void SshSession::_run(void) { } void SshSession::save_record() { - m_rec.save_record(); + ExThreadSmartLock locker(m_lock); + + tp_channels::iterator it = m_channels.begin(); + for (; it != m_channels.end(); ++it) { + (*it)->rec.save_record(); + } } @@ -232,57 +258,31 @@ int SshSession::_on_auth_password_request(ssh_session session, const char *user, EXLOGV("[ssh] authenticating, session-id: %s\n", _this->m_sid.c_str()); int protocol = 0; - TPP_CONNECT_INFO* sess_info = g_ssh_env.get_connect_info(_this->m_sid.c_str()); + //TPP_CONNECT_INFO* sess_info = g_ssh_env.get_connect_info(_this->m_sid.c_str()); + _this->m_conn_info = g_ssh_env.get_connect_info(_this->m_sid.c_str()); - if (NULL == sess_info) { -// EXLOGW("[ssh] try to get login-info from ssh-sftp-session.\n"); - // 尝试从sftp连接记录中获取连接信息(一个ssh会话如果成为sftp会话,内部会将连接信息记录下来备用) -// TS_SFTP_SESSION_INFO sftp_info; -// if (!_this->m_proxy->get_sftp_session_info(_this->m_sid, sftp_info)) { - EXLOGE("[ssh] no such session: %s\n", _this->m_sid.c_str()); - _this->m_have_error = true; - _this->m_retcode = TP_SESS_STAT_ERR_AUTH_DENIED; - return SSH_AUTH_DENIED; -// } -// -// _this->m_conn_ip = sftp_info.host_ip; -// _this->m_conn_port = sftp_info.host_port; -// _this->m_auth_type = sftp_info.auth_mode; -// _this->m_acc_name = sftp_info.user_name; -// _this->m_acc_secret = sftp_info.user_auth; -// protocol = TP_PROTOCOL_TYPE_SSH; -// -// // 因为是从sftp会话得来的登录数据,因此限制本会话只能用于sftp,不允许再使用shell了。 -// _this->_enter_sftp_mode(); + if (NULL == _this->m_conn_info) { + EXLOGE("[ssh] no such session: %s\n", _this->m_sid.c_str()); + _this->m_have_error = true; + _this->_session_error(TP_SESS_STAT_ERR_SESSION); + return SSH_AUTH_DENIED; } else { - _this->m_conn_ip = sess_info->conn_ip; - _this->m_conn_port = sess_info->conn_port; - _this->m_auth_type = sess_info->auth_type; - _this->m_acc_name = sess_info->acc_username; - _this->m_acc_secret = sess_info->acc_secret; - protocol = sess_info->protocol_type; + _this->m_conn_ip = _this->m_conn_info->conn_ip; + _this->m_conn_port = _this->m_conn_info->conn_port; + _this->m_auth_type = _this->m_conn_info->auth_type; + _this->m_acc_name = _this->m_conn_info->acc_username; + _this->m_acc_secret = _this->m_conn_info->acc_secret; + protocol = _this->m_conn_info->protocol_type; } if (protocol != TP_PROTOCOL_TYPE_SSH) { - g_ssh_env.free_connect_info(sess_info); EXLOGE("[ssh] session '%s' is not for SSH.\n", _this->m_sid.c_str()); _this->m_have_error = true; - _this->m_retcode = TP_SESS_STAT_ERR_AUTH_DENIED; + _this->_session_error(TP_SESS_STAT_ERR_INTERNAL); return SSH_AUTH_DENIED; } - if (!_this->_on_session_begin(sess_info)) - { - g_ssh_env.free_connect_info(sess_info); - _this->m_have_error = true; - _this->m_retcode = TP_SESS_STAT_ERR_AUTH_DENIED; - return SSH_AUTH_DENIED; - } - - g_ssh_env.free_connect_info(sess_info); - sess_info = NULL; - // 现在尝试根据session-id获取得到的信息,连接并登录真正的SSH服务器 EXLOGV("[ssh] try to connect to real SSH server %s:%d\n", _this->m_conn_ip.c_str(), _this->m_conn_port); _this->m_srv_session = ssh_new(); @@ -306,30 +306,24 @@ int SshSession::_on_auth_password_request(ssh_session session, const char *user, if (rc != SSH_OK) { EXLOGE("[ssh] can not connect to real SSH server %s:%d. [%d]%s\n", _this->m_conn_ip.c_str(), _this->m_conn_port, rc, ssh_get_error(_this->m_srv_session)); _this->m_have_error = true; - _this->m_retcode = TP_SESS_STAT_ERR_CONNECT; + _this->_session_error(TP_SESS_STAT_ERR_CONNECT); return SSH_AUTH_ERROR; } - if (!g_ssh_env.session_update(_this->m_db_id, TP_SESS_STAT_STARTED)) - { - EXLOGD("[ssh] session_update error. %d\n", _this->m_db_id); - return false; - } - -// // 检查服务端支持的认证协议 + // // 检查服务端支持的认证协议 ssh_userauth_none(_this->m_srv_session, NULL); -// rc = ssh_userauth_none(_this->m_srv_session, NULL); -// if (rc == SSH_AUTH_ERROR) { -// EXLOGE("[ssh] invalid password for password mode to login to real SSH server %s:%d.\n", _this->m_server_ip.c_str(), _this->m_server_port); -// _this->m_have_error = true; -// _this->m_retcode = SESS_STAT_ERR_AUTH_DENIED; -// return SSH_AUTH_ERROR; -// } -// // int auth_methods = ssh_userauth_list(_this->m_srv_session, NULL); -// const char* banner = ssh_get_issue_banner(_this->m_srv_session); -// if (NULL != banner) { -// EXLOGE("[ssh] issue banner: %s\n", banner); -// } + // rc = ssh_userauth_none(_this->m_srv_session, NULL); + // if (rc == SSH_AUTH_ERROR) { + // EXLOGE("[ssh] invalid password for password mode to login to real SSH server %s:%d.\n", _this->m_server_ip.c_str(), _this->m_server_port); + // _this->m_have_error = true; + // _this->m_retcode = SESS_STAT_ERR_AUTH_DENIED; + // return SSH_AUTH_ERROR; + // } + // // int auth_methods = ssh_userauth_list(_this->m_srv_session, NULL); + // const char* banner = ssh_get_issue_banner(_this->m_srv_session); + // if (NULL != banner) { + // EXLOGE("[ssh] issue banner: %s\n", banner); + // } if (_this->m_auth_type == TP_AUTH_TYPE_PASSWORD) { @@ -350,7 +344,7 @@ int SshSession::_on_auth_password_request(ssh_session session, const char *user, break; int nprompts = ssh_userauth_kbdint_getnprompts(_this->m_srv_session); - if(0 == nprompts) { + if (0 == nprompts) { rc = ssh_userauth_kbdint(_this->m_srv_session, NULL, NULL); continue; } @@ -364,7 +358,7 @@ int SshSession::_on_auth_password_request(ssh_session session, const char *user, if (rc < 0) { EXLOGE("[ssh] invalid password for interactive mode to login to real SSH server %s:%d.\n", _this->m_conn_ip.c_str(), _this->m_conn_port); _this->m_have_error = true; - _this->m_retcode = TP_SESS_STAT_ERR_AUTH_DENIED; + _this->_session_error(TP_SESS_STAT_ERR_AUTH_DENIED); return SSH_AUTH_ERROR; } } @@ -394,7 +388,7 @@ int SshSession::_on_auth_password_request(ssh_session session, const char *user, EXLOGE("[ssh] can not use password mode or interactive mode to login to real SSH server %s:%d.\n", _this->m_conn_ip.c_str(), _this->m_conn_port); _this->m_have_error = true; - _this->m_retcode = TP_SESS_STAT_ERR_AUTH_DENIED; + _this->_session_error(TP_SESS_STAT_ERR_AUTH_DENIED); return SSH_AUTH_ERROR; } else if (_this->m_auth_type == TP_AUTH_TYPE_PRIVATE_KEY) { @@ -402,7 +396,7 @@ int SshSession::_on_auth_password_request(ssh_session session, const char *user, if (SSH_OK != ssh_pki_import_privkey_base64(_this->m_acc_secret.c_str(), NULL, NULL, NULL, &key)) { EXLOGE("[ssh] can not import private-key for auth.\n"); _this->m_have_error = true; - _this->m_retcode = TP_SESS_STAT_ERR_BAD_SSH_KEY; + _this->_session_error(TP_SESS_STAT_ERR_BAD_SSH_KEY); return SSH_AUTH_ERROR; } @@ -417,17 +411,18 @@ int SshSession::_on_auth_password_request(ssh_session session, const char *user, else { EXLOGE("[ssh] failed to use private-key to login to real SSH server %s:%d.\n", _this->m_conn_ip.c_str(), _this->m_conn_port); _this->m_have_error = true; - _this->m_retcode = TP_SESS_STAT_ERR_AUTH_DENIED; + _this->_session_error(TP_SESS_STAT_ERR_AUTH_DENIED); return SSH_AUTH_ERROR; } } else if (_this->m_auth_type == TP_AUTH_TYPE_NONE) { + _this->_session_error(TP_SESS_STAT_ERR_AUTH_DENIED); return SSH_AUTH_ERROR; } else { EXLOGE("[ssh] invalid auth mode.\n"); _this->m_have_error = true; - _this->m_retcode = TP_SESS_STAT_ERR_AUTH_DENIED; + _this->_session_error(TP_SESS_STAT_ERR_AUTH_DENIED); return SSH_AUTH_ERROR; } } @@ -436,14 +431,10 @@ ssh_channel SshSession::_on_new_channel_request(ssh_session session, void *userd // 客户端尝试打开一个通道(然后才能通过这个通道发控制命令或者收发数据) EXLOGV("[ssh] client open channel\n"); - // TODO: 记录会话开始,应该在这里进行,这样可以为每一个通道记录不同的日志,避免类似SecureCRT多标签页使用“复制会话”这样的功能将多个标签页中的记录混杂在一起。 - // TODO: 每个通道应该记录单独的录像文件 - - SshSession *_this = (SshSession *)userdata; ssh_channel cli_channel = ssh_channel_new(session); - if(cli_channel == NULL) { + if (cli_channel == NULL) { EXLOGE("[ssh] can not create channel for client.\n"); return NULL; } @@ -451,7 +442,7 @@ ssh_channel SshSession::_on_new_channel_request(ssh_session session, void *userd // 我们也要向真正的服务器申请打开一个通道,来进行转发 ssh_channel srv_channel = ssh_channel_new(_this->m_srv_session); - if(srv_channel == NULL) { + if (srv_channel == NULL) { EXLOGE("[ssh] can not create channel for server.\n"); return NULL; } @@ -462,46 +453,51 @@ ssh_channel SshSession::_on_new_channel_request(ssh_session session, void *userd } ssh_set_channel_callbacks(srv_channel, &_this->m_srv_channel_cb); + TP_SSH_CHANNEL_PAIR* cp = new TP_SSH_CHANNEL_PAIR; + cp->type = TS_SSH_CHANNEL_TYPE_UNKNOWN; + cp->cli_channel = cli_channel; + cp->srv_channel = srv_channel; + + if (!_this->_on_session_begin(cp)) { + ssh_channel_close(cli_channel); + ssh_channel_free(cli_channel); + ssh_channel_close(srv_channel); + ssh_channel_free(srv_channel); + delete cp; + return NULL; + } + // 将客户端和服务端的通道关联起来 { ExThreadSmartLock locker(_this->m_lock); - - TS_SSH_CHANNEL_INFO *srv_info = new TS_SSH_CHANNEL_INFO; - srv_info->channel = srv_channel; - srv_info->type = TS_SSH_CHANNEL_TYPE_UNKNOWN; - _this->m_channel_cli_srv.insert(std::make_pair(cli_channel, srv_info)); - - TS_SSH_CHANNEL_INFO *cli_info = new TS_SSH_CHANNEL_INFO; - cli_info->channel = cli_channel; - cli_info->type = TS_SSH_CHANNEL_TYPE_UNKNOWN; - _this->m_channel_srv_cli.insert(std::make_pair(srv_channel, cli_info)); + _this->m_channels.push_back(cp); } EXLOGD("[ssh] channel for client and server created.\n"); return cli_channel; } -TS_SSH_CHANNEL_INFO *SshSession::_get_cli_channel(ssh_channel srv_channel) { +TP_SSH_CHANNEL_PAIR* SshSession::_get_channel_pair(int channel_side, ssh_channel channel) { ExThreadSmartLock locker(m_lock); - ts_ssh_channel_map::iterator it = m_channel_srv_cli.find(srv_channel); - if (it == m_channel_srv_cli.end()) - return NULL; - else - return it->second; -} -TS_SSH_CHANNEL_INFO *SshSession::_get_srv_channel(ssh_channel cli_channel) { - ExThreadSmartLock locker(m_lock); - ts_ssh_channel_map::iterator it = m_channel_cli_srv.find(cli_channel); - if (it == m_channel_cli_srv.end()) - return NULL; - else - return it->second; -} + tp_channels::iterator it = m_channels.begin(); + for (; it != m_channels.end(); ++it) { + if (channel_side == TP_SSH_CLIENT_SIDE) { + if ((*it)->cli_channel == channel) + return (*it); + } + else { + if ((*it)->srv_channel == channel) + return (*it); + } + } -void SshSession::_process_ssh_command(int from, const ex_u8* data, int len) + return NULL; +} + +void SshSession::_process_ssh_command(TppSshRec* rec, int from, const ex_u8* data, int len) { - if (TS_SSH_DATA_FROM_CLIENT == from) + if (TP_SSH_CLIENT_SIDE == from) { m_command_flag = 0; @@ -593,7 +589,7 @@ void SshSession::_process_ssh_command(int from, const ex_u8* data, int len) ex_replace_all(str, "\n", ""); //EXLOGD("[ssh] save cmd: [%s]", str.c_str()); str += "\r\n"; - m_rec.record_command(str); + rec->record_command(str); } m_cmd_char_list.clear(); m_cmd_char_pos = m_cmd_char_list.begin(); @@ -611,7 +607,7 @@ void SshSession::_process_ssh_command(int from, const ex_u8* data, int len) } } } - else if (TS_SSH_DATA_FROM_SERVER == from) + else if (TP_SSH_SERVER_SIDE == from) { if (m_command_flag == 0) return; @@ -774,7 +770,7 @@ void SshSession::_process_ssh_command(int from, const ex_u8* data, int len) return; } -void SshSession::_process_sftp_command(const ex_u8* data, int len) { +void SshSession::_process_sftp_command(TppSshRec* rec, const ex_u8* data, int len) { // SFTP protocol: https://tools.ietf.org/html/draft-ietf-secsh-filexfer-13 //EXLOG_BIN(data, len, "[sftp] client channel data"); @@ -789,7 +785,7 @@ void SshSession::_process_sftp_command(const ex_u8* data, int len) { if (sftp_cmd == 0x01) { // 0x01 = 1 = SSH_FXP_INIT - m_rec.record_command("SFTP INITIALIZE\r\n"); + rec->record_command("SFTP INITIALIZE\r\n"); return; } @@ -864,101 +860,90 @@ void SshSession::_process_sftp_command(const ex_u8* data, int len) { ex_strformat(msg, 2048, "%d:%s:%s:%s\r\n", sftp_cmd, act, str1.c_str(), str2.c_str()); } - m_rec.record_command(msg); + rec->record_command(msg); } int SshSession::_on_client_pty_request(ssh_session session, ssh_channel channel, const char *term, int x, int y, int px, int py, void *userdata) { SshSession *_this = (SshSession *)userdata; - if (_this->m_is_sftp) { - EXLOGE("[ssh] try to request pty on a sftp-session.\n"); - return SSH_ERROR; - } - EXLOGD("[ssh] client request terminal: %s, (%d, %d) / (%d, %d)\n", term, x, y, px, py); - _this->m_rec.record_win_size_startup(x, y); - TS_SSH_CHANNEL_INFO *info = _this->_get_srv_channel(channel); - if (NULL == info || NULL == info->channel) { - EXLOGE("[ssh] when client request pty, not found server channel.\n"); + + TP_SSH_CHANNEL_PAIR* cp = _this->_get_channel_pair(TP_SSH_CLIENT_SIDE, channel); + if (NULL == cp) { + EXLOGE("[ssh] when client request pty, not found channel pair.\n"); return SSH_ERROR; } - return ssh_channel_request_pty_size(info->channel, term, x, y); + cp->rec.record_win_size_startup(x, y); + + return ssh_channel_request_pty_size(cp->srv_channel, term, x, y); } int SshSession::_on_client_shell_request(ssh_session session, ssh_channel channel, void *userdata) { SshSession *_this = (SshSession *)userdata; - if (_this->m_is_sftp) { - EXLOGE("[ssh] request shell on a sftp-session is denied.\n"); - return SSH_ERROR; - } - EXLOGD("[ssh] client request shell\n"); - TS_SSH_CHANNEL_INFO *srv_info = _this->_get_srv_channel(channel); - if (NULL == srv_info || NULL == srv_info->channel) { - EXLOGE("[ssh] when client request shell, not found server channel.\n"); + TP_SSH_CHANNEL_PAIR* cp = _this->_get_channel_pair(TP_SSH_CLIENT_SIDE, channel); + if (NULL == cp) { + EXLOGE("[ssh] when client request shell, not found channel pair.\n"); return SSH_ERROR; } - srv_info->type = TS_SSH_CHANNEL_TYPE_SHELL; - TS_SSH_CHANNEL_INFO *cli_info = _this->_get_cli_channel(srv_info->channel); - if (NULL == cli_info || NULL == cli_info->channel) { - EXLOGE("[ssh] when client request shell, not found client channel.\n"); - return SSH_ERROR; - } - cli_info->type = TS_SSH_CHANNEL_TYPE_SHELL; + cp->type = TS_SSH_CHANNEL_TYPE_SHELL; + g_ssh_env.session_update(cp->db_id, TP_PROTOCOL_TYPE_SSH_SHELL, TP_SESS_STAT_STARTED); // FIXME: if client is putty, it will block here. the following function will never return. // at this time, can not write data to this channel. read from this channel with timeout, got 0 byte. // I have no idea how to fix it... :( - return ssh_channel_request_shell(srv_info->channel); + return ssh_channel_request_shell(cp->srv_channel); } void SshSession::_on_client_channel_close(ssh_session session, ssh_channel channel, void *userdata) { EXLOGD("[ssh] on_client_channel_close().\n"); SshSession *_this = (SshSession *)userdata; - TS_SSH_CHANNEL_INFO *info = _this->_get_srv_channel(channel); - if (NULL == info || NULL == info->channel) { - EXLOGW("[ssh] when close client channel, not found server channel, maybe it already closed.\n"); + + TP_SSH_CHANNEL_PAIR* cp = _this->_get_channel_pair(TP_SSH_CLIENT_SIDE, channel); + if (NULL == cp) { + EXLOGE("[ssh] when client channel close, not found channel pair.\n"); return; } - if (!ssh_channel_is_eof(channel)) - ssh_channel_send_eof(channel); - if (!ssh_channel_is_closed(channel)) - ssh_channel_close(channel); - //ssh_channel_free(channel); - if (!ssh_channel_is_eof(info->channel)) - ssh_channel_send_eof(info->channel); - if (!ssh_channel_is_closed(info->channel)) - ssh_channel_close(info->channel); - //ssh_channel_free(info->channel); + if (cp->srv_channel == NULL) { + EXLOGW("[ssh] when client channel close, server-channel not exists.\n"); + } + else { + if (!ssh_channel_is_closed(cp->srv_channel)) { + if (!ssh_channel_is_eof(cp->srv_channel)) { + //EXLOGD("[ssh] when client channel close, send eof to server-channel.\n"); + ssh_channel_send_eof(cp->cli_channel); + } - { - ExThreadSmartLock locker(_this->m_lock); + //EXLOGD("[ssh] when client channel close, close server-channel.\n"); + ssh_channel_close(cp->srv_channel); - ts_ssh_channel_map::iterator it = _this->m_channel_cli_srv.find(channel); - if (it != _this->m_channel_cli_srv.end()) { - delete it->second; - _this->m_channel_cli_srv.erase(it); - } - else { - EXLOGW("[ssh] when remove client channel, it not in charge.\n"); - } - - it = _this->m_channel_srv_cli.find(info->channel); - if (it != _this->m_channel_srv_cli.end()) { - delete it->second; - _this->m_channel_srv_cli.erase(it); - } - else { - EXLOGW("[ssh] when remove client channel, not found server channel.\n"); + ssh_channel_free(cp->srv_channel); + cp->srv_channel = NULL; } } + + if (!ssh_channel_is_closed(cp->cli_channel)) { + if (!ssh_channel_is_eof(cp->cli_channel)) { + //EXLOGD("[ssh] when client channel close, send eof to client-channel.\n"); + ssh_channel_send_eof(cp->cli_channel); + } + + //EXLOGD("[ssh] when client channel close, close client-channel.\n"); + ssh_channel_close(cp->cli_channel); + + ssh_channel_free(cp->cli_channel); + cp->cli_channel = NULL; + } + + + _this->_on_session_end(cp); } int SshSession::_on_client_channel_data(ssh_session session, ssh_channel channel, void *data, unsigned int len, int is_stderr, void *userdata) @@ -973,19 +958,25 @@ int SshSession::_on_client_channel_data(ssh_session session, ssh_channel channel if (_this->m_recving_from_cli) return 0; - TS_SSH_CHANNEL_INFO *info = _this->_get_srv_channel(channel); - if (NULL == info || NULL == info->channel) { - EXLOGE("[ssh] when receive client channel data, not found server channel.\n"); + TP_SSH_CHANNEL_PAIR* cp = _this->_get_channel_pair(TP_SSH_CLIENT_SIDE, channel); + if (NULL == cp) { + EXLOGE("[ssh] when receive client channel data, not found channel pair.\n"); return SSH_ERROR; } + // TS_SSH_CHANNEL_INFO *info = _this->_get_srv_channel(channel); + // if (NULL == info || NULL == info->channel) { + // EXLOGE("[ssh] when receive client channel data, not found server channel.\n"); + // return SSH_ERROR; + // } + _this->m_recving_from_cli = true; - if (info->type == TS_SSH_CHANNEL_TYPE_SHELL) + if (cp->type == TS_SSH_CHANNEL_TYPE_SHELL) { try { - _this->_process_ssh_command(TS_SSH_DATA_FROM_CLIENT, (ex_u8*)data, len); + _this->_process_ssh_command(&cp->rec, TP_SSH_CLIENT_SIDE, (ex_u8*)data, len); } catch (...) { @@ -993,72 +984,84 @@ int SshSession::_on_client_channel_data(ssh_session session, ssh_channel channel } else { - _this->_process_sftp_command((ex_u8*)data, len); + _this->_process_sftp_command(&cp->rec, (ex_u8*)data, len); } int ret = 0; if (is_stderr) - ret = ssh_channel_write_stderr(info->channel, data, len); + ret = ssh_channel_write_stderr(cp->srv_channel, data, len); else - ret = ssh_channel_write(info->channel, data, len); - if (ret <= 0) - EXLOGE("[ssh] send to server failed.\n"); + ret = ssh_channel_write(cp->srv_channel, data, len); + + if (ret == SSH_ERROR) { + EXLOGE("[ssh] send data(%dB) to server failed. [%d][cli:%s][srv:%s]\n", len, ret, ssh_get_error(_this->m_cli_session), ssh_get_error(_this->m_srv_session)); + } _this->m_recving_from_cli = false; - return len; + return ret; } int SshSession::_on_client_pty_win_change(ssh_session session, ssh_channel channel, int width, int height, int pxwidth, int pwheight, void *userdata) { EXLOGD("[ssh] client pty win size change to: (%d, %d)\n", width, height); SshSession *_this = (SshSession *)userdata; - TS_SSH_CHANNEL_INFO *info = _this->_get_srv_channel(channel); - if (NULL == info || NULL == info->channel) { - EXLOGE("[ssh] when client pty win change, not found server channel.\n"); + + TP_SSH_CHANNEL_PAIR* cp = _this->_get_channel_pair(TP_SSH_CLIENT_SIDE, channel); + if (NULL == cp) { + EXLOGE("[ssh] when client pty win change, not found channel pair.\n"); return SSH_ERROR; } - _this->m_rec.record_win_size_change(width, height); + // TS_SSH_CHANNEL_INFO *info = _this->_get_srv_channel(channel); + // if (NULL == info || NULL == info->channel) { + // EXLOGE("[ssh] when client pty win change, not found server channel.\n"); + // return SSH_ERROR; + // } - return ssh_channel_change_pty_size(info->channel, width, height); + cp->rec.record_win_size_change(width, height); + + return ssh_channel_change_pty_size(cp->srv_channel, width, height); } int SshSession::_on_client_channel_subsystem_request(ssh_session session, ssh_channel channel, const char *subsystem, void *userdata) { EXLOGD("[ssh] on_client_channel_subsystem_request(): %s\n", subsystem); SshSession *_this = (SshSession *)userdata; + TP_SSH_CHANNEL_PAIR* cp = _this->_get_channel_pair(TP_SSH_CLIENT_SIDE, channel); + if (NULL == cp) { + EXLOGE("[ssh] when request channel subsystem, not found channel pair.\n"); + return SSH_ERROR; + } + // 目前只支持SFTP子系统 if (strcmp(subsystem, "sftp") != 0) { EXLOGE("[ssh] support `sftp` subsystem only, but got `%s`.\n", subsystem); - _this->m_retcode = TP_SESS_STAT_ERR_UNSUPPORT_PROTOCOL; + cp->retcode = TP_SESS_STAT_ERR_UNSUPPORT_PROTOCOL; return SSH_ERROR; } - TS_SSH_CHANNEL_INFO *srv_info = _this->_get_srv_channel(channel); - if (NULL == srv_info || NULL == srv_info->channel) { - EXLOGE("[ssh] when receive client channel subsystem request, not found server channel.\n"); - return SSH_ERROR; - } - srv_info->type = TS_SSH_CHANNEL_TYPE_SFTP; + // TS_SSH_CHANNEL_INFO *srv_info = _this->_get_srv_channel(channel); + // if (NULL == srv_info || NULL == srv_info->channel) { + // EXLOGE("[ssh] when receive client channel subsystem request, not found server channel.\n"); + // return SSH_ERROR; + // } + // srv_info->type = TS_SSH_CHANNEL_TYPE_SFTP; + // + // TS_SSH_CHANNEL_INFO *cli_info = _this->_get_cli_channel(srv_info->channel); + // if (NULL == cli_info || NULL == cli_info->channel) { + // EXLOGE("[ssh] when client request shell, not found client channel.\n"); + // return SSH_ERROR; + // } + // cli_info->type = TS_SSH_CHANNEL_TYPE_SFTP; + cp->type = TS_SSH_CHANNEL_TYPE_SFTP; + + g_ssh_env.session_update(cp->db_id, TP_PROTOCOL_TYPE_SSH_SFTP, TP_SESS_STAT_STARTED); - TS_SSH_CHANNEL_INFO *cli_info = _this->_get_cli_channel(srv_info->channel); - if (NULL == cli_info || NULL == cli_info->channel) { - EXLOGE("[ssh] when client request shell, not found client channel.\n"); - return SSH_ERROR; - } - cli_info->type = TS_SSH_CHANNEL_TYPE_SFTP; // 一个ssh会话打开了sftp通道,就将连接信息记录下来备用,随后这个session-id再次尝试连接时,我们允许其连接。 - _this->_enter_sftp_mode(); + //_this->_enter_sftp_mode(); - return ssh_channel_request_subsystem(srv_info->channel, subsystem); -} - -void SshSession::_enter_sftp_mode(void) { - if (!m_is_sftp) { - m_is_sftp = true; - m_proxy->add_sftp_session_info(m_sid, m_conn_ip, m_conn_port, m_acc_name, m_acc_secret, m_auth_type); - } + return ssh_channel_request_subsystem(cp->srv_channel, subsystem); } int SshSession::_on_client_channel_exec_request(ssh_session session, ssh_channel channel, const char *command, void *userdata) { @@ -1071,15 +1074,21 @@ int SshSession::_on_server_channel_data(ssh_session session, ssh_channel channel //EXLOG_BIN((ex_u8*)data, len, "on_server_channel_data [is_stderr=%d]:", is_stderr); SshSession *_this = (SshSession *)userdata; + // return 0 means data not processed, so this function will be called with this data again. if (_this->m_recving_from_cli) return 0; if (_this->m_recving_from_srv) return 0; - TS_SSH_CHANNEL_INFO *info = _this->_get_cli_channel(channel); - if (NULL == info || NULL == info->channel) { - EXLOGE("[ssh] when receive server channel data, not found client channel.\n"); - _this->m_retcode = TP_SESS_STAT_ERR_INTERNAL; + // TS_SSH_CHANNEL_INFO *info = _this->_get_cli_channel(channel); + // if (NULL == info || NULL == info->channel) { + // EXLOGE("[ssh] when receive server channel data, not found client channel.\n"); + // _this->m_retcode = TP_SESS_STAT_ERR_INTERNAL; + // return SSH_ERROR; + // } + TP_SSH_CHANNEL_PAIR* cp = _this->_get_channel_pair(TP_SSH_SERVER_SIDE, channel); + if (NULL == cp) { + EXLOGE("[ssh] when receive server channel data, not found channel pair.\n"); return SSH_ERROR; } @@ -1087,7 +1096,7 @@ int SshSession::_on_server_channel_data(ssh_session session, ssh_channel channel // TODO: hard code not good... :( // 偶尔,某次操作会导致ssh_session->session_state为SSH_SESSION_STATE_ERROR // 但是将其强制改为SSH_SESSION_STATE_AUTHENTICATED,后续操作仍然能成功(主要在向客户端发送第一包数据时) - ex_u8* _t = (ex_u8*)(ssh_channel_get_session(info->channel)); + ex_u8* _t = (ex_u8*)(ssh_channel_get_session(cp->cli_channel)); if (_t[1116] == 9) // SSH_SESSION_STATE_AUTHENTICATED = 8, SSH_SESSION_STATE_ERROR = 9 { EXLOGW(" --- [ssh] hard code to fix client connect session error state.\n"); @@ -1097,12 +1106,13 @@ int SshSession::_on_server_channel_data(ssh_session session, ssh_channel channel _this->m_recving_from_srv = true; - if (info->type == TS_SSH_CHANNEL_TYPE_SHELL && !is_stderr) + if (cp->type == TS_SSH_CHANNEL_TYPE_SHELL && !is_stderr) { try { - _this->_process_ssh_command(TS_SSH_DATA_FROM_SERVER, (ex_u8*)data, len); - _this->m_rec.record(TS_RECORD_TYPE_SSH_DATA, (unsigned char *)data, len); + _this->_process_ssh_command(&cp->rec, TP_SSH_SERVER_SIDE, (ex_u8*)data, len); + //_this->m_rec.record(TS_RECORD_TYPE_SSH_DATA, (unsigned char *)data, len); + cp->rec.record(TS_RECORD_TYPE_SSH_DATA, (unsigned char *)data, len); } catch (...) { @@ -1118,7 +1128,7 @@ int SshSession::_on_server_channel_data(ssh_session session, ssh_channel channel { _this->m_is_first_server_data = false; - if (info->type != TS_SSH_CHANNEL_TYPE_SFTP) + if (cp->type != TS_SSH_CHANNEL_TYPE_SFTP) { char buf[256] = { 0 }; @@ -1140,7 +1150,7 @@ int SshSession::_on_server_channel_data(ssh_session session, ssh_channel channel "\r\n", _this->m_conn_ip.c_str(), _this->m_conn_port, auth_mode - ); + ); int buf_len = strlen(buf); ex_bin _data; @@ -1148,7 +1158,7 @@ int SshSession::_on_server_channel_data(ssh_session session, ssh_channel channel memcpy(&_data[0], buf, buf_len); memcpy(&_data[buf_len], data, len); - ret = ssh_channel_write(info->channel, &_data[0], _data.size()); + ret = ssh_channel_write(cp->cli_channel, &_data[0], _data.size()); _this->m_recving_from_srv = false; return len; @@ -1157,11 +1167,12 @@ int SshSession::_on_server_channel_data(ssh_session session, ssh_channel channel #endif if (is_stderr) - ret = ssh_channel_write_stderr(info->channel, data, len); + ret = ssh_channel_write_stderr(cp->cli_channel, data, len); else - ret = ssh_channel_write(info->channel, data, len); + ret = ssh_channel_write(cp->cli_channel, data, len); + if (ret == SSH_ERROR) { - EXLOGE("[ssh] send data(%dB) to client failed (2). [%d][%s][%s]\n", len, ret, ssh_get_error(_this->m_cli_session), ssh_get_error(_this->m_cli_session)); + EXLOGE("[ssh] send data(%dB) to client failed. [%d][cli:%s][srv:%s]\n", len, ret, ssh_get_error(_this->m_cli_session), ssh_get_error(_this->m_srv_session)); } _this->m_recving_from_srv = false; @@ -1172,43 +1183,44 @@ void SshSession::_on_server_channel_close(ssh_session session, ssh_channel chann EXLOGD("[ssh] on_server_channel_close().\n"); SshSession *_this = (SshSession *)userdata; - TS_SSH_CHANNEL_INFO *info = _this->_get_cli_channel(channel); - if (NULL == info || NULL == info->channel) { - EXLOGW("[ssh] when server channel close, not found client channel, maybe it already closed.\n"); + + TP_SSH_CHANNEL_PAIR* cp = _this->_get_channel_pair(TP_SSH_SERVER_SIDE, channel); + if (NULL == cp) { + EXLOGE("[ssh] when server channel close, not found channel pair.\n"); return; } - if (!ssh_channel_is_eof(channel)) - ssh_channel_send_eof(channel); - if (!ssh_channel_is_closed(channel)) - ssh_channel_close(channel); - //ssh_channel_free(channel); + // will the server-channel exist, the client-channel must exist too. + if (cp->cli_channel == NULL) { + EXLOGE("[ssh] when server channel close, client-channel not exists.\n"); + } + else { + if (!ssh_channel_is_closed(cp->cli_channel)) { + if (!ssh_channel_is_eof(cp->cli_channel)) { + //EXLOGD("[ssh] when server channel close, send eof to client-channel.\n"); + ssh_channel_send_eof(cp->cli_channel); + } - if (!ssh_channel_is_eof(info->channel)) - ssh_channel_send_eof(info->channel); - if (!ssh_channel_is_closed(info->channel)) - ssh_channel_close(info->channel); - //ssh_channel_free(info->channel); + //EXLOGD("[ssh] when server channel close, close client-channel.\n"); + ssh_channel_close(cp->cli_channel); - { - ExThreadSmartLock locker(_this->m_lock); - - ts_ssh_channel_map::iterator it = _this->m_channel_srv_cli.find(channel); - if (it != _this->m_channel_srv_cli.end()) { - delete it->second; - _this->m_channel_srv_cli.erase(it); - } - else { - EXLOGW("[ssh] when remove server channel, it not in charge..\n"); - } - - it = _this->m_channel_cli_srv.find(info->channel); - if (it != _this->m_channel_cli_srv.end()) { - delete it->second; - _this->m_channel_cli_srv.erase(it); - } - else { - EXLOGW("[ssh] when remove server channel, not found client channel.\n"); + ssh_channel_free(cp->cli_channel); + cp->cli_channel = NULL; } } + + if (!ssh_channel_is_closed(cp->srv_channel)) { + if (!ssh_channel_is_eof(cp->srv_channel)) { + //EXLOGD("[ssh] when server channel close, send eof to server-channel.\n"); + ssh_channel_send_eof(cp->srv_channel); + } + + //EXLOGD("[ssh] when server channel close, close server-channel.\n"); + ssh_channel_close(cp->srv_channel); + + ssh_channel_free(cp->srv_channel); + cp->srv_channel = NULL; + } + + _this->_on_session_end(cp); } diff --git a/server/tp_core/protocol/ssh/ssh_session.h b/server/tp_core/protocol/ssh/ssh_session.h index 67d4458..876ca26 100644 --- a/server/tp_core/protocol/ssh/ssh_session.h +++ b/server/tp_core/protocol/ssh/ssh_session.h @@ -17,24 +17,33 @@ #define TS_SSH_CHANNEL_TYPE_SHELL 1 #define TS_SSH_CHANNEL_TYPE_SFTP 2 -#define TS_SSH_DATA_FROM_CLIENT 1 -#define TS_SSH_DATA_FROM_SERVER 2 - -typedef struct TS_SSH_CHANNEL_INFO -{ - int type; // TS_SSH_CHANNEL_TYPE_SHELL or TS_SSH_CHANNEL_TYPE_SFTP - ssh_channel channel; - - TS_SSH_CHANNEL_INFO() - { - type = TS_SSH_CHANNEL_TYPE_UNKNOWN; - channel = NULL; - } -}TS_SSH_CHANNEL_INFO; - -typedef std::map ts_ssh_channel_map; +#define TP_SSH_CLIENT_SIDE 1 +#define TP_SSH_SERVER_SIDE 2 class SshProxy; +class SshSession; + +class TP_SSH_CHANNEL_PAIR { + + friend class SshSession; + +public: + TP_SSH_CHANNEL_PAIR(); + +private: + int type; // TS_SSH_CHANNEL_TYPE_SHELL or TS_SSH_CHANNEL_TYPE_SFTP + ssh_channel cli_channel; + ssh_channel srv_channel; + + TppSshRec rec; + + int retcode; + int db_id; +}; + +typedef std::list tp_channels; + + class SshSession : public ExThreadBase { @@ -44,9 +53,7 @@ public: SshProxy* get_proxy(void) { return m_proxy; } - - TS_SSH_CHANNEL_INFO* _get_cli_channel(ssh_channel srv_channel); - TS_SSH_CHANNEL_INFO* _get_srv_channel(ssh_channel cli_channel); + TP_SSH_CHANNEL_PAIR* _get_channel_pair(int channel_side, ssh_channel channel); void client_ip(const char* ip) { m_client_ip = ip; } const char* client_ip(void) const { return m_client_ip.c_str(); } @@ -56,24 +63,22 @@ public: void save_record(); protected: - // 继承自 TppSessionBase - bool _on_session_begin(const TPP_CONNECT_INFO* info); - bool _on_session_end(void); - - void _thread_loop(void); void _set_stop_flag(void); - void _process_ssh_command(int from, const ex_u8* data, int len); - void _process_sftp_command(const ex_u8* data, int len); + void _session_error(int err_code); + bool _on_session_begin(TP_SSH_CHANNEL_PAIR* cp); + void _on_session_end(TP_SSH_CHANNEL_PAIR* cp); + + + void _process_ssh_command(TppSshRec* rec, int from, const ex_u8* data, int len); + void _process_sftp_command(TppSshRec* rec, const ex_u8* data, int len); private: void _run(void); void _close_channels(void); - void _enter_sftp_mode(void); - static int _on_auth_password_request(ssh_session session, const char *user, const char *password, void *userdata); static ssh_channel _on_new_channel_request(ssh_session session, void *userdata); static int _on_client_pty_request(ssh_session session, ssh_channel channel, const char *term, int x, int y, int px, int py, void *userdata); @@ -89,10 +94,6 @@ private: static void _on_server_channel_close(ssh_session session, ssh_channel channel, void* userdata); private: - int m_retcode; - int m_db_id; - - TppSshRec m_rec; SshProxy* m_proxy; ssh_session m_cli_session; @@ -103,6 +104,8 @@ private: ex_astr m_client_ip; ex_u16 m_client_port; + TPP_CONNECT_INFO* m_conn_info; + ex_astr m_sid; ex_astr m_conn_ip; ex_u16 m_conn_port; @@ -111,12 +114,10 @@ private: int m_auth_type; bool m_is_first_server_data; - bool m_is_sftp; bool m_is_logon; // 一个ssh_session中可以打开多个ssh_channel - ts_ssh_channel_map m_channel_cli_srv; // 通过客户端通道查找服务端通道 - ts_ssh_channel_map m_channel_srv_cli; // 通过服务端通道查找客户端通道 + tp_channels m_channels; bool m_have_error; diff --git a/server/www/teleport/static/js/audit/record-list.js b/server/www/teleport/static/js/audit/record-list.js index 4b928c5..7fabbfd 100644 --- a/server/www/teleport/static/js/audit/record-list.js +++ b/server/www/teleport/static/js/audit/record-list.js @@ -23,8 +23,8 @@ $app.create_controls = function (cb_stack) { var table_record_options = { dom_id: 'table-record', data_source: { - type: 'ajax-post', - url: '/audit/get-records', + type: 'ajax-post' + ,url: '/audit/get-records' //exclude: {'state': [TP_SESS_STAT_RUNNING, TP_SESS_STAT_STARTED]} }, column_default: {sort: false, align: 'left'}, @@ -42,15 +42,13 @@ $app.create_controls = function (cb_stack) { { title: 'ID', key: 'id', - // sort: true, - // sort_asc: false, + sort: true, + sort_asc: false, fields: {id: 'id'} }, { title: '浼氳瘽ID', key: 'sid', - // sort: true, - // sort_asc: false, render: 'sid', width: 60, fields: {sid: 'sid'} @@ -94,8 +92,8 @@ $app.create_controls = function (cb_stack) { { title: '寮濮嬫椂闂', key: 'time_begin', - sort: true, - sort_asc: false, + // sort: true, + // sort_asc: false, render: 'time_begin', fields: {time_begin: 'time_begin'} }, @@ -162,19 +160,6 @@ $app.create_controls = function (cb_stack) { $app.dom.btn_refresh_record.click(function () { $app.table_record.load_data(); }); - // $app.dom.chkbox_host_select_all.click(function () { - // var _objects = $('#' + $app.table_record.dom_id + ' tbody').find('[data-check-box]'); - // if ($(this).is(':checked')) { - // $.each(_objects, function (i, _obj) { - // $(_obj).prop('checked', true); - // }); - // } else { - // $.each(_objects, function (i, _obj) { - // $(_obj).prop('checked', false); - // }); - // } - // }); - //$app.dom.btn_remove_record.click($app.on_btn_remove_record_click); cb_stack.exec(); }; @@ -273,9 +258,9 @@ $app.on_table_host_render_created = function (render) { case 200: return 'SSH'; case 201: - return 'SFTP'; + return 'SFTP'; case 300: - return 'TELNET'; + return 'TELNET'; default: return '鏈煡'; } @@ -371,9 +356,9 @@ $app.on_table_host_render_created = function (render) { if (fields.state >= TP_SESS_STAT_STARTED || fields.state === TP_SESS_STAT_ERR_RESET) { if (fields.state === TP_SESS_STAT_STARTED) { - ret.push(' 鍚屾 '); + //ret.push(' 鍚屾 '); } else { - // if (fields.protocol_sub_type !== TP_PROTOCOL_TYPE_SSH_SFTP) + if (fields.protocol_sub_type !== TP_PROTOCOL_TYPE_SSH_SFTP) ret.push(' 鍥炴斁 '); } if (fields.protocol_sub_type !== TP_PROTOCOL_TYPE_RDP_DESKTOP) { @@ -395,8 +380,6 @@ $app.on_table_host_header_created = function (header) { // 琛ㄦ牸鍐呭祵杩囨护鍣ㄧ殑浜嬩欢缁戝畾鍦ㄨ繖鏃惰繘琛岋紙涔熷彲浠ュ欢鏈熷埌鏁翠釜琛ㄦ牸鍒涘缓瀹屾垚鏃惰繘琛岋級 header._table_ctrl.get_filter_ctrl('search').on_created(); - // header._table_ctrl.get_filter_ctrl('role').on_created(); - // header._table_ctrl.get_filter_ctrl('state').on_created(); }; $app.get_selected_record = function (tbl) { diff --git a/server/www/teleport/static/js/audit/replay-ssh.js b/server/www/teleport/static/js/audit/replay-ssh.js index 88f97cc..17e4abf 100644 --- a/server/www/teleport/static/js/audit/replay-ssh.js +++ b/server/www/teleport/static/js/audit/replay-ssh.js @@ -40,6 +40,8 @@ $app.req_record_data = function (record_id, offset) { $app.req_record_data(record_id, g_data_offset); } } else { + $app.dom.status.text("璇诲彇褰曞儚鏁版嵁澶辫触锛" + tp_error_msg(ret.code)); + $tp.notify_error('璇诲彇褰曞儚鏁版嵁澶辫触锛' + tp_error_msg(ret.code, ret.message)); console.log('req_record_info error ', ret.code); } }, @@ -76,16 +78,17 @@ $app.on_init = function (cb_stack) { function (ret) { if (ret.code === TPE_OK) { g_header = ret.data; - // console.log('header', g_header); + console.log('header', g_header); $('#recorder-info').html(tp_format_datetime(g_header.start) + ': ' + g_header.user_name + '@' + g_header.client_ip + ' 璁块棶 ' + g_header.account + '@' + g_header.conn_ip + ':' + g_header.conn_port); $app.req_record_data(record_id, 0); g_current_time = 0; - setTimeout(init, 1000); + //setTimeout(init, 500); + init_and_play(); } else { - $tp.notify_error('璇锋眰褰曞儚鏁版嵁澶辫触锛' + tp_error_msg(ret.code, ret.message)); + $tp.notify_error('璇诲彇褰曞儚淇℃伅澶辫触锛' + tp_error_msg(ret.code, ret.message)); console.error('load init info error ', ret.code); } }, @@ -161,9 +164,9 @@ $app.on_init = function (cb_stack) { pause(); }); $app.dom.progress.mouseup(function () { - // console.log(g_current_time); + g_current_time = parseInt(g_header.time_used * $app.dom.progress.val() / 100); setTimeout(function () { - init(); + init_and_play(); }, 100); }); $app.dom.progress.mousemove(function () { @@ -178,7 +181,7 @@ $app.on_init = function (cb_stack) { } }; - function init() { + function init_and_play() { if (_.isNull(g_console_term)) { g_console_term = new Terminal({ cols: g_header.width, @@ -198,18 +201,22 @@ $app.on_init = function (cb_stack) { g_console_term.reset(g_header.width, g_header.height); } + if(g_header.pkg_count === 0) + return; + $app.dom.progress.val(0); - $app.dom.status.text("姝e湪鎾斁"); + // $app.dom.status.text("姝e湪鎾斁"); $app.dom.btn_play.children().removeClass().addClass('fa fa-pause').text(' 鏆傚仠'); g_need_stop = false; g_playing = true; g_finish = false; g_played_pkg_count = 0; - setTimeout(done, g_record_tick); + //setTimeout(do_play, g_record_tick); + do_play(); } - function done() { + function do_play() { if (g_need_stop) { g_playing = false; return; @@ -217,7 +224,7 @@ $app.on_init = function (cb_stack) { if (g_data.length <= g_played_pkg_count) { $app.dom.status.text("姝e湪缂撳瓨鏁版嵁..."); - g_timer = setTimeout(done, g_record_tick); + g_timer = setTimeout(do_play, g_record_tick); return; } @@ -286,7 +293,7 @@ $app.on_init = function (cb_stack) { $app.dom.btn_play.children().removeClass().addClass('fa fa-play').text(' 鎾斁'); } else { if (!g_need_stop) - g_timer = setTimeout(done, _record_tick); + g_timer = setTimeout(do_play, _record_tick); } } @@ -304,7 +311,7 @@ $app.on_init = function (cb_stack) { g_need_stop = false; g_playing = true; - g_timer = setTimeout(done, g_record_tick); + g_timer = setTimeout(do_play, g_record_tick); } function pause() { @@ -320,7 +327,7 @@ $app.on_init = function (cb_stack) { if (!_.isNull(g_timer)) clearTimeout(g_timer); g_current_time = 0; - init(); + init_and_play(); } cb_stack.exec(); diff --git a/server/www/teleport/static/js/ops/session-list.js b/server/www/teleport/static/js/ops/session-list.js index 8951308..6dbf3a2 100644 --- a/server/www/teleport/static/js/ops/session-list.js +++ b/server/www/teleport/static/js/ops/session-list.js @@ -32,7 +32,7 @@ $app.create_controls = function (cb_stack) { // title: '', title: '', key: 'chkbox', - sort: false, + //sort: false, width: 36, align: 'center', render: 'make_check_box', @@ -41,6 +41,8 @@ $app.create_controls = function (cb_stack) { { title: 'ID', key: 'id', + sort: true, + sort_asc: false, fields: {id: 'id'} }, { diff --git a/server/www/teleport/webroot/app/controller/rpc.py b/server/www/teleport/webroot/app/controller/rpc.py index 38da7cf..7f7ab89 100644 --- a/server/www/teleport/webroot/app/controller/rpc.py +++ b/server/www/teleport/webroot/app/controller/rpc.py @@ -90,10 +90,16 @@ class RpcHandler(TPBaseJsonHandler): return self.write_json(TPE_OK, data={'rid': record_id}) def _session_update(self, param): - if 'rid' not in param or 'code' not in param: + try: + rid = param['rid'] + protocol_sub_type = param['protocol_sub_type'] + code = param['code'] + except: + return self.write_json(TPE_PARAM) + if 'rid' not in param or 'code' not in param : return self.write_json(TPE_PARAM) - if not record.session_update(param['rid'], param['code']): + if not record.session_update(rid, protocol_sub_type, code): return self.write_json(TPE_DATABASE, 'can not write database.') else: return self.write_json(TPE_OK) diff --git a/server/www/teleport/webroot/app/model/record.py b/server/www/teleport/webroot/app/model/record.py index 5f8327c..8a882e7 100644 --- a/server/www/teleport/webroot/app/model/record.py +++ b/server/www/teleport/webroot/app/model/record.py @@ -293,9 +293,9 @@ def session_begin(sid, user_id, host_id, acc_id, user_username, acc_username, ho return TPE_OK, record_id -def session_update(record_id, state): +def session_update(record_id, protocol_sub_type, state): db = get_db() - sql = 'UPDATE `{}record` SET state={} WHERE id={};'.format(db.table_prefix, int(state), int(record_id)) + sql = 'UPDATE `{}record` SET protocol_sub_type={}, state={} WHERE id={};'.format(db.table_prefix, protocol_sub_type, int(state), int(record_id)) return db.exec(sql)