mirror of https://github.com/tp4a/teleport
改进:
1. SSH按通道进行记录录像,避免一个会话多个通道时录像数据混杂导致播放混乱; 2. 无论是SSH-Shell还是SSH-SFTP,均能够根据实际建立连接并进行操作正确记录其类型,方便界面展示; 3. 核心模块能够处理连接信息的引用计数,因此SFTP上编辑、保存文件可以正常工作了; 4. 能够正确处理绝大部分断开连接后状态还在“使用中”的问题,但SecureCRT通过“连接SFTP标签页”后,有时仍然存在此问题。pull/105/head
parent
83b9ba01bc
commit
907cb1b9e1
|
@ -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 // 会话结束,因为无法连接到远程主机
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
#include <memory>
|
||||
|
||||
//#include <sys/types.h>
|
||||
//#include <sys/stat.h>
|
||||
|
||||
#include "base_record.h"
|
||||
|
||||
TppRecBase::TppRecBase()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
// Ïß³ÌÑ»·
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -7,18 +7,6 @@
|
|||
|
||||
typedef std::map<SshSession*, unsigned char> 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<ex_astr, TS_SFTP_SESSION_INFO*> 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;
|
||||
};
|
||||
|
|
|
@ -5,19 +5,27 @@
|
|||
#include <algorithm>
|
||||
#include <teleport_const.h>
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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<ssh_channel, TS_SSH_CHANNEL_INFO*> 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_SSH_CHANNEL_PAIR*> 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;
|
||||
|
||||
|
|
|
@ -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 '<span class="label label-success">SSH</span>';
|
||||
case 201:
|
||||
return '<span class="label label-success">SFTP</span>';
|
||||
return '<span class="label label-info">SFTP</span>';
|
||||
case 300:
|
||||
return '<span class="label label-success">TELNET</span>';
|
||||
return '<span class="label label-warning">TELNET</span>';
|
||||
default:
|
||||
return '<span class="label label-danger">未知</span>';
|
||||
}
|
||||
|
@ -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('<a href="javascript:;" class="btn btn-sm btn-warning" data-action="sync" data-record-id="' + fields.id + '"><i class="fa fa-clone fa-fw"></i> 同步</a> ');
|
||||
//ret.push('<a href="javascript:;" class="btn btn-sm btn-warning" data-action="sync" data-record-id="' + fields.id + '"><i class="fa fa-clone fa-fw"></i> 同步</a> ');
|
||||
} else {
|
||||
// if (fields.protocol_sub_type !== TP_PROTOCOL_TYPE_SSH_SFTP)
|
||||
if (fields.protocol_sub_type !== TP_PROTOCOL_TYPE_SSH_SFTP)
|
||||
ret.push('<a href="javascript:;" class="btn btn-sm btn-primary" data-action="replay" data-record-id="' + fields.id + '"><i class="fa fa-caret-square-o-right fa-fw"></i> 回放</a> ');
|
||||
}
|
||||
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) {
|
||||
|
|
|
@ -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("正在播放");
|
||||
// $app.dom.status.text("正在播放");
|
||||
$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("正在缓存数据...");
|
||||
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();
|
||||
|
|
|
@ -32,7 +32,7 @@ $app.create_controls = function (cb_stack) {
|
|||
// title: '<input type="checkbox" id="user-list-select-all" value="">',
|
||||
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'}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue