telnet可以录像和播放了(还不能记录命令,不能感知客户端窗口大小变化)
							parent
							
								
									db9838e480
								
							
						
					
					
						commit
						21e07f7b32
					
				|  | @ -46,7 +46,7 @@ bind-ip=0.0.0.0 | |||
| bind-port=52089 | ||||
| 
 | ||||
| [protocol-telnet] | ||||
| enabled=false | ||||
| enabled=true | ||||
| lib=tptelnet | ||||
| bind-ip=0.0.0.0 | ||||
| bind-port=52389 | ||||
|  |  | |||
|  | @ -14,8 +14,6 @@ TelnetConn::TelnetConn(TelnetSession *sess, bool is_server_side) : m_session(ses | |||
| 		m_state = TELNET_CONN_STATE_FREE; | ||||
|     } | ||||
| 
 | ||||
|     m_is_recving = false; | ||||
| 
 | ||||
| 	m_timer_running = false; | ||||
| 
 | ||||
|     uv_tcp_init(sess->get_loop(), &m_handle); | ||||
|  | @ -26,7 +24,6 @@ TelnetConn::~TelnetConn() { | |||
| } | ||||
| 
 | ||||
| bool TelnetConn::start_recv() { | ||||
| 	m_is_recving = true; | ||||
| 	int err = uv_read_start((uv_stream_t *)&m_handle, _on_alloc, _on_recv); | ||||
| 	if (err != 0) { | ||||
| 		EXLOGE("[telnet] [%s] can not start to read.\n", m_name); | ||||
|  | @ -34,7 +31,6 @@ bool TelnetConn::start_recv() { | |||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	m_is_recving = true; | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
|  | @ -53,41 +49,12 @@ void TelnetConn::close() { | |||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	if (m_is_recving) { | ||||
| 		m_is_recving = false; | ||||
| 		uv_read_stop((uv_stream_t*)&m_handle); | ||||
| 	} | ||||
| 
 | ||||
| // 	int uverr = 0;
 | ||||
| // 	uv_shutdown_t *sreq = (uv_shutdown_t *)calloc(1, sizeof(uv_shutdown_t));
 | ||||
| // 	sreq->data = this;
 | ||||
| // 	if ((uverr = uv_shutdown(sreq, stream_handle(), _uv_on_shutdown)) != 0) {
 | ||||
| // 		EXLOGW("[telnet] [%s] error when shutdown connection. %s\n", m_name, uv_strerror(uverr));
 | ||||
| // 		free(sreq);
 | ||||
| // 
 | ||||
| // 		m_state = TELNET_CONN_STATE_FREE;
 | ||||
| // 
 | ||||
| // 		m_session->on_conn_close();
 | ||||
| // 	}
 | ||||
| // 	else {
 | ||||
| // 		m_state = RDP_CONN_STATE_CLOSING;
 | ||||
| // 	}
 | ||||
| 
 | ||||
| 	uv_read_stop((uv_stream_t*)&m_handle); | ||||
| 	uv_close(handle() , _uv_on_closed); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // void TelnetConn::_uv_on_shutdown(uv_shutdown_t *req, int status) {
 | ||||
| // 	TelnetConn *_this = (TelnetConn *)req->data;
 | ||||
| // 	//EXLOGD("[telnet] [%s]  .. _uv_on_shutdown, status=%d\n", _this->m_name, status);
 | ||||
| // 	uv_close((uv_handle_t *)req->handle, _uv_on_closed);
 | ||||
| // 	free(req);
 | ||||
| // }
 | ||||
| 
 | ||||
| void TelnetConn::_uv_on_closed(uv_handle_t *handle) { | ||||
| 	TelnetConn *_this = (TelnetConn *)handle->data; | ||||
| 	//EXLOGD("[telnet] [%s]  .. _uv_on_closed\n", _this->m_name);
 | ||||
| 	_this->m_state = TELNET_CONN_STATE_FREE; | ||||
| 	_this->m_session->on_conn_close(); | ||||
| } | ||||
|  | @ -101,11 +68,8 @@ void TelnetConn::_on_alloc(uv_handle_t *handle, size_t suggested_size, uv_buf_t | |||
| void TelnetConn::_on_recv(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf) { | ||||
|     TelnetConn *_this = (TelnetConn *) handle->data; | ||||
| 
 | ||||
|     //ExThreadSmartLock locker(_this->m_locker_recv);
 | ||||
| 
 | ||||
|     if (nread == 0) { | ||||
|         free(buf->base); | ||||
|         //_this->m_session->do_next(_this);
 | ||||
|         return; | ||||
|     } | ||||
|     else if (nread < 0) { | ||||
|  | @ -128,8 +92,6 @@ void TelnetConn::_on_recv(uv_stream_t *handle, ssize_t nread, const uv_buf_t *bu | |||
| // #endif
 | ||||
| 	} | ||||
| 
 | ||||
| 	EXLOG_BIN((ex_u8*)buf->base, nread, "--READ-- %s", _this->m_name); | ||||
| 
 | ||||
|     _this->m_buf_data.append((ex_u8 *) buf->base, nread); | ||||
|     free(buf->base); | ||||
| 
 | ||||
|  | @ -140,17 +102,6 @@ bool TelnetConn::send(MemBuffer &mbuf) { | |||
|     return _raw_send(mbuf.data(), mbuf.size()); | ||||
| } | ||||
| 
 | ||||
| // bool TelnetConn::send(TelnetPkgBase &pkg) {
 | ||||
| //     MemBuffer mbuf;
 | ||||
| //     MemStream s(mbuf);
 | ||||
| //     if (TPE_OK != pkg.build(s)) {
 | ||||
| //         EXLOGE("[telnet] when send, can not build package to binary.\n");
 | ||||
| //         return false;
 | ||||
| //     }
 | ||||
| // 
 | ||||
| //     return _raw_send(mbuf.data(), mbuf.size());
 | ||||
| // }
 | ||||
| 
 | ||||
| bool TelnetConn::send(const ex_u8 *data, size_t size) { | ||||
|     return _raw_send(data, size); | ||||
| } | ||||
|  | @ -158,13 +109,9 @@ bool TelnetConn::send(const ex_u8 *data, size_t size) { | |||
| bool TelnetConn::_raw_send(const ex_u8 *data, size_t size) { | ||||
| // #ifdef LOG_DATA
 | ||||
| // 	if (!m_session->is_relay())
 | ||||
| 		EXLOG_BIN(data, size, "[telnet] [%s] SEND %dB.", m_name, size); | ||||
| // 		EXLOG_BIN(data, size, "[telnet] [%s] SEND %dB.", m_name, size);
 | ||||
| // #endif
 | ||||
| 
 | ||||
|     return raw_send(data, size); | ||||
| } | ||||
| 
 | ||||
| bool TelnetConn::raw_send(const ex_u8 *data, size_t size) { | ||||
| 	uv_write_t *w = (uv_write_t *) calloc(1, sizeof(uv_write_t)); | ||||
| 
 | ||||
|     ex_u8 *_data = (ex_u8 *) calloc(1, size); | ||||
|  | @ -252,7 +199,6 @@ void TelnetConn::connect(const char *server_ip, ex_u16 server_port) { | |||
| void TelnetConn::_uv_on_connect_timeout(uv_timer_t *timer) | ||||
| { | ||||
| 	TelnetConn *_this = (TelnetConn *)timer->data; | ||||
| 	//EXLOGD("[telnet] [%s]  .. _uv_on_connect_timeout.\n", _this->m_name);
 | ||||
| 
 | ||||
| 	if (_this->m_timer_running) { | ||||
| 		_this->m_timer_running = false; | ||||
|  | @ -268,7 +214,6 @@ void TelnetConn::_uv_on_connect_timeout(uv_timer_t *timer) | |||
| 
 | ||||
| void TelnetConn::_uv_on_reconnect(uv_handle_t *handle) { | ||||
| 	TelnetConn *_this = (TelnetConn *)handle->data; | ||||
| 	//EXLOGD("[telnet] [%s]  .. _uv_on_reconnect.\n", _this->m_name);
 | ||||
| 	_this->m_state = TELNET_CONN_STATE_FREE; | ||||
| 
 | ||||
|     uv_tcp_init(_this->m_session->get_loop(), &_this->m_handle); | ||||
|  | @ -280,7 +225,6 @@ void TelnetConn::_uv_on_reconnect(uv_handle_t *handle) { | |||
| void TelnetConn::_uv_on_connected(uv_connect_t *req, int status) { | ||||
| 	TelnetConn *_this = (TelnetConn *)req->data; | ||||
|     free(req); | ||||
| 	//EXLOGD("[telnet] [%s]  .. _uv_on_connected: status=%d.\n", _this->m_name, status);
 | ||||
| 
 | ||||
| 	if (_this->m_timer_running) { | ||||
| 		_this->m_timer_running = false; | ||||
|  | @ -308,5 +252,4 @@ void TelnetConn::_uv_on_connected(uv_connect_t *req, int status) { | |||
| 
 | ||||
| //static
 | ||||
| void TelnetConn::_uv_on_timer_connect_timeout_closed(uv_handle_t *handle) { | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -3,19 +3,8 @@ | |||
| 
 | ||||
| #include <uv.h> | ||||
| 
 | ||||
| // typedef time_t mbedtls_time_t;
 | ||||
| 
 | ||||
| // #include <mbedtls/arc4.h>
 | ||||
| // #include <mbedtls/ssl.h>
 | ||||
| // #include <mbedtls/entropy.h>
 | ||||
| // #include <mbedtls/ctr_drbg.h>
 | ||||
| 
 | ||||
| // #include "telnet_package.h"
 | ||||
| #include "../../common/ts_membuf.h" | ||||
| #include "../../common/ts_memstream.h" | ||||
| // #include "telnet_bulk.h"
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| //#define LOG_DATA
 | ||||
| 
 | ||||
|  | @ -47,45 +36,14 @@ public: | |||
|     MemBuffer &data() { return m_buf_data; } | ||||
| 
 | ||||
|     bool send(MemBuffer &mbuf); | ||||
| //     bool send(TelnetPkgBase &pkg);
 | ||||
|     bool send(const ex_u8 *data, size_t size); | ||||
|     bool raw_send(const ex_u8 *data, size_t size); | ||||
| 
 | ||||
| 	// connect to real server, for proxy-client-side only.
 | ||||
|     void connect(const char *server_ip, ex_u16 server_port = 3389); | ||||
| 	// try to close this connection. return current RDP_CONN_STATE_XXXX.
 | ||||
| 	// try to close this connection. return current TELNET_CONN_STATE_XXXX.
 | ||||
| 	void close(); | ||||
| 	bool start_recv(); | ||||
| 
 | ||||
| 
 | ||||
|     // 密钥相关
 | ||||
| //     void gen_session_keys(ex_u8 *client_random, ex_u8 *server_random);
 | ||||
| //     void decrypt(ex_u8 *buf_data, size_t buf_size, bool update_counter);
 | ||||
| //     void encrypt(ex_u8 *buf_data, size_t buf_size, bool update_counter);
 | ||||
| //     ex_u32 get_dec_counter() { return m_decrypt_total; }
 | ||||
| //     ex_u32 get_enc_counter() { return m_encrypt_total; }
 | ||||
| //     void calc_mac(ex_u8 *buf_data, size_t buf_size, ex_u8 *signature, bool with_counter = false, ex_u32 counter = 0);
 | ||||
| 
 | ||||
|     // RDP-SSL 相关
 | ||||
| //     bool ssl_prepare();
 | ||||
| 
 | ||||
| //     mbedtls_ssl_context *ssl_context() { return &m_ssl_ctx; }
 | ||||
| 
 | ||||
| // 	bool ssl_is_in_handshake() { return m_ssl_ctx.state != MBEDTLS_SSL_HANDSHAKE_OVER; }
 | ||||
| //     int ssl_do_handshake();
 | ||||
| //     int ssl_do_read();
 | ||||
| 
 | ||||
| //     bool ssl_send(MemBuffer &mbuf);
 | ||||
| //     bool ssl_send(TelnetPkgBase &pkg);
 | ||||
| //     bool ssl_send(const ex_u8 *data, size_t size);
 | ||||
| 
 | ||||
| //     MemBuffer &ssl_data() { return m_ssl_mbuf; }
 | ||||
| 
 | ||||
| //     static int on_ssl_read(void *ctx, ex_u8 *buf, size_t len);
 | ||||
| //     static int on_ssl_write(void *ctx, const ex_u8 *buf, size_t len);
 | ||||
| 
 | ||||
| 	//RDP_BULK* get_bulk() { return m_bulk; }
 | ||||
| 
 | ||||
| private: | ||||
|     static void _on_alloc(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf); | ||||
|     static void _on_recv(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf); | ||||
|  | @ -93,18 +51,10 @@ private: | |||
| 	static void _uv_on_connect_timeout(uv_timer_t *timer); | ||||
|     static void _uv_on_connected(uv_connect_t *req, int status); | ||||
|     static void _uv_on_reconnect(uv_handle_t *handle); | ||||
| 	static void _uv_on_shutdown(uv_shutdown_t *req, int status); | ||||
| 	static void _uv_on_closed(uv_handle_t *handle); | ||||
| 	static void _uv_on_timer_connect_timeout_closed(uv_handle_t *handle); | ||||
| 
 | ||||
| //     static void _sec_hash_48(ex_u8 *buf_out, ex_u8 *buf_in, ex_u8 *salt1, ex_u8 *salt2, ex_u8 salt);
 | ||||
| // 	static void _sec_hash_16(ex_u8 *buf_out, ex_u8 *buf_in, ex_u8 *salt1, ex_u8 *salt2);
 | ||||
| //     void _sec_update(ex_u8 *init_key, ex_u8 *curr_key);
 | ||||
| 
 | ||||
|     bool _raw_send(const ex_u8 *data, size_t size); | ||||
| //     bool _ssl_send(const ex_u8 *data, size_t size);
 | ||||
| //     bool _ssl_prepare_as_server();
 | ||||
| //     bool _ssl_prepare_as_client();
 | ||||
| 
 | ||||
| private: | ||||
|     TelnetSession *m_session; | ||||
|  | @ -117,46 +67,13 @@ private: | |||
| 	uv_timer_t m_timer_connect_timeout; | ||||
| 	bool m_timer_running;  // does m_timer_connect_timeout initialized and started.
 | ||||
| 
 | ||||
| 	ex_u8 m_state; // RDP_CONN_STATE_XXXX
 | ||||
| 	ex_u8 m_state; // TELNET_CONN_STATE_XXXX
 | ||||
| 
 | ||||
|     // 作为client需要的数据(远程主机信息)
 | ||||
|     std::string m_server_ip; | ||||
|     ex_u16 m_server_port; | ||||
|     bool m_is_recving;      // does this connection is receiving data?
 | ||||
| 
 | ||||
|     ExThreadLock m_locker_send; | ||||
|     ExThreadLock m_locker_recv; | ||||
|     MemBuffer m_buf_data; | ||||
| 
 | ||||
| 
 | ||||
|     // 会话密钥相关
 | ||||
| //     ex_u8 m_rc4_key_len;
 | ||||
| //     ex_u8 m_mac_key[16];
 | ||||
| //     ex_u8 m_init_enc_key[16];
 | ||||
| //     ex_u8 m_init_dec_key[16];
 | ||||
| //     ex_u8 m_curr_enc_key[16];
 | ||||
| //     ex_u8 m_curr_dec_key[16];
 | ||||
| //     mbedtls_arc4_context m_rc4_encrypt_key;
 | ||||
| //     mbedtls_arc4_context m_rc4_decrypt_key;
 | ||||
| 
 | ||||
| //     ex_u32 m_encrypt_count;
 | ||||
| //     ex_u32 m_decrypt_count;
 | ||||
| //     ex_u32 m_encrypt_total;
 | ||||
| //     ex_u32 m_decrypt_total;
 | ||||
| 
 | ||||
| 
 | ||||
|     // RDP-SSL相关
 | ||||
| //     MemBuffer m_ssl_mbuf;     // 存放接收到的数据(经过ssl解密)的缓冲区,等待处理。处理函数处理之后,应该将已经处理过的数据弹掉。
 | ||||
| //     mbedtls_ssl_context m_ssl_ctx;
 | ||||
| //     mbedtls_x509_crt m_ssl_node_cert;
 | ||||
| //     mbedtls_pk_context m_ssl_node_key;
 | ||||
| //     mbedtls_ssl_config m_ssl_conf;
 | ||||
| //     mbedtls_entropy_context m_ssl_entropy;
 | ||||
| //     mbedtls_ctr_drbg_context m_ssl_ctr_drbg;
 | ||||
| //     mbedtls_x509_crt m_ssl_ca_cert;
 | ||||
| 
 | ||||
| 	// 数据包解析相关
 | ||||
| 	//RDP_BULK* m_bulk;
 | ||||
| }; | ||||
| 
 | ||||
| #endif // __TELNET_CONN_H__
 | ||||
|  |  | |||
|  | @ -60,15 +60,6 @@ void TppTelnetRec::save_record() { | |||
| 	_save_to_cmd_file(); | ||||
| } | ||||
| 
 | ||||
| // void TppTelnetRec::record_time_begin(void)	// 指定从此时开始计时,之前收到的包会计时为0,这样播放时会快进到此处。
 | ||||
| // {
 | ||||
| // 	m_start_time = ex_get_tick_count();
 | ||||
| // //	m_head.timestamp = time(NULL);
 | ||||
| // 	m_head.basic.timestamp = (ex_u64)time(NULL);
 | ||||
| // 	m_save_full_header = true;
 | ||||
| // 	m_header_changed = true;
 | ||||
| // }
 | ||||
| 
 | ||||
| void TppTelnetRec::record(ex_u8 type, const ex_u8* data, size_t size) | ||||
| { | ||||
| 	if (data == NULL || 0 == size) | ||||
|  | @ -100,7 +91,6 @@ void TppTelnetRec::record_win_size(int width, int height) | |||
| 	m_head.basic.height = (ex_u16)height; | ||||
| 	m_save_full_header = true; | ||||
| 	m_header_changed = true; | ||||
| 	//_save_to_info_file();
 | ||||
| } | ||||
| 
 | ||||
| bool TppTelnetRec::_save_to_info_file() { | ||||
|  |  | |||
|  | @ -23,7 +23,6 @@ public: | |||
| 	TppTelnetRec(); | ||||
| 	virtual ~TppTelnetRec(); | ||||
| 
 | ||||
| // 	void record_time_begin(void); // 指定从此时开始计时,之前收到的包会计时为0,这样播放时会快进到此处。
 | ||||
| 	void record(ex_u8 type, const ex_u8* data, size_t size); | ||||
| 	void record_win_size(int width, int height); | ||||
| 
 | ||||
|  |  | |||
|  | @ -16,8 +16,8 @@ TelnetSession::TelnetSession(TelnetProxy *proxy) : | |||
| 	m_proxy(proxy), | ||||
| 	m_conn_info(NULL) | ||||
| { | ||||
| 	m_client_type = 0; | ||||
| 	m_state = TP_SESS_STAT_RUNNING; | ||||
| 	m_record_started = false; | ||||
| 	m_db_id = 0; | ||||
| 	m_is_relay = false; | ||||
| 	m_is_closed = false; | ||||
|  | @ -40,9 +40,6 @@ TelnetSession::~TelnetSession() { | |||
| 	delete m_conn_client; | ||||
| 	delete m_conn_server; | ||||
| 
 | ||||
| // 	mbedtls_rsa_free(&m_server_pubkey);
 | ||||
| // 	mbedtls_rsa_free(&m_proxy_keypair_dynamic);
 | ||||
| 
 | ||||
| 	if (NULL != m_conn_info) { | ||||
| 		g_telnet_env.free_connect_info(m_conn_info); | ||||
| 	} | ||||
|  | @ -126,21 +123,9 @@ void TelnetSession::do_next(TelnetConn *conn) { | |||
| 	case s_negotiation_with_client: | ||||
| 		new_status = _do_negotiation_with_client(conn); | ||||
| 		break; | ||||
| // 	case s_ssl_handshake_with_client:    // 与客户端端进行SSL握手
 | ||||
| // 		new_status = _do_ssl_handshake_with_client();
 | ||||
| // 		break;
 | ||||
| // 	case s_connect_server:
 | ||||
| // 		new_status = _do_connect_server();
 | ||||
| // 		break;
 | ||||
| 	case s_server_connected: | ||||
| 		new_status = _do_server_connected(); | ||||
| 		break; | ||||
| // 	case s_negotiation_with_server:
 | ||||
| // 		new_status = _do_negotiation_with_server();
 | ||||
| // 		break;
 | ||||
| // 	case s_ssl_handshake_with_server:
 | ||||
| // 		new_status = _do_ssl_handshake_with_server();
 | ||||
| // 		break;
 | ||||
| 	case s_relay: | ||||
| 		new_status = _do_relay(conn); | ||||
| 		break; | ||||
|  | @ -164,7 +149,6 @@ void TelnetSession::do_next(TelnetConn *conn) { | |||
| 	if (m_status == s_dead) { | ||||
| 		EXLOGW("[telnet] try to remove session.\n"); | ||||
| 		_on_session_end(); | ||||
| 		//m_proxy->session_finished(this);
 | ||||
| 		m_is_closed = true; | ||||
| 		m_proxy->clean_session(); | ||||
| 	} | ||||
|  | @ -410,9 +394,6 @@ sess_state TelnetSession::_do_negotiation_with_client(TelnetConn* conn) { | |||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// 记录日志,会话开始了
 | ||||
| // 		set_info(sess_info);
 | ||||
| 
 | ||||
| 		// try to connect to real server.
 | ||||
| 		m_conn_server->connect(m_conn_ip.c_str(), m_conn_port); | ||||
| 
 | ||||
|  | @ -439,6 +420,7 @@ sess_state TelnetSession::_do_server_connected() { | |||
| 		m_conn_server->send(_d, sizeof(_d) - 1); | ||||
| 	} | ||||
| 
 | ||||
| 	m_is_relay = true; | ||||
| 	EXLOGW("[telnet] enter relay mode.\n"); | ||||
| 
 | ||||
| 	return s_relay; | ||||
|  | @ -451,15 +433,6 @@ sess_state TelnetSession::_do_relay(TelnetConn *conn) { | |||
| 	if (conn->is_server_side()) | ||||
| 	{ | ||||
| 		// 收到了客户端发来的数据
 | ||||
| // 		if (!_this->m_is_changle_title_sent)
 | ||||
| // 		{
 | ||||
| // 			_this->m_is_changle_title_sent = true;
 | ||||
| // 			ts_astr msg = "\033]0;TP#telnet://";
 | ||||
| // 			msg += m_server_ip;
 | ||||
| // 			msg += "\007\x0d\x0a";
 | ||||
| // 			m_conn_client->send((ts_u8*)msg.c_str(), msg.length());
 | ||||
| // 		}
 | ||||
| 
 | ||||
| 		if (_this->m_is_putty_mode && !_this->m_is_putty_eat_username) | ||||
| 		{ | ||||
| 			if (_this->_eat_username(m_conn_client, m_conn_server)) | ||||
|  | @ -482,6 +455,8 @@ sess_state TelnetSession::_do_relay(TelnetConn *conn) { | |||
| 	else | ||||
| 	{ | ||||
| 		// 收到了服务端返回的数据
 | ||||
| 		if(m_record_started) | ||||
| 			m_rec.record(TS_RECORD_TYPE_TELNET_DATA, m_conn_server->data().data(), m_conn_server->data().size()); | ||||
| 
 | ||||
| 		if (!_this->m_username_sent && _this->m_acc_name.length() > 0) | ||||
| 		{ | ||||
|  | @ -497,6 +472,14 @@ sess_state TelnetSession::_do_relay(TelnetConn *conn) { | |||
| 			{ | ||||
| 				_this->m_password_sent = true; | ||||
| 				is_processed = true; | ||||
| 
 | ||||
| 				if (!m_record_started) { | ||||
| 					m_record_started = true; | ||||
| 					if (!_on_session_begin()) { | ||||
| 						return _do_close(TP_SESS_STAT_ERR_INTERNAL); | ||||
| 					} | ||||
| 				} | ||||
| 
 | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
|  | @ -506,54 +489,7 @@ sess_state TelnetSession::_do_relay(TelnetConn *conn) { | |||
| 			return s_relay; | ||||
| 		} | ||||
| 
 | ||||
| 
 | ||||
| 		// 替换会导致客户端窗口标题改变的数据
 | ||||
| 		//ts_u8* data = m_conn_server->data().data();
 | ||||
| 		//size_t len = m_conn_server->data().size();
 | ||||
| // 		if (len > 5)
 | ||||
| // 		{
 | ||||
| // 			const ts_u8* _begin = memmem(data, len, (const ts_u8*)"\033]0;", 4);
 | ||||
| // 
 | ||||
| // 			if (NULL != _begin)
 | ||||
| // 			{
 | ||||
| // 				size_t len_before = _begin - data;
 | ||||
| // 
 | ||||
| // 				const ts_u8* _end = memmem(_begin + 4, len - len_before, (const ts_u8*)"\007", 1);
 | ||||
| // 				if (NULL != _end)
 | ||||
| // 				{
 | ||||
| // 					_end++;
 | ||||
| // 
 | ||||
| // 					// 这个包中含有改变标题的数据,将标题换为我们想要的
 | ||||
| // 					size_t len_end = len - (_end - data);
 | ||||
| // 					MemBuffer mbuf;
 | ||||
| // 
 | ||||
| // 					if (len_before > 0)
 | ||||
| // 						mbuf.append(data, len_before);
 | ||||
| // 
 | ||||
| // 					mbuf.append((ts_u8*)"\033]0;TP#ssh://", 13);
 | ||||
| // 					mbuf.append((ts_u8*)_this->m_server_ip.c_str(), _this->m_server_ip.length());
 | ||||
| // 					mbuf.append((ts_u8*)"\007", 1);
 | ||||
| // 
 | ||||
| // 					if (len_end > 0)
 | ||||
| // 						mbuf.append(_end, len_end);
 | ||||
| // 
 | ||||
| // 					m_conn_client->send(mbuf.data(), mbuf.size());
 | ||||
| // 				}
 | ||||
| // 				else
 | ||||
| // 				{
 | ||||
| // 					m_conn_client->send(m_conn_server->data().data(), m_conn_server->data().size());
 | ||||
| // 				}
 | ||||
| // 			}
 | ||||
| // 			else
 | ||||
| // 			{
 | ||||
| // 				m_conn_client->send(m_conn_server->data().data(), m_conn_server->data().size());
 | ||||
| // 			}
 | ||||
| // 		}
 | ||||
| // 		else
 | ||||
| 		{ | ||||
| 			m_conn_client->send(m_conn_server->data().data(), m_conn_server->data().size()); | ||||
| 		} | ||||
| 
 | ||||
| 		m_conn_client->send(m_conn_server->data().data(), m_conn_server->data().size()); | ||||
| 		m_conn_server->data().empty(); | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -12,7 +12,6 @@ enum sess_state { | |||
| 	s_client_connect,	// 客户端连接
 | ||||
| 	s_negotiation_with_client,	// 与客户端进行握手,直到得到客户端发来的登录用户名(其实是SessionID)
 | ||||
| 
 | ||||
| // 	s_connect_server,	// 与服务端连接
 | ||||
| 	s_server_connected,	// 成功连接上服务器了
 | ||||
| 
 | ||||
| 	s_relay,	// 正常转发数据
 | ||||
|  | @ -38,8 +37,6 @@ public: | |||
| 	TelnetConn* server() { return m_conn_server; } | ||||
| 	uv_loop_t* get_loop(); | ||||
| 
 | ||||
| 	//bool is_client_auth_replaced() const { return m_is_client_auth_replaced; }
 | ||||
| 
 | ||||
| 	void set_state(int state) { m_state = state; } | ||||
| 	void close(int err_code); | ||||
| 	void on_conn_close(); | ||||
|  | @ -53,13 +50,9 @@ public: | |||
| 		m_rec.record(type, data, size); | ||||
| 	} | ||||
| 
 | ||||
| 	//static bool init_builtin_keypair();
 | ||||
| 
 | ||||
| 	void client_addr(const char* addr) { m_client_addr = addr; } | ||||
| 	const char* client_addr() const { return m_client_addr.c_str(); } | ||||
| 
 | ||||
| 	//static void release_builtin_keys();
 | ||||
| 
 | ||||
| 	bool is_relay() { return m_is_relay; } | ||||
| 	bool is_closed() { return m_is_closed; } | ||||
| 
 | ||||
|  | @ -72,26 +65,19 @@ protected: | |||
| private: | ||||
| 	sess_state _do_client_connect(TelnetConn* conn); | ||||
| 	sess_state _do_negotiation_with_client(TelnetConn* conn); | ||||
| 	//sess_state _do_ssl_handshake_with_client();
 | ||||
| // 	sess_state _do_connect_server();
 | ||||
| 	sess_state _do_server_connected(); | ||||
| 	//sess_state _do_negotiation_with_server();
 | ||||
| 	//sess_state _do_ssl_handshake_with_server();
 | ||||
| 	sess_state _do_relay(TelnetConn* conn); | ||||
| 	//sess_state _relay_dispatch_rdp(TelnetConn* conn_from, TelnetConn* conn_to);
 | ||||
| 	//sess_state _relay_dispatch_ssl(TelnetConn* conn_from, TelnetConn* conn_to);
 | ||||
| 	sess_state _do_close(int err_code); | ||||
| 	sess_state _do_check_closing(); | ||||
| 
 | ||||
| 	//bool _replace_server_cert(SC_ConferenceCreateResponse& gcc);
 | ||||
| 	bool _parse_find_and_send(TelnetConn* conn_recv, TelnetConn* conn_remote, const char* find, const char* send); | ||||
| 	bool _eat_username(TelnetConn* conn_recv, TelnetConn* conn_remote); | ||||
| 
 | ||||
| private: | ||||
| 	int m_state; | ||||
| 	int m_client_type; // 1 = mstsc, 2=freerdp
 | ||||
| 
 | ||||
| 	TPP_CONNECT_INFO* m_conn_info; | ||||
| 	bool m_record_started; | ||||
| 	int m_db_id; | ||||
| 
 | ||||
| 	bool m_is_relay;	// 是否进入relay模式了(只有进入relay模式才会有录像存在)
 | ||||
|  | @ -118,7 +104,6 @@ private: | |||
| 
 | ||||
| 	bool m_is_putty_mode; | ||||
| 	bool m_is_putty_eat_username; | ||||
| // 	bool m_is_changle_title_sent;	// 连接成功后,可以给客户端发送一个特殊的字符序列,客户端会改变窗口标题(已经在PuTTY/SecureCRT测试过)
 | ||||
| 
 | ||||
| 	bool m_username_sent; | ||||
| 	bool m_password_sent; | ||||
|  |  | |||
|  | @ -19,14 +19,14 @@ bool TppTelnetEnv::_on_init(TPP_INIT_ARGS* args) { | |||
| 
 | ||||
| 	ex_wstr tmp; | ||||
| 	if (!ps->GetStr(L"bind-ip", tmp)) { | ||||
| 		bind_ip = TS_RDP_PROXY_HOST; | ||||
| 		bind_ip = TS_TELNET_PROXY_HOST; | ||||
| 	} | ||||
| 	else { | ||||
| 		ex_wstr2astr(tmp, bind_ip); | ||||
| 	} | ||||
| 
 | ||||
| 	if (!ps->GetInt(L"bind-port", bind_port)) { | ||||
| 		bind_port = TS_RDP_PROXY_PORT; | ||||
| 		bind_port = TS_TELNET_PROXY_PORT; | ||||
| 	} | ||||
| 
 | ||||
| 	return true; | ||||
|  |  | |||
|  | @ -167,47 +167,6 @@ | |||
|     <ClCompile Include="..\..\..\..\external\libuv\src\win\util.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\libuv\src\win\winapi.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\libuv\src\win\winsock.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\aes.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\arc4.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\asn1parse.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\base64.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\bignum.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\blowfish.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\certs.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\cipher.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\cipher_wrap.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\ctr_drbg.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\debug.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\des.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\dhm.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\entropy.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\entropy_poll.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\error.c"> | ||||
|       <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)mbedtls_error.obj</ObjectFileName> | ||||
|       <ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)mbedtls_error.obj</ObjectFileName> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\hmac_drbg.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\md.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\md5.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\md_wrap.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\oid.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\pem.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\pk.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\pkcs12.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\pkcs5.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\pkparse.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\pk_wrap.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\rsa.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\sha1.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\sha256.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\sha512.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\ssl_ciphersuites.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\ssl_cli.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\ssl_srv.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\ssl_tls.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\timing.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\x509.c" /> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\x509_crt.c" /> | ||||
|     <ClCompile Include="..\..\common\base_env.cpp" /> | ||||
|     <ClCompile Include="..\..\common\base_record.cpp" /> | ||||
|     <ClCompile Include="..\..\common\ts_membuf.cpp" /> | ||||
|  |  | |||
|  | @ -36,9 +36,6 @@ | |||
|     <Filter Include="libuv\src\win"> | ||||
|       <UniqueIdentifier>{89181d75-3db3-45a5-a35d-9083fb349de3}</UniqueIdentifier> | ||||
|     </Filter> | ||||
|     <Filter Include="mbedtls"> | ||||
|       <UniqueIdentifier>{bedac06f-83d5-4cd3-832d-0bce55c3dc52}</UniqueIdentifier> | ||||
|     </Filter> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <ClInclude Include="..\..\..\..\common\libex\include\ex\ex_const.h"> | ||||
|  | @ -304,119 +301,5 @@ | |||
|     <ClCompile Include="..\..\..\..\external\libuv\src\win\process-stdio.c"> | ||||
|       <Filter>libuv\src\win</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\rsa.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\sha1.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\md5.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\bignum.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\md.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\md_wrap.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\sha256.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\sha512.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\asn1parse.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\oid.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\debug.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\x509.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\pk.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\pk_wrap.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\x509_crt.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\certs.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\entropy.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\ctr_drbg.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\arc4.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\pem.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\dhm.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\cipher.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\aes.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\des.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\base64.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\hmac_drbg.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\entropy_poll.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\cipher_wrap.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\blowfish.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\pkparse.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\pkcs5.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\pkcs12.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\error.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\timing.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\ssl_tls.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\ssl_ciphersuites.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\ssl_cli.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\..\..\..\external\mbedtls\library\ssl_srv.c"> | ||||
|       <Filter>mbedtls</Filter> | ||||
|     </ClCompile> | ||||
|   </ItemGroup> | ||||
| </Project> | ||||
|  | @ -166,6 +166,8 @@ $app.on_table_host_cell_created = function (tbl, row_id, col_key, cell_obj) { | |||
|                     // window.open('/audit/replay/' + row_data.protocol_type + '/' + row_data.id);
 | ||||
|                 } else if (row_data.protocol_type === TP_PROTOCOL_TYPE_SSH) { | ||||
|                     window.open('/audit/replay/' + row_data.protocol_type + '/' + row_data.id); | ||||
|                 } else if (row_data.protocol_type === TP_PROTOCOL_TYPE_TELNET) { | ||||
|                     window.open('/audit/replay/' + row_data.protocol_type + '/' + row_data.id); | ||||
|                 } | ||||
|             } else if (action === 'cmd') { | ||||
|                 //$app.dlg_accounts.show(row_id);
 | ||||
|  | @ -334,7 +336,7 @@ $app.on_table_host_render_created = function (render) { | |||
|     }; | ||||
| 
 | ||||
|     render.record_action = function (row_id, fields) { | ||||
|         if(fields.state === TP_SESS_STAT_RUNNING || fields.state === TP_SESS_STAT_STARTED) | ||||
|         if (fields.state === TP_SESS_STAT_RUNNING || fields.state === TP_SESS_STAT_STARTED) | ||||
|             return ''; | ||||
| 
 | ||||
|         var ret = []; | ||||
|  | @ -346,7 +348,9 @@ $app.on_table_host_render_created = function (render) { | |||
|                 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) { | ||||
|             if (fields.protocol_sub_type === TP_PROTOCOL_TYPE_SSH_SHELL | ||||
|                 || fields.protocol_sub_type === TP_PROTOCOL_TYPE_SSH_SFTP | ||||
|             ) { | ||||
|                 ret.push('<a href="javascript:;" class="btn btn-sm btn-info" data-action="cmd" data-record-id="' + fields.id + '"><i class="fa fa-list-alt fa-fw"></i> 日志</a> '); | ||||
|             } | ||||
|         } | ||||
|  |  | |||
|  | @ -0,0 +1,335 @@ | |||
| "use strict"; | ||||
| 
 | ||||
| $app.on_init = function (cb_stack) { | ||||
|     var record_id = $app.options.record_id; | ||||
| 
 | ||||
|     $app.record_hdr = null; | ||||
|     $app.record_data = []; | ||||
|     $app.record_data_offset = 0; | ||||
|     $app.played_pkg_count = 0; | ||||
|     $app.player_timer = null; | ||||
|     $app.is_playing = false; | ||||
|     $app.is_need_stop = false; | ||||
|     $app.need_skip = true; | ||||
|     $app.player_console_term = null; | ||||
|     $app.player_current_time = null; | ||||
|     $app.is_finished = false; | ||||
|     $app.record_tick = 50; | ||||
| 
 | ||||
| 
 | ||||
|     $app.speed_table = [ | ||||
|         {speed: 1, name: '正常速度'}, | ||||
|         {speed: 2, name: '快进 x2'}, | ||||
|         {speed: 4, name: '快进 x4'}, | ||||
|         {speed: 8, name: '快进 x8'}, | ||||
|         {speed: 16, name: '快进 x16'} | ||||
|     ]; | ||||
|     $app.speed_offset = 0; | ||||
| 
 | ||||
| 
 | ||||
|     $app.dom = { | ||||
|         time: $('#play-time'), | ||||
|         btn_play: $('#btn-play'), | ||||
|         btn_speed: $('#btn-speed'), | ||||
|         btn_skip: $('#btn-skip'), | ||||
|         btn_restart: $('#btn-restart'), | ||||
|         btn_big_font: $('#btn-big-font'), | ||||
|         btn_small_font: $('#btn-small-font'), | ||||
|         progress: $('#progress'), | ||||
|         status: $('#play-status'), | ||||
|         xterm_box: $('#xterm-box'), | ||||
|         xterm_terminal: null, | ||||
|         xterm_viewport: null | ||||
|     }; | ||||
| 
 | ||||
|     $app.dom.progress.width($('#toolbar').width()).val(0); | ||||
| 
 | ||||
|     Terminal.cursorBlink = false; | ||||
| 
 | ||||
|     $tp.ajax_post_json('/audit/get-record-header', {protocol: TP_PROTOCOL_TYPE_TELNET, id: record_id}, | ||||
|         function (ret) { | ||||
|             if (ret.code === TPE_OK) { | ||||
|                 $app.record_hdr = ret.data; | ||||
|                 if ($app.record_hdr.width === 0) | ||||
|                     $app.record_hdr.width = 80; | ||||
|                 if ($app.record_hdr.height === 0) | ||||
|                     $app.record_hdr.height = 24; | ||||
|                 console.log('header', $app.record_hdr); | ||||
| 
 | ||||
|                 $('#recorder-info').html(tp_format_datetime($app.record_hdr.start) + ': ' + $app.record_hdr.user_name + '@' + $app.record_hdr.client_ip + ' 访问 ' + $app.record_hdr.account + '@' + $app.record_hdr.conn_ip + ':' + $app.record_hdr.conn_port); | ||||
| 
 | ||||
|                 $app.req_record_data(record_id, 0); | ||||
| 
 | ||||
|                 $app.player_current_time = 0; | ||||
|                 //setTimeout(init, 500);
 | ||||
|                 $app.init_and_play(); | ||||
|             } else { | ||||
|                 $tp.notify_error('读取录像信息失败:' + tp_error_msg(ret.code, ret.message)); | ||||
|                 console.error('load init info error ', ret.code); | ||||
|             } | ||||
|         }, | ||||
|         function () { | ||||
|             $tp.notify_error('网络通讯失败'); | ||||
|         } | ||||
|     ); | ||||
| 
 | ||||
|     $app.dom.btn_big_font.click(function () { | ||||
|         if (_.isNull($app.dom.xterm_terminal)) | ||||
|             return; | ||||
|         var _size = parseInt($app.dom.xterm_terminal.css('font-size')); | ||||
|         if (_size >= 24) | ||||
|             return; | ||||
| 
 | ||||
|         $app.dom.xterm_terminal.css('font-size', _size + 1); | ||||
| 
 | ||||
|         $app.player_console_term.charMeasure.measure(); | ||||
|         $app.adjust_viewport(); | ||||
|     }); | ||||
| 
 | ||||
|     $app.dom.btn_small_font.click(function () { | ||||
|         if (_.isNull($app.dom.xterm_terminal)) | ||||
|             return; | ||||
| 
 | ||||
|         var _size = parseInt($app.dom.xterm_terminal.css('font-size')); | ||||
|         if (_size <= 12) | ||||
|             return; | ||||
| 
 | ||||
|         $app.dom.xterm_terminal.css('font-size', _size - 1); | ||||
| 
 | ||||
|         $app.player_console_term.charMeasure.measure(); | ||||
|         $app.adjust_viewport(); | ||||
|     }); | ||||
| 
 | ||||
|     $app.dom.btn_play.click(function () { | ||||
|         if ($app.is_playing) | ||||
|             $app.pause(); | ||||
|         else | ||||
|             $app.play(); | ||||
|     }); | ||||
| 
 | ||||
|     $app.dom.btn_skip.click(function () { | ||||
|         var obj = $('#btn-skip i'); | ||||
|         if ($app.need_skip) { | ||||
|             $app.need_skip = false; | ||||
|             obj.removeClass('fa-check-square-o').addClass('fa-square-o'); | ||||
|         } else { | ||||
|             $app.need_skip = true; | ||||
|             obj.removeClass('fa-square-o').addClass('fa-check-square-o'); | ||||
|         } | ||||
| 
 | ||||
|         // console.log('skip:', $app.need_skip);
 | ||||
|     }); | ||||
| 
 | ||||
|     $app.dom.btn_restart.click(function () { | ||||
|         $app.restart(); | ||||
|     }); | ||||
| 
 | ||||
|     $app.speed_offset = 0; | ||||
|     $app.dom.btn_speed.text($app.speed_table[$app.speed_offset].name); | ||||
| 
 | ||||
|     $app.dom.btn_speed.click(function () { | ||||
|         var length = $app.speed_table.length; | ||||
|         $app.speed_offset += 1; | ||||
|         if ($app.speed_offset === length) { | ||||
|             $app.speed_offset = 0; | ||||
|         } | ||||
|         $app.dom.btn_speed.text($app.speed_table[$app.speed_offset].name); | ||||
|     }); | ||||
| 
 | ||||
|     $app.dom.progress.mousedown(function () { | ||||
|         $app.pause(); | ||||
|     }); | ||||
|     $app.dom.progress.mouseup(function () { | ||||
|         $app.player_current_time = parseInt($app.record_hdr.time_used * $app.dom.progress.val() / 100); | ||||
|         setTimeout(function () { | ||||
|             $app.init_and_play(); | ||||
|         }, 100); | ||||
|     }); | ||||
|     $app.dom.progress.mousemove(function () { | ||||
|         $app.player_current_time = parseInt($app.record_hdr.time_used * $app.dom.progress.val() / 100); | ||||
|         $app.dom.time.text(parseInt(($app.player_current_time) / 1000) + '/' + parseInt($app.record_hdr.time_used / 1000) + '秒'); | ||||
|     }); | ||||
| 
 | ||||
|     $app.adjust_viewport = function () { | ||||
|         if (!_.isNull($app.dom.xterm_viewport)) { | ||||
|             $app.dom.xterm_viewport.width(parseInt(window.getComputedStyle($app.dom.xterm_rows[0]).width)); | ||||
|             $app.dom.xterm_viewport.height(parseInt(window.getComputedStyle($app.dom.xterm_rows[0]).height) - 1); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     cb_stack.exec(); | ||||
| }; | ||||
| 
 | ||||
| $app.req_record_data = function (record_id, offset) { | ||||
|     $tp.ajax_post_json('/audit/get-record-data', {protocol: TP_PROTOCOL_TYPE_TELNET, id: record_id, offset: offset}, | ||||
|         function (ret) { | ||||
|             if (ret.code === TPE_OK) { | ||||
|                 // console.log('data', ret.data);
 | ||||
|                 $app.record_data = $app.record_data.concat(ret.data.data_list); | ||||
|                 $app.record_data_offset += ret.data.data_size; | ||||
| 
 | ||||
|                 if ($app.record_data.length < $app.record_hdr.pkg_count) { | ||||
|                     $app.req_record_data(record_id, $app.record_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); | ||||
|             } | ||||
|         }, | ||||
|         function () { | ||||
|             console.log('req_record_info error'); | ||||
|         }, | ||||
|         30 * 1000 | ||||
|     ); | ||||
| }; | ||||
| 
 | ||||
| $app.init_and_play = function() { | ||||
|     if (_.isNull($app.player_console_term)) { | ||||
|         $app.player_console_term = new Terminal({ | ||||
|             cols: $app.record_hdr.width, | ||||
|             rows: $app.record_hdr.height | ||||
|         }); | ||||
| 
 | ||||
|         $app.player_console_term.on('refresh', function () { | ||||
|             $app.adjust_viewport(); | ||||
|         }); | ||||
| 
 | ||||
|         $app.player_console_term.open(document.getElementById('xterm-box'), true); | ||||
| 
 | ||||
|         $app.dom.xterm_terminal = $('#xterm-box .terminal'); | ||||
|         $app.dom.xterm_rows = $('#xterm-box .terminal .xterm-rows'); | ||||
|         $app.dom.xterm_viewport = $('#xterm-box .terminal .xterm-viewport'); | ||||
|     } else { | ||||
|         $app.player_console_term.reset($app.record_hdr.width, $app.record_hdr.height); | ||||
|     } | ||||
| 
 | ||||
|     if ($app.record_hdr.pkg_count === 0) | ||||
|         return; | ||||
| 
 | ||||
|     $app.dom.progress.val(0); | ||||
|     // $app.dom.status.text("正在播放");
 | ||||
|     $app.dom.btn_play.children().removeClass().addClass('fa fa-pause').text(' 暂停'); | ||||
| 
 | ||||
|     $app.is_need_stop = false; | ||||
|     $app.is_playing = true; | ||||
|     $app.is_finished = false; | ||||
|     $app.played_pkg_count = 0; | ||||
|     //setTimeout(do_play, $app.record_tick);
 | ||||
|     $app.do_play(); | ||||
| }; | ||||
| 
 | ||||
| $app.do_play = function() { | ||||
|     if ($app.is_need_stop) { | ||||
|         $app.is_playing = false; | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     if ($app.record_data.length <= $app.played_pkg_count) { | ||||
|         $app.dom.status.text("正在缓存数据..."); | ||||
|         $app.player_timer = setTimeout($app.do_play, $app.record_tick); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     $app.dom.status.text("正在播放"); | ||||
|     $app.player_current_time += $app.record_tick * $app.speed_table[$app.speed_offset].speed; | ||||
| 
 | ||||
|     var _record_tick = $app.record_tick; | ||||
| 
 | ||||
|     for (var i = $app.played_pkg_count; i < $app.record_data.length; i++) { | ||||
|         if ($app.is_need_stop) | ||||
|             break; | ||||
| 
 | ||||
|         var play_data = $app.record_data[i]; | ||||
| 
 | ||||
|         if (play_data.t < $app.player_current_time) { | ||||
|             if (play_data.a === 1) { | ||||
|                 $app.player_console_term.resize(play_data.w, play_data.h); | ||||
|             } else if (play_data.a === 2) { | ||||
|                 $app.player_console_term.write(play_data.d); | ||||
|             } | ||||
|             else { | ||||
|                 $app.player_console_term.write(tp_base64_decode(play_data.d)); | ||||
|             } | ||||
| 
 | ||||
|             if (($app.played_pkg_count + 1) === $app.record_hdr.pkg_count) { | ||||
|                 $app.dom.progress.val(100); | ||||
|                 $app.dom.status.text('播放完成'); | ||||
|                 $app.dom.time.text(parseInt($app.record_hdr.time_used / 1000) + '秒'); | ||||
|                 $app.is_finished = true; | ||||
|                 $app.is_playing = false; | ||||
|                 $app.dom.btn_play.children().removeClass().addClass('fa fa-play').text(' 播放'); | ||||
| 
 | ||||
|                 return; | ||||
|             } else { | ||||
|                 $app.played_pkg_count++; | ||||
|             } | ||||
| 
 | ||||
|         } else { | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if ($app.is_need_stop) | ||||
|         return; | ||||
| 
 | ||||
|     if ($app.need_skip) { | ||||
|         if (play_data.t - $app.player_current_time > 800) { | ||||
|             $app.player_current_time = play_data.t; // - $app.record_tick * $app.speed_table[$app.speed_offset].speed;
 | ||||
|             _record_tick = 800; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // sync progress bar.
 | ||||
|     var _progress = parseInt($app.player_current_time * 100 / $app.record_hdr.time_used); | ||||
|     $app.dom.progress.val(_progress); | ||||
|     var temp = parseInt($app.player_current_time / 1000); | ||||
|     $app.dom.time.text(temp + '/' + parseInt($app.record_hdr.time_used / 1000) + '秒'); | ||||
| 
 | ||||
|     // if all packages played
 | ||||
|     if ($app.played_pkg_count >= $app.record_hdr.pkg_count) { | ||||
|         $app.dom.progress.val(100); | ||||
|         $app.dom.status.text('播放完成'); | ||||
|         $app.dom.time.text(parseInt($app.record_hdr.time_used / 1000) + '秒'); | ||||
|         $app.is_finished = true; | ||||
|         $app.is_playing = false; | ||||
|         $app.dom.btn_play.children().removeClass().addClass('fa fa-play').text(' 播放'); | ||||
|     } else { | ||||
|         if (!$app.is_need_stop) | ||||
|             $app.player_timer = setTimeout($app.do_play, _record_tick); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| $app.play = function() { | ||||
|     if ($app.is_playing) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     if ($app.is_finished) { | ||||
|         $app.restart(); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     $app.dom.btn_play.children().removeClass().addClass('fa fa-pause').text(' 暂停'); | ||||
| 
 | ||||
|     $app.is_need_stop = false; | ||||
|     $app.is_playing = true; | ||||
|     $app.player_timer = setTimeout($app.do_play, $app.record_tick); | ||||
| }; | ||||
| 
 | ||||
| $app.pause = function() { | ||||
|     if (!_.isNull($app.player_timer)) | ||||
|         clearTimeout($app.player_timer); | ||||
|     $app.dom.btn_play.children().removeClass().addClass('fa fa-play').text(' 播放'); | ||||
|     $app.is_need_stop = true; | ||||
|     $app.is_playing = false; | ||||
|     $app.dom.status.text("已暂停"); | ||||
| }; | ||||
| 
 | ||||
| $app.restart = function() { | ||||
|     if (!_.isNull($app.player_timer)) | ||||
|         clearTimeout($app.player_timer); | ||||
|     $app.player_current_time = 0; | ||||
|     $app.init_and_play(); | ||||
| }; | ||||
| 
 | ||||
|  | @ -0,0 +1,105 @@ | |||
| <%! | ||||
|     page_title_ = '录像回放' | ||||
| %> | ||||
| 
 | ||||
| <%inherit file="../page_single_base.mako"/> | ||||
| 
 | ||||
| <%block name="extend_js_file"> | ||||
|     <script type="text/javascript" src="${ static_url('plugins/xterm/xterm.js') }"></script> | ||||
|     <script type="text/javascript" src="${ static_url('js/audit/replay-telnet.js') }"></script> | ||||
| </%block> | ||||
| 
 | ||||
| <%block name="extend_css_file"> | ||||
|     <link href="${ static_url('plugins/xterm/xterm.css') }" rel="stylesheet" type="text/css"/> | ||||
| </%block> | ||||
| 
 | ||||
| <%block name="embed_css"> | ||||
|     <style type="text/css"> | ||||
|         .container { | ||||
|             width:100%; | ||||
|             padding-right: 20px; | ||||
|         } | ||||
|         #xterm-box { | ||||
|             margin: 10px 0; | ||||
| ##             background-color: #1e1e1e; | ||||
|             ##             margin-top: 10px; | ||||
|             ##             margin-bottom: 48px; | ||||
|             ##             width: 300px; | ||||
| ##             border: 1px solid #9c9c9c; | ||||
|         } | ||||
| 
 | ||||
|         .terminal { | ||||
|             font-family: Consolas, Monaco, courier-new, courier, monospace; | ||||
|             color: #b7b7b7; | ||||
|             font-size: 13px; | ||||
|             display: inline-block; | ||||
|         } | ||||
| 
 | ||||
|         .terminal { | ||||
|             ##             background-color: transparent; | ||||
|         } | ||||
| 
 | ||||
|         .terminal .xterm-viewport { | ||||
|             ##             background-color: transparent; | ||||
|             ##             display:none; | ||||
|             ##             overflow: auto; | ||||
|             padding-right:17px; | ||||
|         } | ||||
| 
 | ||||
|         .terminal .xterm-rows { | ||||
| ##             margin:5px; | ||||
|             padding:5px; | ||||
|             border-right: 1px dashed #363636; | ||||
|             background-color: #1e1e1e; | ||||
|         } | ||||
|     </style> | ||||
| </%block> | ||||
| 
 | ||||
| <%block name="page_header"> | ||||
|     <div class="container-fluid top-navbar"> | ||||
|         <div class="breadcrumb-container"> | ||||
|             <ol class="breadcrumb"> | ||||
|                 <li><i class="fa fa-server"></i> ${self.attr.page_title_}</li> | ||||
|                 <li class="sub-title"><span id="recorder-info"></span></li> | ||||
|             </ol> | ||||
|         </div> | ||||
|     </div> | ||||
| </%block> | ||||
| 
 | ||||
| 
 | ||||
| <div class="page-content"> | ||||
|     <div id="toolbar" style="display: inline-block;"> | ||||
|         <button id="btn-play" type="button" class="btn btn-primary btn-sm" style="width:80px;"><i class="fa fa-pause fa-fw"> 暂停</i></button> | ||||
|         <button id="btn-restart" type="button" class="btn btn-success btn-sm"><i class="fa fa-refresh fa-fw"></i> 重新播放</button> | ||||
| 
 | ||||
|         <button id="btn-speed" type="button" class="btn btn-info btn-sm" style="width:80px;">正常速度</button> | ||||
| 
 | ||||
|         <button id="btn-big-font" type="button" class="btn btn-default btn-sm"><i class="fa fa-font fa-fw"></i>+</button> | ||||
|         <button id="btn-small-font" type="button" class="btn btn-default btn-sm"><i class="fa fa-font fa-fw"></i>-</button> | ||||
| 
 | ||||
|         <div style="display:inline-block;position:relative;top:4px;margin-left:10px;margin-right:15px;"> | ||||
|             <span id="btn-skip" style="cursor:pointer;"><i class="fa fa-check-square-o fa-fw"></i> 跳过无操作时间</span> | ||||
|         </div> | ||||
| 
 | ||||
|         <span id="play-status" class="badge badge-normal" style="margin-left:5px;">正在获取数据</span> | ||||
|         <span id="play-time" class="badge badge-success" style="margin-left:5px;">总时长:未知</span> | ||||
|     </div> | ||||
|     <input id="progress" type="range" value="0" min=0 max=100 style="margin-top: 10px;"/> | ||||
|     <div id="xterm-box"></div> | ||||
| 
 | ||||
| </div> | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| <%block name="extend_content"> | ||||
| 
 | ||||
| </%block> | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| <%block name="embed_js"> | ||||
|     <script type="text/javascript"> | ||||
|         $app.add_options(${page_param}); | ||||
|     </script> | ||||
| </%block> | ||||
|  | @ -499,6 +499,9 @@ class ReplayHandler(TPBaseHandler): | |||
|         elif protocol == TP_PROTOCOL_TYPE_SSH: | ||||
|             param = {'record_id': record_id} | ||||
|             self.render('audit/replay-ssh.mako', page_param=json.dumps(param)) | ||||
|         elif protocol == TP_PROTOCOL_TYPE_TELNET: | ||||
|             param = {'record_id': record_id} | ||||
|             self.render('audit/replay-telnet.mako', page_param=json.dumps(param)) | ||||
| 
 | ||||
| 
 | ||||
| # # class PlayRdpHandler(TPBaseAdminAuthHandler): | ||||
|  | @ -641,6 +644,8 @@ class DoGetRecordDataHandler(TPBaseJsonHandler): | |||
|             data_list, data_size, err = record.read_rdp_record_data(record_id, offset) | ||||
|         elif protocol_type == TP_PROTOCOL_TYPE_SSH: | ||||
|             data_list, data_size, err = record.read_ssh_record_data(record_id, offset) | ||||
|         elif protocol_type == TP_PROTOCOL_TYPE_TELNET: | ||||
|             data_list, data_size, err = record.read_telnet_record_data(record_id, offset) | ||||
|         else: | ||||
|             self.write_json(TPE_NOT_EXISTS) | ||||
|         self.write_json(err, data={'data_list': data_list, 'data_size': data_size}) | ||||
|  |  | |||
|  | @ -134,6 +134,8 @@ def read_record_head(protocol_type, record_id): | |||
|         path_name = 'rdp' | ||||
|     elif protocol_type == TP_PROTOCOL_TYPE_SSH: | ||||
|         path_name = 'ssh' | ||||
|     elif protocol_type == TP_PROTOCOL_TYPE_TELNET: | ||||
|         path_name = 'telnet' | ||||
| 
 | ||||
|     record_path = os.path.join(tp_cfg().core.replay_path, path_name, '{:09d}'.format(int(record_id))) | ||||
|     header_file_path = os.path.join(record_path, 'tp-{}.tpr'.format(path_name)) | ||||
|  | @ -366,6 +368,82 @@ def read_ssh_record_data(record_id, offset): | |||
|     return data_list, data_size, TPE_OK | ||||
| 
 | ||||
| 
 | ||||
| def read_telnet_record_data(record_id, offset): | ||||
|     if not tp_cfg().core.detected: | ||||
|         return None, TPE_NO_CORE_SERVER | ||||
| 
 | ||||
|     record_path = os.path.join(tp_cfg().core.replay_path, 'telnet', '{:09d}'.format(int(record_id))) | ||||
|     file_data = os.path.join(record_path, 'tp-telnet.dat') | ||||
| 
 | ||||
|     if not os.path.exists(file_data): | ||||
|         return None, 0, TPE_NOT_EXISTS | ||||
| 
 | ||||
|     data_list = list() | ||||
|     data_size = 0 | ||||
|     file = None | ||||
|     try: | ||||
|         file_size = os.path.getsize(file_data) | ||||
|         if offset >= file_size: | ||||
|             return None, 0, TPE_FAILED | ||||
| 
 | ||||
|         file = open(file_data, 'rb') | ||||
|         if offset > 0: | ||||
|             file.seek(offset, io.SEEK_SET) | ||||
| 
 | ||||
|         # read 1000 packages one time from offset. | ||||
|         for i in range(1000): | ||||
|             """ | ||||
|             // 一个数据包的头 | ||||
|             typedef struct TS_RECORD_PKG | ||||
|             { | ||||
|                 ex_u8 type;			// 包的数据类型 | ||||
|                 ex_u32 size;		// 这个包的总大小(不含包头) | ||||
|                 ex_u32 time_ms;		// 这个包距起始时间的时间差(毫秒,意味着一个连接不能持续超过49天) | ||||
|                 ex_u8 _reserve[3];	// 保留 | ||||
|             }TS_RECORD_PKG; | ||||
|             """ | ||||
|             _data = file.read(12) | ||||
|             data_size += 12 | ||||
|             _action, _size, _time, = struct.unpack_from('=BII', _data) | ||||
|             if offset + data_size + _size > file_size: | ||||
|                 return None, 0, TPE_FAILED | ||||
| 
 | ||||
|             _data = file.read(_size) | ||||
|             data_size += _size | ||||
| 
 | ||||
|             temp = dict() | ||||
|             temp['a'] = _action | ||||
|             temp['t'] = _time | ||||
|             if _action == 1: | ||||
|                 # this is window size changed. | ||||
|                 w, h = struct.unpack_from('HH', _data) | ||||
|                 temp['w'] = w | ||||
|                 temp['h'] = h | ||||
|             elif _action == 2: | ||||
|                 try: | ||||
|                     _d = _data.decode() | ||||
|                     temp['d'] = _d | ||||
|                 except: | ||||
|                     _data = base64.b64encode(_data) | ||||
|                     temp['a'] = 3 | ||||
|                     temp['d'] = _data.decode() | ||||
|             else: | ||||
|                 return None, 0, TPE_FAILED | ||||
| 
 | ||||
|             data_list.append(temp) | ||||
|             if offset + data_size == file_size: | ||||
|                 break | ||||
| 
 | ||||
|     except Exception: | ||||
|         log.e('failed to read record file: {}\n'.format(file_data)) | ||||
|         return None, 0, TPE_FAILED | ||||
|     finally: | ||||
|         if file is not None: | ||||
|             file.close() | ||||
| 
 | ||||
|     return data_list, data_size, TPE_OK | ||||
| 
 | ||||
| 
 | ||||
| def delete_log(log_list): | ||||
|     try: | ||||
|         where = list() | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Apex Liu
						Apex Liu