diff --git a/server/tp_core/protocol/ssh/ssh_proxy.cpp b/server/tp_core/protocol/ssh/ssh_proxy.cpp index 324642c..330ccaf 100644 --- a/server/tp_core/protocol/ssh/ssh_proxy.cpp +++ b/server/tp_core/protocol/ssh/ssh_proxy.cpp @@ -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类实例管理,其析构时会释放。 + // 娉ㄦ剰锛宻sh_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); diff --git a/server/tp_core/protocol/ssh/ssh_session.cpp b/server/tp_core/protocol/ssh/ssh_session.cpp index fddf9f9..8b35d89 100644 --- a/server/tp_core/protocol/ssh/ssh_session.cpp +++ b/server/tp_core/protocol/ssh/ssh_session.cpp @@ -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()了。 + // 濡傛灉涓杈规槸璧癝SHv1锛屽彟涓杈规槸SSHv2锛屾斁鍦ㄥ悓涓涓猠vent_loop鏃讹紝SSHv1浼氭敹涓嶅埌鏁版嵁锛屾斁鍒板惊鐜腑鏃讹紝SSHv2寰椾笉鍒版暟鎹 + // 鎵浠ワ紝褰揝SHv1鐨勮繙绋嬩富鏈鸿繛鎺ュ悗锛屽埌寤虹珛濂絪hell鐜涔嬪悗锛屽氨杩涘叆鍙︿竴绉嶈鍙栨暟鎹殑寰幆锛屼笉鍐嶄娇鐢╯sh_event_dopoll()浜嗐 if (m_ssh_ver == 1) { - tp_channels::iterator it = m_channels.begin(); // SSHv1只能打开一个channel + tp_channels::iterator it = m_channels.begin(); // SSHv1鍙兘鎵撳紑涓涓猚hannel 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銆 + // 鍥犳姝ゅ琛屼负涓庡鎴风鐩磋繛杩滅▼涓绘満鏈変簺涓嶄竴鏍枫傜洿杩炴椂锛孲ecureCRT鐨勫厠闅嗕細璇濆姛鑳戒細鍥犱负浠ヤ负杩炴帴鐨勬槸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); - // 我们也要向真正的服务器申请打开一个通道,来进行转发 + // 鎴戜滑涔熻鍚戠湡姝g殑鏈嶅姟鍣ㄧ敵璇锋墦寮涓涓氶亾锛屾潵杩涜杞彂 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; - // 当前线程正在接收服务端返回的数据,因此我们直接返回,这样紧跟着会重新再发送此数据的 + // 褰撳墠绾跨▼姝e湪鎺ユ敹鏈嶅姟绔繑鍥炵殑鏁版嵁锛屽洜姝ゆ垜浠洿鎺ヨ繑鍥烇紝杩欐牱绱ц窡鐫浼氶噸鏂板啀鍙戦佹鏁版嵁鐨 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子系统 + // 鐩墠鍙敮鎸丼FTP瀛愮郴缁 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 杩欐牱鐨勬暟鎹紝瀹㈡埛绔細鏍规嵁姝ゆ敼鍙樼獥鍙f爣棰 + // 鎴戜滑闇瑕佹浛鎹㈣繖閮ㄥ垎鏁版嵁锛屼娇涔嬫樉绀虹被浼 \033]0;TP#ssh://remote-ip\007 杩欐牱鐨勬爣棰樸 + // 浣嗘槸杩欐牱浼氶檷浣庝竴浜涙ц兘锛屽洜姝ょ洰鍓嶄笉鍚敤锛屼繚鐣欐閮ㄥ垎浠g爜澶囩敤銆 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,就不计做命令。 + // 鏈夋椂鍦ㄦ墽琛岀被浼紅op鍛戒护鐨勬儏鍐典笅锛岃緭鍏ヤ竴涓瓧姣'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] + // 鍏朵腑锛宖lag鐩墠鎬绘槸涓0锛屽彲浠ュ拷鐣ワ紙涓轰繚璇佷笌ssh-cmd鏍煎紡涓鑷达級锛宼ime-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;