telnet可以录像和播放了(还不能记录命令,不能感知客户端窗口大小变化)

pull/105/head
Apex Liu 2018-04-06 07:59:44 +08:00
parent db9838e480
commit 21e07f7b32
15 changed files with 704 additions and 565 deletions

View File

@ -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

View File

@ -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) {
}

View File

@ -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__

View File

@ -1,168 +1,158 @@
#include "telnet_recorder.h"
static ex_u8 TPP_RECORD_MAGIC[4] = { 'T', 'P', 'P', 'R' };
TppTelnetRec::TppTelnetRec()
{
#include "telnet_recorder.h"
static ex_u8 TPP_RECORD_MAGIC[4] = { 'T', 'P', 'P', 'R' };
TppTelnetRec::TppTelnetRec()
{
m_cmd_cache.reserve(MAX_SIZE_PER_FILE);
memset(&m_head, 0, sizeof(TS_RECORD_HEADER));
memcpy((ex_u8*)(&m_head.info.magic), TPP_RECORD_MAGIC, sizeof(ex_u32));
m_head.info.ver = 0x03;
m_header_changed = false;
m_save_full_header = false;
m_file_info = NULL;
m_file_data = NULL;
m_file_cmd = NULL;
}
TppTelnetRec::~TppTelnetRec()
{
end();
}
bool TppTelnetRec::_on_begin(const TPP_CONNECT_INFO* info)
{
if (NULL == info)
return false;
m_head.basic.timestamp = (ex_u64)time(NULL);
m_head.basic.protocol_type = (ex_u16)info->protocol_type;
m_head.basic.protocol_sub_type = (ex_u16)info->protocol_sub_type;
m_head.basic.conn_port = (ex_u16)info->conn_port;
memcpy(m_head.basic.acc_username, info->acc_username, strlen(info->acc_username) >= 63 ? 63 : strlen(info->acc_username));
memcpy(m_head.basic.user_username, info->user_username, strlen(info->user_username) >= 63 ? 63 : strlen(info->user_username));
memcpy(m_head.basic.host_ip, info->host_ip, strlen(info->host_ip) >= 39 ? 39 : strlen(info->host_ip));
memcpy(m_head.basic.conn_ip, info->conn_ip, strlen(info->conn_ip) >= 39 ? 39 : strlen(info->conn_ip));
memcpy(m_head.basic.client_ip, info->client_ip, strlen(info->client_ip) >= 39 ? 39 : strlen(info->client_ip));
return true;
}
bool TppTelnetRec::_on_end()
{
// 如果还有剩下未写入的数据,写入文件中。
save_record();
if (m_file_info != NULL)
fclose(m_file_info);
if (m_file_data != NULL)
fclose(m_file_data);
if (m_file_cmd != NULL)
fclose(m_file_cmd);
return true;
}
void TppTelnetRec::save_record() {
_save_to_data_file();
_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)
return;
if (sizeof(TS_RECORD_PKG) + size + m_cache.size() > MAX_SIZE_PER_FILE)
_save_to_data_file();
TS_RECORD_PKG pkg = { 0 };
pkg.type = type;
pkg.size = (ex_u32)size;
if (m_start_time > 0)
{
pkg.time_ms = (ex_u32)(ex_get_tick_count() - m_start_time);
m_head.info.time_ms = pkg.time_ms;
}
m_cache.append((ex_u8*)&pkg, sizeof(TS_RECORD_PKG));
m_cache.append(data, size);
m_head.info.packages++;
m_header_changed = true;
}
void TppTelnetRec::record_win_size(int width, int height)
{
m_head.basic.width = (ex_u16)width;
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() {
if (!m_header_changed)
return true;
if (m_file_info == NULL) {
ex_wstr fname = m_base_path;
ex_path_join(fname, false, m_base_fname.c_str(), NULL);
fname += L".tpr";
m_file_info = ex_fopen(fname, L"wb");
if (NULL == m_file_info)
{
EXLOGE("[ssh] can not open record info-file for write.\n");
return false;
}
// first time to save header, write whole header.
m_save_full_header = true;
}
fseek(m_file_info, 0L, SEEK_SET);
if (m_save_full_header) {
fwrite(&m_head, ts_record_header_size, 1, m_file_info);
fflush(m_file_info);
m_save_full_header = false;
}
else {
fwrite(&m_head.info, ts_record_header_info_size, 1, m_file_info);
fflush(m_file_info);
}
return true;
}
bool TppTelnetRec::_save_to_data_file()
{
if (m_cache.size() == 0)
return true;
if (m_file_data == NULL) {
ex_wstr fname = m_base_path;
ex_path_join(fname, false, m_base_fname.c_str(), NULL);
fname += L".dat";
m_file_data = ex_fopen(fname, L"wb");
if (NULL == m_file_data)
{
EXLOGE("[ssh] can not open record data-file for write.\n");
return false;
}
m_header_changed = true;
}
fwrite(m_cache.data(), m_cache.size(), 1, m_file_data);
fflush(m_file_data);
m_cache.empty();
return _save_to_info_file();
}
memset(&m_head, 0, sizeof(TS_RECORD_HEADER));
memcpy((ex_u8*)(&m_head.info.magic), TPP_RECORD_MAGIC, sizeof(ex_u32));
m_head.info.ver = 0x03;
m_header_changed = false;
m_save_full_header = false;
m_file_info = NULL;
m_file_data = NULL;
m_file_cmd = NULL;
}
TppTelnetRec::~TppTelnetRec()
{
end();
}
bool TppTelnetRec::_on_begin(const TPP_CONNECT_INFO* info)
{
if (NULL == info)
return false;
m_head.basic.timestamp = (ex_u64)time(NULL);
m_head.basic.protocol_type = (ex_u16)info->protocol_type;
m_head.basic.protocol_sub_type = (ex_u16)info->protocol_sub_type;
m_head.basic.conn_port = (ex_u16)info->conn_port;
memcpy(m_head.basic.acc_username, info->acc_username, strlen(info->acc_username) >= 63 ? 63 : strlen(info->acc_username));
memcpy(m_head.basic.user_username, info->user_username, strlen(info->user_username) >= 63 ? 63 : strlen(info->user_username));
memcpy(m_head.basic.host_ip, info->host_ip, strlen(info->host_ip) >= 39 ? 39 : strlen(info->host_ip));
memcpy(m_head.basic.conn_ip, info->conn_ip, strlen(info->conn_ip) >= 39 ? 39 : strlen(info->conn_ip));
memcpy(m_head.basic.client_ip, info->client_ip, strlen(info->client_ip) >= 39 ? 39 : strlen(info->client_ip));
return true;
}
bool TppTelnetRec::_on_end()
{
// 如果还有剩下未写入的数据,写入文件中。
save_record();
if (m_file_info != NULL)
fclose(m_file_info);
if (m_file_data != NULL)
fclose(m_file_data);
if (m_file_cmd != NULL)
fclose(m_file_cmd);
return true;
}
void TppTelnetRec::save_record() {
_save_to_data_file();
_save_to_cmd_file();
}
void TppTelnetRec::record(ex_u8 type, const ex_u8* data, size_t size)
{
if (data == NULL || 0 == size)
return;
if (sizeof(TS_RECORD_PKG) + size + m_cache.size() > MAX_SIZE_PER_FILE)
_save_to_data_file();
TS_RECORD_PKG pkg = { 0 };
pkg.type = type;
pkg.size = (ex_u32)size;
if (m_start_time > 0)
{
pkg.time_ms = (ex_u32)(ex_get_tick_count() - m_start_time);
m_head.info.time_ms = pkg.time_ms;
}
m_cache.append((ex_u8*)&pkg, sizeof(TS_RECORD_PKG));
m_cache.append(data, size);
m_head.info.packages++;
m_header_changed = true;
}
void TppTelnetRec::record_win_size(int width, int height)
{
m_head.basic.width = (ex_u16)width;
m_head.basic.height = (ex_u16)height;
m_save_full_header = true;
m_header_changed = true;
}
bool TppTelnetRec::_save_to_info_file() {
if (!m_header_changed)
return true;
if (m_file_info == NULL) {
ex_wstr fname = m_base_path;
ex_path_join(fname, false, m_base_fname.c_str(), NULL);
fname += L".tpr";
m_file_info = ex_fopen(fname, L"wb");
if (NULL == m_file_info)
{
EXLOGE("[ssh] can not open record info-file for write.\n");
return false;
}
// first time to save header, write whole header.
m_save_full_header = true;
}
fseek(m_file_info, 0L, SEEK_SET);
if (m_save_full_header) {
fwrite(&m_head, ts_record_header_size, 1, m_file_info);
fflush(m_file_info);
m_save_full_header = false;
}
else {
fwrite(&m_head.info, ts_record_header_info_size, 1, m_file_info);
fflush(m_file_info);
}
return true;
}
bool TppTelnetRec::_save_to_data_file()
{
if (m_cache.size() == 0)
return true;
if (m_file_data == NULL) {
ex_wstr fname = m_base_path;
ex_path_join(fname, false, m_base_fname.c_str(), NULL);
fname += L".dat";
m_file_data = ex_fopen(fname, L"wb");
if (NULL == m_file_data)
{
EXLOGE("[ssh] can not open record data-file for write.\n");
return false;
}
m_header_changed = true;
}
fwrite(m_cache.data(), m_cache.size(), 1, m_file_data);
fflush(m_file_data);
m_cache.empty();
return _save_to_info_file();
}
bool TppTelnetRec::_save_to_cmd_file()
{

View 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);

View File

@ -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();
}

View File

@ -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;

View File

@ -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;

View File

@ -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" />

View File

@ -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>

View File

@ -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>&nbsp');
}
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>&nbsp');
}
}

View File

@ -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();
};

View File

@ -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>

View File

@ -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})

View File

@ -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()