mirror of https://github.com/tp4a/teleport
try to solve bug: connect to ssh server, sometimes block when send data to client.
parent
958712745b
commit
dbe893c88c
|
@ -86,7 +86,7 @@ void SshProxy::kill_sessions(const ex_astrs &sessions) {
|
|||
for (size_t i = 0; i < sessions.size(); ++i) {
|
||||
if (it->first->sid() == sessions[i]) {
|
||||
EXLOGW("[ssh] try to kill %s\n", sessions[i].c_str());
|
||||
it->first->check_noop_timeout(0, 0); // 立即结束
|
||||
it->first->check_noop_timeout(0, 0); // 立即结束
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -96,13 +96,15 @@ void SshProxy::_thread_loop() {
|
|||
EXLOGI("[ssh] TeleportServer-SSH ready on %s:%d\n", m_host_ip.c_str(), m_host_port);
|
||||
|
||||
for (;;) {
|
||||
// 注意,ssh_new()出来的指针,如果遇到停止标志,本函数内部就释放了,否则这个指针交给了SshSession类实例管理,其析构时会释放。
|
||||
// 注意,ssh_new()出来的指针,如果遇到停止标志,本函数内部就释放了,否则这个指针交给了SshSession类实例管理,其析构时会释放。
|
||||
ssh_session sess_to_client = ssh_new();
|
||||
|
||||
// int flag = SSH_LOG_FUNCTIONS;
|
||||
// ssh_options_set(sess_to_client, SSH_OPTIONS_LOG_VERBOSITY, &flag);
|
||||
// #ifdef EX_DEBUG
|
||||
// int flag = SSH_LOG_FUNCTIONS;
|
||||
// ssh_options_set(sess_to_client, SSH_OPTIONS_LOG_VERBOSITY, &flag);
|
||||
// #endif
|
||||
|
||||
ssh_set_blocking(sess_to_client, 1);
|
||||
//ssh_set_blocking(sess_to_client, 1);
|
||||
|
||||
struct sockaddr_storage sock_client;
|
||||
char ip[32] = {0};
|
||||
|
@ -145,14 +147,14 @@ void SshProxy::_thread_loop() {
|
|||
sess->start();
|
||||
}
|
||||
|
||||
// 等待所有工作线程退出
|
||||
// 等待所有工作线程退出
|
||||
//m_thread_mgr.stop_all();
|
||||
|
||||
{
|
||||
ExThreadSmartLock locker(m_lock);
|
||||
ts_ssh_sessions::iterator it = m_sessions.begin();
|
||||
for (; it != m_sessions.end(); ++it) {
|
||||
it->first->check_noop_timeout(0, 0); // 立即结束
|
||||
it->first->check_noop_timeout(0, 0); // 立即结束
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -173,7 +175,7 @@ void SshProxy::_on_stop() {
|
|||
ExThreadBase::_on_stop();
|
||||
|
||||
if (m_is_running) {
|
||||
// 用一个变通的方式来结束阻塞中的监听,就是连接一下它。
|
||||
// 用一个变通的方式来结束阻塞中的监听,就是连接一下它。
|
||||
ex_astr host_ip = m_host_ip;
|
||||
if (host_ip == "0.0.0.0")
|
||||
host_ip = "127.0.0.1";
|
||||
|
@ -195,7 +197,7 @@ void SshProxy::_on_stop() {
|
|||
}
|
||||
|
||||
void SshProxy::session_finished(SshSession *sess) {
|
||||
// TODO: 向核心模块汇报此会话终止,以减少对应连接信息的引用计数
|
||||
// TODO: 向核心模块汇报此会话终止,以减少对应连接信息的引用计数
|
||||
|
||||
ExThreadSmartLock locker(m_lock);
|
||||
ts_ssh_sessions::iterator it = m_sessions.find(sess);
|
||||
|
|
|
@ -129,7 +129,7 @@ void SshSession::_record_end(TP_SSH_CHANNEL_PAIR *cp) {
|
|||
if (cp->db_id > 0) {
|
||||
//EXLOGD("[ssh] [channel:%d] channel end with code: %d\n", cp->channel_id, cp->state);
|
||||
|
||||
// 如果会话过程中没有发生错误,则将其状态改为结束,否则记录下错误值
|
||||
// 如果会话过程中没有发生错误,则将其状态改为结束,否则记录下错误值
|
||||
if (cp->state == TP_SESS_STAT_RUNNING || cp->state == TP_SESS_STAT_STARTED)
|
||||
cp->state = TP_SESS_STAT_END;
|
||||
|
||||
|
@ -257,7 +257,7 @@ void SshSession::_run(void) {
|
|||
|
||||
int err = SSH_OK;
|
||||
|
||||
// 安全连接(密钥交换)
|
||||
// 安全连接(密钥交换)
|
||||
err = ssh_handle_key_exchange(m_cli_session);
|
||||
if (err != SSH_OK) {
|
||||
EXLOGE("[ssh] key exchange with client failed: %s\n", ssh_get_error(m_cli_session));
|
||||
|
@ -275,7 +275,7 @@ void SshSession::_run(void) {
|
|||
return;
|
||||
}
|
||||
|
||||
// 认证,并打开一个通道
|
||||
// 认证,并打开一个通道
|
||||
while (!(m_is_logon && !m_channels.empty())) {
|
||||
if (m_have_error)
|
||||
break;
|
||||
|
@ -296,7 +296,7 @@ void SshSession::_run(void) {
|
|||
|
||||
EXLOGW("[ssh] authenticated and got a channel.\n");
|
||||
|
||||
// 现在双方的连接已经建立好了,开始转发
|
||||
// 现在双方的连接已经建立好了,开始转发
|
||||
ssh_event_add_session(event_loop, m_srv_session);
|
||||
do {
|
||||
//err = ssh_event_dopoll(event_loop, 5000);
|
||||
|
@ -333,11 +333,11 @@ void SshSession::_run(void) {
|
|||
ssh_event_free(event_loop);
|
||||
|
||||
|
||||
// 如果一边是走SSHv1,另一边是SSHv2,放在同一个event_loop时,SSHv1会收不到数据,放到循环中时,SSHv2得不到数据
|
||||
// 所以,当SSHv1的远程主机连接后,到建立好shell环境之后,就进入另一种读取数据的循环,不再使用ssh_event_dopoll()了。
|
||||
// 如果一边是走SSHv1,另一边是SSHv2,放在同一个event_loop时,SSHv1会收不到数据,放到循环中时,SSHv2得不到数据
|
||||
// 所以,当SSHv1的远程主机连接后,到建立好shell环境之后,就进入另一种读取数据的循环,不再使用ssh_event_dopoll()了。
|
||||
|
||||
if (m_ssh_ver == 1) {
|
||||
tp_channels::iterator it = m_channels.begin(); // SSHv1只能打开一个channel
|
||||
tp_channels::iterator it = m_channels.begin(); // SSHv1只能打开一个channel
|
||||
ssh_channel cli = (*it)->cli_channel;
|
||||
ssh_channel srv = (*it)->srv_channel;
|
||||
|
||||
|
@ -447,7 +447,7 @@ int SshSession::_on_auth_password_request(ssh_session session, const char *user,
|
|||
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();
|
||||
|
||||
ssh_set_blocking(_this->m_srv_session, 1);
|
||||
// ssh_set_blocking(_this->m_srv_session, 1);
|
||||
|
||||
ssh_options_set(_this->m_srv_session, SSH_OPTIONS_HOST, _this->m_conn_ip.c_str());
|
||||
int port = (int) _this->m_conn_port;
|
||||
|
@ -460,6 +460,9 @@ int SshSession::_on_auth_password_request(ssh_session session, const char *user,
|
|||
// ssh_options_set(_this->m_srv_session, SSH_OPTIONS_LOG_VERBOSITY, &flag);
|
||||
//#endif
|
||||
|
||||
int _timeout_cli = 120; // 120 sec.
|
||||
ssh_options_set(_this->m_cli_session, SSH_OPTIONS_TIMEOUT, &_timeout_cli);
|
||||
|
||||
|
||||
if (_this->m_auth_type != TP_AUTH_TYPE_NONE)
|
||||
ssh_options_set(_this->m_srv_session, SSH_OPTIONS_USER, _this->m_acc_name.c_str());
|
||||
|
@ -478,6 +481,11 @@ int SshSession::_on_auth_password_request(ssh_session session, const char *user,
|
|||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
|
||||
if(ssh_is_blocking(_this->m_cli_session))
|
||||
EXLOGD("[ssh] client session is blocking.\n");
|
||||
if(ssh_is_blocking(_this->m_srv_session))
|
||||
EXLOGD("[ssh] server session is blocking.\n");
|
||||
|
||||
// once the server are connected, change the timeout back to default.
|
||||
_timeout = 120; // in seconds.
|
||||
ssh_options_set(_this->m_srv_session, SSH_OPTIONS_TIMEOUT, &_timeout);
|
||||
|
@ -635,13 +643,13 @@ int SshSession::_on_auth_password_request(ssh_session session, const char *user,
|
|||
}
|
||||
|
||||
ssh_channel SshSession::_on_new_channel_request(ssh_session session, void *userdata) {
|
||||
// 客户端尝试打开一个通道(然后才能通过这个通道发控制命令或者收发数据)
|
||||
// 客户端尝试打开一个通道(然后才能通过这个通道发控制命令或者收发数据)
|
||||
EXLOGV("[ssh] client open channel\n");
|
||||
|
||||
SshSession *_this = (SshSession *) userdata;
|
||||
|
||||
// TODO: 客户端与TP连接使用的总是SSHv2协议,因为最开始连接时还不知道真正的远程主机是不是SSHv1。
|
||||
// 因此此处行为与客户端直连远程主机有些不一样。直连时,SecureCRT的克隆会话功能会因为以为连接的是SSHv1而自动重新连接,而不是打开新通道。
|
||||
// TODO: 客户端与TP连接使用的总是SSHv2协议,因为最开始连接时还不知道真正的远程主机是不是SSHv1。
|
||||
// 因此此处行为与客户端直连远程主机有些不一样。直连时,SecureCRT的克隆会话功能会因为以为连接的是SSHv1而自动重新连接,而不是打开新通道。
|
||||
if (_this->m_ssh_ver == 1 && _this->m_channels.size() != 0) {
|
||||
EXLOGE("[ssh] SSH1 supports only one execution channel. One has already been opened.\n");
|
||||
return NULL;
|
||||
|
@ -654,7 +662,7 @@ ssh_channel SshSession::_on_new_channel_request(ssh_session session, void *userd
|
|||
}
|
||||
ssh_set_channel_callbacks(cli_channel, &_this->m_cli_channel_cb);
|
||||
|
||||
// 我们也要向真正的服务器申请打开一个通道,来进行转发
|
||||
// 我们也要向真正的服务器申请打开一个通道,来进行转发
|
||||
ssh_channel srv_channel = ssh_channel_new(_this->m_srv_session);
|
||||
if (srv_channel == NULL) {
|
||||
EXLOGE("[ssh] can not create channel for server.\n");
|
||||
|
@ -683,7 +691,7 @@ ssh_channel SshSession::_on_new_channel_request(ssh_session session, void *userd
|
|||
return NULL;
|
||||
}
|
||||
|
||||
// 将客户端和服务端的通道关联起来
|
||||
// 将客户端和服务端的通道关联起来
|
||||
{
|
||||
ExThreadSmartLock locker(_this->m_lock);
|
||||
_this->m_channels.push_back(cp);
|
||||
|
@ -795,7 +803,7 @@ int SshSession::_on_client_channel_data(ssh_session session, ssh_channel channel
|
|||
|
||||
SshSession *_this = (SshSession *) userdata;
|
||||
|
||||
// 当前线程正在接收服务端返回的数据,因此我们直接返回,这样紧跟着会重新再发送此数据的
|
||||
// 当前线程正在接收服务端返回的数据,因此我们直接返回,这样紧跟着会重新再发送此数据的
|
||||
if (_this->m_recving_from_srv) {
|
||||
// EXLOGD("recving from srv...try again later...\n");
|
||||
return 0;
|
||||
|
@ -816,14 +824,14 @@ int SshSession::_on_client_channel_data(ssh_session session, ssh_channel channel
|
|||
|
||||
int _len = len;
|
||||
if (cp->type == TS_SSH_CHANNEL_TYPE_SHELL) {
|
||||
// 在收取服务端数据直到显示命令行提示符之前,不允许发送客户端数据到服务端,避免日志记录混乱。
|
||||
// 在收取服务端数据直到显示命令行提示符之前,不允许发送客户端数据到服务端,避免日志记录混乱。
|
||||
if (!cp->server_ready) {
|
||||
_this->m_recving_from_cli = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 不可以拆分!!否则执行 rz 命令会出错!
|
||||
// xxxx 如果用户复制粘贴多行文本,我们将其拆分为每一行发送一次数据包
|
||||
// 不可以拆分!!否则执行 rz 命令会出错!
|
||||
// xxxx 如果用户复制粘贴多行文本,我们将其拆分为每一行发送一次数据包
|
||||
// for (unsigned int i = 0; i < len; ++i) {
|
||||
// if (((ex_u8 *) data)[i] == 0x0d) {
|
||||
// _len = i + 1;
|
||||
|
@ -890,7 +898,7 @@ int SshSession::_on_client_channel_subsystem_request(ssh_session session, ssh_ch
|
|||
cp->last_access_timestamp = (ex_u32) time(NULL);
|
||||
|
||||
|
||||
// 目前只支持SFTP子系统
|
||||
// 目前只支持SFTP子系统
|
||||
if (strcmp(subsystem, "sftp") != 0) {
|
||||
EXLOGE("[ssh] support `sftp` subsystem only, but got `%s`.\n", subsystem);
|
||||
cp->state = TP_SESS_STAT_ERR_UNSUPPORT_PROTOCOL;
|
||||
|
@ -962,7 +970,7 @@ int SshSession::_on_server_channel_data(ssh_session session, ssh_channel channel
|
|||
|
||||
int ret = 0;
|
||||
|
||||
// 收到第一包服务端返回的数据时,在输出数据之前显示一些自定义的信息
|
||||
// 收到第一包服务端返回的数据时,在输出数据之前显示一些自定义的信息
|
||||
#if 1
|
||||
if (!is_stderr && cp->is_first_server_data) {
|
||||
cp->is_first_server_data = false;
|
||||
|
@ -989,13 +997,15 @@ int SshSession::_on_server_channel_data(ssh_session session, ssh_channel channel
|
|||
"\r\n"\
|
||||
"%s\r\n"\
|
||||
"Teleport SSH Bastion Server...\r\n"\
|
||||
" - teleport to %s:%d\r\n"\
|
||||
" - teleport to %s:%d [%d]\r\n"\
|
||||
" - authroized by %s\r\n"\
|
||||
"%s\r\n"\
|
||||
"\r\n\r\n",
|
||||
line.c_str(),
|
||||
_this->m_conn_ip.c_str(),
|
||||
_this->m_conn_port, auth_mode,
|
||||
_this->m_conn_port,
|
||||
cp->db_id,
|
||||
auth_mode,
|
||||
line.c_str()
|
||||
);
|
||||
|
||||
|
@ -1014,15 +1024,45 @@ int SshSession::_on_server_channel_data(ssh_session session, ssh_channel channel
|
|||
#endif
|
||||
|
||||
#if 1
|
||||
// 直接转发数据到客户端
|
||||
if (is_stderr)
|
||||
ret = ssh_channel_write_stderr(cp->cli_channel, data, len);
|
||||
else
|
||||
ret = ssh_channel_write(cp->cli_channel, data, len);
|
||||
//static int idx = 0;
|
||||
|
||||
ssh_set_blocking(_this->m_cli_session, 0);
|
||||
|
||||
int xx = 0;
|
||||
for(xx = 0; xx < 10; ++xx) {
|
||||
|
||||
// idx++;
|
||||
// EXLOGD(">>>>> %d . %d\n", cp->db_id, idx);
|
||||
|
||||
// 直接转发数据到客户端
|
||||
if (is_stderr)
|
||||
ret = ssh_channel_write_stderr(cp->cli_channel, data, len);
|
||||
else
|
||||
ret = ssh_channel_write(cp->cli_channel, data, len);
|
||||
|
||||
// EXLOGD("<<<<< %d . %d\n", cp->db_id, idx);
|
||||
|
||||
if(ret == SSH_OK) {
|
||||
// EXLOGD("ssh_channel_write() ok.\n");
|
||||
break;
|
||||
}
|
||||
else if(ret == SSH_AGAIN) {
|
||||
// EXLOGD("ssh_channel_write() need again, %d.\n", xx);
|
||||
ex_sleep_ms(500);
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
// EXLOGD("ssh_channel_write() failed.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ssh_set_blocking(_this->m_cli_session, 1);
|
||||
|
||||
#else
|
||||
// 分析收到的服务端数据包,如果包含类似 \033]0;AABB\007 这样的数据,客户端会根据此改变窗口标题
|
||||
// 我们需要替换这部分数据,使之显示类似 \033]0;TP#ssh://remote-ip\007 这样的标题。
|
||||
// 但是这样会降低一些性能,因此目前不启用,保留此部分代码备用。
|
||||
// 分析收到的服务端数据包,如果包含类似 \033]0;AABB\007 这样的数据,客户端会根据此改变窗口标题
|
||||
// 我们需要替换这部分数据,使之显示类似 \033]0;TP#ssh://remote-ip\007 这样的标题。
|
||||
// 但是这样会降低一些性能,因此目前不启用,保留此部分代码备用。
|
||||
if (is_stderr) {
|
||||
ret = ssh_channel_write_stderr(cp->cli_channel, data, len);
|
||||
}
|
||||
|
@ -1039,7 +1079,7 @@ int SshSession::_on_server_channel_data(ssh_session session, ssh_channel channel
|
|||
{
|
||||
_end++;
|
||||
|
||||
// 这个包中含有改变标题的数据,将标题换为我们想要的
|
||||
// 这个包中含有改变标题的数据,将标题换为我们想要的
|
||||
EXLOGD("-- found title\n");
|
||||
size_t len_end = len - (_end - (const ex_u8*)data);
|
||||
MemBuffer mbuf;
|
||||
|
@ -1061,7 +1101,7 @@ int SshSession::_on_server_channel_data(ssh_session session, ssh_channel channel
|
|||
if (ret == SSH_ERROR)
|
||||
break;
|
||||
if (ret == mbuf.size()) {
|
||||
ret = len; // 表示我们已经处理了所有的数据了。
|
||||
ret = len; // 表示我们已经处理了所有的数据了。
|
||||
break;
|
||||
}
|
||||
else {
|
||||
|
@ -1140,7 +1180,7 @@ void SshSession::_process_ssh_command(TP_SSH_CHANNEL_PAIR *cp, int from, const e
|
|||
if (TP_SSH_CLIENT_SIDE == from) {
|
||||
if (len >= 2) {
|
||||
if (((ex_u8 *) data)[len - 1] == 0x0d) {
|
||||
// 疑似复制粘贴多行命令一次性执行,将其记录到日志文件中
|
||||
// 疑似复制粘贴多行命令一次性执行,将其记录到日志文件中
|
||||
ex_astr str((const char *) data, len - 1);
|
||||
cp->rec.record_command(1, str);
|
||||
|
||||
|
@ -1149,13 +1189,13 @@ void SshSession::_process_ssh_command(TP_SSH_CHANNEL_PAIR *cp, int from, const e
|
|||
}
|
||||
}
|
||||
|
||||
// 客户端输入回车时,可能时执行了一条命令,需要根据服务端返回的数据进行进一步判断
|
||||
// 客户端输入回车时,可能时执行了一条命令,需要根据服务端返回的数据进行进一步判断
|
||||
cp->maybe_cmd = (data[len - 1] == 0x0d);
|
||||
// if (cp->maybe_cmd)
|
||||
// EXLOGD("[ssh] maybe cmd.\n");
|
||||
|
||||
// 有时在执行类似top命令的情况下,输入一个字母'q'就退出程序,没有输入回车,可能会导致后续记录命令时将返回的命令行提示符作为命令
|
||||
// 记录下来了,要避免这种情况,排除的方式是:客户端单个字母,后续服务端如果收到的是控制序列 1b 5b xx xx,就不计做命令。
|
||||
// 有时在执行类似top命令的情况下,输入一个字母'q'就退出程序,没有输入回车,可能会导致后续记录命令时将返回的命令行提示符作为命令
|
||||
// 记录下来了,要避免这种情况,排除的方式是:客户端单个字母,后续服务端如果收到的是控制序列 1b 5b xx xx,就不计做命令。
|
||||
cp->client_single_char = (len == 1 && isprint(data[0]));
|
||||
|
||||
cp->process_srv = true;
|
||||
|
@ -1194,15 +1234,15 @@ void SshSession::_process_ssh_command(TP_SSH_CHANNEL_PAIR *cp, int from, const e
|
|||
|
||||
case 0x4b: { // 'K'
|
||||
if (0 == esc_arg) {
|
||||
// 删除光标到行尾的字符串
|
||||
// 删除光标到行尾的字符串
|
||||
cp->cmd_char_list.erase(cp->cmd_char_pos, cp->cmd_char_list.end());
|
||||
cp->cmd_char_pos = cp->cmd_char_list.end();
|
||||
} else if (1 == esc_arg) {
|
||||
// 删除从开始到光标处的字符串
|
||||
// 删除从开始到光标处的字符串
|
||||
cp->cmd_char_list.erase(cp->cmd_char_list.begin(), cp->cmd_char_pos);
|
||||
cp->cmd_char_pos = cp->cmd_char_list.end();
|
||||
} else if (2 == esc_arg) {
|
||||
// 删除整行
|
||||
// 删除整行
|
||||
cp->cmd_char_list.clear();
|
||||
cp->cmd_char_pos = cp->cmd_char_list.begin();
|
||||
}
|
||||
|
@ -1211,7 +1251,7 @@ void SshSession::_process_ssh_command(TP_SSH_CHANNEL_PAIR *cp, int from, const e
|
|||
break;
|
||||
}
|
||||
case 0x43: {// ^[C
|
||||
// 光标右移
|
||||
// 光标右移
|
||||
if (esc_arg == 0)
|
||||
esc_arg = 1;
|
||||
for (int j = 0; j < esc_arg; ++j) {
|
||||
|
@ -1222,7 +1262,7 @@ void SshSession::_process_ssh_command(TP_SSH_CHANNEL_PAIR *cp, int from, const e
|
|||
break;
|
||||
}
|
||||
case 0x44: { // ^[D
|
||||
// 光标左移
|
||||
// 光标左移
|
||||
if (esc_arg == 0)
|
||||
esc_arg = 1;
|
||||
for (int j = 0; j < esc_arg; ++j) {
|
||||
|
@ -1234,7 +1274,7 @@ void SshSession::_process_ssh_command(TP_SSH_CHANNEL_PAIR *cp, int from, const e
|
|||
break;
|
||||
}
|
||||
|
||||
case 0x50: {// 'P' 删除指定数量的字符
|
||||
case 0x50: {// 'P' 删除指定数量的字符
|
||||
|
||||
if (esc_arg == 0)
|
||||
esc_arg = 1;
|
||||
|
@ -1246,7 +1286,7 @@ void SshSession::_process_ssh_command(TP_SSH_CHANNEL_PAIR *cp, int from, const e
|
|||
break;
|
||||
}
|
||||
|
||||
case 0x40: { // '@' 插入指定数量的空白字符
|
||||
case 0x40: { // '@' 插入指定数量的空白字符
|
||||
if (esc_arg == 0)
|
||||
esc_arg = 1;
|
||||
for (int j = 0; j < esc_arg; ++j)
|
||||
|
@ -1268,10 +1308,10 @@ void SshSession::_process_ssh_command(TP_SSH_CHANNEL_PAIR *cp, int from, const e
|
|||
|
||||
switch (ch) {
|
||||
case 0x07:
|
||||
// 响铃
|
||||
// 响铃
|
||||
break;
|
||||
case 0x08: {
|
||||
// 光标左移
|
||||
// 光标左移
|
||||
if (cp->cmd_char_pos != cp->cmd_char_list.begin())
|
||||
cp->cmd_char_pos--;
|
||||
break;
|
||||
|
@ -1344,10 +1384,10 @@ void SshSession::_process_sftp_command(TP_SSH_CHANNEL_PAIR *cp, const ex_u8 *dat
|
|||
// SFTP protocol: https://tools.ietf.org/html/draft-ietf-secsh-filexfer-13
|
||||
//EXLOG_BIN(data, len, "[sftp] client channel data");
|
||||
|
||||
// TODO: 根据客户端的请求和服务端的返回,可以进一步判断用户是如何操作文件的,比如读、写等等,以及操作的结果是成功还是失败。
|
||||
// 记录格式: time-offset,flag,action,result,file-path,[file-path]
|
||||
// 其中,flag目前总是为0,可以忽略(为保证与ssh-cmd格式一致),time-offset/action/result 都是数字
|
||||
// file-path是被操作的对象,规格为 长度:实际内容,例如, 13:/root/abc.txt
|
||||
// TODO: 根据客户端的请求和服务端的返回,可以进一步判断用户是如何操作文件的,比如读、写等等,以及操作的结果是成功还是失败。
|
||||
// 记录格式: time-offset,flag,action,result,file-path,[file-path]
|
||||
// 其中,flag目前总是为0,可以忽略(为保证与ssh-cmd格式一致),time-offset/action/result 都是数字
|
||||
// file-path是被操作的对象,规格为 长度:实际内容,例如, 13:/root/abc.txt
|
||||
|
||||
|
||||
if (len < 9)
|
||||
|
@ -1365,7 +1405,7 @@ void SshSession::_process_sftp_command(TP_SSH_CHANNEL_PAIR *cp, const ex_u8 *dat
|
|||
return;
|
||||
}
|
||||
|
||||
// 需要的数据至少14字节
|
||||
// 需要的数据至少14字节
|
||||
// uint32 + byte + uint32 + (uint32 + char + ...)
|
||||
// pkg_len + cmd + req_id + string( length + content...)
|
||||
if (len < 14)
|
||||
|
@ -1398,13 +1438,13 @@ void SshSession::_process_sftp_command(TP_SSH_CHANNEL_PAIR *cp, const ex_u8 *dat
|
|||
break;
|
||||
case 0x12:
|
||||
// 0x12 = 18 = SSH_FXP_RENAME
|
||||
// rename操作数据中包含两个字符串
|
||||
// rename操作数据中包含两个字符串
|
||||
str2_ptr = str1_ptr + str1_len + 4;
|
||||
str2_len = (int) ((str2_ptr[0] << 24) | (str2_ptr[1] << 16) | (str2_ptr[2] << 8) | str2_ptr[3]);
|
||||
break;
|
||||
case 0x15:
|
||||
// 0x15 = 21 = SSH_FXP_LINK
|
||||
// link操作数据中包含两个字符串,前者是新的链接文件名,后者是现有被链接的文件名
|
||||
// link操作数据中包含两个字符串,前者是新的链接文件名,后者是现有被链接的文件名
|
||||
str2_ptr = str1_ptr + str1_len + 4;
|
||||
str2_len = (int) ((str2_ptr[0] << 24) | (str2_ptr[1] << 16) | (str2_ptr[2] << 8) | str2_ptr[3]);
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue